Mercurial > public > mercurial-scm > hg
comparison mercurial/posix.py @ 43076:2372284d9457
formatting: blacken the codebase
This is using my patch to black
(https://github.com/psf/black/pull/826) so we don't un-wrap collection
literals.
Done with:
hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S
# skip-blame mass-reformatting only
# no-check-commit reformats foo_bar functions
Differential Revision: https://phab.mercurial-scm.org/D6971
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:45:02 -0400 |
parents | 97ada9b8d51b |
children | 687b865b95ad |
comparison
equal
deleted
inserted
replaced
43075:57875cf423c9 | 43076:2372284d9457 |
---|---|
38 # Some platforms build Python without os.link on systems that are | 38 # Some platforms build Python without os.link on systems that are |
39 # vaguely unix-like but don't have hardlink support. For those | 39 # vaguely unix-like but don't have hardlink support. For those |
40 # poor souls, just say we tried and that it failed so we fall back | 40 # poor souls, just say we tried and that it failed so we fall back |
41 # to copies. | 41 # to copies. |
42 def oslink(src, dst): | 42 def oslink(src, dst): |
43 raise OSError(errno.EINVAL, | 43 raise OSError( |
44 'hardlinks not supported: %s to %s' % (src, dst)) | 44 errno.EINVAL, 'hardlinks not supported: %s to %s' % (src, dst) |
45 ) | |
46 | |
47 | |
45 readlink = os.readlink | 48 readlink = os.readlink |
46 unlink = os.unlink | 49 unlink = os.unlink |
47 rename = os.rename | 50 rename = os.rename |
48 removedirs = os.removedirs | 51 removedirs = os.removedirs |
49 expandglobs = False | 52 expandglobs = False |
50 | 53 |
51 umask = os.umask(0) | 54 umask = os.umask(0) |
52 os.umask(umask) | 55 os.umask(umask) |
53 | 56 |
54 if not pycompat.ispy3: | 57 if not pycompat.ispy3: |
58 | |
55 def posixfile(name, mode=r'r', buffering=-1): | 59 def posixfile(name, mode=r'r', buffering=-1): |
56 fp = open(name, mode=mode, buffering=buffering) | 60 fp = open(name, mode=mode, buffering=buffering) |
57 # The position when opening in append mode is implementation defined, so | 61 # The position when opening in append mode is implementation defined, so |
58 # make it consistent by always seeking to the end. | 62 # make it consistent by always seeking to the end. |
59 if r'a' in mode: | 63 if r'a' in mode: |
60 fp.seek(0, os.SEEK_END) | 64 fp.seek(0, os.SEEK_END) |
61 return fp | 65 return fp |
66 | |
67 | |
62 else: | 68 else: |
63 # The underlying file object seeks as required in Python 3: | 69 # The underlying file object seeks as required in Python 3: |
64 # https://github.com/python/cpython/blob/v3.7.3/Modules/_io/fileio.c#L474 | 70 # https://github.com/python/cpython/blob/v3.7.3/Modules/_io/fileio.c#L474 |
65 posixfile = open | 71 posixfile = open |
72 | |
66 | 73 |
67 def split(p): | 74 def split(p): |
68 '''Same as posixpath.split, but faster | 75 '''Same as posixpath.split, but faster |
69 | 76 |
70 >>> import posixpath | 77 >>> import posixpath |
84 nh = ht[0].rstrip('/') | 91 nh = ht[0].rstrip('/') |
85 if nh: | 92 if nh: |
86 return nh, ht[1] | 93 return nh, ht[1] |
87 return ht[0] + '/', ht[1] | 94 return ht[0] + '/', ht[1] |
88 | 95 |
96 | |
89 def openhardlinks(): | 97 def openhardlinks(): |
90 '''return true if it is safe to hold open file handles to hardlinks''' | 98 '''return true if it is safe to hold open file handles to hardlinks''' |
91 return True | 99 return True |
92 | 100 |
101 | |
93 def nlinks(name): | 102 def nlinks(name): |
94 '''return number of hardlinks for the given file''' | 103 '''return number of hardlinks for the given file''' |
95 return os.lstat(name).st_nlink | 104 return os.lstat(name).st_nlink |
105 | |
96 | 106 |
97 def parsepatchoutput(output_line): | 107 def parsepatchoutput(output_line): |
98 """parses the output produced by patch and returns the filename""" | 108 """parses the output produced by patch and returns the filename""" |
99 pf = output_line[14:] | 109 pf = output_line[14:] |
100 if pycompat.sysplatform == 'OpenVMS': | 110 if pycompat.sysplatform == 'OpenVMS': |
101 if pf[0] == '`': | 111 if pf[0] == '`': |
102 pf = pf[1:-1] # Remove the quotes | 112 pf = pf[1:-1] # Remove the quotes |
103 else: | 113 else: |
104 if pf.startswith("'") and pf.endswith("'") and " " in pf: | 114 if pf.startswith("'") and pf.endswith("'") and " " in pf: |
105 pf = pf[1:-1] # Remove the quotes | 115 pf = pf[1:-1] # Remove the quotes |
106 return pf | 116 return pf |
117 | |
107 | 118 |
108 def sshargs(sshcmd, host, user, port): | 119 def sshargs(sshcmd, host, user, port): |
109 '''Build argument list for ssh''' | 120 '''Build argument list for ssh''' |
110 args = user and ("%s@%s" % (user, host)) or host | 121 args = user and ("%s@%s" % (user, host)) or host |
111 if '-' in args[:1]: | 122 if '-' in args[:1]: |
112 raise error.Abort( | 123 raise error.Abort( |
113 _('illegal ssh hostname or username starting with -: %s') % args) | 124 _('illegal ssh hostname or username starting with -: %s') % args |
125 ) | |
114 args = shellquote(args) | 126 args = shellquote(args) |
115 if port: | 127 if port: |
116 args = '-p %s %s' % (shellquote(port), args) | 128 args = '-p %s %s' % (shellquote(port), args) |
117 return args | 129 return args |
118 | 130 |
131 | |
119 def isexec(f): | 132 def isexec(f): |
120 """check whether a file is executable""" | 133 """check whether a file is executable""" |
121 return (os.lstat(f).st_mode & 0o100 != 0) | 134 return os.lstat(f).st_mode & 0o100 != 0 |
135 | |
122 | 136 |
123 def setflags(f, l, x): | 137 def setflags(f, l, x): |
124 st = os.lstat(f) | 138 st = os.lstat(f) |
125 s = st.st_mode | 139 s = st.st_mode |
126 if l: | 140 if l: |
144 data = os.readlink(f) | 158 data = os.readlink(f) |
145 unlink(f) | 159 unlink(f) |
146 fp = open(f, "wb") | 160 fp = open(f, "wb") |
147 fp.write(data) | 161 fp.write(data) |
148 fp.close() | 162 fp.close() |
149 s = 0o666 & ~umask # avoid restatting for chmod | 163 s = 0o666 & ~umask # avoid restatting for chmod |
150 | 164 |
151 sx = s & 0o100 | 165 sx = s & 0o100 |
152 if st.st_nlink > 1 and bool(x) != bool(sx): | 166 if st.st_nlink > 1 and bool(x) != bool(sx): |
153 # the file is a hardlink, break it | 167 # the file is a hardlink, break it |
154 with open(f, "rb") as fp: | 168 with open(f, "rb") as fp: |
162 # and obey umask. | 176 # and obey umask. |
163 os.chmod(f, s | (s & 0o444) >> 2 & ~umask) | 177 os.chmod(f, s | (s & 0o444) >> 2 & ~umask) |
164 elif not x and sx: | 178 elif not x and sx: |
165 # Turn off all +x bits | 179 # Turn off all +x bits |
166 os.chmod(f, s & 0o666) | 180 os.chmod(f, s & 0o666) |
181 | |
167 | 182 |
168 def copymode(src, dst, mode=None, enforcewritable=False): | 183 def copymode(src, dst, mode=None, enforcewritable=False): |
169 '''Copy the file mode from the file at path src to dst. | 184 '''Copy the file mode from the file at path src to dst. |
170 If src doesn't exist, we're using mode instead. If mode is None, we're | 185 If src doesn't exist, we're using mode instead. If mode is None, we're |
171 using umask.''' | 186 using umask.''' |
183 | 198 |
184 if enforcewritable: | 199 if enforcewritable: |
185 new_mode |= stat.S_IWUSR | 200 new_mode |= stat.S_IWUSR |
186 | 201 |
187 os.chmod(dst, new_mode) | 202 os.chmod(dst, new_mode) |
203 | |
188 | 204 |
189 def checkexec(path): | 205 def checkexec(path): |
190 """ | 206 """ |
191 Check whether the given path is on a filesystem with UNIX-like exec flags | 207 Check whether the given path is on a filesystem with UNIX-like exec flags |
192 | 208 |
232 try: | 248 try: |
233 m = os.stat(checknoexec).st_mode | 249 m = os.stat(checknoexec).st_mode |
234 except OSError as e: | 250 except OSError as e: |
235 if e.errno != errno.ENOENT: | 251 if e.errno != errno.ENOENT: |
236 raise | 252 raise |
237 open(checknoexec, 'w').close() # might fail | 253 open(checknoexec, 'w').close() # might fail |
238 m = os.stat(checknoexec).st_mode | 254 m = os.stat(checknoexec).st_mode |
239 if m & EXECFLAGS == 0: | 255 if m & EXECFLAGS == 0: |
240 # check-exec is exec and check-no-exec is not exec | 256 # check-exec is exec and check-no-exec is not exec |
241 return True | 257 return True |
242 # checknoexec exists but is exec - delete it | 258 # checknoexec exists but is exec - delete it |
266 unlink(fn) | 282 unlink(fn) |
267 except (IOError, OSError): | 283 except (IOError, OSError): |
268 # we don't care, the user probably won't be able to commit anyway | 284 # we don't care, the user probably won't be able to commit anyway |
269 return False | 285 return False |
270 | 286 |
287 | |
271 def checklink(path): | 288 def checklink(path): |
272 """check whether the given path is on a symlink-capable filesystem""" | 289 """check whether the given path is on a symlink-capable filesystem""" |
273 # mktemp is not racy because symlink creation will fail if the | 290 # mktemp is not racy because symlink creation will fail if the |
274 # file already exists | 291 # file already exists |
275 while True: | 292 while True: |
281 if os.path.isdir(cachedir): | 298 if os.path.isdir(cachedir): |
282 checkdir = cachedir | 299 checkdir = cachedir |
283 else: | 300 else: |
284 checkdir = path | 301 checkdir = path |
285 cachedir = None | 302 cachedir = None |
286 name = tempfile.mktemp(dir=pycompat.fsdecode(checkdir), | 303 name = tempfile.mktemp( |
287 prefix=r'checklink-') | 304 dir=pycompat.fsdecode(checkdir), prefix=r'checklink-' |
305 ) | |
288 name = pycompat.fsencode(name) | 306 name = pycompat.fsencode(name) |
289 try: | 307 try: |
290 fd = None | 308 fd = None |
291 if cachedir is None: | 309 if cachedir is None: |
292 fd = pycompat.namedtempfile(dir=checkdir, | 310 fd = pycompat.namedtempfile( |
293 prefix='hg-checklink-') | 311 dir=checkdir, prefix='hg-checklink-' |
312 ) | |
294 target = os.path.basename(fd.name) | 313 target = os.path.basename(fd.name) |
295 else: | 314 else: |
296 # create a fixed file to link to; doesn't matter if it | 315 # create a fixed file to link to; doesn't matter if it |
297 # already exists. | 316 # already exists. |
298 target = 'checklink-target' | 317 target = 'checklink-target' |
332 # sshfs might report failure while successfully creating the link | 351 # sshfs might report failure while successfully creating the link |
333 if inst.errno == errno.EIO and os.path.exists(name): | 352 if inst.errno == errno.EIO and os.path.exists(name): |
334 unlink(name) | 353 unlink(name) |
335 return False | 354 return False |
336 | 355 |
356 | |
337 def checkosfilename(path): | 357 def checkosfilename(path): |
338 '''Check that the base-relative path is a valid filename on this platform. | 358 '''Check that the base-relative path is a valid filename on this platform. |
339 Returns None if the path is ok, or a UI string describing the problem.''' | 359 Returns None if the path is ok, or a UI string describing the problem.''' |
340 return None # on posix platforms, every path is ok | 360 return None # on posix platforms, every path is ok |
361 | |
341 | 362 |
342 def getfsmountpoint(dirpath): | 363 def getfsmountpoint(dirpath): |
343 '''Get the filesystem mount point from a directory (best-effort) | 364 '''Get the filesystem mount point from a directory (best-effort) |
344 | 365 |
345 Returns None if we are unsure. Raises OSError on ENOENT, EPERM, etc. | 366 Returns None if we are unsure. Raises OSError on ENOENT, EPERM, etc. |
346 ''' | 367 ''' |
347 return getattr(osutil, 'getfsmountpoint', lambda x: None)(dirpath) | 368 return getattr(osutil, 'getfsmountpoint', lambda x: None)(dirpath) |
348 | 369 |
370 | |
349 def getfstype(dirpath): | 371 def getfstype(dirpath): |
350 '''Get the filesystem type name from a directory (best-effort) | 372 '''Get the filesystem type name from a directory (best-effort) |
351 | 373 |
352 Returns None if we are unsure. Raises OSError on ENOENT, EPERM, etc. | 374 Returns None if we are unsure. Raises OSError on ENOENT, EPERM, etc. |
353 ''' | 375 ''' |
354 return getattr(osutil, 'getfstype', lambda x: None)(dirpath) | 376 return getattr(osutil, 'getfstype', lambda x: None)(dirpath) |
355 | 377 |
378 | |
356 def setbinary(fd): | 379 def setbinary(fd): |
357 pass | 380 pass |
358 | 381 |
382 | |
359 def pconvert(path): | 383 def pconvert(path): |
360 return path | 384 return path |
361 | 385 |
386 | |
362 def localpath(path): | 387 def localpath(path): |
363 return path | 388 return path |
389 | |
364 | 390 |
365 def samefile(fpath1, fpath2): | 391 def samefile(fpath1, fpath2): |
366 """Returns whether path1 and path2 refer to the same file. This is only | 392 """Returns whether path1 and path2 refer to the same file. This is only |
367 guaranteed to work for files, not directories.""" | 393 guaranteed to work for files, not directories.""" |
368 return os.path.samefile(fpath1, fpath2) | 394 return os.path.samefile(fpath1, fpath2) |
395 | |
369 | 396 |
370 def samedevice(fpath1, fpath2): | 397 def samedevice(fpath1, fpath2): |
371 """Returns whether fpath1 and fpath2 are on the same device. This is only | 398 """Returns whether fpath1 and fpath2 are on the same device. This is only |
372 guaranteed to work for files, not directories.""" | 399 guaranteed to work for files, not directories.""" |
373 st1 = os.lstat(fpath1) | 400 st1 = os.lstat(fpath1) |
374 st2 = os.lstat(fpath2) | 401 st2 = os.lstat(fpath2) |
375 return st1.st_dev == st2.st_dev | 402 return st1.st_dev == st2.st_dev |
376 | 403 |
404 | |
377 # os.path.normcase is a no-op, which doesn't help us on non-native filesystems | 405 # os.path.normcase is a no-op, which doesn't help us on non-native filesystems |
378 def normcase(path): | 406 def normcase(path): |
379 return path.lower() | 407 return path.lower() |
408 | |
380 | 409 |
381 # what normcase does to ASCII strings | 410 # what normcase does to ASCII strings |
382 normcasespec = encoding.normcasespecs.lower | 411 normcasespec = encoding.normcasespecs.lower |
383 # fallback normcase function for non-ASCII strings | 412 # fallback normcase function for non-ASCII strings |
384 normcasefallback = normcase | 413 normcasefallback = normcase |
421 while pos < l: | 450 while pos < l: |
422 try: | 451 try: |
423 c = encoding.getutf8char(path, pos) | 452 c = encoding.getutf8char(path, pos) |
424 pos += len(c) | 453 pos += len(c) |
425 except ValueError: | 454 except ValueError: |
426 c = '%%%02X' % ord(path[pos:pos + 1]) | 455 c = '%%%02X' % ord(path[pos : pos + 1]) |
427 pos += 1 | 456 pos += 1 |
428 s += c | 457 s += c |
429 | 458 |
430 u = s.decode('utf-8') | 459 u = s.decode('utf-8') |
431 | 460 |
432 # Decompose then lowercase (HFS+ technote specifies lower) | 461 # Decompose then lowercase (HFS+ technote specifies lower) |
433 enc = unicodedata.normalize(r'NFD', u).lower().encode('utf-8') | 462 enc = unicodedata.normalize(r'NFD', u).lower().encode('utf-8') |
434 # drop HFS+ ignored characters | 463 # drop HFS+ ignored characters |
435 return encoding.hfsignoreclean(enc) | 464 return encoding.hfsignoreclean(enc) |
436 | 465 |
466 | |
437 if pycompat.sysplatform == 'cygwin': | 467 if pycompat.sysplatform == 'cygwin': |
438 # workaround for cygwin, in which mount point part of path is | 468 # workaround for cygwin, in which mount point part of path is |
439 # treated as case sensitive, even though underlying NTFS is case | 469 # treated as case sensitive, even though underlying NTFS is case |
440 # insensitive. | 470 # insensitive. |
441 | 471 |
442 # default mount points | 472 # default mount points |
443 cygwinmountpoints = sorted([ | 473 cygwinmountpoints = sorted( |
444 "/usr/bin", | 474 ["/usr/bin", "/usr/lib", "/cygdrive",], reverse=True |
445 "/usr/lib", | 475 ) |
446 "/cygdrive", | |
447 ], reverse=True) | |
448 | 476 |
449 # use upper-ing as normcase as same as NTFS workaround | 477 # use upper-ing as normcase as same as NTFS workaround |
450 def normcase(path): | 478 def normcase(path): |
451 pathlen = len(path) | 479 pathlen = len(path) |
452 if (pathlen == 0) or (path[0] != pycompat.ossep): | 480 if (pathlen == 0) or (path[0] != pycompat.ossep): |
457 for mp in cygwinmountpoints: | 485 for mp in cygwinmountpoints: |
458 if not path.startswith(mp): | 486 if not path.startswith(mp): |
459 continue | 487 continue |
460 | 488 |
461 mplen = len(mp) | 489 mplen = len(mp) |
462 if mplen == pathlen: # mount point itself | 490 if mplen == pathlen: # mount point itself |
463 return mp | 491 return mp |
464 if path[mplen] == pycompat.ossep: | 492 if path[mplen] == pycompat.ossep: |
465 return mp + encoding.upper(path[mplen:]) | 493 return mp + encoding.upper(path[mplen:]) |
466 | 494 |
467 return encoding.upper(path) | 495 return encoding.upper(path) |
480 # problems when Mercurial is used from both Cygwin and native | 508 # problems when Mercurial is used from both Cygwin and native |
481 # Windows, with other native tools, or on shared volumes | 509 # Windows, with other native tools, or on shared volumes |
482 def checklink(path): | 510 def checklink(path): |
483 return False | 511 return False |
484 | 512 |
513 | |
485 _needsshellquote = None | 514 _needsshellquote = None |
515 | |
516 | |
486 def shellquote(s): | 517 def shellquote(s): |
487 if pycompat.sysplatform == 'OpenVMS': | 518 if pycompat.sysplatform == 'OpenVMS': |
488 return '"%s"' % s | 519 return '"%s"' % s |
489 global _needsshellquote | 520 global _needsshellquote |
490 if _needsshellquote is None: | 521 if _needsshellquote is None: |
493 # "s" shouldn't have to be quoted | 524 # "s" shouldn't have to be quoted |
494 return s | 525 return s |
495 else: | 526 else: |
496 return "'%s'" % s.replace("'", "'\\''") | 527 return "'%s'" % s.replace("'", "'\\''") |
497 | 528 |
529 | |
498 def shellsplit(s): | 530 def shellsplit(s): |
499 """Parse a command string in POSIX shell way (best-effort)""" | 531 """Parse a command string in POSIX shell way (best-effort)""" |
500 return pycompat.shlexsplit(s, posix=True) | 532 return pycompat.shlexsplit(s, posix=True) |
501 | 533 |
534 | |
502 def quotecommand(cmd): | 535 def quotecommand(cmd): |
503 return cmd | 536 return cmd |
537 | |
504 | 538 |
505 def testpid(pid): | 539 def testpid(pid): |
506 '''return False if pid dead, True if running or not sure''' | 540 '''return False if pid dead, True if running or not sure''' |
507 if pycompat.sysplatform == 'OpenVMS': | 541 if pycompat.sysplatform == 'OpenVMS': |
508 return True | 542 return True |
510 os.kill(pid, 0) | 544 os.kill(pid, 0) |
511 return True | 545 return True |
512 except OSError as inst: | 546 except OSError as inst: |
513 return inst.errno != errno.ESRCH | 547 return inst.errno != errno.ESRCH |
514 | 548 |
549 | |
515 def isowner(st): | 550 def isowner(st): |
516 """Return True if the stat object st is from the current user.""" | 551 """Return True if the stat object st is from the current user.""" |
517 return st.st_uid == os.getuid() | 552 return st.st_uid == os.getuid() |
553 | |
518 | 554 |
519 def findexe(command): | 555 def findexe(command): |
520 '''Find executable for command searching like which does. | 556 '''Find executable for command searching like which does. |
521 If command is a basename then PATH is searched for command. | 557 If command is a basename then PATH is searched for command. |
522 PATH isn't searched if command is an absolute or relative path. | 558 PATH isn't searched if command is an absolute or relative path. |
540 executable = findexisting(os.path.join(path, command)) | 576 executable = findexisting(os.path.join(path, command)) |
541 if executable is not None: | 577 if executable is not None: |
542 return executable | 578 return executable |
543 return None | 579 return None |
544 | 580 |
581 | |
545 def setsignalhandler(): | 582 def setsignalhandler(): |
546 pass | 583 pass |
547 | 584 |
585 | |
548 _wantedkinds = {stat.S_IFREG, stat.S_IFLNK} | 586 _wantedkinds = {stat.S_IFREG, stat.S_IFLNK} |
587 | |
549 | 588 |
550 def statfiles(files): | 589 def statfiles(files): |
551 '''Stat each file in files. Yield each stat, or None if a file does not | 590 '''Stat each file in files. Yield each stat, or None if a file does not |
552 exist or has a type we don't care about.''' | 591 exist or has a type we don't care about.''' |
553 lstat = os.lstat | 592 lstat = os.lstat |
561 if err.errno not in (errno.ENOENT, errno.ENOTDIR): | 600 if err.errno not in (errno.ENOENT, errno.ENOTDIR): |
562 raise | 601 raise |
563 st = None | 602 st = None |
564 yield st | 603 yield st |
565 | 604 |
605 | |
566 def getuser(): | 606 def getuser(): |
567 '''return name of current user''' | 607 '''return name of current user''' |
568 return pycompat.fsencode(getpass.getuser()) | 608 return pycompat.fsencode(getpass.getuser()) |
609 | |
569 | 610 |
570 def username(uid=None): | 611 def username(uid=None): |
571 """Return the name of the user with the given uid. | 612 """Return the name of the user with the given uid. |
572 | 613 |
573 If uid is None, return the name of the current user.""" | 614 If uid is None, return the name of the current user.""" |
577 try: | 618 try: |
578 return pycompat.fsencode(pwd.getpwuid(uid)[0]) | 619 return pycompat.fsencode(pwd.getpwuid(uid)[0]) |
579 except KeyError: | 620 except KeyError: |
580 return b'%d' % uid | 621 return b'%d' % uid |
581 | 622 |
623 | |
582 def groupname(gid=None): | 624 def groupname(gid=None): |
583 """Return the name of the group with the given gid. | 625 """Return the name of the group with the given gid. |
584 | 626 |
585 If gid is None, return the name of the current group.""" | 627 If gid is None, return the name of the current group.""" |
586 | 628 |
589 try: | 631 try: |
590 return pycompat.fsencode(grp.getgrgid(gid)[0]) | 632 return pycompat.fsencode(grp.getgrgid(gid)[0]) |
591 except KeyError: | 633 except KeyError: |
592 return pycompat.bytestr(gid) | 634 return pycompat.bytestr(gid) |
593 | 635 |
636 | |
594 def groupmembers(name): | 637 def groupmembers(name): |
595 """Return the list of members of the group with the given | 638 """Return the list of members of the group with the given |
596 name, KeyError if the group does not exist. | 639 name, KeyError if the group does not exist. |
597 """ | 640 """ |
598 name = pycompat.fsdecode(name) | 641 name = pycompat.fsdecode(name) |
599 return pycompat.rapply(pycompat.fsencode, list(grp.getgrnam(name).gr_mem)) | 642 return pycompat.rapply(pycompat.fsencode, list(grp.getgrnam(name).gr_mem)) |
600 | 643 |
644 | |
601 def spawndetached(args): | 645 def spawndetached(args): |
602 return os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0), | 646 return os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0), args[0], args) |
603 args[0], args) | 647 |
604 | 648 |
605 def gethgcmd(): | 649 def gethgcmd(): |
606 return sys.argv[:1] | 650 return sys.argv[:1] |
607 | 651 |
652 | |
608 def makedir(path, notindexed): | 653 def makedir(path, notindexed): |
609 os.mkdir(path) | 654 os.mkdir(path) |
610 | 655 |
656 | |
611 def lookupreg(key, name=None, scope=None): | 657 def lookupreg(key, name=None, scope=None): |
612 return None | 658 return None |
659 | |
613 | 660 |
614 def hidewindow(): | 661 def hidewindow(): |
615 """Hide current shell window. | 662 """Hide current shell window. |
616 | 663 |
617 Used to hide the window opened when starting asynchronous | 664 Used to hide the window opened when starting asynchronous |
618 child process under Windows, unneeded on other systems. | 665 child process under Windows, unneeded on other systems. |
619 """ | 666 """ |
620 pass | 667 pass |
668 | |
621 | 669 |
622 class cachestat(object): | 670 class cachestat(object): |
623 def __init__(self, path): | 671 def __init__(self, path): |
624 self.stat = os.stat(path) | 672 self.stat = os.stat(path) |
625 | 673 |
633 # Only dev, ino, size, mtime and atime are likely to change. Out | 681 # Only dev, ino, size, mtime and atime are likely to change. Out |
634 # of these, we shouldn't compare atime but should compare the | 682 # of these, we shouldn't compare atime but should compare the |
635 # rest. However, one of the other fields changing indicates | 683 # rest. However, one of the other fields changing indicates |
636 # something fishy going on, so return False if anything but atime | 684 # something fishy going on, so return False if anything but atime |
637 # changes. | 685 # changes. |
638 return (self.stat.st_mode == other.stat.st_mode and | 686 return ( |
639 self.stat.st_ino == other.stat.st_ino and | 687 self.stat.st_mode == other.stat.st_mode |
640 self.stat.st_dev == other.stat.st_dev and | 688 and self.stat.st_ino == other.stat.st_ino |
641 self.stat.st_nlink == other.stat.st_nlink and | 689 and self.stat.st_dev == other.stat.st_dev |
642 self.stat.st_uid == other.stat.st_uid and | 690 and self.stat.st_nlink == other.stat.st_nlink |
643 self.stat.st_gid == other.stat.st_gid and | 691 and self.stat.st_uid == other.stat.st_uid |
644 self.stat.st_size == other.stat.st_size and | 692 and self.stat.st_gid == other.stat.st_gid |
645 self.stat[stat.ST_MTIME] == other.stat[stat.ST_MTIME] and | 693 and self.stat.st_size == other.stat.st_size |
646 self.stat[stat.ST_CTIME] == other.stat[stat.ST_CTIME]) | 694 and self.stat[stat.ST_MTIME] == other.stat[stat.ST_MTIME] |
695 and self.stat[stat.ST_CTIME] == other.stat[stat.ST_CTIME] | |
696 ) | |
647 except AttributeError: | 697 except AttributeError: |
648 return False | 698 return False |
649 | 699 |
650 def __ne__(self, other): | 700 def __ne__(self, other): |
651 return not self == other | 701 return not self == other |
702 | |
652 | 703 |
653 def statislink(st): | 704 def statislink(st): |
654 '''check whether a stat result is a symlink''' | 705 '''check whether a stat result is a symlink''' |
655 return st and stat.S_ISLNK(st.st_mode) | 706 return st and stat.S_ISLNK(st.st_mode) |
656 | 707 |
708 | |
657 def statisexec(st): | 709 def statisexec(st): |
658 '''check whether a stat result is an executable file''' | 710 '''check whether a stat result is an executable file''' |
659 return st and (st.st_mode & 0o100 != 0) | 711 return st and (st.st_mode & 0o100 != 0) |
712 | |
660 | 713 |
661 def poll(fds): | 714 def poll(fds): |
662 """block until something happens on any file descriptor | 715 """block until something happens on any file descriptor |
663 | 716 |
664 This is a generic helper that will check for any activity | 717 This is a generic helper that will check for any activity |
672 break | 725 break |
673 except select.error as inst: | 726 except select.error as inst: |
674 if inst.args[0] == errno.EINTR: | 727 if inst.args[0] == errno.EINTR: |
675 continue | 728 continue |
676 raise | 729 raise |
677 except ValueError: # out of range file descriptor | 730 except ValueError: # out of range file descriptor |
678 raise NotImplementedError() | 731 raise NotImplementedError() |
679 return sorted(list(set(sum(res, [])))) | 732 return sorted(list(set(sum(res, [])))) |
733 | |
680 | 734 |
681 def readpipe(pipe): | 735 def readpipe(pipe): |
682 """Read all available data from a pipe.""" | 736 """Read all available data from a pipe.""" |
683 # We can't fstat() a pipe because Linux will always report 0. | 737 # We can't fstat() a pipe because Linux will always report 0. |
684 # So, we set the pipe to non-blocking mode and read everything | 738 # So, we set the pipe to non-blocking mode and read everything |
699 break | 753 break |
700 | 754 |
701 return ''.join(chunks) | 755 return ''.join(chunks) |
702 finally: | 756 finally: |
703 fcntl.fcntl(pipe, fcntl.F_SETFL, oldflags) | 757 fcntl.fcntl(pipe, fcntl.F_SETFL, oldflags) |
758 | |
704 | 759 |
705 def bindunixsocket(sock, path): | 760 def bindunixsocket(sock, path): |
706 """Bind the UNIX domain socket to the specified path""" | 761 """Bind the UNIX domain socket to the specified path""" |
707 # use relative path instead of full path at bind() if possible, since | 762 # use relative path instead of full path at bind() if possible, since |
708 # AF_UNIX path has very small length limit (107 chars) on common | 763 # AF_UNIX path has very small length limit (107 chars) on common |