diff options
Diffstat (limited to 'git-p4.py')
-rwxr-xr-x | git-p4.py | 278 |
1 files changed, 166 insertions, 112 deletions
diff --git a/git-p4.py b/git-p4.py index 3991e7d1a7fc..9a71a6690db3 100755 --- a/git-p4.py +++ b/git-p4.py @@ -7,6 +7,14 @@ # 2007 Trolltech ASA # License: MIT <http://www.opensource.org/licenses/mit-license.php> # +# pylint: disable=invalid-name,missing-docstring,too-many-arguments,broad-except +# pylint: disable=no-self-use,wrong-import-position,consider-iterating-dictionary +# pylint: disable=wrong-import-order,unused-import,too-few-public-methods +# pylint: disable=too-many-lines,ungrouped-imports,fixme,too-many-locals +# pylint: disable=line-too-long,bad-whitespace,superfluous-parens +# pylint: disable=too-many-statements,too-many-instance-attributes +# pylint: disable=too-many-branches,too-many-nested-blocks +# import sys if sys.hexversion < 0x02040000: # The limiter is the subprocess module @@ -161,12 +169,30 @@ def calcDiskFree(): return st.f_bavail * st.f_frsize def die(msg): + """ Terminate execution. Make sure that any running child processes have been wait()ed for before + calling this. + """ if verbose: raise Exception(msg) else: sys.stderr.write(msg + "\n") sys.exit(1) +def prompt(prompt_text): + """ Prompt the user to choose one of the choices + + Choices are identified in the prompt_text by square brackets around + a single letter option. + """ + choices = set(m.group(1) for m in re.finditer(r"\[(.)\]", prompt_text)) + while True: + response = raw_input(prompt_text).strip().lower() + if not response: + continue + response = response[0] + if response in choices: + return response + def write_pipe(c, stdin): if verbose: sys.stderr.write('Writing pipe: %s\n' % str(c)) @@ -603,6 +629,14 @@ class P4RequestSizeException(P4ServerException): super(P4RequestSizeException, self).__init__(exit_code, p4_result) self.limit = limit +class P4CommandException(P4Exception): + """ Something went wrong calling p4 which means we have to give up """ + def __init__(self, msg): + self.msg = msg + + def __str__(self): + return self.msg + def isModeExecChanged(src_mode, dst_mode): return isModeExec(src_mode) != isModeExec(dst_mode) @@ -1160,13 +1194,11 @@ class LargeFileSystem(object): if contentsSize <= gitConfigInt('git-p4.largeFileCompressedThreshold'): return False contentTempFile = self.generateTempFile(contents) - compressedContentFile = tempfile.NamedTemporaryFile(prefix='git-p4-large-file', delete=False) - zf = zipfile.ZipFile(compressedContentFile.name, mode='w') - zf.write(contentTempFile, compress_type=zipfile.ZIP_DEFLATED) - zf.close() - compressedContentsSize = zf.infolist()[0].compress_size + compressedContentFile = tempfile.NamedTemporaryFile(prefix='git-p4-large-file', delete=True) + with zipfile.ZipFile(compressedContentFile, mode='w') as zf: + zf.write(contentTempFile, compress_type=zipfile.ZIP_DEFLATED) + compressedContentsSize = zf.infolist()[0].compress_size os.remove(contentTempFile) - os.remove(compressedContentFile.name) if compressedContentsSize > gitConfigInt('git-p4.largeFileCompressedThreshold'): return True return False @@ -1259,9 +1291,15 @@ class GitLFS(LargeFileSystem): pointerFile = re.sub(r'Git LFS pointer for.*\n\n', '', pointerFile) oid = re.search(r'^oid \w+:(\w+)', pointerFile, re.MULTILINE).group(1) + # if someone use external lfs.storage ( not in local repo git ) + lfs_path = gitConfig('lfs.storage') + if not lfs_path: + lfs_path = 'lfs' + if not os.path.isabs(lfs_path): + lfs_path = os.path.join(os.getcwd(), '.git', lfs_path) localLargeFile = os.path.join( - os.getcwd(), - '.git', 'lfs', 'objects', oid[:2], oid[2:4], + lfs_path, + 'objects', oid[:2], oid[2:4], oid, ) # LFS Spec states that pointer files should not have the executable bit set. @@ -1780,12 +1818,11 @@ class P4Submit(Command, P4UserMap): if os.stat(template_file).st_mtime > mtime: return True - while True: - response = raw_input("Submit template unchanged. Submit anyway? [y]es, [n]o (skip this patch) ") - if response == 'y': - return True - if response == 'n': - return False + response = prompt("Submit template unchanged. Submit anyway? [y]es, [n]o (skip this patch) ") + if response == 'y': + return True + if response == 'n': + return False def get_diff_description(self, editedFiles, filesToAdd, symlinks): # diff @@ -2347,31 +2384,22 @@ class P4Submit(Command, P4UserMap): " --prepare-p4-only") break if i < last: - quit = False - while True: - # prompt for what to do, or use the option/variable - if self.conflict_behavior == "ask": - print("What do you want to do?") - response = raw_input("[s]kip this commit but apply" - " the rest, or [q]uit? ") - if not response: - continue - elif self.conflict_behavior == "skip": - response = "s" - elif self.conflict_behavior == "quit": - response = "q" - else: - die("Unknown conflict_behavior '%s'" % - self.conflict_behavior) - - if response[0] == "s": - print("Skipping this commit, but applying the rest") - break - if response[0] == "q": - print("Quitting") - quit = True - break - if quit: + # prompt for what to do, or use the option/variable + if self.conflict_behavior == "ask": + print("What do you want to do?") + response = prompt("[s]kip this commit but apply the rest, or [q]uit? ") + elif self.conflict_behavior == "skip": + response = "s" + elif self.conflict_behavior == "quit": + response = "q" + else: + die("Unknown conflict_behavior '%s'" % + self.conflict_behavior) + + if response == "s": + print("Skipping this commit, but applying the rest") + if response == "q": + print("Quitting") break chdir(self.oldWorkingDirectory) @@ -3525,10 +3553,79 @@ class P4Sync(Command, P4UserMap): self.updateOptionDict(details) try: self.commit(details, self.extractFilesFromCommit(details), self.branch) - except IOError: + except IOError as err: print("IO error with git fast-import. Is your git version recent enough?") + print("IO error details: {}".format(err)) print(self.gitError.read()) + + def importRevisions(self, args, branch_arg_given): + changes = [] + + if len(self.changesFile) > 0: + with open(self.changesFile) as f: + output = f.readlines() + changeSet = set() + for line in output: + changeSet.add(int(line)) + + for change in changeSet: + changes.append(change) + + changes.sort() + else: + # catch "git p4 sync" with no new branches, in a repo that + # does not have any existing p4 branches + if len(args) == 0: + if not self.p4BranchesInGit: + raise P4CommandException("No remote p4 branches. Perhaps you never did \"git p4 clone\" in here.") + + # The default branch is master, unless --branch is used to + # specify something else. Make sure it exists, or complain + # nicely about how to use --branch. + if not self.detectBranches: + if not branch_exists(self.branch): + if branch_arg_given: + raise P4CommandException("Error: branch %s does not exist." % self.branch) + else: + raise P4CommandException("Error: no branch %s; perhaps specify one with --branch." % + self.branch) + + if self.verbose: + print("Getting p4 changes for %s...%s" % (', '.join(self.depotPaths), + self.changeRange)) + changes = p4ChangesForPaths(self.depotPaths, self.changeRange, self.changes_block_size) + + if len(self.maxChanges) > 0: + changes = changes[:min(int(self.maxChanges), len(changes))] + + if len(changes) == 0: + if not self.silent: + print("No changes to import!") + else: + if not self.silent and not self.detectBranches: + print("Import destination: %s" % self.branch) + + self.updatedBranches = set() + + if not self.detectBranches: + if args: + # start a new branch + self.initialParent = "" + else: + # build on a previous revision + self.initialParent = parseRevision(self.branch) + + self.importChanges(changes) + + if not self.silent: + print("") + if len(self.updatedBranches) > 0: + sys.stdout.write("Updated branches: ") + for b in self.updatedBranches: + sys.stdout.write("%s " % b) + sys.stdout.write("\n") + def openStreams(self): self.importProcess = subprocess.Popen(["git", "fast-import"], stdin=subprocess.PIPE, @@ -3539,11 +3636,14 @@ class P4Sync(Command, P4UserMap): self.gitError = self.importProcess.stderr def closeStreams(self): + if self.gitStream is None: + return self.gitStream.close() if self.importProcess.wait() != 0: die("fast-import failed: %s" % self.gitError.read()) self.gitOutput.close() self.gitError.close() + self.gitStream = None def run(self, args): if self.importIntoRemotes: @@ -3727,87 +3827,36 @@ class P4Sync(Command, P4UserMap): b = b[len(self.projectName):] self.createdBranches.add(b) - self.openStreams() - - if revision: - self.importHeadRevision(revision) - else: - changes = [] - - if len(self.changesFile) > 0: - output = open(self.changesFile).readlines() - changeSet = set() - for line in output: - changeSet.add(int(line)) - - for change in changeSet: - changes.append(change) - - changes.sort() - else: - # catch "git p4 sync" with no new branches, in a repo that - # does not have any existing p4 branches - if len(args) == 0: - if not self.p4BranchesInGit: - die("No remote p4 branches. Perhaps you never did \"git p4 clone\" in here.") - - # The default branch is master, unless --branch is used to - # specify something else. Make sure it exists, or complain - # nicely about how to use --branch. - if not self.detectBranches: - if not branch_exists(self.branch): - if branch_arg_given: - die("Error: branch %s does not exist." % self.branch) - else: - die("Error: no branch %s; perhaps specify one with --branch." % - self.branch) + p4_check_access() - if self.verbose: - print("Getting p4 changes for %s...%s" % (', '.join(self.depotPaths), - self.changeRange)) - changes = p4ChangesForPaths(self.depotPaths, self.changeRange, self.changes_block_size) + self.openStreams() - if len(self.maxChanges) > 0: - changes = changes[:min(int(self.maxChanges), len(changes))] + err = None - if len(changes) == 0: - if not self.silent: - print("No changes to import!") + try: + if revision: + self.importHeadRevision(revision) else: - if not self.silent and not self.detectBranches: - print("Import destination: %s" % self.branch) + self.importRevisions(args, branch_arg_given) - self.updatedBranches = set() + if gitConfigBool("git-p4.importLabels"): + self.importLabels = True - if not self.detectBranches: - if args: - # start a new branch - self.initialParent = "" - else: - # build on a previous revision - self.initialParent = parseRevision(self.branch) + if self.importLabels: + p4Labels = getP4Labels(self.depotPaths) + gitTags = getGitTags() - self.importChanges(changes) + missingP4Labels = p4Labels - gitTags + self.importP4Labels(self.gitStream, missingP4Labels) - if not self.silent: - print("") - if len(self.updatedBranches) > 0: - sys.stdout.write("Updated branches: ") - for b in self.updatedBranches: - sys.stdout.write("%s " % b) - sys.stdout.write("\n") - - if gitConfigBool("git-p4.importLabels"): - self.importLabels = True - - if self.importLabels: - p4Labels = getP4Labels(self.depotPaths) - gitTags = getGitTags() + except P4CommandException as e: + err = e - missingP4Labels = p4Labels - gitTags - self.importP4Labels(self.gitStream, missingP4Labels) + finally: + self.closeStreams() - self.closeStreams() + if err: + die(str(err)) # Cleanup temporary branches created during import if self.tempBranches != []: @@ -4141,7 +4190,12 @@ def main(): description = cmd.description, formatter = HelpFormatter()) - (cmd, args) = parser.parse_args(sys.argv[2:], cmd); + try: + (cmd, args) = parser.parse_args(sys.argv[2:], cmd); + except: + parser.print_help() + raise + global verbose verbose = cmd.verbose if cmd.needsGit: |