git-p4: improve consistency of docstring formatting

This patch attempts to improve the consistency of the docstrings by making the following changes: - Rewraps all docstrings to a 79-character column limit. - Adds a full stop at the end of every docstring. - Removes any spaces after the opening triple-quotes of all docstrings. - Sets the hanging indent of multi-line docstrings to 3-spaces. - Ensures that the closing triple-quotes of multi-line docstrings are always on a new line indented by a 3-space indent. Signed-off-by: Joel Holdsworth <jholdsworth@nvidia.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Joel Holdsworth committed Apr 1, 2022 at 15:24 UTC 59ef3fc1044eb01b4691f0ca6ca0b1313f7bdc00
1 file changed +158 -133
git-p4.py
+158 -133
@@ -61,9 +61,9 @@ re_k_keywords = re.compile(br'\$(Id|Header|Author|Date|DateTime|Change|File|Revi
61
62
63 def format_size_human_readable(num):
64 - """ Returns a number of units (typically bytes) formatted as a human-readable
65 - string.
66 - """
64 + """Returns a number of units (typically bytes) formatted as a
65 + human-readable string.
66 + """
67 if num < 1024:
68 return '{:d} B'.format(num)
69 for unit in ["Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]:
@@ -76,10 +76,10 @@ def format_size_human_readable(num):
76 def p4_build_cmd(cmd):
77 """Build a suitable p4 command line.
78
79 - This consolidates building and returning a p4 command line into one
80 - location. It means that hooking into the environment, or other configuration
81 - can be done more easily.
82 - """
79 + This consolidates building and returning a p4 command line into one
80 + location. It means that hooking into the environment, or other
81 + configuration can be done more easily.
82 + """
83 real_cmd = ["p4"]
84
85 user = gitConfig("git-p4.user")
@@ -122,9 +122,9 @@ def p4_build_cmd(cmd):
122
123
124 def git_dir(path):
125 - """ Return TRUE if the given path is a git directory (/path/to/dir/.git).
126 - This won't automatically add ".git" to a directory.
127 - """
125 + """Return TRUE if the given path is a git directory (/path/to/dir/.git).
126 + This won't automatically add ".git" to a directory.
127 + """
128 d = read_pipe(["git", "--git-dir", path, "rev-parse", "--git-dir"], True).strip()
129 if not d or len(d) == 0:
130 return None
@@ -133,20 +133,18 @@ def git_dir(path):
133
134
135 def chdir(path, is_client_path=False):
136 - """Do chdir to the given path, and set the PWD environment
137 - variable for use by P4. It does not look at getcwd() output.
138 - Since we're not using the shell, it is necessary to set the
139 - PWD environment variable explicitly.
140 -
141 - Normally, expand the path to force it to be absolute. This
142 - addresses the use of relative path names inside P4 settings,
143 - e.g. P4CONFIG=.p4config. P4 does not simply open the filename
144 - as given; it looks for .p4config using PWD.
145 -
146 - If is_client_path, the path was handed to us directly by p4,
147 - and may be a symbolic link. Do not call os.getcwd() in this
148 - case, because it will cause p4 to think that PWD is not inside
149 - the client path.
136 + """Do chdir to the given path, and set the PWD environment variable for use
137 + by P4. It does not look at getcwd() output. Since we're not using the
138 + shell, it is necessary to set the PWD environment variable explicitly.
139 +
140 + Normally, expand the path to force it to be absolute. This addresses
141 + the use of relative path names inside P4 settings, e.g.
142 + P4CONFIG=.p4config. P4 does not simply open the filename as given; it
143 + looks for .p4config using PWD.
144 +
145 + If is_client_path, the path was handed to us directly by p4, and may be
146 + a symbolic link. Do not call os.getcwd() in this case, because it will
147 + cause p4 to think that PWD is not inside the client path.
148 """
149
150 os.chdir(path)
@@ -167,9 +165,9 @@ def calcDiskFree():
165
166
167 def die(msg):
170 - """ Terminate execution. Make sure that any running child processes have been wait()ed for before
171 - calling this.
172 - """
168 + """Terminate execution. Make sure that any running child processes have
169 + been wait()ed for before calling this.
170 + """
171 if verbose:
172 raise Exception(msg)
173 else:
@@ -178,11 +176,11 @@ def die(msg):
176
177
178 def prompt(prompt_text):
181 - """ Prompt the user to choose one of the choices
179 + """Prompt the user to choose one of the choices.
180
183 - Choices are identified in the prompt_text by square brackets around
184 - a single letter option.
185 - """
181 + Choices are identified in the prompt_text by square brackets around a
182 + single letter option.
183 + """
184 choices = set(m.group(1) for m in re.finditer(r"\[(.)\]", prompt_text))
185 while True:
186 sys.stderr.flush()
@@ -215,8 +213,10 @@ else:
213
214
215 def decode_path(path):
218 - """Decode a given string (bytes or otherwise) using configured path encoding options
219 - """
216 + """Decode a given string (bytes or otherwise) using configured path
217 + encoding options.
218 + """
219 +
220 encoding = gitConfig('git-p4.pathEncoding') or 'utf_8'
221 if bytes is not str:
222 return path.decode(encoding, errors='replace') if isinstance(path, bytes) else path
@@ -262,10 +262,9 @@ def p4_write_pipe(c, stdin, *k, **kw):
262
263
264 def read_pipe_full(c, *k, **kw):
265 - """ Read output from command. Returns a tuple
266 - of the return status, stdout text and stderr
267 - text.
268 - """
265 + """Read output from command. Returns a tuple of the return status, stdout
266 + text and stderr text.
267 + """
268 if verbose:
269 sys.stderr.write('Reading pipe: {}\n'.format(' '.join(c)))
270
@@ -276,12 +275,12 @@ def read_pipe_full(c, *k, **kw):
275
276
277 def read_pipe(c, ignore_error=False, raw=False, *k, **kw):
279 - """ Read output from command. Returns the output text on
280 - success. On failure, terminates execution, unless
281 - ignore_error is True, when it returns an empty string.
278 + """Read output from command. Returns the output text on success. On
279 + failure, terminates execution, unless ignore_error is True, when it
280 + returns an empty string.
281
283 - If raw is True, do not attempt to decode output text.
284 - """
282 + If raw is True, do not attempt to decode output text.
283 + """
284 (retcode, out, err) = read_pipe_full(c, *k, **kw)
285 if retcode != 0:
286 if ignore_error:
@@ -294,9 +293,9 @@ def read_pipe(c, ignore_error=False, raw=False, *k, **kw):
293
294
295 def read_pipe_text(c, *k, **kw):
297 - """ Read output from a command with trailing whitespace stripped.
298 - On error, returns None.
299 - """
296 + """Read output from a command with trailing whitespace stripped. On error,
297 + returns None.
298 + """
299 (retcode, out, err) = read_pipe_full(c, *k, **kw)
300 if retcode != 0:
301 return None
@@ -324,14 +323,15 @@ def read_pipe_lines(c, raw=False, *k, **kw):
323
324
325 def p4_read_pipe_lines(c, *k, **kw):
327 - """Specifically invoke p4 on the command supplied. """
326 + """Specifically invoke p4 on the command supplied."""
327 real_cmd = p4_build_cmd(c)
328 return read_pipe_lines(real_cmd, *k, **kw)
329
330
331 def p4_has_command(cmd):
333 - """Ask p4 for help on this command. If it returns an error, the
334 - command does not exist in this version of p4."""
332 + """Ask p4 for help on this command. If it returns an error, the command
333 + does not exist in this version of p4.
334 + """
335 real_cmd = p4_build_cmd(["help", cmd])
336 p = subprocess.Popen(real_cmd, stdout=subprocess.PIPE,
337 stderr=subprocess.PIPE)
@@ -340,10 +340,11 @@ def p4_has_command(cmd):
340
341
342 def p4_has_move_command():
343 - """See if the move command exists, that it supports -k, and that
344 - it has not been administratively disabled. The arguments
345 - must be correct, but the filenames do not have to exist. Use
346 - ones with wildcards so even if they exist, it will fail."""
343 + """See if the move command exists, that it supports -k, and that it has not
344 + been administratively disabled. The arguments must be correct, but the
345 + filenames do not have to exist. Use ones with wildcards so even if they
346 + exist, it will fail.
347 + """
348
349 if not p4_has_command("move"):
350 return False
@@ -372,7 +373,7 @@ def system(cmd, ignore_error=False, *k, **kw):
373
374
375 def p4_system(cmd, *k, **kw):
375 - """Specifically invoke p4 as the system command. """
376 + """Specifically invoke p4 as the system command."""
377 real_cmd = p4_build_cmd(cmd)
378 retcode = subprocess.call(real_cmd, *k, **kw)
379 if retcode:
@@ -384,8 +385,8 @@ def die_bad_access(s):
385
386
387 def p4_check_access(min_expiration=1):
387 - """ Check if we can access Perforce - account still logged in
388 - """
388 + """Check if we can access Perforce - account still logged in."""
389 +
390 results = p4CmdList(["login", "-s"])
391
392 if len(results) == 0:
@@ -433,14 +434,14 @@ _p4_version_string = None
434
435
436 def p4_version_string():
436 - """Read the version string, showing just the last line, which
437 - hopefully is the interesting version bit.
437 + """Read the version string, showing just the last line, which hopefully is
438 + the interesting version bit.
439
440 $ p4 -V
441 Perforce - The Fast Software Configuration Management System.
442 Copyright 1995-2011 Perforce Software. All rights reserved.
443 Rev. P4/NTX86/2011.1/393975 (2011/12/16).
443 - """
444 + """
445 global _p4_version_string
446 if not _p4_version_string:
447 a = p4_read_pipe_lines(["-V"])
@@ -495,9 +496,11 @@ def p4_last_change():
496
497
498 def p4_describe(change, shelved=False):
498 - """Make sure it returns a valid result by checking for
499 - the presence of field "time". Return a dict of the
500 - results."""
499 + """Make sure it returns a valid result by checking for the presence of
500 + field "time".
501 +
502 + Return a dict of the results.
503 + """
504
505 cmd = ["describe", "-s"]
506 if shelved:
@@ -651,21 +654,22 @@ _diff_tree_pattern = None
654 def parseDiffTreeEntry(entry):
655 """Parses a single diff tree entry into its component elements.
656
654 - See git-diff-tree(1) manpage for details about the format of the diff
655 - output. This method returns a dictionary with the following elements:
656 -
657 - src_mode - The mode of the source file
658 - dst_mode - The mode of the destination file
659 - src_sha1 - The sha1 for the source file
660 - dst_sha1 - The sha1 fr the destination file
661 - status - The one letter status of the diff (i.e. 'A', 'M', 'D', etc)
662 - status_score - The score for the status (applicable for 'C' and 'R'
663 - statuses). This is None if there is no score.
664 - src - The path for the source file.
665 - dst - The path for the destination file. This is only present for
666 - copy or renames. If it is not present, this is None.
667 -
668 - If the pattern is not matched, None is returned."""
657 + See git-diff-tree(1) manpage for details about the format of the diff
658 + output. This method returns a dictionary with the following elements:
659 +
660 + src_mode - The mode of the source file
661 + dst_mode - The mode of the destination file
662 + src_sha1 - The sha1 for the source file
663 + dst_sha1 - The sha1 fr the destination file
664 + status - The one letter status of the diff (i.e. 'A', 'M', 'D', etc)
665 + status_score - The score for the status (applicable for 'C' and 'R'
666 + statuses). This is None if there is no score.
667 + src - The path for the source file.
668 + dst - The path for the destination file. This is only present for
669 + copy or renames. If it is not present, this is None.
670 +
671 + If the pattern is not matched, None is returned.
672 + """
673
674 global _diff_tree_pattern
675 if not _diff_tree_pattern:
@@ -693,14 +697,16 @@ def isModeExec(mode):
697
698
699 class P4Exception(Exception):
696 - """ Base class for exceptions from the p4 client """
700 + """Base class for exceptions from the p4 client."""
701
702 def __init__(self, exit_code):
703 self.p4ExitCode = exit_code
704
705
706 class P4ServerException(P4Exception):
703 - """ Base class for exceptions where we get some kind of marshalled up result from the server """
707 + """Base class for exceptions where we get some kind of marshalled up result
708 + from the server.
709 + """
710
711 def __init__(self, exit_code, p4_result):
712 super(P4ServerException, self).__init__(exit_code)
@@ -710,7 +716,7 @@ class P4ServerException(P4Exception):
716
717
718 class P4RequestSizeException(P4ServerException):
713 - """ One of the maxresults or maxscanrows errors """
719 + """One of the maxresults or maxscanrows errors."""
720
721 def __init__(self, exit_code, p4_result, limit):
722 super(P4RequestSizeException, self).__init__(exit_code, p4_result)
@@ -718,7 +724,7 @@ class P4RequestSizeException(P4ServerException):
724
725
726 class P4CommandException(P4Exception):
721 - """ Something went wrong calling p4 which means we have to give up """
727 + """Something went wrong calling p4 which means we have to give up."""
728
729 def __init__(self, msg):
730 self.msg = msg
@@ -943,7 +949,8 @@ def gitConfig(key, typeSpecifier=None):
949 def gitConfigBool(key):
950 """Return a bool, using git config --bool. It is True only if the
951 variable is set to true, and False if set to false or not present
946 - in the config."""
952 + in the config.
953 + """
954
955 if key not in _gitConfig:
956 _gitConfig[key] = gitConfig(key, '--bool') == "true"
@@ -976,7 +983,8 @@ def p4BranchesInGit(branchesAreInRemotes=True):
983 in remotes or heads as specified by the argument. Return
984 a dictionary of { branch: revision } for each one found.
985 The branch names are the short names, without any
979 - "p4/" prefix."""
986 + "p4/" prefix.
987 + """
988
989 branches = {}
990
@@ -1207,7 +1215,8 @@ def p4PathStartsWith(path, prefix):
1215
1216 def getClientSpec():
1217 """Look at the p4 client spec, create a View() object that contains
1210 - all the mappings, and return it."""
1218 + all the mappings, and return it.
1219 + """
1220
1221 specList = p4CmdList(["client", "-o"])
1222 if len(specList) != 1:
@@ -1290,13 +1299,15 @@ class LargeFileSystem(object):
1299 self.writeToGitStream = writeToGitStream
1300
1301 def generatePointer(self, cloneDestination, contentFile):
1293 - """Return the content of a pointer file that is stored in Git instead of
1294 - the actual content."""
1302 + """Return the content of a pointer file that is stored in Git instead
1303 + of the actual content.
1304 + """
1305 assert False, "Method 'generatePointer' required in " + self.__class__.__name__
1306
1307 def pushFile(self, localLargeFile):
1308 """Push the actual content which is not stored in the Git repository to
1299 - a server."""
1309 + a server.
1310 + """
1311 assert False, "Method 'pushFile' required in " + self.__class__.__name__
1312
1313 def hasLargeFileExtension(self, relPath):
@@ -1344,7 +1355,8 @@ class LargeFileSystem(object):
1355 def processContent(self, git_mode, relPath, contents):
1356 """Processes the content of git fast import. This method decides if a
1357 file is stored in the large file system and handles all necessary
1347 - steps."""
1358 + steps.
1359 + """
1360 if self.exceedsLargeFileThreshold(relPath, contents) or self.hasLargeFileExtension(relPath):
1361 contentTempFile = self.generateTempFile(contents)
1362 (pointer_git_mode, contents, localLargeFile) = self.generatePointer(contentTempFile)
@@ -1369,7 +1381,8 @@ class MockLFS(LargeFileSystem):
1381
1382 def generatePointer(self, contentFile):
1383 """The pointer content is the original content prefixed with "pointer-".
1372 - The local filename of the large file storage is derived from the file content.
1384 + The local filename of the large file storage is derived from the
1385 + file content.
1386 """
1387 with open(contentFile, 'r') as f:
1388 content = next(f)
@@ -1379,8 +1392,8 @@ class MockLFS(LargeFileSystem):
1392 return (gitMode, pointerContents, localLargeFile)
1393
1394 def pushFile(self, localLargeFile):
1382 - """The remote filename of the large file storage is the same as the local
1383 - one but in a different directory.
1395 + """The remote filename of the large file storage is the same as the
1396 + local one but in a different directory.
1397 """
1398 remotePath = os.path.join(os.path.dirname(localLargeFile), '..', 'remote')
1399 if not os.path.exists(remotePath):
@@ -1390,7 +1403,8 @@ class MockLFS(LargeFileSystem):
1403
1404 class GitLFS(LargeFileSystem):
1405 """Git LFS as backend for the git-p4 large file system.
1393 - See https://git-lfs.github.com/ for details."""
1406 + See https://git-lfs.github.com/ for details.
1407 + """
1408
1409 def __init__(self, *args):
1410 LargeFileSystem.__init__(self, *args)
@@ -1656,20 +1670,20 @@ class P4Submit(Command, P4UserMap):
1670 die("You have files opened with perforce! Close them before starting the sync.")
1671
1672 def separate_jobs_from_description(self, message):
1659 - """Extract and return a possible Jobs field in the commit
1660 - message. It goes into a separate section in the p4 change
1661 - specification.
1673 + """Extract and return a possible Jobs field in the commit message. It
1674 + goes into a separate section in the p4 change specification.
1675
1663 - A jobs line starts with "Jobs:" and looks like a new field
1664 - in a form. Values are white-space separated on the same
1665 - line or on following lines that start with a tab.
1676 + A jobs line starts with "Jobs:" and looks like a new field in a
1677 + form. Values are white-space separated on the same line or on
1678 + following lines that start with a tab.
1679
1667 - This does not parse and extract the full git commit message
1668 - like a p4 form. It just sees the Jobs: line as a marker
1669 - to pass everything from then on directly into the p4 form,
1670 - but outside the description section.
1680 + This does not parse and extract the full git commit message like a
1681 + p4 form. It just sees the Jobs: line as a marker to pass everything
1682 + from then on directly into the p4 form, but outside the description
1683 + section.
1684
1672 - Return a tuple (stripped log message, jobs string)."""
1685 + Return a tuple (stripped log message, jobs string).
1686 + """
1687
1688 m = re.search(r'^Jobs:', message, re.MULTILINE)
1689 if m is None:
@@ -1680,9 +1694,10 @@ class P4Submit(Command, P4UserMap):
1694 return (stripped_message, jobtext)
1695
1696 def prepareLogMessage(self, template, message, jobs):
1683 - """Edits the template returned from "p4 change -o" to insert
1684 - the message in the Description field, and the jobs text in
1685 - the Jobs field."""
1697 + """Edits the template returned from "p4 change -o" to insert the
1698 + message in the Description field, and the jobs text in the Jobs
1699 + field.
1700 + """
1701 result = ""
1702
1703 inDescriptionSection = False
@@ -1807,11 +1822,13 @@ class P4Submit(Command, P4UserMap):
1822
1823 def prepareSubmitTemplate(self, changelist=None):
1824 """Run "p4 change -o" to grab a change specification template.
1825 +
1826 This does not use "p4 -G", as it is nice to keep the submission
1827 template in original order, since a human might edit it.
1828
1829 Remove lines in the Files section that show changes to files
1814 - outside the depot path we're committing into."""
1830 + outside the depot path we're committing into.
1831 + """
1832
1833 [upstream, settings] = findUpstreamBranchPoint()
1834
@@ -1874,8 +1891,10 @@ class P4Submit(Command, P4UserMap):
1891 return template
1892
1893 def edit_template(self, template_file):
1877 - """Invoke the editor to let the user change the submission
1878 - message. Return true if okay to continue with the submit."""
1894 + """Invoke the editor to let the user change the submission message.
1895 +
1896 + Return true if okay to continue with the submit.
1897 + """
1898
1899 # if configured to skip the editing part, just submit
1900 if gitConfigBool("git-p4.skipSubmitEdit"):
@@ -2571,8 +2590,9 @@ class P4Submit(Command, P4UserMap):
2590
2591
2592 class View(object):
2574 - """Represent a p4 view ("p4 help views"), and map files in a
2575 - repo according to the view."""
2593 + """Represent a p4 view ("p4 help views"), and map files in a repo according
2594 + to the view.
2595 + """
2596
2597 def __init__(self, client_name):
2598 self.mappings = []
@@ -2581,9 +2601,10 @@ class View(object):
2601 self.client_spec_path_cache = {}
2602
2603 def append(self, view_line):
2584 - """Parse a view line, splitting it into depot and client
2585 - sides. Append to self.mappings, preserving order. This
2586 - is only needed for tag creation."""
2604 + """Parse a view line, splitting it into depot and client sides. Append
2605 + to self.mappings, preserving order. This is only needed for tag
2606 + creation.
2607 + """
2608
2609 # Split the view line into exactly two words. P4 enforces
2610 # structure on these lines that simplifies this quite a bit.
@@ -2632,7 +2653,7 @@ class View(object):
2653 return clientFile[len(self.client_prefix):]
2654
2655 def update_client_spec_path_cache(self, files):
2635 - """ Caching file paths by "p4 where" batch query """
2656 + """Caching file paths by "p4 where" batch query."""
2657
2658 # List depot file paths exclude that already cached
2659 fileArgs = [f['path'] for f in files if decode_path(f['path']) not in self.client_spec_path_cache]
@@ -2664,9 +2685,11 @@ class View(object):
2685 self.client_spec_path_cache[depotFile] = b''
2686
2687 def map_in_client(self, depot_path):
2667 - """Return the relative location in the client where this
2668 - depot file should live. Returns "" if the file should
2669 - not be mapped in the client."""
2688 + """Return the relative location in the client where this depot file
2689 + should live.
2690 +
2691 + Returns "" if the file should not be mapped in the client.
2692 + """
2693
2694 if gitConfigBool("core.ignorecase"):
2695 depot_path = depot_path.lower()
@@ -2817,10 +2840,10 @@ class P4Sync(Command, P4UserMap):
2840 return jobs
2841
2842 def stripRepoPath(self, path, prefixes):
2820 - """When streaming files, this is called to map a p4 depot path
2821 - to where it should go in git. The prefixes are either
2822 - self.depotPaths, or self.branchPrefixes in the case of
2823 - branch detection."""
2843 + """When streaming files, this is called to map a p4 depot path to where
2844 + it should go in git. The prefixes are either self.depotPaths, or
2845 + self.branchPrefixes in the case of branch detection.
2846 + """
2847
2848 if self.useClientSpec:
2849 # branch detection moves files up a level (the branch name)
@@ -2849,8 +2872,9 @@ class P4Sync(Command, P4UserMap):
2872 return path
2873
2874 def splitFilesIntoBranches(self, commit):
2852 - """Look at each depotFile in the commit to figure out to what
2853 - branch it belongs."""
2875 + """Look at each depotFile in the commit to figure out to what branch it
2876 + belongs.
2877 + """
2878
2879 if self.clientSpecDirs:
2880 files = self.extractFilesFromCommit(commit)
@@ -3122,9 +3146,10 @@ class P4Sync(Command, P4UserMap):
3146 return "%s <a@b>" % userid
3147
3148 def streamTag(self, gitStream, labelName, labelDetails, commit, epoch):
3125 - """ Stream a p4 tag.
3126 - commit is either a git commit, or a fast-import mark, ":<p4commit>"
3127 - """
3149 + """Stream a p4 tag.
3150 +
3151 + Commit is either a git commit, or a fast-import mark, ":<p4commit>".
3152 + """
3153
3154 if verbose:
3155 print("writing tag %s for commit %s" % (labelName, commit))
@@ -4175,8 +4200,7 @@ class P4Unshelve(Command):
4200 self.destbranch = "refs/remotes/p4-unshelved"
4201
4202 def renameBranch(self, branch_name):
4178 - """ Rename the existing branch to branch_name.N
4179 - """
4203 + """Rename the existing branch to branch_name.N ."""
4204
4205 found = True
4206 for i in range(0,1000):
@@ -4192,9 +4216,9 @@ class P4Unshelve(Command):
4216 sys.exit("gave up trying to rename existing branch {0}".format(sync.branch))
4217
4218 def findLastP4Revision(self, starting_point):
4195 - """ Look back from starting_point for the first commit created by git-p4
4196 - to find the P4 commit we are based on, and the depot-paths.
4197 - """
4219 + """Look back from starting_point for the first commit created by git-p4
4220 + to find the P4 commit we are based on, and the depot-paths.
4221 + """
4222
4223 for parent in (range(65535)):
4224 log = extractLogMessageFromGitCommit("{0}~{1}".format(starting_point, parent))
@@ -4205,8 +4229,9 @@ class P4Unshelve(Command):
4229 sys.exit("could not find git-p4 commits in {0}".format(self.origin))
4230
4231 def createShelveParent(self, change, branch_name, sync, origin):
4208 - """ Create a commit matching the parent of the shelved changelist 'change'
4209 - """
4232 + """Create a commit matching the parent of the shelved changelist
4233 + 'change'.
4234 + """
4235 parent_description = p4_describe(change, shelved=True)
4236 parent_description['desc'] = 'parent for shelved changelist {}\n'.format(change)
4237 files = sync.extractFilesFromCommit(parent_description, shelved=False, shelved_cl=change)