[arch-commits] Commit in git/repos/extra-x86_64 (12 files)

Christian Hesse eworm at archlinux.org
Wed Mar 18 07:35:08 UTC 2020


    Date: Wednesday, March 18, 2020 @ 07:35:08
  Author: eworm
Revision: 377836

archrelease: copy trunk to extra-x86_64

Added:
  git/repos/extra-x86_64/0001-git-p4-python.patch
    (from rev 377835, git/trunk/0001-git-p4-python.patch)
  git/repos/extra-x86_64/PKGBUILD
    (from rev 377835, git/trunk/PKGBUILD)
  git/repos/extra-x86_64/git-daemon.socket
    (from rev 377835, git/trunk/git-daemon.socket)
  git/repos/extra-x86_64/git-daemon at .service
    (from rev 377835, git/trunk/git-daemon at .service)
  git/repos/extra-x86_64/git-sysusers.conf
    (from rev 377835, git/trunk/git-sysusers.conf)
  git/repos/extra-x86_64/git.install
    (from rev 377835, git/trunk/git.install)
Deleted:
  git/repos/extra-x86_64/0001-git-p4-python.patch
  git/repos/extra-x86_64/PKGBUILD
  git/repos/extra-x86_64/git-daemon.socket
  git/repos/extra-x86_64/git-daemon at .service
  git/repos/extra-x86_64/git-sysusers.conf
  git/repos/extra-x86_64/git.install

--------------------------+
 0001-git-p4-python.patch | 1262 ++++++++++++++++++++++-----------------------
 PKGBUILD                 |  272 ++++-----
 git-daemon.socket        |   18 
 git-daemon at .service      |   28 
 git-sysusers.conf        |    2 
 git.install              |   28 
 6 files changed, 805 insertions(+), 805 deletions(-)

Deleted: 0001-git-p4-python.patch
===================================================================
--- 0001-git-p4-python.patch	2020-03-18 07:35:01 UTC (rev 377835)
+++ 0001-git-p4-python.patch	2020-03-18 07:35:08 UTC (rev 377836)
@@ -1,631 +0,0 @@
-diff --git a/git-p4.py b/git-p4.py
-index 40d9e7c594..ca0a874501 100755
---- a/git-p4.py
-+++ b/git-p4.py
-@@ -8,12 +8,12 @@
- # License: MIT <http://www.opensource.org/licenses/mit-license.php>
- #
- import sys
--if sys.hexversion < 0x02040000:
--    # The limiter is the subprocess module
--    sys.stderr.write("git-p4: requires Python 2.4 or later.\n")
-+if sys.version_info.major < 3 and sys.version_info.minor < 7:
-+    sys.stderr.write("git-p4: requires Python 2.7 or later.\n")
-     sys.exit(1)
- import os
- import optparse
-+import functools
- import marshal
- import subprocess
- import tempfile
-@@ -27,36 +27,15 @@
- import ctypes
- import errno
- 
-+# On python2.7 where raw_input() and input() are both availble,
-+# we want raw_input's semantics, but aliased to input for python3
-+# compatibility
- # support basestring in python3
- try:
--    unicode = unicode
--except NameError:
--    # 'unicode' is undefined, must be Python 3
--    str = str
--    unicode = str
--    bytes = bytes
--    basestring = (str,bytes)
--else:
--    # 'unicode' exists, must be Python 2
--    str = str
--    unicode = unicode
--    bytes = str
--    basestring = basestring
--
--try:
--    from subprocess import CalledProcessError
--except ImportError:
--    # from python2.7:subprocess.py
--    # Exception classes used by this module.
--    class CalledProcessError(Exception):
--        """This exception is raised when a process run by check_call() returns
--        a non-zero exit status.  The exit status will be stored in the
--        returncode attribute."""
--        def __init__(self, returncode, cmd):
--            self.returncode = returncode
--            self.cmd = cmd
--        def __str__(self):
--            return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode)
-+    if raw_input and input:
-+        input = raw_input
-+except:
-+    pass
- 
- verbose = False
- 
-@@ -105,7 +84,7 @@ def p4_build_cmd(cmd):
-         # Provide a way to not pass this option by setting git-p4.retries to 0
-         real_cmd += ["-r", str(retries)]
- 
--    if isinstance(cmd,basestring):
-+    if not isinstance(cmd, list):
-         real_cmd = ' '.join(real_cmd) + ' ' + cmd
-     else:
-         real_cmd += cmd
-@@ -175,18 +154,48 @@ def prompt(prompt_text):
-     """
-     choices = set(m.group(1) for m in re.finditer(r"\[(.)\]", prompt_text))
-     while True:
--        response = raw_input(prompt_text).strip().lower()
-+        response = input(prompt_text).strip().lower()
-         if not response:
-             continue
-         response = response[0]
-         if response in choices:
-             return response
- 
-+# We need different encoding/decoding strategies for text data being passed
-+# around in pipes depending on python version
-+if bytes is not str:
-+    # For python3, always encode and decode as appropriate
-+    def decode_text_stream(s):
-+        return s.decode() if isinstance(s, bytes) else s
-+    def encode_text_stream(s):
-+        return s.encode() if isinstance(s, str) else s
-+else:
-+    # For python2.7, pass read strings as-is, but also allow writing unicode
-+    def decode_text_stream(s):
-+        return s
-+    def encode_text_stream(s):
-+        return s.encode('utf_8') if isinstance(s, unicode) else s
-+
-+def decode_path(path):
-+    """Decode a given string (bytes or otherwise) using configured path encoding options
-+    """
-+    encoding = gitConfig('git-p4.pathEncoding') or 'utf_8'
-+    if bytes is not str:
-+        return path.decode(encoding, errors='replace') if isinstance(path, bytes) else path
-+    else:
-+        try:
-+            path.decode('ascii')
-+        except:
-+            path = path.decode(encoding, errors='replace')
-+            if verbose:
-+                print('Path with non-ASCII characters detected. Used {} to decode: {}'.format(encoding, path))
-+        return path
-+
- def write_pipe(c, stdin):
-     if verbose:
-         sys.stderr.write('Writing pipe: %s\n' % str(c))
- 
--    expand = isinstance(c,basestring)
-+    expand = not isinstance(c, list)
-     p = subprocess.Popen(c, stdin=subprocess.PIPE, shell=expand)
-     pipe = p.stdin
-     val = pipe.write(stdin)
-@@ -198,6 +207,8 @@ def write_pipe(c, stdin):
- 
- def p4_write_pipe(c, stdin):
-     real_cmd = p4_build_cmd(c)
-+    if bytes is not str and isinstance(stdin, str):
-+        stdin = encode_text_stream(stdin)
-     return write_pipe(real_cmd, stdin)
- 
- def read_pipe_full(c):
-@@ -208,15 +219,17 @@ def read_pipe_full(c):
-     if verbose:
-         sys.stderr.write('Reading pipe: %s\n' % str(c))
- 
--    expand = isinstance(c,basestring)
-+    expand = not isinstance(c, list)
-     p = subprocess.Popen(c, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=expand)
-     (out, err) = p.communicate()
--    return (p.returncode, out, err)
-+    return (p.returncode, out, decode_text_stream(err))
- 
--def read_pipe(c, ignore_error=False):
-+def read_pipe(c, ignore_error=False, raw=False):
-     """ Read output from  command. Returns the output text on
-         success. On failure, terminates execution, unless
-         ignore_error is True, when it returns an empty string.
-+
-+        If raw is True, do not attempt to decode output text.
-     """
-     (retcode, out, err) = read_pipe_full(c)
-     if retcode != 0:
-@@ -224,6 +237,8 @@ def read_pipe(c, ignore_error=False):
-             out = ""
-         else:
-             die('Command failed: %s\nError: %s' % (str(c), err))
-+    if not raw:
-+        out = decode_text_stream(out)
-     return out
- 
- def read_pipe_text(c):
-@@ -234,23 +249,22 @@ def read_pipe_text(c):
-     if retcode != 0:
-         return None
-     else:
--        return out.rstrip()
-+        return decode_text_stream(out).rstrip()
- 
--def p4_read_pipe(c, ignore_error=False):
-+def p4_read_pipe(c, ignore_error=False, raw=False):
-     real_cmd = p4_build_cmd(c)
--    return read_pipe(real_cmd, ignore_error)
-+    return read_pipe(real_cmd, ignore_error, raw=raw)
- 
- def read_pipe_lines(c):
-     if verbose:
-         sys.stderr.write('Reading pipe: %s\n' % str(c))
- 
--    expand = isinstance(c, basestring)
-+    expand = not isinstance(c, list)
-     p = subprocess.Popen(c, stdout=subprocess.PIPE, shell=expand)
-     pipe = p.stdout
--    val = pipe.readlines()
-+    val = [decode_text_stream(line) for line in pipe.readlines()]
-     if pipe.close() or p.wait():
-         die('Command failed: %s' % str(c))
--
-     return val
- 
- def p4_read_pipe_lines(c):
-@@ -278,6 +292,7 @@ def p4_has_move_command():
-     cmd = p4_build_cmd(["move", "-k", "@from", "@to"])
-     p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-     (out, err) = p.communicate()
-+    err = decode_text_stream(err)
-     # return code will be 1 in either case
-     if err.find("Invalid option") >= 0:
-         return False
-@@ -287,7 +302,7 @@ def p4_has_move_command():
-     return True
- 
- def system(cmd, ignore_error=False):
--    expand = isinstance(cmd,basestring)
-+    expand = not isinstance(cmd, list)
-     if verbose:
-         sys.stderr.write("executing %s\n" % str(cmd))
-     retcode = subprocess.call(cmd, shell=expand)
-@@ -299,7 +314,7 @@ def system(cmd, ignore_error=False):
- def p4_system(cmd):
-     """Specifically invoke p4 as the system command. """
-     real_cmd = p4_build_cmd(cmd)
--    expand = isinstance(real_cmd, basestring)
-+    expand = not isinstance(real_cmd, list)
-     retcode = subprocess.call(real_cmd, shell=expand)
-     if retcode:
-         raise CalledProcessError(retcode, real_cmd)
-@@ -537,7 +552,7 @@ def getP4OpenedType(file):
- # Return the set of all p4 labels
- def getP4Labels(depotPaths):
-     labels = set()
--    if isinstance(depotPaths,basestring):
-+    if not isinstance(depotPaths, list):
-         depotPaths = [depotPaths]
- 
-     for l in p4CmdList(["labels"] + ["%s..." % p for p in depotPaths]):
-@@ -554,12 +569,7 @@ def getGitTags():
-         gitTags.add(tag)
-     return gitTags
- 
--def diffTreePattern():
--    # This is a simple generator for the diff tree regex pattern. This could be
--    # a class variable if this and parseDiffTreeEntry were a part of a class.
--    pattern = re.compile(':(\d+) (\d+) (\w+) (\w+) ([A-Z])(\d+)?\t(.*?)((\t(.*))|$)')
--    while True:
--        yield pattern
-+_diff_tree_pattern = None
- 
- def parseDiffTreeEntry(entry):
-     """Parses a single diff tree entry into its component elements.
-@@ -580,7 +590,11 @@ def parseDiffTreeEntry(entry):
- 
-     If the pattern is not matched, None is returned."""
- 
--    match = diffTreePattern().next().match(entry)
-+    global _diff_tree_pattern
-+    if not _diff_tree_pattern:
-+        _diff_tree_pattern = re.compile(':(\d+) (\d+) (\w+) (\w+) ([A-Z])(\d+)?\t(.*?)((\t(.*))|$)')
-+
-+    match = _diff_tree_pattern.match(entry)
-     if match:
-         return {
-             'src_mode': match.group(1),
-@@ -624,7 +638,7 @@ def isModeExecChanged(src_mode, dst_mode):
- def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None, skip_info=False,
-         errors_as_exceptions=False):
- 
--    if isinstance(cmd,basestring):
-+    if not isinstance(cmd, list):
-         cmd = "-G " + cmd
-         expand = True
-     else:
-@@ -641,11 +655,12 @@ def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None, skip_info=False,
-     stdin_file = None
-     if stdin is not None:
-         stdin_file = tempfile.TemporaryFile(prefix='p4-stdin', mode=stdin_mode)
--        if isinstance(stdin,basestring):
-+        if not isinstance(stdin, list):
-             stdin_file.write(stdin)
-         else:
-             for i in stdin:
--                stdin_file.write(i + '\n')
-+                stdin_file.write(encode_text_stream(i))
-+                stdin_file.write(b'\n')
-         stdin_file.flush()
-         stdin_file.seek(0)
- 
-@@ -658,6 +673,20 @@ def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None, skip_info=False,
-     try:
-         while True:
-             entry = marshal.load(p4.stdout)
-+            if bytes is not str:
-+                # Decode unmarshalled dict to use str keys and values, except for:
-+                #   - `data` which may contain arbitrary binary data
-+                #   - `depotFile[0-9]*`, `path`, or `clientFile` which may contain non-UTF8 encoded text
-+                decoded_entry = {}
-+                for key, value in entry.items():
-+                    key = key.decode()
-+                    if isinstance(value, bytes) and not (key in ('data', 'path', 'clientFile') or key.startswith('depotFile')):
-+                        value = value.decode()
-+                    decoded_entry[key] = value
-+                # Parse out data if it's an error response
-+                if decoded_entry.get('code') == 'error' and 'data' in decoded_entry:
-+                    decoded_entry['data'] = decoded_entry['data'].decode()
-+                entry = decoded_entry
-             if skip_info:
-                 if 'code' in entry and entry['code'] == 'info':
-                     continue
-@@ -708,7 +737,8 @@ def p4Where(depotPath):
-         if "depotFile" in entry:
-             # Search for the base client side depot path, as long as it starts with the branch's P4 path.
-             # The base path always ends with "/...".
--            if entry["depotFile"].find(depotPath) == 0 and entry["depotFile"][-4:] == "/...":
-+            entry_path = decode_path(entry['depotFile'])
-+            if entry_path.find(depotPath) == 0 and entry_path[-4:] == "/...":
-                 output = entry
-                 break
-         elif "data" in entry:
-@@ -723,11 +753,11 @@ def p4Where(depotPath):
-         return ""
-     clientPath = ""
-     if "path" in output:
--        clientPath = output.get("path")
-+        clientPath = decode_path(output['path'])
-     elif "data" in output:
-         data = output.get("data")
--        lastSpace = data.rfind(" ")
--        clientPath = data[lastSpace + 1:]
-+        lastSpace = data.rfind(b" ")
-+        clientPath = decode_path(data[lastSpace + 1:])
- 
-     if clientPath.endswith("..."):
-         clientPath = clientPath[:-3]
-@@ -875,6 +905,7 @@ def branch_exists(branch):
-     cmd = [ "git", "rev-parse", "--symbolic", "--verify", branch ]
-     p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-     out, _ = p.communicate()
-+    out = decode_text_stream(out)
-     if p.returncode:
-         return False
-     # expect exactly one line of output: the branch name
-@@ -1152,7 +1183,7 @@ def pushFile(self, localLargeFile):
-         assert False, "Method 'pushFile' required in " + self.__class__.__name__
- 
-     def hasLargeFileExtension(self, relPath):
--        return reduce(
-+        return functools.reduce(
-             lambda a, b: a or b,
-             [relPath.endswith('.' + e) for e in gitConfigList('git-p4.largeFileExtensions')],
-             False
-@@ -1259,7 +1290,7 @@ def generatePointer(self, contentFile):
-             ['git', 'lfs', 'pointer', '--file=' + contentFile],
-             stdout=subprocess.PIPE
-         )
--        pointerFile = pointerProcess.stdout.read()
-+        pointerFile = decode_text_stream(pointerProcess.stdout.read())
-         if pointerProcess.wait():
-             os.remove(contentFile)
-             die('git-lfs pointer command failed. Did you install the extension?')
-@@ -1395,14 +1426,14 @@ def getUserMapFromPerforceServer(self):
-         for (key, val) in self.users.items():
-             s += "%s\t%s\n" % (key.expandtabs(1), val.expandtabs(1))
- 
--        open(self.getUserCacheFilename(), "wb").write(s)
-+        open(self.getUserCacheFilename(), 'w').write(s)
-         self.userMapFromPerforceServer = True
- 
-     def loadUserMapFromCache(self):
-         self.users = {}
-         self.userMapFromPerforceServer = False
-         try:
--            cache = open(self.getUserCacheFilename(), "rb")
-+            cache = open(self.getUserCacheFilename(), 'r')
-             lines = cache.readlines()
-             cache.close()
-             for line in lines:
-@@ -1679,7 +1710,8 @@ def modifyChangelistUser(self, changelist, newUser):
-         c = changes[0]
-         if c['User'] == newUser: return   # nothing to do
-         c['User'] = newUser
--        input = marshal.dumps(c)
-+        # p4 does not understand format version 3 and above
-+        input = marshal.dumps(c, 2)
- 
-         result = p4CmdList("change -f -i", stdin=input)
-         for r in result:
-@@ -1743,7 +1775,7 @@ def prepareSubmitTemplate(self, changelist=None):
-                 break
-         if not change_entry:
-             die('Failed to decode output of p4 change -o')
--        for key, value in change_entry.iteritems():
-+        for key, value in change_entry.items():
-             if key.startswith('File'):
-                 if 'depot-paths' in settings:
-                     if not [p for p in settings['depot-paths']
-@@ -2023,7 +2055,7 @@ def applyCommit(self, id):
-         tmpFile = os.fdopen(handle, "w+b")
-         if self.isWindows:
-             submitTemplate = submitTemplate.replace("\n", "\r\n")
--        tmpFile.write(submitTemplate)
-+        tmpFile.write(encode_text_stream(submitTemplate))
-         tmpFile.close()
- 
-         if self.prepare_p4_only:
-@@ -2070,7 +2102,7 @@ def applyCommit(self, id):
-             if self.edit_template(fileName):
-                 # read the edited message and submit
-                 tmpFile = open(fileName, "rb")
--                message = tmpFile.read()
-+                message = decode_text_stream(tmpFile.read())
-                 tmpFile.close()
-                 if self.isWindows:
-                     message = message.replace("\r\n", "\n")
-@@ -2490,7 +2522,7 @@ def append(self, view_line):
- 
-     def convert_client_path(self, clientFile):
-         # chop off //client/ part to make it relative
--        if not clientFile.startswith(self.client_prefix):
-+        if not decode_path(clientFile).startswith(self.client_prefix):
-             die("No prefix '%s' on clientFile '%s'" %
-                 (self.client_prefix, clientFile))
-         return clientFile[len(self.client_prefix):]
-@@ -2499,7 +2531,7 @@ def update_client_spec_path_cache(self, files):
-         """ Caching file paths by "p4 where" batch query """
- 
-         # List depot file paths exclude that already cached
--        fileArgs = [f['path'] for f in files if f['path'] not in self.client_spec_path_cache]
-+        fileArgs = [f['path'] for f in files if decode_path(f['path']) not in self.client_spec_path_cache]
- 
-         if len(fileArgs) == 0:
-             return  # All files in cache
-@@ -2514,16 +2546,18 @@ def update_client_spec_path_cache(self, files):
-             if "unmap" in res:
-                 # it will list all of them, but only one not unmap-ped
-                 continue
-+            depot_path = decode_path(res['depotFile'])
-             if gitConfigBool("core.ignorecase"):
--                res['depotFile'] = res['depotFile'].lower()
--            self.client_spec_path_cache[res['depotFile']] = self.convert_client_path(res["clientFile"])
-+                depot_path = depot_path.lower()
-+            self.client_spec_path_cache[depot_path] = self.convert_client_path(res["clientFile"])
- 
-         # not found files or unmap files set to ""
-         for depotFile in fileArgs:
-+            depotFile = decode_path(depotFile)
-             if gitConfigBool("core.ignorecase"):
-                 depotFile = depotFile.lower()
-             if depotFile not in self.client_spec_path_cache:
--                self.client_spec_path_cache[depotFile] = ""
-+                self.client_spec_path_cache[depotFile] = b''
- 
-     def map_in_client(self, depot_path):
-         """Return the relative location in the client where this
-@@ -2628,6 +2662,7 @@ def __init__(self):
-     def checkpoint(self):
-         self.gitStream.write("checkpoint\n\n")
-         self.gitStream.write("progress checkpoint\n\n")
-+        self.gitStream.flush()
-         out = self.gitOutput.readline()
-         if self.verbose:
-             print("checkpoint finished: " + out)
-@@ -2641,7 +2676,7 @@ def isPathWanted(self, path):
-             elif path.lower() == p.lower():
-                 return False
-         for p in self.depotPaths:
--            if p4PathStartsWith(path, p):
-+            if p4PathStartsWith(path, decode_path(p)):
-                 return True
-         return False
- 
-@@ -2650,7 +2685,7 @@ def extractFilesFromCommit(self, commit, shelved=False, shelved_cl = 0):
-         fnum = 0
-         while "depotFile%s" % fnum in commit:
-             path =  commit["depotFile%s" % fnum]
--            found = self.isPathWanted(path)
-+            found = self.isPathWanted(decode_path(path))
-             if not found:
-                 fnum = fnum + 1
-                 continue
-@@ -2684,7 +2719,7 @@ def stripRepoPath(self, path, prefixes):
-         if self.useClientSpec:
-             # branch detection moves files up a level (the branch name)
-             # from what client spec interpretation gives
--            path = self.clientSpecDirs.map_in_client(path)
-+            path = decode_path(self.clientSpecDirs.map_in_client(path))
-             if self.detectBranches:
-                 for b in self.knownBranches:
-                     if p4PathStartsWith(path, b + "/"):
-@@ -2718,14 +2753,15 @@ def splitFilesIntoBranches(self, commit):
-         branches = {}
-         fnum = 0
-         while "depotFile%s" % fnum in commit:
--            path =  commit["depotFile%s" % fnum]
-+            raw_path = commit["depotFile%s" % fnum]
-+            path = decode_path(raw_path)
-             found = self.isPathWanted(path)
-             if not found:
-                 fnum = fnum + 1
-                 continue
- 
-             file = {}
--            file["path"] = path
-+            file["path"] = raw_path
-             file["rev"] = commit["rev%s" % fnum]
-             file["action"] = commit["action%s" % fnum]
-             file["type"] = commit["type%s" % fnum]
-@@ -2734,7 +2770,7 @@ def splitFilesIntoBranches(self, commit):
-             # start with the full relative path where this file would
-             # go in a p4 client
-             if self.useClientSpec:
--                relPath = self.clientSpecDirs.map_in_client(path)
-+                relPath = decode_path(self.clientSpecDirs.map_in_client(path))
-             else:
-                 relPath = self.stripRepoPath(path, self.depotPaths)
- 
-@@ -2750,7 +2786,7 @@ def splitFilesIntoBranches(self, commit):
-         return branches
- 
-     def writeToGitStream(self, gitMode, relPath, contents):
--        self.gitStream.write('M %s inline %s\n' % (gitMode, relPath))
-+        self.gitStream.write(encode_text_stream(u'M {} inline {}\n'.format(gitMode, relPath)))
-         self.gitStream.write('data %d\n' % sum(len(d) for d in contents))
-         for d in contents:
-             self.gitStream.write(d)
-@@ -2772,14 +2808,15 @@ def encodeWithUTF8(self, path):
-     # - helper for streamP4Files
- 
-     def streamOneP4File(self, file, contents):
--        relPath = self.stripRepoPath(file['depotFile'], self.branchPrefixes)
--        relPath = self.encodeWithUTF8(relPath)
-+        file_path = file['depotFile']
-+        relPath = self.stripRepoPath(decode_path(file_path), self.branchPrefixes)
-+
-         if verbose:
-             if 'fileSize' in self.stream_file:
-                 size = int(self.stream_file['fileSize'])
-             else:
-                 size = 0 # deleted files don't get a fileSize apparently
--            sys.stdout.write('\r%s --> %s (%i MB)\n' % (file['depotFile'], relPath, size/1024/1024))
-+            sys.stdout.write('\r%s --> %s (%i MB)\n' % (file_path, relPath, size/1024/1024))
-             sys.stdout.flush()
- 
-         (type_base, type_mods) = split_p4_type(file["type"])
-@@ -2791,13 +2828,13 @@ def streamOneP4File(self, file, contents):
-             git_mode = "120000"
-             # p4 print on a symlink sometimes contains "target\n";
-             # if it does, remove the newline
--            data = ''.join(contents)
-+            data = ''.join(decode_text_stream(c) for c in contents)
-             if not data:
-                 # Some version of p4 allowed creating a symlink that pointed
-                 # to nothing.  This causes p4 errors when checking out such
-                 # a change, and errors here too.  Work around it by ignoring
-                 # the bad symlink; hopefully a future change fixes it.
--                print("\nIgnoring empty symlink in %s" % file['depotFile'])
-+                print("\nIgnoring empty symlink in %s" % file_path)
-                 return
-             elif data[-1] == '\n':
-                 contents = [data[:-1]]
-@@ -2816,7 +2853,7 @@ def streamOneP4File(self, file, contents):
-             # just the native "NT" type.
-             #
-             try:
--                text = p4_read_pipe(['print', '-q', '-o', '-', '%s@%s' % (file['depotFile'], file['change'])])
-+                text = p4_read_pipe(['print', '-q', '-o', '-', '%s@%s' % (decode_path(file['depotFile']), file['change'])], raw=True)
-             except Exception as e:
-                 if 'Translation of file content failed' in str(e):
-                     type_base = 'binary'
-@@ -2824,7 +2861,7 @@ def streamOneP4File(self, file, contents):
-                     raise e
-             else:
-                 if p4_version_string().find('/NT') >= 0:
--                    text = text.replace('\r\n', '\n')
-+                    text = text.replace(b'\r\n', b'\n')
-                 contents = [ text ]
- 
-         if type_base == "apple":
-@@ -2845,7 +2882,7 @@ def streamOneP4File(self, file, contents):
-         pattern = p4_keywords_regexp_for_type(type_base, type_mods)
-         if pattern:
-             regexp = re.compile(pattern, re.VERBOSE)
--            text = ''.join(contents)
-+            text = ''.join(decode_text_stream(c) for c in contents)
-             text = regexp.sub(r'$\1$', text)
-             contents = [ text ]
- 
-@@ -2855,12 +2892,11 @@ def streamOneP4File(self, file, contents):
-         self.writeToGitStream(git_mode, relPath, contents)
- 
-     def streamOneP4Deletion(self, file):
--        relPath = self.stripRepoPath(file['path'], self.branchPrefixes)
--        relPath = self.encodeWithUTF8(relPath)
-+        relPath = self.stripRepoPath(decode_path(file['path']), self.branchPrefixes)
-         if verbose:
-             sys.stdout.write("delete %s\n" % relPath)
-             sys.stdout.flush()
--        self.gitStream.write("D %s\n" % relPath)
-+        self.gitStream.write(encode_text_stream(u'D {}\n'.format(relPath)))
- 
-         if self.largeFileSystem and self.largeFileSystem.isLargeFile(relPath):
-             self.largeFileSystem.removeLargeFile(relPath)
-@@ -2960,9 +2996,9 @@ def streamP4FilesCbSelf(entry):
-                 if 'shelved_cl' in f:
-                     # Handle shelved CLs using the "p4 print file@=N" syntax to print
-                     # the contents
--                    fileArg = '%s@=%d' % (f['path'], f['shelved_cl'])
-+                    fileArg = f['path'] + encode_text_stream('@={}'.format(f['shelved_cl']))
-                 else:
--                    fileArg = '%s#%s' % (f['path'], f['rev'])
-+                    fileArg = f['path'] + encode_text_stream('#{}'.format(f['rev']))
- 
-                 fileArgs.append(fileArg)
- 
-@@ -3043,8 +3079,8 @@ def commit(self, details, files, branch, parent = "", allow_empty=False):
-         if self.clientSpecDirs:
-             self.clientSpecDirs.update_client_spec_path_cache(files)
- 
--        files = [f for f in files
--            if self.inClientSpec(f['path']) and self.hasBranchPrefix(f['path'])]
-+        files = [f for (f, path) in ((f, decode_path(f['path'])) for f in files)
-+            if self.inClientSpec(path) and self.hasBranchPrefix(path)]
- 
-         if gitConfigBool('git-p4.keepEmptyCommits'):
-             allow_empty = True
-@@ -3548,6 +3584,15 @@ def openStreams(self):
-         self.gitStream = self.importProcess.stdin
-         self.gitError = self.importProcess.stderr
- 
-+        if bytes is not str:
-+            # Wrap gitStream.write() so that it can be called using `str` arguments
-+            def make_encoded_write(write):
-+                def encoded_write(s):
-+                    return write(s.encode() if isinstance(s, str) else s)
-+                return encoded_write
-+
-+            self.gitStream.write = make_encoded_write(self.gitStream.write)
-+
-     def closeStreams(self):
-         self.gitStream.close()
-         if self.importProcess.wait() != 0:

Copied: git/repos/extra-x86_64/0001-git-p4-python.patch (from rev 377835, git/trunk/0001-git-p4-python.patch)
===================================================================
--- 0001-git-p4-python.patch	                        (rev 0)
+++ 0001-git-p4-python.patch	2020-03-18 07:35:08 UTC (rev 377836)
@@ -0,0 +1,631 @@
+diff --git a/git-p4.py b/git-p4.py
+index 40d9e7c594..ca0a874501 100755
+--- a/git-p4.py
++++ b/git-p4.py
+@@ -8,12 +8,12 @@
+ # License: MIT <http://www.opensource.org/licenses/mit-license.php>
+ #
+ import sys
+-if sys.hexversion < 0x02040000:
+-    # The limiter is the subprocess module
+-    sys.stderr.write("git-p4: requires Python 2.4 or later.\n")
++if sys.version_info.major < 3 and sys.version_info.minor < 7:
++    sys.stderr.write("git-p4: requires Python 2.7 or later.\n")
+     sys.exit(1)
+ import os
+ import optparse
++import functools
+ import marshal
+ import subprocess
+ import tempfile
+@@ -27,36 +27,15 @@
+ import ctypes
+ import errno
+ 
++# On python2.7 where raw_input() and input() are both availble,
++# we want raw_input's semantics, but aliased to input for python3
++# compatibility
+ # support basestring in python3
+ try:
+-    unicode = unicode
+-except NameError:
+-    # 'unicode' is undefined, must be Python 3
+-    str = str
+-    unicode = str
+-    bytes = bytes
+-    basestring = (str,bytes)
+-else:
+-    # 'unicode' exists, must be Python 2
+-    str = str
+-    unicode = unicode
+-    bytes = str
+-    basestring = basestring
+-
+-try:
+-    from subprocess import CalledProcessError
+-except ImportError:
+-    # from python2.7:subprocess.py
+-    # Exception classes used by this module.
+-    class CalledProcessError(Exception):
+-        """This exception is raised when a process run by check_call() returns
+-        a non-zero exit status.  The exit status will be stored in the
+-        returncode attribute."""
+-        def __init__(self, returncode, cmd):
+-            self.returncode = returncode
+-            self.cmd = cmd
+-        def __str__(self):
+-            return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode)
++    if raw_input and input:
++        input = raw_input
++except:
++    pass
+ 
+ verbose = False
+ 
+@@ -105,7 +84,7 @@ def p4_build_cmd(cmd):
+         # Provide a way to not pass this option by setting git-p4.retries to 0
+         real_cmd += ["-r", str(retries)]
+ 
+-    if isinstance(cmd,basestring):
++    if not isinstance(cmd, list):
+         real_cmd = ' '.join(real_cmd) + ' ' + cmd
+     else:
+         real_cmd += cmd
+@@ -175,18 +154,48 @@ def prompt(prompt_text):
+     """
+     choices = set(m.group(1) for m in re.finditer(r"\[(.)\]", prompt_text))
+     while True:
+-        response = raw_input(prompt_text).strip().lower()
++        response = input(prompt_text).strip().lower()
+         if not response:
+             continue
+         response = response[0]
+         if response in choices:
+             return response
+ 
++# We need different encoding/decoding strategies for text data being passed
++# around in pipes depending on python version
++if bytes is not str:
++    # For python3, always encode and decode as appropriate
++    def decode_text_stream(s):
++        return s.decode() if isinstance(s, bytes) else s
++    def encode_text_stream(s):
++        return s.encode() if isinstance(s, str) else s
++else:
++    # For python2.7, pass read strings as-is, but also allow writing unicode
++    def decode_text_stream(s):
++        return s
++    def encode_text_stream(s):
++        return s.encode('utf_8') if isinstance(s, unicode) else s
++
++def decode_path(path):
++    """Decode a given string (bytes or otherwise) using configured path encoding options
++    """
++    encoding = gitConfig('git-p4.pathEncoding') or 'utf_8'
++    if bytes is not str:
++        return path.decode(encoding, errors='replace') if isinstance(path, bytes) else path
++    else:
++        try:
++            path.decode('ascii')
++        except:
++            path = path.decode(encoding, errors='replace')
++            if verbose:
++                print('Path with non-ASCII characters detected. Used {} to decode: {}'.format(encoding, path))
++        return path
++
+ def write_pipe(c, stdin):
+     if verbose:
+         sys.stderr.write('Writing pipe: %s\n' % str(c))
+ 
+-    expand = isinstance(c,basestring)
++    expand = not isinstance(c, list)
+     p = subprocess.Popen(c, stdin=subprocess.PIPE, shell=expand)
+     pipe = p.stdin
+     val = pipe.write(stdin)
+@@ -198,6 +207,8 @@ def write_pipe(c, stdin):
+ 
+ def p4_write_pipe(c, stdin):
+     real_cmd = p4_build_cmd(c)
++    if bytes is not str and isinstance(stdin, str):
++        stdin = encode_text_stream(stdin)
+     return write_pipe(real_cmd, stdin)
+ 
+ def read_pipe_full(c):
+@@ -208,15 +219,17 @@ def read_pipe_full(c):
+     if verbose:
+         sys.stderr.write('Reading pipe: %s\n' % str(c))
+ 
+-    expand = isinstance(c,basestring)
++    expand = not isinstance(c, list)
+     p = subprocess.Popen(c, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=expand)
+     (out, err) = p.communicate()
+-    return (p.returncode, out, err)
++    return (p.returncode, out, decode_text_stream(err))
+ 
+-def read_pipe(c, ignore_error=False):
++def read_pipe(c, ignore_error=False, raw=False):
+     """ Read output from  command. Returns the output text on
+         success. On failure, terminates execution, unless
+         ignore_error is True, when it returns an empty string.
++
++        If raw is True, do not attempt to decode output text.
+     """
+     (retcode, out, err) = read_pipe_full(c)
+     if retcode != 0:
+@@ -224,6 +237,8 @@ def read_pipe(c, ignore_error=False):
+             out = ""
+         else:
+             die('Command failed: %s\nError: %s' % (str(c), err))
++    if not raw:
++        out = decode_text_stream(out)
+     return out
+ 
+ def read_pipe_text(c):
+@@ -234,23 +249,22 @@ def read_pipe_text(c):
+     if retcode != 0:
+         return None
+     else:
+-        return out.rstrip()
++        return decode_text_stream(out).rstrip()
+ 
+-def p4_read_pipe(c, ignore_error=False):
++def p4_read_pipe(c, ignore_error=False, raw=False):
+     real_cmd = p4_build_cmd(c)
+-    return read_pipe(real_cmd, ignore_error)
++    return read_pipe(real_cmd, ignore_error, raw=raw)
+ 
+ def read_pipe_lines(c):
+     if verbose:
+         sys.stderr.write('Reading pipe: %s\n' % str(c))
+ 
+-    expand = isinstance(c, basestring)
++    expand = not isinstance(c, list)
+     p = subprocess.Popen(c, stdout=subprocess.PIPE, shell=expand)
+     pipe = p.stdout
+-    val = pipe.readlines()
++    val = [decode_text_stream(line) for line in pipe.readlines()]
+     if pipe.close() or p.wait():
+         die('Command failed: %s' % str(c))
+-
+     return val
+ 
+ def p4_read_pipe_lines(c):
+@@ -278,6 +292,7 @@ def p4_has_move_command():
+     cmd = p4_build_cmd(["move", "-k", "@from", "@to"])
+     p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+     (out, err) = p.communicate()
++    err = decode_text_stream(err)
+     # return code will be 1 in either case
+     if err.find("Invalid option") >= 0:
+         return False
+@@ -287,7 +302,7 @@ def p4_has_move_command():
+     return True
+ 
+ def system(cmd, ignore_error=False):
+-    expand = isinstance(cmd,basestring)
++    expand = not isinstance(cmd, list)
+     if verbose:
+         sys.stderr.write("executing %s\n" % str(cmd))
+     retcode = subprocess.call(cmd, shell=expand)
+@@ -299,7 +314,7 @@ def system(cmd, ignore_error=False):
+ def p4_system(cmd):
+     """Specifically invoke p4 as the system command. """
+     real_cmd = p4_build_cmd(cmd)
+-    expand = isinstance(real_cmd, basestring)
++    expand = not isinstance(real_cmd, list)
+     retcode = subprocess.call(real_cmd, shell=expand)
+     if retcode:
+         raise CalledProcessError(retcode, real_cmd)
+@@ -537,7 +552,7 @@ def getP4OpenedType(file):
+ # Return the set of all p4 labels
+ def getP4Labels(depotPaths):
+     labels = set()
+-    if isinstance(depotPaths,basestring):
++    if not isinstance(depotPaths, list):
+         depotPaths = [depotPaths]
+ 
+     for l in p4CmdList(["labels"] + ["%s..." % p for p in depotPaths]):
+@@ -554,12 +569,7 @@ def getGitTags():
+         gitTags.add(tag)
+     return gitTags
+ 
+-def diffTreePattern():
+-    # This is a simple generator for the diff tree regex pattern. This could be
+-    # a class variable if this and parseDiffTreeEntry were a part of a class.
+-    pattern = re.compile(':(\d+) (\d+) (\w+) (\w+) ([A-Z])(\d+)?\t(.*?)((\t(.*))|$)')
+-    while True:
+-        yield pattern
++_diff_tree_pattern = None
+ 
+ def parseDiffTreeEntry(entry):
+     """Parses a single diff tree entry into its component elements.
+@@ -580,7 +590,11 @@ def parseDiffTreeEntry(entry):
+ 
+     If the pattern is not matched, None is returned."""
+ 
+-    match = diffTreePattern().next().match(entry)
++    global _diff_tree_pattern
++    if not _diff_tree_pattern:
++        _diff_tree_pattern = re.compile(':(\d+) (\d+) (\w+) (\w+) ([A-Z])(\d+)?\t(.*?)((\t(.*))|$)')
++
++    match = _diff_tree_pattern.match(entry)
+     if match:
+         return {
+             'src_mode': match.group(1),
+@@ -624,7 +638,7 @@ def isModeExecChanged(src_mode, dst_mode):
+ def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None, skip_info=False,
+         errors_as_exceptions=False):
+ 
+-    if isinstance(cmd,basestring):
++    if not isinstance(cmd, list):
+         cmd = "-G " + cmd
+         expand = True
+     else:
+@@ -641,11 +655,12 @@ def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None, skip_info=False,
+     stdin_file = None
+     if stdin is not None:
+         stdin_file = tempfile.TemporaryFile(prefix='p4-stdin', mode=stdin_mode)
+-        if isinstance(stdin,basestring):
++        if not isinstance(stdin, list):
+             stdin_file.write(stdin)
+         else:
+             for i in stdin:
+-                stdin_file.write(i + '\n')
++                stdin_file.write(encode_text_stream(i))
++                stdin_file.write(b'\n')
+         stdin_file.flush()
+         stdin_file.seek(0)
+ 
+@@ -658,6 +673,20 @@ def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None, skip_info=False,
+     try:
+         while True:
+             entry = marshal.load(p4.stdout)
++            if bytes is not str:
++                # Decode unmarshalled dict to use str keys and values, except for:
++                #   - `data` which may contain arbitrary binary data
++                #   - `depotFile[0-9]*`, `path`, or `clientFile` which may contain non-UTF8 encoded text
++                decoded_entry = {}
++                for key, value in entry.items():
++                    key = key.decode()
++                    if isinstance(value, bytes) and not (key in ('data', 'path', 'clientFile') or key.startswith('depotFile')):
++                        value = value.decode()
++                    decoded_entry[key] = value
++                # Parse out data if it's an error response
++                if decoded_entry.get('code') == 'error' and 'data' in decoded_entry:
++                    decoded_entry['data'] = decoded_entry['data'].decode()
++                entry = decoded_entry
+             if skip_info:
+                 if 'code' in entry and entry['code'] == 'info':
+                     continue
+@@ -708,7 +737,8 @@ def p4Where(depotPath):
+         if "depotFile" in entry:
+             # Search for the base client side depot path, as long as it starts with the branch's P4 path.
+             # The base path always ends with "/...".
+-            if entry["depotFile"].find(depotPath) == 0 and entry["depotFile"][-4:] == "/...":
++            entry_path = decode_path(entry['depotFile'])
++            if entry_path.find(depotPath) == 0 and entry_path[-4:] == "/...":
+                 output = entry
+                 break
+         elif "data" in entry:
+@@ -723,11 +753,11 @@ def p4Where(depotPath):
+         return ""
+     clientPath = ""
+     if "path" in output:
+-        clientPath = output.get("path")
++        clientPath = decode_path(output['path'])
+     elif "data" in output:
+         data = output.get("data")
+-        lastSpace = data.rfind(" ")
+-        clientPath = data[lastSpace + 1:]
++        lastSpace = data.rfind(b" ")
++        clientPath = decode_path(data[lastSpace + 1:])
+ 
+     if clientPath.endswith("..."):
+         clientPath = clientPath[:-3]
+@@ -875,6 +905,7 @@ def branch_exists(branch):
+     cmd = [ "git", "rev-parse", "--symbolic", "--verify", branch ]
+     p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+     out, _ = p.communicate()
++    out = decode_text_stream(out)
+     if p.returncode:
+         return False
+     # expect exactly one line of output: the branch name
+@@ -1152,7 +1183,7 @@ def pushFile(self, localLargeFile):
+         assert False, "Method 'pushFile' required in " + self.__class__.__name__
+ 
+     def hasLargeFileExtension(self, relPath):
+-        return reduce(
++        return functools.reduce(
+             lambda a, b: a or b,
+             [relPath.endswith('.' + e) for e in gitConfigList('git-p4.largeFileExtensions')],
+             False
+@@ -1259,7 +1290,7 @@ def generatePointer(self, contentFile):
+             ['git', 'lfs', 'pointer', '--file=' + contentFile],
+             stdout=subprocess.PIPE
+         )
+-        pointerFile = pointerProcess.stdout.read()
++        pointerFile = decode_text_stream(pointerProcess.stdout.read())
+         if pointerProcess.wait():
+             os.remove(contentFile)
+             die('git-lfs pointer command failed. Did you install the extension?')
+@@ -1395,14 +1426,14 @@ def getUserMapFromPerforceServer(self):
+         for (key, val) in self.users.items():
+             s += "%s\t%s\n" % (key.expandtabs(1), val.expandtabs(1))
+ 
+-        open(self.getUserCacheFilename(), "wb").write(s)
++        open(self.getUserCacheFilename(), 'w').write(s)
+         self.userMapFromPerforceServer = True
+ 
+     def loadUserMapFromCache(self):
+         self.users = {}
+         self.userMapFromPerforceServer = False
+         try:
+-            cache = open(self.getUserCacheFilename(), "rb")
++            cache = open(self.getUserCacheFilename(), 'r')
+             lines = cache.readlines()
+             cache.close()
+             for line in lines:
+@@ -1679,7 +1710,8 @@ def modifyChangelistUser(self, changelist, newUser):
+         c = changes[0]
+         if c['User'] == newUser: return   # nothing to do
+         c['User'] = newUser
+-        input = marshal.dumps(c)
++        # p4 does not understand format version 3 and above
++        input = marshal.dumps(c, 2)
+ 
+         result = p4CmdList("change -f -i", stdin=input)
+         for r in result:
+@@ -1743,7 +1775,7 @@ def prepareSubmitTemplate(self, changelist=None):
+                 break
+         if not change_entry:
+             die('Failed to decode output of p4 change -o')
+-        for key, value in change_entry.iteritems():
++        for key, value in change_entry.items():
+             if key.startswith('File'):
+                 if 'depot-paths' in settings:
+                     if not [p for p in settings['depot-paths']
+@@ -2023,7 +2055,7 @@ def applyCommit(self, id):
+         tmpFile = os.fdopen(handle, "w+b")
+         if self.isWindows:
+             submitTemplate = submitTemplate.replace("\n", "\r\n")
+-        tmpFile.write(submitTemplate)
++        tmpFile.write(encode_text_stream(submitTemplate))
+         tmpFile.close()
+ 
+         if self.prepare_p4_only:
+@@ -2070,7 +2102,7 @@ def applyCommit(self, id):
+             if self.edit_template(fileName):
+                 # read the edited message and submit
+                 tmpFile = open(fileName, "rb")
+-                message = tmpFile.read()
++                message = decode_text_stream(tmpFile.read())
+                 tmpFile.close()
+                 if self.isWindows:
+                     message = message.replace("\r\n", "\n")
+@@ -2490,7 +2522,7 @@ def append(self, view_line):
+ 
+     def convert_client_path(self, clientFile):
+         # chop off //client/ part to make it relative
+-        if not clientFile.startswith(self.client_prefix):
++        if not decode_path(clientFile).startswith(self.client_prefix):
+             die("No prefix '%s' on clientFile '%s'" %
+                 (self.client_prefix, clientFile))
+         return clientFile[len(self.client_prefix):]
+@@ -2499,7 +2531,7 @@ def update_client_spec_path_cache(self, files):
+         """ Caching file paths by "p4 where" batch query """
+ 
+         # List depot file paths exclude that already cached
+-        fileArgs = [f['path'] for f in files if f['path'] not in self.client_spec_path_cache]
++        fileArgs = [f['path'] for f in files if decode_path(f['path']) not in self.client_spec_path_cache]
+ 
+         if len(fileArgs) == 0:
+             return  # All files in cache
+@@ -2514,16 +2546,18 @@ def update_client_spec_path_cache(self, files):
+             if "unmap" in res:
+                 # it will list all of them, but only one not unmap-ped
+                 continue
++            depot_path = decode_path(res['depotFile'])
+             if gitConfigBool("core.ignorecase"):
+-                res['depotFile'] = res['depotFile'].lower()
+-            self.client_spec_path_cache[res['depotFile']] = self.convert_client_path(res["clientFile"])
++                depot_path = depot_path.lower()
++            self.client_spec_path_cache[depot_path] = self.convert_client_path(res["clientFile"])
+ 
+         # not found files or unmap files set to ""
+         for depotFile in fileArgs:
++            depotFile = decode_path(depotFile)
+             if gitConfigBool("core.ignorecase"):
+                 depotFile = depotFile.lower()
+             if depotFile not in self.client_spec_path_cache:
+-                self.client_spec_path_cache[depotFile] = ""
++                self.client_spec_path_cache[depotFile] = b''
+ 
+     def map_in_client(self, depot_path):
+         """Return the relative location in the client where this
+@@ -2628,6 +2662,7 @@ def __init__(self):
+     def checkpoint(self):
+         self.gitStream.write("checkpoint\n\n")
+         self.gitStream.write("progress checkpoint\n\n")
++        self.gitStream.flush()
+         out = self.gitOutput.readline()
+         if self.verbose:
+             print("checkpoint finished: " + out)
+@@ -2641,7 +2676,7 @@ def isPathWanted(self, path):
+             elif path.lower() == p.lower():
+                 return False
+         for p in self.depotPaths:
+-            if p4PathStartsWith(path, p):
++            if p4PathStartsWith(path, decode_path(p)):
+                 return True
+         return False
+ 
+@@ -2650,7 +2685,7 @@ def extractFilesFromCommit(self, commit, shelved=False, shelved_cl = 0):
+         fnum = 0
+         while "depotFile%s" % fnum in commit:
+             path =  commit["depotFile%s" % fnum]
+-            found = self.isPathWanted(path)
++            found = self.isPathWanted(decode_path(path))
+             if not found:
+                 fnum = fnum + 1
+                 continue
+@@ -2684,7 +2719,7 @@ def stripRepoPath(self, path, prefixes):
+         if self.useClientSpec:
+             # branch detection moves files up a level (the branch name)
+             # from what client spec interpretation gives
+-            path = self.clientSpecDirs.map_in_client(path)
++            path = decode_path(self.clientSpecDirs.map_in_client(path))
+             if self.detectBranches:
+                 for b in self.knownBranches:
+                     if p4PathStartsWith(path, b + "/"):
+@@ -2718,14 +2753,15 @@ def splitFilesIntoBranches(self, commit):
+         branches = {}
+         fnum = 0
+         while "depotFile%s" % fnum in commit:
+-            path =  commit["depotFile%s" % fnum]
++            raw_path = commit["depotFile%s" % fnum]
++            path = decode_path(raw_path)
+             found = self.isPathWanted(path)
+             if not found:
+                 fnum = fnum + 1
+                 continue
+ 
+             file = {}
+-            file["path"] = path
++            file["path"] = raw_path
+             file["rev"] = commit["rev%s" % fnum]
+             file["action"] = commit["action%s" % fnum]
+             file["type"] = commit["type%s" % fnum]
+@@ -2734,7 +2770,7 @@ def splitFilesIntoBranches(self, commit):
+             # start with the full relative path where this file would
+             # go in a p4 client
+             if self.useClientSpec:
+-                relPath = self.clientSpecDirs.map_in_client(path)
++                relPath = decode_path(self.clientSpecDirs.map_in_client(path))
+             else:
+                 relPath = self.stripRepoPath(path, self.depotPaths)
+ 
+@@ -2750,7 +2786,7 @@ def splitFilesIntoBranches(self, commit):
+         return branches
+ 
+     def writeToGitStream(self, gitMode, relPath, contents):
+-        self.gitStream.write('M %s inline %s\n' % (gitMode, relPath))
++        self.gitStream.write(encode_text_stream(u'M {} inline {}\n'.format(gitMode, relPath)))
+         self.gitStream.write('data %d\n' % sum(len(d) for d in contents))
+         for d in contents:
+             self.gitStream.write(d)
+@@ -2772,14 +2808,15 @@ def encodeWithUTF8(self, path):
+     # - helper for streamP4Files
+ 
+     def streamOneP4File(self, file, contents):
+-        relPath = self.stripRepoPath(file['depotFile'], self.branchPrefixes)
+-        relPath = self.encodeWithUTF8(relPath)
++        file_path = file['depotFile']
++        relPath = self.stripRepoPath(decode_path(file_path), self.branchPrefixes)
++
+         if verbose:
+             if 'fileSize' in self.stream_file:
+                 size = int(self.stream_file['fileSize'])
+             else:
+                 size = 0 # deleted files don't get a fileSize apparently
+-            sys.stdout.write('\r%s --> %s (%i MB)\n' % (file['depotFile'], relPath, size/1024/1024))
++            sys.stdout.write('\r%s --> %s (%i MB)\n' % (file_path, relPath, size/1024/1024))
+             sys.stdout.flush()
+ 
+         (type_base, type_mods) = split_p4_type(file["type"])
+@@ -2791,13 +2828,13 @@ def streamOneP4File(self, file, contents):
+             git_mode = "120000"
+             # p4 print on a symlink sometimes contains "target\n";
+             # if it does, remove the newline
+-            data = ''.join(contents)
++            data = ''.join(decode_text_stream(c) for c in contents)
+             if not data:
+                 # Some version of p4 allowed creating a symlink that pointed
+                 # to nothing.  This causes p4 errors when checking out such
+                 # a change, and errors here too.  Work around it by ignoring
+                 # the bad symlink; hopefully a future change fixes it.
+-                print("\nIgnoring empty symlink in %s" % file['depotFile'])
++                print("\nIgnoring empty symlink in %s" % file_path)
+                 return
+             elif data[-1] == '\n':
+                 contents = [data[:-1]]
+@@ -2816,7 +2853,7 @@ def streamOneP4File(self, file, contents):
+             # just the native "NT" type.
+             #
+             try:
+-                text = p4_read_pipe(['print', '-q', '-o', '-', '%s@%s' % (file['depotFile'], file['change'])])
++                text = p4_read_pipe(['print', '-q', '-o', '-', '%s@%s' % (decode_path(file['depotFile']), file['change'])], raw=True)
+             except Exception as e:
+                 if 'Translation of file content failed' in str(e):
+                     type_base = 'binary'
+@@ -2824,7 +2861,7 @@ def streamOneP4File(self, file, contents):
+                     raise e
+             else:
+                 if p4_version_string().find('/NT') >= 0:
+-                    text = text.replace('\r\n', '\n')
++                    text = text.replace(b'\r\n', b'\n')
+                 contents = [ text ]
+ 
+         if type_base == "apple":
+@@ -2845,7 +2882,7 @@ def streamOneP4File(self, file, contents):
+         pattern = p4_keywords_regexp_for_type(type_base, type_mods)
+         if pattern:
+             regexp = re.compile(pattern, re.VERBOSE)
+-            text = ''.join(contents)
++            text = ''.join(decode_text_stream(c) for c in contents)
+             text = regexp.sub(r'$\1$', text)
+             contents = [ text ]
+ 
+@@ -2855,12 +2892,11 @@ def streamOneP4File(self, file, contents):
+         self.writeToGitStream(git_mode, relPath, contents)
+ 
+     def streamOneP4Deletion(self, file):
+-        relPath = self.stripRepoPath(file['path'], self.branchPrefixes)
+-        relPath = self.encodeWithUTF8(relPath)
++        relPath = self.stripRepoPath(decode_path(file['path']), self.branchPrefixes)
+         if verbose:
+             sys.stdout.write("delete %s\n" % relPath)
+             sys.stdout.flush()
+-        self.gitStream.write("D %s\n" % relPath)
++        self.gitStream.write(encode_text_stream(u'D {}\n'.format(relPath)))
+ 
+         if self.largeFileSystem and self.largeFileSystem.isLargeFile(relPath):
+             self.largeFileSystem.removeLargeFile(relPath)
+@@ -2960,9 +2996,9 @@ def streamP4FilesCbSelf(entry):
+                 if 'shelved_cl' in f:
+                     # Handle shelved CLs using the "p4 print file@=N" syntax to print
+                     # the contents
+-                    fileArg = '%s@=%d' % (f['path'], f['shelved_cl'])
++                    fileArg = f['path'] + encode_text_stream('@={}'.format(f['shelved_cl']))
+                 else:
+-                    fileArg = '%s#%s' % (f['path'], f['rev'])
++                    fileArg = f['path'] + encode_text_stream('#{}'.format(f['rev']))
+ 
+                 fileArgs.append(fileArg)
+ 
+@@ -3043,8 +3079,8 @@ def commit(self, details, files, branch, parent = "", allow_empty=False):
+         if self.clientSpecDirs:
+             self.clientSpecDirs.update_client_spec_path_cache(files)
+ 
+-        files = [f for f in files
+-            if self.inClientSpec(f['path']) and self.hasBranchPrefix(f['path'])]
++        files = [f for (f, path) in ((f, decode_path(f['path'])) for f in files)
++            if self.inClientSpec(path) and self.hasBranchPrefix(path)]
+ 
+         if gitConfigBool('git-p4.keepEmptyCommits'):
+             allow_empty = True
+@@ -3548,6 +3584,15 @@ def openStreams(self):
+         self.gitStream = self.importProcess.stdin
+         self.gitError = self.importProcess.stderr
+ 
++        if bytes is not str:
++            # Wrap gitStream.write() so that it can be called using `str` arguments
++            def make_encoded_write(write):
++                def encoded_write(s):
++                    return write(s.encode() if isinstance(s, str) else s)
++                return encoded_write
++
++            self.gitStream.write = make_encoded_write(self.gitStream.write)
++
+     def closeStreams(self):
+         self.gitStream.close()
+         if self.importProcess.wait() != 0:

Deleted: PKGBUILD
===================================================================
--- PKGBUILD	2020-03-18 07:35:01 UTC (rev 377835)
+++ PKGBUILD	2020-03-18 07:35:08 UTC (rev 377836)
@@ -1,136 +0,0 @@
-# Maintainer: Christian Hesse <mail at eworm.de>
-# Maintainer: Dan McGee <dan at archlinux.org>
-
-pkgname=git
-pkgver=2.25.1
-pkgrel=1
-pkgdesc='the fast distributed version control system'
-arch=('x86_64')
-url='https://git-scm.com/'
-license=('GPL2')
-depends=('curl' 'expat' 'perl' 'perl-error' 'perl-mailtools'
-         'openssl' 'pcre2' 'grep' 'shadow')
-makedepends=('python' 'libgnome-keyring' 'xmlto' 'asciidoc')
-optdepends=('tk: gitk and git gui'
-            'perl-libwww: git svn'
-            'perl-term-readkey: git svn and interactive.singlekey setting'
-            'perl-mime-tools: git send-email'
-            'perl-net-smtp-ssl: git send-email TLS support'
-            'perl-authen-sasl: git send-email TLS support'
-            'perl-mediawiki-api: git mediawiki support'
-            'perl-datetime-format-iso8601: git mediawiki support'
-            'perl-lwp-protocol-https: git mediawiki https support'
-            'perl-cgi: gitweb (web interface) support'
-            'python: git svn & git p4'
-            'subversion: git svn'
-            'org.freedesktop.secrets: keyring credential helper'
-            'libsecret: libsecret credential helper')
-install=git.install
-validpgpkeys=('96E07AF25771955980DAD10020D04E5A713660A7') # Junio C Hamano
-source=("https://www.kernel.org/pub/software/scm/git/git-$pkgver.tar."{xz,sign}
-        '0001-git-p4-python.patch'
-        'git-daemon at .service'
-        'git-daemon.socket'
-        'git-sysusers.conf')
-sha256sums=('222796cc6e3bf2f9fd765f8f097daa3c3999bb7865ac88a8c974d98182e29f26'
-            'SKIP'
-            '0d19345aaeaeb374f8bfc30b823e8f53cb128c56b68c6504bbdd8766c03d1df9'
-            '14c0b67cfe116b430645c19d8c4759419657e6809dfa28f438c33a005245ad91'
-            'ac4c90d62c44926e6d30d18d97767efc901076d4e0283ed812a349aece72f203'
-            '7630e8245526ad80f703fac9900a1328588c503ce32b37b9f8811674fcda4a45')
-
-_make_paths=(
-  prefix='/usr'
-  gitexecdir='/usr/lib/git-core'
-  perllibdir="$(/usr/bin/perl -MConfig -wle 'print $Config{installvendorlib}')"
-)
-
-_make_options=(
-  CFLAGS="$CFLAGS"
-  LDFLAGS="$LDFLAGS"
-  INSTALL_SYMLINKS=1
-  MAN_BOLD_LITERAL=1
-  NO_PERL_CPAN_FALLBACKS=1
-  USE_LIBPCRE2=1
-)
-
-prepare() {
-  cd "$srcdir/$pkgname-$pkgver"
-
-  patch -Np1 < ../0001-git-p4-python.patch
-}
-
-build() {
-  cd "$srcdir/$pkgname-$pkgver"
-
-  make \
-    "${_make_paths[@]}" \
-    "${_make_options[@]}" \
-    all man
-
-  make -C contrib/credential/gnome-keyring
-  make -C contrib/credential/libsecret
-  make -C contrib/subtree "${_make_paths[@]}" all man
-  make -C contrib/mw-to-git "${_make_paths[@]}" all
-  make -C contrib/diff-highlight "${_make_paths[@]}"
-}
-
-check() {
-  cd "$srcdir/$pkgname-$pkgver"
-
-  local jobs
-  jobs=$(expr "$MAKEFLAGS" : '.*\(-j[0-9]*\).*') || true
-  mkdir -p /dev/shm/git-test
-  # explicitly specify SHELL to avoid a test failure in t/t9903-bash-prompt.sh
-  # which is caused by 'git rebase' trying to use builduser's SHELL inside the
-  # build chroot (i.e.: /usr/bin/nologin)
-  SHELL=/bin/sh \
-  make \
-    "${_make_paths[@]}" \
-    "${_make_options[@]}" \
-    NO_SVN_TESTS=y \
-    DEFAULT_TEST_TARGET=prove \
-    GIT_PROVE_OPTS="$jobs -Q" \
-    GIT_TEST_OPTS="--root=/dev/shm/git-test" \
-    test
-}
-
-package() {
-  cd "$srcdir/$pkgname-$pkgver"
-  
-  make \
-    "${_make_paths[@]}" \
-    "${_make_options[@]}" \
-    DESTDIR="$pkgdir" \
-    install install-man
-
-  # bash completion
-  mkdir -p "$pkgdir"/usr/share/bash-completion/completions/
-  install -m 0644 ./contrib/completion/git-completion.bash "$pkgdir"/usr/share/bash-completion/completions/git
-  # fancy git prompt
-  mkdir -p "$pkgdir"/usr/share/git/
-  install -m 0644 ./contrib/completion/git-prompt.sh "$pkgdir"/usr/share/git/git-prompt.sh
-  # gnome credentials helper (deprecated, but we will keep it as long there is no extra cost)
-  # https://gitlab.gnome.org/GNOME/libgnome-keyring/commit/6a5adea4aec93
-  install -m 0755 contrib/credential/gnome-keyring/git-credential-gnome-keyring \
-      "$pkgdir"/usr/lib/git-core/git-credential-gnome-keyring
-  make -C contrib/credential/gnome-keyring clean
-  # libsecret credentials helper
-  install -m 0755 contrib/credential/libsecret/git-credential-libsecret \
-      "$pkgdir"/usr/lib/git-core/git-credential-libsecret
-  make -C contrib/credential/libsecret clean
-  # subtree installation
-  make -C contrib/subtree "${_make_paths[@]}" DESTDIR="$pkgdir" install install-man
-  # mediawiki installation
-  make -C contrib/mw-to-git "${_make_paths[@]}" DESTDIR="$pkgdir" install
-  # the rest of the contrib stuff
-  find contrib/ -name '.gitignore' -delete
-  cp -a ./contrib/* "$pkgdir"/usr/share/git/
-
-  # git-daemon via systemd socket activation
-  install -D -m 0644 "$srcdir"/git-daemon at .service "$pkgdir"/usr/lib/systemd/system/git-daemon at .service
-  install -D -m 0644 "$srcdir"/git-daemon.socket "$pkgdir"/usr/lib/systemd/system/git-daemon.socket
-
-  # sysusers file
-  install -D -m 0644 "$srcdir"/git-sysusers.conf "$pkgdir"/usr/lib/sysusers.d/git.conf
-}

Copied: git/repos/extra-x86_64/PKGBUILD (from rev 377835, git/trunk/PKGBUILD)
===================================================================
--- PKGBUILD	                        (rev 0)
+++ PKGBUILD	2020-03-18 07:35:08 UTC (rev 377836)
@@ -0,0 +1,136 @@
+# Maintainer: Christian Hesse <mail at eworm.de>
+# Maintainer: Dan McGee <dan at archlinux.org>
+
+pkgname=git
+pkgver=2.25.2
+pkgrel=1
+pkgdesc='the fast distributed version control system'
+arch=('x86_64')
+url='https://git-scm.com/'
+license=('GPL2')
+depends=('curl' 'expat' 'perl' 'perl-error' 'perl-mailtools'
+         'openssl' 'pcre2' 'grep' 'shadow')
+makedepends=('python' 'libgnome-keyring' 'xmlto' 'asciidoc')
+optdepends=('tk: gitk and git gui'
+            'perl-libwww: git svn'
+            'perl-term-readkey: git svn and interactive.singlekey setting'
+            'perl-mime-tools: git send-email'
+            'perl-net-smtp-ssl: git send-email TLS support'
+            'perl-authen-sasl: git send-email TLS support'
+            'perl-mediawiki-api: git mediawiki support'
+            'perl-datetime-format-iso8601: git mediawiki support'
+            'perl-lwp-protocol-https: git mediawiki https support'
+            'perl-cgi: gitweb (web interface) support'
+            'python: git svn & git p4'
+            'subversion: git svn'
+            'org.freedesktop.secrets: keyring credential helper'
+            'libsecret: libsecret credential helper')
+install=git.install
+validpgpkeys=('96E07AF25771955980DAD10020D04E5A713660A7') # Junio C Hamano
+source=("https://www.kernel.org/pub/software/scm/git/git-$pkgver.tar."{xz,sign}
+        '0001-git-p4-python.patch'
+        'git-daemon at .service'
+        'git-daemon.socket'
+        'git-sysusers.conf')
+sha256sums=('9b937103e048e2d3bf964d4132a0e7edccc2583d4ef30bc8a516f93a76de7123'
+            'SKIP'
+            '0d19345aaeaeb374f8bfc30b823e8f53cb128c56b68c6504bbdd8766c03d1df9'
+            '14c0b67cfe116b430645c19d8c4759419657e6809dfa28f438c33a005245ad91'
+            'ac4c90d62c44926e6d30d18d97767efc901076d4e0283ed812a349aece72f203'
+            '7630e8245526ad80f703fac9900a1328588c503ce32b37b9f8811674fcda4a45')
+
+_make_paths=(
+  prefix='/usr'
+  gitexecdir='/usr/lib/git-core'
+  perllibdir="$(/usr/bin/perl -MConfig -wle 'print $Config{installvendorlib}')"
+)
+
+_make_options=(
+  CFLAGS="$CFLAGS"
+  LDFLAGS="$LDFLAGS"
+  INSTALL_SYMLINKS=1
+  MAN_BOLD_LITERAL=1
+  NO_PERL_CPAN_FALLBACKS=1
+  USE_LIBPCRE2=1
+)
+
+prepare() {
+  cd "$srcdir/$pkgname-$pkgver"
+
+  patch -Np1 < ../0001-git-p4-python.patch
+}
+
+build() {
+  cd "$srcdir/$pkgname-$pkgver"
+
+  make \
+    "${_make_paths[@]}" \
+    "${_make_options[@]}" \
+    all man
+
+  make -C contrib/credential/gnome-keyring
+  make -C contrib/credential/libsecret
+  make -C contrib/subtree "${_make_paths[@]}" all man
+  make -C contrib/mw-to-git "${_make_paths[@]}" all
+  make -C contrib/diff-highlight "${_make_paths[@]}"
+}
+
+check() {
+  cd "$srcdir/$pkgname-$pkgver"
+
+  local jobs
+  jobs=$(expr "$MAKEFLAGS" : '.*\(-j[0-9]*\).*') || true
+  mkdir -p /dev/shm/git-test
+  # explicitly specify SHELL to avoid a test failure in t/t9903-bash-prompt.sh
+  # which is caused by 'git rebase' trying to use builduser's SHELL inside the
+  # build chroot (i.e.: /usr/bin/nologin)
+  SHELL=/bin/sh \
+  make \
+    "${_make_paths[@]}" \
+    "${_make_options[@]}" \
+    NO_SVN_TESTS=y \
+    DEFAULT_TEST_TARGET=prove \
+    GIT_PROVE_OPTS="$jobs -Q" \
+    GIT_TEST_OPTS="--root=/dev/shm/git-test" \
+    test
+}
+
+package() {
+  cd "$srcdir/$pkgname-$pkgver"
+  
+  make \
+    "${_make_paths[@]}" \
+    "${_make_options[@]}" \
+    DESTDIR="$pkgdir" \
+    install install-man
+
+  # bash completion
+  mkdir -p "$pkgdir"/usr/share/bash-completion/completions/
+  install -m 0644 ./contrib/completion/git-completion.bash "$pkgdir"/usr/share/bash-completion/completions/git
+  # fancy git prompt
+  mkdir -p "$pkgdir"/usr/share/git/
+  install -m 0644 ./contrib/completion/git-prompt.sh "$pkgdir"/usr/share/git/git-prompt.sh
+  # gnome credentials helper (deprecated, but we will keep it as long there is no extra cost)
+  # https://gitlab.gnome.org/GNOME/libgnome-keyring/commit/6a5adea4aec93
+  install -m 0755 contrib/credential/gnome-keyring/git-credential-gnome-keyring \
+      "$pkgdir"/usr/lib/git-core/git-credential-gnome-keyring
+  make -C contrib/credential/gnome-keyring clean
+  # libsecret credentials helper
+  install -m 0755 contrib/credential/libsecret/git-credential-libsecret \
+      "$pkgdir"/usr/lib/git-core/git-credential-libsecret
+  make -C contrib/credential/libsecret clean
+  # subtree installation
+  make -C contrib/subtree "${_make_paths[@]}" DESTDIR="$pkgdir" install install-man
+  # mediawiki installation
+  make -C contrib/mw-to-git "${_make_paths[@]}" DESTDIR="$pkgdir" install
+  # the rest of the contrib stuff
+  find contrib/ -name '.gitignore' -delete
+  cp -a ./contrib/* "$pkgdir"/usr/share/git/
+
+  # git-daemon via systemd socket activation
+  install -D -m 0644 "$srcdir"/git-daemon at .service "$pkgdir"/usr/lib/systemd/system/git-daemon at .service
+  install -D -m 0644 "$srcdir"/git-daemon.socket "$pkgdir"/usr/lib/systemd/system/git-daemon.socket
+
+  # sysusers file
+  install -D -m 0644 "$srcdir"/git-sysusers.conf "$pkgdir"/usr/lib/sysusers.d/git.conf
+}

Deleted: git-daemon.socket
===================================================================
--- git-daemon.socket	2020-03-18 07:35:01 UTC (rev 377835)
+++ git-daemon.socket	2020-03-18 07:35:08 UTC (rev 377836)
@@ -1,9 +0,0 @@
-[Unit]
-Description=Git Daemon Socket
-
-[Socket]
-ListenStream=9418
-Accept=true
-
-[Install]
-WantedBy=sockets.target

Copied: git/repos/extra-x86_64/git-daemon.socket (from rev 377835, git/trunk/git-daemon.socket)
===================================================================
--- git-daemon.socket	                        (rev 0)
+++ git-daemon.socket	2020-03-18 07:35:08 UTC (rev 377836)
@@ -0,0 +1,9 @@
+[Unit]
+Description=Git Daemon Socket
+
+[Socket]
+ListenStream=9418
+Accept=true
+
+[Install]
+WantedBy=sockets.target

Deleted: git-daemon at .service
===================================================================
--- git-daemon at .service	2020-03-18 07:35:01 UTC (rev 377835)
+++ git-daemon at .service	2020-03-18 07:35:08 UTC (rev 377836)
@@ -1,14 +0,0 @@
-[Unit]
-Description=Git Daemon Instance
-
-[Service]
-User=git
-# The '-' is to ignore non-zero exit statuses
-ExecStart=-/usr/lib/git-core/git-daemon --inetd --export-all --base-path=/srv/git
-StandardInput=socket
-StandardOutput=inherit
-StandardError=journal
-ProtectSystem=full
-ProtectHome=on
-PrivateDevices=on
-NoNewPrivileges=on

Copied: git/repos/extra-x86_64/git-daemon at .service (from rev 377835, git/trunk/git-daemon at .service)
===================================================================
--- git-daemon at .service	                        (rev 0)
+++ git-daemon at .service	2020-03-18 07:35:08 UTC (rev 377836)
@@ -0,0 +1,14 @@
+[Unit]
+Description=Git Daemon Instance
+
+[Service]
+User=git
+# The '-' is to ignore non-zero exit statuses
+ExecStart=-/usr/lib/git-core/git-daemon --inetd --export-all --base-path=/srv/git
+StandardInput=socket
+StandardOutput=inherit
+StandardError=journal
+ProtectSystem=full
+ProtectHome=on
+PrivateDevices=on
+NoNewPrivileges=on

Deleted: git-sysusers.conf
===================================================================
--- git-sysusers.conf	2020-03-18 07:35:01 UTC (rev 377835)
+++ git-sysusers.conf	2020-03-18 07:35:08 UTC (rev 377836)
@@ -1 +0,0 @@
-u git - "git daemon user" / /usr/bin/git-shell

Copied: git/repos/extra-x86_64/git-sysusers.conf (from rev 377835, git/trunk/git-sysusers.conf)
===================================================================
--- git-sysusers.conf	                        (rev 0)
+++ git-sysusers.conf	2020-03-18 07:35:08 UTC (rev 377836)
@@ -0,0 +1 @@
+u git - "git daemon user" / /usr/bin/git-shell

Deleted: git.install
===================================================================
--- git.install	2020-03-18 07:35:01 UTC (rev 377835)
+++ git.install	2020-03-18 07:35:08 UTC (rev 377836)
@@ -1,14 +0,0 @@
-#!/bin/sh
-
-post_install() {
-  # make git-shell a valid shell
-  if ! grep -qe '^/usr/bin/git-shell$' etc/shells; then
-    echo '/usr/bin/git-shell' >> etc/shells
-  fi
-}
-
-# do not modify user settings (shell) in post-upgrade function!
-
-post_remove() {
-  sed -i -r '/^\/usr\/bin\/git-shell$/d' etc/shells
-}

Copied: git/repos/extra-x86_64/git.install (from rev 377835, git/trunk/git.install)
===================================================================
--- git.install	                        (rev 0)
+++ git.install	2020-03-18 07:35:08 UTC (rev 377836)
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+post_install() {
+  # make git-shell a valid shell
+  if ! grep -qe '^/usr/bin/git-shell$' etc/shells; then
+    echo '/usr/bin/git-shell' >> etc/shells
+  fi
+}
+
+# do not modify user settings (shell) in post-upgrade function!
+
+post_remove() {
+  sed -i -r '/^\/usr\/bin\/git-shell$/d' etc/shells
+}



More information about the arch-commits mailing list