From: Joel Holdsworth <jholdsworth@nvidia.com>
To: git@vger.kernel.org, Luke Diamand <luke@diamand.org>,
Junio C Hamano <gitster@pobox.com>,
Eric Sunshine <sunshine@sunshineco.com>
Cc: Tzadik Vanderhoof <tzadik.vanderhoof@gmail.com>,
Dorgon Chang <dorgonman@hotmail.com>,
Joachim Kuebart <joachim.kuebart@gmail.com>,
Daniel Levin <dendy.ua@gmail.com>,
Johannes Schindelin <johannes.schindelin@gmx.de>,
Ben Keene <seraphire@gmail.com>,
Andrew Oakley <andrew@adoakley.name>,
Joel Holdsworth <jholdsworth@nvidia.com>
Subject: [PATCH v2 2/3] git-p4: pass command arguments as lists instead of using shell
Date: Thu, 6 Jan 2022 21:40:34 +0000 [thread overview]
Message-ID: <20220106214035.90725-3-jholdsworth@nvidia.com> (raw)
In-Reply-To: <20220106214035.90725-1-jholdsworth@nvidia.com>
In the majority of the subprocess calls where shell=True was used, it
was only needed to parse command arguments by spaces. In each of these
cases, the commands are now being passed in as lists instead of strings.
This change aids the comprehensibility of the code. Constucting commands
and arguments using strings risks bugs from unsanitized inputs, and the
attendant complexity of properly quoting and escaping command arguments.
Signed-off-by: Joel Holdsworth <jholdsworth@nvidia.com>
---
git-p4.py | 105 ++++++++++++++++++++++--------------------------------
1 file changed, 43 insertions(+), 62 deletions(-)
diff --git a/git-p4.py b/git-p4.py
index 7ec90388b6..492eb5aa23 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -96,10 +96,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
@@ -721,12 +718,7 @@ def isModeExecChanged(src_mode, dst_mode):
def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None, skip_info=False,
errors_as_exceptions=False, *k, **kw):
- if not isinstance(cmd, list):
- cmd = "-G " + cmd
- else:
- cmd = ["-G"] + cmd
-
- cmd = p4_build_cmd(cmd)
+ cmd = p4_build_cmd(["-G"] + cmd)
if verbose:
sys.stderr.write("Opening pipe: %s\n" % str(cmd))
@@ -849,7 +841,7 @@ def isValidGitDir(path):
return git_dir(path) != None
def parseRevision(ref):
- return read_pipe("git rev-parse %s" % ref, shell=True).strip()
+ return read_pipe(["git", "rev-parse", ref]).strip()
def branchExists(ref):
rev = read_pipe(["git", "rev-parse", "-q", "--verify", ref],
@@ -955,13 +947,13 @@ 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, shell=True):
+ for line in read_pipe_lines(cmdline):
line = line.strip()
# only import to p4/
@@ -1024,7 +1016,7 @@ def createOrUpdateBranchesFromOrigin(localRefPrefix = "refs/remotes/p4/", silent
originPrefix = "origin/p4/"
- for line in read_pipe_lines("git rev-parse --symbolic --remotes", shell=True):
+ for line in read_pipe_lines(["git", "rev-parse", "--symbolic", "--remotes"]):
line = line.strip()
if (not line.startswith(originPrefix)) or line.endswith("HEAD"):
continue
@@ -1062,8 +1054,7 @@ def createOrUpdateBranchesFromOrigin(localRefPrefix = "refs/remotes/p4/", silent
remoteHead, ','.join(settings['depot-paths'])))
if update:
- system("git update-ref %s %s" % (remoteHead, originHead),
- shell=True)
+ system(["git", "update-ref", remoteHead, originHead])
def originP4BranchesExist():
return gitBranchExists("origin") or gitBranchExists("origin/p4") or gitBranchExists("origin/p4/master")
@@ -1177,7 +1168,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", shell=True)
+ specList = p4CmdList(["client", "-o"])
if len(specList) != 1:
die('Output from "client -o" is %d lines, expecting 1' %
len(specList))
@@ -1206,7 +1197,7 @@ def getClientSpec():
def getClientRoot():
"""Grab the client directory."""
- output = p4CmdList("client -o", shell=True)
+ output = p4CmdList(["client", "-o"])
if len(output) != 1:
die('Output from "client -o" is %d lines, expecting 1' % len(output))
@@ -1461,7 +1452,7 @@ def p4UserId(self):
if self.myP4UserId:
return self.myP4UserId
- results = p4CmdList("user -o", shell=True)
+ results = p4CmdList(["user", "-o"])
for r in results:
if 'User' in r:
self.myP4UserId = r['User']
@@ -1486,7 +1477,7 @@ def getUserMapFromPerforceServer(self):
self.users = {}
self.emails = {}
- for output in p4CmdList("users", shell=True):
+ for output in p4CmdList(["users"]):
if "User" not in output:
continue
self.users[output["User"]] = output["FullName"] + " <" + output["Email"] + ">"
@@ -1684,7 +1675,7 @@ def __init__(self):
die("Large file system not supported for git-p4 submit command. Please remove it from config.")
def check(self):
- if len(p4CmdList("opened ...", shell=True)) > 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):
@@ -1788,7 +1779,7 @@ def lastP4Changelist(self):
# 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", shell=True) # find the current client
+ results = p4CmdList(["client", "-o"]) # find the current client
client = None
for r in results:
if 'Client' in r:
@@ -1804,7 +1795,7 @@ def lastP4Changelist(self):
def modifyChangelistUser(self, changelist, newUser):
# fixup the user field of a changelist after it has been submitted.
- changes = p4CmdList("change -o %s" % changelist, shell=True)
+ changes = p4CmdList(["change", "-o", changelist])
if len(changes) != 1:
die("Bad output from p4 change modifying %s to user %s" %
(changelist, newUser))
@@ -1815,7 +1806,7 @@ def modifyChangelistUser(self, changelist, newUser):
# p4 does not understand format version 3 and above
input = marshal.dumps(c, 2)
- result = p4CmdList("change -f -i", stdin=input, shell=True)
+ result = p4CmdList(["change", "-f", "-i"], stdin=input)
for r in result:
if 'code' in r:
if r['code'] == 'error':
@@ -1921,7 +1912,7 @@ def edit_template(self, template_file):
if "P4EDITOR" in os.environ and (os.environ.get("P4EDITOR") != ""):
editor = os.environ.get("P4EDITOR")
else:
- editor = read_pipe("git var GIT_EDITOR", shell=True).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
@@ -1980,8 +1971,7 @@ def applyCommit(self, id):
(p4User, gitEmail) = self.p4UserForCommit(id)
diff = read_pipe_lines(
- "git diff-tree -r %s \"%s^\" \"%s\"" % (self.diffOpts, id, id),
- shell=True)
+ ["git", "diff-tree", "-r"] + self.diffOpts + ["{}^".format(id), id])
filesToAdd = set()
filesToChangeType = set()
filesToDelete = set()
@@ -2467,17 +2457,17 @@ def run(self, args):
#
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
@@ -2485,12 +2475,12 @@ def run(self, args):
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):
@@ -3436,12 +3426,9 @@ def getBranchMapping(self):
lostAndFoundBranches = set()
user = gitConfig("git-p4.branchUser")
- if len(user) > 0:
- command = "branches -u %s" % user
- else:
- command = "branches"
- for info in p4CmdList(command, shell=True):
+ 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:
@@ -3532,9 +3519,8 @@ def gitCommitByP4Change(self, ref, change):
while True:
if self.verbose:
print("trying: earliest %s latest %s" % (earliestCommit, latestCommit))
- next = read_pipe(
- "git rev-list --bisect %s %s" % (latestCommit, earliestCommit),
- shell=True).strip()
+ next = read_pipe(["git", "rev-list", "--bisect",
+ latestCommit, earliestCommit]).strip()
if len(next) == 0:
if self.verbose:
print("argh")
@@ -3689,7 +3675,7 @@ def sync_origin_only(self):
if self.hasOrigin:
if not self.silent:
print('Syncing with origin first, using "git fetch origin"')
- system("git fetch origin", shell=True)
+ 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))
@@ -3856,8 +3842,8 @@ def run(self, args):
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, shell=True)
- system("git branch -D p4", shell=True)
+ 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:
@@ -4060,7 +4046,7 @@ def run(self, args):
# Cleanup temporary branches created during import
if self.tempBranches != []:
for branch in self.tempBranches:
- read_pipe("git update-ref -d %s" % branch, shell=True)
+ 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
@@ -4092,7 +4078,7 @@ def run(self, args):
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 --", shell=True)) > 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()
@@ -4103,10 +4089,10 @@ def rebase(self):
upstream = re.sub("~[0-9]+$", "", upstream)
print("Rebasing the current branch onto %s" % upstream)
- oldHead = read_pipe("git rev-parse HEAD", shell=True).strip()
- system("git rebase %s" % upstream, shell=True)
- system("git diff-tree --stat --summary -M %s HEAD --" % oldHead,
- shell=True)
+ 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):
@@ -4183,7 +4169,7 @@ def run(self, args):
# auto-set this variable if invoked with --use-client-spec
if self.useClientSpec_from_options:
- system("git config --bool git-p4.useclientspec true", shell=True)
+ system(["git", "config", "--bool", "git-p4.useclientspec", "true"])
return True
@@ -4314,10 +4300,7 @@ def run(self, args):
if originP4BranchesExist():
createOrUpdateBranchesFromOrigin()
- cmdline = "git rev-parse --symbolic "
- cmdline += " --remotes"
-
- for line in read_pipe_lines(cmdline, shell=True):
+ for line in read_pipe_lines(["git", "rev-parse", "--symbolic", "--remotes"]):
line = line.strip()
if not line.startswith('p4/') or line == "p4/HEAD":
@@ -4402,11 +4385,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", shell=True).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", shell=True).strip()
+ cdup = read_pipe(["git", "rev-parse", "--show-cdup"]).strip()
if len(cdup) > 0:
chdir(cdup);
--
2.34.1
next prev parent reply other threads:[~2022-01-06 21:41 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-01-06 21:40 [PATCH v2 0/3] git-p4: Rationalise command construction Joel Holdsworth
2022-01-06 21:40 ` [PATCH v2 1/3] git-p4: don't select shell mode using the type of the command argument Joel Holdsworth
2022-01-06 21:40 ` Joel Holdsworth [this message]
2022-01-06 21:40 ` [PATCH v2 3/3] git-p4: don't print shell commands as python lists Joel Holdsworth
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220106214035.90725-3-jholdsworth@nvidia.com \
--to=jholdsworth@nvidia.com \
--cc=andrew@adoakley.name \
--cc=dendy.ua@gmail.com \
--cc=dorgonman@hotmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=joachim.kuebart@gmail.com \
--cc=johannes.schindelin@gmx.de \
--cc=luke@diamand.org \
--cc=seraphire@gmail.com \
--cc=sunshine@sunshineco.com \
--cc=tzadik.vanderhoof@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).