76 tree = self.xml( |
76 tree = self.xml( |
77 b'changes', xml_output=True, summary=True, repodir=self.path |
77 b'changes', xml_output=True, summary=True, repodir=self.path |
78 ) |
78 ) |
79 tagname = None |
79 tagname = None |
80 child = None |
80 child = None |
81 for elt in tree.findall(b'patch'): |
81 for elt in tree.findall('patch'): |
82 node = elt.get(b'hash') |
82 node = self.recode(elt.get('hash')) |
83 name = elt.findtext(b'name', b'') |
83 name = self.recode(elt.findtext('name', '')) |
84 if name.startswith(b'TAG '): |
84 if name.startswith(b'TAG '): |
85 tagname = name[4:].strip() |
85 tagname = name[4:].strip() |
86 elif tagname is not None: |
86 elif tagname is not None: |
87 self.tags[tagname] = node |
87 self.tags[tagname] = node |
88 tagname = None |
88 tagname = None |
108 # patch metadata byte-for-byte, even in the XML changelog. |
108 # patch metadata byte-for-byte, even in the XML changelog. |
109 etree = ElementTree() |
109 etree = ElementTree() |
110 # While we are decoding the XML as latin-1 to be as liberal as |
110 # While we are decoding the XML as latin-1 to be as liberal as |
111 # possible, etree will still raise an exception if any |
111 # possible, etree will still raise an exception if any |
112 # non-printable characters are in the XML changelog. |
112 # non-printable characters are in the XML changelog. |
113 parser = XMLParser(encoding=b'latin-1') |
113 parser = XMLParser(encoding='latin-1') |
114 p = self._run(cmd, **kwargs) |
114 p = self._run(cmd, **kwargs) |
115 etree.parse(p.stdout, parser=parser) |
115 etree.parse(p.stdout, parser=parser) |
116 p.wait() |
116 p.wait() |
117 self.checkexit(p.returncode) |
117 self.checkexit(p.returncode) |
118 return etree.getroot() |
118 return etree.getroot() |
119 |
119 |
120 def format(self): |
120 def format(self): |
121 output, status = self.run(b'show', b'repo', repodir=self.path) |
121 output, status = self.run(b'show', b'repo', repodir=self.path) |
122 self.checkexit(status) |
122 self.checkexit(status) |
123 m = re.search(r'^\s*Format:\s*(.*)$', output, re.MULTILINE) |
123 m = re.search(br'^\s*Format:\s*(.*)$', output, re.MULTILINE) |
124 if not m: |
124 if not m: |
125 return None |
125 return None |
126 return b','.join(sorted(f.strip() for f in m.group(1).split(b','))) |
126 return b','.join(sorted(f.strip() for f in m.group(1).split(b','))) |
127 |
127 |
128 def manifest(self): |
128 def manifest(self): |
141 return self.parents[None] |
141 return self.parents[None] |
142 |
142 |
143 def getcommit(self, rev): |
143 def getcommit(self, rev): |
144 elt = self.changes[rev] |
144 elt = self.changes[rev] |
145 dateformat = b'%a %b %d %H:%M:%S %Z %Y' |
145 dateformat = b'%a %b %d %H:%M:%S %Z %Y' |
146 date = dateutil.strdate(elt.get(b'local_date'), dateformat) |
146 date = dateutil.strdate(elt.get('local_date'), dateformat) |
147 desc = elt.findtext(b'name') + b'\n' + elt.findtext(b'comment', b'') |
147 desc = elt.findtext('name') + '\n' + elt.findtext('comment', '') |
148 # etree can return unicode objects for name, comment, and author, |
148 # etree can return unicode objects for name, comment, and author, |
149 # so recode() is used to ensure str objects are emitted. |
149 # so recode() is used to ensure str objects are emitted. |
150 newdateformat = b'%Y-%m-%d %H:%M:%S %1%2' |
150 newdateformat = b'%Y-%m-%d %H:%M:%S %1%2' |
151 return common.commit( |
151 return common.commit( |
152 author=self.recode(elt.get(b'author')), |
152 author=self.recode(elt.get('author')), |
153 date=dateutil.datestr(date, newdateformat), |
153 date=dateutil.datestr(date, newdateformat), |
154 desc=self.recode(desc).strip(), |
154 desc=self.recode(desc).strip(), |
155 parents=self.parents[rev], |
155 parents=self.parents[rev], |
156 ) |
156 ) |
157 |
157 |
158 def pull(self, rev): |
158 def pull(self, rev): |
159 output, status = self.run( |
159 output, status = self.run( |
160 b'pull', |
160 b'pull', |
161 self.path, |
161 self.path, |
162 all=True, |
162 all=True, |
163 match=b'hash %s' % rev, |
163 match=b'hash %s' % self.recode(rev), |
164 no_test=True, |
164 no_test=True, |
165 no_posthook=True, |
165 no_posthook=True, |
166 external_merge=b'/bin/false', |
166 external_merge=b'/bin/false', |
167 repodir=self.tmppath, |
167 repodir=self.tmppath, |
168 ) |
168 ) |
176 if full: |
176 if full: |
177 raise error.Abort(_(b"convert from darcs does not support --full")) |
177 raise error.Abort(_(b"convert from darcs does not support --full")) |
178 copies = {} |
178 copies = {} |
179 changes = [] |
179 changes = [] |
180 man = None |
180 man = None |
181 for elt in self.changes[rev].find(b'summary').getchildren(): |
181 for elt in self.changes[rev].find('summary').getchildren(): |
182 if elt.tag in (b'add_directory', b'remove_directory'): |
182 if elt.tag in ('add_directory', 'remove_directory'): |
183 continue |
183 continue |
184 if elt.tag == b'move': |
184 if elt.tag == 'move': |
185 if man is None: |
185 if man is None: |
186 man = self.manifest() |
186 man = self.manifest() |
187 source, dest = elt.get(b'from'), elt.get(b'to') |
187 source = self.recode(elt.get('from')) |
|
188 dest = self.recode(elt.get('to')) |
188 if source in man: |
189 if source in man: |
189 # File move |
190 # File move |
190 changes.append((source, rev)) |
191 changes.append((source, rev)) |
191 changes.append((dest, rev)) |
192 changes.append((dest, rev)) |
192 copies[dest] = source |
193 copies[dest] = source |
199 fdest = dest + b'/' + f[len(source) :] |
200 fdest = dest + b'/' + f[len(source) :] |
200 changes.append((f, rev)) |
201 changes.append((f, rev)) |
201 changes.append((fdest, rev)) |
202 changes.append((fdest, rev)) |
202 copies[fdest] = f |
203 copies[fdest] = f |
203 else: |
204 else: |
204 changes.append((elt.text.strip(), rev)) |
205 changes.append((self.recode(elt.text.strip()), rev)) |
205 self.pull(rev) |
206 self.pull(rev) |
206 self.lastrev = rev |
207 self.lastrev = rev |
207 return sorted(changes), copies, set() |
208 return sorted(changes), copies, set() |
208 |
209 |
209 def getfile(self, name, rev): |
210 def getfile(self, name, rev): |