##// END OF EJS Templates
keepalive: attempt to fix issue1003...
keepalive: attempt to fix issue1003 This is a reimport of the relevant piece of the upstream urlgrabber, which appears to be more correct.

File last commit:

r7875:553aa0cb default
r8146:4f13ed6e default
Show More
gnuarch.py
335 lines | 12.3 KiB | text/x-python | PythonLexer
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 # GNU Arch support for the convert extension
Joel Rosdahl
Remove unused imports
r6212 from common import NoRepo, commandline, commit, converter_source
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 from mercurial.i18n import _
from mercurial import util
Edouard Gomez
convert/gnuarch: set prefered locale for str conversions...
r7579 import os, shutil, tempfile, stat, locale
Edouard Gomez
convert/gnuarch: fix cat-log parsing...
r7578 from email.Parser import Parser
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
class gnuarch_source(converter_source, commandline):
class gnuarch_rev:
def __init__(self, rev):
self.rev = rev
self.summary = ''
self.date = None
self.author = ''
Edouard Gomez
convert/gnuarch: parse continuation-of revisions in gnuarch source...
r7583 self.continuationof = None
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 self.add_files = []
self.mod_files = []
self.del_files = []
self.ren_files = {}
self.ren_dirs = {}
def __init__(self, ui, path, rev=None):
super(gnuarch_source, self).__init__(ui, path, rev=rev)
if not os.path.exists(os.path.join(path, '{arch}')):
Martin Geisler
move % out of translatable strings...
r6913 raise NoRepo(_("%s does not look like a GNU Arch repo") % path)
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
# Could use checktool, but we want to check for baz or tla.
self.execmd = None
Patrick Mezard
convert: detect baz before tla...
r6083 if util.find_exe('baz'):
self.execmd = 'baz'
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 else:
Patrick Mezard
convert: detect baz before tla...
r6083 if util.find_exe('tla'):
self.execmd = 'tla'
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 else:
raise util.Abort(_('cannot find a GNU Arch tool'))
commandline.__init__(self, ui, self.execmd)
self.path = os.path.realpath(path)
self.tmppath = None
self.treeversion = None
self.lastrev = None
self.changes = {}
self.parents = {}
self.tags = {}
self.modecache = {}
Edouard Gomez
convert/gnuarch: fix cat-log parsing...
r7578 self.catlogparser = Parser()
Edouard Gomez
convert/gnuarch: set prefered locale for str conversions...
r7579 self.locale = locale.getpreferredencoding()
Edouard Gomez
convert/gnuarch: retrieve known archive names list...
r7584 self.archives = []
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
def before(self):
Edouard Gomez
convert/gnuarch: retrieve known archive names list...
r7584 # Get registered archives
self.archives = [i.rstrip('\n')
for i in self.runlines0('archives', '-n')]
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 if self.execmd == 'tla':
output = self.run0('tree-version', self.path)
else:
output = self.run0('tree-version', '-d', self.path)
self.treeversion = output.strip()
# Get name of temporary directory
version = self.treeversion.split('/')
self.tmppath = os.path.join(tempfile.gettempdir(),
'hg-%s' % version[1])
# Generate parents dictionary
Edouard Gomez
convert/gnuarch: follow continuation-of revisions...
r7585 self.parents[None] = []
treeversion = self.treeversion
child = None
while treeversion:
self.ui.status(_('analyzing tree version %s...\n') % treeversion)
archive = treeversion.split('/')[0]
if archive not in self.archives:
self.ui.status(_('tree analysis stopped because it points to an unregistered archive %s...\n') % archive)
break
# Get the complete list of revisions for that tree version
output, status = self.runlines('revisions', '-r', '-f', treeversion)
self.checkexit(status, 'failed retrieveing revisions for %s' % treeversion)
# No new iteration unless a revision has a continuation-of header
treeversion = None
for l in output:
rev = l.strip()
self.changes[rev] = self.gnuarch_rev(rev)
self.parents[rev] = []
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
Edouard Gomez
convert/gnuarch: follow continuation-of revisions...
r7585 # Read author, date and summary
catlog, status = self.run('cat-log', '-d', self.path, rev)
if status:
catlog = self.run0('cat-archive-log', rev)
self._parsecatlog(catlog, rev)
# Populate the parents map
self.parents[child].append(rev)
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
Edouard Gomez
convert/gnuarch: follow continuation-of revisions...
r7585 # Keep track of the current revision as the child of the next
# revision scanned
child = rev
# Check if we have to follow the usual incremental history
# or if we have to 'jump' to a different treeversion given
# by the continuation-of header.
if self.changes[rev].continuationof:
treeversion = '--'.join(self.changes[rev].continuationof.split('--')[:-1])
break
# If we reached a base-0 revision w/o any continuation-of
# header, it means the tree history ends here.
if rev[-6:] == 'base-0':
break
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
def after(self):
Martin Geisler
move % out of translatable strings...
r6913 self.ui.debug(_('cleaning up %s\n') % self.tmppath)
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 shutil.rmtree(self.tmppath, ignore_errors=True)
def getheads(self):
return self.parents[None]
def getfile(self, name, rev):
if rev != self.lastrev:
raise util.Abort(_('internal calling inconsistency'))
# Raise IOError if necessary (i.e. deleted files).
if not os.path.exists(os.path.join(self.tmppath, name)):
raise IOError
data, mode = self._getfile(name, rev)
self.modecache[(name, rev)] = mode
return data
def getmode(self, name, rev):
return self.modecache[(name, rev)]
def getchanges(self, rev):
self.modecache = {}
self._update(rev)
changes = []
copies = {}
for f in self.changes[rev].add_files:
changes.append((f, rev))
for f in self.changes[rev].mod_files:
changes.append((f, rev))
for f in self.changes[rev].del_files:
changes.append((f, rev))
for src in self.changes[rev].ren_files:
to = self.changes[rev].ren_files[src]
changes.append((src, rev))
changes.append((to, rev))
Patrick Mezard
convert/gnuarch: fix switched copy source and destination...
r7567 copies[to] = src
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
for src in self.changes[rev].ren_dirs:
to = self.changes[rev].ren_dirs[src]
chgs, cps = self._rendirchanges(src, to);
changes += [(f, rev) for f in chgs]
Patrick Mezard
convert/gnuarch: fix switched copy source and destination...
r7567 copies.update(cps)
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
self.lastrev = rev
Patrick Mezard
convert/gnuarch: fix switched copy source and destination...
r7567 return util.sort(util.unique(changes)), copies
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
def getcommit(self, rev):
changes = self.changes[rev]
return commit(author = changes.author, date = changes.date,
Edouard Gomez
convert/gnuarch: keep track of original revision in extra headers...
r7581 desc = changes.summary, parents = self.parents[rev], rev=rev)
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
def gettags(self):
return self.tags
def _execute(self, cmd, *args, **kwargs):
cmdline = [self.execmd, cmd]
cmdline += args
cmdline = [util.shellquote(arg) for arg in cmdline]
cmdline += ['>', util.nulldev, '2>', util.nulldev]
cmdline = util.quotecommand(' '.join(cmdline))
self.ui.debug(cmdline, '\n')
return os.system(cmdline)
def _update(self, rev):
Edouard Gomez
convert/gnuarch: follow continuation-of revisions...
r7585 self.ui.debug(_('applying revision %s...\n') % rev)
changeset, status = self.runlines('replay', '-d', self.tmppath,
rev)
if status:
# Something went wrong while merging (baz or tla
# issue?), get latest revision and try from there
shutil.rmtree(self.tmppath, ignore_errors=True)
Aleix Conchillo Flaque
convert: improve gnu arch source performance and other fixes...
r6049 self._obtainrevision(rev)
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 else:
Edouard Gomez
convert/gnuarch: follow continuation-of revisions...
r7585 old_rev = self.parents[rev][0]
self.ui.debug(_('computing changeset between %s and %s...\n')
% (old_rev, rev))
self._parsechangeset(changeset, rev)
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035
def _getfile(self, name, rev):
mode = os.lstat(os.path.join(self.tmppath, name)).st_mode
if stat.S_ISLNK(mode):
data = os.readlink(os.path.join(self.tmppath, name))
mode = mode and 'l' or ''
else:
data = open(os.path.join(self.tmppath, name), 'rb').read()
mode = (mode & 0111) and 'x' or ''
return data, mode
def _exclude(self, name):
exclude = [ '{arch}', '.arch-ids', '.arch-inventory' ]
for exc in exclude:
if name.find(exc) != -1:
return True
return False
def _readcontents(self, path):
files = []
contents = os.listdir(path)
while len(contents) > 0:
c = contents.pop()
p = os.path.join(path, c)
Aleix Conchillo Flaque
convert: do not skip some lines in gnu arch summaries
r6044 # os.walk could be used, but here we avoid internal GNU
# Arch files and directories, thus saving a lot time.
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 if not self._exclude(p):
if os.path.isdir(p):
contents += [os.path.join(c, f) for f in os.listdir(p)]
else:
files.append(c)
return files
def _rendirchanges(self, src, dest):
changes = []
copies = {}
files = self._readcontents(os.path.join(self.tmppath, dest))
for f in files:
s = os.path.join(src, f)
d = os.path.join(dest, f)
changes.append(s)
changes.append(d)
Patrick Mezard
convert/gnuarch: fix switched copy source and destination...
r7567 copies[d] = s
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 return changes, copies
Aleix Conchillo Flaque
convert: improve gnu arch source performance and other fixes...
r6049 def _obtainrevision(self, rev):
Martin Geisler
move % out of translatable strings...
r6913 self.ui.debug(_('obtaining revision %s...\n') % rev)
Edouard Gomez
convert/gnuarch: use fully qualified revisions...
r7582 output = self._execute('get', rev, self.tmppath)
Aleix Conchillo Flaque
convert: improve gnu arch source performance and other fixes...
r6049 self.checkexit(output)
Martin Geisler
move % out of translatable strings...
r6913 self.ui.debug(_('analysing revision %s...\n') % rev)
Aleix Conchillo Flaque
convert: improve gnu arch source performance and other fixes...
r6049 files = self._readcontents(self.tmppath)
self.changes[rev].add_files += files
Aleix Conchillo Flaque
convert: added GNU Arch (tla) tests and related fixes
r6079 def _stripbasepath(self, path):
if path.startswith('./'):
return path[2:]
return path
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 def _parsecatlog(self, data, rev):
Edouard Gomez
convert/gnuarch: fix cat-log parsing...
r7578 try:
catlog = self.catlogparser.parsestr(data)
Edouard Gomez
convert/gnuarch: recode cat-log parts to utf-8 to be hg.description friendly
r7592
# Commit date
Edouard Gomez
convert/gnuarch: fix cat-log parsing...
r7578 self.changes[rev].date = util.datestr(
util.strdate(catlog['Standard-date'],
'%Y-%m-%d %H:%M:%S'))
Edouard Gomez
convert/gnuarch: recode cat-log parts to utf-8 to be hg.description friendly
r7592
# Commit author
self.changes[rev].author = self.recode(catlog['Creator'])
# Commit description
self.changes[rev].summary = '\n\n'.join((catlog['Summary'],
catlog.get_payload()))
self.changes[rev].summary = self.recode(self.changes[rev].summary)
# Commit revision origin when dealing with a branch or tag
Edouard Gomez
convert/gnuarch: parse continuation-of revisions in gnuarch source...
r7583 if catlog.has_key('Continuation-of'):
Edouard Gomez
convert/gnuarch: recode cat-log parts to utf-8 to be hg.description friendly
r7592 self.changes[rev].continuationof = self.recode(catlog['Continuation-of'])
Peter Arrenbrecht
cleanup: drop unused assignments
r7875 except Exception:
Edouard Gomez
convert/gnuarch: fix cat-log parsing...
r7578 raise util.Abort(_('could not parse cat-log of %s') % rev)
Aleix Conchillo Flaque
convert: add full description for gnu arch revisions
r6037
Aleix Conchillo Flaque
convert: improve gnu arch source performance and other fixes...
r6049 def _parsechangeset(self, data, rev):
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 for l in data:
l = l.strip()
Aleix Conchillo Flaque
convert: support binary files, link to files (viceversa) in gnu arch
r6055 # Added file (ignore added directory)
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 if l.startswith('A') and not l.startswith('A/'):
Aleix Conchillo Flaque
convert: added GNU Arch (tla) tests and related fixes
r6079 file = self._stripbasepath(l[1:].strip())
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 if not self._exclude(file):
self.changes[rev].add_files.append(file)
Aleix Conchillo Flaque
convert: support binary files, link to files (viceversa) in gnu arch
r6055 # Deleted file (ignore deleted directory)
elif l.startswith('D') and not l.startswith('D/'):
Aleix Conchillo Flaque
convert: added GNU Arch (tla) tests and related fixes
r6079 file = self._stripbasepath(l[1:].strip())
Aleix Conchillo Flaque
convert: support binary files, link to files (viceversa) in gnu arch
r6055 if not self._exclude(file):
self.changes[rev].del_files.append(file)
# Modified binary file
elif l.startswith('Mb'):
Aleix Conchillo Flaque
convert: added GNU Arch (tla) tests and related fixes
r6079 file = self._stripbasepath(l[2:].strip())
Aleix Conchillo Flaque
convert: support binary files, link to files (viceversa) in gnu arch
r6055 if not self._exclude(file):
self.changes[rev].mod_files.append(file)
# Modified link
elif l.startswith('M->'):
Aleix Conchillo Flaque
convert: added GNU Arch (tla) tests and related fixes
r6079 file = self._stripbasepath(l[3:].strip())
Aleix Conchillo Flaque
convert: support binary files, link to files (viceversa) in gnu arch
r6055 if not self._exclude(file):
self.changes[rev].mod_files.append(file)
# Modified file
elif l.startswith('M'):
Aleix Conchillo Flaque
convert: added GNU Arch (tla) tests and related fixes
r6079 file = self._stripbasepath(l[1:].strip())
Aleix Conchillo Flaque
convert: support binary files, link to files (viceversa) in gnu arch
r6055 if not self._exclude(file):
self.changes[rev].mod_files.append(file)
# Renamed file (or link)
elif l.startswith('=>'):
files = l[2:].strip().split(' ')
if len(files) == 1:
files = l[2:].strip().split('\t')
Aleix Conchillo Flaque
convert: added GNU Arch (tla) tests and related fixes
r6079 src = self._stripbasepath(files[0])
dst = self._stripbasepath(files[1])
if not self._exclude(src) and not self._exclude(dst):
self.changes[rev].ren_files[src] = dst
Aleix Conchillo Flaque
convert: support binary files, link to files (viceversa) in gnu arch
r6055 # Conversion from file to link or from link to file (modified)
elif l.startswith('ch'):
Aleix Conchillo Flaque
convert: added GNU Arch (tla) tests and related fixes
r6079 file = self._stripbasepath(l[2:].strip())
Aleix Conchillo Flaque
convert: support binary files, link to files (viceversa) in gnu arch
r6055 if not self._exclude(file):
self.changes[rev].mod_files.append(file)
# Renamed directory
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 elif l.startswith('/>'):
dirs = l[2:].strip().split(' ')
if len(dirs) == 1:
dirs = l[2:].strip().split('\t')
Aleix Conchillo Flaque
convert: added GNU Arch (tla) tests and related fixes
r6079 src = self._stripbasepath(dirs[0])
dst = self._stripbasepath(dirs[1])
if not self._exclude(src) and not self._exclude(dst):
self.changes[rev].ren_dirs[src] = dst