diff options
Diffstat (limited to 'git-p4.py')
-rwxr-xr-x | git-p4.py | 421 |
1 files changed, 136 insertions, 285 deletions
@@ -56,6 +56,21 @@ defaultBlockSize = 1<<20 p4_access_checked = False +re_ko_keywords = re.compile(br'\$(Id|Header)(:[^$\n]+)?\$') +re_k_keywords = re.compile(br'\$(Id|Header|Author|Date|DateTime|Change|File|Revision)(:[^$\n]+)?\$') + +def format_size_human_readable(num): + """ Returns a number of units (typically bytes) formatted as a human-readable + string. + """ + if num < 1024: + return '{:d} B'.format(num) + for unit in ["Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]: + num /= 1024.0 + if num < 1024.0: + return "{:3.1f} {}B".format(num, unit) + return "{:.1f} YiB".format(num) + def p4_build_cmd(cmd): """Build a suitable p4 command line. @@ -93,10 +108,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 not isinstance(cmd, list): - real_cmd = ' '.join(real_cmd) + ' ' + cmd - else: - real_cmd += cmd + real_cmd += cmd # now check that we can actually talk to the server global p4_access_checked @@ -208,151 +220,93 @@ def decode_path(path): def run_git_hook(cmd, param=[]): """Execute a hook if the hook exists.""" + args = ['git', 'hook', 'run', '--ignore-missing', cmd] + if param: + args.append("--") + for p in param: + args.append(p) + return subprocess.call(args) == 0 + +def write_pipe(c, stdin, *k, **kw): if verbose: - sys.stderr.write("Looking for hook: %s\n" % cmd) - sys.stderr.flush() - - hooks_path = gitConfig("core.hooksPath") - if len(hooks_path) <= 0: - hooks_path = os.path.join(os.environ["GIT_DIR"], "hooks") - - if not isinstance(param, list): - param=[param] - - # resolve hook file name, OS depdenent - hook_file = os.path.join(hooks_path, cmd) - if platform.system() == 'Windows': - if not os.path.isfile(hook_file): - # look for the file with an extension - files = glob.glob(hook_file + ".*") - if not files: - return True - files.sort() - hook_file = files.pop() - while hook_file.upper().endswith(".SAMPLE"): - # The file is a sample hook. We don't want it - if len(files) > 0: - hook_file = files.pop() - else: - return True - - if not os.path.isfile(hook_file) or not os.access(hook_file, os.X_OK): - return True - - return run_hook_command(hook_file, param) == 0 - -def run_hook_command(cmd, param): - """Executes a git hook command - cmd = the command line file to be executed. This can be - a file that is run by OS association. - - param = a list of parameters to pass to the cmd command - - On windows, the extension is checked to see if it should - be run with the Git for Windows Bash shell. If there - is no file extension, the file is deemed a bash shell - and will be handed off to sh.exe. Otherwise, Windows - will be called with the shell to handle the file assocation. - - For non Windows operating systems, the file is called - as an executable. - """ - cli = [cmd] + param - use_shell = False - if platform.system() == 'Windows': - (root,ext) = os.path.splitext(cmd) - if ext == "": - exe_path = os.environ.get("EXEPATH") - if exe_path is None: - exe_path = "" - else: - exe_path = os.path.join(exe_path, "bin") - cli = [os.path.join(exe_path, "SH.EXE")] + cli - else: - use_shell = True - return subprocess.call(cli, shell=use_shell) - - -def write_pipe(c, stdin): - if verbose: - sys.stderr.write('Writing pipe: %s\n' % str(c)) + sys.stderr.write('Writing pipe: {}\n'.format(' '.join(c))) - expand = not isinstance(c, list) - p = subprocess.Popen(c, stdin=subprocess.PIPE, shell=expand) + p = subprocess.Popen(c, stdin=subprocess.PIPE, *k, **kw) pipe = p.stdin val = pipe.write(stdin) pipe.close() if p.wait(): - die('Command failed: %s' % str(c)) + die('Command failed: {}'.format(' '.join(c))) return val -def p4_write_pipe(c, stdin): +def p4_write_pipe(c, stdin, *k, **kw): 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) + return write_pipe(real_cmd, stdin, *k, **kw) -def read_pipe_full(c): +def read_pipe_full(c, *k, **kw): """ Read output from command. Returns a tuple of the return status, stdout text and stderr text. """ if verbose: - sys.stderr.write('Reading pipe: %s\n' % str(c)) + sys.stderr.write('Reading pipe: {}\n'.format(' '.join(c))) - expand = not isinstance(c, list) - p = subprocess.Popen(c, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=expand) + p = subprocess.Popen( + c, stdout=subprocess.PIPE, stderr=subprocess.PIPE, *k, **kw) (out, err) = p.communicate() return (p.returncode, out, decode_text_stream(err)) -def read_pipe(c, ignore_error=False, raw=False): +def read_pipe(c, ignore_error=False, raw=False, *k, **kw): """ 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) + (retcode, out, err) = read_pipe_full(c, *k, **kw) if retcode != 0: if ignore_error: out = "" else: - die('Command failed: %s\nError: %s' % (str(c), err)) + die('Command failed: {}\nError: {}'.format(' '.join(c), err)) if not raw: out = decode_text_stream(out) return out -def read_pipe_text(c): +def read_pipe_text(c, *k, **kw): """ Read output from a command with trailing whitespace stripped. On error, returns None. """ - (retcode, out, err) = read_pipe_full(c) + (retcode, out, err) = read_pipe_full(c, *k, **kw) if retcode != 0: return None else: return decode_text_stream(out).rstrip() -def p4_read_pipe(c, ignore_error=False, raw=False): +def p4_read_pipe(c, ignore_error=False, raw=False, *k, **kw): real_cmd = p4_build_cmd(c) - return read_pipe(real_cmd, ignore_error, raw=raw) + return read_pipe(real_cmd, ignore_error, raw=raw, *k, **kw) -def read_pipe_lines(c): +def read_pipe_lines(c, raw=False, *k, **kw): if verbose: - sys.stderr.write('Reading pipe: %s\n' % str(c)) + sys.stderr.write('Reading pipe: {}\n'.format(' '.join(c))) - expand = not isinstance(c, list) - p = subprocess.Popen(c, stdout=subprocess.PIPE, shell=expand) + p = subprocess.Popen(c, stdout=subprocess.PIPE, *k, **kw) pipe = p.stdout - val = [decode_text_stream(line) for line in pipe.readlines()] + lines = pipe.readlines() + if not raw: + lines = [decode_text_stream(line) for line in lines] if pipe.close() or p.wait(): - die('Command failed: %s' % str(c)) - return val + die('Command failed: {}'.format(' '.join(c))) + return lines -def p4_read_pipe_lines(c): +def p4_read_pipe_lines(c, *k, **kw): """Specifically invoke p4 on the command supplied. """ real_cmd = p4_build_cmd(c) - return read_pipe_lines(real_cmd) + return read_pipe_lines(real_cmd, *k, **kw) def p4_has_command(cmd): """Ask p4 for help on this command. If it returns an error, the @@ -383,23 +337,22 @@ def p4_has_move_command(): # assume it failed because @... was invalid changelist return True -def system(cmd, ignore_error=False): - expand = not isinstance(cmd, list) +def system(cmd, ignore_error=False, *k, **kw): if verbose: - sys.stderr.write("executing %s\n" % str(cmd)) - retcode = subprocess.call(cmd, shell=expand) + sys.stderr.write("executing {}\n".format( + ' '.join(cmd) if isinstance(cmd, list) else cmd)) + retcode = subprocess.call(cmd, *k, **kw) if retcode and not ignore_error: - raise CalledProcessError(retcode, cmd) + raise subprocess.CalledProcessError(retcode, cmd) return retcode -def p4_system(cmd): +def p4_system(cmd, *k, **kw): """Specifically invoke p4 as the system command. """ real_cmd = p4_build_cmd(cmd) - expand = not isinstance(real_cmd, list) - retcode = subprocess.call(real_cmd, shell=expand) + retcode = subprocess.call(real_cmd, *k, **kw) if retcode: - raise CalledProcessError(retcode, real_cmd) + raise subprocess.CalledProcessError(retcode, real_cmd) def die_bad_access(s): die("failure accessing depot: {0}".format(s.rstrip())) @@ -577,20 +530,12 @@ def p4_type(f): # def p4_keywords_regexp_for_type(base, type_mods): if base in ("text", "unicode", "binary"): - kwords = None if "ko" in type_mods: - kwords = 'Id|Header' + return re_ko_keywords elif "k" in type_mods: - kwords = 'Id|Header|Author|Date|DateTime|Change|File|Revision' + return re_k_keywords else: return None - pattern = r""" - \$ # Starts with a dollar, followed by... - (%s) # one of the keywords, followed by... - (:[^$\n]+)? # possibly an old expansion, followed by... - \$ # another dollar - """ % kwords - return pattern else: return None @@ -726,18 +671,11 @@ def isModeExecChanged(src_mode, dst_mode): return isModeExec(src_mode) != isModeExec(dst_mode) def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None, skip_info=False, - errors_as_exceptions=False): - - if not isinstance(cmd, list): - cmd = "-G " + cmd - expand = True - else: - cmd = ["-G"] + cmd - expand = False + errors_as_exceptions=False, *k, **kw): - cmd = p4_build_cmd(cmd) + cmd = p4_build_cmd(["-G"] + cmd) if verbose: - sys.stderr.write("Opening pipe: %s\n" % str(cmd)) + sys.stderr.write("Opening pipe: {}\n".format(' '.join(cmd))) # Use a temporary file to avoid deadlocks without # subprocess.communicate(), which would put another copy @@ -754,10 +692,8 @@ def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None, skip_info=False, stdin_file.flush() stdin_file.seek(0) - p4 = subprocess.Popen(cmd, - shell=expand, - stdin=stdin_file, - stdout=subprocess.PIPE) + p4 = subprocess.Popen( + cmd, stdin=stdin_file, stdout=subprocess.PIPE, *k, **kw) result = [] try: @@ -810,8 +746,8 @@ def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None, skip_info=False, return result -def p4Cmd(cmd): - list = p4CmdList(cmd) +def p4Cmd(cmd, *k, **kw): + list = p4CmdList(cmd, *k, **kw) result = {} for entry in list: result.update(entry) @@ -860,7 +796,7 @@ def isValidGitDir(path): return git_dir(path) != None def parseRevision(ref): - return read_pipe("git rev-parse %s" % ref).strip() + return read_pipe(["git", "rev-parse", ref]).strip() def branchExists(ref): rev = read_pipe(["git", "rev-parse", "-q", "--verify", ref], @@ -966,11 +902,11 @@ def p4BranchesInGit(branchesAreInRemotes=True): branches = {} - cmdline = "git rev-parse --symbolic " + cmdline = ["git", "rev-parse", "--symbolic"] if branchesAreInRemotes: - cmdline += "--remotes" + cmdline.append("--remotes") else: - cmdline += "--branches" + cmdline.append("--branches") for line in read_pipe_lines(cmdline): line = line.strip() @@ -1035,7 +971,7 @@ def createOrUpdateBranchesFromOrigin(localRefPrefix = "refs/remotes/p4/", silent originPrefix = "origin/p4/" - for line in read_pipe_lines("git rev-parse --symbolic --remotes"): + for line in read_pipe_lines(["git", "rev-parse", "--symbolic", "--remotes"]): line = line.strip() if (not line.startswith(originPrefix)) or line.endswith("HEAD"): continue @@ -1073,7 +1009,7 @@ def createOrUpdateBranchesFromOrigin(localRefPrefix = "refs/remotes/p4/", silent remoteHead, ','.join(settings['depot-paths']))) if update: - system("git update-ref %s %s" % (remoteHead, originHead)) + system(["git", "update-ref", remoteHead, originHead]) def originP4BranchesExist(): return gitBranchExists("origin") or gitBranchExists("origin/p4") or gitBranchExists("origin/p4/master") @@ -1187,7 +1123,7 @@ def getClientSpec(): """Look at the p4 client spec, create a View() object that contains all the mappings, and return it.""" - specList = p4CmdList("client -o") + specList = p4CmdList(["client", "-o"]) if len(specList) != 1: die('Output from "client -o" is %d lines, expecting 1' % len(specList)) @@ -1216,7 +1152,7 @@ def getClientSpec(): def getClientRoot(): """Grab the client directory.""" - output = p4CmdList("client -o") + output = p4CmdList(["client", "-o"]) if len(output) != 1: die('Output from "client -o" is %d lines, expecting 1' % len(output)) @@ -1471,7 +1407,7 @@ class P4UserMap: if self.myP4UserId: return self.myP4UserId - results = p4CmdList("user -o") + results = p4CmdList(["user", "-o"]) for r in results: if 'User' in r: self.myP4UserId = r['User'] @@ -1496,7 +1432,7 @@ class P4UserMap: self.users = {} self.emails = {} - for output in p4CmdList("users"): + for output in p4CmdList(["users"]): if "User" not in output: continue self.users[output["User"]] = output["FullName"] + " <" + output["Email"] + ">" @@ -1532,80 +1468,6 @@ class P4UserMap: except IOError: self.getUserMapFromPerforceServer() -class P4Debug(Command): - def __init__(self): - Command.__init__(self) - self.options = [] - self.description = "A tool to debug the output of p4 -G." - self.needsGit = False - - def run(self, args): - j = 0 - for output in p4CmdList(args): - print('Element: %d' % j) - j += 1 - print(output) - return True - -class P4RollBack(Command): - def __init__(self): - Command.__init__(self) - self.options = [ - optparse.make_option("--local", dest="rollbackLocalBranches", action="store_true") - ] - self.description = "A tool to debug the multi-branch import. Don't use :)" - self.rollbackLocalBranches = False - - def run(self, args): - if len(args) != 1: - return False - maxChange = int(args[0]) - - if "p4ExitCode" in p4Cmd("changes -m 1"): - die("Problems executing p4"); - - if self.rollbackLocalBranches: - refPrefix = "refs/heads/" - lines = read_pipe_lines("git rev-parse --symbolic --branches") - else: - refPrefix = "refs/remotes/" - lines = read_pipe_lines("git rev-parse --symbolic --remotes") - - for line in lines: - if self.rollbackLocalBranches or (line.startswith("p4/") and line != "p4/HEAD\n"): - line = line.strip() - ref = refPrefix + line - log = extractLogMessageFromGitCommit(ref) - settings = extractSettingsGitLog(log) - - depotPaths = settings['depot-paths'] - change = settings['change'] - - changed = False - - if len(p4Cmd("changes -m 1 " + ' '.join (['%s...@%s' % (p, maxChange) - for p in depotPaths]))) == 0: - print("Branch %s did not exist at change %s, deleting." % (ref, maxChange)) - system("git update-ref -d %s `git rev-parse %s`" % (ref, ref)) - continue - - while change and int(change) > maxChange: - changed = True - if self.verbose: - print("%s is at %s ; rewinding towards %s" % (ref, change, maxChange)) - system("git update-ref %s \"%s^\"" % (ref, ref)) - log = extractLogMessageFromGitCommit(ref) - settings = extractSettingsGitLog(log) - - - depotPaths = settings['depot-paths'] - change = settings['change'] - - if changed: - print("%s rewound to %s" % (ref, change)) - - return True - class P4Submit(Command, P4UserMap): conflict_behavior_choices = ("ask", "skip", "quit") @@ -1694,7 +1556,7 @@ class P4Submit(Command, P4UserMap): die("Large file system not supported for git-p4 submit command. Please remove it from config.") def check(self): - if len(p4CmdList("opened ...")) > 0: + if len(p4CmdList(["opened", "..."])) > 0: die("You have files opened with perforce! Close them before starting the sync.") def separate_jobs_from_description(self, message): @@ -1753,18 +1615,13 @@ class P4Submit(Command, P4UserMap): return result - def patchRCSKeywords(self, file, pattern): - # Attempt to zap the RCS keywords in a p4 controlled file matching the given pattern + def patchRCSKeywords(self, file, regexp): + # Attempt to zap the RCS keywords in a p4 controlled file matching the given regex (handle, outFileName) = tempfile.mkstemp(dir='.') try: - outFile = os.fdopen(handle, "w+") - inFile = open(file, "r") - regexp = re.compile(pattern, re.VERBOSE) - for line in inFile.readlines(): - line = regexp.sub(r'$\1$', line) - outFile.write(line) - inFile.close() - outFile.close() + with os.fdopen(handle, "wb") as outFile, open(file, "rb") as inFile: + for line in inFile.readlines(): + outFile.write(regexp.sub(br'$\1$', line)) # Forcibly overwrite the original file os.unlink(file) shutil.move(outFileName, file) @@ -1803,7 +1660,7 @@ class P4Submit(Command, P4UserMap): # then gets used to patch up the username in the change. If the same # client spec is being used by multiple processes then this might go # wrong. - results = p4CmdList("client -o") # find the current client + results = p4CmdList(["client", "-o"]) # find the current client client = None for r in results: if 'Client' in r: @@ -1819,7 +1676,7 @@ class P4Submit(Command, P4UserMap): def modifyChangelistUser(self, changelist, newUser): # fixup the user field of a changelist after it has been submitted. - changes = p4CmdList("change -o %s" % changelist) + changes = p4CmdList(["change", "-o", changelist]) if len(changes) != 1: die("Bad output from p4 change modifying %s to user %s" % (changelist, newUser)) @@ -1830,7 +1687,7 @@ class P4Submit(Command, P4UserMap): # p4 does not understand format version 3 and above input = marshal.dumps(c, 2) - result = p4CmdList("change -f -i", stdin=input) + result = p4CmdList(["change", "-f", "-i"], stdin=input) for r in result: if 'code' in r: if r['code'] == 'error': @@ -1936,7 +1793,7 @@ class P4Submit(Command, P4UserMap): if "P4EDITOR" in os.environ and (os.environ.get("P4EDITOR") != ""): editor = os.environ.get("P4EDITOR") else: - editor = read_pipe("git var GIT_EDITOR").strip() + editor = read_pipe(["git", "var", "GIT_EDITOR"]).strip() system(["sh", "-c", ('%s "$@"' % editor), editor, template_file]) # If the file was not saved, prompt to see if this patch should @@ -1994,7 +1851,8 @@ class P4Submit(Command, P4UserMap): (p4User, gitEmail) = self.p4UserForCommit(id) - diff = read_pipe_lines("git diff-tree -r %s \"%s^\" \"%s\"" % (self.diffOpts, id, id)) + diff = read_pipe_lines( + ["git", "diff-tree", "-r"] + self.diffOpts + ["{}^".format(id), id]) filesToAdd = set() filesToChangeType = set() filesToDelete = set() @@ -2091,25 +1949,24 @@ class P4Submit(Command, P4UserMap): # the patch to see if that's possible. if gitConfigBool("git-p4.attemptRCSCleanup"): file = None - pattern = None kwfiles = {} for file in editedFiles | filesToDelete: # did this file's delta contain RCS keywords? - pattern = p4_keywords_regexp_for_file(file) - - if pattern: + regexp = p4_keywords_regexp_for_file(file) + if regexp: # this file is a possibility...look for RCS keywords. - regexp = re.compile(pattern, re.VERBOSE) - for line in read_pipe_lines(["git", "diff", "%s^..%s" % (id, id), file]): + for line in read_pipe_lines( + ["git", "diff", "%s^..%s" % (id, id), file], + raw=True): if regexp.search(line): if verbose: - print("got keyword match on %s in %s in %s" % (pattern, line, file)) - kwfiles[file] = pattern + print("got keyword match on %s in %s in %s" % (regex.pattern, line, file)) + kwfiles[file] = regexp break - for file in kwfiles: + for file, regexp in kwfiles.items(): if verbose: - print("zapping %s with %s" % (line,pattern)) + print("zapping %s with %s" % (line, regexp.pattern)) # File is being deleted, so not open in p4. Must # disable the read-only bit on windows. if self.isWindows and file not in editedFiles: @@ -2131,7 +1988,7 @@ class P4Submit(Command, P4UserMap): # # Apply the patch for real, and do add/delete/+x handling. # - system(applyPatchCmd) + system(applyPatchCmd, shell=True) for f in filesToChangeType: p4_edit(f, "-t", "auto") @@ -2481,17 +2338,17 @@ class P4Submit(Command, P4UserMap): # if self.detectRenames: # command-line -M arg - self.diffOpts = "-M" + self.diffOpts = ["-M"] else: # If not explicitly set check the config variable detectRenames = gitConfig("git-p4.detectRenames") if detectRenames.lower() == "false" or detectRenames == "": - self.diffOpts = "" + self.diffOpts = [] elif detectRenames.lower() == "true": - self.diffOpts = "-M" + self.diffOpts = ["-M"] else: - self.diffOpts = "-M%s" % detectRenames + self.diffOpts = ["-M{}".format(detectRenames)] # no command-line arg for -C or --find-copies-harder, just # config variables @@ -2499,12 +2356,12 @@ class P4Submit(Command, P4UserMap): if detectCopies.lower() == "false" or detectCopies == "": pass elif detectCopies.lower() == "true": - self.diffOpts += " -C" + self.diffOpts.append("-C") else: - self.diffOpts += " -C%s" % detectCopies + self.diffOpts.append("-C{}".format(detectCopies)) if gitConfigBool("git-p4.detectCopiesHarder"): - self.diffOpts += " --find-copies-harder" + self.diffOpts.append("--find-copies-harder") num_shelves = len(self.update_shelve) if num_shelves > 0 and num_shelves != len(commits): @@ -2966,7 +2823,8 @@ class P4Sync(Command, P4UserMap): 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_path, relPath, size/1024/1024)) + sys.stdout.write('\r%s --> %s (%s)\n' % ( + file_path, relPath, format_size_human_readable(size))) sys.stdout.flush() (type_base, type_mods) = split_p4_type(file["type"]) @@ -3029,12 +2887,9 @@ class P4Sync(Command, P4UserMap): # Note that we do not try to de-mangle keywords on utf16 files, # even though in theory somebody may want that. - pattern = p4_keywords_regexp_for_type(type_base, type_mods) - if pattern: - regexp = re.compile(pattern, re.VERBOSE) - text = ''.join(decode_text_stream(c) for c in contents) - text = regexp.sub(r'$\1$', text) - contents = [ encode_text_stream(text) ] + regexp = p4_keywords_regexp_for_type(type_base, type_mods) + if regexp: + contents = [regexp.sub(br'$\1$', c) for c in contents] if self.largeFileSystem: (git_mode, contents) = self.largeFileSystem.processContent(git_mode, relPath, contents) @@ -3064,9 +2919,8 @@ class P4Sync(Command, P4UserMap): if not err and 'fileSize' in self.stream_file: required_bytes = int((4 * int(self.stream_file["fileSize"])) - calcDiskFree()) if required_bytes > 0: - err = 'Not enough space left on %s! Free at least %i MB.' % ( - os.getcwd(), required_bytes/1024/1024 - ) + err = 'Not enough space left on %s! Free at least %s.' % ( + os.getcwd(), format_size_human_readable(required_bytes)) if err: f = None @@ -3110,7 +2964,9 @@ class P4Sync(Command, P4UserMap): size = int(self.stream_file["fileSize"]) if size > 0: progress = 100*self.stream_file['streamContentSize']/size - sys.stdout.write('\r%s %d%% (%i MB)' % (self.stream_file['depotFile'], progress, int(size/1024/1024))) + sys.stdout.write('\r%s %d%% (%s)' % ( + self.stream_file['depotFile'], progress, + format_size_human_readable(size))) sys.stdout.flush() self.stream_have_file_info = True @@ -3453,12 +3309,9 @@ class P4Sync(Command, P4UserMap): lostAndFoundBranches = set() user = gitConfig("git-p4.branchUser") - if len(user) > 0: - command = "branches -u %s" % user - else: - command = "branches" - for info in p4CmdList(command): + for info in p4CmdList( + ["branches"] + (["-u", user] if len(user) > 0 else [])): details = p4Cmd(["branch", "-o", info["branch"]]) viewIdx = 0 while "View%s" % viewIdx in details: @@ -3549,7 +3402,8 @@ class P4Sync(Command, P4UserMap): while True: if self.verbose: print("trying: earliest %s latest %s" % (earliestCommit, latestCommit)) - next = read_pipe("git rev-list --bisect %s %s" % (latestCommit, earliestCommit)).strip() + next = read_pipe(["git", "rev-list", "--bisect", + latestCommit, earliestCommit]).strip() if len(next) == 0: if self.verbose: print("argh") @@ -3623,7 +3477,8 @@ class P4Sync(Command, P4UserMap): self.updateOptionDict(description) if not self.silent: - sys.stdout.write("\rImporting revision %s (%s%%)" % (change, cnt * 100 / len(changes))) + sys.stdout.write("\rImporting revision %s (%d%%)" % ( + change, (cnt * 100) // len(changes))) sys.stdout.flush() cnt = cnt + 1 @@ -3704,7 +3559,7 @@ class P4Sync(Command, P4UserMap): if self.hasOrigin: if not self.silent: print('Syncing with origin first, using "git fetch origin"') - system("git fetch origin") + system(["git", "fetch", "origin"]) def importHeadRevision(self, revision): print("Doing initial import of %s from revision %s into %s" % (' '.join(self.depotPaths), revision, self.branch)) @@ -3871,8 +3726,8 @@ class P4Sync(Command, P4UserMap): if len(self.branch) == 0: self.branch = self.refPrefix + "master" if gitBranchExists("refs/heads/p4") and self.importIntoRemotes: - system("git update-ref %s refs/heads/p4" % self.branch) - system("git branch -D p4") + system(["git", "update-ref", self.branch, "refs/heads/p4"]) + system(["git", "branch", "-D", "p4"]) # accept either the command-line option, or the configuration variable if self.useClientSpec: @@ -4075,7 +3930,7 @@ class P4Sync(Command, P4UserMap): # Cleanup temporary branches created during import if self.tempBranches != []: for branch in self.tempBranches: - read_pipe("git update-ref -d %s" % branch) + read_pipe(["git", "update-ref", "-d", branch]) os.rmdir(os.path.join(os.environ.get("GIT_DIR", ".git"), self.tempBranchLocation)) # Create a symbolic ref p4/HEAD pointing to p4/<branch> to allow @@ -4107,7 +3962,7 @@ class P4Rebase(Command): def rebase(self): if os.system("git update-index --refresh") != 0: die("Some files in your working directory are modified and different than what is in your index. You can use git update-index <filename> to bring the index up to date or stash away all your changes with git stash."); - if len(read_pipe("git diff-index HEAD --")) > 0: + if len(read_pipe(["git", "diff-index", "HEAD", "--"])) > 0: die("You have uncommitted changes. Please commit them before rebasing or stash them away with git stash."); [upstream, settings] = findUpstreamBranchPoint() @@ -4118,9 +3973,10 @@ class P4Rebase(Command): upstream = re.sub("~[0-9]+$", "", upstream) print("Rebasing the current branch onto %s" % upstream) - oldHead = read_pipe("git rev-parse HEAD").strip() - system("git rebase %s" % upstream) - system("git diff-tree --stat --summary -M %s HEAD --" % oldHead) + oldHead = read_pipe(["git", "rev-parse", "HEAD"]).strip() + system(["git", "rebase", upstream]) + system(["git", "diff-tree", "--stat", "--summary", "-M", oldHead, + "HEAD", "--"]) return True class P4Clone(P4Sync): @@ -4181,7 +4037,7 @@ class P4Clone(P4Sync): init_cmd.append("--bare") retcode = subprocess.call(init_cmd) if retcode: - raise CalledProcessError(retcode, init_cmd) + raise subprocess.CalledProcessError(retcode, init_cmd) if not P4Sync.run(self, depotPaths): return False @@ -4197,7 +4053,7 @@ class P4Clone(P4Sync): # auto-set this variable if invoked with --use-client-spec if self.useClientSpec_from_options: - system("git config --bool git-p4.useclientspec true") + system(["git", "config", "--bool", "git-p4.useclientspec", "true"]) return True @@ -4328,10 +4184,7 @@ class P4Branches(Command): if originP4BranchesExist(): createOrUpdateBranchesFromOrigin() - cmdline = "git rev-parse --symbolic " - cmdline += " --remotes" - - for line in read_pipe_lines(cmdline): + for line in read_pipe_lines(["git", "rev-parse", "--symbolic", "--remotes"]): line = line.strip() if not line.startswith('p4/') or line == "p4/HEAD": @@ -4363,13 +4216,11 @@ def printUsage(commands): print("") commands = { - "debug" : P4Debug, "submit" : P4Submit, "commit" : P4Submit, "sync" : P4Sync, "rebase" : P4Rebase, "clone" : P4Clone, - "rollback" : P4RollBack, "branches" : P4Branches, "unshelve" : P4Unshelve, } @@ -4416,9 +4267,9 @@ def main(): cmd.gitdir = os.path.abspath(".git") if not isValidGitDir(cmd.gitdir): # "rev-parse --git-dir" without arguments will try $PWD/.git - cmd.gitdir = read_pipe("git rev-parse --git-dir").strip() + cmd.gitdir = read_pipe(["git", "rev-parse", "--git-dir"]).strip() if os.path.exists(cmd.gitdir): - cdup = read_pipe("git rev-parse --show-cdup").strip() + cdup = read_pipe(["git", "rev-parse", "--show-cdup"]).strip() if len(cdup) > 0: chdir(cdup); |