summaryrefslogtreecommitdiff
path: root/eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/hgext/convert/p4.py
diff options
context:
space:
mode:
Diffstat (limited to 'eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/hgext/convert/p4.py')
-rw-r--r--eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/hgext/convert/p4.py202
1 files changed, 202 insertions, 0 deletions
diff --git a/eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/hgext/convert/p4.py b/eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/hgext/convert/p4.py
new file mode 100644
index 0000000..5d640ad
--- /dev/null
+++ b/eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/hgext/convert/p4.py
@@ -0,0 +1,202 @@
+# Perforce source for convert extension.
+#
+# Copyright 2009, Frank Kingswood <frank@kingswood-consulting.co.uk>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+from mercurial import util
+from mercurial.i18n import _
+
+from common import commit, converter_source, checktool, NoRepo
+import marshal
+import re
+
+def loaditer(f):
+ "Yield the dictionary objects generated by p4"
+ try:
+ while True:
+ d = marshal.load(f)
+ if not d:
+ break
+ yield d
+ except EOFError:
+ pass
+
+class p4_source(converter_source):
+ def __init__(self, ui, path, rev=None):
+ super(p4_source, self).__init__(ui, path, rev=rev)
+
+ if "/" in path and not path.startswith('//'):
+ raise NoRepo(_('%s does not look like a P4 repository') % path)
+
+ checktool('p4', abort=False)
+
+ self.p4changes = {}
+ self.heads = {}
+ self.changeset = {}
+ self.files = {}
+ self.tags = {}
+ self.lastbranch = {}
+ self.parent = {}
+ self.encoding = "latin_1"
+ self.depotname = {} # mapping from local name to depot name
+ self.re_type = re.compile(
+ "([a-z]+)?(text|binary|symlink|apple|resource|unicode|utf\d+)"
+ "(\+\w+)?$")
+ self.re_keywords = re.compile(
+ r"\$(Id|Header|Date|DateTime|Change|File|Revision|Author)"
+ r":[^$\n]*\$")
+ self.re_keywords_old = re.compile("\$(Id|Header):[^$\n]*\$")
+
+ self._parse(ui, path)
+
+ def _parse_view(self, path):
+ "Read changes affecting the path"
+ cmd = 'p4 -G changes -s submitted %s' % util.shellquote(path)
+ stdout = util.popen(cmd, mode='rb')
+ for d in loaditer(stdout):
+ c = d.get("change", None)
+ if c:
+ self.p4changes[c] = True
+
+ def _parse(self, ui, path):
+ "Prepare list of P4 filenames and revisions to import"
+ ui.status(_('reading p4 views\n'))
+
+ # read client spec or view
+ if "/" in path:
+ self._parse_view(path)
+ if path.startswith("//") and path.endswith("/..."):
+ views = {path[:-3]:""}
+ else:
+ views = {"//": ""}
+ else:
+ cmd = 'p4 -G client -o %s' % util.shellquote(path)
+ clientspec = marshal.load(util.popen(cmd, mode='rb'))
+
+ views = {}
+ for client in clientspec:
+ if client.startswith("View"):
+ sview, cview = clientspec[client].split()
+ self._parse_view(sview)
+ if sview.endswith("...") and cview.endswith("..."):
+ sview = sview[:-3]
+ cview = cview[:-3]
+ cview = cview[2:]
+ cview = cview[cview.find("/") + 1:]
+ views[sview] = cview
+
+ # list of changes that affect our source files
+ self.p4changes = self.p4changes.keys()
+ self.p4changes.sort(key=int)
+
+ # list with depot pathnames, longest first
+ vieworder = views.keys()
+ vieworder.sort(key=len, reverse=True)
+
+ # handle revision limiting
+ startrev = self.ui.config('convert', 'p4.startrev', default=0)
+ self.p4changes = [x for x in self.p4changes
+ if ((not startrev or int(x) >= int(startrev)) and
+ (not self.rev or int(x) <= int(self.rev)))]
+
+ # now read the full changelists to get the list of file revisions
+ ui.status(_('collecting p4 changelists\n'))
+ lastid = None
+ for change in self.p4changes:
+ cmd = "p4 -G describe -s %s" % change
+ stdout = util.popen(cmd, mode='rb')
+ d = marshal.load(stdout)
+ desc = self.recode(d["desc"])
+ shortdesc = desc.split("\n", 1)[0]
+ t = '%s %s' % (d["change"], repr(shortdesc)[1:-1])
+ ui.status(util.ellipsis(t, 80) + '\n')
+
+ if lastid:
+ parents = [lastid]
+ else:
+ parents = []
+
+ date = (int(d["time"]), 0) # timezone not set
+ c = commit(author=self.recode(d["user"]), date=util.datestr(date),
+ parents=parents, desc=desc, branch='',
+ extra={"p4": change})
+
+ files = []
+ i = 0
+ while ("depotFile%d" % i) in d and ("rev%d" % i) in d:
+ oldname = d["depotFile%d" % i]
+ filename = None
+ for v in vieworder:
+ if oldname.startswith(v):
+ filename = views[v] + oldname[len(v):]
+ break
+ if filename:
+ files.append((filename, d["rev%d" % i]))
+ self.depotname[filename] = oldname
+ i += 1
+ self.changeset[change] = c
+ self.files[change] = files
+ lastid = change
+
+ if lastid:
+ self.heads = [lastid]
+
+ def getheads(self):
+ return self.heads
+
+ def getfile(self, name, rev):
+ cmd = 'p4 -G print %s' \
+ % util.shellquote("%s#%s" % (self.depotname[name], rev))
+ stdout = util.popen(cmd, mode='rb')
+
+ mode = None
+ contents = ""
+ keywords = None
+
+ for d in loaditer(stdout):
+ code = d["code"]
+ data = d.get("data")
+
+ if code == "error":
+ raise IOError(d["generic"], data)
+
+ elif code == "stat":
+ p4type = self.re_type.match(d["type"])
+ if p4type:
+ mode = ""
+ flags = (p4type.group(1) or "") + (p4type.group(3) or "")
+ if "x" in flags:
+ mode = "x"
+ if p4type.group(2) == "symlink":
+ mode = "l"
+ if "ko" in flags:
+ keywords = self.re_keywords_old
+ elif "k" in flags:
+ keywords = self.re_keywords
+
+ elif code == "text" or code == "binary":
+ contents += data
+
+ if mode is None:
+ raise IOError(0, "bad stat")
+
+ if keywords:
+ contents = keywords.sub("$\\1$", contents)
+ if mode == "l" and contents.endswith("\n"):
+ contents = contents[:-1]
+
+ return contents, mode
+
+ def getchanges(self, rev):
+ return self.files[rev], {}
+
+ def getcommit(self, rev):
+ return self.changeset[rev]
+
+ def gettags(self):
+ return self.tags
+
+ def getchangedfiles(self, rev, i):
+ return sorted([x[0] for x in self.files[rev]])