##// END OF EJS Templates
convert: Work around p4 instability (issue2465)...
Mike Sperber -
r12891:b69fd38a stable
parent child Browse files
Show More
@@ -1,203 +1,202 b''
1 1 # Perforce source for convert extension.
2 2 #
3 3 # Copyright 2009, Frank Kingswood <frank@kingswood-consulting.co.uk>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from mercurial import util
9 9 from mercurial.i18n import _
10 10
11 11 from common import commit, converter_source, checktool, NoRepo
12 12 import marshal
13 13 import re
14 14
15 15 def loaditer(f):
16 16 "Yield the dictionary objects generated by p4"
17 17 try:
18 18 while True:
19 19 d = marshal.load(f)
20 20 if not d:
21 21 break
22 22 yield d
23 23 except EOFError:
24 24 pass
25 25
26 26 class p4_source(converter_source):
27 27 def __init__(self, ui, path, rev=None):
28 28 super(p4_source, self).__init__(ui, path, rev=rev)
29 29
30 30 if "/" in path and not path.startswith('//'):
31 31 raise NoRepo(_('%s does not look like a P4 repository') % path)
32 32
33 33 checktool('p4', abort=False)
34 34
35 35 self.p4changes = {}
36 36 self.heads = {}
37 37 self.changeset = {}
38 38 self.files = {}
39 39 self.tags = {}
40 40 self.lastbranch = {}
41 41 self.parent = {}
42 42 self.encoding = "latin_1"
43 43 self.depotname = {} # mapping from local name to depot name
44 44 self.re_type = re.compile(
45 45 "([a-z]+)?(text|binary|symlink|apple|resource|unicode|utf\d+)"
46 46 "(\+\w+)?$")
47 47 self.re_keywords = re.compile(
48 48 r"\$(Id|Header|Date|DateTime|Change|File|Revision|Author)"
49 49 r":[^$\n]*\$")
50 50 self.re_keywords_old = re.compile("\$(Id|Header):[^$\n]*\$")
51 51
52 52 self._parse(ui, path)
53 53
54 54 def _parse_view(self, path):
55 55 "Read changes affecting the path"
56 56 cmd = 'p4 -G changes -s submitted %s' % util.shellquote(path)
57 57 stdout = util.popen(cmd, mode='rb')
58 58 for d in loaditer(stdout):
59 59 c = d.get("change", None)
60 60 if c:
61 61 self.p4changes[c] = True
62 62
63 63 def _parse(self, ui, path):
64 64 "Prepare list of P4 filenames and revisions to import"
65 65 ui.status(_('reading p4 views\n'))
66 66
67 67 # read client spec or view
68 68 if "/" in path:
69 69 self._parse_view(path)
70 70 if path.startswith("//") and path.endswith("/..."):
71 71 views = {path[:-3]:""}
72 72 else:
73 73 views = {"//": ""}
74 74 else:
75 75 cmd = 'p4 -G client -o %s' % util.shellquote(path)
76 76 clientspec = marshal.load(util.popen(cmd, mode='rb'))
77 77
78 78 views = {}
79 79 for client in clientspec:
80 80 if client.startswith("View"):
81 81 sview, cview = clientspec[client].split()
82 82 self._parse_view(sview)
83 83 if sview.endswith("...") and cview.endswith("..."):
84 84 sview = sview[:-3]
85 85 cview = cview[:-3]
86 86 cview = cview[2:]
87 87 cview = cview[cview.find("/") + 1:]
88 88 views[sview] = cview
89 89
90 90 # list of changes that affect our source files
91 91 self.p4changes = self.p4changes.keys()
92 92 self.p4changes.sort(key=int)
93 93
94 94 # list with depot pathnames, longest first
95 95 vieworder = views.keys()
96 96 vieworder.sort(key=len, reverse=True)
97 97
98 98 # handle revision limiting
99 99 startrev = self.ui.config('convert', 'p4.startrev', default=0)
100 100 self.p4changes = [x for x in self.p4changes
101 101 if ((not startrev or int(x) >= int(startrev)) and
102 102 (not self.rev or int(x) <= int(self.rev)))]
103 103
104 104 # now read the full changelists to get the list of file revisions
105 105 ui.status(_('collecting p4 changelists\n'))
106 106 lastid = None
107 107 for change in self.p4changes:
108 cmd = "p4 -G describe %s" % change
108 cmd = "p4 -G describe -s %s" % change
109 109 stdout = util.popen(cmd, mode='rb')
110 110 d = marshal.load(stdout)
111
112 111 desc = self.recode(d["desc"])
113 112 shortdesc = desc.split("\n", 1)[0]
114 113 t = '%s %s' % (d["change"], repr(shortdesc)[1:-1])
115 114 ui.status(util.ellipsis(t, 80) + '\n')
116 115
117 116 if lastid:
118 117 parents = [lastid]
119 118 else:
120 119 parents = []
121 120
122 121 date = (int(d["time"]), 0) # timezone not set
123 122 c = commit(author=self.recode(d["user"]), date=util.datestr(date),
124 123 parents=parents, desc=desc, branch='',
125 124 extra={"p4": change})
126 125
127 126 files = []
128 127 i = 0
129 128 while ("depotFile%d" % i) in d and ("rev%d" % i) in d:
130 129 oldname = d["depotFile%d" % i]
131 130 filename = None
132 131 for v in vieworder:
133 132 if oldname.startswith(v):
134 133 filename = views[v] + oldname[len(v):]
135 134 break
136 135 if filename:
137 136 files.append((filename, d["rev%d" % i]))
138 137 self.depotname[filename] = oldname
139 138 i += 1
140 139 self.changeset[change] = c
141 140 self.files[change] = files
142 141 lastid = change
143 142
144 143 if lastid:
145 144 self.heads = [lastid]
146 145
147 146 def getheads(self):
148 147 return self.heads
149 148
150 149 def getfile(self, name, rev):
151 150 cmd = 'p4 -G print %s' \
152 151 % util.shellquote("%s#%s" % (self.depotname[name], rev))
153 152 stdout = util.popen(cmd, mode='rb')
154 153
155 154 mode = None
156 155 contents = ""
157 156 keywords = None
158 157
159 158 for d in loaditer(stdout):
160 159 code = d["code"]
161 160 data = d.get("data")
162 161
163 162 if code == "error":
164 163 raise IOError(d["generic"], data)
165 164
166 165 elif code == "stat":
167 166 p4type = self.re_type.match(d["type"])
168 167 if p4type:
169 168 mode = ""
170 169 flags = (p4type.group(1) or "") + (p4type.group(3) or "")
171 170 if "x" in flags:
172 171 mode = "x"
173 172 if p4type.group(2) == "symlink":
174 173 mode = "l"
175 174 if "ko" in flags:
176 175 keywords = self.re_keywords_old
177 176 elif "k" in flags:
178 177 keywords = self.re_keywords
179 178
180 179 elif code == "text" or code == "binary":
181 180 contents += data
182 181
183 182 if mode is None:
184 183 raise IOError(0, "bad stat")
185 184
186 185 if keywords:
187 186 contents = keywords.sub("$\\1$", contents)
188 187 if mode == "l" and contents.endswith("\n"):
189 188 contents = contents[:-1]
190 189
191 190 return contents, mode
192 191
193 192 def getchanges(self, rev):
194 193 return self.files[rev], {}
195 194
196 195 def getcommit(self, rev):
197 196 return self.changeset[rev]
198 197
199 198 def gettags(self):
200 199 return self.tags
201 200
202 201 def getchangedfiles(self, rev, i):
203 202 return sorted([x[0] for x in self.files[rev]])
General Comments 0
You need to be logged in to leave comments. Login now