##// END OF EJS Templates
merge with stable
merge with stable

File last commit:

r13759:49b818fd default
r13969:336bb8b5 merge default
Show More
common.py
411 lines | 12.7 KiB | text/x-python | PythonLexer
Martin Geisler
convert: add copyright and license headers to back-ends
r8250 # common.py - common code for the convert extension
#
# Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
#
# This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Martin Geisler
convert: add copyright and license headers to back-ends
r8250
Bryan O'Sullivan
convert: abstract map files into a class
r5510 import base64, errno
Maxim Dounin
convert: add commandline.xargs(), use it in svn_sink class...
r5832 import os
Patrick Mezard
convert: replace fork with subprocess call.
r5127 import cPickle as pickle
Martin Geisler
removed unused imports
r8656 from mercurial import util
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 from mercurial.i18n import _
Patrick Mezard
convert: replace fork with subprocess call.
r5127
def encodeargs(args):
def encodearg(s):
lines = base64.encodestring(s)
lines = [l.splitlines()[0] for l in lines]
return ''.join(lines)
Thomas Arendsen Hein
Remove trailing spaces, fix indentation
r5143
Patrick Mezard
convert: replace fork with subprocess call.
r5127 s = pickle.dumps(args)
return encodearg(s)
def decodeargs(s):
s = base64.decodestring(s)
return pickle.loads(s)
Brendan Cully
Split convert extension into common and repository type modules
r4536
Matt Mackall
many, many trivial check-code fixups
r10282 class MissingTool(Exception):
pass
Patrick Mezard
convert: allow missing tools not to stop source type detection
r6332
def checktool(exe, name=None, abort=True):
Patrick Mezard
convert: fail if an external required tool is not found
r5497 name = name or exe
if not util.find_exe(exe):
Patrick Mezard
convert: allow missing tools not to stop source type detection
r6332 exc = abort and util.Abort or MissingTool
raise exc(_('cannot find required "%s" tool') % name)
Patrick Mezard
convert: fail if an external required tool is not found
r5497
Matt Mackall
many, many trivial check-code fixups
r10282 class NoRepo(Exception):
pass
Brendan Cully
Split convert extension into common and repository type modules
r4536
Alexis S. L. Carvalho
convert: change SKIPREV to 'SKIP'
r5400 SKIPREV = 'SKIP'
Alexis S. L. Carvalho
convert: allow the converter_source to say "skip this revision"...
r5374
Brendan Cully
Split convert extension into common and repository type modules
r4536 class commit(object):
Bryan O'Sullivan
convert: make contents of "extra" dict available from sources, for sinks....
r5439 def __init__(self, author, date, desc, parents, branch=None, rev=None,
Patrick Mezard
convert: add --sourcesort option for source specific sort...
r8690 extra={}, sortkey=None):
Alexis S. L. Carvalho
convert: use 'unknown' and '0 0' if commit author or date weren't specified...
r5984 self.author = author or 'unknown'
self.date = date or '0 0'
Bryan O'Sullivan
convert: empty log messages are OK as of 7f5c3fb0a37d
r5024 self.desc = desc
Bryan O'Sullivan
convert: make commit constructor clearer and less magical
r5012 self.parents = parents
self.branch = branch
self.rev = rev
Bryan O'Sullivan
convert: make contents of "extra" dict available from sources, for sinks....
r5439 self.extra = extra
Patrick Mezard
convert: add --sourcesort option for source specific sort...
r8690 self.sortkey = sortkey
Brendan Cully
Split convert extension into common and repository type modules
r4536
class converter_source(object):
"""Conversion source interface"""
Bryan O'Sullivan
convert: some tidyups, doc improvements, and test fixes...
r5556 def __init__(self, ui, path=None, rev=None):
Brendan Cully
Split convert extension into common and repository type modules
r4536 """Initialize conversion source (or raise NoRepo("message")
exception if path is not a valid repository)"""
Brendan Cully
convert: move some code into common init function
r4810 self.ui = ui
self.path = path
self.rev = rev
self.encoding = 'utf-8'
Brendan Cully
convert: export revmap to source....
r4812
Bryan O'Sullivan
convert: add before/after hooks for converter sources
r5356 def before(self):
pass
def after(self):
pass
Bryan O'Sullivan
convert: abstract map files into a class
r5510 def setrevmap(self, revmap):
"""set the map of already-converted revisions"""
Brendan Cully
convert: svn: use revmap to parse only new revisions in incremental conversions
r4813 pass
Brendan Cully
Split convert extension into common and repository type modules
r4536
def getheads(self):
"""Return a list of this repository's heads"""
raise NotImplementedError()
def getfile(self, name, rev):
Patrick Mezard
convert: merge sources getmode() into getfile()
r11134 """Return a pair (data, mode) where data is the file content
as a string and mode one of '', 'x' or 'l'. rev is the
identifier returned by a previous call to getchanges(). Raise
IOError to indicate that name was deleted in rev.
Patrick Mezard
convert: improve convert_source documentation
r7055 """
Brendan Cully
Split convert extension into common and repository type modules
r4536 raise NotImplementedError()
def getchanges(self, version):
Dirkjan Ochtman
clean up trailing spaces, leading spaces in C
r7186 """Returns a tuple of (files, copies).
Patrick Mezard
convert: improve convert_source documentation
r7055
files is a sorted list of (filename, id) tuples for all files
Greg Ward
convert: improve docstrings, comments.
r8444 changed between version and its first parent returned by
Patrick Mezard
convert: improve convert_source documentation
r7055 getcommit(). id is the source revision id of the file.
Brendan Cully
Split convert extension into common and repository type modules
r4536
Brendan Cully
convert: look up copies in getchanges instead of getcommit...
r5121 copies is a dictionary of dest: source
"""
Brendan Cully
Split convert extension into common and repository type modules
r4536 raise NotImplementedError()
def getcommit(self, version):
"""Return the commit object for version"""
raise NotImplementedError()
def gettags(self):
Patrick Mezard
convert/svn: test svn tags encoding
r8887 """Return the tags as a dictionary of name: revision
Tag names must be UTF-8 strings.
"""
Brendan Cully
Split convert extension into common and repository type modules
r4536 raise NotImplementedError()
Brendan Cully
convert: ove recode method into converter_source
r4759 def recode(self, s, encoding=None):
if not encoding:
Brendan Cully
convert: move some code into common init function
r4810 encoding = self.encoding or 'utf-8'
Thomas Arendsen Hein
removed trailing whitespace
r4957
Thomas Arendsen Hein
Don't decode unicode strings....
r5287 if isinstance(s, unicode):
return s.encode("utf-8")
Brendan Cully
convert: ove recode method into converter_source
r4759 try:
return s.decode(encoding).encode("utf-8")
except:
try:
return s.decode("latin-1").encode("utf-8")
except:
return s.decode(encoding, "replace").encode("utf-8")
Alexis S. L. Carvalho
convert: readd --filemap...
r5377 def getchangedfiles(self, rev, i):
"""Return the files changed by rev compared to parent[i].
Thomas Arendsen Hein
Removed tabs and trailing whitespace in python files
r5760
Alexis S. L. Carvalho
convert: readd --filemap...
r5377 i is an index selecting one of the parents of rev. The return
value should be the list of files that are different in rev and
this parent.
If rev has no parents, i is None.
Thomas Arendsen Hein
Removed tabs and trailing whitespace in python files
r5760
Alexis S. L. Carvalho
convert: readd --filemap...
r5377 This function is only needed to support --filemap
"""
raise NotImplementedError()
Bryan O'Sullivan
convert: tell the source repository when a rev has been converted...
r5554 def converted(self, rev, sinkrev):
'''Notify the source that a revision has been converted.'''
pass
Patrick Mezard
convert: fail fast if source does not support --sourcesort
r8691 def hasnativeorder(self):
"""Return true if this source has a meaningful, native revision
order. For instance, Mercurial revisions are store sequentially
while there is no such global ordering with Darcs.
"""
return False
Patrick Mezard
convert: rewrite tags when converting from hg to hg
r8693 def lookuprev(self, rev):
"""If rev is a meaningful revision reference in source, return
the referenced identifier in the same format used by getcommit().
return None otherwise.
"""
return None
Bryan O'Sullivan
convert: tell the source repository when a rev has been converted...
r5554
Edouard Gomez
convert: add bookmark support to common sink/source implementation
r13744 def getbookmarks(self):
"""Return the bookmarks as a dictionary of name: revision
Bookmark names are to be UTF-8 strings.
"""
return {}
Brendan Cully
Split convert extension into common and repository type modules
r4536 class converter_sink(object):
"""Conversion sink (target) interface"""
def __init__(self, ui, path):
"""Initialize conversion sink (or raise NoRepo("message")
Bryan O'Sullivan
convert: refactor sink initialisation, to remove hardcoding of hg...
r5441 exception if path is not a valid repository)
created is a list of paths to remove if a fatal error occurs
later"""
self.ui = ui
Bryan O'Sullivan
convert: add default constructor for converter_sink
r5440 self.path = path
Bryan O'Sullivan
convert: refactor sink initialisation, to remove hardcoding of hg...
r5441 self.created = []
Brendan Cully
Split convert extension into common and repository type modules
r4536
def getheads(self):
"""Return a list of this repository's heads"""
raise NotImplementedError()
Bryan O'Sullivan
convert: rename mapfile to revmapfile, so we can map more than just revs
r5011 def revmapfile(self):
Brendan Cully
Split convert extension into common and repository type modules
r4536 """Path to a file that will contain lines
source_rev_id sink_rev_id
mapping equivalent revision identifiers for each system."""
raise NotImplementedError()
Edouard Gomez
convert extension: Add support for username mapping...
r4589 def authorfile(self):
"""Path to a file that will contain lines
srcauthor=dstauthor
mapping equivalent authors identifiers for each system."""
Brendan Cully
convert: fix various authormap handling bugs
r4590 return None
Edouard Gomez
convert extension: Add support for username mapping...
r4589
Patrick Mezard
convert: rewrite tags when converting from hg to hg
r8693 def putcommit(self, files, copies, parents, commit, source, revmap):
Brendan Cully
Split convert extension into common and repository type modules
r4536 """Create a revision with all changed files listed in 'files'
Patrick Mezard
convert: rewrite tags when converting from hg to hg
r8693 and having listed parents. 'commit' is a commit object
containing at a minimum the author, date, and message for this
changeset. 'files' is a list of (path, version) tuples,
'copies' is a dictionary mapping destinations to sources,
'source' is the source repository, and 'revmap' is a mapfile
Patrick Mezard
convert: merge sources getmode() into getfile()
r11134 of source revisions to converted revisions. Only getfile() and
lookuprev() should be called on 'source'.
Patrick Mezard
convert: reintegrate file retrieval code in sinks...
r6716
Note that the sink repository is not told to update itself to
a particular revision (or even what that revision would be)
before it receives the file data.
"""
Brendan Cully
Split convert extension into common and repository type modules
r4536 raise NotImplementedError()
def puttags(self, tags):
"""Put tags into sink.
Patrick Mezard
convert/svn: test svn tags encoding
r8887
tags: {tagname: sink_rev_id, ...} where tagname is an UTF-8 string.
Patrick Mezard
convert: fix history topology when using hg.tagsbranch...
r9431 Return a pair (tag_revision, tag_parent_revision), or (None, None)
if nothing was changed.
Patrick Mezard
convert/svn: test svn tags encoding
r8887 """
Brendan Cully
Split convert extension into common and repository type modules
r4536 raise NotImplementedError()
Patrick Mezard
convert: replace fork with subprocess call.
r5127
Patrick Mezard
convert: hg.clonebranches must pull missing parents (issue941)
r5934 def setbranch(self, branch, pbranches):
Patrick Mezard
convert: reintegrate file retrieval code in sinks...
r6716 """Set the current branch name. Called before the first putcommit
Brendan Cully
convert: hg: optionally create branches as clones...
r5173 on the branch.
branch: branch name for subsequent commits
Patrick Mezard
convert: hg.clonebranches must pull missing parents (issue941)
r5934 pbranches: (converted parent revision, parent branch) tuples"""
Brendan Cully
convert: hg: optionally create branches as clones...
r5173 pass
Alexis S. L. Carvalho
convert: add a mode where mercurial_sink skips empty revisions....
r5378
def setfilemapmode(self, active):
"""Tell the destination that we're using a filemap
Some converter_sources (svn in particular) can claim that a file
was changed in a revision, even if there was no change. This method
tells the destination that we're using a filemap and that it should
filter empty revisions.
"""
pass
Bryan O'Sullivan
convert: abstract map files into a class
r5510
Bryan O'Sullivan
convert: abstract darcs's commandline handling
r5512 def before(self):
pass
def after(self):
pass
Edouard Gomez
convert: add bookmark support to common sink/source implementation
r13744 def putbookmarks(self, bookmarks):
"""Put bookmarks into sink.
bookmarks: {bookmarkname: sink_rev_id, ...}
where bookmarkname is an UTF-8 string.
"""
pass
Bryan O'Sullivan
convert: abstract darcs's commandline handling
r5512
class commandline(object):
def __init__(self, ui, command):
self.ui = ui
self.command = command
def prerun(self):
pass
def postrun(self):
pass
Daniel Atallah
convert: add support to common commandline to access stdin of the process
r13759 def _cmdline(self, cmd, closestdin, *args, **kwargs):
Bryan O'Sullivan
convert: abstract darcs's commandline handling
r5512 cmdline = [self.command, cmd] + list(args)
for k, v in kwargs.iteritems():
if len(k) == 1:
cmdline.append('-' + k)
else:
cmdline.append('--' + k.replace('_', '-'))
try:
if len(k) == 1:
cmdline.append('' + v)
else:
cmdline[-1] += '=' + v
except TypeError:
pass
cmdline = [util.shellquote(arg) for arg in cmdline]
Patrick Mezard
convert: display child command output if --debug (fix 878466138b57)
r7611 if not self.ui.debugflag:
Bryan O'Sullivan
convert: print darcs error messages iff --debug
r7610 cmdline += ['2>', util.nulldev]
Daniel Atallah
convert: add support to common commandline to access stdin of the process
r13759 if closestdin:
cmdline += ['<', util.nulldev]
Patrick Mezard
convert: fix util.popen regression in darcs converter
r5529 cmdline = ' '.join(cmdline)
Maxim Dounin
convert: add commandline.xargs(), use it in svn_sink class...
r5832 return cmdline
Bryan O'Sullivan
convert: abstract darcs's commandline handling
r5512
Maxim Dounin
convert: add commandline.xargs(), use it in svn_sink class...
r5832 def _run(self, cmd, *args, **kwargs):
Daniel Atallah
convert: add support to common commandline to access stdin of the process
r13759 return self._dorun(util.popen, cmd, True, *args, **kwargs)
def _run2(self, cmd, *args, **kwargs):
return self._dorun(util.popen2, cmd, False, *args, **kwargs)
def _dorun(self, openfunc, cmd, closestdin, *args, **kwargs):
cmdline = self._cmdline(cmd, closestdin, *args, **kwargs)
Martin Geisler
do not attempt to translate ui.debug output
r9467 self.ui.debug('running: %s\n' % (cmdline,))
Bryan O'Sullivan
convert: abstract darcs's commandline handling
r5512 self.prerun()
try:
Daniel Atallah
convert: add support to common commandline to access stdin of the process
r13759 return openfunc(cmdline)
Bryan O'Sullivan
convert: abstract darcs's commandline handling
r5512 finally:
self.postrun()
def run(self, cmd, *args, **kwargs):
fp = self._run(cmd, *args, **kwargs)
output = fp.read()
self.ui.debug(output)
return output, fp.close()
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 def runlines(self, cmd, *args, **kwargs):
fp = self._run(cmd, *args, **kwargs)
output = fp.readlines()
Aleix Conchillo Flaque
convert: improve gnu arch source performance and other fixes...
r6049 self.ui.debug(''.join(output))
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 return output, fp.close()
Bryan O'Sullivan
convert: abstract darcs's commandline handling
r5512 def checkexit(self, status, output=''):
if status:
if output:
self.ui.warn(_('%s error:\n') % self.command)
self.ui.warn(output)
msg = util.explain_exit(status)[0]
Martin Geisler
convert: do not ask for translation of "%s %s"
r8970 raise util.Abort('%s %s' % (self.command, msg))
Bryan O'Sullivan
convert: abstract darcs's commandline handling
r5512
def run0(self, cmd, *args, **kwargs):
output, status = self.run(cmd, *args, **kwargs)
self.checkexit(status, output)
return output
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 def runlines0(self, cmd, *args, **kwargs):
output, status = self.runlines(cmd, *args, **kwargs)
Aleix Conchillo Flaque
convert: improve gnu arch source performance and other fixes...
r6049 self.checkexit(status, ''.join(output))
Aleix Conchillo Flaque
convert: added GNU Arch source converter
r6035 return output
Maxim Dounin
convert: add commandline.xargs(), use it in svn_sink class...
r5832 def getargmax(self):
if '_argmax' in self.__dict__:
return self._argmax
# POSIX requires at least 4096 bytes for ARG_MAX
self._argmax = 4096
try:
self._argmax = os.sysconf("SC_ARG_MAX")
except:
pass
# Windows shells impose their own limits on command line length,
# down to 2047 bytes for cmd.exe under Windows NT/2k and 2500 bytes
# for older 4nt.exe. See http://support.microsoft.com/kb/830473 for
# details about cmd.exe limitations.
# Since ARG_MAX is for command line _and_ environment, lower our limit
# (and make happy Windows shells while doing this).
Matt Mackall
many, many trivial check-code fixups
r10282 self._argmax = self._argmax / 2 - 1
Maxim Dounin
convert: add commandline.xargs(), use it in svn_sink class...
r5832 return self._argmax
Daniel Atallah
convert: add support to common commandline to access stdin of the process
r13759 def limit_arglist(self, arglist, cmd, closestdin, *args, **kwargs):
cmdlen = len(self._cmdline(cmd, closestdin, *args, **kwargs))
limit = self.getargmax() - cmdlen
Maxim Dounin
convert: add commandline.xargs(), use it in svn_sink class...
r5832 bytes = 0
fl = []
for fn in arglist:
b = len(fn) + 3
if bytes + b < limit or len(fl) == 0:
fl.append(fn)
bytes += b
else:
yield fl
fl = [fn]
bytes = b
if fl:
yield fl
def xargs(self, arglist, cmd, *args, **kwargs):
Daniel Atallah
convert: add support to common commandline to access stdin of the process
r13759 for l in self.limit_arglist(arglist, cmd, True, *args, **kwargs):
Maxim Dounin
convert: add commandline.xargs(), use it in svn_sink class...
r5832 self.run0(cmd, *(list(args) + l), **kwargs)
Bryan O'Sullivan
convert: abstract map files into a class
r5510
class mapfile(dict):
def __init__(self, ui, path):
super(mapfile, self).__init__()
self.ui = ui
self.path = path
self.fp = None
self.order = []
self._read()
def _read(self):
Stefan Rusek
Handle when the slicemap option is an empty string...
r7774 if not self.path:
Bryan O'Sullivan
convert: allow synthetic history to be spliced in....
r5996 return
Bryan O'Sullivan
convert: abstract map files into a class
r5510 try:
fp = open(self.path, 'r')
except IOError, err:
if err.errno != errno.ENOENT:
raise
return
Patrick Mezard
convert: better mapfile parsing errors (issue1581/1)
r8047 for i, line in enumerate(fp):
try:
Patrick Mezard
convert: make mapfile handle LF and CRLF shamap (issue1846)
r9528 key, value = line.splitlines()[0].rsplit(' ', 1)
Patrick Mezard
convert: better mapfile parsing errors (issue1581/1)
r8047 except ValueError:
Matt Mackall
many, many trivial check-code fixups
r10282 raise util.Abort(
_('syntax error in %s(%d): key/value pair expected')
% (self.path, i + 1))
Bryan O'Sullivan
convert: abstract map files into a class
r5510 if key not in self:
self.order.append(key)
super(mapfile, self).__setitem__(key, value)
fp.close()
Thomas Arendsen Hein
Removed tabs and trailing whitespace in python files
r5760
Bryan O'Sullivan
convert: abstract map files into a class
r5510 def __setitem__(self, key, value):
if self.fp is None:
try:
self.fp = open(self.path, 'a')
except IOError, err:
raise util.Abort(_('could not open map file %r: %s') %
(self.path, err.strerror))
self.fp.write('%s %s\n' % (key, value))
self.fp.flush()
super(mapfile, self).__setitem__(key, value)
def close(self):
Bryan O'Sullivan
convert: abstract darcs's commandline handling
r5512 if self.fp:
self.fp.close()
self.fp = None