Merge branch 'pw/p4-appledouble-fix'
authorJunio C Hamano <gitster@pobox.com>
Mon, 7 Nov 2011 05:21:57 +0000 (21:21 -0800)
committerJunio C Hamano <gitster@pobox.com>
Mon, 7 Nov 2011 05:21:57 +0000 (21:21 -0800)
* pw/p4-appledouble-fix:
git-p4: ignore apple filetype

1  2 
contrib/fast-import/git-p4
index f885d707c4a9d80928cecb3d4867deb268929670,da1db4a8c0e6f7cabe90944a715cfc3751331ddf..b975d67fca530a35c590cb677a6f11eabb7900bb
@@@ -22,39 -22,36 +22,39 @@@ def p4_build_cmd(cmd)
      location. It means that hooking into the environment, or other configuration
      can be done more easily.
      """
 -    real_cmd = "%s " % "p4"
 +    real_cmd = ["p4"]
  
      user = gitConfig("git-p4.user")
      if len(user) > 0:
 -        real_cmd += "-u %s " % user
 +        real_cmd += ["-u",user]
  
      password = gitConfig("git-p4.password")
      if len(password) > 0:
 -        real_cmd += "-P %s " % password
 +        real_cmd += ["-P", password]
  
      port = gitConfig("git-p4.port")
      if len(port) > 0:
 -        real_cmd += "-p %s " % port
 +        real_cmd += ["-p", port]
  
      host = gitConfig("git-p4.host")
      if len(host) > 0:
 -        real_cmd += "-h %s " % host
 +        real_cmd += ["-h", host]
  
      client = gitConfig("git-p4.client")
      if len(client) > 0:
 -        real_cmd += "-c %s " % client
 +        real_cmd += ["-c", client]
  
 -    real_cmd += "%s" % (cmd)
 -    if verbose:
 -        print real_cmd
 +
 +    if isinstance(cmd,basestring):
 +        real_cmd = ' '.join(real_cmd) + ' ' + cmd
 +    else:
 +        real_cmd += cmd
      return real_cmd
  
  def chdir(dir):
 -    if os.name == 'nt':
 -        os.environ['PWD']=dir
 +    # 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.chdir(dir)
  
  def die(msg):
          sys.stderr.write(msg + "\n")
          sys.exit(1)
  
 -def write_pipe(c, str):
 +def write_pipe(c, stdin):
      if verbose:
 -        sys.stderr.write('Writing pipe: %s\n' % c)
 +        sys.stderr.write('Writing pipe: %s\n' % str(c))
  
 -    pipe = os.popen(c, 'w')
 -    val = pipe.write(str)
 -    if pipe.close():
 -        die('Command failed: %s' % c)
 +    expand = isinstance(c,basestring)
 +    p = subprocess.Popen(c, stdin=subprocess.PIPE, shell=expand)
 +    pipe = p.stdin
 +    val = pipe.write(stdin)
 +    pipe.close()
 +    if p.wait():
 +        die('Command failed: %s' % str(c))
  
      return val
  
 -def p4_write_pipe(c, str):
 +def p4_write_pipe(c, stdin):
      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):
      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()
 -    if pipe.close() and not ignore_error:
 -        die('Command failed: %s' % c)
 +    if p.wait() and not ignore_error:
 +        die('Command failed: %s' % str(c))
  
      return val
  
@@@ -101,14 -93,12 +101,14 @@@ def p4_read_pipe(c, ignore_error=False)
  
  def read_pipe_lines(c):
      if verbose:
 -        sys.stderr.write('Reading pipe: %s\n' % c)
 -    ## todo: check return status
 -    pipe = os.popen(c, 'rb')
 +        sys.stderr.write('Reading pipe: %s\n' % str(c))
 +
 +    expand = isinstance(c, basestring)
 +    p = subprocess.Popen(c, stdout=subprocess.PIPE, shell=expand)
 +    pipe = p.stdout
      val = pipe.readlines()
 -    if pipe.close():
 -        die('Command failed: %s' % c)
 +    if pipe.close() or p.wait():
 +        die('Command failed: %s' % str(c))
  
      return val
  
@@@ -118,37 -108,15 +118,37 @@@ def p4_read_pipe_lines(c)
      return read_pipe_lines(real_cmd)
  
  def system(cmd):
 +    expand = isinstance(cmd,basestring)
      if verbose:
 -        sys.stderr.write("executing %s\n" % cmd)
 -    if os.system(cmd) != 0:
 -        die("command failed: %s" % cmd)
 +        sys.stderr.write("executing %s\n" % str(cmd))
 +    subprocess.check_call(cmd, shell=expand)
  
  def p4_system(cmd):
      """Specifically invoke p4 as the system command. """
      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 p4_delete(f):
 +    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
@@@ -199,12 -167,12 +199,12 @@@ def setP4ExecBit(file, mode)
          if p4Type[-1] == "+":
              p4Type = p4Type[0:-1]
  
 -    p4_system("reopen -t %s %s" % (p4Type, file))
 +    p4_reopen(p4Type, file)
  
  def getP4OpenedType(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)
      if match:
          return match.group(1)
@@@ -260,17 -228,9 +260,17 @@@ def isModeExecChanged(src_mode, dst_mod
      return isModeExec(src_mode) != isModeExec(dst_mode)
  
  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:
 -        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
      # subprocess.communicate(), which would put another copy
      stdin_file = None
      if stdin is not None:
          stdin_file = tempfile.TemporaryFile(prefix='p4-stdin', mode=stdin_mode)
 -        stdin_file.write(stdin)
 +        if isinstance(stdin,basestring):
 +            stdin_file.write(stdin)
 +        else:
 +            for i in stdin:
 +                stdin_file.write(i + '\n')
          stdin_file.flush()
          stdin_file.seek(0)
  
 -    p4 = subprocess.Popen(cmd, shell=True,
 +    p4 = subprocess.Popen(cmd,
 +                          shell=expand,
                            stdin=stdin_file,
                            stdout=subprocess.PIPE)
  
@@@ -320,7 -275,7 +320,7 @@@ def p4Where(depotPath)
      if not depotPath.endswith("/"):
          depotPath += "/"
      depotPath = depotPath + "..."
 -    outputList = p4CmdList("where %s" % depotPath)
 +    outputList = p4CmdList(["where", depotPath])
      output = None
      for entry in outputList:
          if "depotFile" in entry:
@@@ -522,10 -477,8 +522,10 @@@ def originP4BranchesExist()
  
  def p4ChangesForPaths(depotPaths, changeRange):
      assert depotPaths
 -    output = p4_read_pipe_lines("changes " + ' '.join (["%s...%s" % (p, changeRange)
 -                                                        for p in depotPaths]))
 +    cmd = ['changes']
 +    for p in depotPaths:
 +        cmd += ["%s...%s" % (p, changeRange)]
 +    output = p4_read_pipe_lines(cmd)
  
      changes = {}
      for line in output:
@@@ -608,7 -561,7 +608,7 @@@ class P4Debug(Command)
  
      def run(self, args):
          j = 0
 -        for output in p4CmdList(" ".join(args)):
 +        for output in p4CmdList(args):
              print 'Element: %d' % j
              j += 1
              print output
@@@ -762,7 -715,7 +762,7 @@@ class P4Submit(Command, P4UserMap)
                  break
          if not client:
              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:
              if r.has_key('change'):
                  return r['change']
          # remove lines in the Files section that show changes to files outside the depot path we're committing into
          template = ""
          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"):
                  line = line[:-2] + "\n"
              if inFilesSection:
              modifier = diff['status']
              path = diff['src']
              if modifier == "M":
 -                p4_system("edit \"%s\"" % path)
 +                p4_edit(path)
                  if isModeExecChanged(diff['src_mode'], diff['dst_mode']):
                      filesToChangeExecBit[path] = diff['dst_mode']
                  editedFiles.add(path)
                      filesToAdd.remove(path)
              elif modifier == "C":
                  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']:
 -                    p4_system("edit \"%s\"" % (dest))
 +                    p4_edit(dest)
                  if isModeExecChanged(diff['src_mode'], diff['dst_mode']):
 -                    p4_system("edit \"%s\"" % (dest))
 +                    p4_edit(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_integrate(src, dest)
                  if diff['src_sha1'] != diff['dst_sha1']:
 -                    p4_system("edit \"%s\"" % (dest))
 +                    p4_edit(dest)
                  if isModeExecChanged(diff['src_mode'], diff['dst_mode']):
 -                    p4_system("edit \"%s\"" % (dest))
 +                    p4_edit(dest)
                      filesToChangeExecBit[dest] = diff['dst_mode']
                  os.unlink(dest)
                  editedFiles.add(dest)
              if response == "s":
                  print "Skipping! Good luck with the next patches..."
                  for f in editedFiles:
 -                    p4_system("revert \"%s\"" % f);
 +                    p4_revert(f)
                  for f in filesToAdd:
 -                    system("rm %s" %f)
 +                    os.remove(f)
                  return
              elif response == "a":
                  os.system(applyPatchCmd)
          system(applyPatchCmd)
  
          for f in filesToAdd:
 -            p4_system("add \"%s\"" % f)
 +            p4_add(f)
          for f in filesToDelete:
 -            p4_system("revert \"%s\"" % f)
 -            p4_system("delete \"%s\"" % f)
 +            p4_revert(f)
 +            p4_delete(f)
  
          # Set/clear executable bits
          for f in filesToChangeExecBit.keys():
                  del(os.environ["P4DIFF"])
              diff = ""
              for editedFile in editedFiles:
 -                diff += p4_read_pipe("diff -du %r" % editedFile)
 +                diff += p4_read_pipe(['diff', '-du', editedFile])
  
              newdiff = ""
              for newFile in filesToAdd:
                  submitTemplate = message[:message.index(separatorLine)]
                  if self.isWindows:
                      submitTemplate = submitTemplate.replace("\r\n", "\n")
 -                p4_write_pipe("submit -i", submitTemplate)
 +                p4_write_pipe(['submit', '-i'], submitTemplate)
  
                  if self.preserveUser:
                      if p4User:
  
              else:
                  for f in editedFiles:
 -                    p4_system("revert \"%s\"" % f);
 +                    p4_revert(f)
                  for f in filesToAdd:
 -                    p4_system("revert \"%s\"" % f);
 -                    system("rm %s" %f)
 +                    p4_revert(f)
 +                    os.remove(f)
  
              os.remove(fileName)
          else:
  
          chdir(self.clientPath)
          print "Synchronizing p4 checkout..."
 -        p4_system("sync ...")
 -
 +        p4_sync("...")
          self.check()
  
          commits = []
@@@ -1315,9 -1269,22 +1315,22 @@@ class P4Sync(Command, P4UserMap)
              # 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 - "%s"' % file['depotFile'])
 +            text = p4_read_pipe(['print', '-q', '-o', '-', file['depotFile']])
              contents = [ text ]
  
+         if type_base == "apple":
+             # Apple filetype files will be streamed as a concatenation of
+             # its appledouble header and the contents.  This is useless
+             # on both macs and non-macs.  If using "print -q -o xx", it
+             # will create "xx" with the data, and "%xx" with the header.
+             # This is also not very useful.
+             #
+             # Ideally, someday, this script can learn how to generate
+             # appledouble files directly and import those to git, but
+             # non-mac machines can never find a use for apple filetype.
+             print "\nIgnoring apple filetype file %s" % file['depotFile']
+             return
          # Perhaps windows wants unicode, utf16 newlines translated too;
          # but this is not doing it.
          if self.isWindows and type_base == "text":
          # even though in theory somebody may want that.
          if type_base in ("text", "unicode", "binary"):
              if "ko" in type_mods:
 -                contents = map(lambda text: re.sub(r'(?i)\$(Id|Header):[^$]*\$', r'$\1$', text), contents)
 +                text = ''.join(contents)
 +                text = re.sub(r'\$(Id|Header):[^$]*\$', r'$\1$', text)
 +                contents = [ text ]
              elif "k" in type_mods:
 -                contents = map(lambda text: re.sub(r'\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$\n]*\$', r'$\1$', text), contents)
 +                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" % (git_mode, relPath))
  
              def streamP4FilesCbSelf(entry):
                  self.streamP4FilesCb(entry)
  
 -            p4CmdList("-x - print",
 -                '\n'.join(['%s#%s' % (f['path'], f['rev'])
 -                                                  for f in filesToRead]),
 -                cb=streamP4FilesCbSelf)
 +            fileArgs = ['%s#%s' % (f['path'], f['rev']) for f in filesToRead]
 +
 +            p4CmdList(["-x", "-", "print"],
 +                      stdin=fileArgs,
 +                      cb=streamP4FilesCbSelf)
  
              # do the last chunk
              if self.stream_file.has_key('depotFile'):
              if self.verbose:
                  print "Change %s is labelled %s" % (change, labelDetails)
  
 -            files = p4CmdList("files " + ' '.join (["%s...@%s" % (p, change)
 -                                                    for p in branchPrefixes]))
 +            files = p4CmdList(["files"] + ["%s...@%s" % (p, change)
 +                                                    for p in branchPrefixes])
  
              if len(files) == len(labelRevisions):
  
              newestChange = 0
              if self.verbose:
                  print "Querying files for label %s" % label
 -            for file in p4CmdList("files "
 -                                  +  ' '.join (["%s...@%s" % (p, label)
 -                                                for p in self.depotPaths])):
 +            for file in p4CmdList(["files"] +
 +                                      ["%s...@%s" % (p, label)
 +                                          for p in self.depotPaths]):
                  revisions[file["depotFile"]] = file["rev"]
                  change = int(file["change"])
                  if change > newestChange:
          newestRevision = 0
  
          fileCnt = 0
 -        for info in p4CmdList("files "
 -                              +  ' '.join(["%s...%s"
 -                                           % (p, revision)
 -                                           for p in self.depotPaths])):
 +        fileArgs = ["%s...%s" % (p,revision) for p in self.depotPaths]
 +
 +        for info in p4CmdList(["files"] + fileArgs):
  
              if 'code' in info and info['code'] == 'error':
                  sys.stderr.write("p4 returned an error: %s\n"