git-p4: convert descriptive class and function comments into docstrings

Previously, a small number of functions, methods and classes were
documented using comments. This patch improves consistency by converting
these into docstrings similar to those that already exist in the script.

Signed-off-by: Joel Holdsworth <jholdsworth@nvidia.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Joel Holdsworth
2022-04-01 15:24:47 +01:00
committed by Junio C Hamano
parent 59ef3fc104
commit 522e914f65

164
git-p4.py
View File

@@ -458,7 +458,7 @@ def p4_sync(f, *options):
def p4_add(f): def p4_add(f):
# forcibly add file names with wildcards """Forcibly add file names with wildcards."""
if wildcard_present(f): if wildcard_present(f):
p4_system(["add", "-f", f]) p4_system(["add", "-f", f])
else: else:
@@ -526,12 +526,10 @@ def p4_describe(change, shelved=False):
return d return d
#
# Canonicalize the p4 type and return a tuple of the
# base type, plus any modifiers. See "p4 help filetypes"
# for a list and explanation.
#
def split_p4_type(p4type): def split_p4_type(p4type):
"""Canonicalize the p4 type and return a tuple of the base type, plus any
modifiers. See "p4 help filetypes" for a list and explanation.
"""
p4_filetypes_historical = { p4_filetypes_historical = {
"ctempobj": "binary+Sw", "ctempobj": "binary+Sw",
@@ -562,19 +560,18 @@ def split_p4_type(p4type):
return (base, mods) return (base, mods)
#
# return the raw p4 type of a file (text, text+ko, etc)
#
def p4_type(f): def p4_type(f):
"""Return the raw p4 type of a file (text, text+ko, etc)."""
results = p4CmdList(["fstat", "-T", "headType", wildcard_encode(f)]) results = p4CmdList(["fstat", "-T", "headType", wildcard_encode(f)])
return results[0]['headType'] return results[0]['headType']
#
# Given a type base and modifier, return a regexp matching
# the keywords that can be expanded in the file
#
def p4_keywords_regexp_for_type(base, type_mods): def p4_keywords_regexp_for_type(base, type_mods):
"""Given a type base and modifier, return a regexp matching the keywords
that can be expanded in the file.
"""
if base in ("text", "unicode", "binary"): if base in ("text", "unicode", "binary"):
if "ko" in type_mods: if "ko" in type_mods:
return re_ko_keywords return re_ko_keywords
@@ -586,12 +583,11 @@ def p4_keywords_regexp_for_type(base, type_mods):
return None return None
#
# Given a file, return a regexp matching the possible
# RCS keywords that will be expanded, or None for files
# with kw expansion turned off.
#
def p4_keywords_regexp_for_file(file): def p4_keywords_regexp_for_file(file):
"""Given a file, return a regexp matching the possible RCS keywords that
will be expanded, or None for files with kw expansion turned off.
"""
if not os.path.exists(file): if not os.path.exists(file):
return None return None
else: else:
@@ -600,8 +596,9 @@ def p4_keywords_regexp_for_file(file):
def setP4ExecBit(file, mode): def setP4ExecBit(file, mode):
# Reopens an already open file and changes the execute bit to match """Reopens an already open file and changes the execute bit to match the
# the execute bit setting in the passed in mode. execute bit setting in the passed in mode.
"""
p4Type = "+x" p4Type = "+x"
@@ -616,7 +613,7 @@ def setP4ExecBit(file, mode):
def getP4OpenedType(file): def getP4OpenedType(file):
# Returns the perforce file type for the given file. """Returns the perforce file type for the given file."""
result = p4_read_pipe(["opened", wildcard_encode(file)]) result = p4_read_pipe(["opened", wildcard_encode(file)])
match = re.match(".*\((.+)\)( \*exclusive\*)?\r?$", result) match = re.match(".*\((.+)\)( \*exclusive\*)?\r?$", result)
@@ -626,8 +623,9 @@ def getP4OpenedType(file):
die("Could not determine file type for %s (result: '%s')" % (file, result)) die("Could not determine file type for %s (result: '%s')" % (file, result))
# Return the set of all p4 labels
def getP4Labels(depotPaths): def getP4Labels(depotPaths):
"""Return the set of all p4 labels."""
labels = set() labels = set()
if not isinstance(depotPaths, list): if not isinstance(depotPaths, list):
depotPaths = [depotPaths] depotPaths = [depotPaths]
@@ -639,8 +637,9 @@ def getP4Labels(depotPaths):
return labels return labels
# Return the set of all git tags
def getGitTags(): def getGitTags():
"""Return the set of all git tags."""
gitTags = set() gitTags = set()
for line in read_pipe_lines(["git", "tag"]): for line in read_pipe_lines(["git", "tag"]):
tag = line.strip() tag = line.strip()
@@ -691,8 +690,9 @@ def parseDiffTreeEntry(entry):
def isModeExec(mode): def isModeExec(mode):
# Returns True if the given git mode represents an executable file, """Returns True if the given git mode represents an executable file,
# otherwise False. otherwise False.
"""
return mode[-3:] == "755" return mode[-3:] == "755"
@@ -1201,13 +1201,14 @@ def p4ChangesForPaths(depotPaths, changeRange, requestedBlockSize):
def p4PathStartsWith(path, prefix): def p4PathStartsWith(path, prefix):
# This method tries to remedy a potential mixed-case issue: """This method tries to remedy a potential mixed-case issue:
#
# If UserA adds //depot/DirA/file1 If UserA adds //depot/DirA/file1
# and UserB adds //depot/dira/file2 and UserB adds //depot/dira/file2
#
# we may or may not have a problem. If you have core.ignorecase=true, we may or may not have a problem. If you have core.ignorecase=true,
# we treat DirA and dira as the same directory we treat DirA and dira as the same directory.
"""
if gitConfigBool("core.ignorecase"): if gitConfigBool("core.ignorecase"):
return path.lower().startswith(prefix.lower()) return path.lower().startswith(prefix.lower())
return path.startswith(prefix) return path.startswith(prefix)
@@ -1259,12 +1260,14 @@ def getClientRoot():
return entry["Root"] return entry["Root"]
#
# P4 wildcards are not allowed in filenames. P4 complains
# if you simply add them, but you can force it with "-f", in
# which case it translates them into %xx encoding internally.
#
def wildcard_decode(path): def wildcard_decode(path):
"""Decode P4 wildcards into %xx encoding
P4 wildcards are not allowed in filenames. P4 complains if you simply
add them, but you can force it with "-f", in which case it translates
them into %xx encoding internally.
"""
# Search for and fix just these four characters. Do % last so # Search for and fix just these four characters. Do % last so
# that fixing it does not inadvertently create new %-escapes. # that fixing it does not inadvertently create new %-escapes.
# Cannot have * in a filename in windows; untested as to # Cannot have * in a filename in windows; untested as to
@@ -1278,6 +1281,8 @@ def wildcard_decode(path):
def wildcard_encode(path): def wildcard_encode(path):
"""Encode %xx coded wildcards into P4 coding."""
# do % first to avoid double-encoding the %s introduced here # do % first to avoid double-encoding the %s introduced here
path = path.replace("%", "%25") \ path = path.replace("%", "%25") \
.replace("*", "%2A") \ .replace("*", "%2A") \
@@ -1524,7 +1529,7 @@ class P4UserMap:
die("Could not find your p4 user id") die("Could not find your p4 user id")
def p4UserIsMe(self, p4User): def p4UserIsMe(self, p4User):
# return True if the given p4 user is actually me """Return True if the given p4 user is actually me."""
me = self.p4UserId() me = self.p4UserId()
if not p4User or p4User != me: if not p4User or p4User != me:
return False return False
@@ -1727,7 +1732,9 @@ class P4Submit(Command, P4UserMap):
return result return result
def patchRCSKeywords(self, file, regexp): def patchRCSKeywords(self, file, regexp):
# Attempt to zap the RCS keywords in a p4 controlled file matching the given regex """Attempt to zap the RCS keywords in a p4 controlled file matching the
given regex.
"""
(handle, outFileName) = tempfile.mkstemp(dir='.') (handle, outFileName) = tempfile.mkstemp(dir='.')
try: try:
with os.fdopen(handle, "wb") as outFile, open(file, "rb") as inFile: with os.fdopen(handle, "wb") as outFile, open(file, "rb") as inFile:
@@ -1745,7 +1752,9 @@ class P4Submit(Command, P4UserMap):
print("Patched up RCS keywords in %s" % file) print("Patched up RCS keywords in %s" % file)
def p4UserForCommit(self,id): def p4UserForCommit(self,id):
# Return the tuple (perforce user,git email) for a given git commit id """Return the tuple (perforce user,git email) for a given git commit
id.
"""
self.getUserMapFromPerforceServer() self.getUserMapFromPerforceServer()
gitEmail = read_pipe(["git", "log", "--max-count=1", gitEmail = read_pipe(["git", "log", "--max-count=1",
"--format=%ae", id]) "--format=%ae", id])
@@ -1756,7 +1765,7 @@ class P4Submit(Command, P4UserMap):
return (self.emails[gitEmail],gitEmail) return (self.emails[gitEmail],gitEmail)
def checkValidP4Users(self,commits): def checkValidP4Users(self,commits):
# check if any git authors cannot be mapped to p4 users """Check if any git authors cannot be mapped to p4 users."""
for id in commits: for id in commits:
(user,email) = self.p4UserForCommit(id) (user,email) = self.p4UserForCommit(id)
if not user: if not user:
@@ -1767,10 +1776,12 @@ class P4Submit(Command, P4UserMap):
die("Error: %s\nSet git-p4.allowMissingP4Users to true to allow this." % msg) die("Error: %s\nSet git-p4.allowMissingP4Users to true to allow this." % msg)
def lastP4Changelist(self): def lastP4Changelist(self):
# Get back the last changelist number submitted in this client spec. This """Get back the last changelist number submitted in this client spec.
# 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 This then gets used to patch up the username in the change. If the
# wrong. 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 client = None
for r in results: for r in results:
@@ -1786,7 +1797,7 @@ class P4Submit(Command, P4UserMap):
die("Could not get changelist number for last submit - cannot patch up user details") die("Could not get changelist number for last submit - cannot patch up user details")
def modifyChangelistUser(self, changelist, newUser): def modifyChangelistUser(self, changelist, newUser):
# fixup the user field of a changelist after it has been submitted. """Fixup the user field of a changelist after it has been submitted."""
changes = p4CmdList(["change", "-o", changelist]) changes = p4CmdList(["change", "-o", changelist])
if len(changes) != 1: if len(changes) != 1:
die("Bad output from p4 change modifying %s to user %s" % die("Bad output from p4 change modifying %s to user %s" %
@@ -1809,8 +1820,9 @@ class P4Submit(Command, P4UserMap):
die("Could not modify user field of changelist %s to %s" % (changelist, newUser)) die("Could not modify user field of changelist %s to %s" % (changelist, newUser))
def canChangeChangelists(self): def canChangeChangelists(self):
# check to see if we have p4 admin or super-user permissions, either of """Check to see if we have p4 admin or super-user permissions, either
# which are required to modify changelists. of which are required to modify changelists.
"""
results = p4CmdList(["protects", self.depotPath]) results = p4CmdList(["protects", self.depotPath])
for r in results: for r in results:
if 'perm' in r: if 'perm' in r:
@@ -2262,9 +2274,11 @@ class P4Submit(Command, P4UserMap):
os.remove(fileName) os.remove(fileName)
return submitted return submitted
# Export git tags as p4 labels. Create a p4 label and then tag
# with that.
def exportGitTags(self, gitTags): def exportGitTags(self, gitTags):
"""Export git tags as p4 labels. Create a p4 label and then tag with
that.
"""
validLabelRegexp = gitConfig("git-p4.labelExportRegexp") validLabelRegexp = gitConfig("git-p4.labelExportRegexp")
if len(validLabelRegexp) == 0: if len(validLabelRegexp) == 0:
validLabelRegexp = defaultLabelRegexp validLabelRegexp = defaultLabelRegexp
@@ -2787,8 +2801,8 @@ class P4Sync(Command, P4UserMap):
self.tz = "%+03d%02d" % (- time.timezone / 3600, ((- time.timezone % 3600) / 60)) self.tz = "%+03d%02d" % (- time.timezone / 3600, ((- time.timezone % 3600) / 60))
self.labels = {} self.labels = {}
# Force a checkpoint in fast-import and wait for it to finish
def checkpoint(self): def checkpoint(self):
"""Force a checkpoint in fast-import and wait for it to finish."""
self.gitStream.write("checkpoint\n\n") self.gitStream.write("checkpoint\n\n")
self.gitStream.write("progress checkpoint\n\n") self.gitStream.write("progress checkpoint\n\n")
self.gitStream.flush() self.gitStream.flush()
@@ -2934,10 +2948,12 @@ class P4Sync(Command, P4UserMap):
print('Path with non-ASCII characters detected. Used %s to encode: %s ' % (encoding, path)) print('Path with non-ASCII characters detected. Used %s to encode: %s ' % (encoding, path))
return path return path
# output one file from the P4 stream
# - helper for streamP4Files
def streamOneP4File(self, file, contents): def streamOneP4File(self, file, contents):
"""Output one file from the P4 stream.
This is a helper for streamP4Files().
"""
file_path = file['depotFile'] file_path = file['depotFile']
relPath = self.stripRepoPath(decode_path(file_path), self.branchPrefixes) relPath = self.stripRepoPath(decode_path(file_path), self.branchPrefixes)
@@ -3029,8 +3045,8 @@ class P4Sync(Command, P4UserMap):
if self.largeFileSystem and self.largeFileSystem.isLargeFile(relPath): if self.largeFileSystem and self.largeFileSystem.isLargeFile(relPath):
self.largeFileSystem.removeLargeFile(relPath) self.largeFileSystem.removeLargeFile(relPath)
# handle another chunk of streaming data
def streamP4FilesCb(self, marshalled): def streamP4FilesCb(self, marshalled):
"""Handle another chunk of streaming data."""
# catch p4 errors and complain # catch p4 errors and complain
err = None err = None
@@ -3094,8 +3110,9 @@ class P4Sync(Command, P4UserMap):
self.stream_have_file_info = True self.stream_have_file_info = True
# Stream directly from "p4 files" into "git fast-import"
def streamP4Files(self, files): def streamP4Files(self, files):
"""Stream directly from "p4 files" into "git fast-import."""
filesForCommit = [] filesForCommit = []
filesToRead = [] filesToRead = []
filesToDelete = [] filesToDelete = []
@@ -3199,15 +3216,18 @@ class P4Sync(Command, P4UserMap):
return hasPrefix return hasPrefix
def findShadowedFiles(self, files, change): def findShadowedFiles(self, files, change):
# Perforce allows you commit files and directories with the same name, """Perforce allows you commit files and directories with the same name,
# so you could have files //depot/foo and //depot/foo/bar both checked so you could have files //depot/foo and //depot/foo/bar both checked
# in. A p4 sync of a repository in this state fails. Deleting one of in. A p4 sync of a repository in this state fails. Deleting one of
# the files recovers the repository. the files recovers the repository.
#
# Git will not allow the broken state to exist and only the most recent Git will not allow the broken state to exist and only the most
# of the conflicting names is left in the repository. When one of the recent of the conflicting names is left in the repository. When one
# conflicting files is deleted we need to re-add the other one to make of the conflicting files is deleted we need to re-add the other one
# sure the git repository recovers in the same way as perforce. to make sure the git repository recovers in the same way as
perforce.
"""
deleted = [f for f in files if f['action'] in self.delete_actions] deleted = [f for f in files if f['action'] in self.delete_actions]
to_check = set() to_check = set()
for f in deleted: for f in deleted:
@@ -3324,8 +3344,11 @@ class P4Sync(Command, P4UserMap):
print("Tag %s does not match with change %s: file count is different." print("Tag %s does not match with change %s: file count is different."
% (labelDetails["label"], change)) % (labelDetails["label"], change))
# Build a dictionary of changelists and labels, for "detect-labels" option.
def getLabels(self): def getLabels(self):
"""Build a dictionary of changelists and labels, for "detect-labels"
option.
"""
self.labels = {} self.labels = {}
l = p4CmdList(["labels"] + ["%s..." % p for p in self.depotPaths]) l = p4CmdList(["labels"] + ["%s..." % p for p in self.depotPaths])
@@ -3351,11 +3374,12 @@ class P4Sync(Command, P4UserMap):
if self.verbose: if self.verbose:
print("Label changes: %s" % self.labels.keys()) print("Label changes: %s" % self.labels.keys())
# Import p4 labels as git tags. A direct mapping does not
# exist, so assume that if all the files are at the same revision
# then we can use that, or it's something more complicated we should
# just ignore.
def importP4Labels(self, stream, p4Labels): def importP4Labels(self, stream, p4Labels):
"""Import p4 labels as git tags. A direct mapping does not exist, so
assume that if all the files are at the same revision then we can
use that, or it's something more complicated we should just ignore.
"""
if verbose: if verbose:
print("import p4 labels: " + ' '.join(p4Labels)) print("import p4 labels: " + ' '.join(p4Labels))