Merge branch 'mh/p4'
authorJunio C Hamano <gitster@pobox.com>
Fri, 4 Mar 2011 23:02:28 +0000 (15:02 -0800)
committerJunio C Hamano <gitster@pobox.com>
Fri, 4 Mar 2011 23:02:28 +0000 (15:02 -0800)
* mh/p4:
git-p4 submit: prevent 'Jobs' section from being removed from p4 change log

1  2 
contrib/fast-import/git-p4
index a4f440d11696caa6ee4756108bec78a85d4b04f7,8b00fd87972846ec5ddfb20159867f86e91aa354..2df3bb21c4aff3863844a0f679d257efa48e68b5
@@@ -543,13 -543,13 +543,13 @@@ class P4Submit(Command)
          self.options = [
                  optparse.make_option("--verbose", dest="verbose", action="store_true"),
                  optparse.make_option("--origin", dest="origin"),
 -                optparse.make_option("-M", dest="detectRename", action="store_true"),
 +                optparse.make_option("-M", dest="detectRenames", action="store_true"),
          ]
          self.description = "Submit changes from git to the perforce depot."
          self.usage += " [name of git branch to submit into perforce depot]"
          self.interactive = True
          self.origin = ""
 -        self.detectRename = False
 +        self.detectRenames = False
          self.verbose = False
          self.isWindows = (platform.system() == "Windows")
  
                  continue
  
              if inDescriptionSection:
-                 if line.startswith("Files:"):
+                 if line.startswith("Files:") or line.startswith("Jobs:"):
                      inDescriptionSection = False
                  else:
                      continue
  
      def applyCommit(self, id):
          print "Applying %s" % (read_pipe("git log --max-count=1 --pretty=oneline %s" % id))
 -        diffOpts = ("", "-M")[self.detectRename]
 +
 +        if not self.detectRenames:
 +            # If not explicitly set check the config variable
 +            self.detectRenames = gitConfig("git-p4.detectRenames").lower() == "true"
 +
 +        if self.detectRenames:
 +            diffOpts = "-M"
 +        else:
 +            diffOpts = ""
 +
 +        if gitConfig("git-p4.detectCopies").lower() == "true":
 +            diffOpts += " -C"
 +
 +        if gitConfig("git-p4.detectCopiesHarder").lower() == "true":
 +            diffOpts += " --find-copies-harder"
 +
          diff = read_pipe_lines("git diff-tree -r %s \"%s^\" \"%s\"" % (diffOpts, id, id))
          filesToAdd = set()
          filesToDelete = set()
                  filesToDelete.add(path)
                  if path in filesToAdd:
                      filesToAdd.remove(path)
 +            elif modifier == "C":
 +                src, dest = diff['src'], diff['dst']
 +                p4_system("integrate -Dt \"%s\" \"%s\"" % (src, dest))
 +                if diff['src_sha1'] != diff['dst_sha1']:
 +                    p4_system("edit \"%s\"" % (dest))
 +                if isModeExecChanged(diff['src_mode'], diff['dst_mode']):
 +                    p4_system("edit \"%s\"" % (dest))
 +                    filesToChangeExecBit[dest] = diff['dst_mode']
 +                os.unlink(dest)
 +                editedFiles.add(dest)
              elif modifier == "R":
                  src, dest = diff['src'], diff['dst']
                  p4_system("integrate -Dt \"%s\" \"%s\"" % (src, dest))
 -                p4_system("edit \"%s\"" % (dest))
 +                if diff['src_sha1'] != diff['dst_sha1']:
 +                    p4_system("edit \"%s\"" % (dest))
                  if isModeExecChanged(diff['src_mode'], diff['dst_mode']):
 +                    p4_system("edit \"%s\"" % (dest))
                      filesToChangeExecBit[dest] = diff['dst_mode']
                  os.unlink(dest)
                  editedFiles.add(dest)
          return True
  
  class P4Sync(Command):
 +    delete_actions = ( "delete", "move/delete", "purge" )
 +
      def __init__(self):
          Command.__init__(self)
          self.options = [
          if gitConfig("git-p4.syncFromOrigin") == "false":
              self.syncWithOrigin = False
  
 +    #
 +    # P4 wildcards are not allowed in filenames.  P4 complains
 +    # if you simply add them, but you can force it with "-f", in
 +    # which case it translates them into %xx encoding internally.
 +    # Search for and fix just these four characters.  Do % last so
 +    # that fixing it does not inadvertently create new %-escapes.
 +    #
 +    def wildcard_decode(self, path):
 +        # Cannot have * in a filename in windows; untested as to
 +        # what p4 would do in such a case.
 +        if not self.isWindows:
 +            path = path.replace("%2A", "*")
 +        path = path.replace("%23", "#") \
 +                   .replace("%40", "@") \
 +                   .replace("%25", "%")
 +        return path
 +
      def extractFilesFromCommit(self, commit):
          self.cloneExclude = [re.sub(r"\.\.\.$", "", path)
                               for path in self.cloneExclude]
            return
  
          relPath = self.stripRepoPath(file['depotFile'], self.branchPrefixes)
 +        relPath = self.wildcard_decode(relPath)
          if verbose:
              sys.stderr.write("%s\n" % relPath)
  
  
              if includeFile:
                  filesForCommit.append(f)
 -                if f['action'] not in ('delete', 'move/delete', 'purge'):
 -                    filesToRead.append(f)
 -                else:
 +                if f['action'] in self.delete_actions:
                      filesToDelete.append(f)
 +                else:
 +                    filesToRead.append(f)
  
          # deleted files...
          for f in filesToDelete:
  
                  cleanedFiles = {}
                  for info in files:
 -                    if info["action"] in ("delete", "purge"):
 +                    if info["action"] in self.delete_actions:
                          continue
                      cleanedFiles[info["depotFile"]] = info["rev"]
  
          print "Doing initial import of %s from revision %s into %s" % (' '.join(self.depotPaths), revision, self.branch)
  
          details = { "user" : "git perforce import user", "time" : int(time.time()) }
 -        details["desc"] = ("Initial import of %s from the state at revision %s"
 +        details["desc"] = ("Initial import of %s from the state at revision %s\n"
                             % (' '.join(self.depotPaths), revision))
          details["change"] = revision
          newestRevision = 0
                                             % (p, revision)
                                             for p in self.depotPaths])):
  
 -            if info['code'] == 'error':
 +            if 'code' in info and info['code'] == 'error':
                  sys.stderr.write("p4 returned an error: %s\n"
                                   % info['data'])
 +                if info['data'].find("must refer to client") >= 0:
 +                    sys.stderr.write("This particular p4 error is misleading.\n")
 +                    sys.stderr.write("Perhaps the depot path was misspelled.\n");
 +                    sys.stderr.write("Depot path:  %s\n" % " ".join(self.depotPaths))
 +                sys.exit(1)
 +            if 'p4ExitCode' in info:
 +                sys.stderr.write("p4 exitcode: %s\n" % info['p4ExitCode'])
                  sys.exit(1)
  
  
              if change > newestRevision:
                  newestRevision = change
  
 -            if info["action"] in ("delete", "purge"):
 +            if info["action"] in self.delete_actions:
                  # don't increase the file cnt, otherwise details["depotFile123"] will have gaps!
                  #fileCnt = fileCnt + 1
                  continue
  
                  changes.sort()
              else:
 +                if not self.p4BranchesInGit:
 +                    die("No remote p4 branches.  Perhaps you never did \"git p4 clone\" in here.");
                  if self.verbose:
                      print "Getting p4 changes for %s...%s" % (', '.join(self.depotPaths),
                                                                self.changeRange)
@@@ -1845,13 -1789,10 +1845,13 @@@ class P4Clone(P4Sync)
                                   help="where to leave result of the clone"),
              optparse.make_option("-/", dest="cloneExclude",
                                   action="append", type="string",
 -                                 help="exclude depot path")
 +                                 help="exclude depot path"),
 +            optparse.make_option("--bare", dest="cloneBare",
 +                                 action="store_true", default=False),
          ]
          self.cloneDestination = None
          self.needsGit = False
 +        self.cloneBare = False
  
      # This is required for the "append" cloneExclude action
      def ensure_value(self, attr, value):
              self.cloneDestination = self.defaultDestination(args)
  
          print "Importing from %s into %s" % (', '.join(depotPaths), self.cloneDestination)
 +
          if not os.path.exists(self.cloneDestination):
              os.makedirs(self.cloneDestination)
          chdir(self.cloneDestination)
 -        system("git init")
 -        self.gitdir = os.getcwd() + "/.git"
 +
 +        init_cmd = [ "git", "init" ]
 +        if self.cloneBare:
 +            init_cmd.append("--bare")
 +        subprocess.check_call(init_cmd)
 +
          if not P4Sync.run(self, depotPaths):
              return False
          if self.branch != "master":
                  masterbranch = "refs/heads/p4/master"
              if gitBranchExists(masterbranch):
                  system("git branch master %s" % masterbranch)
 -                system("git checkout -f")
 +                if not self.cloneBare:
 +                    system("git checkout -f")
              else:
                  print "Could not detect main branch. No checkout/master branch created."