From a0f182b4e8ffbdd1db32f112cfcc986664527e45 Mon Sep 17 00:00:00 2001 From: Gregory Szorc Date: Mon, 8 Jun 2015 09:33:46 -0700 Subject: [PATCH] Bug 1168607 - Add mode to MercurialFileFinder to support non-relative paths; r=glandium The moz.build reader uses absolute paths when referencing moz.build files. *Finder classes expect paths to be relative to a base. When we switched the reader to use *Finder instances for I/O, we simply provided a default FileFinder based at the filesystem root. This was quick and easy. Things worked. Unfortunately, that solution isn't ideal because not all *Finder instances can accept absolute paths like that. The MercurialRevisionFinder is one of them. Changing the moz.build reader to talk in terms of relative paths is a lot of work. While this would be ideal, it is significantly easier to defer the problem until later and hack up MercurialRevisionFinder to accept absolute paths. This commit does exactly that. Bug 1171069 has been filed to track converting BuildReader to relative paths. --- python/mozbuild/mozpack/files.py | 24 ++++++++++++++++++++-- python/mozbuild/mozpack/test/test_files.py | 22 ++++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/python/mozbuild/mozpack/files.py b/python/mozbuild/mozpack/files.py index 7b779ea41ad..a3fd903161f 100644 --- a/python/mozbuild/mozpack/files.py +++ b/python/mozbuild/mozpack/files.py @@ -978,17 +978,28 @@ class MercurialFile(BaseFile): class MercurialRevisionFinder(BaseFinder): """A finder that operates on a specific Mercurial revision.""" - def __init__(self, repo, rev='.', **kwargs): + def __init__(self, repo, rev='.', recognize_repo_paths=False, **kwargs): """Create a finder attached to a specific revision in a repository. If no revision is given, open the parent of the working directory. + + ``recognize_repo_paths`` will enable a mode where ``.get()`` will + recognize full paths that include the repo's path. Typically Finder + instances are "bound" to a base directory and paths are relative to + that directory. This mode changes that. When this mode is activated, + ``.find()`` will not work! This mode exists to support the moz.build + reader, which uses absolute paths instead of relative paths. The reader + should eventually be rewritten to use relative paths and this hack + should be removed (TODO bug 1171069). """ if not hglib: raise Exception('hglib package not found') super(MercurialRevisionFinder, self).__init__(base=repo, **kwargs) - self._root = repo + self._root = mozpath.normpath(repo).rstrip('/') + self._recognize_repo_paths = recognize_repo_paths + # We change directories here otherwise we have to deal with relative # paths. oldcwd = os.getcwd() @@ -1007,9 +1018,18 @@ class MercurialRevisionFinder(BaseFinder): self._files[relpath] = None def _find(self, pattern): + if self._recognize_repo_paths: + raise NotImplementedError('cannot use find with recognize_repo_path') + return self._find_helper(pattern, self._files, self._get) def get(self, path): + if self._recognize_repo_paths: + if not path.startswith(self._root): + raise ValueError('lookups in recognize_repo_paths mode must be ' + 'prefixed with repo path: %s' % path) + path = path[len(self._root) + 1:] + try: return self._get(path) except KeyError: diff --git a/python/mozbuild/mozpack/test/test_files.py b/python/mozbuild/mozpack/test/test_files.py index 471ca58aaf0..db9ac081810 100644 --- a/python/mozbuild/mozpack/test/test_files.py +++ b/python/mozbuild/mozpack/test/test_files.py @@ -1081,6 +1081,28 @@ class TestMercurialRevisionFinder(MatchTestTemplate, TestWithTmpDir): f = finder.get('bar') self.assertEqual(f.read(), 'bar second') + def test_recognize_repo_paths(self): + c = hglib.open(self.tmpdir) + with open(self.tmppath('foo'), 'wb') as fh: + fh.write('initial') + c.add(self.tmppath('foo')) + c.commit('initial') + c.rawcommand(['update', 'null']) + + finder = MercurialRevisionFinder(self.tmpdir, rev='0', + recognize_repo_paths=True) + with self.assertRaises(NotImplementedError): + list(finder.find('')) + + with self.assertRaises(ValueError): + finder.get('foo') + with self.assertRaises(ValueError): + finder.get('') + + f = finder.get(self.tmppath('foo')) + self.assertIsInstance(f, MercurialFile) + self.assertEqual(f.read(), 'initial') + if __name__ == '__main__': mozunit.main()