changeset 851:9ce00cb1d676

Merge alternate tunnel schemes.
author Augie Fackler <durin42@gmail.com>
date Sat, 25 Feb 2012 14:51:22 -0600
parents d3bc067c0f72 (current diff) 4e203a47102a (diff)
children 8a226f0f99aa
files hgsubversion/svnexternals.py
diffstat 45 files changed, 424 insertions(+), 262 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore
+++ b/.hgignore
@@ -12,3 +12,8 @@ MANIFEST
 dist
 *.egg-info
 hgsubversion/__version__.py
+nbproject
+.project
+.pydevproject
+.settings
+*.orig
--- a/.hgtags
+++ b/.hgtags
@@ -5,3 +5,4 @@ 8e621dbb82d4363a85317638ad237e2817c56347
 093ae2915b452539b44390ee4ea14987484e1eee 1.1.2
 708234ad6c97fb52417e0b46a86c8373e25123a5 1.2
 4bbc6bf947f56a92e95a04a27b94a9f72d5482d7 1.2.1
+0cbf9fd89672e73165e1bb4db1ec8f7f65b95c94 1.3
--- 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
--- 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
--- 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):
--- 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
--- 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
--- 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
--- 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:
--- 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'))
--- 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)
--- 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)
 
--- 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('/'),))
--- 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):]
--- 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):
--- 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)))
--- 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},
 )
--- 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)
--- 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)
--- 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.'
 
--- 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))
--- 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)
--- 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)
--- 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)
--- 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)
--- 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)
--- 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)
--- 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')
--- 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)
--- 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)
--- 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)
--- 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)
--- 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)
--- 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)
--- 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)
--- 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)
--- 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)
--- 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)
--- 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)
--- 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:
--- 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)
--- 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)
--- 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)
--- 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)
--- 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)