/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/urlutils.py

  • Committer: Martin Pool
  • Date: 2006-06-20 05:32:16 UTC
  • mfrom: (1797 +trunk)
  • mto: This revision was merged to the branch mainline in revision 1798.
  • Revision ID: mbp@sourcefrog.net-20060620053216-817857d7ca3e9d1f
[merge] bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
"""A collection of function for handling URL operations."""
20
20
 
21
21
import os
22
 
from posixpath import split as _posix_split
 
22
from posixpath import split as _posix_split, normpath as _posix_normpath
23
23
import re
24
24
import sys
25
25
import urllib
116
116
    if m:
117
117
        scheme = m.group('scheme')
118
118
        path = m.group('path').split('/')
 
119
        if path[-1:] == ['']:
 
120
            # Strip off a trailing slash
 
121
            # This helps both when we are at the root, and when
 
122
            # 'base' has an extra slash at the end
 
123
            path = path[:-1]
119
124
    else:
120
125
        path = base.split('/')
121
126
 
160
165
    """
161
166
    # importing directly from posixpath allows us to test this 
162
167
    # on non-posix platforms
163
 
    from posixpath import normpath
164
 
    return 'file://' + escape(normpath(bzrlib.osutils._posix_abspath(path)))
 
168
    return 'file://' + escape(_posix_normpath(
 
169
        bzrlib.osutils._posix_abspath(path)))
165
170
 
166
171
 
167
172
def _win32_local_path_from_url(url):
168
 
    """Convert a url like file:///C|/path/to/foo into C:/path/to/foo"""
 
173
    """Convert a url like file:///C:/path/to/foo into C:/path/to/foo"""
169
174
    if not url.startswith('file:///'):
170
175
        raise errors.InvalidURL(url, 'local urls must start with file:///')
171
176
    # We strip off all 3 slashes
172
177
    win32_url = url[len('file:///'):]
173
 
    if (win32_url[0] not in 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
 
178
    if (win32_url[0] not in ('abcdefghijklmnopqrstuvwxyz'
 
179
                             'ABCDEFGHIJKLMNOPQRSTUVWXYZ')
174
180
        or win32_url[1] not in  '|:'
175
181
        or win32_url[2] != '/'):
176
 
        raise errors.InvalidURL(url, 'Win32 file urls start with file:///X|/, where X is a valid drive letter')
177
 
    # TODO: jam 20060426, we could .upper() or .lower() the drive letter
178
 
    #       for better consistency.
179
 
    return win32_url[0].upper() + u':' + unescape(win32_url[2:])
 
182
        raise errors.InvalidURL(url, 'Win32 file urls start with'
 
183
                ' file:///x:/, where x is a valid drive letter')
 
184
    # Preferentially using .lower() because os.getcwd() returns
 
185
    # paths with lowercase drive letters, and that helps
 
186
    # bzrlib.osutils.relpath() work correctly
 
187
    return win32_url[0].lower() + u':' + unescape(win32_url[2:])
180
188
 
181
189
 
182
190
def _win32_local_path_to_url(path):
183
 
    """Convert a local path like ./foo into a URL like file:///C|/path/to/foo
 
191
    """Convert a local path like ./foo into a URL like file:///C:/path/to/foo
184
192
 
185
193
    This also handles transforming escaping unicode characters, etc.
186
194
    """
187
195
    # importing directly from ntpath allows us to test this 
188
 
    # on non-win32 platforms
 
196
    # on non-win32 platform
 
197
    # FIXME: It turns out that on nt, ntpath.abspath uses nt._getfullpathname
 
198
    #       which actually strips trailing space characters.
 
199
    #       The worst part is that under linux ntpath.abspath has different
 
200
    #       semantics, since 'nt' is not an available module.
189
201
    win32_path = bzrlib.osutils._nt_normpath(
190
202
        bzrlib.osutils._win32_abspath(path)).replace('\\', '/')
191
 
    return 'file:///' + win32_path[0].upper() + ':' + escape(win32_path[2:])
 
203
    return 'file:///' + win32_path[0].lower() + ':' + escape(win32_path[2:])
192
204
 
193
205
 
194
206
local_path_to_url = _posix_local_path_to_url
195
207
local_path_from_url = _posix_local_path_from_url
196
208
MIN_ABS_FILEURL_LENGTH = len('file:///')
 
209
WIN32_MIN_ABS_FILEURL_LENGTH = len('file:///C:/')
197
210
 
198
211
if sys.platform == 'win32':
199
212
    local_path_to_url = _win32_local_path_to_url
200
213
    local_path_from_url = _win32_local_path_from_url
201
214
 
202
 
    MIN_ABS_FILEURL_LENGTH = len('file:///C|/')
 
215
    MIN_ABS_FILEURL_LENGTH = WIN32_MIN_ABS_FILEURL_LENGTH
203
216
 
204
217
 
205
218
_url_scheme_re = re.compile(r'^(?P<scheme>[^:/]{2,})://(?P<path>.*)$')
291
304
    return "/".join(output_sections) or "."
292
305
 
293
306
 
 
307
def _win32_extract_drive_letter(url_base, path):
 
308
    """On win32 the drive letter needs to be added to the url base."""
 
309
    # Strip off the drive letter
 
310
    # path is currently /C:/foo
 
311
    if len(path) < 3 or path[2] not in ':|' or path[3] != '/':
 
312
        raise errors.InvalidURL(url_base + path, 
 
313
            'win32 file:/// paths need a drive letter')
 
314
    url_base += path[0:3] # file:// + /C:
 
315
    path = path[3:] # /foo
 
316
    return url_base, path
 
317
 
 
318
 
294
319
def split(url, exclude_trailing_slash=True):
295
320
    """Split a URL into its parent directory and a child directory.
296
321
 
320
345
 
321
346
    if sys.platform == 'win32' and url.startswith('file:///'):
322
347
        # Strip off the drive letter
 
348
        # url_base is currently file://
323
349
        # path is currently /C:/foo
324
 
        if path[2:3] not in ':|' or path[3:4] not in '\\/':
325
 
            raise errors.InvalidURL(url, 
326
 
                'win32 file:/// paths need a drive letter')
327
 
        url_base += path[0:3] # file:// + /C:
328
 
        path = path[3:] # /foo
 
350
        url_base, path = _win32_extract_drive_letter(url_base, path)
 
351
        # now it should be file:///C: and /foo
329
352
 
330
353
    if exclude_trailing_slash and len(path) > 1 and path.endswith('/'):
331
354
        path = path[:-1]
333
356
    return url_base + head, tail
334
357
 
335
358
 
 
359
def _win32_strip_local_trailing_slash(url):
 
360
    """Strip slashes after the drive letter"""
 
361
    if len(url) > WIN32_MIN_ABS_FILEURL_LENGTH:
 
362
        return url[:-1]
 
363
    else:
 
364
        return url
 
365
 
 
366
 
336
367
def strip_trailing_slash(url):
337
368
    """Strip trailing slash, except for root paths.
338
369
 
352
383
        file:///foo/      => file:///foo
353
384
        # This is unique on win32 platforms, and is the only URL
354
385
        # format which does it differently.
355
 
        file:///C|/       => file:///C|/
 
386
        file:///c|/       => file:///c:/
356
387
    """
357
388
    if not url.endswith('/'):
358
389
        # Nothing to do
359
390
        return url
360
391
    if sys.platform == 'win32' and url.startswith('file:///'):
361
 
        # This gets handled specially, because the 'top-level'
362
 
        # of a win32 path is actually the drive letter
363
 
        if len(url) > MIN_ABS_FILEURL_LENGTH:
364
 
            return url[:-1]
365
 
        else:
366
 
            return url
 
392
        return _win32_strip_local_trailing_slash(url)
367
393
 
368
394
    scheme_loc, first_path_slash = _find_scheme_and_separator(url)
369
395
    if scheme_loc is None: