Skip to content

Commit a0a80f1

Browse files
committed
Merge branch 'git-p4' of git://repo.or.cz/git/git-p4
* 'git-p4' of git://repo.or.cz/git/git-p4: git-p4: Support usage of perforce client spec git-p4: git-p4 submit cleanups. git-p4: Removed git-p4 submit --direct. git-p4: Clean up git-p4 submit's log message handling. git-p4: Remove --log-substitutions feature. git-p4: support exclude paths
2 parents 77266e9 + 3a70cdf commit a0a80f1

File tree

1 file changed

+98
-118
lines changed

1 file changed

+98
-118
lines changed

contrib/fast-import/git-p4

Lines changed: 98 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -464,71 +464,47 @@ class P4Submit(Command):
464464
def __init__(self):
465465
Command.__init__(self)
466466
self.options = [
467-
optparse.make_option("--continue", action="store_false", dest="firstTime"),
468467
optparse.make_option("--verbose", dest="verbose", action="store_true"),
469468
optparse.make_option("--origin", dest="origin"),
470-
optparse.make_option("--reset", action="store_true", dest="reset"),
471-
optparse.make_option("--log-substitutions", dest="substFile"),
472-
optparse.make_option("--direct", dest="directSubmit", action="store_true"),
473469
optparse.make_option("-M", dest="detectRename", action="store_true"),
474470
]
475471
self.description = "Submit changes from git to the perforce depot."
476472
self.usage += " [name of git branch to submit into perforce depot]"
477-
self.firstTime = True
478-
self.reset = False
479473
self.interactive = True
480-
self.substFile = ""
481-
self.firstTime = True
482474
self.origin = ""
483-
self.directSubmit = False
484475
self.detectRename = False
485476
self.verbose = False
486477
self.isWindows = (platform.system() == "Windows")
487478

488-
self.logSubstitutions = {}
489-
self.logSubstitutions["<enter description here>"] = "%log%"
490-
self.logSubstitutions["\tDetails:"] = "\tDetails: %log%"
491-
492479
def check(self):
493480
if len(p4CmdList("opened ...")) > 0:
494481
die("You have files opened with perforce! Close them before starting the sync.")
495482

496-
def start(self):
497-
if len(self.config) > 0 and not self.reset:
498-
die("Cannot start sync. Previous sync config found at %s\n"
499-
"If you want to start submitting again from scratch "
500-
"maybe you want to call git-p4 submit --reset" % self.configFile)
501-
502-
commits = []
503-
if self.directSubmit:
504-
commits.append("0")
505-
else:
506-
for line in read_pipe_lines("git rev-list --no-merges %s..%s" % (self.origin, self.master)):
507-
commits.append(line.strip())
508-
commits.reverse()
509-
510-
self.config["commits"] = commits
511-
483+
# replaces everything between 'Description:' and the next P4 submit template field with the
484+
# commit message
512485
def prepareLogMessage(self, template, message):
513486
result = ""
514487

488+
inDescriptionSection = False
489+
515490
for line in template.split("\n"):
516491
if line.startswith("#"):
517492
result += line + "\n"
518493
continue
519494

520-
substituted = False
521-
for key in self.logSubstitutions.keys():
522-
if line.find(key) != -1:
523-
value = self.logSubstitutions[key]
524-
value = value.replace("%log%", message)
525-
if value != "@remove@":
526-
result += line.replace(key, value) + "\n"
527-
substituted = True
528-
break
495+
if inDescriptionSection:
496+
if line.startswith("Files:"):
497+
inDescriptionSection = False
498+
else:
499+
continue
500+
else:
501+
if line.startswith("Description:"):
502+
inDescriptionSection = True
503+
line += "\n"
504+
for messageLine in message.split("\n"):
505+
line += "\t" + messageLine + "\n"
529506

530-
if not substituted:
531-
result += line + "\n"
507+
result += line + "\n"
532508

533509
return result
534510

@@ -557,13 +533,9 @@ class P4Submit(Command):
557533
return template
558534

559535
def applyCommit(self, id):
560-
if self.directSubmit:
561-
print "Applying local change in working directory/index"
562-
diff = self.diffStatus
563-
else:
564-
print "Applying %s" % (read_pipe("git log --max-count=1 --pretty=oneline %s" % id))
565-
diffOpts = ("", "-M")[self.detectRename]
566-
diff = read_pipe_lines("git diff-tree -r %s \"%s^\" \"%s\"" % (diffOpts, id, id))
536+
print "Applying %s" % (read_pipe("git log --max-count=1 --pretty=oneline %s" % id))
537+
diffOpts = ("", "-M")[self.detectRename]
538+
diff = read_pipe_lines("git diff-tree -r %s \"%s^\" \"%s\"" % (diffOpts, id, id))
567539
filesToAdd = set()
568540
filesToDelete = set()
569541
editedFiles = set()
@@ -598,10 +570,7 @@ class P4Submit(Command):
598570
else:
599571
die("unknown modifier %s for %s" % (modifier, path))
600572

601-
if self.directSubmit:
602-
diffcmd = "cat \"%s\"" % self.diffFile
603-
else:
604-
diffcmd = "git format-patch -k --stdout \"%s^\"..\"%s\"" % (id, id)
573+
diffcmd = "git format-patch -k --stdout \"%s^\"..\"%s\"" % (id, id)
605574
patchcmd = diffcmd + " | git apply "
606575
tryPatchCmd = patchcmd + "--check -"
607576
applyPatchCmd = patchcmd + "--check --apply -"
@@ -649,13 +618,10 @@ class P4Submit(Command):
649618
mode = filesToChangeExecBit[f]
650619
setP4ExecBit(f, mode)
651620

652-
logMessage = ""
653-
if not self.directSubmit:
654-
logMessage = extractLogMessageFromGitCommit(id)
655-
logMessage = logMessage.replace("\n", "\n\t")
656-
if self.isWindows:
657-
logMessage = logMessage.replace("\n", "\r\n")
658-
logMessage = logMessage.strip()
621+
logMessage = extractLogMessageFromGitCommit(id)
622+
if self.isWindows:
623+
logMessage = logMessage.replace("\n", "\r\n")
624+
logMessage = logMessage.strip()
659625

660626
template = self.prepareSubmitTemplate()
661627

@@ -694,12 +660,6 @@ class P4Submit(Command):
694660
if self.isWindows:
695661
submitTemplate = submitTemplate.replace("\r\n", "\n")
696662

697-
if self.directSubmit:
698-
print "Submitting to git first"
699-
os.chdir(self.oldWorkingDirectory)
700-
write_pipe("git commit -a -F -", submitTemplate)
701-
os.chdir(self.clientPath)
702-
703663
write_pipe("p4 submit -i", submitTemplate)
704664
else:
705665
fileName = "submit.txt"
@@ -741,65 +701,33 @@ class P4Submit(Command):
741701
print "Perforce checkout for depot path %s located at %s" % (self.depotPath, self.clientPath)
742702
self.oldWorkingDirectory = os.getcwd()
743703

744-
if self.directSubmit:
745-
self.diffStatus = read_pipe_lines("git diff -r --name-status HEAD")
746-
if len(self.diffStatus) == 0:
747-
print "No changes in working directory to submit."
748-
return True
749-
patch = read_pipe("git diff -p --binary --diff-filter=ACMRTUXB HEAD")
750-
self.diffFile = self.gitdir + "/p4-git-diff"
751-
f = open(self.diffFile, "wb")
752-
f.write(patch)
753-
f.close();
754-
755704
os.chdir(self.clientPath)
756705
print "Syncronizing p4 checkout..."
757706
system("p4 sync ...")
758707

759-
if self.reset:
760-
self.firstTime = True
761-
762-
if len(self.substFile) > 0:
763-
for line in open(self.substFile, "r").readlines():
764-
tokens = line.strip().split("=")
765-
self.logSubstitutions[tokens[0]] = tokens[1]
766-
767708
self.check()
768-
self.configFile = self.gitdir + "/p4-git-sync.cfg"
769-
self.config = shelve.open(self.configFile, writeback=True)
770-
771-
if self.firstTime:
772-
self.start()
773709

774-
commits = self.config.get("commits", [])
710+
commits = []
711+
for line in read_pipe_lines("git rev-list --no-merges %s..%s" % (self.origin, self.master)):
712+
commits.append(line.strip())
713+
commits.reverse()
775714

776715
while len(commits) > 0:
777-
self.firstTime = False
778716
commit = commits[0]
779717
commits = commits[1:]
780-
self.config["commits"] = commits
781718
self.applyCommit(commit)
782719
if not self.interactive:
783720
break
784721

785-
self.config.close()
786-
787-
if self.directSubmit:
788-
os.remove(self.diffFile)
789-
790722
if len(commits) == 0:
791-
if self.firstTime:
792-
print "No changes found to apply between %s and current HEAD" % self.origin
793-
else:
794-
print "All changes applied!"
795-
os.chdir(self.oldWorkingDirectory)
723+
print "All changes applied!"
724+
os.chdir(self.oldWorkingDirectory)
796725

797-
sync = P4Sync()
798-
sync.run([])
726+
sync = P4Sync()
727+
sync.run([])
799728

800-
rebase = P4Rebase()
801-
rebase.rebase()
802-
os.remove(self.configFile)
729+
rebase = P4Rebase()
730+
rebase.rebase()
803731

804732
return True
805733

@@ -817,7 +745,9 @@ class P4Sync(Command):
817745
help="Import into refs/heads/ , not refs/remotes"),
818746
optparse.make_option("--max-changes", dest="maxChanges"),
819747
optparse.make_option("--keep-path", dest="keepRepoPath", action='store_true',
820-
help="Keep entire BRANCH/DIR/SUBDIR prefix during import")
748+
help="Keep entire BRANCH/DIR/SUBDIR prefix during import"),
749+
optparse.make_option("--use-client-spec", dest="useClientSpec", action='store_true',
750+
help="Only sync files that are included in the Perforce Client Spec")
821751
]
822752
self.description = """Imports from Perforce into a git repository.\n
823753
example:
@@ -843,18 +773,27 @@ class P4Sync(Command):
843773
self.keepRepoPath = False
844774
self.depotPaths = None
845775
self.p4BranchesInGit = []
776+
self.cloneExclude = []
777+
self.useClientSpec = False
778+
self.clientSpecDirs = []
846779

847780
if gitConfig("git-p4.syncFromOrigin") == "false":
848781
self.syncWithOrigin = False
849782

850783
def extractFilesFromCommit(self, commit):
784+
self.cloneExclude = [re.sub(r"\.\.\.$", "", path)
785+
for path in self.cloneExclude]
851786
files = []
852787
fnum = 0
853788
while commit.has_key("depotFile%s" % fnum):
854789
path = commit["depotFile%s" % fnum]
855790

856-
found = [p for p in self.depotPaths
857-
if path.startswith (p)]
791+
if [p for p in self.cloneExclude
792+
if path.startswith (p)]:
793+
found = False
794+
else:
795+
found = [p for p in self.depotPaths
796+
if path.startswith (p)]
858797
if not found:
859798
fnum = fnum + 1
860799
continue
@@ -911,11 +850,21 @@ class P4Sync(Command):
911850

912851
## Should move this out, doesn't use SELF.
913852
def readP4Files(self, files):
853+
for f in files:
854+
for val in self.clientSpecDirs:
855+
if f['path'].startswith(val[0]):
856+
if val[1] > 0:
857+
f['include'] = True
858+
else:
859+
f['include'] = False
860+
break
861+
914862
files = [f for f in files
915-
if f['action'] != 'delete']
863+
if f['action'] != 'delete' and
864+
(f.has_key('include') == False or f['include'] == True)]
916865

917866
if not files:
918-
return
867+
return []
919868

920869
filedata = p4CmdList('-x - print',
921870
stdin='\n'.join(['%s#%s' % (f['path'], f['rev'])
@@ -950,6 +899,7 @@ class P4Sync(Command):
950899
for f in files:
951900
assert not f.has_key('data')
952901
f['data'] = contents[f['path']]
902+
return files
953903

954904
def commit(self, details, files, branch, branchPrefixes, parent = ""):
955905
epoch = details["time"]
@@ -966,11 +916,7 @@ class P4Sync(Command):
966916
new_files.append (f)
967917
else:
968918
sys.stderr.write("Ignoring file outside of prefix: %s\n" % path)
969-
files = new_files
970-
self.readP4Files(files)
971-
972-
973-
919+
files = self.readP4Files(new_files)
974920

975921
self.gitStream.write("commit %s\n" % branch)
976922
# gitStream.write("mark :%s\n" % details["change"])
@@ -1385,6 +1331,26 @@ class P4Sync(Command):
13851331
print self.gitError.read()
13861332

13871333

1334+
def getClientSpec(self):
1335+
specList = p4CmdList( "client -o" )
1336+
temp = {}
1337+
for entry in specList:
1338+
for k,v in entry.iteritems():
1339+
if k.startswith("View"):
1340+
if v.startswith('"'):
1341+
start = 1
1342+
else:
1343+
start = 0
1344+
index = v.find("...")
1345+
v = v[start:index]
1346+
if v.startswith("-"):
1347+
v = v[1:]
1348+
temp[v] = -len(v)
1349+
else:
1350+
temp[v] = len(v)
1351+
self.clientSpecDirs = temp.items()
1352+
self.clientSpecDirs.sort( lambda x, y: abs( y[1] ) - abs( x[1] ) )
1353+
13881354
def run(self, args):
13891355
self.depotPaths = []
13901356
self.changeRange = ""
@@ -1417,6 +1383,9 @@ class P4Sync(Command):
14171383
if not gitBranchExists(self.refPrefix + "HEAD") and self.importIntoRemotes and gitBranchExists(self.branch):
14181384
system("git symbolic-ref %sHEAD %s" % (self.refPrefix, self.branch))
14191385

1386+
if self.useClientSpec or gitConfig("p4.useclientspec") == "true":
1387+
self.getClientSpec()
1388+
14201389
# TODO: should always look at previous commits,
14211390
# merge with previous imports, if possible.
14221391
if args == []:
@@ -1634,13 +1603,23 @@ class P4Clone(P4Sync):
16341603
P4Sync.__init__(self)
16351604
self.description = "Creates a new git repository and imports from Perforce into it"
16361605
self.usage = "usage: %prog [options] //depot/path[@revRange]"
1637-
self.options.append(
1606+
self.options += [
16381607
optparse.make_option("--destination", dest="cloneDestination",
16391608
action='store', default=None,
1640-
help="where to leave result of the clone"))
1609+
help="where to leave result of the clone"),
1610+
optparse.make_option("-/", dest="cloneExclude",
1611+
action="append", type="string",
1612+
help="exclude depot path")
1613+
]
16411614
self.cloneDestination = None
16421615
self.needsGit = False
16431616

1617+
# This is required for the "append" cloneExclude action
1618+
def ensure_value(self, attr, value):
1619+
if not hasattr(self, attr) or getattr(self, attr) is None:
1620+
setattr(self, attr, value)
1621+
return getattr(self, attr)
1622+
16441623
def defaultDestination(self, args):
16451624
## TODO: use common prefix of args?
16461625
depotPath = args[0]
@@ -1664,6 +1643,7 @@ class P4Clone(P4Sync):
16641643
self.cloneDestination = depotPaths[-1]
16651644
depotPaths = depotPaths[:-1]
16661645

1646+
self.cloneExclude = ["/"+p for p in self.cloneExclude]
16671647
for p in depotPaths:
16681648
if not p.startswith("//"):
16691649
return False

0 commit comments

Comments
 (0)