##// END OF EJS Templates
tests: rename "u" to more usual "ui" in test-context.py...
tests: rename "u" to more usual "ui" in test-context.py Differential Revision: https://phab.mercurial-scm.org/D6191

File last commit:

r41993:faa04f45 default
r42223:4950ae4d default
Show More
posix.py
706 lines | 22.2 KiB | text/x-python | PythonLexer
Martin Geisler
put license and copyright info into comment blocks
r8226 # posix.py - Posix utility function implementations for Mercurial
#
# Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
#
# This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Matt Mackall
util: split out posix, windows, and win32 modules
r7890
Gregory Szorc
posix: use absolute_import
r25967 from __future__ import absolute_import
import errno
import fcntl
import getpass
import grp
import os
import pwd
import re
Pierre-Yves David
util: add a simple poll utility...
r25420 import select
Gregory Szorc
posix: use absolute_import
r25967 import stat
import sys
import tempfile
import unicodedata
from .i18n import _
from . import (
encoding,
Augie Fackler
ssh: ban any username@host or host that starts with - (SEC)...
r33724 error,
Matt Harbison
util: move getfstype() to the platform modules...
r35527 policy,
Pulkit Goyal
py3: replace os.pathsep with pycompat.ospathsep...
r30612 pycompat,
Gregory Szorc
posix: use absolute_import
r25967 )
Matt Mackall
util: split out posix, windows, and win32 modules
r7890
Matt Harbison
util: move getfstype() to the platform modules...
r35527 osutil = policy.importmod(r'osutil')
Alejandro Santos
compat: use open() instead of file() everywhere
r9031 posixfile = open
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 normpath = os.path.normpath
samestat = os.path.samestat
Augie Fackler
posix: work around "posix" systems without os.link available (issue4974)...
r27236 try:
oslink = os.link
except AttributeError:
# Some platforms build Python without os.link on systems that are
# vaguely unix-like but don't have hardlink support. For those
# poor souls, just say we tried and that it failed so we fall back
# to copies.
def oslink(src, dst):
raise OSError(errno.EINVAL,
'hardlinks not supported: %s to %s' % (src, dst))
Matt Harbison
py3: convert os.readlink() path to native strings on Windows...
r39940 readlink = os.readlink
Adrian Buehlmann
reintroduces util.unlink, for POSIX and Windows....
r13280 unlink = os.unlink
Adrian Buehlmann
util: move rename into posix.py and windows.py
r9549 rename = os.rename
FUJIWARA Katsunori
util: add removedirs as platform depending function...
r24692 removedirs = os.removedirs
Matt Mackall
cmdutils: Take over glob expansion duties from util
r8614 expandglobs = False
Matt Mackall
util: split out posix, windows, and win32 modules
r7890
umask = os.umask(0)
os.umask(umask)
Bryan O'Sullivan
util: implement a faster os.path.split for posix systems...
r17560 def split(p):
Remy Blank
posix: fix split() for the case where the path is at the root of the filesystem...
r18288 '''Same as posixpath.split, but faster
>>> import posixpath
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> for f in [b'/absolute/path/to/file',
... b'relative/path/to/file',
... b'file_alone',
... b'path/to/directory/',
... b'/multiple/path//separators',
... b'/file_at_root',
... b'///multiple_leading_separators_at_root',
... b'']:
Remy Blank
posix: fix split() for the case where the path is at the root of the filesystem...
r18288 ... assert split(f) == posixpath.split(f), f
'''
Bryan O'Sullivan
util: implement a faster os.path.split for posix systems...
r17560 ht = p.rsplit('/', 1)
if len(ht) == 1:
return '', p
nh = ht[0].rstrip('/')
if nh:
return nh, ht[1]
Remy Blank
posix: fix split() for the case where the path is at the root of the filesystem...
r18288 return ht[0] + '/', ht[1]
Bryan O'Sullivan
util: implement a faster os.path.split for posix systems...
r17560
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 def openhardlinks():
'''return true if it is safe to hold open file handles to hardlinks'''
return True
Adrian Buehlmann
port win32.py to using the Python ctypes library...
r13375 def nlinks(name):
'''return number of hardlinks for the given file'''
return os.lstat(name).st_nlink
Adrian Buehlmann
rename util.parse_patch_output to parsepatchoutput
r14231 def parsepatchoutput(output_line):
timeless
Generally replace "file name" with "filename" in help and comments.
r8761 """parses the output produced by patch and returns the filename"""
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 pf = output_line[14:]
Pulkit Goyal
py3: replace sys.platform with pycompat.sysplatform (part 2 of 2)
r30642 if pycompat.sysplatform == 'OpenVMS':
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 if pf[0] == '`':
pf = pf[1:-1] # Remove the quotes
else:
Peter Arrenbrecht
whitespace cleanup
r8219 if pf.startswith("'") and pf.endswith("'") and " " in pf:
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 pf = pf[1:-1] # Remove the quotes
return pf
def sshargs(sshcmd, host, user, port):
'''Build argument list for ssh'''
args = user and ("%s@%s" % (user, host)) or host
Jun Wu
ssh: quote parameters using shellquote (SEC)...
r33732 if '-' in args[:1]:
Augie Fackler
ssh: ban any username@host or host that starts with - (SEC)...
r33724 raise error.Abort(
_('illegal ssh hostname or username starting with -: %s') % args)
Jun Wu
ssh: quote parameters using shellquote (SEC)...
r33732 args = shellquote(args)
if port:
args = '-p %s %s' % (shellquote(port), args)
return args
Matt Mackall
util: split out posix, windows, and win32 modules
r7890
Adrian Buehlmann
rename util.is_exec to isexec
r14273 def isexec(f):
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 """check whether a file is executable"""
Gregory Szorc
global: mass rewrite to use modern octal syntax...
r25658 return (os.lstat(f).st_mode & 0o100 != 0)
Matt Mackall
util: split out posix, windows, and win32 modules
r7890
Adrian Buehlmann
rename util.set_flags to setflags
r14232 def setflags(f, l, x):
Koen Van Hoof
chmod: create a new file when flags are set on a hardlinked file...
r32721 st = os.lstat(f)
s = st.st_mode
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 if l:
if not stat.S_ISLNK(s):
# switch file to link
Pulkit Goyal
py3: make sure we open the files in bytes mode...
r36321 fp = open(f, 'rb')
Dan Villiom Podlaski Christiansen
explicitly close files...
r13400 data = fp.read()
fp.close()
Ryan McElroy
posix: use local reference to unlink...
r31537 unlink(f)
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 try:
os.symlink(data, f)
Idan Kamara
eliminate various naked except clauses
r14004 except OSError:
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 # failed to make a link, rewrite file
Pulkit Goyal
py3: make sure we open the files in bytes mode...
r36321 fp = open(f, "wb")
Dan Villiom Podlaski Christiansen
explicitly close files...
r13400 fp.write(data)
fp.close()
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 # no chmod needed at this point
return
if stat.S_ISLNK(s):
# switch link to file
data = os.readlink(f)
Ryan McElroy
posix: use local reference to unlink...
r31537 unlink(f)
Pulkit Goyal
py3: make sure we open the files in bytes mode...
r36321 fp = open(f, "wb")
Dan Villiom Podlaski Christiansen
explicitly close files...
r13400 fp.write(data)
fp.close()
Gregory Szorc
global: mass rewrite to use modern octal syntax...
r25658 s = 0o666 & ~umask # avoid restatting for chmod
Matt Mackall
util: split out posix, windows, and win32 modules
r7890
Gregory Szorc
global: mass rewrite to use modern octal syntax...
r25658 sx = s & 0o100
Koen Van Hoof
chmod: create a new file when flags are set on a hardlinked file...
r32721 if st.st_nlink > 1 and bool(x) != bool(sx):
# the file is a hardlink, break it
with open(f, "rb") as fp:
data = fp.read()
unlink(f)
with open(f, "wb") as fp:
fp.write(data)
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 if x and not sx:
# Turn on +x for every +r bit when making a file executable
# and obey umask.
Gregory Szorc
global: mass rewrite to use modern octal syntax...
r25658 os.chmod(f, s | (s & 0o444) >> 2 & ~umask)
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 elif not x and sx:
# Turn off all +x bits
Gregory Szorc
global: mass rewrite to use modern octal syntax...
r25658 os.chmod(f, s & 0o666)
Matt Mackall
util: split out posix, windows, and win32 modules
r7890
Boris Feld
update: fix edge-case with update.atomic-file and read-only files...
r41325 def copymode(src, dst, mode=None, enforcewritable=False):
Adrian Buehlmann
util: move copymode into posix.py and windows.py...
r15011 '''Copy the file mode from the file at path src to dst.
If src doesn't exist, we're using mode instead. If mode is None, we're
using umask.'''
try:
Gregory Szorc
global: mass rewrite to use modern octal syntax...
r25658 st_mode = os.lstat(src).st_mode & 0o777
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except OSError as inst:
Adrian Buehlmann
util: move copymode into posix.py and windows.py...
r15011 if inst.errno != errno.ENOENT:
raise
st_mode = mode
if st_mode is None:
st_mode = ~umask
Gregory Szorc
global: mass rewrite to use modern octal syntax...
r25658 st_mode &= 0o666
Boris Feld
update: fix edge-case with update.atomic-file and read-only files...
r41325
new_mode = st_mode
if enforcewritable:
new_mode |= stat.S_IWUSR
os.chmod(dst, new_mode)
Adrian Buehlmann
util: move copymode into posix.py and windows.py...
r15011
Adrian Buehlmann
util: move checkexec() to posix.py and return False on Windows
r13879 def checkexec(path):
"""
Check whether the given path is on a filesystem with UNIX-like exec flags
Requires a directory (like /foo/.hg)
"""
# VFAT on some Linux versions can flip mode but it doesn't persist
# a FS remount. Frequently we can detect it if files are created
# with exec bit on.
try:
EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
Boris Feld
checkexec: create destination directory if necessary...
r40703 basedir = os.path.join(path, '.hg')
Boris Feld
check-exec: write file in 'wcache' instead of 'cache'...
r40823 cachedir = os.path.join(basedir, 'wcache')
Boris Feld
checkexec: create destination directory if necessary...
r40703 storedir = os.path.join(basedir, 'store')
if not os.path.exists(cachedir):
try:
# we want to create the 'cache' directory, not the '.hg' one.
# Automatically creating '.hg' directory could silently spawn
# invalid Mercurial repositories. That seems like a bad idea.
os.mkdir(cachedir)
if os.path.exists(storedir):
copymode(storedir, cachedir)
else:
copymode(basedir, cachedir)
except (IOError, OSError):
# we other fallback logic triggers
pass
Mads Kiilerich
posix: give checkexec a fast path; keep the check files and test read only...
r30446 if os.path.isdir(cachedir):
checkisexec = os.path.join(cachedir, 'checkisexec')
checknoexec = os.path.join(cachedir, 'checknoexec')
try:
m = os.stat(checkisexec).st_mode
except OSError as e:
if e.errno != errno.ENOENT:
raise
# checkisexec does not exist - fall through ...
else:
# checkisexec exists, check if it actually is exec
if m & EXECFLAGS != 0:
# ensure checkisexec exists, check it isn't exec
try:
m = os.stat(checknoexec).st_mode
except OSError as e:
if e.errno != errno.ENOENT:
raise
Augie Fackler
posix: use open() instead of file()
r31505 open(checknoexec, 'w').close() # might fail
Mads Kiilerich
posix: give checkexec a fast path; keep the check files and test read only...
r30446 m = os.stat(checknoexec).st_mode
if m & EXECFLAGS == 0:
# check-exec is exec and check-no-exec is not exec
return True
# checknoexec exists but is exec - delete it
Ryan McElroy
posix: use local reference to unlink...
r31537 unlink(checknoexec)
Mads Kiilerich
posix: give checkexec a fast path; keep the check files and test read only...
r30446 # checkisexec exists but is not exec - delete it
Ryan McElroy
posix: use local reference to unlink...
r31537 unlink(checkisexec)
Mads Kiilerich
posix: give checkexec a fast path; keep the check files and test read only...
r30446
# check using one file, leave it as checkisexec
checkdir = cachedir
else:
# check directly in path and don't leave checkisexec behind
checkdir = path
checkisexec = None
Yuya Nishihara
py3: wrap tempfile.mkstemp() to use bytes path...
r38182 fh, fn = pycompat.mkstemp(dir=checkdir, prefix='hg-checkexec-')
Adrian Buehlmann
util: move checkexec() to posix.py and return False on Windows
r13879 try:
os.close(fh)
Mads Kiilerich
posix: simplify checkexec check...
r30445 m = os.stat(fn).st_mode
Mads Kiilerich
posix: give checkexec a fast path; keep the check files and test read only...
r30446 if m & EXECFLAGS == 0:
os.chmod(fn, m & 0o777 | EXECFLAGS)
if os.stat(fn).st_mode & EXECFLAGS != 0:
if checkisexec is not None:
os.rename(fn, checkisexec)
fn = None
return True
Adrian Buehlmann
util: move checkexec() to posix.py and return False on Windows
r13879 finally:
Mads Kiilerich
posix: give checkexec a fast path; keep the check files and test read only...
r30446 if fn is not None:
Ryan McElroy
posix: use local reference to unlink...
r31537 unlink(fn)
Adrian Buehlmann
util: move checkexec() to posix.py and return False on Windows
r13879 except (IOError, OSError):
# we don't care, the user probably won't be able to commit anyway
return False
Adrian Buehlmann
util: move checklink() to posix.py and return False on Windows...
r13890 def checklink(path):
"""check whether the given path is on a symlink-capable filesystem"""
# mktemp is not racy because symlink creation will fail if the
# file already exists
Matt Mackall
posix: retry on symlink race in checklink...
r26883 while True:
Boris Feld
check-exec: write file in 'wcache' instead of 'cache'...
r40823 cachedir = os.path.join(path, '.hg', 'wcache')
Mads Kiilerich
posix: give checklink a fast path that cache the check file and is read only...
r30448 checklink = os.path.join(cachedir, 'checklink')
# try fast path, read only
if os.path.islink(checklink):
return True
Mads Kiilerich
posix: move checklink test file to .hg/cache...
r30447 if os.path.isdir(cachedir):
checkdir = cachedir
else:
checkdir = path
cachedir = None
Yuya Nishihara
py3: wrap tempfile.NamedTemporaryFile() to return bytes fp.name...
r38184 name = tempfile.mktemp(dir=pycompat.fsdecode(checkdir),
Augie Fackler
posix: tiptoe around tempfile module more delicately...
r31506 prefix=r'checklink-')
name = pycompat.fsencode(name)
Augie Fackler
checklink: always close the NamedTemporaryFile...
r22946 try:
Martijn Pieters
posix: give the cached symlink a real target...
r30555 fd = None
if cachedir is None:
Yuya Nishihara
py3: wrap tempfile.NamedTemporaryFile() to return bytes fp.name...
r38184 fd = pycompat.namedtempfile(dir=checkdir,
prefix='hg-checklink-')
target = os.path.basename(fd.name)
Martijn Pieters
posix: give the cached symlink a real target...
r30555 else:
# create a fixed file to link to; doesn't matter if it
# already exists.
target = 'checklink-target'
Augie Fackler
checklink: degrade gracefully on posix when fs is readonly (issue5511)...
r32393 try:
Augie Fackler
cleanup: fix some latent open(path).read() et al calls we previously missed...
r36966 fullpath = os.path.join(cachedir, target)
open(fullpath, 'w').close()
Augie Fackler
checklink: degrade gracefully on posix when fs is readonly (issue5511)...
r32393 except IOError as inst:
if inst[0] == errno.EACCES:
# If we can't write to cachedir, just pretend
# that the fs is readonly and by association
# that the fs won't support symlinks. This
# seems like the least dangerous way to avoid
# data loss.
return False
raise
Matt Mackall
posix: retry on symlink race in checklink...
r26883 try:
Martijn Pieters
posix: give the cached symlink a real target...
r30555 os.symlink(target, name)
Mads Kiilerich
posix: give checklink a fast path that cache the check file and is read only...
r30448 if cachedir is None:
Ryan McElroy
posix: use local reference to unlink...
r31537 unlink(name)
Mads Kiilerich
posix: give checklink a fast path that cache the check file and is read only...
r30448 else:
try:
os.rename(name, checklink)
except OSError:
Ryan McElroy
posix: use local reference to unlink...
r31537 unlink(name)
Matt Mackall
posix: retry on symlink race in checklink...
r26883 return True
except OSError as inst:
# link creation might race, try again
Augie Fackler
posix: use inst.errno instead of inst[0] on OSError instances...
r37953 if inst.errno == errno.EEXIST:
Matt Mackall
posix: retry on symlink race in checklink...
r26883 continue
Matt Mackall
posix: fix test-permissions regression
r26889 raise
Matt Mackall
posix: retry on symlink race in checklink...
r26883 finally:
Martijn Pieters
posix: give the cached symlink a real target...
r30555 if fd is not None:
fd.close()
Matt Mackall
posix: retry on symlink race in checklink...
r26883 except AttributeError:
return False
Matt Mackall
posix: fix test-permissions regression
r26889 except OSError as inst:
# sshfs might report failure while successfully creating the link
Augie Fackler
posix: use inst.errno instead of inst[0] on OSError instances...
r37953 if inst.errno == errno.EIO and os.path.exists(name):
Ryan McElroy
posix: use local reference to unlink...
r31537 unlink(name)
Matt Mackall
posix: fix test-permissions regression
r26889 return False
Adrian Buehlmann
util: move checklink() to posix.py and return False on Windows...
r13890
Adrian Buehlmann
path_auditor: check filenames for basic platform validity (issue2755)...
r13916 def checkosfilename(path):
'''Check that the base-relative path is a valid filename on this platform.
Returns None if the path is ok, or a UI string describing the problem.'''
Augie Fackler
posix: replace superfluous pass statement with explicit return
r34382 return None # on posix platforms, every path is ok
Adrian Buehlmann
path_auditor: check filenames for basic platform validity (issue2755)...
r13916
Matt Harbison
util: add a function to show the mount point of the filesystem...
r35531 def getfsmountpoint(dirpath):
'''Get the filesystem mount point from a directory (best-effort)
Returns None if we are unsure. Raises OSError on ENOENT, EPERM, etc.
'''
return getattr(osutil, 'getfsmountpoint', lambda x: None)(dirpath)
Matt Harbison
util: move getfstype() to the platform modules...
r35527 def getfstype(dirpath):
'''Get the filesystem type name from a directory (best-effort)
Returns None if we are unsure. Raises OSError on ENOENT, EPERM, etc.
'''
return getattr(osutil, 'getfstype', lambda x: None)(dirpath)
Adrian Buehlmann
rename util.set_binary to setbinary
r14233 def setbinary(fd):
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 pass
def pconvert(path):
return path
def localpath(path):
return path
Siddharth Agarwal
Add support for relinking on Windows....
r10218 def samefile(fpath1, fpath2):
"""Returns whether path1 and path2 refer to the same file. This is only
guaranteed to work for files, not directories."""
return os.path.samefile(fpath1, fpath2)
def samedevice(fpath1, fpath2):
"""Returns whether fpath1 and fpath2 are on the same device. This is only
guaranteed to work for files, not directories."""
st1 = os.lstat(fpath1)
st2 = os.lstat(fpath2)
return st1.st_dev == st2.st_dev
Matt Mackall
dirstate: fix case-folding identity for traditional Unix...
r15488 # os.path.normcase is a no-op, which doesn't help us on non-native filesystems
def normcase(path):
return path.lower()
Siddharth Agarwal
posix: define normcase spec and fallback...
r24594 # what normcase does to ASCII strings
normcasespec = encoding.normcasespecs.lower
# fallback normcase function for non-ASCII strings
normcasefallback = normcase
Jun Wu
codemod: use pycompat.isdarwin...
r34648 if pycompat.isdarwin:
Matt Mackall
posix: add extended support for OS X path folding...
r15551
def normcase(path):
Matt Mackall
hfs+: rewrite percent-escaper (issue3918)...
r19131 '''
Normalize a filename for OS X-compatible comparison:
- escape-encode invalid characters
- decompose to NFD
- lowercase
Augie Fackler
darwin: omit ignorable codepoints when normcase()ing a file path...
r23597 - omit ignored characters [200c-200f, 202a-202e, 206a-206f,feff]
Matt Mackall
hfs+: rewrite percent-escaper (issue3918)...
r19131
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> normcase(b'UPPER')
Matt Mackall
hfs+: rewrite percent-escaper (issue3918)...
r19131 'upper'
Augie Fackler
posix: fix HFS+ normcase doctest to produce valid bytes literals in Python 3...
r34196 >>> normcase(b'Caf\\xc3\\xa9')
Matt Mackall
hfs+: rewrite percent-escaper (issue3918)...
r19131 'cafe\\xcc\\x81'
Augie Fackler
posix: fix HFS+ normcase doctest to produce valid bytes literals in Python 3...
r34196 >>> normcase(b'\\xc3\\x89')
Matt Mackall
hfs+: rewrite percent-escaper (issue3918)...
r19131 'e\\xcc\\x81'
Augie Fackler
posix: fix HFS+ normcase doctest to produce valid bytes literals in Python 3...
r34196 >>> normcase(b'\\xb8\\xca\\xc3\\xca\\xbe\\xc8.JPG') # issue3918
Matt Mackall
hfs+: rewrite percent-escaper (issue3918)...
r19131 '%b8%ca%c3\\xca\\xbe%c8.jpg'
'''
Matt Mackall
posix: add extended support for OS X path folding...
r15551 try:
Siddharth Agarwal
normcase: for darwin, use fast ASCII lower...
r22781 return encoding.asciilower(path) # exception for non-ASCII
Mads Kiilerich
OS X: try cheap ascii .lower() in normcase before making full unicode dance...
r18501 except UnicodeDecodeError:
Siddharth Agarwal
darwin: define normcase spec and fallback...
r24595 return normcasefallback(path)
normcasespec = encoding.normcasespecs.lower
def normcasefallback(path):
Mads Kiilerich
OS X: try cheap ascii .lower() in normcase before making full unicode dance...
r18501 try:
Matt Mackall
posix: add extended support for OS X path folding...
r15551 u = path.decode('utf-8')
except UnicodeDecodeError:
Matt Mackall
hfs+: rewrite percent-escaper (issue3918)...
r19131 # OS X percent-encodes any bytes that aren't valid utf-8
s = ''
Matt Mackall
posix: use getutf8char to handle OS X filename percent-escaping...
r26876 pos = 0
Matt Mackall
mac: fix percent-encoding of non-utf-8 characters (issue4999)
r27380 l = len(path)
Matt Mackall
posix: use getutf8char to handle OS X filename percent-escaping...
r26876 while pos < l:
try:
c = encoding.getutf8char(path, pos)
pos += len(c)
except ValueError:
Augie Fackler
posix: use slicing to grab a single byte out of a bytes in HFS+ normcase code
r34198 c = '%%%02X' % ord(path[pos:pos + 1])
Matt Mackall
posix: use getutf8char to handle OS X filename percent-escaping...
r26876 pos += 1
s += c
Matt Mackall
hfs+: rewrite percent-escaper (issue3918)...
r19131
Matt Mackall
posix: add extended support for OS X path folding...
r15551 u = s.decode('utf-8')
# Decompose then lowercase (HFS+ technote specifies lower)
Augie Fackler
posix: always pass a native str to unicodedata.normalize's first arg
r34199 enc = unicodedata.normalize(r'NFD', u).lower().encode('utf-8')
Augie Fackler
darwin: omit ignorable codepoints when normcase()ing a file path...
r23597 # drop HFS+ ignored characters
return encoding.hfsignoreclean(enc)
Matt Mackall
posix: add extended support for OS X path folding...
r15551
Pulkit Goyal
py3: replace sys.platform with pycompat.sysplatform (part 1 of 2)...
r30641 if pycompat.sysplatform == 'cygwin':
FUJIWARA Katsunori
cygwin: add cygwin specific normcase logic...
r15711 # workaround for cygwin, in which mount point part of path is
# treated as case sensitive, even though underlying NTFS is case
# insensitive.
# default mount points
cygwinmountpoints = sorted([
"/usr/bin",
"/usr/lib",
"/cygdrive",
], reverse=True)
# use upper-ing as normcase as same as NTFS workaround
def normcase(path):
pathlen = len(path)
Pulkit Goyal
py3: replace os.sep with pycompat.ossep (part 2 of 4)...
r30614 if (pathlen == 0) or (path[0] != pycompat.ossep):
FUJIWARA Katsunori
cygwin: add cygwin specific normcase logic...
r15711 # treat as relative
Adrian Buehlmann
util, posix: eliminate encodinglower and encodingupper...
r17203 return encoding.upper(path)
FUJIWARA Katsunori
cygwin: add cygwin specific normcase logic...
r15711
# to preserve case of mountpoint part
for mp in cygwinmountpoints:
if not path.startswith(mp):
continue
mplen = len(mp)
if mplen == pathlen: # mount point itself
return mp
Pulkit Goyal
py3: replace os.sep with pycompat.ossep (part 2 of 4)...
r30614 if path[mplen] == pycompat.ossep:
Adrian Buehlmann
util, posix: eliminate encodinglower and encodingupper...
r17203 return mp + encoding.upper(path[mplen:])
FUJIWARA Katsunori
cygwin: add cygwin specific normcase logic...
r15711
Adrian Buehlmann
util, posix: eliminate encodinglower and encodingupper...
r17203 return encoding.upper(path)
FUJIWARA Katsunori
cygwin: add cygwin specific normcase logic...
r15711
Siddharth Agarwal
cygwin: define normcase spec and fallback...
r24596 normcasespec = encoding.normcasespecs.other
normcasefallback = normcase
A. S. Budden
posix: ignore execution bit in cygwin (issue3301)
r16240 # Cygwin translates native ACLs to POSIX permissions,
# but these translations are not supported by native
# tools, so the exec bit tends to be set erroneously.
# Therefore, disable executable bit access on Cygwin.
def checkexec(path):
return False
Matt Mackall
posix: disable cygwin's symlink emulation
r16241 # Similarly, Cygwin's symlink emulation is likely to create
# problems when Mercurial is used from both Cygwin and native
# Windows, with other native tools, or on shared volumes
def checklink(path):
return False
FUJIWARA Katsunori
posix: quote the specified string only when it may have to be quoted...
r23683 _needsshellquote = None
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 def shellquote(s):
Pulkit Goyal
py3: replace sys.platform with pycompat.sysplatform (part 2 of 2)
r30642 if pycompat.sysplatform == 'OpenVMS':
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 return '"%s"' % s
FUJIWARA Katsunori
posix: quote the specified string only when it may have to be quoted...
r23683 global _needsshellquote
if _needsshellquote is None:
Pulkit Goyal
py3: make the regular expression bytes to prevent TypeError
r31491 _needsshellquote = re.compile(br'[^a-zA-Z0-9._/+-]').search
Yuya Nishihara
shellquote: fix missing quotes for empty string...
r24108 if s and not _needsshellquote(s):
FUJIWARA Katsunori
posix: quote the specified string only when it may have to be quoted...
r23683 # "s" shouldn't have to be quoted
return s
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 else:
return "'%s'" % s.replace("'", "'\\''")
Yuya Nishihara
util: factor out shellsplit() function...
r36433 def shellsplit(s):
"""Parse a command string in POSIX shell way (best-effort)"""
return pycompat.shlexsplit(s, posix=True)
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 def quotecommand(cmd):
return cmd
def testpid(pid):
'''return False if pid dead, True if running or not sure'''
Pulkit Goyal
py3: replace sys.platform with pycompat.sysplatform (part 2 of 2)
r30642 if pycompat.sysplatform == 'OpenVMS':
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 return True
try:
os.kill(pid, 0)
return True
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except OSError as inst:
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 return inst.errno != errno.ESRCH
Martin Geisler
posix: do not use fstat in isowner...
r8657 def isowner(st):
"""Return True if the stat object st is from the current user."""
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 return st.st_uid == os.getuid()
Adrian Buehlmann
rename util.find_exe to findexe
r14271 def findexe(command):
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 '''Find executable for command searching like which does.
If command is a basename then PATH is searched for command.
PATH isn't searched if command is an absolute or relative path.
If command isn't found None is returned.'''
Pulkit Goyal
py3: replace sys.platform with pycompat.sysplatform (part 1 of 2)...
r30641 if pycompat.sysplatform == 'OpenVMS':
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 return command
def findexisting(executable):
'Will return executable if existing file'
Marc-Antoine Ruel
posix: fix findexe() to check for file type and access
r15499 if os.path.isfile(executable) and os.access(executable, os.X_OK):
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 return executable
return None
Pulkit Goyal
py3: replace os.sep with pycompat.ossep (part 2 of 4)...
r30614 if pycompat.ossep in command:
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 return findexisting(command)
Pulkit Goyal
py3: replace sys.platform with pycompat.sysplatform (part 1 of 2)...
r30641 if pycompat.sysplatform == 'plan9':
Steven Stallion
plan9: initial support for plan 9 from bell labs...
r16383 return findexisting(os.path.join('/bin', command))
Pulkit Goyal
py3: replace os.environ with encoding.environ (part 1 of 5)...
r30634 for path in encoding.environ.get('PATH', '').split(pycompat.ospathsep):
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 executable = findexisting(os.path.join(path, command))
if executable is not None:
Marc-Antoine Ruel
posix: fix findexe() to check for file type and access
r15499 return executable
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 return None
Adrian Buehlmann
rename util.set_signal_handler to setsignalhandler
r14237 def setsignalhandler():
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 pass
Martin von Zweigbergk
cleanup: use set literals...
r32291 _wantedkinds = {stat.S_IFREG, stat.S_IFLNK}
Bryan O'Sullivan
dirstate: move file type filtering to its source...
r18017
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 def statfiles(files):
Bryan O'Sullivan
dirstate: move file type filtering to its source...
r18017 '''Stat each file in files. Yield each stat, or None if a file does not
exist or has a type we don't care about.'''
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 lstat = os.lstat
Bryan O'Sullivan
dirstate: move file type filtering to its source...
r18017 getkind = stat.S_IFMT
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 for nf in files:
try:
st = lstat(nf)
Bryan O'Sullivan
dirstate: move file type filtering to its source...
r18017 if getkind(st.st_mode) not in _wantedkinds:
st = None
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except OSError as err:
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 if err.errno not in (errno.ENOENT, errno.ENOTDIR):
raise
st = None
yield st
def getuser():
'''return name of current user'''
Pulkit Goyal
py3: make posix.getuser return a bytes
r32129 return pycompat.fsencode(getpass.getuser())
Matt Mackall
util: split out posix, windows, and win32 modules
r7890
def username(uid=None):
"""Return the name of the user with the given uid.
If uid is None, return the name of the current user."""
if uid is None:
uid = os.getuid()
try:
Pulkit Goyal
py3: make sure util.username() always returns bytes...
r38271 return pycompat.fsencode(pwd.getpwuid(uid)[0])
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 except KeyError:
Pulkit Goyal
py3: make sure util.username() always returns bytes...
r38271 return b'%d' % uid
Matt Mackall
util: split out posix, windows, and win32 modules
r7890
def groupname(gid=None):
"""Return the name of the group with the given gid.
If gid is None, return the name of the current group."""
if gid is None:
gid = os.getgid()
try:
Pulkit Goyal
py3: make sure return value of posix.groupname() is bytes...
r41993 return pycompat.fsencode(grp.getgrgid(gid)[0])
Matt Mackall
util: split out posix, windows, and win32 modules
r7890 except KeyError:
Pulkit Goyal
py3: make sure return value of posix.groupname() is bytes...
r41993 return pycompat.bytestr(gid)
Patrick Mezard
serve: add and use portable spawnvp replacement...
r10237
Patrick Mezard
acl: grp module is not available on windows
r11138 def groupmembers(name):
"""Return the list of members of the group with the given
name, KeyError if the group does not exist.
"""
Pulkit Goyal
py3: do a fsdecode(), fsencode() dance in posix.py...
r41664 name = pycompat.fsdecode(name)
return pycompat.rapply(pycompat.fsencode, list(grp.getgrnam(name).gr_mem))
Patrick Mezard
acl: grp module is not available on windows
r11138
Patrick Mezard
serve: add and use portable spawnvp replacement...
r10237 def spawndetached(args):
return os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
args[0], args)
Patrick Mezard
Find right hg command for detached process...
r10239 def gethgcmd():
return sys.argv[:1]
Patrick Mezard
util: fix default termwidth() under Windows...
r11010
Adrian Buehlmann
util: move "default" makedir to posix.py...
r14908 def makedir(path, notindexed):
os.mkdir(path)
Adrian Buehlmann
util: move "default" unlinkpath to posix.py...
r14909
Adrian Buehlmann
util: move "default" lookupreg to posix.py...
r14910 def lookupreg(key, name=None, scope=None):
return None
Adrian Buehlmann
util: move "default" hidewindow to posix.py...
r14911
def hidewindow():
"""Hide current shell window.
Used to hide the window opened when starting asynchronous
child process under Windows, unneeded on other systems.
"""
pass
Adrian Buehlmann
util: eliminate wildcard imports
r14926
Idan Kamara
posix, windows: introduce cachestat...
r14927 class cachestat(object):
def __init__(self, path):
self.stat = os.stat(path)
def cacheable(self):
return bool(self.stat.st_ino)
Martin Geisler
Use explicit integer division...
r15791 __hash__ = object.__hash__
Idan Kamara
posix, windows: introduce cachestat...
r14927 def __eq__(self, other):
try:
Siddharth Agarwal
posix: don't compare atime when determining if a file has changed...
r18442 # Only dev, ino, size, mtime and atime are likely to change. Out
# of these, we shouldn't compare atime but should compare the
# rest. However, one of the other fields changing indicates
# something fishy going on, so return False if anything but atime
# changes.
return (self.stat.st_mode == other.stat.st_mode and
self.stat.st_ino == other.stat.st_ino and
self.stat.st_dev == other.stat.st_dev and
self.stat.st_nlink == other.stat.st_nlink and
self.stat.st_uid == other.stat.st_uid and
self.stat.st_gid == other.stat.st_gid and
self.stat.st_size == other.stat.st_size and
Augie Fackler
cleanup: use stat_result[stat.ST_MTIME] instead of stat_result.st_mtime...
r36799 self.stat[stat.ST_MTIME] == other.stat[stat.ST_MTIME] and
self.stat[stat.ST_CTIME] == other.stat[stat.ST_CTIME])
Idan Kamara
posix, windows: introduce cachestat...
r14927 except AttributeError:
return False
def __ne__(self, other):
return not self == other
Bryan O'Sullivan
util: add functions to check symlink/exec bits...
r18868 def statislink(st):
'''check whether a stat result is a symlink'''
return st and stat.S_ISLNK(st.st_mode)
def statisexec(st):
'''check whether a stat result is an executable file'''
Gregory Szorc
global: mass rewrite to use modern octal syntax...
r25658 return st and (st.st_mode & 0o100 != 0)
Gregory Szorc
platform: implement readpipe()...
r22245
Pierre-Yves David
util: add a simple poll utility...
r25420 def poll(fds):
"""block until something happens on any file descriptor
This is a generic helper that will check for any activity
(read, write. exception) and return the list of touched files.
In unsupported cases, it will raise a NotImplementedError"""
try:
Yuya Nishihara
posix: make poll() restart on interruption by signal (issue5452)...
r30654 while True:
try:
res = select.select(fds, fds, fds)
break
except select.error as inst:
if inst.args[0] == errno.EINTR:
continue
raise
Pierre-Yves David
util: add a simple poll utility...
r25420 except ValueError: # out of range file descriptor
raise NotImplementedError()
return sorted(list(set(sum(res, []))))
Gregory Szorc
platform: implement readpipe()...
r22245 def readpipe(pipe):
"""Read all available data from a pipe."""
Gregory Szorc
posix: implement readpipe using non-blocking I/O (issue4336)...
r22246 # We can't fstat() a pipe because Linux will always report 0.
# So, we set the pipe to non-blocking mode and read everything
# that's available.
flags = fcntl.fcntl(pipe, fcntl.F_GETFL)
flags |= os.O_NONBLOCK
oldflags = fcntl.fcntl(pipe, fcntl.F_SETFL, flags)
Gregory Szorc
platform: implement readpipe()...
r22245
Gregory Szorc
posix: implement readpipe using non-blocking I/O (issue4336)...
r22246 try:
chunks = []
while True:
try:
s = pipe.read()
if not s:
break
chunks.append(s)
except IOError:
break
return ''.join(chunks)
finally:
fcntl.fcntl(pipe, fcntl.F_SETFL, oldflags)
Yuya Nishihara
chgserver: extract utility to bind unix domain socket to long path...
r29530
def bindunixsocket(sock, path):
"""Bind the UNIX domain socket to the specified path"""
# use relative path instead of full path at bind() if possible, since
# AF_UNIX path has very small length limit (107 chars) on common
# platforms (see sys/un.h)
dirname, basename = os.path.split(path)
bakwdfd = None
if dirname:
bakwdfd = os.open('.', os.O_DIRECTORY)
os.chdir(dirname)
sock.bind(basename)
if bakwdfd:
os.fchdir(bakwdfd)
os.close(bakwdfd)