~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/osutils.py

Merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
import time
32
32
import types
33
33
import tempfile
 
34
import unicodedata
 
35
from ntpath import (abspath as _nt_abspath,
 
36
                    join as _nt_join,
 
37
                    normpath as _nt_normpath,
 
38
                    realpath as _nt_realpath,
 
39
                    )
34
40
 
35
41
import bzrlib
36
42
from bzrlib.errors import (BzrError,
172
178
            else:
173
179
                rename_func(tmp_name, new)
174
180
 
 
181
 
 
182
# In Python 2.4.2 and older, os.path.abspath and os.path.realpath
 
183
# choke on a Unicode string containing a relative path if
 
184
# os.getcwd() returns a non-sys.getdefaultencoding()-encoded
 
185
# string.
 
186
_fs_enc = sys.getfilesystemencoding()
 
187
def _posix_abspath(path):
 
188
    return os.path.abspath(path.encode(_fs_enc)).decode(_fs_enc)
 
189
    # jam 20060426 This is another possibility which mimics 
 
190
    # os.path.abspath, only uses unicode characters instead
 
191
    # if not os.path.isabs(path):
 
192
    #     return os.path.join(os.getcwdu(), path)
 
193
    # return path
 
194
 
 
195
 
 
196
def _posix_realpath(path):
 
197
    return os.path.realpath(path.encode(_fs_enc)).decode(_fs_enc)
 
198
 
 
199
 
 
200
def _win32_abspath(path):
 
201
    return _nt_abspath(path.encode(_fs_enc)).decode(_fs_enc).replace('\\', '/')
 
202
 
 
203
 
 
204
def _win32_realpath(path):
 
205
    return _nt_realpath(path.encode(_fs_enc)).decode(_fs_enc).replace('\\', '/')
 
206
 
 
207
 
 
208
def _win32_pathjoin(*args):
 
209
    return _nt_join(*args).replace('\\', '/')
 
210
 
 
211
 
 
212
def _win32_normpath(path):
 
213
    return _nt_normpath(path).replace('\\', '/')
 
214
 
 
215
 
 
216
def _win32_getcwd():
 
217
    return os.getcwdu().replace('\\', '/')
 
218
 
 
219
 
 
220
def _win32_mkdtemp(*args, **kwargs):
 
221
    return tempfile.mkdtemp(*args, **kwargs).replace('\\', '/')
 
222
 
 
223
 
 
224
def _win32_rename(old, new):
 
225
    fancy_rename(old, new, rename_func=os.rename, unlink_func=os.unlink)
 
226
 
 
227
 
175
228
# Default is to just use the python builtins, but these can be rebound on
176
229
# particular platforms.
177
 
abspath = os.path.abspath
178
 
realpath = os.path.realpath
 
230
abspath = _posix_abspath
 
231
realpath = _posix_realpath
179
232
pathjoin = os.path.join
180
233
normpath = os.path.normpath
181
234
getcwd = os.getcwdu
187
240
 
188
241
MIN_ABS_PATHLENGTH = 1
189
242
 
190
 
if os.name == "posix":
191
 
    # In Python 2.4.2 and older, os.path.abspath and os.path.realpath
192
 
    # choke on a Unicode string containing a relative path if
193
 
    # os.getcwd() returns a non-sys.getdefaultencoding()-encoded
194
 
    # string.
195
 
    _fs_enc = sys.getfilesystemencoding()
196
 
    def abspath(path):
197
 
        return os.path.abspath(path.encode(_fs_enc)).decode(_fs_enc)
198
 
 
199
 
    def realpath(path):
200
 
        return os.path.realpath(path.encode(_fs_enc)).decode(_fs_enc)
201
243
 
202
244
if sys.platform == 'win32':
203
 
    # We need to use the Unicode-aware os.path.abspath and
204
 
    # os.path.realpath on Windows systems.
205
 
    def abspath(path):
206
 
        return os.path.abspath(path).replace('\\', '/')
207
 
 
208
 
    def realpath(path):
209
 
        return os.path.realpath(path).replace('\\', '/')
210
 
 
211
 
    def pathjoin(*args):
212
 
        return os.path.join(*args).replace('\\', '/')
213
 
 
214
 
    def normpath(path):
215
 
        return os.path.normpath(path).replace('\\', '/')
216
 
 
217
 
    def getcwd():
218
 
        return os.getcwdu().replace('\\', '/')
219
 
 
220
 
    def mkdtemp(*args, **kwargs):
221
 
        return tempfile.mkdtemp(*args, **kwargs).replace('\\', '/')
222
 
 
223
 
    def rename(old, new):
224
 
        fancy_rename(old, new, rename_func=os.rename, unlink_func=os.unlink)
 
245
    abspath = _win32_abspath
 
246
    realpath = _win32_realpath
 
247
    pathjoin = _win32_pathjoin
 
248
    normpath = _win32_normpath
 
249
    getcwd = _win32_getcwd
 
250
    mkdtemp = _win32_mkdtemp
 
251
    rename = _win32_rename
225
252
 
226
253
    MIN_ABS_PATHLENGTH = 3
227
254
 
629
656
    assert len(base) >= MIN_ABS_PATHLENGTH, ('Length of base must be equal or'
630
657
        ' exceed the platform minimum length (which is %d)' % 
631
658
        MIN_ABS_PATHLENGTH)
 
659
 
632
660
    rp = abspath(path)
633
661
 
634
662
    s = []
640
668
        if tail:
641
669
            s.insert(0, tail)
642
670
    else:
643
 
        # XXX This should raise a NotChildPath exception, as its not tied
644
 
        # to branch anymore.
645
671
        raise PathNotChild(rp, base)
646
672
 
647
673
    if s:
666
692
        raise BzrBadParameterNotUnicode(unicode_or_utf8_string)
667
693
 
668
694
 
 
695
_platform_normalizes_filenames = False
 
696
if sys.platform == 'darwin':
 
697
    _platform_normalizes_filenames = True
 
698
 
 
699
 
 
700
def normalizes_filenames():
 
701
    """Return True if this platform normalizes unicode filenames.
 
702
 
 
703
    Mac OSX does, Windows/Linux do not.
 
704
    """
 
705
    return _platform_normalizes_filenames
 
706
 
 
707
 
 
708
if _platform_normalizes_filenames:
 
709
    def unicode_filename(path):
 
710
        """Make sure 'path' is a properly normalized filename.
 
711
 
 
712
        On platforms where the system normalizes filenames (Mac OSX),
 
713
        you can access a file by any path which will normalize
 
714
        correctly.
 
715
        Internally, bzr only supports NFC/NFKC normalization, since
 
716
        that is the standard for XML documents.
 
717
        So we return an normalized path, and indicate this has been
 
718
        properly normalized.
 
719
 
 
720
        :return: (path, is_normalized) Return a path which can
 
721
                access the file, and whether or not this path is
 
722
                normalized.
 
723
        """
 
724
        return unicodedata.normalize('NFKC', path), True
 
725
else:
 
726
    def unicode_filename(path):
 
727
        """Make sure 'path' is a properly normalized filename.
 
728
 
 
729
        On platforms where the system does not normalize filenames 
 
730
        (Windows, Linux), you have to access a file by its exact path.
 
731
        Internally, bzr only supports NFC/NFKC normalization, since
 
732
        that is the standard for XML documents.
 
733
        So we return the original path, and indicate if this is
 
734
        properly normalized.
 
735
 
 
736
        :return: (path, is_normalized) Return a path which can
 
737
                access the file, and whether or not this path is
 
738
                normalized.
 
739
        """
 
740
        return path, unicodedata.normalize('NFKC', path) == path
 
741
 
 
742
 
669
743
def terminal_width():
670
744
    """Return estimated terminal width."""
671
745
    if sys.platform == 'win32':
693
767
    return sys.platform != "win32"
694
768
 
695
769
 
696
 
def strip_trailing_slash(path):
697
 
    """Strip trailing slash, except for root paths.
698
 
    The definition of 'root path' is platform-dependent.
699
 
    """
700
 
    if len(path) != MIN_ABS_PATHLENGTH and path[-1] == '/':
701
 
        return path[:-1]
702
 
    else:
703
 
        return path
704
 
 
705
 
 
706
770
_validWin32PathRE = re.compile(r'^([A-Za-z]:[/\\])?[^:<>*"?\|]*$')
707
771
 
708
772