Merge branch 'pw/p4'
authorJunio C Hamano <gitster@pobox.com>
Wed, 23 Mar 2011 21:54:24 +0000 (14:54 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 23 Mar 2011 21:54:24 +0000 (14:54 -0700)
* pw/p4:
git-p4: test sync new branch
git-p4: fix sync new branch regression

1  2 
contrib/fast-import/git-p4
index 47ba7adafba2f0eb3966dcac11b8063e3171145a,d4ddf8dc58e10c5091cac9dd17b22f1afcf4c242..388151503423aeff0a99ee943f7eebf0c8fec476
@@@ -333,13 -333,9 +333,13 @@@ def gitBranchExists(branch)
      return proc.wait() == 0;
  
  _gitConfig = {}
 -def gitConfig(key):
 +def gitConfig(key, args = None): # set args to "--bool", for instance
      if not _gitConfig.has_key(key):
 -        _gitConfig[key] = read_pipe("git config %s" % key, ignore_error=True).strip()
 +        argsFilter = ""
 +        if args != None:
 +            argsFilter = "%s " % args
 +        cmd = "git config %s%s" % (argsFilter, key)
 +        _gitConfig[key] = read_pipe(cmd, ignore_error=True).strip()
      return _gitConfig[key]
  
  def p4BranchesInGit(branchesAreInRemotes = True):
@@@ -456,19 -452,6 +456,19 @@@ def p4ChangesForPaths(depotPaths, chang
      changelist.sort()
      return changelist
  
 +def p4PathStartsWith(path, prefix):
 +    # This method tries to remedy a potential mixed-case issue:
 +    #
 +    # If UserA adds  //depot/DirA/file1
 +    # and UserB adds //depot/dira/file2
 +    #
 +    # we may or may not have a problem. If you have core.ignorecase=true,
 +    # we treat DirA and dira as the same directory
 +    ignorecase = gitConfig("core.ignorecase", "--bool") == "true"
 +    if ignorecase:
 +        return path.lower().startswith(prefix.lower())
 +    return path.startswith(prefix)
 +
  class Command:
      def __init__(self):
          self.usage = "usage: %prog [options]"
@@@ -560,13 -543,13 +560,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
                      lastTab = path.rfind("\t")
                      if lastTab != -1:
                          path = path[:lastTab]
 -                        if not path.startswith(self.depotPath):
 +                        if not p4PathStartsWith(path, self.depotPath):
                              continue
                  else:
                      inFilesSection = False
  
      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)
@@@ -954,11 -910,11 +954,11 @@@ class P4Sync(Command)
              path =  commit["depotFile%s" % fnum]
  
              if [p for p in self.cloneExclude
 -                if path.startswith (p)]:
 +                if p4PathStartsWith(path, p)]:
                  found = False
              else:
                  found = [p for p in self.depotPaths
 -                         if path.startswith (p)]
 +                         if p4PathStartsWith(path, p)]
              if not found:
                  fnum = fnum + 1
                  continue
          return files
  
      def stripRepoPath(self, path, prefixes):
 +        if self.useClientSpec:
 +
 +            # if using the client spec, we use the output directory
 +            # specified in the client.  For example, a view
 +            #   //depot/foo/branch/... //client/branch/foo/...
 +            # will end up putting all foo/branch files into
 +            #  branch/foo/
 +            for val in self.clientSpecDirs:
 +                if path.startswith(val[0]):
 +                    # replace the depot path with the client path
 +                    path = path.replace(val[0], val[1][1])
 +                    # now strip out the client (//client/...)
 +                    path = re.sub("^(//[^/]+/)", '', path)
 +                    # the rest is all path
 +                    return path
 +
          if self.keepRepoPath:
              prefixes = [re.sub("^(//[^/]+/).*", r'\1', prefixes[0])]
  
          for p in prefixes:
 -            if path.startswith(p):
 +            if p4PathStartsWith(path, p):
                  path = path[len(p):]
  
          return path
          while commit.has_key("depotFile%s" % fnum):
              path =  commit["depotFile%s" % fnum]
              found = [p for p in self.depotPaths
 -                     if path.startswith (p)]
 +                     if p4PathStartsWith(path, p)]
              if not found:
                  fnum = fnum + 1
                  continue
              includeFile = True
              for val in self.clientSpecDirs:
                  if f['path'].startswith(val[0]):
 -                    if val[1] <= 0:
 +                    if val[1][0] <= 0:
                          includeFile = False
                      break
  
          # create a commit.
          new_files = []
          for f in files:
 -            if [p for p in branchPrefixes if f['path'].startswith(p)]:
 +            if [p for p in branchPrefixes if p4PathStartsWith(f['path'], p)]:
                  new_files.append (f)
              else:
 -                sys.stderr.write("Ignoring file outside of prefix: %s\n" % path)
 +                sys.stderr.write("Ignoring file outside of prefix: %s\n" % f['path'])
  
          self.gitStream.write("commit %s\n" % branch)
  #        gitStream.write("mark :%s\n" % details["change"])
                  source = paths[0]
                  destination = paths[1]
                  ## HACK
 -                if source.startswith(self.depotPaths[0]) and destination.startswith(self.depotPaths[0]):
 +                if p4PathStartsWith(source, self.depotPaths[0]) and p4PathStartsWith(destination, self.depotPaths[0]):
                      source = source[len(self.depotPaths[0]):-4]
                      destination = destination[len(self.depotPaths[0]):-4]
  
          for entry in specList:
              for k,v in entry.iteritems():
                  if k.startswith("View"):
 +
 +                    # p4 has these %%1 to %%9 arguments in specs to
 +                    # reorder paths; which we can't handle (yet :)
 +                    if re.match('%%\d', v) != None:
 +                        print "Sorry, can't handle %%n arguments in client specs"
 +                        sys.exit(1)
 +
                      if v.startswith('"'):
                          start = 1
                      else:
                          start = 0
                      index = v.find("...")
 +
 +                    # save the "client view"; i.e the RHS of the view
 +                    # line that tells the client where to put the
 +                    # files for this view.
 +                    cv = v[index+3:].strip() # +3 to remove previous '...'
 +
 +                    # if the client view doesn't end with a
 +                    # ... wildcard, then we're going to mess up the
 +                    # output directory, so fail gracefully.
 +                    if not cv.endswith('...'):
 +                        print 'Sorry, client view in "%s" needs to end with wildcard' % (k)
 +                        sys.exit(1)
 +                    cv=cv[:-3]
 +
 +                    # now save the view; +index means included, -index
 +                    # means it should be filtered out.
                      v = v[start:index]
                      if v.startswith("-"):
                          v = v[1:]
 -                        temp[v] = -len(v)
 +                        include = -len(v)
                      else:
 -                        temp[v] = len(v)
 +                        include = len(v)
 +
 +                    temp[v] = (include, cv)
 +
          self.clientSpecDirs = temp.items()
 -        self.clientSpecDirs.sort( lambda x, y: abs( y[1] ) - abs( x[1] ) )
 +        self.clientSpecDirs.sort( lambda x, y: abs( y[1][0] ) - abs( x[1][0] ) )
  
      def run(self, args):
          self.depotPaths = []
  
                  changes.sort()
              else:
-                 if not isinstance(self, P4Clone) and not self.p4BranchesInGit:
+                 # catch "git-p4 sync" with no new branches, in a repo that
+                 # does not have any existing git-p4 branches
+                 if len(args) == 0 and 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),