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@.service (from rev 377835, git/trunk/git-daemon@.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@.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@.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 <m...@eworm.de> -# Maintainer: Dan McGee <d...@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@.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@.service "$pkgdir"/usr/lib/systemd/system/git-daemon@.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 <m...@eworm.de> +# Maintainer: Dan McGee <d...@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@.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@.service "$pkgdir"/usr/lib/systemd/system/git-daemon@.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@.service =================================================================== --- git-daemon@.service 2020-03-18 07:35:01 UTC (rev 377835) +++ git-daemon@.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@.service (from rev 377835, git/trunk/git-daemon@.service) =================================================================== --- git-daemon@.service (rev 0) +++ git-daemon@.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 +}