# HG changeset patch # User Augie Fackler # Date 1330203082 21600 # Node ID 9ce00cb1d6766b5df59662c3ac5e649b5342df88 # Parent d3bc067c0f72135d2d72da84be11cbca9afb8146# Parent 4e203a47102a1fa75224e7e12bab78ccb921e0bf Merge alternate tunnel schemes. diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -12,3 +12,8 @@ MANIFEST dist *.egg-info hgsubversion/__version__.py +nbproject +.project +.pydevproject +.settings +*.orig diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -5,3 +5,4 @@ 8e621dbb82d4363a85317638ad237e2817c56347 093ae2915b452539b44390ee4ea14987484e1eee 1.1.2 708234ad6c97fb52417e0b46a86c8373e25123a5 1.2 4bbc6bf947f56a92e95a04a27b94a9f72d5482d7 1.2.1 +0cbf9fd89672e73165e1bb4db1ec8f7f65b95c94 1.3 diff --git a/hgsubversion/editor.py b/hgsubversion/editor.py --- a/hgsubversion/editor.py +++ b/hgsubversion/editor.py @@ -119,7 +119,7 @@ class HgEditor(svnwrap.Editor): # assuming it is a directory self.current.externals[path] = None map(self.current.delete, [pat for pat in self.current.files.iterkeys() - if pat.startswith(path+'/')]) + if pat.startswith(path + '/')]) for f in ctx.walk(util.PrefixMatch(br_path2)): f_p = '%s/%s' % (path, f[len(br_path2):]) if f_p not in self.current.files: @@ -335,23 +335,26 @@ class HgEditor(svnwrap.Editor): self.stream = target handler = svnwrap.apply_txdelta(base, target) - if not callable(handler): #pragma: no cover + if not callable(handler): # pragma: no cover raise hgutil.Abort('Error in Subversion bindings: ' 'cannot call handler!') def txdelt_window(window): try: if not self.meta.is_path_valid(self.current.file): return + # Already get and store the value here, because calling + # handler(window) seems to close the target in Subversion 1.7. + val = target.getvalue() handler(window) # window being None means commit this file if not window: - self.current.files[self.current.file] = target.getvalue() - except svnwrap.SubversionException, e: #pragma: no cover + self.current.files[self.current.file] = val + except svnwrap.SubversionException, e: # pragma: no cover if e.args[1] == svnwrap.ERR_INCOMPLETE_DATA: self.current.missing.add(self.current.file) - else: #pragma: no cover + else: # pragma: no cover raise hgutil.Abort(*e.args) - except: #pragma: no cover + except: # pragma: no cover print len(base), self.current.file self._exception_info = sys.exc_info() raise diff --git a/hgsubversion/help/subversion.rst b/hgsubversion/help/subversion.rst --- a/hgsubversion/help/subversion.rst +++ b/hgsubversion/help/subversion.rst @@ -306,6 +306,17 @@ settings: Set the username or password for accessing Subversion repositories. + ``hgsubversion.password_stores`` + + List of methods to use for storing passwords (similar to the option of the + same name in the subversion configuration files). Default is + ``gnome_keyring,keychain,kwallet,windows``. Password stores can be disabled + completely by setting this to an empty value. + + .. NOTE:: + + Password stores are only supported with the SWIG bindings. + ``hgsubversion.stupid`` Setting this boolean option to true will force using a slower method for pulling revisions from Subversion. This method is compatible with servers diff --git a/hgsubversion/maps.py b/hgsubversion/maps.py --- a/hgsubversion/maps.py +++ b/hgsubversion/maps.py @@ -5,6 +5,7 @@ from mercurial import util as hgutil from mercurial import node import svncommands +import util class AuthorMap(dict): '''A mapping from Subversion-style authors to Mercurial-style @@ -20,7 +21,7 @@ class AuthorMap(dict): The ui argument is used to print diagnostic messages. The path argument is the location of the backing store, - typically .hg/authormap. + typically .hg/svn/authors. ''' self.ui = ui self.path = path @@ -136,14 +137,14 @@ class Tags(dict): print 'tagmap too new -- please upgrade' raise NotImplementedError for l in f: - hash, revision, tag = l.split(' ', 2) + ha, revision, tag = l.split(' ', 2) revision = int(revision) tag = tag[:-1] if self.endrev is not None and revision > self.endrev: break if not tag: continue - dict.__setitem__(self, tag, node.bin(hash)) + dict.__setitem__(self, tag, node.bin(ha)) f.close() def _write(self): @@ -168,11 +169,11 @@ class Tags(dict): def __setitem__(self, tag, info): if not tag: raise hgutil.Abort('tag cannot be empty') - hash, revision = info + ha, revision = info f = open(self.path, 'a') - f.write('%s %s %s\n' % (node.hex(hash), revision, tag)) + f.write('%s %s %s\n' % (node.hex(ha), revision, tag)) f.close() - dict.__setitem__(self, tag, hash) + dict.__setitem__(self, tag, ha) class RevMap(dict): @@ -185,11 +186,10 @@ class RevMap(dict): self.ypath = os.path.join(repo.path, 'svn', 'lastpulled') # TODO(durin42): Consider moving management of the youngest # file to svnmeta itself rather than leaving it here. - self._youngest = 0 # must load youngest file first, or else self._load() can # clobber the info - if os.path.isfile(self.ypath): - self._youngest = int(open(self.ypath).read().strip()) + _yonngest_str = util.load_string(self.ypath, '0') + self._youngest = int(_yonngest_str.strip()) self.oldest = 0 if os.path.isfile(self.path): self._load() @@ -198,9 +198,7 @@ class RevMap(dict): def _set_youngest(self, rev): self._youngest = max(self._youngest, rev) - fp = open(self.ypath, 'wb') - fp.write(str(self._youngest) + '\n') - fp.close() + util.save_string(self.ypath, str(self._youngest) + '\n') def _get_youngest(self): return self._youngest @@ -221,7 +219,7 @@ class RevMap(dict): print 'revmap too new -- please upgrade' raise NotImplementedError for l in f: - revnum, hash, branch = l.split(' ', 2) + revnum, ha, branch = l.split(' ', 2) if branch == '\n': branch = None else: @@ -231,7 +229,7 @@ class RevMap(dict): self.youngest = revnum if revnum < self.oldest or not self.oldest: self.oldest = revnum - dict.__setitem__(self, (revnum, branch), node.bin(hash)) + dict.__setitem__(self, (revnum, branch), node.bin(ha)) f.close() def _write(self): @@ -239,70 +237,96 @@ class RevMap(dict): f.write('%s\n' % self.VERSION) f.close() - def __setitem__(self, key, hash): + def __setitem__(self, key, ha): revnum, branch = key f = open(self.path, 'a') b = branch or '' - f.write(str(revnum) + ' ' + node.hex(hash) + ' ' + b + '\n') + f.write(str(revnum) + ' ' + node.hex(ha) + ' ' + b + '\n') f.close() if revnum > self.youngest or not self.youngest: self.youngest = revnum if revnum < self.oldest or not self.oldest: self.oldest = revnum - dict.__setitem__(self, (revnum, branch), hash) + dict.__setitem__(self, (revnum, branch), ha) class FileMap(object): - def __init__(self, repo): - self.ui = repo.ui + VERSION = 1 + + def __init__(self, ui, path): + '''Initialise a new FileMap. + + The ui argument is used to print diagnostic messages. + + The path argument is the location of the backing store, + typically .hg/svn/filemap. + ''' + self.ui = ui + self.path = path self.include = {} self.exclude = {} - filemap = repo.ui.config('hgsubversion', 'filemap') - if filemap and os.path.exists(filemap): - self.load(filemap) + if os.path.isfile(self.path): + self._load() + else: + self._write() def _rpairs(self, name): - yield '.', name e = len(name) while e != -1: yield name[:e], name[e+1:] e = name.rfind('/', 0, e) + yield '.', name - def check(self, map, path): - map = getattr(self, map) - for pre, suf in self._rpairs(path): - if pre not in map: - continue - return map[pre] - return None + def check(self, m, path): + m = getattr(self, m) + for pre, _suf in self._rpairs(path): + if pre in m: + return m[pre] + return -1 def __contains__(self, path): - if len(self.include) and len(path): + if not len(path): + return True + if len(self.include): inc = self.check('include', path) + elif not len(self.exclude): + return True else: - inc = path - if len(self.exclude) and len(path): + inc = 0 + if len(self.exclude): exc = self.check('exclude', path) else: - exc = None - if inc is None or exc is not None: - return False - return True + exc = -1 + # respect rule order: newer rules override older + return inc > exc + + # Needed so empty filemaps are false + def __len__(self): + return len(self.include) + len(self.exclude) - def add(self, fn, map, path): - mapping = getattr(self, map) + def add(self, fn, m, path): + mapping = getattr(self, m) if path in mapping: msg = 'duplicate %s entry in %s: "%s"\n' - self.ui.status(msg % (map, fn, path)) + self.ui.status(msg % (m, fn, path)) return - bits = map.strip('e'), path + bits = m.strip('e'), path self.ui.debug('%sing %s\n' % bits) - mapping[path] = path + # respect rule order + mapping[path] = len(self) + if fn != self.path: + f = open(self.path, 'a') + f.write(m + ' ' + path + '\n') + f.close() def load(self, fn): self.ui.note('reading file map from %s\n' % fn) f = open(fn, 'r') + self.load_fd(f, fn) + f.close() + + def load_fd(self, f, fn): for line in f: if line.strip() == '' or line.strip()[0] == '#': continue @@ -317,6 +341,20 @@ class FileMap(object): except IndexError: msg = 'ignoring bad line in filemap %s: %s\n' self.ui.warn(msg % (fn, line.rstrip())) + + def _load(self): + self.ui.note('reading in-repo file map from %s\n' % self.path) + f = open(self.path) + ver = int(f.readline()) + if ver != self.VERSION: + print 'filemap too new -- please upgrade' + raise NotImplementedError + self.load_fd(f, self.path) + f.close() + + def _write(self): + f = open(self.path, 'w') + f.write('%s\n' % self.VERSION) f.close() class BranchMap(dict): diff --git a/hgsubversion/replay.py b/hgsubversion/replay.py --- a/hgsubversion/replay.py +++ b/hgsubversion/replay.py @@ -71,7 +71,7 @@ def convert_rev(ui, meta, svn, r, tbdelt updateexternals(ui, meta, current) - if current.exception is not None: #pragma: no cover + if current.exception is not None: # pragma: no cover traceback.print_exception(*current.exception) raise ReplayException() if current.missing: @@ -174,7 +174,7 @@ def convert_rev(ui, meta, svn, r, tbdelt date, extra) - new_hash = meta.repo.commitctx(current_ctx) + new_hash = meta.repo.svn_commitctx(current_ctx) util.describe_commit(ui, new_hash, branch) if (rev.revnum, branch) not in meta.revmap and not tag: meta.revmap[rev.revnum, branch] = new_hash @@ -194,7 +194,7 @@ def convert_rev(ui, meta, svn, r, tbdelt raise IOError(errno.ENOENT, 'deleting all files') # True here meant nuke all files, shouldn't happen with branch closing - if current.emptybranches[branch]: #pragma: no cover + if current.emptybranches[branch]: # pragma: no cover raise hgutil.Abort('Empty commit to an open branch attempted. ' 'Please report this issue.') @@ -209,7 +209,7 @@ def convert_rev(ui, meta, svn, r, tbdelt meta.authors[rev.author], date, extra) - new_hash = meta.repo.commitctx(current_ctx) + new_hash = meta.repo.svn_commitctx(current_ctx) util.describe_commit(ui, new_hash, branch) if (rev.revnum, branch) not in meta.revmap: meta.revmap[rev.revnum, branch] = new_hash diff --git a/hgsubversion/stupid.py b/hgsubversion/stupid.py --- a/hgsubversion/stupid.py +++ b/hgsubversion/stupid.py @@ -2,10 +2,11 @@ import cStringIO import errno import re -from mercurial import patch -from mercurial import node from mercurial import context +from mercurial import node +from mercurial import patch from mercurial import revlog +from mercurial import util as hgutil import svnwrap import svnexternals @@ -45,7 +46,7 @@ class BadPatchApply(Exception): pass -def print_your_svn_is_old_message(ui): #pragma: no cover +def print_your_svn_is_old_message(ui): # pragma: no cover ui.status("In light of that, I'll fall back and do diffs, but it won't do " "as good a job. You should really upgrade your server.\n") @@ -407,7 +408,7 @@ def fetch_externals(ui, svn, branchpath, # revision in the common case. dirs = set(externals) if parentctx.node() == revlog.nullid: - dirs.update([p for p,k in svn.list_files(branchpath, r.revnum) if k == 'd']) + dirs.update([p for p, k in svn.list_files(branchpath, r.revnum) if k == 'd']) dirs.add('') else: branchprefix = (branchpath and branchpath + '/') or branchpath @@ -559,7 +560,7 @@ def branches_in_paths(meta, tbdelta, pat # we need to detect those branches. It's a little thorny and slow, but # seems to be the best option. elif paths[p].copyfrom_path and not p.startswith('tags/'): - paths_need_discovery.extend(['%s/%s' % (p,x[0]) + paths_need_discovery.extend(['%s/%s' % (p, x[0]) for x in listdir(p, revnum) if x[1] == 'f']) @@ -589,6 +590,9 @@ def branches_in_paths(meta, tbdelta, pat def convert_rev(ui, meta, svn, r, tbdelta, firstrun): # this server fails at replay + if meta.filemap: + raise hgutil.Abort('filemaps currently unsupported with stupid replay.') + branches = branches_in_paths(meta, tbdelta, r.paths, r.revnum, svn.checkpath, svn.list_files) brpaths = branches.values() @@ -709,7 +713,7 @@ def convert_rev(ui, meta, svn, r, tbdelt meta.authors[r.author], date, extra) - ha = meta.repo.commitctx(current_ctx) + ha = meta.repo.svn_commitctx(current_ctx) if not tag: if (not origbranch in meta.branches diff --git a/hgsubversion/svncommands.py b/hgsubversion/svncommands.py --- a/hgsubversion/svncommands.py +++ b/hgsubversion/svncommands.py @@ -55,7 +55,7 @@ def verify(ui, repo, args=None, **opts): svnfiles.add(fn) fp = fn if branchpath: - fp = branchpath + '/' + fn + fp = branchpath + '/' + fn data, mode = svn.get_file(posixpath.normpath(fp), srev) fctx = ctx[fn] dmatch = fctx.data() == data diff --git a/hgsubversion/svnexternals.py b/hgsubversion/svnexternals.py --- a/hgsubversion/svnexternals.py +++ b/hgsubversion/svnexternals.py @@ -17,7 +17,7 @@ try: canonpath = hgutil.canonpath except (ImportError, AttributeError): from mercurial import scmutil - canonpath = scmutil.canonpath + canonpath = scmutil.canonpath passpegrev = False import util @@ -59,7 +59,6 @@ class externalsfile(dict): def read(self, data): self.clear() fp = cStringIO.StringIO(data) - dirs = {} target = None for line in fp.readlines(): if not line.strip(): @@ -120,7 +119,7 @@ def parsedefinition(line): revgroup = 2 path, rev, source = m.group(1, 2, 3) try: - nrev = int(rev) + int(rev) # ensure revision is int()able, so we bail otherwise norevline = line[:m.start(revgroup)] + '{REV}' + line[m.end(revgroup):] except (TypeError, ValueError): norevline = line @@ -232,7 +231,7 @@ class externalsupdater: if rev: revspec = ['-r', rev] if os.path.isdir(path): - exturl, extroot, extrev = getsvninfo(path) + exturl, _extroot, extrev = getsvninfo(path) # Comparing the source paths is not enough, but I don't # know how to compare path+pegrev. The following update # might fail if the path was replaced by another unrelated @@ -347,7 +346,7 @@ def getchanges(ui, repo, parentctx, exts if exts: defs = parsedefinitions(ui, repo, '', exts) hgsub, hgsubstate = [], [] - for path, rev, source, pegrev, norevline, base in sorted(defs): + for path, rev, _source, _pegrev, norevline, base in sorted(defs): hgsub.append('%s = [hgsubversion] %s:%s\n' % (path, base, norevline)) if rev is None: diff --git a/hgsubversion/svnmeta.py b/hgsubversion/svnmeta.py --- a/hgsubversion/svnmeta.py +++ b/hgsubversion/svnmeta.py @@ -24,7 +24,7 @@ def pickle_atomic(data, file_path, dir=N f = os.fdopen(f, 'w') pickle.dump(data, f) f.close() - except: #pragma: no cover + except: # pragma: no cover raise else: hgutil.rename(path, file_path) @@ -55,6 +55,7 @@ class SVNMeta(object): 'usebranchnames', True) branchmap = self.ui.config('hgsubversion', 'branchmap') tagmap = self.ui.config('hgsubversion', 'tagmap') + filemap = self.ui.config('hgsubversion', 'filemap') self.branches = {} if os.path.exists(self.branch_info_file): @@ -94,8 +95,11 @@ class SVNMeta(object): if tagmap: self.tagmap.load(tagmap) + self.filemap = maps.FileMap(self.ui, self.filemap_file) + if filemap: + self.filemap.load(filemap) + self.lastdate = '1970-01-01 00:00:00 -0000' - self.filemap = maps.FileMap(repo) self.addedtags = {} self.deletedtags = {} @@ -191,6 +195,10 @@ class SVNMeta(object): def authors_file(self): return os.path.join(self.meta_data_dir, 'authors') + @property + def filemap_file(self): + return os.path.join(self.meta_data_dir, 'filemap') + @property def branchmapfile(self): return os.path.join(self.meta_data_dir, 'branchmap') @@ -257,7 +265,7 @@ class SVNMeta(object): branchpath = branch[3:] else: branchpath = 'branches/%s' % branch - path = '%s/%s' % (subdir , branchpath) + path = '%s/%s' % (subdir, branchpath) extra['convert_revision'] = 'svn:%(uuid)s%(path)s@%(rev)s' % { 'uuid': self.uuid, @@ -368,7 +376,7 @@ class SVNMeta(object): else: path = test.split('/')[-1] test = '/'.join(test.split('/')[:-1]) - ln = self.localname(test) + ln = self.localname(test) if ln and ln.startswith('../'): return None, None, None return path, ln, test @@ -424,7 +432,7 @@ class SVNMeta(object): branch_created_rev = self.branches[branch][2] if parent_branch == 'trunk': parent_branch = None - if branch_created_rev <= number+1 and branch != parent_branch: + if branch_created_rev <= number + 1 and branch != parent_branch: # did the branch exist in previous run if exact and branch in self.prevbranches: if self.prevbranches[branch][1] < real_num: @@ -450,7 +458,7 @@ class SVNMeta(object): return node.hex(self.revmap[tagged]) tag = fromtag # Reference an existing tag - limitedtags = maps.Tags(self.repo, endrev=number-1) + limitedtags = maps.Tags(self.repo, endrev=number - 1) if tag in limitedtags: return limitedtags[tag] r, br = self.get_parent_svn_branch_and_rev(number - 1, branch, exact) @@ -609,7 +617,7 @@ class SVNMeta(object): branchparent = branchparent.parents()[0] branch = self.get_source_rev(ctx=branchparent)[1] - parentctx = self.repo[self.get_parent_revision(rev.revnum+1, branch)] + parentctx = self.repo[self.get_parent_revision(rev.revnum + 1, branch)] if '.hgtags' in parentctx: tagdata = parentctx.filectx('.hgtags').data() else: @@ -639,7 +647,7 @@ class SVNMeta(object): self.authors[rev.author], date, parentctx.extra()) - new_hash = self.repo.commitctx(ctx) + new_hash = self.repo.svn_commitctx(ctx) if not newparent: assert self.revmap[revnum, branch] == parentctx.node() self.revmap[revnum, branch] = new_hash @@ -704,7 +712,7 @@ class SVNMeta(object): self.authors[rev.author], date, extra) - new = self.repo.commitctx(ctx) + new = self.repo.svn_commitctx(ctx) if not fromtag and (rev.revnum, b) not in self.revmap: self.revmap[rev.revnum, b] = new @@ -726,5 +734,5 @@ class SVNMeta(object): self.authors[rev.author], self.fixdate(rev.date), extra) - new = self.repo.commitctx(ctx) + new = self.repo.svn_commitctx(ctx) self.ui.status('Marked branch %s as closed.\n' % (branch or 'default')) diff --git a/hgsubversion/svnrepo.py b/hgsubversion/svnrepo.py --- a/hgsubversion/svnrepo.py +++ b/hgsubversion/svnrepo.py @@ -14,11 +14,14 @@ subclass: pull() is called on the instan are used to distinguish and filter these operations from others. """ +import errno + from mercurial import error from mercurial import util as hgutil from mercurial import httprepo import mercurial.repo +import re import util import wrappers import svnwrap @@ -26,6 +29,25 @@ import svnmeta propertycache = hgutil.propertycache +class ctxctx(object): + """Proxies a ctx object and ensures files is never empty.""" + def __init__(self, ctx): + self._ctx = ctx + + def files(self): + return self._ctx.files() or ['.svn'] + + def filectx(self, path, filelog=None): + if path == '.svn': + raise IOError(errno.ENOENT, '.svn is a fake file') + return self._ctx.filectx(path, filelog=filelog) + + def __getattr__(self, name): + return getattr(self._ctx, name) + + def __getitem__(self, key): + return self._ctx[key] + def generate_repo_class(ui, repo): """ This function generates the local repository wrapper. """ @@ -53,6 +75,10 @@ def generate_repo_class(ui, repo): return wrapper class svnlocalrepo(superclass): + def svn_commitctx(self, ctx): + """Commits a ctx, but defeats manifest recycling introduced in hg 1.9.""" + return self.commitctx(ctxctx(ctx)) + # TODO use newbranch to allow branch creation in Subversion? @remotesvn def push(self, remote, force=False, revs=None, newbranch=None): @@ -82,6 +108,14 @@ class svnremoterepo(mercurial.repo.repos raise hgutil.Abort('no Subversion URL specified') self.path = path self.capabilities = set(['lookup', 'subversion']) + pws = self.ui.config('hgsubversion', 'password_stores', None) + if pws is not None: + # Split pws at comas and strip neighbouring whitespace (whitespace + # at the beginning and end of pws has already been removed by the + # config parser). + self.password_stores = re.split(r'\s*,\s*', pws) + else: + self.password_stores = None @propertycache def svnauth(self): @@ -102,7 +136,7 @@ class svnremoterepo(mercurial.repo.repos @propertycache def svn(self): try: - return svnwrap.SubversionRepo(*self.svnauth) + return svnwrap.SubversionRepo(*self.svnauth, password_stores=self.password_stores) except svnwrap.SubversionConnectionException, e: self.ui.traceback() raise hgutil.Abort(e) diff --git a/hgsubversion/svnwrap/common.py b/hgsubversion/svnwrap/common.py --- a/hgsubversion/svnwrap/common.py +++ b/hgsubversion/svnwrap/common.py @@ -38,7 +38,7 @@ def parse_url(url, user=None, passwd=Non user, passwd = userpass, '' user, passwd = urllib.unquote(user), urllib.unquote(passwd) if user and scheme == 'svn+ssh': - netloc = '@'.join((user, netloc, )) + netloc = '@'.join((user, netloc,)) url = urlparse.urlunparse((scheme, netloc, path, params, query, fragment)) return (user or None, passwd or None, url) diff --git a/hgsubversion/svnwrap/subvertpy_wrapper.py b/hgsubversion/svnwrap/subvertpy_wrapper.py --- a/hgsubversion/svnwrap/subvertpy_wrapper.py +++ b/hgsubversion/svnwrap/subvertpy_wrapper.py @@ -31,7 +31,7 @@ except ImportError: def _versionstr(v): return '.'.join(str(d) for d in v) -if subvertpy.__version__ < subvertpy_required: #pragma: no cover +if subvertpy.__version__ < subvertpy_required: # pragma: no cover raise ImportError('Subvertpy %s or later required, ' 'but %s found' % (_versionstr(subvertpy_required), @@ -87,7 +87,7 @@ class PathAdapter(object): self.copyfrom_path = intern(self.copyfrom_path) class AbstractEditor(object): - __slots__ = ('editor', ) + __slots__ = ('editor',) def __init__(self, editor): self.editor = editor @@ -131,7 +131,7 @@ class AbstractEditor(object): self.editor.delete_entry(path, revnum, None) class FileEditor(AbstractEditor): - __slots__ = ('path', ) + __slots__ = ('path',) def __init__(self, editor, path): super(FileEditor, self).__init__(editor) @@ -145,7 +145,7 @@ class FileEditor(AbstractEditor): del self.path class DirectoryEditor(AbstractEditor): - __slots__ = ('path', ) + __slots__ = ('path',) def __init__(self, editor, path): super(DirectoryEditor, self).__init__(editor) @@ -165,8 +165,11 @@ class SubversionRepo(object): This wrapper uses Subvertpy, an alternate set of bindings for Subversion that's more pythonic and sucks less. See earlier in this file for version requirements. + + Note that password stores do not work, the parameter is only here + to ensure that the API is the same as for the SWIG wrapper. """ - def __init__(self, url='', username='', password='', head=None): + def __init__(self, url='', username='', password='', head=None, password_stores=None): parsed = common.parse_url(url, username, password) # --username and --password override URL credentials self.username = parsed[0] @@ -306,7 +309,7 @@ class SubversionRepo(object): # ra.get_log(), even with chunk_size set, takes a while # when converting the 65k+ rev. in LLVM. self.remote.get_log(paths=paths, revprops=revprops, - start=start+1, end=stop, limit=chunk_size, + start=start + 1, end=stop, limit=chunk_size, discover_changed_paths=True, callback=callback) except SubversionException, e: @@ -338,7 +341,7 @@ class SubversionRepo(object): commit_info.append(args) commit_info = [] revprops = { properties.PROP_REVISION_LOG: message } - #revprops.update(props) + # revprops.update(props) commiteditor = self.remote.get_commit_editor(revprops, commitcb) paths = set(paths) @@ -417,7 +420,7 @@ class SubversionRepo(object): try: self.remote.replay(revision, oldestrev, AbstractEditor(editor)) - except (SubversionException, NotImplementedError), e: #pragma: no cover + except (SubversionException, NotImplementedError), e: # pragma: no cover # can I depend on this number being constant? if (isinstance(e, NotImplementedError) or e.args[1] == subvertpy.ERR_RA_NOT_IMPLEMENTED or @@ -477,7 +480,7 @@ class SubversionRepo(object): # File not found raise IOError(errno.ENOENT, e.args[0]) raise - if mode == 'l': + if mode == 'l': linkprefix = "link " if data.startswith(linkprefix): data = data[len(linkprefix):] @@ -531,4 +534,4 @@ class SubversionRepo(object): if not path or path == '.': return self.svn_url assert path[0] != '/', path - return '/'.join((self.svn_url, urllib.quote(path).rstrip('/'), )) + return '/'.join((self.svn_url, urllib.quote(path).rstrip('/'),)) diff --git a/hgsubversion/svnwrap/svn_swig_wrapper.py b/hgsubversion/svnwrap/svn_swig_wrapper.py --- a/hgsubversion/svnwrap/svn_swig_wrapper.py +++ b/hgsubversion/svnwrap/svn_swig_wrapper.py @@ -29,7 +29,7 @@ except ImportError: raise ImportError('Subversion %d.%d.%d or later required, ' 'but no bindings were found' % required_bindings) -if current_bindings < required_bindings: #pragma: no cover +if current_bindings < required_bindings: # pragma: no cover raise ImportError('Subversion %d.%d.%d or later required, ' 'but bindings for %d.%d.%d found' % (required_bindings + current_bindings)) @@ -60,7 +60,7 @@ def optrev(revnum): svn_config = core.svn_config_get_config(None) class RaCallbacks(ra.Callbacks): @staticmethod - def open_tmp_file(pool): #pragma: no cover + def open_tmp_file(pool): # pragma: no cover (fd, fn) = tempfile.mkstemp() os.close(fd) return fn @@ -82,13 +82,13 @@ def ieditor(fn): def fun(self, *args, **kwargs): try: return fn(self, *args, **kwargs) - except: #pragma: no cover + except: # pragma: no cover if self.current.exception is not None: self.current.exception = sys.exc_info() raise return fun -def user_pass_prompt(realm, default_username, ms, pool): #pragma: no cover +def user_pass_prompt(realm, default_username, ms, pool): # pragma: no cover # FIXME: should use getpass() and username() from mercurial.ui creds = core.svn_auth_cred_simple_t() creds.may_save = ms @@ -103,7 +103,7 @@ def user_pass_prompt(realm, default_user creds.password = getpass.getpass('Password for %s: ' % creds.username) return creds -def _create_auth_baton(pool): +def _create_auth_baton(pool, password_stores): """Create a Subversion authentication baton. """ # Give the client context baton a suite of authentication # providers.h @@ -124,7 +124,9 @@ def _create_auth_baton(pool): None) if getprovider: # Available in svn >= 1.6 - for name in ('gnome_keyring', 'keychain', 'kwallet', 'windows'): + if password_stores is None: + password_stores = ('gnome_keyring', 'keychain', 'kwallet', 'windows') + for name in password_stores: for type in ('simple', 'ssl_client_cert_pw', 'ssl_server_trust'): p = getprovider(name, type, pool) if p: @@ -158,14 +160,14 @@ class SubversionRepo(object): It uses the SWIG Python bindings, see above for requirements. """ - def __init__(self, url='', username='', password='', head=None): + def __init__(self, url='', username='', password='', head=None, password_stores=None): parsed = common.parse_url(url, username, password) # --username and --password override URL credentials self.username = parsed[0] self.password = parsed[1] self.svn_url = parsed[2] self.auth_baton_pool = core.Pool() - self.auth_baton = _create_auth_baton(self.auth_baton_pool) + self.auth_baton = _create_auth_baton(self.auth_baton_pool, password_stores) # self.init_ra_and_client() assumes that a pool already exists self.pool = core.Pool() @@ -233,7 +235,7 @@ class SubversionRepo(object): holder = [] ra.get_log(self.ra, [''], self.HEAD, 1, - 1, #limit of how many log messages to load + 1, # limit of how many log messages to load True, # don't need to know changed paths True, # stop on copies lambda paths, revnum, author, date, message, pool: @@ -293,9 +295,9 @@ class SubversionRepo(object): # when converting the 65k+ rev. in LLVM. ra.get_log(self.ra, paths, - start+1, + start + 1, stop, - chunk_size, #limit of how many log messages to load + chunk_size, # limit of how many log messages to load True, # don't need to know changed paths True, # stop on copies callback, @@ -403,7 +405,7 @@ class SubversionRepo(object): try: ra.replay(self.ra, revision, oldest_rev_i_have, True, e_ptr, e_baton, self.pool) - except SubversionException, e: #pragma: no cover + except SubversionException, e: # pragma: no cover # can I depend on this number being constant? if (e.apr_err == core.SVN_ERR_RA_NOT_IMPLEMENTED or e.apr_err == core.SVN_ERR_UNSUPPORTED_FEATURE): @@ -497,7 +499,7 @@ class SubversionRepo(object): if e.args[1] in notfound: # File not found raise IOError(errno.ENOENT, e.args[0]) raise - if mode == 'l': + if mode == 'l': linkprefix = "link " if data.startswith(linkprefix): data = data[len(linkprefix):] diff --git a/hgsubversion/util.py b/hgsubversion/util.py --- a/hgsubversion/util.py +++ b/hgsubversion/util.py @@ -35,7 +35,7 @@ def filterdiff(diff, oldrev, newrev): diff) oldrev = formatrev(oldrev) newrev = formatrev(newrev) - diff = a_re.sub(r'--- \1'+ oldrev, diff) + diff = a_re.sub(r'--- \1' + oldrev, diff) diff = b_re.sub(r'+++ \1' + newrev, diff) diff = devnull_re.sub(r'\1 /dev/null\t(working copy)', diff) diff = header_re.sub(r'Index: \1' + '\n' + ('=' * 67), diff) @@ -65,9 +65,9 @@ def islocalrepo(url): path = url[prefixlen:] path = urllib.url2pathname(path).replace(os.sep, '/') while '/' in path: - if reduce(lambda x,y: x and y, + if reduce(lambda x, y: x and y, map(lambda p: os.path.exists(os.path.join(path, p)), - ('hooks', 'format', 'db', ))): + ('hooks', 'format', 'db',))): return True path = path.rsplit('/', 1)[0] return False @@ -99,6 +99,29 @@ def normalize_url(url): url = '%s#%s' % (url, checkout) return url + +def load_string(file_path, default=None, limit=1024): + if not os.path.exists(file_path): + return default + try: + f = open(file_path, 'r') + ret = f.read(limit) + f.close() + except: + return default + if ret == '': + return default + return ret + + +def save_string(file_path, string): + if string is None: + string = "" + f = open(file_path, 'wb') + f.write(str(string)) + f.close() + + # TODO remove when we drop 1.3 support def progress(ui, *args, **kwargs): if getattr(ui, 'progress', False): diff --git a/hgsubversion/wrappers.py b/hgsubversion/wrappers.py --- a/hgsubversion/wrappers.py +++ b/hgsubversion/wrappers.py @@ -1,6 +1,7 @@ from hgext import rebase as hgrebase from mercurial import cmdutil +from mercurial import discovery from mercurial import patch from mercurial import hg from mercurial import util as hgutil @@ -90,7 +91,13 @@ def findcommonoutgoing(repo, other, only meta = repo.svnmeta(svn.uuid, svn.subdir) parent = repo.parents()[0].node() hashes = meta.revmap.hashes() - return util.outgoing_common_and_heads(repo, hashes, parent) + common, heads = util.outgoing_common_and_heads(repo, hashes, parent) + outobj = getattr(discovery, 'outgoing', None) + if outobj is not None: + # Mercurial 2.1 and later + return outobj(repo.changelog, common, heads) + # Mercurial 2.0 and earlier + return common, heads def findoutgoing(repo, dest=None, heads=None, force=False): @@ -98,7 +105,7 @@ def findoutgoing(repo, dest=None, heads= """ assert dest.capable('subversion') # split off #rev; TODO implement --revision/#rev support - #svnurl, revs, checkout = util.parseurl(dest.svnurl, heads) + # svnurl, revs, checkout = util.parseurl(dest.svnurl, heads) svn = dest.svn meta = repo.svnmeta(svn.uuid, svn.subdir) parent = repo.parents()[0].node() @@ -354,11 +361,11 @@ def pull(repo, source, heads=[], force=F converted = True firstrun = False - except svnwrap.SubversionRepoCanNotReplay, e: #pragma: no cover + except svnwrap.SubversionRepoCanNotReplay, e: # pragma: no cover ui.status('%s\n' % e.message) stupidmod.print_your_svn_is_old_message(ui) have_replay = False - except svnwrap.SubversionException, e: #pragma: no cover + except svnwrap.SubversionException, e: # pragma: no cover if (e.args[1] == svnwrap.ERR_RA_DAV_REQUEST_FAILED and '502' in str(e) and tries < 3): @@ -476,6 +483,8 @@ def clone(orig, ui, source, dest=None, * data['srcrepo'], data['dstrepo'] = orig(ui, *args, **opts) + return data['srcrepo'], data['dstrepo'] + for opt, (section, name) in optionmap.iteritems(): if opt in opts and opts[opt]: ui.setconfig(section, name, str(opts.pop(opt))) diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -72,7 +72,7 @@ elif os.path.exists('.hg_archival.txt'): kw = dict([t.strip() for t in l.split(':', 1)] for l in open('.hg_archival.txt')) if 'tag' in kw: - version = kw['tag'] + version = kw['tag'] elif 'latesttag' in kw: version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw else: @@ -107,22 +107,22 @@ except ImportError: requires.append('subvertpy>=0.7.4') setup( - name = 'hgsubversion', - version = version, - url = 'http://bitbucket.org/durin42/hgsubversion', - license = 'GNU GPL', - author = 'Augie Fackler, others', - author_email = 'durin42@gmail.com', - description = ('hgsubversion is a Mercurial extension for working with ' + name='hgsubversion', + version=version, + url='http://bitbucket.org/durin42/hgsubversion', + license='GNU GPL', + author='Augie Fackler, others', + author_email='durin42@gmail.com', + description=('hgsubversion is a Mercurial extension for working with ' 'Subversion repositories.'), - long_description = open(os.path.join(os.path.dirname(__file__), + long_description=open(os.path.join(os.path.dirname(__file__), 'README')).read(), - keywords = 'mercurial', - packages = ('hgsubversion', 'hgsubversion.svnwrap'), - package_data = { 'hgsubversion': ['help/subversion.rst'] }, - platforms = 'any', + keywords='mercurial', + packages=('hgsubversion', 'hgsubversion.svnwrap'), + package_data={ 'hgsubversion': ['help/subversion.rst'] }, + platforms='any', install_requires=requires, - classifiers = [ + classifiers=[ 'License :: OSI Approved :: GNU General Public License (GPL)', 'Intended Audience :: Developers', 'Topic :: Software Development :: Version Control', @@ -130,5 +130,5 @@ setup( 'Programming Language :: Python', 'Operating System :: OS Independent', ], - cmdclass = {'build_py': build_py}, + cmdclass={'build_py': build_py}, ) diff --git a/tests/comprehensive/test_stupid_pull.py b/tests/comprehensive/test_stupid_pull.py --- a/tests/comprehensive/test_stupid_pull.py +++ b/tests/comprehensive/test_stupid_pull.py @@ -52,10 +52,10 @@ for case in (f for f in os.listdir(test_ name += '_single' attrs[name] = buildmethod(case, name, 'single') -StupidPullTests = type('StupidPullTests', (test_util.TestBase, ), attrs) +StupidPullTests = type('StupidPullTests', (test_util.TestBase,), attrs) def suite(): - all = [unittest.TestLoader().loadTestsFromTestCase(StupidPullTests), + all_tests = [unittest.TestLoader().loadTestsFromTestCase(StupidPullTests), ] - return unittest.TestSuite(all) + return unittest.TestSuite(all_tests) diff --git a/tests/comprehensive/test_verify.py b/tests/comprehensive/test_verify.py --- a/tests/comprehensive/test_verify.py +++ b/tests/comprehensive/test_verify.py @@ -51,5 +51,5 @@ for case in fixtures: VerifyTests = type('VerifyTests', (test_util.TestBase,), attrs) def suite(): - all = [unittest.TestLoader().loadTestsFromTestCase(VerifyTests)] - return unittest.TestSuite(all) + all_tests = [unittest.TestLoader().loadTestsFromTestCase(VerifyTests)] + return unittest.TestSuite(all_tests) diff --git a/tests/fixtures/rsvn.py b/tests/fixtures/rsvn.py --- a/tests/fixtures/rsvn.py +++ b/tests/fixtures/rsvn.py @@ -169,7 +169,7 @@ def rsvn(pool): sys.stderr.write(str(e) + '\n\n') usage() sys.exit(1) - + for opt, value in opts: if opt == '--version': print '%s version %s' % (os.path.basename(sys.argv[0]), VERSION) @@ -181,75 +181,75 @@ def rsvn(pool): username = value elif opt == '--message': log_msg = value - + if log_msg == None: usage('Missing --message argument') sys.exit(1) - + if len(args) != 1: usage('Missing repository path argument') sys.exit(1) - + repos_path = args[0] print 'Accessing repository at [%s]' % repos_path repository = Repository(repos_path, pool) sub = repository.subpool() - + try: txn = repository.begin(username, log_msg) - + # Read commands from STDIN lineno = 0 for line in sys.stdin: lineno += 1 - + core.svn_pool_clear(sub) try: if COMMENT_RE.search(line): continue - + match = RCOPY_RE.search(line) if match: src = match.group(1) dest = match.group(2) txn.copy(src, dest, sub) continue - + match = RMOVE_RE.search(line) if match: src = match.group(1) dest = match.group(2) txn.move(src, dest, sub) continue - + match = RMKDIR_RE.search(line) if match: entry = match.group(1) txn.mkdir(entry, sub) continue - + match = RDELETE_RE.search(line) if match: entry = match.group(1) txn.delete(entry, sub) continue - + raise NameError, ('Unknown command [%s] on line %d' % (line, lineno)) - + except: - sys.stderr.write(('Exception occured while processing line %d:\n' % + sys.stderr.write(('Exception occured while processing line %d:\n' % lineno)) etype, value, tb = sys.exc_info() traceback.print_exception(etype, value, tb, None, sys.stderr) sys.stderr.write('\n') txn.rollback() sys.exit(1) - + new_rev = txn.commit() print '\nCommitted revision %d.' % new_rev - + finally: print '\nRepository closed.' diff --git a/tests/run.py b/tests/run.py --- a/tests/run.py +++ b/tests/run.py @@ -93,23 +93,23 @@ if __name__ == '__main__': import tempfile sys.stdout = tempfile.TemporaryFile() - all = tests() + all_tests = tests() args = [i.split('.py')[0].replace('-', '_') for i in args] if not args: check = lambda x: options.comprehensive or not comprehensive(x) - mods = [m for (n, m) in sorted(all.iteritems()) if check(m)] + mods = [m for (n, m) in sorted(all_tests.iteritems()) if check(m)] suite = [m.suite() for m in mods] else: suite = [] for arg in args: if arg == 'test_util': continue - elif arg not in all: + elif arg not in all_tests: print >> sys.stderr, 'test module %s not available' % arg else: - suite.append(all[arg].suite()) + suite.append(all_tests[arg].suite()) runner = unittest.TextTestRunner(**testargs) result = runner.run(unittest.TestSuite(suite)) diff --git a/tests/test_binaryfiles.py b/tests/test_binaryfiles.py --- a/tests/test_binaryfiles.py +++ b/tests/test_binaryfiles.py @@ -11,6 +11,6 @@ class TestFetchBinaryFiles(test_util.Tes self.test_binaryfiles(True) def suite(): - all = [unittest.TestLoader().loadTestsFromTestCase(TestFetchBinaryFiles), + all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestFetchBinaryFiles), ] - return unittest.TestSuite(all) + return unittest.TestSuite(all_tests) diff --git a/tests/test_diff.py b/tests/test_diff.py --- a/tests/test_diff.py +++ b/tests/test_diff.py @@ -33,11 +33,11 @@ class DiffTests(test_util.TestBase): ]) u = ui.ui() u.pushbuffer() - wrappers.diff(lambda x,y,z: None, u, self.repo, svn=True) + wrappers.diff(lambda x, y, z: None, u, self.repo, svn=True) self.assertEqual(u.popbuffer(), expected_diff_output) def suite(): - all = [unittest.TestLoader().loadTestsFromTestCase(DiffTests), + all_tests = [unittest.TestLoader().loadTestsFromTestCase(DiffTests), ] - return unittest.TestSuite(all) + return unittest.TestSuite(all_tests) diff --git a/tests/test_externals.py b/tests/test_externals.py --- a/tests/test_externals.py +++ b/tests/test_externals.py @@ -10,7 +10,7 @@ try: subrepo.svnsubrepo hgutil.checknlink except (ImportError, AttributeError), e: - print >>sys.stderr, 'test_externals: skipping .hgsub tests' + print >> sys.stderr, 'test_externals: skipping .hgsub tests' subrepo = None from hgsubversion import svnexternals @@ -358,7 +358,7 @@ HEAD subdir2/deps/project2 self.assertchanges(changes, self.repo['tip']) # Check .hgsub and .hgsubstate were not pushed - self.assertEqual(['dir', 'subdir1', 'subdir1/a','subdir2', + self.assertEqual(['dir', 'subdir1', 'subdir1/a', 'subdir2', 'subdir2/a'], self.svnls('trunk')) # Remove all references from one directory, add a new one @@ -408,7 +408,7 @@ HEAD subdir1/deps/project1 self.assertchanges(changes, self.repo['tip']) def suite(): - all = [unittest.TestLoader().loadTestsFromTestCase(TestFetchExternals), + all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestFetchExternals), unittest.TestLoader().loadTestsFromTestCase(TestPushExternals), ] - return unittest.TestSuite(all) + return unittest.TestSuite(all_tests) diff --git a/tests/test_fetch_branches.py b/tests/test_fetch_branches.py --- a/tests/test_fetch_branches.py +++ b/tests/test_fetch_branches.py @@ -163,6 +163,6 @@ class TestFetchBranches(test_util.TestBa self.test_replace_branch_with_branch(True) def suite(): - all = [unittest.TestLoader().loadTestsFromTestCase(TestFetchBranches), + all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestFetchBranches), ] - return unittest.TestSuite(all) + return unittest.TestSuite(all_tests) diff --git a/tests/test_fetch_command.py b/tests/test_fetch_command.py --- a/tests/test_fetch_command.py +++ b/tests/test_fetch_command.py @@ -165,7 +165,7 @@ class TestBasicRepoLayout(test_util.Test commands.clone(ui, repo_url + subdir, wc_path) commands.clone(ui, repo_url + quoted_subdir, wc2_path) - repo = hg.repository(ui, wc_path) + repo = hg.repository(ui, wc_path) repo2 = hg.repository(ui, wc2_path) self.assertEqual(repo['tip'].extra()['convert_revision'], @@ -224,7 +224,7 @@ class TestStupidPull(test_util.TestBase) '1a6c3f30911d57abb67c257ec0df3e7bc44786f7') def suite(): - all = [unittest.TestLoader().loadTestsFromTestCase(TestBasicRepoLayout), + all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestBasicRepoLayout), unittest.TestLoader().loadTestsFromTestCase(TestStupidPull), ] - return unittest.TestSuite(all) + return unittest.TestSuite(all_tests) diff --git a/tests/test_fetch_exec.py b/tests/test_fetch_exec.py --- a/tests/test_fetch_exec.py +++ b/tests/test_fetch_exec.py @@ -33,6 +33,6 @@ class TestFetchExec(test_util.TestBase): self.test_empty_prop_val_executable(True) def suite(): - all = [unittest.TestLoader().loadTestsFromTestCase(TestFetchExec), + all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestFetchExec), ] - return unittest.TestSuite(all) + return unittest.TestSuite(all_tests) diff --git a/tests/test_fetch_mappings.py b/tests/test_fetch_mappings.py --- a/tests/test_fetch_mappings.py +++ b/tests/test_fetch_mappings.py @@ -26,7 +26,7 @@ class MapTests(test_util.TestBase): @property def branchmap(self): return os.path.join(self.tmpdir, 'branchmap') - + @property def tagmap(self): return os.path.join(self.tmpdir, 'tagmap') @@ -96,8 +96,8 @@ class MapTests(test_util.TestBase): test = maps.AuthorMap(self.ui(), self.authors) fromself = set(test) test.load(orig) - all = set(test) - self.assertEqual(fromself.symmetric_difference(all), set()) + all_tests = set(test) + self.assertEqual(fromself.symmetric_difference(all_tests), set()) def test_file_map(self, stupid=False): test_util.load_svndump_fixture(self.repo_path, 'replace_trunk_with_branch.svndump') @@ -112,7 +112,8 @@ class MapTests(test_util.TestBase): self.assertEqual(node.hex(self.repo['default'].node()), 'e524296152246b3837fe9503c83b727075835155') def test_file_map_stupid(self): - self.test_file_map(True) + # TODO: re-enable test if we ever reinstate this feature + self.assertRaises(hgutil.Abort, self.test_file_map, True) def test_file_map_exclude(self, stupid=False): test_util.load_svndump_fixture(self.repo_path, 'replace_trunk_with_branch.svndump') @@ -127,7 +128,27 @@ class MapTests(test_util.TestBase): self.assertEqual(node.hex(self.repo['default'].node()), 'b37a3c0297b71f989064d9b545b5a478bbed7cc1') def test_file_map_exclude_stupid(self): - self.test_file_map_exclude(True) + # TODO: re-enable test if we ever reinstate this feature + self.assertRaises(hgutil.Abort, self.test_file_map_exclude, True) + + def test_file_map_rule_order(self): + test_util.load_svndump_fixture(self.repo_path, 'replace_trunk_with_branch.svndump') + filemap = open(self.filemap, 'w') + filemap.write("exclude alpha\n") + filemap.write("include .\n") + filemap.write("exclude gamma\n") + filemap.close() + ui = self.ui(False) + ui.setconfig('hgsubversion', 'filemap', self.filemap) + commands.clone(ui, test_util.fileurl(self.repo_path), + self.wc_path, filemap=self.filemap) + # The exclusion of alpha is overridden by the later rule to + # include all of '.', whereas gamma should remain excluded + # because it's excluded after the root directory. + self.assertEqual(self.repo[0].manifest().keys(), + ['alpha', 'beta']) + self.assertEqual(self.repo['default'].manifest().keys(), + ['alpha', 'beta']) def test_branchmap(self, stupid=False): test_util.load_svndump_fixture(self.repo_path, 'branchmap.svndump') diff --git a/tests/test_fetch_renames.py b/tests/test_fetch_renames.py --- a/tests/test_fetch_renames.py +++ b/tests/test_fetch_renames.py @@ -75,6 +75,6 @@ class TestFetchRenames(test_util.TestBas self._test_case(True) def suite(): - all = [unittest.TestLoader().loadTestsFromTestCase(TestFetchRenames), + all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestFetchRenames), ] - return unittest.TestSuite(all) + return unittest.TestSuite(all_tests) diff --git a/tests/test_fetch_symlinks.py b/tests/test_fetch_symlinks.py --- a/tests/test_fetch_symlinks.py +++ b/tests/test_fetch_symlinks.py @@ -39,7 +39,7 @@ class TestFetchSymlinks(test_util.TestBa 'linka4': 'link to this', }, } - + for rev in repo: ctx = repo[rev] for f in ctx.manifest(): @@ -53,6 +53,6 @@ class TestFetchSymlinks(test_util.TestBa self.test_symlinks(True) def suite(): - all = [unittest.TestLoader().loadTestsFromTestCase(TestFetchSymlinks), + all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestFetchSymlinks), ] - return unittest.TestSuite(all) + return unittest.TestSuite(all_tests) diff --git a/tests/test_fetch_truncated.py b/tests/test_fetch_truncated.py --- a/tests/test_fetch_truncated.py +++ b/tests/test_fetch_truncated.py @@ -31,6 +31,6 @@ class TestFetchTruncatedHistory(test_uti self.test_truncated_history(True) def suite(): - all = [unittest.TestLoader().loadTestsFromTestCase(TestFetchTruncatedHistory), + all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestFetchTruncatedHistory), ] - return unittest.TestSuite(all) + return unittest.TestSuite(all_tests) diff --git a/tests/test_push_command.py b/tests/test_push_command.py --- a/tests/test_push_command.py +++ b/tests/test_push_command.py @@ -43,7 +43,7 @@ class PushTests(test_util.TestBase): file_callback, 'an_author', '2008-10-07 20:59:48 -0500', - {'branch': 'default',}) + {'branch': 'default', }) new_hash = repo.commitctx(ctx) hg.update(repo, repo['tip'].node()) old_tip = repo['tip'].node() @@ -64,7 +64,7 @@ class PushTests(test_util.TestBase): file_callback, 'an_author', '2008-10-07 20:59:48 -0500', - {'branch': 'default',}) + {'branch': 'default', }) new_hash = repo.commitctx(ctx) hg.update(repo, repo['tip'].node()) # Touch an existing file @@ -116,7 +116,7 @@ class PushTests(test_util.TestBase): filectxfn=file_callback, user='an_author', date='2008-10-07 20:59:48 -0500', - extra={'branch': 'default',}) + extra={'branch': 'default', }) new_hash = repo.commitctx(ctx) if not commit: return # some tests use this test as an extended setup. @@ -161,7 +161,7 @@ class PushTests(test_util.TestBase): file_callback, 'an_author', '2008-10-07 20:59:48 -0500', - {'branch': 'default',}) + {'branch': 'default', }) new_hash = repo.commitctx(ctx) if not commit: return # some tests use this test as an extended setup. @@ -183,7 +183,7 @@ class PushTests(test_util.TestBase): copied=False) oldtiphash = self.repo['default'].node() ctx = context.memctx(self.repo, - (self.repo[0].node(), revlog.nullid, ), + (self.repo[0].node(), revlog.nullid,), 'automated test', ['gamma', ], filectxfn, @@ -229,7 +229,7 @@ class PushTests(test_util.TestBase): file_callback, 'an_author', '2008-10-07 20:59:48 -0500', - {'branch': 'default',}) + {'branch': 'default', }) new_hash = repo.commitctx(ctx) hg.update(repo, repo['tip'].node()) self.pushrevisions() @@ -264,7 +264,7 @@ class PushTests(test_util.TestBase): file_callback, 'an_author', '2008-10-07 20:59:48 -0500', - {'branch': 'the_branch',}) + {'branch': 'the_branch', }) new_hash = repo.commitctx(ctx) hg.update(repo, repo['tip'].node()) if push: @@ -291,7 +291,7 @@ class PushTests(test_util.TestBase): oldf.close() # do a commit here - self.commitchanges([('foobaz', 'foobaz', 'This file is added on default.', ), + self.commitchanges([('foobaz', 'foobaz', 'This file is added on default.',), ], parent='default', message='commit to default') @@ -469,13 +469,13 @@ class PushTests(test_util.TestBase): def test_push_outdated_base_text(self): self.test_push_two_revs() - changes = [('adding_file', 'adding_file', 'different_content', ), + changes = [('adding_file', 'adding_file', 'different_content',), ] par = self.repo['tip'].rev() self.commitchanges(changes, parent=par) self.pushrevisions() changes = [('adding_file', 'adding_file', - 'even_more different_content', ), + 'even_more different_content',), ] self.commitchanges(changes, parent=par) try: @@ -490,12 +490,12 @@ class PushTests(test_util.TestBase): def suite(): test_classes = [PushTests, ] - tests = [] + all_tests = [] # This is the quickest hack I could come up with to load all the tests from # both classes. Would love a patch that simplifies this without adding # dependencies. for tc in test_classes: for attr in dir(tc): if attr.startswith('test_'): - tests.append(tc(attr)) - return unittest.TestSuite(tests) + all_tests.append(tc(attr)) + return unittest.TestSuite(all_tests) diff --git a/tests/test_push_dirs.py b/tests/test_push_dirs.py --- a/tests/test_push_dirs.py +++ b/tests/test_push_dirs.py @@ -48,7 +48,7 @@ class TestPushDirectories(test_util.Test def test_push_new_dir_project_root_not_repo_root(self): self._load_fixture_and_fetch('fetch_missing_files_subdir.svndump', subdir='foo') - changes = [('magic_new/a', 'magic_new/a', 'ohai', ), + changes = [('magic_new/a', 'magic_new/a', 'ohai',), ] self.commitchanges(changes) self.pushrevisions() @@ -64,20 +64,21 @@ class TestPushDirectories(test_util.Test def test_push_new_file_existing_dir_root_not_repo_root(self): self._load_fixture_and_fetch('empty_dir_in_trunk_not_repo_root.svndump', subdir='project') - changes = [('narf/a', 'narf/a', 'ohai', ), + changes = [('narf/a', 'narf/a', 'ohai',), ] self.commitchanges(changes) self.assertEqual(self.svnls('project/trunk'), ['a', - 'narf',]) + 'narf', + ]) self.pushrevisions() self.assertEqual(self.svnls('project/trunk'), ['a', 'narf', 'narf/a']) - changes = [('narf/a', None, None, ), + changes = [('narf/a', None, None,), ] self.commitchanges(changes) self.pushrevisions() - self.assertEqual(self.svnls('project/trunk'), ['a' ,]) + self.assertEqual(self.svnls('project/trunk'), ['a']) def test_push_single_dir_change_in_subdir(self): # Tests simple pushing from default branch to a single dir repo @@ -104,6 +105,6 @@ class TestPushDirectories(test_util.Test 'tag_r3/new']) def suite(): - all = [unittest.TestLoader().loadTestsFromTestCase(TestPushDirectories), + all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestPushDirectories), ] - return unittest.TestSuite(all) + return unittest.TestSuite(all_tests) diff --git a/tests/test_push_eol.py b/tests/test_push_eol.py --- a/tests/test_push_eol.py +++ b/tests/test_push_eol.py @@ -37,6 +37,6 @@ class TestPushEol(test_util.TestBase): self._test_push_dirs(True) def suite(): - all = [unittest.TestLoader().loadTestsFromTestCase(TestPushEol), + all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestPushEol), ] - return unittest.TestSuite(all) + return unittest.TestSuite(all_tests) diff --git a/tests/test_push_renames.py b/tests/test_push_renames.py --- a/tests/test_push_renames.py +++ b/tests/test_push_renames.py @@ -79,9 +79,9 @@ class TestPushRenames(test_util.TestBase ('geek/delta', 'geek/delta', 'content',), ('geek/gamma', 'geek/gamma', 'content',), ('geek/later/pi', 'geek/later/pi', 'content geek/later/pi',), - ('geek/later/rho', 'geek/later/rho', 'content geek/later/rho', ), - ('geek/other/blah', 'geek/other/blah', 'content geek/other/blah', ), - ('geek/other/another/layer', 'geek/other/another/layer', 'content deep file', ), + ('geek/later/rho', 'geek/later/rho', 'content geek/later/rho',), + ('geek/other/blah', 'geek/other/blah', 'content geek/other/blah',), + ('geek/other/another/layer', 'geek/other/another/layer', 'content deep file',), ] self.commitchanges(changes) @@ -90,35 +90,35 @@ class TestPushRenames(test_util.TestBase changes = [ # rename (copy + remove) all of geek to greek - ('geek/alpha', 'greek/alpha', None, ), - ('geek/beta', 'greek/beta', None, ), - ('geek/delta', 'greek/delta', None, ), - ('geek/gamma', 'greek/gamma', None, ), - ('geek/later/pi', 'greek/later/pi', None, ), - ('geek/later/rho', 'greek/later/rho', None, ), - ('geek/other/blah', 'greek/other/blah', None, ), - ('geek/other/another/layer', 'greek/other/another/layer', None, ), + ('geek/alpha', 'greek/alpha', None,), + ('geek/beta', 'greek/beta', None,), + ('geek/delta', 'greek/delta', None,), + ('geek/gamma', 'greek/gamma', None,), + ('geek/later/pi', 'greek/later/pi', None,), + ('geek/later/rho', 'greek/later/rho', None,), + ('geek/other/blah', 'greek/other/blah', None,), + ('geek/other/another/layer', 'greek/other/another/layer', None,), - ('geek/alpha', None, None, ), - ('geek/beta', None, None, ), - ('geek/delta', None, None, ), - ('geek/gamma', None, None, ), - ('geek/later/pi', None, None, ), - ('geek/later/rho', None, None, ), - ('geek/other/blah', None, None, ), - ('geek/other/another/layer', None, None, ), + ('geek/alpha', None, None,), + ('geek/beta', None, None,), + ('geek/delta', None, None,), + ('geek/gamma', None, None,), + ('geek/later/pi', None, None,), + ('geek/later/rho', None, None,), + ('geek/other/blah', None, None,), + ('geek/other/another/layer', None, None,), ] self.commitchanges(changes) self.pushrevisions() # print '\n'.join(sorted(self.svnls('trunk'))) assert reduce(lambda x, y: x and y, - ('geek' not in f for f in self.svnls('trunk'))),( + ('geek' not in f for f in self.svnls('trunk'))), ( 'This failure means rename of an entire tree is broken.' ' There is a print on the preceding line commented out ' 'that should help you.') def suite(): - all = [unittest.TestLoader().loadTestsFromTestCase(TestPushRenames), + all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestPushRenames), ] - return unittest.TestSuite(all) + return unittest.TestSuite(all_tests) diff --git a/tests/test_rebuildmeta.py b/tests/test_rebuildmeta.py --- a/tests/test_rebuildmeta.py +++ b/tests/test_rebuildmeta.py @@ -55,7 +55,7 @@ def _do_case(self, name, stupid, single) self.assertTrue(os.path.isdir(os.path.join(src.path, 'svn')), 'no .hg/svn directory in the destination!') dest = hg.repository(u, os.path.dirname(dest.path)) - for tf in ('lastpulled', 'rev_map', 'uuid', 'tagmap', 'layout', 'subdir', ): + for tf in ('lastpulled', 'rev_map', 'uuid', 'tagmap', 'layout', 'subdir',): stf = os.path.join(src.path, 'svn', tf) self.assertTrue(os.path.isfile(stf), '%r is missing!' % stf) @@ -113,10 +113,10 @@ for case in [f for f in os.listdir(test_ name = bname + '_single' attrs[name] = buildmethod(case, name, False, True) -RebuildMetaTests = type('RebuildMetaTests', (test_util.TestBase, ), attrs) +RebuildMetaTests = type('RebuildMetaTests', (test_util.TestBase,), attrs) def suite(): - all = [unittest.TestLoader().loadTestsFromTestCase(RebuildMetaTests), + all_tests = [unittest.TestLoader().loadTestsFromTestCase(RebuildMetaTests), ] - return unittest.TestSuite(all) + return unittest.TestSuite(all_tests) diff --git a/tests/test_single_dir_clone.py b/tests/test_single_dir_clone.py --- a/tests/test_single_dir_clone.py +++ b/tests/test_single_dir_clone.py @@ -105,7 +105,7 @@ class TestSingleDir(test_util.TestBase): file_callback, 'an_author', '2009-10-19 18:49:30 -0500', - {'branch': 'default',}) + {'branch': 'default', }) repo.commitctx(ctx) hg.update(repo, repo['tip'].node()) self.pushrevisions() @@ -136,7 +136,7 @@ class TestSingleDir(test_util.TestBase): filectxfn, 'an_author', '2009-10-19 18:49:30 -0500', - {'branch': 'localhacking',}) + {'branch': 'localhacking', }) n = repo.commitctx(ctx) self.assertEqual(self.repo['tip']['bogus'].data(), 'contents of bogus') @@ -171,7 +171,7 @@ class TestSingleDir(test_util.TestBase): file_callback, 'an_author', '2009-10-19 18:49:30 -0500', - {'branch': 'default',}) + {'branch': 'default', }) repo.commitctx(ctx) hg.update(repo, repo['tip'].node()) self.pushrevisions(expected_extra_back=1) @@ -206,7 +206,7 @@ class TestSingleDir(test_util.TestBase): file_callback(name), 'an_author', '2009-10-19 18:49:30 -0500', - {'branch': name,})) + {'branch': name, })) parent = repo['tip'].node() commit_to_branch('default', parent) @@ -252,7 +252,7 @@ class TestSingleDir(test_util.TestBase): file_callback, 'an_author', '2009-10-19 18:49:30 -0500', - {'branch': 'default',}) + {'branch': 'default', }) self.repo.commitctx(ctx) hg.update(self.repo, self.repo['tip'].node()) self.pushrevisions() @@ -266,5 +266,5 @@ class TestSingleDir(test_util.TestBase): self.test_push_single_dir_renamed_branch(True) def suite(): - all = [unittest.TestLoader().loadTestsFromTestCase(TestSingleDir)] - return unittest.TestSuite(all) + all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestSingleDir)] + return unittest.TestSuite(all_tests) diff --git a/tests/test_startrev.py b/tests/test_startrev.py --- a/tests/test_startrev.py +++ b/tests/test_startrev.py @@ -61,10 +61,10 @@ for case in [f for f in os.listdir(test_ name = bname + '_stupid' attrs[name] = buildmethod(case, name, subdir, True) -StartRevTests = type('StartRevTests', (test_util.TestBase, ), attrs) +StartRevTests = type('StartRevTests', (test_util.TestBase,), attrs) def suite(): - all = [unittest.TestLoader().loadTestsFromTestCase(StartRevTests), + all_tests = [unittest.TestLoader().loadTestsFromTestCase(StartRevTests), ] - return unittest.TestSuite(all) + return unittest.TestSuite(all_tests) diff --git a/tests/test_svnwrap.py b/tests/test_svnwrap.py --- a/tests/test_svnwrap.py +++ b/tests/test_svnwrap.py @@ -22,10 +22,10 @@ class TestBasicRepoLayout(unittest.TestC def setUp(self): self.tmpdir = tempfile.mkdtemp('svnwrap_test') self.repo_path = '%s/testrepo' % self.tmpdir - subprocess.call(['svnadmin', 'create', self.repo_path,]) + subprocess.call(['svnadmin', 'create', self.repo_path, ]) inp = open(os.path.join(os.path.dirname(__file__), 'fixtures', 'project_root_at_repo_root.svndump')) - proc = subprocess.call(['svnadmin', 'load', self.repo_path,], + proc = subprocess.call(['svnadmin', 'load', self.repo_path, ], stdin=inp, close_fds=test_util.canCloseFds, stdout=subprocess.PIPE, @@ -57,10 +57,10 @@ class TestRootAsSubdirOfRepo(TestBasicRe def setUp(self): self.tmpdir = tempfile.mkdtemp('svnwrap_test') self.repo_path = '%s/testrepo' % self.tmpdir - subprocess.call(['svnadmin', 'create', self.repo_path,]) + subprocess.call(['svnadmin', 'create', self.repo_path, ]) inp = open(os.path.join(os.path.dirname(__file__), 'fixtures', 'project_root_not_repo_root.svndump')) - ret = subprocess.call(['svnadmin', 'load', self.repo_path,], + ret = subprocess.call(['svnadmin', 'load', self.repo_path, ], stdin=inp, close_fds=test_util.canCloseFds, stdout=subprocess.PIPE, @@ -71,6 +71,6 @@ class TestRootAsSubdirOfRepo(TestBasicRe )) def suite(): - all = [unittest.TestLoader().loadTestsFromTestCase(TestBasicRepoLayout), + all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestBasicRepoLayout), unittest.TestLoader().loadTestsFromTestCase(TestRootAsSubdirOfRepo)] - return unittest.TestSuite(all) + return unittest.TestSuite(all_tests) diff --git a/tests/test_tags.py b/tests/test_tags.py --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -138,9 +138,9 @@ rename a tag openheads = [h for h in heads if not repo[h].extra().get('close', False)] closedheads = set(heads) - set(openheads) self.assertEqual(len(openheads), 1) - self.assertEqual(len(closedheads), headcount-1) + self.assertEqual(len(closedheads), headcount - 1) closedheads = sorted(list(closedheads), - cmp=lambda x,y: cmp(repo[x].rev(), repo[y].rev())) + cmp=lambda x, y: cmp(repo[x].rev(), repo[y].rev())) # closeme has no open heads for h in openheads: diff --git a/tests/test_template_keywords.py b/tests/test_template_keywords.py --- a/tests/test_template_keywords.py +++ b/tests/test_template_keywords.py @@ -15,7 +15,7 @@ try: from mercurial import revset revset.methods except ImportError: - revset = None + revset = None class CapturingUI(ui.ui): @@ -82,5 +82,5 @@ class TestLogKeywords(test_util.TestBase template='{rev}:{svnrev} ', **defaults) def suite(): - all = [unittest.TestLoader().loadTestsFromTestCase(TestLogKeywords),] - return unittest.TestSuite(all) + all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestLogKeywords), ] + return unittest.TestSuite(all_tests) diff --git a/tests/test_unaffected_core.py b/tests/test_unaffected_core.py --- a/tests/test_unaffected_core.py +++ b/tests/test_unaffected_core.py @@ -88,5 +88,5 @@ class TestMercurialCore(test_util.TestBa self.assertEqual(repo[branch].hex(), repo2['.'].hex()) def suite(): - all = [unittest.TestLoader().loadTestsFromTestCase(TestMercurialCore)] - return unittest.TestSuite(all) + all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestMercurialCore)] + return unittest.TestSuite(all_tests) diff --git a/tests/test_urls.py b/tests/test_urls.py --- a/tests/test_urls.py +++ b/tests/test_urls.py @@ -29,16 +29,16 @@ class TestSubversionUrls(test_util.TestB def test_svnssh_preserve_user(self): self.assertEqual( - ('user', 't3stpw', 'svn+ssh://user@svn.testurl.com/repo', ), + ('user', 't3stpw', 'svn+ssh://user@svn.testurl.com/repo',), parse_url('svn+ssh://user:t3stpw@svn.testurl.com/repo')) self.assertEqual( - ('bob', '123abc', 'svn+ssh://bob@svn.testurl.com/repo', ), + ('bob', '123abc', 'svn+ssh://bob@svn.testurl.com/repo',), parse_url('svn+ssh://user:t3stpw@svn.testurl.com/repo', 'bob', '123abc')) self.assertEqual( - ('user2', None, 'svn+ssh://user2@svn.testurl.com/repo', ), + ('user2', None, 'svn+ssh://user2@svn.testurl.com/repo',), parse_url('svn+ssh://user2@svn.testurl.com/repo')) self.assertEqual( - ('bob', None, 'svn+ssh://bob@svn.testurl.com/repo', ), + ('bob', None, 'svn+ssh://bob@svn.testurl.com/repo',), parse_url('svn+ssh://user2@svn.testurl.com/repo', 'bob')) def test_user_password_url(self): @@ -75,5 +75,5 @@ class TestSubversionUrls(test_util.TestB self.assertEqual(repo1.svnurl, repo2.svnurl) def suite(): - all = [unittest.TestLoader().loadTestsFromTestCase(TestSubversionUrls)] - return unittest.TestSuite(all) + all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestSubversionUrls)] + return unittest.TestSuite(all_tests) diff --git a/tests/test_util.py b/tests/test_util.py --- a/tests/test_util.py +++ b/tests/test_util.py @@ -43,7 +43,7 @@ from hgsubversion import util # "Note that on Windows, you cannot set close_fds to true and # also redirect the standard handles by setting stdin, stdout or # stderr." -canCloseFds='win32' not in sys.platform +canCloseFds = 'win32' not in sys.platform if not 'win32' in sys.platform: def kill_process(popen_obj): @@ -75,7 +75,7 @@ else: DWORD, 'dwProcessId', ) - CloseHandle = WINAPI(BOOL, ctypes.windll.kernel32.CloseHandle, + CloseHandle = WINAPI(BOOL, ctypes.windll.kernel32.CloseHandle, HANDLE, 'hObject' ) @@ -163,10 +163,10 @@ def load_svndump_fixture(path, fixture_n already exist. ''' if os.path.exists(path): rmtree(path) - subprocess.call(['svnadmin', 'create', path,], + subprocess.call(['svnadmin', 'create', path, ], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) inp = open(os.path.join(FIXTURES, fixture_name)) - proc = subprocess.Popen(['svnadmin', 'load', path,], stdin=inp, + proc = subprocess.Popen(['svnadmin', 'load', path, ], stdin=inp, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) proc.communicate() @@ -248,8 +248,8 @@ class TestBase(unittest.TestCase): def setUp(self): _verify_our_modules() - self.oldenv = dict([(k, os.environ.get(k, None), ) for k in - ('LANG', 'LC_ALL', 'HGRCPATH', )]) + self.oldenv = dict([(k, os.environ.get(k, None),) for k in + ('LANG', 'LC_ALL', 'HGRCPATH',)]) self.oldt = i18n.t os.environ['LANG'] = os.environ['LC_ALL'] = 'C' i18n.t = gettext.translation('hg', i18n.localedir, fallback=True) diff --git a/tests/test_utility_commands.py b/tests/test_utility_commands.py --- a/tests/test_utility_commands.py +++ b/tests/test_utility_commands.py @@ -112,7 +112,7 @@ class UtilityTests(test_util.TestBase): self._load_fixture_and_fetch('two_heads.svndump') u = self.ui() u.pushbuffer() - parents = (self.repo['the_branch'].node(), revlog.nullid, ) + parents = (self.repo['the_branch'].node(), revlog.nullid,) def filectxfn(repo, memctx, path): return context.memfilectx(path=path, data='added', @@ -155,7 +155,7 @@ class UtilityTests(test_util.TestBase): def test_outgoing_output(self): self._load_fixture_and_fetch('two_heads.svndump') u = self.ui() - parents = (self.repo['the_branch'].node(), revlog.nullid, ) + parents = (self.repo['the_branch'].node(), revlog.nullid,) def filectxfn(repo, memctx, path): return context.memfilectx(path=path, data='added', @@ -185,7 +185,7 @@ class UtilityTests(test_util.TestBase): def test_rebase(self): self._load_fixture_and_fetch('two_revs.svndump') - parents = (self.repo[0].node(), revlog.nullid, ) + parents = (self.repo[0].node(), revlog.nullid,) def filectxfn(repo, memctx, path): return context.memfilectx(path=path, data='added', @@ -251,6 +251,6 @@ class UtilityTests(test_util.TestBase): def suite(): - all = [unittest.TestLoader().loadTestsFromTestCase(UtilityTests), + all_tests = [unittest.TestLoader().loadTestsFromTestCase(UtilityTests), ] - return unittest.TestSuite(all) + return unittest.TestSuite(all_tests)