From patchwork Thu Dec 11 15:47:48 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [2, of, 2, stable] scmutil: record all symlinks to a repository in walkrepos From: "Enrique A. Tobis" X-Patchwork-Id: 7051 Message-Id: To: mercurial-devel@selenic.com Date: Thu, 11 Dec 2014 10:47:48 -0500 # HG changeset patch # User Enrique A. Tobis # Date 1418275100 18000 # Thu Dec 11 00:18:20 2014 -0500 # Branch stable # Node ID a2351ea044f117402b17809050bdc5dc2de29ff4 # Parent c67b563426866e1c717c6a25b0056bb51cb155e5 scmutil: record all symlinks to a repository in walkrepos In walkrepos, list all paths that lead to a repository when symlinks are followed, while still avoiding infinite loops. diff -r c67b56342686 -r a2351ea044f1 mercurial/scmutil.py --- a/mercurial/scmutil.py Wed Dec 10 23:46:47 2014 -0500 +++ b/mercurial/scmutil.py Thu Dec 11 00:18:20 2014 -0500 @@ -448,9 +448,6 @@ def walkrepos(path, followsym=False, seen_dirs=None, recurse=False): '''yield every hg repository under path, always recursively. The recurse flag will only control recursion into repo working dirs''' - def errhandler(err): - if err.filename == path: - raise err samestat = getattr(os.path, 'samestat', None) if followsym and samestat is not None: def adddir(dirlst, dirname): @@ -463,35 +460,33 @@ if not match: dirlst.append(dirstat) return not match + removedir = lambda dirlst: dirlst.pop() + if seen_dirs is None: + seen_dirs = [] else: followsym = False - - if (seen_dirs is None) and followsym: - seen_dirs = [] - adddir(seen_dirs, path) - for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler): + adddir = lambda dirlst, dirname: not os.path.islink(dirname) + removedir = lambda dirlst: None + def _walkrepos(path, followsym, seen_dirs, recurse): + dirs = [dirname for dirname in os.listdir(path) + if os.path.isdir(os.path.join(path, dirname))] dirs.sort() if '.hg' in dirs: - yield root # found a repository - qroot = os.path.join(root, '.hg', 'patches') + yield path + qroot = os.path.join(path, '.hg', 'patches') if os.path.isdir(os.path.join(qroot, '.hg')): - yield qroot # we have a patch queue repo here + yield qroot if recurse: - # avoid recursing inside the .hg directory dirs.remove('.hg') else: - dirs[:] = [] # don't descend further - elif followsym: - newdirs = [] - for d in dirs: - fname = os.path.join(root, d) - if adddir(seen_dirs, fname): - if os.path.islink(fname): - for hgname in walkrepos(fname, True, seen_dirs): - yield hgname - else: - newdirs.append(d) - dirs[:] = newdirs + return # don't descend further + for dirname in (os.path.join(path, dirname) for dirname in dirs): + if adddir(seen_dirs, dirname): + for repo in _walkrepos(dirname, followsym, seen_dirs, recurse): + yield repo + removedir(seen_dirs) + for repo in _walkrepos(path, followsym, seen_dirs, recurse): + yield repo def osrcpath(): '''return default os-specific hgrc search path''' diff -r c67b56342686 -r a2351ea044f1 tests/test-hgwebdirsym.t --- a/tests/test-hgwebdirsym.t Wed Dec 10 23:46:47 2014 -0500 +++ b/tests/test-hgwebdirsym.t Thu Dec 11 00:18:20 2014 -0500 @@ -40,6 +40,9 @@ /al/ /b/ /c/ + /circle/al/ + /circle/b/ + /circle/c/ $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'al/file/tip/a?style=raw' 200 Script output follows @@ -53,28 +56,38 @@ 200 Script output follows c - + $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'circle/al/file/tip/a?style=raw' + 200 Script output follows + + a + $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'circle/b/file/tip/b?style=raw' + 200 Script output follows + + b + $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'circle/c/file/tip/c?style=raw' + 200 Script output follows + + c should fail - $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'circle/al/file/tip/a?style=raw' + $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'circle/circle/al/file/tip/a?style=raw' 404 Not Found - error: repository circle/al/file/tip/a not found + error: repository circle/circle/al/file/tip/a not found [1] - $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'circle/b/file/tip/a?style=raw' + $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'circle/circle/b/file/tip/b?style=raw' 404 Not Found - error: repository circle/b/file/tip/a not found + error: repository circle/circle/b/file/tip/b not found [1] - $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'circle/c/file/tip/a?style=raw' + $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'circle/circle/c/file/tip/c?style=raw' 404 Not Found - error: repository circle/c/file/tip/a not found + error: repository circle/circle/c/file/tip/c not found [1] - collections errors $ cat error-collections.log diff -r c67b56342686 -r a2351ea044f1 tests/test-walkrepo.py --- a/tests/test-walkrepo.py Wed Dec 10 23:46:47 2014 -0500 +++ b/tests/test-walkrepo.py Thu Dec 11 00:18:20 2014 -0500 @@ -22,22 +22,22 @@ def runtest(): reposet = frozenset(walkrepos('.', followsym=True)) - if sym and (len(reposet) != 3): + if sym and (len(reposet) != 7): print "reposet = %r" % (reposet,) - print ("Found %d repositories when I should have found 3" + print ("Found %d repositories when I should have found 7" % (len(reposet),)) if (not sym) and (len(reposet) != 2): print "reposet = %r" % (reposet,) print ("Found %d repositories when I should have found 2" % (len(reposet),)) sub1set = frozenset((pjoin('.', 'sub1'), - pjoin('.', 'circle', 'subdir', 'sub1'))) + pjoin('.', 'circle', 'circle', 'subdir', 'sub1'))) if len(sub1set & reposet) != 1: print "sub1set = %r" % (sub1set,) print "reposet = %r" % (reposet,) print "sub1set and reposet should have exactly one path in common." - sub2set = frozenset((pjoin('.', 'subsub1'), - pjoin('.', 'subsubdir', 'subsub1'))) + sub2set = frozenset((pjoin('.', 'sub1'), + pjoin('.', 'circle', 'subdir', 'circle', 'top1'))) if len(sub2set & reposet) != 1: print "sub2set = %r" % (sub2set,) print "reposet = %r" % (reposet,)