29 |
29 |
30 class gnuarch_source(common.converter_source, common.commandline): |
30 class gnuarch_source(common.converter_source, common.commandline): |
31 class gnuarch_rev(object): |
31 class gnuarch_rev(object): |
32 def __init__(self, rev): |
32 def __init__(self, rev): |
33 self.rev = rev |
33 self.rev = rev |
34 self.summary = '' |
34 self.summary = b'' |
35 self.date = None |
35 self.date = None |
36 self.author = '' |
36 self.author = b'' |
37 self.continuationof = None |
37 self.continuationof = None |
38 self.add_files = [] |
38 self.add_files = [] |
39 self.mod_files = [] |
39 self.mod_files = [] |
40 self.del_files = [] |
40 self.del_files = [] |
41 self.ren_files = {} |
41 self.ren_files = {} |
42 self.ren_dirs = {} |
42 self.ren_dirs = {} |
43 |
43 |
44 def __init__(self, ui, repotype, path, revs=None): |
44 def __init__(self, ui, repotype, path, revs=None): |
45 super(gnuarch_source, self).__init__(ui, repotype, path, revs=revs) |
45 super(gnuarch_source, self).__init__(ui, repotype, path, revs=revs) |
46 |
46 |
47 if not os.path.exists(os.path.join(path, '{arch}')): |
47 if not os.path.exists(os.path.join(path, b'{arch}')): |
48 raise common.NoRepo( |
48 raise common.NoRepo( |
49 _("%s does not look like a GNU Arch repository") % path |
49 _(b"%s does not look like a GNU Arch repository") % path |
50 ) |
50 ) |
51 |
51 |
52 # Could use checktool, but we want to check for baz or tla. |
52 # Could use checktool, but we want to check for baz or tla. |
53 self.execmd = None |
53 self.execmd = None |
54 if procutil.findexe('baz'): |
54 if procutil.findexe(b'baz'): |
55 self.execmd = 'baz' |
55 self.execmd = b'baz' |
56 else: |
56 else: |
57 if procutil.findexe('tla'): |
57 if procutil.findexe(b'tla'): |
58 self.execmd = 'tla' |
58 self.execmd = b'tla' |
59 else: |
59 else: |
60 raise error.Abort(_('cannot find a GNU Arch tool')) |
60 raise error.Abort(_(b'cannot find a GNU Arch tool')) |
61 |
61 |
62 common.commandline.__init__(self, ui, self.execmd) |
62 common.commandline.__init__(self, ui, self.execmd) |
63 |
63 |
64 self.path = os.path.realpath(path) |
64 self.path = os.path.realpath(path) |
65 self.tmppath = None |
65 self.tmppath = None |
74 self.archives = [] |
74 self.archives = [] |
75 |
75 |
76 def before(self): |
76 def before(self): |
77 # Get registered archives |
77 # Get registered archives |
78 self.archives = [ |
78 self.archives = [ |
79 i.rstrip('\n') for i in self.runlines0('archives', '-n') |
79 i.rstrip(b'\n') for i in self.runlines0(b'archives', b'-n') |
80 ] |
80 ] |
81 |
81 |
82 if self.execmd == 'tla': |
82 if self.execmd == b'tla': |
83 output = self.run0('tree-version', self.path) |
83 output = self.run0(b'tree-version', self.path) |
84 else: |
84 else: |
85 output = self.run0('tree-version', '-d', self.path) |
85 output = self.run0(b'tree-version', b'-d', self.path) |
86 self.treeversion = output.strip() |
86 self.treeversion = output.strip() |
87 |
87 |
88 # Get name of temporary directory |
88 # Get name of temporary directory |
89 version = self.treeversion.split('/') |
89 version = self.treeversion.split(b'/') |
90 self.tmppath = os.path.join( |
90 self.tmppath = os.path.join( |
91 pycompat.fsencode(tempfile.gettempdir()), 'hg-%s' % version[1] |
91 pycompat.fsencode(tempfile.gettempdir()), b'hg-%s' % version[1] |
92 ) |
92 ) |
93 |
93 |
94 # Generate parents dictionary |
94 # Generate parents dictionary |
95 self.parents[None] = [] |
95 self.parents[None] = [] |
96 treeversion = self.treeversion |
96 treeversion = self.treeversion |
97 child = None |
97 child = None |
98 while treeversion: |
98 while treeversion: |
99 self.ui.status(_('analyzing tree version %s...\n') % treeversion) |
99 self.ui.status(_(b'analyzing tree version %s...\n') % treeversion) |
100 |
100 |
101 archive = treeversion.split('/')[0] |
101 archive = treeversion.split(b'/')[0] |
102 if archive not in self.archives: |
102 if archive not in self.archives: |
103 self.ui.status( |
103 self.ui.status( |
104 _( |
104 _( |
105 'tree analysis stopped because it points to ' |
105 b'tree analysis stopped because it points to ' |
106 'an unregistered archive %s...\n' |
106 b'an unregistered archive %s...\n' |
107 ) |
107 ) |
108 % archive |
108 % archive |
109 ) |
109 ) |
110 break |
110 break |
111 |
111 |
112 # Get the complete list of revisions for that tree version |
112 # Get the complete list of revisions for that tree version |
113 output, status = self.runlines('revisions', '-r', '-f', treeversion) |
113 output, status = self.runlines( |
|
114 b'revisions', b'-r', b'-f', treeversion |
|
115 ) |
114 self.checkexit( |
116 self.checkexit( |
115 status, 'failed retrieving revisions for %s' % treeversion |
117 status, b'failed retrieving revisions for %s' % treeversion |
116 ) |
118 ) |
117 |
119 |
118 # No new iteration unless a revision has a continuation-of header |
120 # No new iteration unless a revision has a continuation-of header |
119 treeversion = None |
121 treeversion = None |
120 |
122 |
138 |
140 |
139 # Check if we have to follow the usual incremental history |
141 # Check if we have to follow the usual incremental history |
140 # or if we have to 'jump' to a different treeversion given |
142 # or if we have to 'jump' to a different treeversion given |
141 # by the continuation-of header. |
143 # by the continuation-of header. |
142 if self.changes[rev].continuationof: |
144 if self.changes[rev].continuationof: |
143 treeversion = '--'.join( |
145 treeversion = b'--'.join( |
144 self.changes[rev].continuationof.split('--')[:-1] |
146 self.changes[rev].continuationof.split(b'--')[:-1] |
145 ) |
147 ) |
146 break |
148 break |
147 |
149 |
148 # If we reached a base-0 revision w/o any continuation-of |
150 # If we reached a base-0 revision w/o any continuation-of |
149 # header, it means the tree history ends here. |
151 # header, it means the tree history ends here. |
150 if rev[-6:] == 'base-0': |
152 if rev[-6:] == b'base-0': |
151 break |
153 break |
152 |
154 |
153 def after(self): |
155 def after(self): |
154 self.ui.debug('cleaning up %s\n' % self.tmppath) |
156 self.ui.debug(b'cleaning up %s\n' % self.tmppath) |
155 shutil.rmtree(self.tmppath, ignore_errors=True) |
157 shutil.rmtree(self.tmppath, ignore_errors=True) |
156 |
158 |
157 def getheads(self): |
159 def getheads(self): |
158 return self.parents[None] |
160 return self.parents[None] |
159 |
161 |
160 def getfile(self, name, rev): |
162 def getfile(self, name, rev): |
161 if rev != self.lastrev: |
163 if rev != self.lastrev: |
162 raise error.Abort(_('internal calling inconsistency')) |
164 raise error.Abort(_(b'internal calling inconsistency')) |
163 |
165 |
164 if not os.path.lexists(os.path.join(self.tmppath, name)): |
166 if not os.path.lexists(os.path.join(self.tmppath, name)): |
165 return None, None |
167 return None, None |
166 |
168 |
167 return self._getfile(name, rev) |
169 return self._getfile(name, rev) |
168 |
170 |
169 def getchanges(self, rev, full): |
171 def getchanges(self, rev, full): |
170 if full: |
172 if full: |
171 raise error.Abort(_("convert from arch does not support --full")) |
173 raise error.Abort(_(b"convert from arch does not support --full")) |
172 self._update(rev) |
174 self._update(rev) |
173 changes = [] |
175 changes = [] |
174 copies = {} |
176 copies = {} |
175 |
177 |
176 for f in self.changes[rev].add_files: |
178 for f in self.changes[rev].add_files: |
212 |
214 |
213 def _execute(self, cmd, *args, **kwargs): |
215 def _execute(self, cmd, *args, **kwargs): |
214 cmdline = [self.execmd, cmd] |
216 cmdline = [self.execmd, cmd] |
215 cmdline += args |
217 cmdline += args |
216 cmdline = [procutil.shellquote(arg) for arg in cmdline] |
218 cmdline = [procutil.shellquote(arg) for arg in cmdline] |
217 cmdline += ['>', os.devnull, '2>', os.devnull] |
219 cmdline += [b'>', os.devnull, b'2>', os.devnull] |
218 cmdline = procutil.quotecommand(' '.join(cmdline)) |
220 cmdline = procutil.quotecommand(b' '.join(cmdline)) |
219 self.ui.debug(cmdline, '\n') |
221 self.ui.debug(cmdline, b'\n') |
220 return os.system(pycompat.rapply(procutil.tonativestr, cmdline)) |
222 return os.system(pycompat.rapply(procutil.tonativestr, cmdline)) |
221 |
223 |
222 def _update(self, rev): |
224 def _update(self, rev): |
223 self.ui.debug('applying revision %s...\n' % rev) |
225 self.ui.debug(b'applying revision %s...\n' % rev) |
224 changeset, status = self.runlines('replay', '-d', self.tmppath, rev) |
226 changeset, status = self.runlines(b'replay', b'-d', self.tmppath, rev) |
225 if status: |
227 if status: |
226 # Something went wrong while merging (baz or tla |
228 # Something went wrong while merging (baz or tla |
227 # issue?), get latest revision and try from there |
229 # issue?), get latest revision and try from there |
228 shutil.rmtree(self.tmppath, ignore_errors=True) |
230 shutil.rmtree(self.tmppath, ignore_errors=True) |
229 self._obtainrevision(rev) |
231 self._obtainrevision(rev) |
230 else: |
232 else: |
231 old_rev = self.parents[rev][0] |
233 old_rev = self.parents[rev][0] |
232 self.ui.debug( |
234 self.ui.debug( |
233 'computing changeset between %s and %s...\n' % (old_rev, rev) |
235 b'computing changeset between %s and %s...\n' % (old_rev, rev) |
234 ) |
236 ) |
235 self._parsechangeset(changeset, rev) |
237 self._parsechangeset(changeset, rev) |
236 |
238 |
237 def _getfile(self, name, rev): |
239 def _getfile(self, name, rev): |
238 mode = os.lstat(os.path.join(self.tmppath, name)).st_mode |
240 mode = os.lstat(os.path.join(self.tmppath, name)).st_mode |
239 if stat.S_ISLNK(mode): |
241 if stat.S_ISLNK(mode): |
240 data = util.readlink(os.path.join(self.tmppath, name)) |
242 data = util.readlink(os.path.join(self.tmppath, name)) |
241 if mode: |
243 if mode: |
242 mode = 'l' |
244 mode = b'l' |
243 else: |
245 else: |
244 mode = '' |
246 mode = b'' |
245 else: |
247 else: |
246 data = util.readfile(os.path.join(self.tmppath, name)) |
248 data = util.readfile(os.path.join(self.tmppath, name)) |
247 mode = (mode & 0o111) and 'x' or '' |
249 mode = (mode & 0o111) and b'x' or b'' |
248 return data, mode |
250 return data, mode |
249 |
251 |
250 def _exclude(self, name): |
252 def _exclude(self, name): |
251 exclude = ['{arch}', '.arch-ids', '.arch-inventory'] |
253 exclude = [b'{arch}', b'.arch-ids', b'.arch-inventory'] |
252 for exc in exclude: |
254 for exc in exclude: |
253 if name.find(exc) != -1: |
255 if name.find(exc) != -1: |
254 return True |
256 return True |
255 return False |
257 return False |
256 |
258 |
280 changes.append(d) |
282 changes.append(d) |
281 copies[d] = s |
283 copies[d] = s |
282 return changes, copies |
284 return changes, copies |
283 |
285 |
284 def _obtainrevision(self, rev): |
286 def _obtainrevision(self, rev): |
285 self.ui.debug('obtaining revision %s...\n' % rev) |
287 self.ui.debug(b'obtaining revision %s...\n' % rev) |
286 output = self._execute('get', rev, self.tmppath) |
288 output = self._execute(b'get', rev, self.tmppath) |
287 self.checkexit(output) |
289 self.checkexit(output) |
288 self.ui.debug('analyzing revision %s...\n' % rev) |
290 self.ui.debug(b'analyzing revision %s...\n' % rev) |
289 files = self._readcontents(self.tmppath) |
291 files = self._readcontents(self.tmppath) |
290 self.changes[rev].add_files += files |
292 self.changes[rev].add_files += files |
291 |
293 |
292 def _stripbasepath(self, path): |
294 def _stripbasepath(self, path): |
293 if path.startswith('./'): |
295 if path.startswith(b'./'): |
294 return path[2:] |
296 return path[2:] |
295 return path |
297 return path |
296 |
298 |
297 def _parsecatlog(self, data, rev): |
299 def _parsecatlog(self, data, rev): |
298 try: |
300 try: |
299 catlog = self.catlogparser.parsestr(data) |
301 catlog = self.catlogparser.parsestr(data) |
300 |
302 |
301 # Commit date |
303 # Commit date |
302 self.changes[rev].date = dateutil.datestr( |
304 self.changes[rev].date = dateutil.datestr( |
303 dateutil.strdate(catlog['Standard-date'], '%Y-%m-%d %H:%M:%S') |
305 dateutil.strdate(catlog[b'Standard-date'], b'%Y-%m-%d %H:%M:%S') |
304 ) |
306 ) |
305 |
307 |
306 # Commit author |
308 # Commit author |
307 self.changes[rev].author = self.recode(catlog['Creator']) |
309 self.changes[rev].author = self.recode(catlog[b'Creator']) |
308 |
310 |
309 # Commit description |
311 # Commit description |
310 self.changes[rev].summary = '\n\n'.join( |
312 self.changes[rev].summary = b'\n\n'.join( |
311 (catlog['Summary'], catlog.get_payload()) |
313 (catlog[b'Summary'], catlog.get_payload()) |
312 ) |
314 ) |
313 self.changes[rev].summary = self.recode(self.changes[rev].summary) |
315 self.changes[rev].summary = self.recode(self.changes[rev].summary) |
314 |
316 |
315 # Commit revision origin when dealing with a branch or tag |
317 # Commit revision origin when dealing with a branch or tag |
316 if 'Continuation-of' in catlog: |
318 if b'Continuation-of' in catlog: |
317 self.changes[rev].continuationof = self.recode( |
319 self.changes[rev].continuationof = self.recode( |
318 catlog['Continuation-of'] |
320 catlog[b'Continuation-of'] |
319 ) |
321 ) |
320 except Exception: |
322 except Exception: |
321 raise error.Abort(_('could not parse cat-log of %s') % rev) |
323 raise error.Abort(_(b'could not parse cat-log of %s') % rev) |
322 |
324 |
323 def _parsechangeset(self, data, rev): |
325 def _parsechangeset(self, data, rev): |
324 for l in data: |
326 for l in data: |
325 l = l.strip() |
327 l = l.strip() |
326 # Added file (ignore added directory) |
328 # Added file (ignore added directory) |
327 if l.startswith('A') and not l.startswith('A/'): |
329 if l.startswith(b'A') and not l.startswith(b'A/'): |
328 file = self._stripbasepath(l[1:].strip()) |
330 file = self._stripbasepath(l[1:].strip()) |
329 if not self._exclude(file): |
331 if not self._exclude(file): |
330 self.changes[rev].add_files.append(file) |
332 self.changes[rev].add_files.append(file) |
331 # Deleted file (ignore deleted directory) |
333 # Deleted file (ignore deleted directory) |
332 elif l.startswith('D') and not l.startswith('D/'): |
334 elif l.startswith(b'D') and not l.startswith(b'D/'): |
333 file = self._stripbasepath(l[1:].strip()) |
335 file = self._stripbasepath(l[1:].strip()) |
334 if not self._exclude(file): |
336 if not self._exclude(file): |
335 self.changes[rev].del_files.append(file) |
337 self.changes[rev].del_files.append(file) |
336 # Modified binary file |
338 # Modified binary file |
337 elif l.startswith('Mb'): |
339 elif l.startswith(b'Mb'): |
338 file = self._stripbasepath(l[2:].strip()) |
340 file = self._stripbasepath(l[2:].strip()) |
339 if not self._exclude(file): |
341 if not self._exclude(file): |
340 self.changes[rev].mod_files.append(file) |
342 self.changes[rev].mod_files.append(file) |
341 # Modified link |
343 # Modified link |
342 elif l.startswith('M->'): |
344 elif l.startswith(b'M->'): |
343 file = self._stripbasepath(l[3:].strip()) |
345 file = self._stripbasepath(l[3:].strip()) |
344 if not self._exclude(file): |
346 if not self._exclude(file): |
345 self.changes[rev].mod_files.append(file) |
347 self.changes[rev].mod_files.append(file) |
346 # Modified file |
348 # Modified file |
347 elif l.startswith('M'): |
349 elif l.startswith(b'M'): |
348 file = self._stripbasepath(l[1:].strip()) |
350 file = self._stripbasepath(l[1:].strip()) |
349 if not self._exclude(file): |
351 if not self._exclude(file): |
350 self.changes[rev].mod_files.append(file) |
352 self.changes[rev].mod_files.append(file) |
351 # Renamed file (or link) |
353 # Renamed file (or link) |
352 elif l.startswith('=>'): |
354 elif l.startswith(b'=>'): |
353 files = l[2:].strip().split(' ') |
355 files = l[2:].strip().split(b' ') |
354 if len(files) == 1: |
356 if len(files) == 1: |
355 files = l[2:].strip().split('\t') |
357 files = l[2:].strip().split(b'\t') |
356 src = self._stripbasepath(files[0]) |
358 src = self._stripbasepath(files[0]) |
357 dst = self._stripbasepath(files[1]) |
359 dst = self._stripbasepath(files[1]) |
358 if not self._exclude(src) and not self._exclude(dst): |
360 if not self._exclude(src) and not self._exclude(dst): |
359 self.changes[rev].ren_files[src] = dst |
361 self.changes[rev].ren_files[src] = dst |
360 # Conversion from file to link or from link to file (modified) |
362 # Conversion from file to link or from link to file (modified) |
361 elif l.startswith('ch'): |
363 elif l.startswith(b'ch'): |
362 file = self._stripbasepath(l[2:].strip()) |
364 file = self._stripbasepath(l[2:].strip()) |
363 if not self._exclude(file): |
365 if not self._exclude(file): |
364 self.changes[rev].mod_files.append(file) |
366 self.changes[rev].mod_files.append(file) |
365 # Renamed directory |
367 # Renamed directory |
366 elif l.startswith('/>'): |
368 elif l.startswith(b'/>'): |
367 dirs = l[2:].strip().split(' ') |
369 dirs = l[2:].strip().split(b' ') |
368 if len(dirs) == 1: |
370 if len(dirs) == 1: |
369 dirs = l[2:].strip().split('\t') |
371 dirs = l[2:].strip().split(b'\t') |
370 src = self._stripbasepath(dirs[0]) |
372 src = self._stripbasepath(dirs[0]) |
371 dst = self._stripbasepath(dirs[1]) |
373 dst = self._stripbasepath(dirs[1]) |
372 if not self._exclude(src) and not self._exclude(dst): |
374 if not self._exclude(src) and not self._exclude(dst): |
373 self.changes[rev].ren_dirs[src] = dst |
375 self.changes[rev].ren_dirs[src] = dst |