Bug 1293259 - [manifestparser] Use rootdir when searching for child manifests draft
authorAndrew Halberstadt <ahalberstadt@mozilla.com>
Tue, 15 Nov 2016 09:42:32 -0500
changeset 439175 e72bf547fe85f9df684ec4edab1f2001ab2989d9
parent 439174 4076bc52c2c4a9d818406e258363fd36a8a2708e
child 439176 dbbdc837d5bb97d73f346df3010929f22e95d52f
push id35923
push userahalberstadt@mozilla.com
push dateTue, 15 Nov 2016 15:06:20 +0000
bugs1293259
milestone53.0a1
Bug 1293259 - [manifestparser] Use rootdir when searching for child manifests MozReview-Commit-ID: DKyhwQjamUA
testing/mozbase/manifestparser/manifestparser/manifestparser.py
--- a/testing/mozbase/manifestparser/manifestparser/manifestparser.py
+++ b/testing/mozbase/manifestparser/manifestparser/manifestparser.py
@@ -85,68 +85,73 @@ class ManifestParser(object):
 
     def path_exists(self, path):
         if self.finder:
             return self.finder.get(path) is not None
         return os.path.exists(path)
 
     # methods for reading manifests
 
-    def _read(self, root, filename, defaults, defaults_only=False, parentmanifest=None):
+    def _read(self, filename, defaults, defaults_only=False, parentmanifest=None):
         """
         Internal recursive method for reading and parsing manifests.
         Stores all found tests in self.tests
-        :param root: The base path
         :param filename: File object or string path for the base manifest file
         :param defaults: Options that apply to all items
         :param defaults_only: If True will only gather options, not include
                               tests. Used for upstream parent includes
                               (default False)
         :param parentmanifest: Filename of the parent manifest (default None)
         """
         def read_file(type):
             include_file = section.split(type, 1)[-1]
             include_file = normalize_path(include_file)
-            if not os.path.isabs(include_file):
-                include_file = os.path.join(here, include_file)
-            if not self.path_exists(include_file):
+
+            if os.path.isabs(include_file):
+                return include_file
+
+            for base in (self.rootdir, here):
+                test = os.path.join(base, include_file)
+                if os.path.exists(test):
+                    include_file = test
+                    break
+            else:
                 message = "Included file '%s' does not exist" % include_file
                 if self.strict:
                     raise IOError(message)
                 else:
                     sys.stderr.write("%s\n" % message)
                     return
             return include_file
 
         # get directory of this file if not file-like object
         if isinstance(filename, string):
             # If we're using mercurial as our filesystem via a finder
             # during manifest reading, the getcwd() calls that happen
             # with abspath calls will not be meaningful, so absolute
             # paths are required.
             if self.finder:
                 assert os.path.isabs(filename)
-            filename = os.path.abspath(filename)
+            elif not os.path.isabs(filename):
+                filename = os.path.join(self.rootdir, filename)
+
             if self.finder:
                 fp = self.finder.get(filename)
             else:
                 fp = open(filename)
             here = os.path.dirname(filename)
         else:
             fp = filename
             filename = here = None
         defaults['here'] = here
 
         # Rootdir is needed for relative path calculation. Precompute it for
         # the microoptimization used below.
-        if self.rootdir is None:
-            rootdir = ""
-        else:
-            assert os.path.isabs(self.rootdir)
-            rootdir = self.rootdir + os.path.sep
+        assert os.path.isabs(self.rootdir)
+        rootdir = self.rootdir + os.path.sep
 
         # read the configuration
         sections = read_ini(fp=fp, variables=defaults, strict=self.strict,
                             handle_defaults=self._handle_defaults)
         self.manifest_defaults[filename] = defaults
 
         parent_section_found = False
 
@@ -158,27 +163,27 @@ class ManifestParser(object):
                 continue
 
             # read the parent manifest if specified
             if section.startswith('parent:'):
                 parent_section_found = True
 
                 include_file = read_file('parent:')
                 if include_file:
-                    self._read(root, include_file, {}, True)
+                    self._read(include_file, {}, True)
                 continue
 
             # a file to include
             # TODO: keep track of included file structure:
             # self.manifests = {'manifest.ini': 'relative/path.ini'}
             if section.startswith('include:'):
                 include_file = read_file('include:')
                 if include_file:
                     include_defaults = data.copy()
-                    self._read(root, include_file, include_defaults, parentmanifest=filename)
+                    self._read(include_file, include_defaults, parentmanifest=filename)
                 continue
 
             # otherwise an item
             # apply ancestor defaults, while maintaining current file priority
             data = dict(self._ancestor_defaults.items() + data.items())
 
             test = data
             test['name'] = section
@@ -260,21 +265,20 @@ class ManifestParser(object):
             # set the per file defaults
             defaults = _defaults.copy()
             here = None
             if isinstance(filename, string):
                 here = os.path.dirname(os.path.abspath(filename))
                 defaults['here'] = here  # directory of master .ini file
 
             if self.rootdir is None:
-                # set the root directory
-                # == the directory of the first manifest given
+                # set rootdir to directory of the first manifest given
                 self.rootdir = here
 
-            self._read(here, filename, defaults)
+            self._read(filename, defaults)
 
     # methods for querying manifests
 
     def query(self, *checks, **kw):
         """
         general query function for tests
         - checks : callable conditions to test if the test fulfills the query
         """