mercurial/posix.py
changeset 49812 58dff81ffba1
parent 49811 0a91aba258e0
child 49815 464fe8b8f474
--- a/mercurial/posix.py	Thu Dec 15 21:13:11 2022 -0500
+++ b/mercurial/posix.py	Fri Dec 16 00:54:39 2022 -0500
@@ -20,9 +20,13 @@
 import unicodedata
 
 from typing import (
+    Iterable,
+    Iterator,
     List,
     NoReturn,
     Optional,
+    Sequence,
+    Union,
 )
 
 from .i18n import _
@@ -91,7 +95,7 @@
     return ht[0] + b'/', ht[1]
 
 
-def openhardlinks():
+def openhardlinks() -> bool:
     '''return true if it is safe to hold open file handles to hardlinks'''
     return True
 
@@ -101,7 +105,7 @@
     return os.lstat(name).st_nlink
 
 
-def parsepatchoutput(output_line):
+def parsepatchoutput(output_line: bytes) -> bytes:
     """parses the output produced by patch and returns the filename"""
     pf = output_line[14:]
     if pycompat.sysplatform == b'OpenVMS':
@@ -113,7 +117,9 @@
     return pf
 
 
-def sshargs(sshcmd, host, user, port):
+def sshargs(
+    sshcmd: bytes, host: bytes, user: Optional[bytes], port: Optional[bytes]
+) -> bytes:
     '''Build argument list for ssh'''
     args = user and (b"%s@%s" % (user, host)) or host
     if b'-' in args[:1]:
@@ -126,12 +132,12 @@
     return args
 
 
-def isexec(f):
+def isexec(f: bytes) -> bool:
     """check whether a file is executable"""
     return os.lstat(f).st_mode & 0o100 != 0
 
 
-def setflags(f, l, x):
+def setflags(f: bytes, l: bool, x: bool) -> None:
     st = os.lstat(f)
     s = st.st_mode
     if l:
@@ -175,7 +181,12 @@
         os.chmod(f, s & 0o666)
 
 
-def copymode(src, dst, mode=None, enforcewritable=False):
+def copymode(
+    src: bytes,
+    dst: bytes,
+    mode: Optional[bytes] = None,
+    enforcewritable: bool = False,
+) -> None:
     """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."""
@@ -195,7 +206,7 @@
     os.chmod(dst, new_mode)
 
 
-def checkexec(path):
+def checkexec(path: bytes) -> bool:
     """
     Check whether the given path is on a filesystem with UNIX-like exec flags
 
@@ -275,7 +286,7 @@
         return False
 
 
-def checklink(path):
+def checklink(path: bytes) -> bool:
     """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
@@ -362,19 +373,19 @@
     return getattr(osutil, 'getfstype', lambda x: None)(dirpath)
 
 
-def get_password():
+def get_password() -> bytes:
     return encoding.strtolocal(getpass.getpass(''))
 
 
-def setbinary(fd):
+def setbinary(fd) -> None:
     pass
 
 
-def pconvert(path):
+def pconvert(path: bytes) -> bytes:
     return path
 
 
-def localpath(path):
+def localpath(path: bytes) -> bytes:
     return path
 
 
@@ -393,7 +404,7 @@
 
 
 # os.path.normcase is a no-op, which doesn't help us on non-native filesystems
-def normcase(path):
+def normcase(path: bytes) -> bytes:
     return path.lower()
 
 
@@ -404,7 +415,7 @@
 
 if pycompat.isdarwin:
 
-    def normcase(path):
+    def normcase(path: bytes) -> bytes:
         """
         Normalize a filename for OS X-compatible comparison:
         - escape-encode invalid characters
@@ -429,7 +440,7 @@
 
     normcasespec = encoding.normcasespecs.lower
 
-    def normcasefallback(path):
+    def normcasefallback(path: bytes) -> bytes:
         try:
             u = path.decode('utf-8')
         except UnicodeDecodeError:
@@ -470,7 +481,7 @@
     )
 
     # use upper-ing as normcase as same as NTFS workaround
-    def normcase(path):
+    def normcase(path: bytes) -> bytes:
         pathlen = len(path)
         if (pathlen == 0) or (path[0] != pycompat.ossep):
             # treat as relative
@@ -496,20 +507,20 @@
     # 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):
+    def checkexec(path: bytes) -> bool:
         return False
 
     # 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):
+    def checklink(path: bytes) -> bool:
         return False
 
 
 _needsshellquote = None
 
 
-def shellquote(s):
+def shellquote(s: bytes) -> bytes:
     if pycompat.sysplatform == b'OpenVMS':
         return b'"%s"' % s
     global _needsshellquote
@@ -522,7 +533,7 @@
         return b"'%s'" % s.replace(b"'", b"'\\''")
 
 
-def shellsplit(s):
+def shellsplit(s: bytes) -> List[bytes]:
     """Parse a command string in POSIX shell way (best-effort)"""
     return pycompat.shlexsplit(s, posix=True)
 
@@ -538,12 +549,12 @@
         return inst.errno != errno.ESRCH
 
 
-def isowner(st):
+def isowner(st: os.stat_result) -> bool:
     """Return True if the stat object st is from the current user."""
     return st.st_uid == os.getuid()
 
 
-def findexe(command):
+def findexe(command: bytes) -> Optional[bytes]:
     """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.
@@ -551,7 +562,7 @@
     if pycompat.sysplatform == b'OpenVMS':
         return command
 
-    def findexisting(executable):
+    def findexisting(executable: bytes) -> Optional[bytes]:
         b'Will return executable if existing file'
         if os.path.isfile(executable) and os.access(executable, os.X_OK):
             return executable
@@ -577,7 +588,7 @@
 _wantedkinds = {stat.S_IFREG, stat.S_IFLNK}
 
 
-def statfiles(files):
+def statfiles(files: Sequence[bytes]) -> Iterator[Optional[os.stat_result]]:
     """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."""
     lstat = os.lstat
@@ -597,7 +608,7 @@
     return pycompat.fsencode(getpass.getuser())
 
 
-def username(uid=None):
+def username(uid: Optional[int] = None) -> Optional[bytes]:
     """Return the name of the user with the given uid.
 
     If uid is None, return the name of the current user."""
@@ -610,7 +621,7 @@
         return b'%d' % uid
 
 
-def groupname(gid=None):
+def groupname(gid: Optional[int] = None) -> Optional[bytes]:
     """Return the name of the group with the given gid.
 
     If gid is None, return the name of the current group."""
@@ -623,7 +634,7 @@
         return pycompat.bytestr(gid)
 
 
-def groupmembers(name):
+def groupmembers(name: bytes) -> List[bytes]:
     """Return the list of members of the group with the given
     name, KeyError if the group does not exist.
     """
@@ -643,7 +654,11 @@
     os.mkdir(path)
 
 
-def lookupreg(key, name=None, scope=None):
+def lookupreg(
+    key: bytes,
+    name: Optional[bytes] = None,
+    scope: Optional[Union[int, Iterable[int]]] = None,
+) -> Optional[bytes]:
     return None
 
 
@@ -690,14 +705,14 @@
         return not self == other
 
 
-def statislink(st):
+def statislink(st: Optional[os.stat_result]) -> bool:
     '''check whether a stat result is a symlink'''
-    return st and stat.S_ISLNK(st.st_mode)
+    return stat.S_ISLNK(st.st_mode) if st else False
 
 
-def statisexec(st):
+def statisexec(st: Optional[os.stat_result]) -> bool:
     '''check whether a stat result is an executable file'''
-    return st and (st.st_mode & 0o100 != 0)
+    return (st.st_mode & 0o100 != 0) if st else False
 
 
 def poll(fds):
@@ -714,7 +729,7 @@
     return sorted(list(set(sum(res, []))))
 
 
-def readpipe(pipe):
+def readpipe(pipe) -> bytes:
     """Read all available data from a pipe."""
     # We can't fstat() a pipe because Linux will always report 0.
     # So, we set the pipe to non-blocking mode and read everything
@@ -739,7 +754,7 @@
         fcntl.fcntl(pipe, fcntl.F_SETFL, oldflags)
 
 
-def bindunixsocket(sock, path):
+def bindunixsocket(sock, path: bytes) -> None:
     """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