git-p4: pass command arguments as lists instead of using shell
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> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
3d8a3038bc
commit
8a470599f3
105
git-p4.py
105
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 @@ class P4UserMap:
|
||||
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 @@ class P4UserMap:
|
||||
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 @@ class P4Submit(Command, P4UserMap):
|
||||
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 @@ class P4Submit(Command, P4UserMap):
|
||||
# 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 @@ class P4Submit(Command, P4UserMap):
|
||||
|
||||
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 @@ class P4Submit(Command, P4UserMap):
|
||||
# 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 @@ class P4Submit(Command, P4UserMap):
|
||||
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 @@ class P4Submit(Command, P4UserMap):
|
||||
(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 @@ class P4Submit(Command, P4UserMap):
|
||||
#
|
||||
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 @@ class P4Submit(Command, P4UserMap):
|
||||
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 @@ class P4Sync(Command, P4UserMap):
|
||||
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 @@ class P4Sync(Command, P4UserMap):
|
||||
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 @@ class P4Sync(Command, P4UserMap):
|
||||
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 @@ class P4Sync(Command, P4UserMap):
|
||||
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 @@ class P4Sync(Command, P4UserMap):
|
||||
# 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 @@ class P4Rebase(Command):
|
||||
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 @@ class P4Rebase(Command):
|
||||
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 @@ class P4Clone(P4Sync):
|
||||
|
||||
# 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 @@ class P4Branches(Command):
|
||||
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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user