mercurial/posix.py
changeset 45942 89a2afe31e82
parent 45718 87c35b5a14eb
child 46680 6595e22048fe
equal deleted inserted replaced
45941:346af7687c6f 45942:89a2afe31e82
    74     # https://github.com/python/cpython/blob/v3.7.3/Modules/_io/fileio.c#L474
    74     # https://github.com/python/cpython/blob/v3.7.3/Modules/_io/fileio.c#L474
    75     posixfile = open
    75     posixfile = open
    76 
    76 
    77 
    77 
    78 def split(p):
    78 def split(p):
    79     '''Same as posixpath.split, but faster
    79     """Same as posixpath.split, but faster
    80 
    80 
    81     >>> import posixpath
    81     >>> import posixpath
    82     >>> for f in [b'/absolute/path/to/file',
    82     >>> for f in [b'/absolute/path/to/file',
    83     ...           b'relative/path/to/file',
    83     ...           b'relative/path/to/file',
    84     ...           b'file_alone',
    84     ...           b'file_alone',
    86     ...           b'/multiple/path//separators',
    86     ...           b'/multiple/path//separators',
    87     ...           b'/file_at_root',
    87     ...           b'/file_at_root',
    88     ...           b'///multiple_leading_separators_at_root',
    88     ...           b'///multiple_leading_separators_at_root',
    89     ...           b'']:
    89     ...           b'']:
    90     ...     assert split(f) == posixpath.split(f), f
    90     ...     assert split(f) == posixpath.split(f), f
    91     '''
    91     """
    92     ht = p.rsplit(b'/', 1)
    92     ht = p.rsplit(b'/', 1)
    93     if len(ht) == 1:
    93     if len(ht) == 1:
    94         return b'', p
    94         return b'', p
    95     nh = ht[0].rstrip(b'/')
    95     nh = ht[0].rstrip(b'/')
    96     if nh:
    96     if nh:
   181         # Turn off all +x bits
   181         # Turn off all +x bits
   182         os.chmod(f, s & 0o666)
   182         os.chmod(f, s & 0o666)
   183 
   183 
   184 
   184 
   185 def copymode(src, dst, mode=None, enforcewritable=False):
   185 def copymode(src, dst, mode=None, enforcewritable=False):
   186     '''Copy the file mode from the file at path src to dst.
   186     """Copy the file mode from the file at path src to dst.
   187     If src doesn't exist, we're using mode instead. If mode is None, we're
   187     If src doesn't exist, we're using mode instead. If mode is None, we're
   188     using umask.'''
   188     using umask."""
   189     try:
   189     try:
   190         st_mode = os.lstat(src).st_mode & 0o777
   190         st_mode = os.lstat(src).st_mode & 0o777
   191     except OSError as inst:
   191     except OSError as inst:
   192         if inst.errno != errno.ENOENT:
   192         if inst.errno != errno.ENOENT:
   193             raise
   193             raise
   357                 unlink(name)
   357                 unlink(name)
   358             return False
   358             return False
   359 
   359 
   360 
   360 
   361 def checkosfilename(path):
   361 def checkosfilename(path):
   362     '''Check that the base-relative path is a valid filename on this platform.
   362     """Check that the base-relative path is a valid filename on this platform.
   363     Returns None if the path is ok, or a UI string describing the problem.'''
   363     Returns None if the path is ok, or a UI string describing the problem."""
   364     return None  # on posix platforms, every path is ok
   364     return None  # on posix platforms, every path is ok
   365 
   365 
   366 
   366 
   367 def getfsmountpoint(dirpath):
   367 def getfsmountpoint(dirpath):
   368     '''Get the filesystem mount point from a directory (best-effort)
   368     """Get the filesystem mount point from a directory (best-effort)
   369 
   369 
   370     Returns None if we are unsure. Raises OSError on ENOENT, EPERM, etc.
   370     Returns None if we are unsure. Raises OSError on ENOENT, EPERM, etc.
   371     '''
   371     """
   372     return getattr(osutil, 'getfsmountpoint', lambda x: None)(dirpath)
   372     return getattr(osutil, 'getfsmountpoint', lambda x: None)(dirpath)
   373 
   373 
   374 
   374 
   375 def getfstype(dirpath):
   375 def getfstype(dirpath):
   376     '''Get the filesystem type name from a directory (best-effort)
   376     """Get the filesystem type name from a directory (best-effort)
   377 
   377 
   378     Returns None if we are unsure. Raises OSError on ENOENT, EPERM, etc.
   378     Returns None if we are unsure. Raises OSError on ENOENT, EPERM, etc.
   379     '''
   379     """
   380     return getattr(osutil, 'getfstype', lambda x: None)(dirpath)
   380     return getattr(osutil, 'getfstype', lambda x: None)(dirpath)
   381 
   381 
   382 
   382 
   383 def setbinary(fd):
   383 def setbinary(fd):
   384     pass
   384     pass
   417 normcasefallback = normcase
   417 normcasefallback = normcase
   418 
   418 
   419 if pycompat.isdarwin:
   419 if pycompat.isdarwin:
   420 
   420 
   421     def normcase(path):
   421     def normcase(path):
   422         '''
   422         """
   423         Normalize a filename for OS X-compatible comparison:
   423         Normalize a filename for OS X-compatible comparison:
   424         - escape-encode invalid characters
   424         - escape-encode invalid characters
   425         - decompose to NFD
   425         - decompose to NFD
   426         - lowercase
   426         - lowercase
   427         - omit ignored characters [200c-200f, 202a-202e, 206a-206f,feff]
   427         - omit ignored characters [200c-200f, 202a-202e, 206a-206f,feff]
   432         'cafe\\xcc\\x81'
   432         'cafe\\xcc\\x81'
   433         >>> normcase(b'\\xc3\\x89')
   433         >>> normcase(b'\\xc3\\x89')
   434         'e\\xcc\\x81'
   434         'e\\xcc\\x81'
   435         >>> normcase(b'\\xb8\\xca\\xc3\\xca\\xbe\\xc8.JPG') # issue3918
   435         >>> normcase(b'\\xb8\\xca\\xc3\\xca\\xbe\\xc8.JPG') # issue3918
   436         '%b8%ca%c3\\xca\\xbe%c8.jpg'
   436         '%b8%ca%c3\\xca\\xbe%c8.jpg'
   437         '''
   437         """
   438 
   438 
   439         try:
   439         try:
   440             return encoding.asciilower(path)  # exception for non-ASCII
   440             return encoding.asciilower(path)  # exception for non-ASCII
   441         except UnicodeDecodeError:
   441         except UnicodeDecodeError:
   442             return normcasefallback(path)
   442             return normcasefallback(path)
   473     # treated as case sensitive, even though underlying NTFS is case
   473     # treated as case sensitive, even though underlying NTFS is case
   474     # insensitive.
   474     # insensitive.
   475 
   475 
   476     # default mount points
   476     # default mount points
   477     cygwinmountpoints = sorted(
   477     cygwinmountpoints = sorted(
   478         [b"/usr/bin", b"/usr/lib", b"/cygdrive",], reverse=True
   478         [
       
   479             b"/usr/bin",
       
   480             b"/usr/lib",
       
   481             b"/cygdrive",
       
   482         ],
       
   483         reverse=True,
   479     )
   484     )
   480 
   485 
   481     # use upper-ing as normcase as same as NTFS workaround
   486     # use upper-ing as normcase as same as NTFS workaround
   482     def normcase(path):
   487     def normcase(path):
   483         pathlen = len(path)
   488         pathlen = len(path)
   551     """Return True if the stat object st is from the current user."""
   556     """Return True if the stat object st is from the current user."""
   552     return st.st_uid == os.getuid()
   557     return st.st_uid == os.getuid()
   553 
   558 
   554 
   559 
   555 def findexe(command):
   560 def findexe(command):
   556     '''Find executable for command searching like which does.
   561     """Find executable for command searching like which does.
   557     If command is a basename then PATH is searched for command.
   562     If command is a basename then PATH is searched for command.
   558     PATH isn't searched if command is an absolute or relative path.
   563     PATH isn't searched if command is an absolute or relative path.
   559     If command isn't found None is returned.'''
   564     If command isn't found None is returned."""
   560     if pycompat.sysplatform == b'OpenVMS':
   565     if pycompat.sysplatform == b'OpenVMS':
   561         return command
   566         return command
   562 
   567 
   563     def findexisting(executable):
   568     def findexisting(executable):
   564         b'Will return executable if existing file'
   569         b'Will return executable if existing file'
   585 
   590 
   586 _wantedkinds = {stat.S_IFREG, stat.S_IFLNK}
   591 _wantedkinds = {stat.S_IFREG, stat.S_IFLNK}
   587 
   592 
   588 
   593 
   589 def statfiles(files):
   594 def statfiles(files):
   590     '''Stat each file in files. Yield each stat, or None if a file does not
   595     """Stat each file in files. Yield each stat, or None if a file does not
   591     exist or has a type we don't care about.'''
   596     exist or has a type we don't care about."""
   592     lstat = os.lstat
   597     lstat = os.lstat
   593     getkind = stat.S_IFMT
   598     getkind = stat.S_IFMT
   594     for nf in files:
   599     for nf in files:
   595         try:
   600         try:
   596             st = lstat(nf)
   601             st = lstat(nf)