Browse Source

Merge branch 'pw/p4-update'

* pw/p4-update:
  git-p4: handle files with shell metacharacters
  git-p4: keyword flattening fixes
  git-p4: stop ignoring apple filetype
  git-p4: recognize all p4 filetypes
  git-p4: handle utf16 filetype properly
  git-p4 tests: refactor and cleanup
maint
Junio C Hamano 13 years ago
parent
commit
5a4fcc28e1
  1. 281
      contrib/fast-import/git-p4
  2. 74
      t/lib-git-p4.sh
  3. 232
      t/t9800-git-p4.sh
  4. 233
      t/t9801-git-p4-branch.sh
  5. 108
      t/t9802-git-p4-filetype.sh
  6. 64
      t/t9803-git-shell-metachars.sh

281
contrib/fast-import/git-p4

@ -22,35 +22,38 @@ def p4_build_cmd(cmd):
location. It means that hooking into the environment, or other configuration location. It means that hooking into the environment, or other configuration
can be done more easily. can be done more easily.
""" """
real_cmd = "%s " % "p4" real_cmd = ["p4"]


user = gitConfig("git-p4.user") user = gitConfig("git-p4.user")
if len(user) > 0: if len(user) > 0:
real_cmd += "-u %s " % user real_cmd += ["-u",user]


password = gitConfig("git-p4.password") password = gitConfig("git-p4.password")
if len(password) > 0: if len(password) > 0:
real_cmd += "-P %s " % password real_cmd += ["-P", password]


port = gitConfig("git-p4.port") port = gitConfig("git-p4.port")
if len(port) > 0: if len(port) > 0:
real_cmd += "-p %s " % port real_cmd += ["-p", port]


host = gitConfig("git-p4.host") host = gitConfig("git-p4.host")
if len(host) > 0: if len(host) > 0:
real_cmd += "-h %s " % host real_cmd += ["-h", host]


client = gitConfig("git-p4.client") client = gitConfig("git-p4.client")
if len(client) > 0: if len(client) > 0:
real_cmd += "-c %s " % client real_cmd += ["-c", client]


real_cmd += "%s" % (cmd)
if verbose: if isinstance(cmd,basestring):
print real_cmd real_cmd = ' '.join(real_cmd) + ' ' + cmd
else:
real_cmd += cmd
return real_cmd return real_cmd


def chdir(dir): def chdir(dir):
if os.name == 'nt': # P4 uses the PWD environment variable rather than getcwd(). Since we're
# not using the shell, we have to set it ourselves.
os.environ['PWD']=dir os.environ['PWD']=dir
os.chdir(dir) os.chdir(dir)


@ -61,29 +64,34 @@ def die(msg):
sys.stderr.write(msg + "\n") sys.stderr.write(msg + "\n")
sys.exit(1) sys.exit(1)


def write_pipe(c, str): def write_pipe(c, stdin):
if verbose: if verbose:
sys.stderr.write('Writing pipe: %s\n' % c) sys.stderr.write('Writing pipe: %s\n' % str(c))


pipe = os.popen(c, 'w') expand = isinstance(c,basestring)
val = pipe.write(str) p = subprocess.Popen(c, stdin=subprocess.PIPE, shell=expand)
if pipe.close(): pipe = p.stdin
die('Command failed: %s' % c) val = pipe.write(stdin)
pipe.close()
if p.wait():
die('Command failed: %s' % str(c))


return val return val


def p4_write_pipe(c, str): def p4_write_pipe(c, stdin):
real_cmd = p4_build_cmd(c) real_cmd = p4_build_cmd(c)
return write_pipe(real_cmd, str) return write_pipe(real_cmd, stdin)


def read_pipe(c, ignore_error=False): def read_pipe(c, ignore_error=False):
if verbose: if verbose:
sys.stderr.write('Reading pipe: %s\n' % c) sys.stderr.write('Reading pipe: %s\n' % str(c))


pipe = os.popen(c, 'rb') expand = isinstance(c,basestring)
p = subprocess.Popen(c, stdout=subprocess.PIPE, shell=expand)
pipe = p.stdout
val = pipe.read() val = pipe.read()
if pipe.close() and not ignore_error: if p.wait() and not ignore_error:
die('Command failed: %s' % c) die('Command failed: %s' % str(c))


return val return val


@ -93,12 +101,14 @@ def p4_read_pipe(c, ignore_error=False):


def read_pipe_lines(c): def read_pipe_lines(c):
if verbose: if verbose:
sys.stderr.write('Reading pipe: %s\n' % c) sys.stderr.write('Reading pipe: %s\n' % str(c))
## todo: check return status
pipe = os.popen(c, 'rb') expand = isinstance(c, basestring)
p = subprocess.Popen(c, stdout=subprocess.PIPE, shell=expand)
pipe = p.stdout
val = pipe.readlines() val = pipe.readlines()
if pipe.close(): if pipe.close() or p.wait():
die('Command failed: %s' % c) die('Command failed: %s' % str(c))


return val return val


@ -108,23 +118,73 @@ def p4_read_pipe_lines(c):
return read_pipe_lines(real_cmd) return read_pipe_lines(real_cmd)


def system(cmd): def system(cmd):
expand = isinstance(cmd,basestring)
if verbose: if verbose:
sys.stderr.write("executing %s\n" % cmd) sys.stderr.write("executing %s\n" % str(cmd))
if os.system(cmd) != 0: subprocess.check_call(cmd, shell=expand)
die("command failed: %s" % cmd)


def p4_system(cmd): def p4_system(cmd):
"""Specifically invoke p4 as the system command. """ """Specifically invoke p4 as the system command. """
real_cmd = p4_build_cmd(cmd) real_cmd = p4_build_cmd(cmd)
return system(real_cmd) expand = isinstance(real_cmd, basestring)
subprocess.check_call(real_cmd, shell=expand)

def p4_integrate(src, dest):
p4_system(["integrate", "-Dt", src, dest])

def p4_sync(path):
p4_system(["sync", path])

def p4_add(f):
p4_system(["add", f])


def isP4Exec(kind): def p4_delete(f):
"""Determine if a Perforce 'kind' should have execute permission p4_system(["delete", f])

def p4_edit(f):
p4_system(["edit", f])

def p4_revert(f):
p4_system(["revert", f])

def p4_reopen(type, file):
p4_system(["reopen", "-t", type, file])

#
# 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):

p4_filetypes_historical = {
"ctempobj": "binary+Sw",
"ctext": "text+C",
"cxtext": "text+Cx",
"ktext": "text+k",
"kxtext": "text+kx",
"ltext": "text+F",
"tempobj": "binary+FSw",
"ubinary": "binary+F",
"uresource": "resource+F",
"uxbinary": "binary+Fx",
"xbinary": "binary+x",
"xltext": "text+Fx",
"xtempobj": "binary+Swx",
"xtext": "text+x",
"xunicode": "unicode+x",
"xutf16": "utf16+x",
}
if p4type in p4_filetypes_historical:
p4type = p4_filetypes_historical[p4type]
mods = ""
s = p4type.split("+")
base = s[0]
mods = ""
if len(s) > 1:
mods = s[1]
return (base, mods)


'p4 help filetypes' gives a list of the types. If it starts with 'x',
or x follows one of a few letters. Otherwise, if there is an 'x' after
a plus sign, it is also executable"""
return (re.search(r"(^[cku]?x)|\+.*x", kind) != None)


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
@ -139,12 +199,12 @@ def setP4ExecBit(file, mode):
if p4Type[-1] == "+": if p4Type[-1] == "+":
p4Type = p4Type[0:-1] p4Type = p4Type[0:-1]


p4_system("reopen -t %s %s" % (p4Type, file)) p4_reopen(p4Type, file)


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 %s" % file) result = p4_read_pipe(["opened", file])
match = re.match(".*\((.+)\)\r?$", result) match = re.match(".*\((.+)\)\r?$", result)
if match: if match:
return match.group(1) return match.group(1)
@ -200,9 +260,17 @@ def isModeExecChanged(src_mode, dst_mode):
return isModeExec(src_mode) != isModeExec(dst_mode) return isModeExec(src_mode) != isModeExec(dst_mode)


def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None): def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None):
cmd = p4_build_cmd("-G %s" % (cmd))
if isinstance(cmd,basestring):
cmd = "-G " + cmd
expand = True
else:
cmd = ["-G"] + cmd
expand = False

cmd = p4_build_cmd(cmd)
if verbose: if verbose:
sys.stderr.write("Opening pipe: %s\n" % cmd) sys.stderr.write("Opening pipe: %s\n" % str(cmd))


# Use a temporary file to avoid deadlocks without # Use a temporary file to avoid deadlocks without
# subprocess.communicate(), which would put another copy # subprocess.communicate(), which would put another copy
@ -210,11 +278,16 @@ def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None):
stdin_file = None stdin_file = None
if stdin is not None: if stdin is not None:
stdin_file = tempfile.TemporaryFile(prefix='p4-stdin', mode=stdin_mode) stdin_file = tempfile.TemporaryFile(prefix='p4-stdin', mode=stdin_mode)
if isinstance(stdin,basestring):
stdin_file.write(stdin) stdin_file.write(stdin)
else:
for i in stdin:
stdin_file.write(i + '\n')
stdin_file.flush() stdin_file.flush()
stdin_file.seek(0) stdin_file.seek(0)


p4 = subprocess.Popen(cmd, shell=True, p4 = subprocess.Popen(cmd,
shell=expand,
stdin=stdin_file, stdin=stdin_file,
stdout=subprocess.PIPE) stdout=subprocess.PIPE)


@ -247,7 +320,7 @@ def p4Where(depotPath):
if not depotPath.endswith("/"): if not depotPath.endswith("/"):
depotPath += "/" depotPath += "/"
depotPath = depotPath + "..." depotPath = depotPath + "..."
outputList = p4CmdList("where %s" % depotPath) outputList = p4CmdList(["where", depotPath])
output = None output = None
for entry in outputList: for entry in outputList:
if "depotFile" in entry: if "depotFile" in entry:
@ -449,8 +522,10 @@ def originP4BranchesExist():


def p4ChangesForPaths(depotPaths, changeRange): def p4ChangesForPaths(depotPaths, changeRange):
assert depotPaths assert depotPaths
output = p4_read_pipe_lines("changes " + ' '.join (["%s...%s" % (p, changeRange) cmd = ['changes']
for p in depotPaths])) for p in depotPaths:
cmd += ["%s...%s" % (p, changeRange)]
output = p4_read_pipe_lines(cmd)


changes = {} changes = {}
for line in output: for line in output:
@ -533,7 +608,7 @@ class P4Debug(Command):


def run(self, args): def run(self, args):
j = 0 j = 0
for output in p4CmdList(" ".join(args)): for output in p4CmdList(args):
print 'Element: %d' % j print 'Element: %d' % j
j += 1 j += 1
print output print output
@ -687,7 +762,7 @@ class P4Submit(Command, P4UserMap):
break break
if not client: if not client:
die("could not get client spec") die("could not get client spec")
results = p4CmdList("changes -c %s -m 1" % client) results = p4CmdList(["changes", "-c", client, "-m", "1"])
for r in results: for r in results:
if r.has_key('change'): if r.has_key('change'):
return r['change'] return r['change']
@ -750,7 +825,7 @@ class P4Submit(Command, P4UserMap):
# remove lines in the Files section that show changes to files outside the depot path we're committing into # remove lines in the Files section that show changes to files outside the depot path we're committing into
template = "" template = ""
inFilesSection = False inFilesSection = False
for line in p4_read_pipe_lines("change -o"): for line in p4_read_pipe_lines(['change', '-o']):
if line.endswith("\r\n"): if line.endswith("\r\n"):
line = line[:-2] + "\n" line = line[:-2] + "\n"
if inFilesSection: if inFilesSection:
@ -807,7 +882,7 @@ class P4Submit(Command, P4UserMap):
modifier = diff['status'] modifier = diff['status']
path = diff['src'] path = diff['src']
if modifier == "M": if modifier == "M":
p4_system("edit \"%s\"" % path) p4_edit(path)
if isModeExecChanged(diff['src_mode'], diff['dst_mode']): if isModeExecChanged(diff['src_mode'], diff['dst_mode']):
filesToChangeExecBit[path] = diff['dst_mode'] filesToChangeExecBit[path] = diff['dst_mode']
editedFiles.add(path) editedFiles.add(path)
@ -822,21 +897,21 @@ class P4Submit(Command, P4UserMap):
filesToAdd.remove(path) filesToAdd.remove(path)
elif modifier == "C": elif modifier == "C":
src, dest = diff['src'], diff['dst'] src, dest = diff['src'], diff['dst']
p4_system("integrate -Dt \"%s\" \"%s\"" % (src, dest)) p4_integrate(src, dest)
if diff['src_sha1'] != diff['dst_sha1']: if diff['src_sha1'] != diff['dst_sha1']:
p4_system("edit \"%s\"" % (dest)) p4_edit(dest)
if isModeExecChanged(diff['src_mode'], diff['dst_mode']): if isModeExecChanged(diff['src_mode'], diff['dst_mode']):
p4_system("edit \"%s\"" % (dest)) p4_edit(dest)
filesToChangeExecBit[dest] = diff['dst_mode'] filesToChangeExecBit[dest] = diff['dst_mode']
os.unlink(dest) os.unlink(dest)
editedFiles.add(dest) editedFiles.add(dest)
elif modifier == "R": elif modifier == "R":
src, dest = diff['src'], diff['dst'] src, dest = diff['src'], diff['dst']
p4_system("integrate -Dt \"%s\" \"%s\"" % (src, dest)) p4_integrate(src, dest)
if diff['src_sha1'] != diff['dst_sha1']: if diff['src_sha1'] != diff['dst_sha1']:
p4_system("edit \"%s\"" % (dest)) p4_edit(dest)
if isModeExecChanged(diff['src_mode'], diff['dst_mode']): if isModeExecChanged(diff['src_mode'], diff['dst_mode']):
p4_system("edit \"%s\"" % (dest)) p4_edit(dest)
filesToChangeExecBit[dest] = diff['dst_mode'] filesToChangeExecBit[dest] = diff['dst_mode']
os.unlink(dest) os.unlink(dest)
editedFiles.add(dest) editedFiles.add(dest)
@ -859,9 +934,9 @@ class P4Submit(Command, P4UserMap):
if response == "s": if response == "s":
print "Skipping! Good luck with the next patches..." print "Skipping! Good luck with the next patches..."
for f in editedFiles: for f in editedFiles:
p4_system("revert \"%s\"" % f); p4_revert(f)
for f in filesToAdd: for f in filesToAdd:
system("rm %s" %f) os.remove(f)
return return
elif response == "a": elif response == "a":
os.system(applyPatchCmd) os.system(applyPatchCmd)
@ -882,10 +957,10 @@ class P4Submit(Command, P4UserMap):
system(applyPatchCmd) system(applyPatchCmd)


for f in filesToAdd: for f in filesToAdd:
p4_system("add \"%s\"" % f) p4_add(f)
for f in filesToDelete: for f in filesToDelete:
p4_system("revert \"%s\"" % f) p4_revert(f)
p4_system("delete \"%s\"" % f) p4_delete(f)


# Set/clear executable bits # Set/clear executable bits
for f in filesToChangeExecBit.keys(): for f in filesToChangeExecBit.keys():
@ -907,7 +982,7 @@ class P4Submit(Command, P4UserMap):
del(os.environ["P4DIFF"]) del(os.environ["P4DIFF"])
diff = "" diff = ""
for editedFile in editedFiles: for editedFile in editedFiles:
diff += p4_read_pipe("diff -du %r" % editedFile) diff += p4_read_pipe(['diff', '-du', editedFile])


newdiff = "" newdiff = ""
for newFile in filesToAdd: for newFile in filesToAdd:
@ -959,7 +1034,7 @@ class P4Submit(Command, P4UserMap):
submitTemplate = message[:message.index(separatorLine)] submitTemplate = message[:message.index(separatorLine)]
if self.isWindows: if self.isWindows:
submitTemplate = submitTemplate.replace("\r\n", "\n") submitTemplate = submitTemplate.replace("\r\n", "\n")
p4_write_pipe("submit -i", submitTemplate) p4_write_pipe(['submit', '-i'], submitTemplate)


if self.preserveUser: if self.preserveUser:
if p4User: if p4User:
@ -970,10 +1045,10 @@ class P4Submit(Command, P4UserMap):


else: else:
for f in editedFiles: for f in editedFiles:
p4_system("revert \"%s\"" % f); p4_revert(f)
for f in filesToAdd: for f in filesToAdd:
p4_system("revert \"%s\"" % f); p4_revert(f)
system("rm %s" %f) os.remove(f)


os.remove(fileName) os.remove(fileName)
else: else:
@ -1026,8 +1101,7 @@ class P4Submit(Command, P4UserMap):


chdir(self.clientPath) chdir(self.clientPath)
print "Synchronizing p4 checkout..." print "Synchronizing p4 checkout..."
p4_system("sync ...") p4_sync("...")

self.check() self.check()


commits = [] commits = []
@ -1219,38 +1293,53 @@ class P4Sync(Command, P4UserMap):
# - helper for streamP4Files # - helper for streamP4Files


def streamOneP4File(self, file, contents): def streamOneP4File(self, file, contents):
if file["type"] == "apple":
print "\nfile %s is a strange apple file that forks. Ignoring" % \
file['depotFile']
return

relPath = self.stripRepoPath(file['depotFile'], self.branchPrefixes) relPath = self.stripRepoPath(file['depotFile'], self.branchPrefixes)
relPath = self.wildcard_decode(relPath) relPath = self.wildcard_decode(relPath)
if verbose: if verbose:
sys.stderr.write("%s\n" % relPath) sys.stderr.write("%s\n" % relPath)


mode = "644" (type_base, type_mods) = split_p4_type(file["type"])
if isP4Exec(file["type"]):
mode = "755" git_mode = "100644"
elif file["type"] == "symlink": if "x" in type_mods:
mode = "120000" git_mode = "100755"
# p4 print on a symlink contains "target\n", so strip it off if type_base == "symlink":
git_mode = "120000"
# p4 print on a symlink contains "target\n"; remove the newline
data = ''.join(contents) data = ''.join(contents)
contents = [data[:-1]] contents = [data[:-1]]


if self.isWindows and file["type"].endswith("text"): if type_base == "utf16":
# p4 delivers different text in the python output to -G
# than it does when using "print -o", or normal p4 client
# operations. utf16 is converted to ascii or utf8, perhaps.
# But ascii text saved as -t utf16 is completely mangled.
# Invoke print -o to get the real contents.
text = p4_read_pipe(['print', '-q', '-o', '-', file['depotFile']])
contents = [ text ]

# Perhaps windows wants unicode, utf16 newlines translated too;
# but this is not doing it.
if self.isWindows and type_base == "text":
mangled = [] mangled = []
for data in contents: for data in contents:
data = data.replace("\r\n", "\n") data = data.replace("\r\n", "\n")
mangled.append(data) mangled.append(data)
contents = mangled contents = mangled


if file['type'] in ('text+ko', 'unicode+ko', 'binary+ko'): # Note that we do not try to de-mangle keywords on utf16 files,
contents = map(lambda text: re.sub(r'(?i)\$(Id|Header):[^$]*\$',r'$\1$', text), contents) # even though in theory somebody may want that.
elif file['type'] in ('text+k', 'ktext', 'kxtext', 'unicode+k', 'binary+k'): if type_base in ("text", "unicode", "binary"):
contents = map(lambda text: re.sub(r'\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$\n]*\$',r'$\1$', text), contents) if "ko" in type_mods:
text = ''.join(contents)
text = re.sub(r'\$(Id|Header):[^$]*\$', r'$\1$', text)
contents = [ text ]
elif "k" in type_mods:
text = ''.join(contents)
text = re.sub(r'\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\$', r'$\1$', text)
contents = [ text ]


self.gitStream.write("M %s inline %s\n" % (mode, relPath)) self.gitStream.write("M %s inline %s\n" % (git_mode, relPath))


# total length... # total length...
length = 0 length = 0
@ -1322,9 +1411,10 @@ class P4Sync(Command, P4UserMap):
def streamP4FilesCbSelf(entry): def streamP4FilesCbSelf(entry):
self.streamP4FilesCb(entry) self.streamP4FilesCb(entry)


p4CmdList("-x - print", fileArgs = ['%s#%s' % (f['path'], f['rev']) for f in filesToRead]
'\n'.join(['%s#%s' % (f['path'], f['rev'])
for f in filesToRead]), p4CmdList(["-x", "-", "print"],
stdin=fileArgs,
cb=streamP4FilesCbSelf) cb=streamP4FilesCbSelf)


# do the last chunk # do the last chunk
@ -1386,8 +1476,8 @@ class P4Sync(Command, P4UserMap):
if self.verbose: if self.verbose:
print "Change %s is labelled %s" % (change, labelDetails) print "Change %s is labelled %s" % (change, labelDetails)


files = p4CmdList("files " + ' '.join (["%s...@%s" % (p, change) files = p4CmdList(["files"] + ["%s...@%s" % (p, change)
for p in branchPrefixes])) for p in branchPrefixes])


if len(files) == len(labelRevisions): if len(files) == len(labelRevisions):


@ -1435,9 +1525,9 @@ class P4Sync(Command, P4UserMap):
newestChange = 0 newestChange = 0
if self.verbose: if self.verbose:
print "Querying files for label %s" % label print "Querying files for label %s" % label
for file in p4CmdList("files " for file in p4CmdList(["files"] +
+ ' '.join (["%s...@%s" % (p, label) ["%s...@%s" % (p, label)
for p in self.depotPaths])): for p in self.depotPaths]):
revisions[file["depotFile"]] = file["rev"] revisions[file["depotFile"]] = file["rev"]
change = int(file["change"]) change = int(file["change"])
if change > newestChange: if change > newestChange:
@ -1692,10 +1782,9 @@ class P4Sync(Command, P4UserMap):
newestRevision = 0 newestRevision = 0


fileCnt = 0 fileCnt = 0
for info in p4CmdList("files " fileArgs = ["%s...%s" % (p,revision) for p in self.depotPaths]
+ ' '.join(["%s...%s"
% (p, revision) for info in p4CmdList(["files"] + fileArgs):
for p in self.depotPaths])):


if 'code' in info and info['code'] == 'error': if 'code' in info and info['code'] == 'error':
sys.stderr.write("p4 returned an error: %s\n" sys.stderr.write("p4 returned an error: %s\n"

74
t/lib-git-p4.sh

@ -0,0 +1,74 @@
#
# Library code for git-p4 tests
#

. ./test-lib.sh

if ! test_have_prereq PYTHON; then
skip_all='skipping git-p4 tests; python not available'
test_done
fi
( p4 -h && p4d -h ) >/dev/null 2>&1 || {
skip_all='skipping git-p4 tests; no p4 or p4d'
test_done
}

GITP4="$GIT_BUILD_DIR/contrib/fast-import/git-p4"

# Try to pick a unique port: guess a large number, then hope
# no more than one of each test is running.
#
# This does not handle the case where somebody else is running the
# same tests and has chosen the same ports.
testid=${this_test#t}
git_p4_test_start=9800
P4DPORT=$((10669 + ($testid - $git_p4_test_start)))

export P4PORT=localhost:$P4DPORT
export P4CLIENT=client

db="$TRASH_DIRECTORY/db"
cli="$TRASH_DIRECTORY/cli"
git="$TRASH_DIRECTORY/git"
pidfile="$TRASH_DIRECTORY/p4d.pid"

start_p4d() {
mkdir -p "$db" "$cli" "$git" &&
(
p4d -q -r "$db" -p $P4DPORT &
echo $! >"$pidfile"
) &&
for i in 1 2 3 4 5 ; do
p4 info >/dev/null 2>&1 && break || true &&
echo waiting for p4d to start &&
sleep 1
done &&
# complain if it never started
p4 info >/dev/null &&
(
cd "$cli" &&
p4 client -i <<-EOF
Client: client
Description: client
Root: $cli
View: //depot/... //client/...
EOF
)
}

kill_p4d() {
pid=$(cat "$pidfile")
# it had better exist for the first kill
kill $pid &&
for i in 1 2 3 4 5 ; do
kill $pid >/dev/null 2>&1 || break
sleep 1
done &&
# complain if it would not die
test_must_fail kill $pid >/dev/null 2>&1 &&
rm -rf "$db" "$cli" "$pidfile"
}

cleanup_git() {
rm -rf "$git"
}

232
t/t9800-git-p4.sh

@ -2,76 +2,51 @@


test_description='git-p4 tests' test_description='git-p4 tests'


. ./test-lib.sh . ./lib-git-p4.sh


( p4 -h && p4d -h ) >/dev/null 2>&1 || { test_expect_success 'start p4d' '
skip_all='skipping git-p4 tests; no p4 or p4d' start_p4d
test_done
}

GITP4=$GIT_BUILD_DIR/contrib/fast-import/git-p4
P4DPORT=10669

export P4PORT=localhost:$P4DPORT

db="$TRASH_DIRECTORY/db"
cli="$TRASH_DIRECTORY/cli"
git="$TRASH_DIRECTORY/git"

test_debug 'echo p4d -q -d -r "$db" -p $P4DPORT'
test_expect_success setup '
mkdir -p "$db" &&
p4d -q -d -r "$db" -p $P4DPORT &&
mkdir -p "$cli" &&
mkdir -p "$git" &&
export P4PORT=localhost:$P4DPORT
' '


test_expect_success 'add p4 files' ' test_expect_success 'add p4 files' '
(
cd "$cli" && cd "$cli" &&
p4 client -i <<-EOF &&
Client: client
Description: client
Root: $cli
View: //depot/... //client/...
EOF
export P4CLIENT=client &&
echo file1 >file1 && echo file1 >file1 &&
p4 add file1 && p4 add file1 &&
p4 submit -d "file1" && p4 submit -d "file1" &&
echo file2 >file2 && echo file2 >file2 &&
p4 add file2 && p4 add file2 &&
p4 submit -d "file2" && p4 submit -d "file2"
cd "$TRASH_DIRECTORY" )
' '


cleanup_git() {
cd "$TRASH_DIRECTORY" &&
rm -rf "$git" &&
mkdir "$git"
}

test_expect_success 'basic git-p4 clone' ' test_expect_success 'basic git-p4 clone' '
"$GITP4" clone --dest="$git" //depot && "$GITP4" clone --dest="$git" //depot &&
test_when_finished cleanup_git && test_when_finished cleanup_git &&
(
cd "$git" && cd "$git" &&
git log --oneline >lines && git log --oneline >lines &&
test_line_count = 1 lines test_line_count = 1 lines
)
' '


test_expect_success 'git-p4 clone @all' ' test_expect_success 'git-p4 clone @all' '
"$GITP4" clone --dest="$git" //depot@all && "$GITP4" clone --dest="$git" //depot@all &&
test_when_finished cleanup_git && test_when_finished cleanup_git &&
(
cd "$git" && cd "$git" &&
git log --oneline >lines && git log --oneline >lines &&
test_line_count = 2 lines test_line_count = 2 lines
)
' '


test_expect_success 'git-p4 sync uninitialized repo' ' test_expect_success 'git-p4 sync uninitialized repo' '
test_create_repo "$git" && test_create_repo "$git" &&
test_when_finished cleanup_git && test_when_finished cleanup_git &&
(
cd "$git" && cd "$git" &&
test_must_fail "$GITP4" sync test_must_fail "$GITP4" sync
)
' '


# #
@ -81,17 +56,19 @@ test_expect_success 'git-p4 sync uninitialized repo' '
test_expect_success 'git-p4 sync new branch' ' test_expect_success 'git-p4 sync new branch' '
test_create_repo "$git" && test_create_repo "$git" &&
test_when_finished cleanup_git && test_when_finished cleanup_git &&
(
cd "$git" && cd "$git" &&
test_commit head && test_commit head &&
"$GITP4" sync --branch=refs/remotes/p4/depot //depot@all && "$GITP4" sync --branch=refs/remotes/p4/depot //depot@all &&
git log --oneline p4/depot >lines && git log --oneline p4/depot >lines &&
test_line_count = 2 lines test_line_count = 2 lines
)
' '


test_expect_success 'exit when p4 fails to produce marshaled output' ' test_expect_success 'exit when p4 fails to produce marshaled output' '
badp4dir="$TRASH_DIRECTORY/badp4dir" && badp4dir="$TRASH_DIRECTORY/badp4dir" &&
mkdir -p "$badp4dir" && mkdir "$badp4dir" &&
test_when_finished "rm -rf $badp4dir" && test_when_finished "rm \"$badp4dir/p4\" && rmdir \"$badp4dir\"" &&
cat >"$badp4dir"/p4 <<-EOF && cat >"$badp4dir"/p4 <<-EOF &&
#!$SHELL_PATH #!$SHELL_PATH
exit 1 exit 1
@ -103,6 +80,7 @@ test_expect_success 'exit when p4 fails to produce marshaled output' '
' '


test_expect_success 'add p4 files with wildcards in the names' ' test_expect_success 'add p4 files with wildcards in the names' '
(
cd "$cli" && cd "$cli" &&
echo file-wild-hash >file-wild#hash && echo file-wild-hash >file-wild#hash &&
echo file-wild-star >file-wild\*star && echo file-wild-star >file-wild\*star &&
@ -110,54 +88,53 @@ test_expect_success 'add p4 files with wildcards in the names' '
echo file-wild-percent >file-wild%percent && echo file-wild-percent >file-wild%percent &&
p4 add -f file-wild* && p4 add -f file-wild* &&
p4 submit -d "file wildcards" p4 submit -d "file wildcards"
)
' '


test_expect_success 'wildcard files git-p4 clone' ' test_expect_success 'wildcard files git-p4 clone' '
"$GITP4" clone --dest="$git" //depot && "$GITP4" clone --dest="$git" //depot &&
test_when_finished cleanup_git && test_when_finished cleanup_git &&
(
cd "$git" && cd "$git" &&
test -f file-wild#hash && test -f file-wild#hash &&
test -f file-wild\*star && test -f file-wild\*star &&
test -f file-wild@at && test -f file-wild@at &&
test -f file-wild%percent test -f file-wild%percent
)
' '


test_expect_success 'clone bare' ' test_expect_success 'clone bare' '
"$GITP4" clone --dest="$git" --bare //depot && "$GITP4" clone --dest="$git" --bare //depot &&
test_when_finished cleanup_git && test_when_finished cleanup_git &&
(
cd "$git" && cd "$git" &&
test ! -d .git && test ! -d .git &&
bare=`git config --get core.bare` && bare=`git config --get core.bare` &&
test "$bare" = true test "$bare" = true
)
' '


p4_add_user() { p4_add_user() {
name=$1 name=$1 fullname=$2 &&
fullname=$2 p4 user -f -i <<-EOF &&
p4 user -f -i <<EOF && User: $name
User: $name Email: $name@localhost
Email: $name@localhost FullName: $fullname
FullName: $fullname EOF
EOF
p4 passwd -P secret $name p4 passwd -P secret $name
} }


p4_grant_admin() { p4_grant_admin() {
name=$1 name=$1 &&
p4 protect -o |\ {
awk "{print}END{print \" admin user $name * //depot/...\"}" |\ p4 protect -o &&
p4 protect -i echo " admin user $name * //depot/..."
} | p4 protect -i
} }


p4_check_commit_author() { p4_check_commit_author() {
file=$1 file=$1 user=$2 &&
user=$2 p4 changes -m 1 //depot/$file | grep -q $user
if p4 changes -m 1 //depot/$file | grep $user > /dev/null ; then
return 0
else
echo "file $file not modified by user $user" 1>&2
return 1
fi
} }


make_change_by_user() { make_change_by_user() {
@ -174,15 +151,17 @@ test_expect_success 'preserve users' '
p4_grant_admin alice && p4_grant_admin alice &&
"$GITP4" clone --dest="$git" //depot && "$GITP4" clone --dest="$git" //depot &&
test_when_finished cleanup_git && test_when_finished cleanup_git &&
(
cd "$git" && cd "$git" &&
echo "username: a change by alice" >> file1 && echo "username: a change by alice" >>file1 &&
echo "username: a change by bob" >> file2 && echo "username: a change by bob" >>file2 &&
git commit --author "Alice <alice@localhost>" -m "a change by alice" file1 && git commit --author "Alice <alice@localhost>" -m "a change by alice" file1 &&
git commit --author "Bob <bob@localhost>" -m "a change by bob" file2 && git commit --author "Bob <bob@localhost>" -m "a change by bob" file2 &&
git config git-p4.skipSubmitEditCheck true && git config git-p4.skipSubmitEditCheck true &&
P4EDITOR=touch P4USER=alice P4PASSWD=secret "$GITP4" commit --preserve-user && P4EDITOR=touch P4USER=alice P4PASSWD=secret "$GITP4" commit --preserve-user &&
p4_check_commit_author file1 alice && p4_check_commit_author file1 alice &&
p4_check_commit_author file2 bob p4_check_commit_author file2 bob
)
' '


# Test username support, submitting as bob, who lacks admin rights. Should # Test username support, submitting as bob, who lacks admin rights. Should
@ -190,32 +169,37 @@ test_expect_success 'preserve users' '
test_expect_success 'refuse to preserve users without perms' ' test_expect_success 'refuse to preserve users without perms' '
"$GITP4" clone --dest="$git" //depot && "$GITP4" clone --dest="$git" //depot &&
test_when_finished cleanup_git && test_when_finished cleanup_git &&
(
cd "$git" && cd "$git" &&
git config git-p4.skipSubmitEditCheck true && git config git-p4.skipSubmitEditCheck true &&
echo "username-noperms: a change by alice" >> file1 && echo "username-noperms: a change by alice" >>file1 &&
git commit --author "Alice <alice@localhost>" -m "perms: a change by alice" file1 && git commit --author "Alice <alice@localhost>" -m "perms: a change by alice" file1 &&
! P4EDITOR=touch P4USER=bob P4PASSWD=secret "$GITP4" commit --preserve-user && P4EDITOR=touch P4USER=bob P4PASSWD=secret test_must_fail "$GITP4" commit --preserve-user &&
! git diff --exit-code HEAD..p4/master > /dev/null test_must_fail git diff --exit-code HEAD..p4/master
)
' '


# What happens with unknown author? Without allowMissingP4Users it should fail. # What happens with unknown author? Without allowMissingP4Users it should fail.
test_expect_success 'preserve user where author is unknown to p4' ' test_expect_success 'preserve user where author is unknown to p4' '
"$GITP4" clone --dest="$git" //depot && "$GITP4" clone --dest="$git" //depot &&
test_when_finished cleanup_git && test_when_finished cleanup_git &&
(
cd "$git" && cd "$git" &&
git config git-p4.skipSubmitEditCheck true && git config git-p4.skipSubmitEditCheck true &&
echo "username-bob: a change by bob" >> file1 && echo "username-bob: a change by bob" >>file1 &&
git commit --author "Bob <bob@localhost>" -m "preserve: a change by bob" file1 && git commit --author "Bob <bob@localhost>" -m "preserve: a change by bob" file1 &&
echo "username-unknown: a change by charlie" >> file1 && echo "username-unknown: a change by charlie" >>file1 &&
git commit --author "Charlie <charlie@localhost>" -m "preserve: a change by charlie" file1 && git commit --author "Charlie <charlie@localhost>" -m "preserve: a change by charlie" file1 &&
! P4EDITOR=touch P4USER=alice P4PASSWD=secret "$GITP4" commit --preserve-user && P4EDITOR=touch P4USER=alice P4PASSWD=secret test_must_fail "$GITP4" commit --preserve-user &&
! git diff --exit-code HEAD..p4/master > /dev/null && test_must_fail git diff --exit-code HEAD..p4/master &&

echo "$0: repeat with allowMissingP4Users enabled" && echo "$0: repeat with allowMissingP4Users enabled" &&
git config git-p4.allowMissingP4Users true && git config git-p4.allowMissingP4Users true &&
git config git-p4.preserveUser true && git config git-p4.preserveUser true &&
P4EDITOR=touch P4USER=alice P4PASSWD=secret "$GITP4" commit && P4EDITOR=touch P4USER=alice P4PASSWD=secret "$GITP4" commit &&
git diff --exit-code HEAD..p4/master > /dev/null && git diff --exit-code HEAD..p4/master &&
p4_check_commit_author file1 alice p4_check_commit_author file1 alice
)
' '


# If we're *not* using --preserve-user, git-p4 should warn if we're submitting # If we're *not* using --preserve-user, git-p4 should warn if we're submitting
@ -225,33 +209,35 @@ test_expect_success 'preserve user where author is unknown to p4' '
test_expect_success 'not preserving user with mixed authorship' ' test_expect_success 'not preserving user with mixed authorship' '
"$GITP4" clone --dest="$git" //depot && "$GITP4" clone --dest="$git" //depot &&
test_when_finished cleanup_git && test_when_finished cleanup_git &&
(
cd "$git" && cd "$git" &&
git config git-p4.skipSubmitEditCheck true && git config git-p4.skipSubmitEditCheck true &&
p4_add_user derek Derek && p4_add_user derek Derek &&


make_change_by_user usernamefile3 Derek derek@localhost && make_change_by_user usernamefile3 Derek derek@localhost &&
P4EDITOR=cat P4USER=alice P4PASSWD=secret "$GITP4" commit >actual && P4EDITOR=cat P4USER=alice P4PASSWD=secret "$GITP4" commit |\
grep "git author derek@localhost does not match" actual && grep "git author derek@localhost does not match" &&


make_change_by_user usernamefile3 Charlie charlie@localhost && make_change_by_user usernamefile3 Charlie charlie@localhost &&
P4EDITOR=cat P4USER=alice P4PASSWD=secret "$GITP4" commit >actual && P4EDITOR=cat P4USER=alice P4PASSWD=secret "$GITP4" commit |\
grep "git author charlie@localhost does not match" actual && grep "git author charlie@localhost does not match" &&


make_change_by_user usernamefile3 alice alice@localhost && make_change_by_user usernamefile3 alice alice@localhost &&
P4EDITOR=cat P4USER=alice P4PASSWD=secret "$GITP4" commit >actual && P4EDITOR=cat P4USER=alice P4PASSWD=secret "$GITP4" |\
! grep "git author.*does not match" actual && test_must_fail grep "git author.*does not match" &&


git config git-p4.skipUserNameCheck true && git config git-p4.skipUserNameCheck true &&
make_change_by_user usernamefile3 Charlie charlie@localhost && make_change_by_user usernamefile3 Charlie charlie@localhost &&
P4EDITOR=cat P4USER=alice P4PASSWD=secret "$GITP4" commit >actual && P4EDITOR=cat P4USER=alice P4PASSWD=secret "$GITP4" commit |\
! grep "git author.*does not match" actual && test_must_fail grep "git author.*does not match" &&


p4_check_commit_author usernamefile3 alice p4_check_commit_author usernamefile3 alice
)
' '


marshal_dump() { marshal_dump() {
what=$1 what=$1
python -c 'import marshal, sys; d = marshal.load(sys.stdin); print d["'$what'"]' "$PYTHON_PATH" -c 'import marshal, sys; d = marshal.load(sys.stdin); print d["'$what'"]'
} }


# Sleep a bit so that the top-most p4 change did not happen "now". Then # Sleep a bit so that the top-most p4 change did not happen "now". Then
@ -263,10 +249,12 @@ test_expect_success 'initial import time from top change time' '
sleep 3 && sleep 3 &&
"$GITP4" clone --dest="$git" //depot && "$GITP4" clone --dest="$git" //depot &&
test_when_finished cleanup_git && test_when_finished cleanup_git &&
(
cd "$git" && cd "$git" &&
gittime=$(git show -s --raw --pretty=format:%at HEAD) && gittime=$(git show -s --raw --pretty=format:%at HEAD) &&
echo $p4time $gittime && echo $p4time $gittime &&
test $p4time = $gittime test $p4time = $gittime
)
' '


# Rename a file and confirm that rename is not detected in P4. # Rename a file and confirm that rename is not detected in P4.
@ -279,6 +267,7 @@ test_expect_success 'initial import time from top change time' '
test_expect_success 'detect renames' ' test_expect_success 'detect renames' '
"$GITP4" clone --dest="$git" //depot@all && "$GITP4" clone --dest="$git" //depot@all &&
test_when_finished cleanup_git && test_when_finished cleanup_git &&
(
cd "$git" && cd "$git" &&
git config git-p4.skipSubmitEditCheck true && git config git-p4.skipSubmitEditCheck true &&


@ -287,7 +276,7 @@ test_expect_success 'detect renames' '
git diff-tree -r -M HEAD && git diff-tree -r -M HEAD &&
"$GITP4" submit && "$GITP4" submit &&
p4 filelog //depot/file4 && p4 filelog //depot/file4 &&
! p4 filelog //depot/file4 | grep -q "branch from" && p4 filelog //depot/file4 | test_must_fail grep -q "branch from" &&


git mv file4 file5 && git mv file4 file5 &&
git commit -a -m "Rename file4 to file5" && git commit -a -m "Rename file4 to file5" &&
@ -304,10 +293,10 @@ test_expect_success 'detect renames' '
git diff-tree -r -M HEAD && git diff-tree -r -M HEAD &&
level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") && level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") &&
test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 && test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 &&
git config git-p4.detectRenames $((level + 2)) && git config git-p4.detectRenames $(($level + 2)) &&
"$GITP4" submit && "$GITP4" submit &&
p4 filelog //depot/file6 && p4 filelog //depot/file6 &&
! p4 filelog //depot/file6 | grep -q "branch from" && p4 filelog //depot/file6 | test_must_fail grep -q "branch from" &&


git mv file6 file7 && git mv file6 file7 &&
echo update >>file7 && echo update >>file7 &&
@ -316,10 +305,11 @@ test_expect_success 'detect renames' '
git diff-tree -r -M HEAD && git diff-tree -r -M HEAD &&
level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") && level=$(git diff-tree -r -M HEAD | sed 1d | cut -f1 | cut -d" " -f5 | sed "s/R0*//") &&
test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 && test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 &&
git config git-p4.detectRenames $((level - 2)) && git config git-p4.detectRenames $(($level - 2)) &&
"$GITP4" submit && "$GITP4" submit &&
p4 filelog //depot/file7 && p4 filelog //depot/file7 &&
p4 filelog //depot/file7 | grep -q "branch from //depot/file6" p4 filelog //depot/file7 | grep -q "branch from //depot/file6"
)
' '


# Copy a file and confirm that copy is not detected in P4. # Copy a file and confirm that copy is not detected in P4.
@ -336,6 +326,7 @@ test_expect_success 'detect renames' '
test_expect_success 'detect copies' ' test_expect_success 'detect copies' '
"$GITP4" clone --dest="$git" //depot@all && "$GITP4" clone --dest="$git" //depot@all &&
test_when_finished cleanup_git && test_when_finished cleanup_git &&
(
cd "$git" && cd "$git" &&
git config git-p4.skipSubmitEditCheck true && git config git-p4.skipSubmitEditCheck true &&


@ -345,7 +336,7 @@ test_expect_success 'detect copies' '
git diff-tree -r -C HEAD && git diff-tree -r -C HEAD &&
"$GITP4" submit && "$GITP4" submit &&
p4 filelog //depot/file8 && p4 filelog //depot/file8 &&
! p4 filelog //depot/file8 | grep -q "branch from" && p4 filelog //depot/file8 | test_must_fail grep -q "branch from" &&


cp file2 file9 && cp file2 file9 &&
git add file9 && git add file9 &&
@ -354,7 +345,7 @@ test_expect_success 'detect copies' '
git config git-p4.detectCopies true && git config git-p4.detectCopies true &&
"$GITP4" submit && "$GITP4" submit &&
p4 filelog //depot/file9 && p4 filelog //depot/file9 &&
! p4 filelog //depot/file9 | grep -q "branch from" && p4 filelog //depot/file9 | test_must_fail grep -q "branch from" &&


echo "file2" >>file2 && echo "file2" >>file2 &&
cp file2 file10 && cp file2 file10 &&
@ -385,10 +376,10 @@ test_expect_success 'detect copies' '
test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 && test -n "$level" && test "$level" -gt 0 && test "$level" -lt 98 &&
src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) &&
test "$src" = file10 && test "$src" = file10 &&
git config git-p4.detectCopies $((level + 2)) && git config git-p4.detectCopies $(($level + 2)) &&
"$GITP4" submit && "$GITP4" submit &&
p4 filelog //depot/file12 && p4 filelog //depot/file12 &&
! p4 filelog //depot/file12 | grep -q "branch from" && p4 filelog //depot/file12 | test_must_fail grep -q "branch from" &&


cp file2 file13 && cp file2 file13 &&
echo "different text" >>file13 && echo "different text" >>file13 &&
@ -399,78 +390,15 @@ test_expect_success 'detect copies' '
test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 && test -n "$level" && test "$level" -gt 2 && test "$level" -lt 100 &&
src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) && src=$(git diff-tree -r -C --find-copies-harder HEAD | sed 1d | cut -f2) &&
test "$src" = file10 && test "$src" = file10 &&
git config git-p4.detectCopies $((level - 2)) && git config git-p4.detectCopies $(($level - 2)) &&
"$GITP4" submit && "$GITP4" submit &&
p4 filelog //depot/file13 && p4 filelog //depot/file13 &&
p4 filelog //depot/file13 | grep -q "branch from //depot/file" p4 filelog //depot/file13 | grep -q "branch from //depot/file"
)
' '


# Create a simple branch structure in P4 depot to check if it is correctly test_expect_success 'kill p4d' '
# cloned. kill_p4d
test_expect_success 'add simple p4 branches' '
cd "$cli" &&
mkdir branch1 &&
cd branch1 &&
echo file1 >file1 &&
echo file2 >file2 &&
p4 add file1 file2 &&
p4 submit -d "branch1" &&
p4 integrate //depot/branch1/... //depot/branch2/... &&
p4 submit -d "branch2" &&
echo file3 >file3 &&
p4 add file3 &&
p4 submit -d "add file3 in branch1" &&
p4 open file2 &&
echo update >>file2 &&
p4 submit -d "update file2 in branch1" &&
p4 integrate //depot/branch1/... //depot/branch3/... &&
p4 submit -d "branch3" &&
cd "$TRASH_DIRECTORY"
'

# Configure branches through git-config and clone them.
# All files are tested to make sure branches were cloned correctly.
# Finally, make an update to branch1 on P4 side to check if it is imported
# correctly by git-p4.
test_expect_success 'git-p4 clone simple branches' '
test_when_finished cleanup_git &&
test_create_repo "$git" &&
cd "$git" &&
git config git-p4.branchList branch1:branch2 &&
git config --add git-p4.branchList branch1:branch3 &&
"$GITP4" clone --dest=. --detect-branches //depot@all &&
git log --all --graph --decorate --stat &&
git reset --hard p4/depot/branch1 &&
test -f file1 &&
test -f file2 &&
test -f file3 &&
grep -q update file2 &&
git reset --hard p4/depot/branch2 &&
test -f file1 &&
test -f file2 &&
test ! -f file3 &&
! grep -q update file2 &&
git reset --hard p4/depot/branch3 &&
test -f file1 &&
test -f file2 &&
test -f file3 &&
grep -q update file2 &&
cd "$cli" &&
cd branch1 &&
p4 edit file2 &&
echo file2_ >>file2 &&
p4 submit -d "update file2 in branch1" &&
cd "$git" &&
git reset --hard p4/depot/branch1 &&
"$GITP4" rebase &&
grep -q file2_ file2
'

test_expect_success 'shutdown' '
pid=`pgrep -f p4d` &&
test -n "$pid" &&
test_debug "ps wl `echo $pid`" &&
kill $pid
' '


test_done test_done

233
t/t9801-git-p4-branch.sh

@ -0,0 +1,233 @@
#!/bin/sh

test_description='git-p4 p4 branching tests'

. ./lib-git-p4.sh

test_expect_success 'start p4d' '
start_p4d
'

#
# 1: //depot/main/f1
# 2: //depot/main/f2
# 3: integrate //depot/main/... -> //depot/branch1/...
# 4: //depot/main/f4
# 5: //depot/branch1/f5
# .: named branch branch2
# 6: integrate -b branch2
# 7: //depot/branch2/f7
# 8: //depot/main/f8
#
test_expect_success 'basic p4 branches' '
(
cd "$cli" &&
mkdir -p main &&

echo f1 >main/f1 &&
p4 add main/f1 &&
p4 submit -d "main/f1" &&

echo f2 >main/f2 &&
p4 add main/f2 &&
p4 submit -d "main/f2" &&

p4 integrate //depot/main/... //depot/branch1/... &&
p4 submit -d "integrate main to branch1" &&

echo f4 >main/f4 &&
p4 add main/f4 &&
p4 submit -d "main/f4" &&

echo f5 >branch1/f5 &&
p4 add branch1/f5 &&
p4 submit -d "branch1/f5" &&

p4 branch -i <<-EOF &&
Branch: branch2
View: //depot/main/... //depot/branch2/...
EOF

p4 integrate -b branch2 &&
p4 submit -d "integrate main to branch2" &&

echo f7 >branch2/f7 &&
p4 add branch2/f7 &&
p4 submit -d "branch2/f7" &&

echo f8 >main/f8 &&
p4 add main/f8 &&
p4 submit -d "main/f8"
)
'

test_expect_success 'import main, no branch detection' '
test_when_finished cleanup_git &&
"$GITP4" clone --dest="$git" //depot/main@all &&
(
cd "$git" &&
git log --oneline --graph --decorate --all &&
git rev-list master >wc &&
test_line_count = 4 wc
)
'

test_expect_success 'import branch1, no branch detection' '
test_when_finished cleanup_git &&
"$GITP4" clone --dest="$git" //depot/branch1@all &&
(
cd "$git" &&
git log --oneline --graph --decorate --all &&
git rev-list master >wc &&
test_line_count = 2 wc
)
'

test_expect_success 'import branch2, no branch detection' '
test_when_finished cleanup_git &&
"$GITP4" clone --dest="$git" //depot/branch2@all &&
(
cd "$git" &&
git log --oneline --graph --decorate --all &&
git rev-list master >wc &&
test_line_count = 2 wc
)
'

test_expect_success 'import depot, no branch detection' '
test_when_finished cleanup_git &&
"$GITP4" clone --dest="$git" //depot@all &&
(
cd "$git" &&
git log --oneline --graph --decorate --all &&
git rev-list master >wc &&
test_line_count = 8 wc
)
'

test_expect_success 'import depot, branch detection' '
test_when_finished cleanup_git &&
"$GITP4" clone --dest="$git" --detect-branches //depot@all &&
(
cd "$git" &&

git log --oneline --graph --decorate --all &&

# 4 main commits
git rev-list master >wc &&
test_line_count = 4 wc &&

# 3 main, 1 integrate, 1 on branch2
git rev-list p4/depot/branch2 >wc &&
test_line_count = 5 wc &&

# no branch1, since no p4 branch created for it
test_must_fail git show-ref p4/depot/branch1
)
'

test_expect_success 'import depot, branch detection, branchList branch definition' '
test_when_finished cleanup_git &&
test_create_repo "$git" &&
(
cd "$git" &&
git config git-p4.branchList main:branch1 &&
"$GITP4" clone --dest=. --detect-branches //depot@all &&

git log --oneline --graph --decorate --all &&

# 4 main commits
git rev-list master >wc &&
test_line_count = 4 wc &&

# 3 main, 1 integrate, 1 on branch2
git rev-list p4/depot/branch2 >wc &&
test_line_count = 5 wc &&

# 2 main, 1 integrate, 1 on branch1
git rev-list p4/depot/branch1 >wc &&
test_line_count = 4 wc
)
'

test_expect_success 'restart p4d' '
kill_p4d &&
start_p4d
'

#
# 1: //depot/branch1/file1
# //depot/branch1/file2
# 2: integrate //depot/branch1/... -> //depot/branch2/...
# 3: //depot/branch1/file3
# 4: //depot/branch1/file2 (edit)
# 5: integrate //depot/branch1/... -> //depot/branch3/...
#
## Create a simple branch structure in P4 depot.
test_expect_success 'add simple p4 branches' '
(
cd "$cli" &&
mkdir branch1 &&
cd branch1 &&
echo file1 >file1 &&
echo file2 >file2 &&
p4 add file1 file2 &&
p4 submit -d "branch1" &&
p4 integrate //depot/branch1/... //depot/branch2/... &&
p4 submit -d "branch2" &&
echo file3 >file3 &&
p4 add file3 &&
p4 submit -d "add file3 in branch1" &&
p4 open file2 &&
echo update >>file2 &&
p4 submit -d "update file2 in branch1" &&
p4 integrate //depot/branch1/... //depot/branch3/... &&
p4 submit -d "branch3"
)
'

# Configure branches through git-config and clone them.
# All files are tested to make sure branches were cloned correctly.
# Finally, make an update to branch1 on P4 side to check if it is imported
# correctly by git-p4.
test_expect_success 'git-p4 clone simple branches' '
test_when_finished cleanup_git &&
test_create_repo "$git" &&
(
cd "$git" &&
git config git-p4.branchList branch1:branch2 &&
git config --add git-p4.branchList branch1:branch3 &&
"$GITP4" clone --dest=. --detect-branches //depot@all &&
git log --all --graph --decorate --stat &&
git reset --hard p4/depot/branch1 &&
test -f file1 &&
test -f file2 &&
test -f file3 &&
grep -q update file2 &&
git reset --hard p4/depot/branch2 &&
test -f file1 &&
test -f file2 &&
test ! -f file3 &&
test_must_fail grep -q update file2 &&
git reset --hard p4/depot/branch3 &&
test -f file1 &&
test -f file2 &&
test -f file3 &&
grep -q update file2 &&
cd "$cli" &&
cd branch1 &&
p4 edit file2 &&
echo file2_ >>file2 &&
p4 submit -d "update file2 in branch3" &&
cd "$git" &&
git reset --hard p4/depot/branch1 &&
"$GITP4" rebase &&
grep -q file2_ file2
)
'

test_expect_success 'kill p4d' '
kill_p4d
'

test_done

108
t/t9802-git-p4-filetype.sh

@ -0,0 +1,108 @@
#!/bin/sh

test_description='git-p4 p4 filetype tests'

. ./lib-git-p4.sh

test_expect_success 'start p4d' '
start_p4d
'

test_expect_success 'utf-16 file create' '
(
cd "$cli" &&

# p4 saves this verbatim
printf "three\nline\ntext\n" >f-ascii &&
p4 add -t text f-ascii &&

# p4 adds \377\376 header
cp f-ascii f-ascii-as-utf16 &&
p4 add -t utf16 f-ascii-as-utf16 &&

# p4 saves this exactly as iconv produced it
printf "three\nline\ntext\n" | iconv -f ascii -t utf-16 >f-utf16 &&
p4 add -t utf16 f-utf16 &&

# this also is unchanged
cp f-utf16 f-utf16-as-text &&
p4 add -t text f-utf16-as-text &&

p4 submit -d "f files" &&

# force update of client files
p4 sync -f
)
'

test_expect_success 'utf-16 file test' '
test_when_finished cleanup_git &&
"$GITP4" clone --dest="$git" //depot@all &&
(
cd "$git" &&

test_cmp "$cli/f-ascii" f-ascii &&
test_cmp "$cli/f-ascii-as-utf16" f-ascii-as-utf16 &&
test_cmp "$cli/f-utf16" f-utf16 &&
test_cmp "$cli/f-utf16-as-text" f-utf16-as-text
)
'

test_expect_success 'keyword file create' '
(
cd "$cli" &&

printf "id\n\$Id\$\n\$Author\$\ntext\n" >k-text-k &&
p4 add -t text+k k-text-k &&

cp k-text-k k-text-ko &&
p4 add -t text+ko k-text-ko &&

cat k-text-k | iconv -f ascii -t utf-16 >k-utf16-k &&
p4 add -t utf16+k k-utf16-k &&

cp k-utf16-k k-utf16-ko &&
p4 add -t utf16+ko k-utf16-ko &&

p4 submit -d "k files" &&
p4 sync -f
)
'

build_smush() {
cat >k_smush.py <<-\EOF &&
import re, sys
sys.stdout.write(re.sub(r'(?i)\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\$', r'$\1$', sys.stdin.read()))
EOF
cat >ko_smush.py <<-\EOF
import re, sys
sys.stdout.write(re.sub(r'(?i)\$(Id|Header):[^$]*\$', r'$\1$', sys.stdin.read()))
EOF
}

test_expect_success 'keyword file test' '
build_smush &&
test_when_finished rm -f k_smush.py ko_smush.py &&
test_when_finished cleanup_git &&
"$GITP4" clone --dest="$git" //depot@all &&
(
cd "$git" &&

# text, ensure unexpanded
"$PYTHON_PATH" "$TRASH_DIRECTORY/k_smush.py" <"$cli/k-text-k" >cli-k-text-k-smush &&
test_cmp cli-k-text-k-smush k-text-k &&
"$PYTHON_PATH" "$TRASH_DIRECTORY/ko_smush.py" <"$cli/k-text-ko" >cli-k-text-ko-smush &&
test_cmp cli-k-text-ko-smush k-text-ko &&

# utf16, even though p4 expands keywords, git-p4 does not
# try to undo that
test_cmp "$cli/k-utf16-k" k-utf16-k &&
test_cmp "$cli/k-utf16-ko" k-utf16-ko
)
'

test_expect_success 'kill p4d' '
kill_p4d
'

test_done

64
t/t9803-git-shell-metachars.sh

@ -0,0 +1,64 @@
#!/bin/sh

test_description='git-p4 transparency to shell metachars in filenames'

. ./lib-git-p4.sh

test_expect_success 'start p4d' '
start_p4d
'

test_expect_success 'init depot' '
(
cd "$cli" &&
echo file1 >file1 &&
p4 add file1 &&
p4 submit -d "file1"
)
'

test_expect_success 'shell metachars in filenames' '
"$GITP4" clone --dest="$git" //depot &&
test_when_finished cleanup_git &&
(
cd "$git" &&
git config git-p4.skipSubmitEditCheck true &&
echo f1 >foo\$bar &&
git add foo\$bar &&
echo f2 >"file with spaces" &&
git add "file with spaces" &&
git commit -m "add files" &&
P4EDITOR=touch "$GITP4" submit
) &&
(
cd "$cli" &&
p4 sync ... &&
test -e "file with spaces" &&
test -e "foo\$bar"
)
'

test_expect_success 'deleting with shell metachars' '
"$GITP4" clone --dest="$git" //depot &&
test_when_finished cleanup_git &&
(
cd "$git" &&
git config git-p4.skipSubmitEditCheck true &&
git rm foo\$bar &&
git rm file\ with\ spaces &&
git commit -m "remove files" &&
P4EDITOR=touch "$GITP4" submit
) &&
(
cd "$cli" &&
p4 sync ... &&
test ! -e "file with spaces" &&
test ! -e foo\$bar
)
'

test_expect_success 'kill p4d' '
kill_p4d
'

test_done
Loading…
Cancel
Save