summaryrefslogtreecommitdiff
path: root/git-p4.py
diff options
context:
space:
mode:
Diffstat (limited to 'git-p4.py')
-rwxr-xr-xgit-p4.py169
1 files changed, 48 insertions, 121 deletions
diff --git a/git-p4.py b/git-p4.py
index 2b4500226a..cb37545455 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -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.
@@ -337,17 +352,19 @@ def p4_read_pipe(c, ignore_error=False, raw=False):
real_cmd = p4_build_cmd(c)
return read_pipe(real_cmd, ignore_error, raw=raw)
-def read_pipe_lines(c):
+def read_pipe_lines(c, raw=False):
if verbose:
sys.stderr.write('Reading pipe: %s\n' % str(c))
expand = not isinstance(c, list)
p = subprocess.Popen(c, stdout=subprocess.PIPE, shell=expand)
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
+ return lines
def p4_read_pipe_lines(c):
"""Specifically invoke p4 on the command supplied. """
@@ -577,20 +594,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
@@ -1532,80 +1541,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")
@@ -1753,18 +1688,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)
@@ -2091,25 +2021,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:
@@ -2966,7 +2895,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 +2959,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 +2991,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 +3036,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
@@ -3623,7 +3551,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
@@ -4363,13 +4292,11 @@ def printUsage(commands):
print("")
commands = {
- "debug" : P4Debug,
"submit" : P4Submit,
"commit" : P4Submit,
"sync" : P4Sync,
"rebase" : P4Rebase,
"clone" : P4Clone,
- "rollback" : P4RollBack,
"branches" : P4Branches,
"unshelve" : P4Unshelve,
}