##// END OF EJS Templates
extensions: improve the consistency of synopses...
extensions: improve the consistency of synopses Trying as much as possible to consistently: - use a present tense predicate followed by a direct object - verb referring directly to the functionality provided (ie. not "add command that does this" but simple "do that") - keep simple and to the point, leaving details for the long help (width is tight, possibly even more so for translations) Thanks to timeless, Martin Geisler, Rafael Villar Burke, Dan Villiom Podlaski Christiansen and others for the helpful suggestions.

File last commit:

r8888:bd93d0e0 default
r8894:868670db default
Show More
subversion.py
1136 lines | 43.1 KiB | text/x-python | PythonLexer
Daniel Holth
convert extension: Add SVN converter
r4765 # Subversion 1.4/1.5 Python API backend
#
# Copyright(C) 2007 Daniel Holth et al
import locale
Bryan O'Sullivan
convert/subversion: work around memory leak in svn's python bindings...
r4946 import os
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 import re
Thomas Arendsen Hein
Move debugsvnlog to subversion module.
r5139 import sys
Bryan O'Sullivan
convert/subversion: work around memory leak in svn's python bindings...
r4946 import cPickle as pickle
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 import tempfile
Patrick Mezard
convert: properly encode subversion URLs (issue 1224)
r7074 import urllib
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513
Patrick Mezard
convert/svn: stop returning unicode revision identifiers
r8886 from mercurial import strutil, util, encoding
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 from mercurial.i18n import _
Daniel Holth
convert extension: Add SVN converter
r4765
# Subversion stuff. Works best with very recent Python SVN bindings
# e.g. SVN 1.5 or backports. Thanks to the bzr folks for enhancing
# these bindings.
from cStringIO import StringIO
Patrick Mezard
convert: improve reporting of invalid svn bindings
r7447 from common import NoRepo, MissingTool, commit, encodeargs, decodeargs
from common import commandline, converter_source, converter_sink, mapfile
Brendan Cully
convert: activate subversion engine...
r4766
try:
from svn.core import SubversionException, Pool
Brendan Cully
convert svn: try to extract URL from source if it is a working directory
r5010 import svn
import svn.client
Brendan Cully
convert: activate subversion engine...
r4766 import svn.core
import svn.ra
import svn.delta
import transport
Ronny Pfannschmidt
convert: hide svn deprecation warnings
r8221 import warnings
warnings.filterwarnings('ignore',
module='svn.core',
category=DeprecationWarning)
Brendan Cully
convert: activate subversion engine...
r4766 except ImportError:
pass
Daniel Holth
convert extension: Add SVN converter
r4765
Patrick Mezard
convert: be even more tolerant when detecting svn tags...
r7381 class SvnPathNotFound(Exception):
pass
Brendan Cully
convert: urlify svn repos if necessary....
r5008 def geturl(path):
Brendan Cully
convert svn: try to extract URL from source if it is a working directory
r5010 try:
Brendan Cully
convert svn: canonicalize path before calling url_from_path....
r5020 return svn.client.url_from_path(svn.core.svn_path_canonicalize(path))
Brendan Cully
convert svn: try to extract URL from source if it is a working directory
r5010 except SubversionException:
pass
Brendan Cully
convert: urlify svn repos if necessary....
r5008 if os.path.isdir(path):
Shun-ichi GOTO
convert: Accept local path on win32.
r5793 path = os.path.normpath(os.path.abspath(path))
if os.name == 'nt':
Shun-ichi GOTO
Use util.normpath() instead of direct path string operation....
r5842 path = '/' + util.normpath(path)
Patrick Mezard
convert/svn: stop returning unicode revision identifiers
r8886 # Module URL is later compared with the repository URL returned
# by svn API, which is UTF-8.
path = encoding.tolocal(path)
Patrick Mezard
convert: properly encode subversion URLs (issue 1224)
r7074 return 'file://%s' % urllib.quote(path)
Brendan Cully
convert: urlify svn repos if necessary....
r5008 return path
Brendan Cully
convert: svn: add helper function for optrevs
r5117 def optrev(number):
optrev = svn.core.svn_opt_revision_t()
optrev.kind = svn.core.svn_opt_revision_number
optrev.value.number = number
return optrev
Bryan O'Sullivan
convert/subversion: work around memory leak in svn's python bindings...
r4946 class changedpath(object):
def __init__(self, p):
self.copyfrom_path = p.copyfrom_path
self.copyfrom_rev = p.copyfrom_rev
self.action = p.action
Patrick Mezard
convert: replace fork with subprocess call.
r5127 def get_log_child(fp, url, paths, start, end, limit=0, discover_changed_paths=True,
strict_node_history=False):
protocol = -1
def receiver(orig_paths, revnum, author, date, message, pool):
if orig_paths is not None:
for k, v in orig_paths.iteritems():
orig_paths[k] = changedpath(v)
pickle.dump((orig_paths, revnum, author, date, message),
Thomas Arendsen Hein
Remove trailing spaces, fix indentation
r5143 fp, protocol)
Patrick Mezard
convert: replace fork with subprocess call.
r5127 try:
# Use an ra of our own so that our parent can consume
# our results without confusing the server.
t = transport.SvnRaTransport(url=url)
svn.ra.get_log(t.ra, paths, start, end, limit,
discover_changed_paths,
strict_node_history,
receiver)
Thomas Arendsen Hein
Replace _ with inst for catching exceptions to not shadow gettext....
r5140 except SubversionException, (inst, num):
Patrick Mezard
convert: replace fork with subprocess call.
r5127 pickle.dump(num, fp, protocol)
Patrick Mezard
convert: make svn revision iterator interruptible
r5873 except IOError:
# Caller may interrupt the iteration
pickle.dump(None, fp, protocol)
Patrick Mezard
convert: replace fork with subprocess call.
r5127 else:
pickle.dump(None, fp, protocol)
fp.close()
Patrick Mezard
convert: avoid svn log retrieval process cleanup...
r6397 # With large history, cleanup process goes crazy and suddenly
# consumes *huge* amount of memory. The output file being closed,
# there is no need for clean termination.
os._exit(0)
Patrick Mezard
convert: replace fork with subprocess call.
r5127
Thomas Arendsen Hein
Move debugsvnlog to subversion module.
r5139 def debugsvnlog(ui, **opts):
"""Fetch SVN log in a subprocess and channel them back to parent to
avoid memory collection issues.
"""
util.set_binary(sys.stdin)
util.set_binary(sys.stdout)
args = decodeargs(sys.stdin.read())
get_log_child(sys.stdout, *args)
Benoit Boissinot
use new style classes
r8778 class logstream(object):
Patrick Mezard
convert: make svn revision iterator interruptible
r5873 """Interruptible revision log iterator."""
def __init__(self, stdout):
self._stdout = stdout
def __iter__(self):
while True:
entry = pickle.load(self._stdout)
try:
orig_paths, revnum, author, date, message = entry
except:
if entry is None:
break
raise SubversionException("child raised exception", entry)
yield entry
def close(self):
if self._stdout:
self._stdout.close()
self._stdout = None
Augie Fackler
convert: Improved svn source detection.
r8074
# Check to see if the given path is a local Subversion repo. Verify this by
# looking for several svn-specific files and directories in the given
# directory.
def filecheck(path, proto):
for x in ('locks', 'hooks', 'format', 'db', ):
if not os.path.exists(os.path.join(path, x)):
return False
return True
# Check to see if a given path is the root of an svn repo over http. We verify
# this by requesting a version-controlled URL we know can't exist and looking
# for the svn-specific "not found" XML.
def httpcheck(path, proto):
Peter Arrenbrecht
whitespace cleanup
r8219 return ('<m:human-readable errcode="160013">' in
urllib.urlopen('%s://%s/!svn/ver/0/.svn' % (proto, path)).read())
Augie Fackler
convert: Improved svn source detection.
r8074
protomap = {'http': httpcheck,
'https': httpcheck,
'file': filecheck,
}
def issvnurl(url):
Edouard Gomez
convert: default to file protocol when no :// found for svn repo url...
r8764 try:
proto, path = url.split('://', 1)
path = urllib.url2pathname(path)
except ValueError:
proto = 'file'
path = os.path.abspath(url)
path = path.replace(os.sep, '/')
Augie Fackler
convert: Improved svn source detection.
r8074 check = protomap.get(proto, lambda p, p2: False)
while '/' in path:
if check(path, proto):
return True
path = path.rsplit('/', 1)[0]
return False
Daniel Holth
convert extension: Add SVN converter
r4765 # SVN conversion code stolen from bzr-svn and tailor
Patrick Mezard
convert: document the subversion conversion model
r5876 #
# Subversion looks like a versioned filesystem, branches structures
# are defined by conventions and not enforced by the tool. First,
# we define the potential branches (modules) as "trunk" and "branches"
# children directories. Revisions are then identified by their
# module and revision number (and a repository identifier).
#
# The revision graph is really a tree (or a forest). By default, a
# revision parent is the previous revision in the same module. If the
# module directory is copied/moved from another module then the
# revision is the module root and its parent the source revision in
# the parent module. A revision has at most one parent.
#
Bryan O'Sullivan
convert: rename convert_svn to svn_source
r5438 class svn_source(converter_source):
Brendan Cully
convert: activate subversion engine...
r4766 def __init__(self, ui, url, rev=None):
Bryan O'Sullivan
convert: rename convert_svn to svn_source
r5438 super(svn_source, self).__init__(ui, url, rev=rev)
Brendan Cully
convert: call superclass init from engine init functions
r4807
Matt Mackall
convert: attempt to check repo type before checking for tool
r7973 if not (url.startswith('svn://') or url.startswith('svn+ssh://') or
(os.path.exists(url) and
os.path.exists(os.path.join(url, '.svn'))) or
Augie Fackler
convert: Improved svn source detection.
r8074 issvnurl(url)):
Matt Mackall
convert: attempt to check repo type before checking for tool
r7973 raise NoRepo("%s does not look like a Subversion repo" % url)
Brendan Cully
convert: activate subversion engine...
r4766 try:
SubversionException
except NameError:
Patrick Mezard
convert: improve reporting of invalid svn bindings
r7447 raise MissingTool(_('Subversion python bindings could not be loaded'))
try:
version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
if version < (1, 4):
raise MissingTool(_('Subversion python bindings %d.%d found, '
'1.4 or later required') % version)
except AttributeError:
raise MissingTool(_('Subversion python bindings are too old, 1.4 '
'or later required'))
Brendan Cully
convert: activate subversion engine...
r4766
Brendan Cully
convert: svn: use revmap to parse only new revisions in incremental conversions
r4813 self.lastrevs = {}
Brendan Cully
convert: activate subversion engine...
r4766 latest = None
Daniel Holth
convert extension: Add SVN converter
r4765 try:
# Support file://path@rev syntax. Useful e.g. to convert
# deleted branches.
Bryan O'Sullivan
convert/subversion.py: str.rsplit is not available in Python 2.3
r4927 at = url.rfind('@')
if at >= 0:
latest = int(url[at+1:])
url = url[:at]
Peter Arrenbrecht
cleanup: drop variables for unused return values...
r7874 except ValueError:
Brendan Cully
convert: activate subversion engine...
r4766 pass
Brendan Cully
convert: urlify svn repos if necessary....
r5008 self.url = geturl(url)
Daniel Holth
convert extension: Add SVN converter
r4765 self.encoding = 'UTF-8' # Subversion is always nominal UTF-8
try:
Brendan Cully
convert: urlify svn repos if necessary....
r5008 self.transport = transport.SvnRaTransport(url=self.url)
Daniel Holth
convert extension: Add SVN converter
r4765 self.ra = self.transport.ra
Bryan O'Sullivan
convert/subversion: work around memory leak in svn's python bindings...
r4946 self.ctx = self.transport.client
Patrick Mezard
convert: properly encode subversion URLs (issue 1224)
r7074 self.baseurl = svn.ra.get_repos_root(self.ra)
Patrick Mezard
convert: fix subpaths detection in svn source
r6538 # Module is either empty or a repository path starting with
# a slash and not ending with a slash.
Patrick Mezard
convert: properly encode subversion URLs (issue 1224)
r7074 self.module = urllib.unquote(self.url[len(self.baseurl):])
Patrick Mezard
convert: restore previous svn transport parent correctly
r6847 self.prevmodule = None
Patrick Mezard
convert: prevent svn branches to leave the root module tree
r5957 self.rootmodule = self.module
Daniel Holth
convert extension: Add SVN converter
r4765 self.commits = {}
Brendan Cully
convert: look up copies in getchanges instead of getcommit...
r5121 self.paths = {}
Patrick Mezard
convert/svn: stop returning unicode revision identifiers
r8886 self.uuid = svn.ra.get_uuid(self.ra)
Peter Arrenbrecht
cleanup: drop unused assignments
r7875 except SubversionException:
Matt Mackall
ui: print_exc() -> traceback()
r8206 ui.traceback()
Alexis S. L. Carvalho
convert: display all errors if we couldn't open the source repo...
r5521 raise NoRepo("%s does not look like a Subversion repo" % self.url)
Daniel Holth
convert extension: Add SVN converter
r4765
Thomas Arendsen Hein
raise util.Abort again if specified revision is not an integer....
r5145 if rev:
try:
latest = int(rev)
except ValueError:
Martin Geisler
i18n: mark strings for translation in convert extension
r6956 raise util.Abort(_('svn: revision %s is not an integer') % rev)
Thomas Arendsen Hein
raise util.Abort again if specified revision is not an integer....
r5145
Patrick Mezard
convert: add shallow, single branch svn conversions via svn.startrev
r6173 self.startrev = self.ui.config('convert', 'svn.startrev', default=0)
try:
self.startrev = int(self.startrev)
if self.startrev < 0:
self.startrev = 0
except ValueError:
Thomas Arendsen Hein
Removed trailing spaces from everything except test output
r6210 raise util.Abort(_('svn: start revision %s is not an integer')
Patrick Mezard
convert: add shallow, single branch svn conversions via svn.startrev
r6173 % self.startrev)
Patrick Mezard
convert: fix svn_source.latest()
r5955 self.head = self.latest(self.module, latest)
Patrick Mezard
convert: prevent svn branches to leave the root module tree
r5957 if not self.head:
Patrick Mezard
convert/svn: stop returning unicode revision identifiers
r8886 raise util.Abort(_('no revision found in module %s')
% self.module)
Patrick Mezard
convert: fix svn_source.latest()
r5955 self.last_changed = self.revnum(self.head)
Thomas Arendsen Hein
Removed trailing spaces from everything except test output
r6210
Alexis S. L. Carvalho
convert_svn: add --filemap support
r5382 self._changescache = None
Daniel Holth
convert extension: Add SVN converter
r4765
Bryan O'Sullivan
convert: tell the source repository when a rev has been converted...
r5554 if os.path.exists(os.path.join(url, '.svn/entries')):
self.wc = url
else:
self.wc = None
self.convertfp = None
Bryan O'Sullivan
convert: abstract map files into a class
r5510 def setrevmap(self, revmap):
Brendan Cully
convert: svn code movement (no actual changes)
r4840 lastrevs = {}
Bryan O'Sullivan
convert: iterate
r5511 for revid in revmap.iterkeys():
Brendan Cully
convert: svn code movement (no actual changes)
r4840 uuid, module, revnum = self.revsplit(revid)
lastrevnum = lastrevs.setdefault(module, revnum)
if revnum > lastrevnum:
lastrevs[module] = revnum
self.lastrevs = lastrevs
Bryan O'Sullivan
convert/subversion.py: fix bad assumptions about SVN path naming...
r4925 def exists(self, path, optrev):
try:
Patrick Mezard
convert: properly encode subversion URLs (issue 1224)
r7074 svn.client.ls(self.url.rstrip('/') + '/' + urllib.quote(path),
Bryan O'Sullivan
convert/subversion.py: fix bad assumptions about SVN path naming...
r4925 optrev, False, self.ctx)
Kirill Smelkov
convert: svn -- fix 'exists'...
r5461 return True
Peter Arrenbrecht
cleanup: drop unused assignments
r7875 except SubversionException:
Kirill Smelkov
convert: svn -- fix 'exists'...
r5461 return False
Bryan O'Sullivan
convert/subversion.py: fix bad assumptions about SVN path naming...
r4925
Brendan Cully
convert: svn code movement (no actual changes)
r4840 def getheads(self):
Edouard Gomez
convert: separate trunk detection from branch layout detection...
r5854
Patrick Mezard
convert: check svn branches are directories
r6491 def isdir(path, revnum):
Patrick Mezard
convert: remove leading slash from ra.check_path inputs (issue 1236)
r6848 kind = self._checkpath(path, revnum)
Patrick Mezard
convert: check svn branches are directories
r6491 return kind == svn.core.svn_node_dir
Edouard Gomez
convert: separate trunk detection from branch layout detection...
r5854 def getcfgpath(name, rev):
cfgpath = self.ui.config('convert', 'svn.' + name)
Patrick Mezard
convert: allow svn trunk/branches/tags detection to be skipped...
r6172 if cfgpath is not None and cfgpath.strip() == '':
return None
Edouard Gomez
convert: separate trunk detection from branch layout detection...
r5854 path = (cfgpath or name).strip('/')
if not self.exists(path, rev):
if cfgpath:
raise util.Abort(_('expected %s to be at %r, but not found')
% (name, path))
return None
self.ui.note(_('found %s at %r\n') % (name, path))
return path
Brendan Cully
convert: svn: add helper function for optrevs
r5117 rev = optrev(self.last_changed)
Edouard Gomez
convert: separate trunk detection from branch layout detection...
r5854 oldmodule = ''
trunk = getcfgpath('trunk', rev)
Patrick Mezard
convert: allow tags detection to be disabled...
r6400 self.tags = getcfgpath('tags', rev)
Edouard Gomez
convert: separate trunk detection from branch layout detection...
r5854 branches = getcfgpath('branches', rev)
# If the project has a trunk or branches, we will extract heads
# from them. We keep the project root otherwise.
if trunk:
oldmodule = self.module or ''
Bryan O'Sullivan
convert/subversion.py: fix bad assumptions about SVN path naming...
r4925 self.module += '/' + trunk
Patrick Mezard
convert: fix svn_source.latest()
r5955 self.head = self.latest(self.module, self.last_changed)
Patrick Mezard
convert: prevent svn branches to leave the root module tree
r5957 if not self.head:
Patrick Mezard
convert/svn: stop returning unicode revision identifiers
r8886 raise util.Abort(_('no revision found in module %s')
% self.module)
Edouard Gomez
convert: separate trunk detection from branch layout detection...
r5854
# First head in the list is the module's head
self.heads = [self.head]
Patrick Mezard
convert: allow tags detection to be disabled...
r6400 if self.tags is not None:
self.tags = '%s/%s' % (oldmodule , (self.tags or 'tags'))
Edouard Gomez
convert: separate trunk detection from branch layout detection...
r5854
# Check if branches bring a few more heads to the list
if branches:
rpath = self.url.strip('/')
Dirkjan Ochtman
clean up trailing spaces
r7184 branchnames = svn.client.ls(rpath + '/' + urllib.quote(branches),
Patrick Mezard
convert: properly encode subversion URLs (issue 1224)
r7074 rev, False, self.ctx)
Bryan O'Sullivan
convert/subversion.py: fix bad assumptions about SVN path naming...
r4925 for branch in branchnames.keys():
Edouard Gomez
convert: separate trunk detection from branch layout detection...
r5854 module = '%s/%s/%s' % (oldmodule, branches, branch)
Patrick Mezard
convert: check svn branches are directories
r6491 if not isdir(module, self.last_changed):
continue
Patrick Mezard
convert: fix svn_source.latest()
r5955 brevid = self.latest(module, self.last_changed)
Patrick Mezard
convert: prevent svn branches to leave the root module tree
r5957 if not brevid:
Patrick Mezard
convert/svn: stop returning unicode revision identifiers
r8886 self.ui.note(_('ignoring empty branch %s\n') % branch)
Patrick Mezard
convert: prevent svn branches to leave the root module tree
r5957 continue
Martin Geisler
i18n: mark strings for translation in convert extension
r6956 self.ui.note(_('found branch %s at %d\n') %
Patrick Mezard
convert: fix svn_source.latest()
r5955 (branch, self.revnum(brevid)))
self.heads.append(brevid)
Kirill Smelkov
convert: svn -- fix tags handling...
r5462
Patrick Mezard
convert: add shallow, single branch svn conversions via svn.startrev
r6173 if self.startrev and self.heads:
if len(self.heads) > 1:
Wagner Bruna
convert: fix typo
r8086 raise util.Abort(_('svn: start revision is not supported '
Patrick Mezard
convert: add shallow, single branch svn conversions via svn.startrev
r6173 'with more than one branch'))
revnum = self.revnum(self.heads[0])
if revnum < self.startrev:
Thomas Arendsen Hein
Removed trailing spaces from everything except test output
r6210 raise util.Abort(_('svn: no revision found after start revision %d')
Patrick Mezard
convert: add shallow, single branch svn conversions via svn.startrev
r6173 % self.startrev)
Brendan Cully
convert: svn code movement (no actual changes)
r4840 return self.heads
def getfile(self, file, rev):
data, mode = self._getfile(file, rev)
self.modecache[(file, rev)] = mode
return data
Thomas Arendsen Hein
removed trailing whitespace
r4957 def getmode(self, file, rev):
Brendan Cully
convert: svn code movement (no actual changes)
r4840 return self.modecache[(file, rev)]
def getchanges(self, rev):
Alexis S. L. Carvalho
convert_svn: add --filemap support
r5382 if self._changescache and self._changescache[0] == rev:
return self._changescache[1]
self._changescache = None
Brendan Cully
convert: svn code movement (no actual changes)
r4840 self.modecache = {}
Brendan Cully
convert: look up copies in getchanges instead of getcommit...
r5121 (paths, parents) = self.paths[rev]
Patrick Mezard
convert: checkout svn root revisions...
r5956 if parents:
files, copies = self.expandpaths(rev, paths, parents)
else:
# Perform a full checkout on roots
uuid, module, revnum = self.revsplit(rev)
Dirkjan Ochtman
clean up trailing spaces
r7184 entries = svn.client.ls(self.baseurl + urllib.quote(module),
Patrick Mezard
convert: properly encode subversion URLs (issue 1224)
r7074 optrev(revnum), True, self.ctx)
Thomas Arendsen Hein
Removed trailing spaces from everything except test output
r6210 files = [n for n,e in entries.iteritems()
Patrick Mezard
convert: checkout svn root revisions...
r5956 if e.kind == svn.core.svn_node_file]
copies = {}
Brendan Cully
convert: look up copies in getchanges instead of getcommit...
r5121 files.sort()
files = zip(files, [rev] * len(files))
Brendan Cully
convert: svn code movement (no actual changes)
r4840 # caller caches the result, so free it here to release memory
Brendan Cully
convert: look up copies in getchanges instead of getcommit...
r5121 del self.paths[rev]
return (files, copies)
Brendan Cully
convert: svn code movement (no actual changes)
r4840
Alexis S. L. Carvalho
convert_svn: add --filemap support
r5382 def getchangedfiles(self, rev, i):
changes = self.getchanges(rev)
self._changescache = (rev, changes)
return [f[0] for f in changes[0]]
Brendan Cully
convert: svn code movement (no actual changes)
r4840 def getcommit(self, rev):
if rev not in self.commits:
uuid, module, revnum = self.revsplit(rev)
self.module = module
self.reparent(module)
Patrick Mezard
convert: fetch less revisions when looking for a branch parent
r5875 # We assume that:
# - requests for revisions after "stop" come from the
# revision graph backward traversal. Cache all of them
# down to stop, they will be used eventually.
# - requests for revisions before "stop" come to get
# isolated branches parents. Just fetch what is needed.
Brendan Cully
convert: svn code movement (no actual changes)
r4840 stop = self.lastrevs.get(module, 0)
Patrick Mezard
convert: fetch less revisions when looking for a branch parent
r5875 if revnum < stop:
stop = revnum + 1
Patrick Mezard
convert: fix parents of last fetched svn revision
r5871 self._fetch_revisions(revnum, stop)
Brendan Cully
convert: svn code movement (no actual changes)
r4840 commit = self.commits[rev]
# caller caches the result, so free it here to release memory
del self.commits[rev]
return commit
def gettags(self):
tags = {}
Patrick Mezard
convert: allow svn trunk/branches/tags detection to be skipped...
r6172 if self.tags is None:
return tags
Thomas Arendsen Hein
Removed trailing spaces from everything except test output
r6210
Patrick Mezard
convert: follow svn tags history (issue953)
r6399 # svn tags are just a convention, project branches left in a
# 'tags' directory. There is no other relationship than
# ancestry, which is expensive to discover and makes them hard
# to update incrementally. Worse, past revisions may be
# referenced by tags far away in the future, requiring a deep
# history traversal on every calculation. Current code
# performs a single backward traversal, tracking moves within
# the tags directory (tag renaming) and recording a new tag
# everytime a project is copied from outside the tags
# directory. It also lists deleted tags, this behaviour may
# change in the future.
pendings = []
tagspath = self.tags
start = svn.ra.get_latest_revnum(self.ra)
Bryan O'Sullivan
convert/subversion: rehandle the no-tags case
r4949 try:
Patrick Mezard
convert: normalize paths sent to svn get_log (issue 1219)
r6850 for entry in self._getlog([self.tags], start, self.startrev):
Patrick Mezard
convert: follow svn tags history (issue953)
r6399 origpaths, revnum, author, date, message = entry
Thomas Arendsen Hein
Fix spacing error introduced in 5efd447a9b8d
r6493 copies = [(e.copyfrom_path, e.copyfrom_rev, p) for p, e
Patrick Mezard
convert: follow svn tags history (issue953)
r6399 in origpaths.iteritems() if e.copyfrom_path]
# Apply moves/copies from more specific to general
Matt Mackall
replace various uses of list.reverse()
r8210 copies.sort(reverse=True)
Patrick Mezard
convert: follow svn tags history (issue953)
r6399
srctagspath = tagspath
if copies and copies[-1][2] == tagspath:
# Track tags directory moves
srctagspath = copies.pop()[0]
for source, sourcerev, dest in copies:
if not dest.startswith(tagspath + '/'):
Bryan O'Sullivan
convert/subversion: rehandle the no-tags case
r4949 continue
Patrick Mezard
convert: follow svn tags history (issue953)
r6399 for tag in pendings:
if tag[0].startswith(dest):
tagpath = source + tag[0][len(dest):]
tag[:2] = [tagpath, sourcerev]
break
else:
Patrick Mezard
convert/svn: ignore composite tags...
r8248 pendings.append([source, sourcerev, dest])
# Filter out tags with children coming from different
# parts of the repository like:
# /tags/tag.1 (from /trunk:10)
# /tags/tag.1/foo (from /branches/foo:12)
# Here/tags/tag.1 discarded as well as its children.
# It happens with tools like cvs2svn. Such tags cannot
# be represented in mercurial.
Dirkjan Ochtman
kill trailing whitespace
r8843 addeds = dict((p, e.copyfrom_path) for p, e
Patrick Mezard
convert/svn: ignore composite tags...
r8248 in origpaths.iteritems() if e.action == 'A')
badroots = set()
for destroot in addeds:
for source, sourcerev, dest in pendings:
if (not dest.startswith(destroot + '/')
or source.startswith(addeds[destroot] + '/')):
continue
badroots.add(destroot)
break
for badroot in badroots:
Dirkjan Ochtman
kill trailing whitespace
r8843 pendings = [p for p in pendings if p[2] != badroot
Patrick Mezard
convert/svn: ignore composite tags...
r8248 and not p[2].startswith(badroot + '/')]
Patrick Mezard
convert: follow svn tags history (issue953)
r6399
# Tell tag renamings from tag creations
remainings = []
Patrick Mezard
convert/svn: ignore composite tags...
r8248 for source, sourcerev, dest in pendings:
tagname = dest.split('/')[-1]
Patrick Mezard
convert: follow svn tags history (issue953)
r6399 if source.startswith(srctagspath):
remainings.append([source, sourcerev, tagname])
continue
Patrick Mezard
convert/svn: keep latest and not oldest tag value
r8246 if tagname in tags:
# Keep the latest tag value
continue
Dirkjan Ochtman
kill trailing whitespace
r8843 # From revision may be fake, get one with changes
Patrick Mezard
convert: be even more tolerant when detecting svn tags...
r7381 try:
tagid = self.latest(source, sourcerev)
Patrick Mezard
convert/svn: keep latest and not oldest tag value
r8246 if tagid and tagname not in tags:
Patrick Mezard
convert: be even more tolerant when detecting svn tags...
r7381 tags[tagname] = tagid
except SvnPathNotFound:
Martin Geisler
convert/subversion: wrap long lines in comments
r8660 # It happens when we are following directories
# we assumed were copied with their parents
# but were really created in the tag
# directory.
Patrick Mezard
convert: be even more tolerant when detecting svn tags...
r7381 pass
Patrick Mezard
convert: follow svn tags history (issue953)
r6399 pendings = remainings
tagspath = srctagspath
Peter Arrenbrecht
cleanup: drop unused assignments
r7875 except SubversionException:
Martin Geisler
i18n: mark strings for translation in convert extension
r6956 self.ui.note(_('no tags found at revision %d\n') % start)
Bryan O'Sullivan
convert/subversion: work around memory leak in svn's python bindings...
r4946 return tags
Brendan Cully
convert: svn code movement (no actual changes)
r4840
Bryan O'Sullivan
convert: tell the source repository when a rev has been converted...
r5554 def converted(self, rev, destrev):
if not self.wc:
return
if self.convertfp is None:
self.convertfp = open(os.path.join(self.wc, '.svn', 'hg-shamap'),
'a')
self.convertfp.write('%s %d\n' % (destrev, self.revnum(rev)))
self.convertfp.flush()
Brendan Cully
convert: move some code into common init function
r4810 def revid(self, revnum, module=None):
Patrick Mezard
convert/svn: stop returning unicode revision identifiers
r8886 return 'svn:%s%s@%s' % (self.uuid, module or self.module, revnum)
Brendan Cully
convert: svn: add revnum() to convert rev to revnum
r4774
def revnum(self, rev):
return int(rev.split('@')[-1])
Brendan Cully
convert: svn: add function to get the latest revision touching a path...
r4789
Brendan Cully
convert: add optional module argument to svn._fetch_revisions
r4794 def revsplit(self, rev):
Patrick Mezard
convert/svn: stop returning unicode revision identifiers
r8886 url, revnum = rev.rsplit('@', 1)
Brendan Cully
convert: add optional module argument to svn._fetch_revisions
r4794 revnum = int(revnum)
parts = url.split('/', 1)
uuid = parts.pop(0)[4:]
Brendan Cully
convert: svn: autodetect /branches, /tags, /trunk....
r4797 mod = ''
Brendan Cully
convert: add optional module argument to svn._fetch_revisions
r4794 if parts:
Brendan Cully
convert: svn: autodetect /branches, /tags, /trunk....
r4797 mod = '/' + parts[0]
Brendan Cully
convert: add optional module argument to svn._fetch_revisions
r4794 return uuid, mod, revnum
Brendan Cully
convert: typo in svn.latest
r4790 def latest(self, path, stop=0):
Patrick Mezard
convert: fix svn_source.latest()
r5955 """Find the latest revid affecting path, up to stop. It may return
a revision in a different module, since a branch may be moved without
Patrick Mezard
convert: prevent svn branches to leave the root module tree
r5957 a change being reported. Return None if computed module does not
belong to rootmodule subtree.
Patrick Mezard
convert: fix svn_source.latest()
r5955 """
Patrick Mezard
convert: avoid querying log of foreign svn branches...
r6281 if not path.startswith(self.rootmodule):
# Requests on foreign branches may be forbidden at server level
self.ui.debug(_('ignoring foreign branch %r\n') % path)
return None
Brendan Cully
convert: svn: add function to get the latest revision touching a path...
r4789 if not stop:
stop = svn.ra.get_latest_revnum(self.ra)
try:
Patrick Mezard
convert: restore previous svn transport parent correctly
r6847 prevmodule = self.reparent('')
Brendan Cully
convert: svn: add function to get the latest revision touching a path...
r4789 dirent = svn.ra.stat(self.ra, path.strip('/'), stop)
Patrick Mezard
convert: restore previous svn transport parent correctly
r6847 self.reparent(prevmodule)
Brendan Cully
convert: svn: add function to get the latest revision touching a path...
r4789 except SubversionException:
dirent = None
if not dirent:
Patrick Mezard
convert: be even more tolerant when detecting svn tags...
r7381 raise SvnPathNotFound(_('%s not found up to revision %d') % (path, stop))
Brendan Cully
convert: svn: add function to get the latest revision touching a path...
r4789
Martin Geisler
convert/subversion: wrap long lines in comments
r8660 # stat() gives us the previous revision on this line of
# development, but it might be in *another module*. Fetch the
# log and detect renames down to the latest revision.
Patrick Mezard
convert: normalize paths sent to svn get_log (issue 1219)
r6850 stream = self._getlog([path], stop, dirent.created_rev)
Patrick Mezard
convert: fix svn_source.latest()
r5955 try:
for entry in stream:
paths, revnum, author, date, message = entry
if revnum <= dirent.created_rev:
break
for p in paths:
if not path.startswith(p) or not paths[p].copyfrom_path:
continue
newpath = paths[p].copyfrom_path + path[len(p):]
Martin Geisler
i18n: mark strings for translation in convert extension
r6956 self.ui.debug(_("branch renamed from %s to %s at %d\n") %
Patrick Mezard
convert: fix svn_source.latest()
r5955 (path, newpath, revnum))
path = newpath
break
finally:
stream.close()
Patrick Mezard
convert: prevent svn branches to leave the root module tree
r5957 if not path.startswith(self.rootmodule):
self.ui.debug(_('ignoring foreign branch %r\n') % path)
return None
Patrick Mezard
convert: fix svn_source.latest()
r5955 return self.revid(dirent.created_rev, path)
Brendan Cully
convert: svn: add function to get the latest revision touching a path...
r4789
Daniel Holth
convert extension: Add SVN converter
r4765 def reparent(self, module):
Patrick Mezard
convert: restore previous svn transport parent correctly
r6847 """Reparent the svn transport and return the previous parent."""
if self.prevmodule == module:
return module
Patrick Mezard
convert: properly encode subversion URLs (issue 1224)
r7074 svnurl = self.baseurl + urllib.quote(module)
Patrick Mezard
convert: restore previous svn transport parent correctly
r6847 prevmodule = self.prevmodule
if prevmodule is None:
prevmodule = ''
Patrick Mezard
Merge with crew-stable
r7075 self.ui.debug(_("reparent to %s\n") % svnurl)
Patrick Mezard
convert: properly encode subversion URLs (issue 1224)
r7074 svn.ra.reparent(self.ra, svnurl)
Patrick Mezard
convert: restore previous svn transport parent correctly
r6847 self.prevmodule = module
return prevmodule
Daniel Holth
convert extension: Add SVN converter
r4765
Brendan Cully
convert: svn: pull up path to file expansion code into separate function....
r5120 def expandpaths(self, rev, paths, parents):
entries = []
Martin Geisler
convert/subversion: wrap long lines in comments
r8660 # Map of entrypath, revision for finding source of deleted
# revisions.
copyfrom = {}
Brendan Cully
convert: svn: pull up path to file expansion code into separate function....
r5120 copies = {}
Patrick Mezard
convert: fix cross-branches subversion revisions handling...
r5872 new_module, revnum = self.revsplit(rev)[1:]
if new_module != self.module:
self.module = new_module
self.reparent(self.module)
Brendan Cully
convert: look up copies in getchanges instead of getcommit...
r5121
Brendan Cully
convert: svn: pull up path to file expansion code into separate function....
r5120 for path, ent in paths:
Patrick Mezard
convert: rename get_entry_from_path() into an svn_source method
r6539 entrypath = self.getrelpath(path)
Brendan Cully
convert: svn: pull up path to file expansion code into separate function....
r5120
Patrick Mezard
convert: remove leading slash from ra.check_path inputs (issue 1236)
r6848 kind = self._checkpath(entrypath, revnum)
Brendan Cully
convert: svn: pull up path to file expansion code into separate function....
r5120 if kind == svn.core.svn_node_file:
Patrick Mezard
convert/svn: remove confusing unicode variable
r8885 entries.append(self.recode(entrypath))
Patrick Mezard
convert: fix svn file copy detection code
r6546 if not ent.copyfrom_path or not parents:
Patrick Mezard
convert: cleanup svn file copy handling
r6544 continue
Martin Geisler
convert/subversion: wrap long lines in comments
r8660 # Copy sources not in parent revisions cannot be
# represented, ignore their origin for now
Patrick Mezard
convert: fix svn file copy detection code
r6546 pmodule, prevnum = self.revsplit(parents[0])[1:]
if ent.copyfrom_rev < prevnum:
continue
copyfrom_path = self.getrelpath(ent.copyfrom_path, pmodule)
Patrick Mezard
convert: cleanup svn file copy handling
r6544 if not copyfrom_path:
continue
Martin Geisler
i18n: mark strings for translation in convert extension
r6956 self.ui.debug(_("copied to %s from %s@%s\n") %
Patrick Mezard
convert: cleanup svn file copy handling
r6544 (entrypath, copyfrom_path, ent.copyfrom_rev))
Patrick Mezard
convert/svn: remove confusing unicode variable
r8885 copies[self.recode(entrypath)] = self.recode(copyfrom_path)
Brendan Cully
convert: svn: pull up path to file expansion code into separate function....
r5120 elif kind == 0: # gone, but had better be a deleted *file*
Martin Geisler
i18n: mark strings for translation in convert extension
r6956 self.ui.debug(_("gone from %s\n") % ent.copyfrom_rev)
Patrick Mezard
convert/svn: remove dead code from entry deletion code path...
r8884 pmodule, prevnum = self.revsplit(parents[0])[1:]
parentpath = pmodule + "/" + entrypath
self.ui.debug(_("entry %s\n") % parentpath)
Brendan Cully
convert: svn: pull up path to file expansion code into separate function....
r5120
Martin Geisler
convert/subversion: wrap long lines in comments
r8660 # We can avoid the reparent calls if the module has
# not changed but it probably does not worth the pain.
Patrick Mezard
convert: restore previous svn transport parent correctly
r6847 prevmodule = self.reparent('')
Patrick Mezard
convert/svn: remove dead code from entry deletion code path...
r8884 fromkind = svn.ra.check_path(self.ra, parentpath.strip('/'), prevnum)
Patrick Mezard
convert: restore previous svn transport parent correctly
r6847 self.reparent(prevmodule)
Thomas Arendsen Hein
Removed trailing spaces from everything except test output
r6210
Patrick Mezard
convert/svn: remove dead code and obsolete comments
r8881 if fromkind == svn.core.svn_node_file:
Patrick Mezard
convert/svn: remove confusing unicode variable
r8885 entries.append(self.recode(entrypath))
Brendan Cully
convert: svn: pull up path to file expansion code into separate function....
r5120 elif fromkind == svn.core.svn_node_dir:
if ent.action == 'C':
Patrick Mezard
convert/svn: remove dead code from entry deletion code path...
r8884 children = self._find_children(path, prevnum)
Brendan Cully
convert: svn: pull up path to file expansion code into separate function....
r5120 else:
Patrick Mezard
convert/svn: remove dead code from entry deletion code path...
r8884 oroot = parentpath.strip('/')
Brendan Cully
convert: svn: pull up path to file expansion code into separate function....
r5120 nroot = path.strip('/')
Patrick Mezard
convert/svn: remove dead code from entry deletion code path...
r8884 children = self._find_children(oroot, prevnum)
Brendan Cully
convert: svn: pull up path to file expansion code into separate function....
r5120 children = [s.replace(oroot,nroot) for s in children]
Patrick Mezard
convert/svn: remove a useless recode() call in deletion path
r8883
Brendan Cully
convert: svn: pull up path to file expansion code into separate function....
r5120 for child in children:
Patrick Mezard
convert/svn: remove dead code from entry deletion code path...
r8884 childpath = self.getrelpath("/" + child, pmodule)
if not childpath:
Patrick Mezard
convert/svn: remove a useless recode() call in deletion path
r8883 continue
Patrick Mezard
convert/svn: remove dead code from entry deletion code path...
r8884 if childpath in copies:
del copies[childpath]
entries.append(childpath)
Brendan Cully
convert: svn: pull up path to file expansion code into separate function....
r5120 else:
Martin Geisler
i18n: mark strings for translation in convert extension
r6956 self.ui.debug(_('unknown path in revision %d: %s\n') % \
Brendan Cully
convert: svn: pull up path to file expansion code into separate function....
r5120 (revnum, path))
elif kind == svn.core.svn_node_dir:
# If the directory just had a prop change,
# then we shouldn't need to look for its children.
Patrick Mezard
convert: don't scan directories on property changes
r5870 if ent.action == 'M':
continue
Matt Mackall
replace util.sort with sorted built-in...
r8209 children = sorted(self._find_children(path, revnum))
Brendan Cully
convert: svn: pull up path to file expansion code into separate function....
r5120 for child in children:
# Can we move a child directory and its
# parent in the same commit? (probably can). Could
# cause problems if instead of revnum -1,
# we have to look in (copyfrom_path, revnum - 1)
Patrick Mezard
convert: rename get_entry_from_path() into an svn_source method
r6539 entrypath = self.getrelpath("/" + child)
Brendan Cully
convert: svn: pull up path to file expansion code into separate function....
r5120 if entrypath:
# Need to filter out directories here...
Patrick Mezard
convert: remove leading slash from ra.check_path inputs (issue 1236)
r6848 kind = self._checkpath(entrypath, revnum)
Brendan Cully
convert: svn: pull up path to file expansion code into separate function....
r5120 if kind != svn.core.svn_node_dir:
entries.append(self.recode(entrypath))
Patrick Mezard
convert/svn: remove dead code and obsolete comments
r8881 # Handle directory copies
Patrick Mezard
convert: handle past or foreign partial svn copies...
r6543 if not ent.copyfrom_path or not parents:
Patrick Mezard
convert: more cleanup in svn directory copy handling
r6542 continue
Martin Geisler
convert/subversion: wrap long lines in comments
r8660 # Copy sources not in parent revisions cannot be
# represented, ignore their origin for now
Patrick Mezard
convert: handle past or foreign partial svn copies...
r6543 pmodule, prevnum = self.revsplit(parents[0])[1:]
if ent.copyfrom_rev < prevnum:
continue
Patrick Mezard
convert/svn: remove useless encoding/decoding calls (issue1676)
r8882 copyfrompath = self.getrelpath(ent.copyfrom_path, pmodule)
Patrick Mezard
convert: more cleanup in svn directory copy handling
r6542 if not copyfrompath:
continue
copyfrom[path] = ent
Martin Geisler
i18n: mark strings for translation in convert extension
r6956 self.ui.debug(_("mark %s came from %s:%d\n")
Patrick Mezard
convert: more cleanup in svn directory copy handling
r6542 % (path, copyfrompath, ent.copyfrom_rev))
children = self._find_children(ent.copyfrom_path, ent.copyfrom_rev)
children.sort()
for child in children:
Patrick Mezard
convert: handle past or foreign partial svn copies...
r6543 entrypath = self.getrelpath("/" + child, pmodule)
Patrick Mezard
convert: more cleanup in svn directory copy handling
r6542 if not entrypath:
continue
Patrick Mezard
convert/svn: remove useless encoding/decoding calls (issue1676)
r8882 copytopath = path + entrypath[len(copyfrompath):]
Patrick Mezard
convert: more cleanup in svn directory copy handling
r6542 copytopath = self.getrelpath(copytopath)
Patrick Mezard
convert/svn: remove useless encoding/decoding calls (issue1676)
r8882 copies[self.recode(copytopath)] = self.recode(entrypath)
Brendan Cully
convert: svn: pull up path to file expansion code into separate function....
r5120
Martin Geisler
util: use built-in set instead of util.unique
r8151 return (list(set(entries)), copies)
Brendan Cully
convert: svn: pull up path to file expansion code into separate function....
r5120
Patrick Mezard
convert: fix parents of last fetched svn revision
r5871 def _fetch_revisions(self, from_revnum, to_revnum):
if from_revnum < to_revnum:
from_revnum, to_revnum = to_revnum, from_revnum
Bryan O'Sullivan
convert/subversion: reduce memory usage by filtering early...
r4940 self.child_cset = None
Patrick Mezard
convert: fix svn branch source detection corner case...
r6545
Bryan O'Sullivan
convert/subversion: work around memory leak in svn's python bindings...
r4946 def parselogentry(orig_paths, revnum, author, date, message):
Thomas Arendsen Hein
Removed trailing spaces from everything except test output
r6210 """Return the parsed commit object or None, and True if
Patrick Mezard
convert: fix cross-branches subversion revisions handling...
r5872 the revision is a branch root.
"""
Martin Geisler
i18n: mark strings for translation in convert extension
r6956 self.ui.debug(_("parsing revision %d (%d changes)\n") %
Bryan O'Sullivan
convert/subversion: work around memory leak in svn's python bindings...
r4946 (revnum, len(orig_paths)))
Bryan O'Sullivan
convert/subversion: reduce memory usage by filtering early...
r4940
Patrick Mezard
convert: prevent svn branches to leave the root module tree
r5957 branched = False
Brendan Cully
convert: move some code into common init function
r4810 rev = self.revid(revnum)
Brendan Cully
convert: svn: some improvements in memory usage
r4837 # branch log might return entries for a parent we already have
Patrick Mezard
convert: fix parents of last fetched svn revision
r5871
Martin Geisler
remove unnecessary outer parenthesis in if-statements
r8117 if rev in self.commits or revnum < to_revnum:
Patrick Mezard
convert: prevent svn branches to leave the root module tree
r5957 return None, branched
Brendan Cully
convert: svn: some improvements in memory usage
r4837
Brendan Cully
convert: svn: pull up path to file expansion code into separate function....
r5120 parents = []
Patrick Mezard
convert: follow svn module parent moves
r5958 # check whether this revision is the start of a branch or part
# of a branch renaming
Matt Mackall
replace util.sort with sorted built-in...
r8209 orig_paths = sorted(orig_paths.iteritems())
Patrick Mezard
convert: follow svn module parent moves
r5958 root_paths = [(p,e) for p,e in orig_paths if self.module.startswith(p)]
if root_paths:
path, ent = root_paths[-1]
Brendan Cully
convert: svn: hoist up branch creation check
r5119 if ent.copyfrom_path:
Patrick Mezard
convert: prevent svn branches to leave the root module tree
r5957 branched = True
Patrick Mezard
convert: follow svn module parent moves
r5958 newpath = ent.copyfrom_path + self.module[len(path):]
Brendan Cully
convert: svn: hoist up branch creation check
r5119 # ent.copyfrom_rev may not be the actual last revision
Patrick Mezard
convert: backout a7492fb2107b...
r7476 previd = self.latest(newpath, ent.copyfrom_rev)
Patrick Mezard
convert: prevent svn branches to leave the root module tree
r5957 if previd is not None:
prevmodule, prevnum = self.revsplit(previd)[1:]
Patrick Mezard
convert: add shallow, single branch svn conversions via svn.startrev
r6173 if prevnum >= self.startrev:
parents = [previd]
Martin Geisler
i18n: mark strings for translation in convert extension
r6956 self.ui.note(_('found parent of branch %s at %d: %s\n') %
Patrick Mezard
convert: add shallow, single branch svn conversions via svn.startrev
r6173 (self.module, prevnum, prevmodule))
Brendan Cully
convert: svn: hoist up branch creation check
r5119 else:
Martin Geisler
lowercase ui.debug and assert output...
r7599 self.ui.debug(_("no copyfrom path, don't know what to do.\n"))
Brendan Cully
convert: svn: hoist up branch creation check
r5119
Brendan Cully
convert: svn: pull up path to file expansion code into separate function....
r5120 paths = []
# filter out unrelated paths
Bryan O'Sullivan
convert/subversion: reduce memory usage by filtering early...
r4940 for path, ent in orig_paths:
Patrick Mezard
convert: improve subversion branch filtering
r6540 if self.getrelpath(path) is None:
Brendan Cully
convert: svn: add an early return to move most changeset parsing out an indent level
r4788 continue
Brendan Cully
convert: svn: pull up path to file expansion code into separate function....
r5120 paths.append((path, ent))
Daniel Holth
convert extension: Add SVN converter
r4765
Brendan Cully
convert: svn: add an early return to move most changeset parsing out an indent level
r4788 # Example SVN datetime. Includes microseconds.
# ISO-8601 conformant
# '2007-01-04T17:35:00.902377Z'
David J. Mellor
convert: fix SVN date parser dropping the final whole second digit
r5617 date = util.parsedate(date[:19] + " UTC", ["%Y-%m-%dT%H:%M:%S"])
Daniel Holth
convert extension: Add SVN converter
r4765
Thomas Arendsen Hein
convert: Do not abort with TypeError if svn commit message is None (issue934)
r5916 log = message and self.recode(message) or ''
Brendan Cully
convert: svn: add an early return to move most changeset parsing out an indent level
r4788 author = author and self.recode(author) or ''
Brendan Cully
convert: svn: pull up path to file expansion code into separate function....
r5120 try:
branch = self.module.split("/")[-1]
if branch == 'trunk':
branch = ''
except IndexError:
branch = None
Daniel Holth
convert extension: Add SVN converter
r4765
Brendan Cully
convert: svn: add an early return to move most changeset parsing out an indent level
r4788 cset = commit(author=author,
Thomas Arendsen Hein
removed trailing whitespace
r4957 date=util.datestr(date),
desc=log,
Brendan Cully
convert: svn: get parent for branch creation events
r4795 parents=parents,
Brendan Cully
convert: record the source revision in the changelog
r4873 branch=branch,
Patrick Mezard
convert/svn: stop returning unicode revision identifiers
r8886 rev=rev)
Brendan Cully
convert: svn: add an early return to move most changeset parsing out an indent level
r4788
Brendan Cully
convert: svn: pull out broken batching code, add alpha tags support
r4796 self.commits[rev] = cset
Patrick Mezard
convert: fix cross-branches subversion revisions handling...
r5872 # The parents list is *shared* among self.paths and the
# commit object. Both will be updated below.
self.paths[rev] = (paths, cset.parents)
Brendan Cully
convert: svn: pull out broken batching code, add alpha tags support
r4796 if self.child_cset and not self.child_cset.parents:
Patrick Mezard
convert: fix cross-branches subversion revisions handling...
r5872 self.child_cset.parents[:] = [rev]
Brendan Cully
convert: svn: add an early return to move most changeset parsing out an indent level
r4788 self.child_cset = cset
Patrick Mezard
convert: prevent svn branches to leave the root module tree
r5957 return cset, branched
Brendan Cully
convert: svn: pull out broken batching code, add alpha tags support
r4796
Martin Geisler
i18n: mark strings for translation in convert extension
r6956 self.ui.note(_('fetching revision log for "%s" from %d to %d\n') %
Brendan Cully
convert: svn: autodetect /branches, /tags, /trunk....
r4797 (self.module, from_revnum, to_revnum))
Daniel Holth
convert extension: Add SVN converter
r4765
try:
Patrick Mezard
convert: fix parents of last fetched svn revision
r5871 firstcset = None
Patrick Mezard
convert: add shallow, single branch svn conversions via svn.startrev
r6173 lastonbranch = False
Patrick Mezard
convert: normalize paths sent to svn get_log (issue 1219)
r6850 stream = self._getlog([self.module], from_revnum, to_revnum)
Patrick Mezard
convert: make svn revision iterator interruptible
r5873 try:
for entry in stream:
paths, revnum, author, date, message = entry
Patrick Mezard
convert: add shallow, single branch svn conversions via svn.startrev
r6173 if revnum < self.startrev:
lastonbranch = True
break
Francis Barber
Fix subversion convert not detecting empty changesets....
r8172 if not paths:
Martin Geisler
i18n: mark strings for translation in convert extension
r6956 self.ui.debug(_('revision %d has no entries\n') % revnum)
Patrick Mezard
convert: make svn revision iterator interruptible
r5873 continue
Thomas Arendsen Hein
Removed trailing spaces from everything except test output
r6210 cset, lastonbranch = parselogentry(paths, revnum, author,
Patrick Mezard
convert: add shallow, single branch svn conversions via svn.startrev
r6173 date, message)
Patrick Mezard
convert: make svn revision iterator interruptible
r5873 if cset:
firstcset = cset
Patrick Mezard
convert: add shallow, single branch svn conversions via svn.startrev
r6173 if lastonbranch:
Patrick Mezard
convert: make svn revision iterator interruptible
r5873 break
finally:
stream.close()
Patrick Mezard
convert: fix parents of last fetched svn revision
r5871
Patrick Mezard
convert: add shallow, single branch svn conversions via svn.startrev
r6173 if not lastonbranch and firstcset and not firstcset.parents:
Patrick Mezard
convert: fix parents of last fetched svn revision
r5871 # The first revision of the sequence (the last fetched one)
# has invalid parents if not a branch root. Find the parent
# revision now, if any.
try:
firstrevnum = self.revnum(firstcset.rev)
if firstrevnum > 1:
latest = self.latest(self.module, firstrevnum - 1)
Patrick Mezard
convert: prevent svn branches to leave the root module tree
r5957 if latest:
firstcset.parents.append(latest)
Patrick Mezard
convert: be even more tolerant when detecting svn tags...
r7381 except SvnPathNotFound:
Patrick Mezard
convert: fix parents of last fetched svn revision
r5871 pass
Thomas Arendsen Hein
Replace _ with inst for catching exceptions to not shadow gettext....
r5140 except SubversionException, (inst, num):
Daniel Holth
convert extension: Add SVN converter
r4765 if num == svn.core.SVN_ERR_FS_NO_SUCH_REVISION:
Martin Geisler
i18n: mark strings for translation in convert extension
r6956 raise util.Abort(_('svn: branch has no revision %s') % to_revnum)
Daniel Holth
convert extension: Add SVN converter
r4765 raise
def _getfile(self, file, rev):
# TODO: ra.get_file transmits the whole file instead of diffs.
mode = ''
try:
Patrick Mezard
convert: fix cross-branches subversion revisions handling...
r5872 new_module, revnum = self.revsplit(rev)[1:]
if self.module != new_module:
self.module = new_module
Daniel Holth
convert extension: Add SVN converter
r4765 self.reparent(self.module)
Patrick Mezard
convert: work around svn.ra.get_files() not releasing input buffer
r7446 io = StringIO()
Daniel Holth
convert extension: Add SVN converter
r4765 info = svn.ra.get_file(self.ra, file, revnum, io)
Patrick Mezard
convert: work around svn.ra.get_files() not releasing input buffer
r7446 data = io.getvalue()
# ra.get_files() seems to keep a reference on the input buffer
# preventing collection. Release it explicitely.
io.close()
Daniel Holth
convert extension: Add SVN converter
r4765 if isinstance(info, list):
info = info[-1]
mode = ("svn:executable" in info) and 'x' or ''
mode = ("svn:special" in info) and 'l' or mode
except SubversionException, e:
notfound = (svn.core.SVN_ERR_FS_NOT_FOUND,
svn.core.SVN_ERR_RA_DAV_PATH_NOT_FOUND)
if e.apr_err in notfound: # File not found
raise IOError()
raise
if mode == 'l':
link_prefix = "link "
if data.startswith(link_prefix):
data = data[len(link_prefix):]
return data, mode
def _find_children(self, path, revnum):
Brendan Cully
convert: svn: ensure leading / is removed from paths in _find_children (broken in 2bd996d0aaf8)
r5114 path = path.strip('/')
Daniel Holth
convert extension: Add SVN converter
r4765 pool = Pool()
Patrick Mezard
convert: properly encode subversion URLs (issue 1224)
r7074 rpath = '/'.join([self.baseurl, urllib.quote(path)]).strip('/')
Dirkjan Ochtman
clean up trailing spaces
r7184 return ['%s/%s' % (path, x) for x in
Patrick Mezard
convert: properly encode subversion URLs (issue 1224)
r7074 svn.client.ls(rpath, optrev(revnum), True, self.ctx, pool).keys()]
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513
Patrick Mezard
convert: rename get_entry_from_path() into an svn_source method
r6539 def getrelpath(self, path, module=None):
if module is None:
module = self.module
# Given the repository url of this wc, say
# "http://server/plone/CMFPlone/branches/Plone-2_0-branch"
# extract the "entry" portion (a relative path) from what
# svn log --xml says, ie
# "/CMFPlone/branches/Plone-2_0-branch/tests/PloneTestCase.py"
# that is to say "tests/PloneTestCase.py"
if path.startswith(module):
relative = path.rstrip('/')[len(module):]
if relative.startswith('/'):
return relative[1:]
elif relative == '':
return relative
# The path is outside our tracked tree...
Martin Geisler
i18n: mark strings for translation in convert extension
r6956 self.ui.debug(_('%r is not under %r, ignoring\n') % (path, module))
Patrick Mezard
convert: rename get_entry_from_path() into an svn_source method
r6539 return None
Patrick Mezard
convert: remove leading slash from ra.check_path inputs (issue 1236)
r6848 def _checkpath(self, path, revnum):
# ra.check_path does not like leading slashes very much, it leads
# to PROPFIND subversion errors
return svn.ra.check_path(self.ra, path.strip('/'), revnum)
Patrick Mezard
convert: normalize paths sent to svn get_log (issue 1219)
r6850 def _getlog(self, paths, start, end, limit=0, discover_changed_paths=True,
strict_node_history=False):
# Normalize path names, svn >= 1.5 only wants paths relative to
# supplied URL
relpaths = []
for p in paths:
if not p.startswith('/'):
p = self.module + '/' + p
relpaths.append(p.strip('/'))
Patrick Mezard
convert: properly encode subversion URLs (issue 1224)
r7074 args = [self.baseurl, relpaths, start, end, limit, discover_changed_paths,
Patrick Mezard
convert: normalize paths sent to svn get_log (issue 1219)
r6850 strict_node_history]
arg = encodeargs(args)
hgexe = util.hgexecutable()
cmd = '%s debugsvnlog' % util.shellquote(hgexe)
Martin Geisler
util: remove ignored mode argument in popen[23]
r8339 stdin, stdout = util.popen2(cmd)
Patrick Mezard
convert: normalize paths sent to svn get_log (issue 1219)
r6850 stdin.write(arg)
stdin.close()
return logstream(stdout)
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 pre_revprop_change = '''#!/bin/sh
REPOS="$1"
REV="$2"
USER="$3"
PROPNAME="$4"
ACTION="$5"
if [ "$ACTION" = "M" -a "$PROPNAME" = "svn:log" ]; then exit 0; fi
if [ "$ACTION" = "A" -a "$PROPNAME" = "hg:convert-branch" ]; then exit 0; fi
if [ "$ACTION" = "A" -a "$PROPNAME" = "hg:convert-rev" ]; then exit 0; fi
echo "Changing prohibited revision property" >&2
exit 1
'''
class svn_sink(converter_sink, commandline):
commit_re = re.compile(r'Committed revision (\d+).', re.M)
def prerun(self):
if self.wc:
os.chdir(self.wc)
def postrun(self):
if self.wc:
os.chdir(self.cwd)
def join(self, name):
return os.path.join(self.wc, '.svn', name)
Thomas Arendsen Hein
Removed tabs and trailing whitespace in python files
r5760
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 def revmapfile(self):
return self.join('hg-shamap')
def authorfile(self):
return self.join('hg-authormap')
def __init__(self, ui, path):
converter_sink.__init__(self, ui, path)
commandline.__init__(self, ui, 'svn')
self.delete = []
Maxim Dounin
convert: svn-sink: copy and set properties after adding dirs/files...
r5698 self.setexec = []
self.delexec = []
self.copies = []
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 self.wc = None
self.cwd = os.getcwd()
path = os.path.realpath(path)
created = False
if os.path.isfile(os.path.join(path, '.svn', 'entries')):
self.wc = path
self.run0('update')
else:
Patrick Mezard
convert: fix svn file:// URL generation under Windows
r5535 wcpath = os.path.join(os.getcwd(), os.path.basename(path) + '-wc')
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 if os.path.isdir(os.path.dirname(path)):
if not os.path.exists(os.path.join(path, 'db', 'fs-type')):
ui.status(_('initializing svn repo %r\n') %
os.path.basename(path))
commandline(ui, 'svnadmin').run0('create', path)
created = path
Shun-ichi GOTO
Use util.normpath() instead of direct path string operation....
r5842 path = util.normpath(path)
Patrick Mezard
convert: fix svn file:// URL generation under Windows
r5535 if not path.startswith('/'):
path = '/' + path
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 path = 'file://' + path
Thomas Arendsen Hein
Removed tabs and trailing whitespace in python files
r5760
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 ui.status(_('initializing svn wc %r\n') % os.path.basename(wcpath))
self.run0('checkout', path, wcpath)
self.wc = wcpath
self.opener = util.opener(self.wc)
self.wopener = util.opener(self.wc)
self.childmap = mapfile(ui, self.join('hg-childmap'))
Patrick Mezard
convert: force svn:executable when execute-bit is not supported...
r5536 self.is_exec = util.checkexec(self.wc) and util.is_exec or None
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513
if created:
hook = os.path.join(created, 'hooks', 'pre-revprop-change')
fp = open(hook, 'w')
fp.write(pre_revprop_change)
fp.close()
Matt Mackall
util: set_flags shouldn't know about repo flag formats
r6877 util.set_flags(hook, False, True)
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513
Bryan O'Sullivan
convert: tell the source repository when a rev has been converted...
r5554 xport = transport.SvnRaTransport(url=geturl(path))
self.uuid = svn.ra.get_uuid(xport.ra)
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 def wjoin(self, *names):
return os.path.join(self.wc, *names)
def putfile(self, filename, flags, data):
if 'l' in flags:
self.wopener.symlink(data, filename)
else:
try:
if os.path.islink(self.wjoin(filename)):
os.unlink(filename)
except OSError:
pass
self.wopener(filename, 'w').write(data)
Patrick Mezard
convert: force svn:executable when execute-bit is not supported...
r5536
if self.is_exec:
was_exec = self.is_exec(self.wjoin(filename))
else:
# On filesystems not supporting execute-bit, there is no way
# to know if it is set but asking subversion. Setting it
# systematically is just as expensive and much simpler.
was_exec = 'x' not in flags
Matt Mackall
util: set_flags shouldn't know about repo flag formats
r6877 util.set_flags(self.wjoin(filename), False, 'x' in flags)
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 if was_exec:
if 'x' not in flags:
Maxim Dounin
convert: svn-sink: copy and set properties after adding dirs/files...
r5698 self.delexec.append(filename)
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 else:
if 'x' in flags:
Maxim Dounin
convert: svn-sink: copy and set properties after adding dirs/files...
r5698 self.setexec.append(filename)
def _copyfile(self, source, dest):
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 # SVN's copy command pukes if the destination file exists, but
# our copyfile method expects to record a copy that has
# already occurred. Cross the semantic gap.
wdest = self.wjoin(dest)
exists = os.path.exists(wdest)
if exists:
fd, tempname = tempfile.mkstemp(
prefix='hg-copy-', dir=os.path.dirname(wdest))
os.close(fd)
os.unlink(tempname)
os.rename(wdest, tempname)
try:
self.run0('copy', source, dest)
finally:
if exists:
try:
os.unlink(wdest)
except OSError:
pass
os.rename(tempname, wdest)
def dirs_of(self, files):
Martin Geisler
util: use built-in set and frozenset...
r8150 dirs = set()
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 for f in files:
if os.path.isdir(self.wjoin(f)):
dirs.add(f)
for i in strutil.rfindall(f, '/'):
dirs.add(f[:i])
return dirs
Maxim Dounin
convert: svn-sink: copy and set properties after adding dirs/files...
r5698 def add_dirs(self, files):
Matt Mackall
replace util.sort with sorted built-in...
r8209 add_dirs = [d for d in sorted(self.dirs_of(files))
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 if not os.path.exists(self.wjoin(d, '.svn', 'entries'))]
if add_dirs:
Maxim Dounin
convert: add commandline.xargs(), use it in svn_sink class...
r5832 self.xargs(add_dirs, 'add', non_recursive=True, quiet=True)
Maxim Dounin
convert: svn-sink: copy and set properties after adding dirs/files...
r5698 return add_dirs
def add_files(self, files):
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 if files:
Maxim Dounin
convert: add commandline.xargs(), use it in svn_sink class...
r5832 self.xargs(files, 'add', quiet=True)
Maxim Dounin
convert: svn-sink: copy and set properties after adding dirs/files...
r5698 return files
Thomas Arendsen Hein
Removed tabs and trailing whitespace in python files
r5760
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 def tidy_dirs(self, names):
deleted = []
Matt Mackall
replace util.sort with sorted built-in...
r8209 for d in sorted(self.dirs_of(names), reverse=True):
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 wd = self.wjoin(d)
if os.listdir(wd) == '.svn':
self.run0('delete', d)
deleted.append(d)
return deleted
def addchild(self, parent, child):
self.childmap[parent] = child
Bryan O'Sullivan
convert: tell the source repository when a rev has been converted...
r5554 def revid(self, rev):
return u"svn:%s@%s" % (self.uuid, rev)
Maxim Dounin
convert: svn-sink: copy and set properties after adding dirs/files...
r5698
Patrick Mezard
convert: rewrite tags when converting from hg to hg
r8693 def putcommit(self, files, copies, parents, commit, source, revmap):
Patrick Mezard
convert: reintegrate file retrieval code in sinks...
r6716 # Apply changes to working copy
for f, v in files:
try:
data = source.getfile(f, v)
Peter Arrenbrecht
cleanup: drop unused assignments
r7875 except IOError:
Patrick Mezard
convert: reintegrate file retrieval code in sinks...
r6716 self.delete.append(f)
else:
e = source.getmode(f, v)
self.putfile(f, e, data)
if f in copies:
self.copies.append([copies[f], f])
files = [f[0] for f in files]
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 for parent in parents:
try:
Bryan O'Sullivan
convert: tell the source repository when a rev has been converted...
r5554 return self.revid(self.childmap[parent])
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 except KeyError:
pass
Martin Geisler
util: use built-in set and frozenset...
r8150 entries = set(self.delete)
files = frozenset(files)
Maxim Dounin
convert: svn-sink: copy and set properties after adding dirs/files...
r5698 entries.update(self.add_dirs(files.difference(entries)))
if self.copies:
for s, d in self.copies:
self._copyfile(s, d)
self.copies = []
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 if self.delete:
Maxim Dounin
convert: add commandline.xargs(), use it in svn_sink class...
r5832 self.xargs(self.delete, 'delete')
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 self.delete = []
entries.update(self.add_files(files.difference(entries)))
entries.update(self.tidy_dirs(entries))
Maxim Dounin
convert: svn-sink: copy and set properties after adding dirs/files...
r5698 if self.delexec:
Maxim Dounin
convert: add commandline.xargs(), use it in svn_sink class...
r5832 self.xargs(self.delexec, 'propdel', 'svn:executable')
Maxim Dounin
convert: svn-sink: copy and set properties after adding dirs/files...
r5698 self.delexec = []
if self.setexec:
Maxim Dounin
convert: add commandline.xargs(), use it in svn_sink class...
r5832 self.xargs(self.setexec, 'propset', 'svn:executable', '*')
Maxim Dounin
convert: svn-sink: copy and set properties after adding dirs/files...
r5698 self.setexec = []
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 fd, messagefile = tempfile.mkstemp(prefix='hg-convert-')
fp = os.fdopen(fd, 'w')
fp.write(commit.desc)
fp.close()
try:
output = self.run0('commit',
username=util.shortuser(commit.author),
file=messagefile,
Shun-ichi GOTO
convert: svn_sink: workaround of command line size limitation on win32....
r5790 encoding='utf-8')
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 try:
rev = self.commit_re.search(output).group(1)
except AttributeError:
self.ui.warn(_('unexpected svn output:\n'))
self.ui.warn(output)
raise util.Abort(_('unable to cope with svn output'))
if commit.rev:
self.run('propset', 'hg:convert-rev', commit.rev,
revprop=True, revision=rev)
if commit.branch and commit.branch != 'default':
self.run('propset', 'hg:convert-branch', commit.branch,
revprop=True, revision=rev)
for parent in parents:
self.addchild(parent, rev)
Bryan O'Sullivan
convert: tell the source repository when a rev has been converted...
r5554 return self.revid(rev)
Bryan O'Sullivan
convert: add support for Subversion as a sink
r5513 finally:
os.unlink(messagefile)
def puttags(self, tags):
self.ui.warn(_('XXX TAGS NOT IMPLEMENTED YET\n'))