Ejemplo n.º 1
0
    def test_find_legacy_env(self):
        """Ensure legacy mozconfig path definitions result in error."""

        os.environ["MOZ_MYCONFIG"] = "/foo"

        with self.assertRaises(MozconfigFindException) as e:
            find_mozconfig(self.get_temp_dir())

        self.assertTrue(str(e.exception).startswith("The MOZ_MYCONFIG"))
Ejemplo n.º 2
0
    def test_find_abs_path_not_exist(self):
        """Ensure a missing absolute path is detected."""
        os.environ["MOZCONFIG"] = "/foo/bar/does/not/exist"

        with self.assertRaises(MozconfigFindException) as e:
            find_mozconfig(self.get_temp_dir())

        self.assertIn("path that does not exist", str(e.exception))
        self.assertTrue(str(e.exception).endswith("/foo/bar/does/not/exist"))
Ejemplo n.º 3
0
    def test_find_path_not_file(self):
        """Ensure non-file paths are detected."""

        os.environ["MOZCONFIG"] = gettempdir()

        with self.assertRaises(MozconfigFindException) as e:
            find_mozconfig(self.get_temp_dir())

        self.assertIn("refers to a non-file", str(e.exception))
        self.assertTrue(str(e.exception).endswith(gettempdir()))
Ejemplo n.º 4
0
    def test_find_deprecated_path_srcdir(self):
        """Ensure we error when deprecated path locations are present."""
        for p in DEPRECATED_TOPSRCDIR_PATHS:
            d = self.get_temp_dir()
            with open(os.path.join(d, p), "w"):
                pass

            with self.assertRaises(MozconfigFindException) as e:
                find_mozconfig(d)

            self.assertIn("This implicit location is no longer", str(e.exception))
            self.assertIn(d, str(e.exception))
Ejemplo n.º 5
0
    def test_find_multiple_defaults(self):
        """Ensure we error when multiple default files are present."""
        self.assertGreater(len(DEFAULT_TOPSRCDIR_PATHS), 1)

        d = self.get_temp_dir()
        for p in DEFAULT_TOPSRCDIR_PATHS:
            with open(os.path.join(d, p), "w"):
                pass

        with self.assertRaises(MozconfigFindException) as e:
            find_mozconfig(d)

        self.assertIn("Multiple default mozconfig files present", str(e.exception))
Ejemplo n.º 6
0
    def _output_mozconfig(self, application, mozconfig_builder):
        # Like 'generate_browser_mozconfig' or 'generate_mobile_android_mozconfig'.
        additional_mozconfig = getattr(
            self.instance, "generate_%s_mozconfig" % application
        )()
        if additional_mozconfig:
            mozconfig_builder.append(additional_mozconfig)
        raw_mozconfig = mozconfig_builder.generate()

        if raw_mozconfig:
            mozconfig_path = find_mozconfig(self.mach_context.topdir)
            if not mozconfig_path:
                # No mozconfig file exists yet
                mozconfig_path = os.path.join(self.mach_context.topdir, "mozconfig")
                with open(mozconfig_path, "w") as mozconfig_file:
                    mozconfig_file.write(raw_mozconfig)
                print(
                    'Your requested configuration has been written to "%s".'
                    % mozconfig_path
                )
            else:
                suggestion = MOZCONFIG_SUGGESTION_TEMPLATE % (
                    mozconfig_path,
                    raw_mozconfig,
                )
                print(suggestion)
Ejemplo n.º 7
0
    def test_find_deprecated_home_paths(self):
        """Ensure we error when deprecated home directory paths are present."""

        for p in DEPRECATED_HOME_PATHS:
            home = self.get_temp_dir()
            os.environ["HOME"] = home
            path = os.path.join(home, p)

            with open(path, "w"):
                pass

            with self.assertRaises(MozconfigFindException) as e:
                find_mozconfig(self.get_temp_dir())

            self.assertIn("This implicit location is no longer", str(e.exception))
            self.assertIn(path, str(e.exception))
Ejemplo n.º 8
0
    def test_find_default_files(self):
        """Ensure default paths are used when present."""
        for p in DEFAULT_TOPSRCDIR_PATHS:
            d = self.get_temp_dir()
            path = os.path.join(d, p)

            with open(path, "w"):
                pass

            self.assertEqual(find_mozconfig(d), path)
Ejemplo n.º 9
0
    def test_find_no_relative_configs(self):
        """Ensure a missing relative-path MOZCONFIG is detected."""
        relative_mozconfig = ".mconfig"
        os.environ["MOZCONFIG"] = relative_mozconfig

        srcdir = self.get_temp_dir()
        curdir = self.get_temp_dir()
        dirs = [srcdir, curdir]

        orig_dir = os.getcwd()
        try:
            os.chdir(curdir)
            with self.assertRaises(MozconfigFindException) as e:
                find_mozconfig(srcdir)
        finally:
            os.chdir(orig_dir)

        self.assertIn("does not exist in any of", str(e.exception))
        for d in dirs:
            self.assertIn(d, str(e.exception))
Ejemplo n.º 10
0
    def test_find_multiple_configs(self):
        """Ensure multiple relative-path MOZCONFIGs result in error."""
        relative_mozconfig = ".mconfig"
        os.environ["MOZCONFIG"] = relative_mozconfig

        srcdir = self.get_temp_dir()
        curdir = self.get_temp_dir()
        dirs = [srcdir, curdir]
        for d in dirs:
            path = os.path.join(d, relative_mozconfig)
            with open(path, "w") as f:
                f.write(path)

        orig_dir = os.getcwd()
        try:
            os.chdir(curdir)
            with self.assertRaises(MozconfigFindException) as e:
                find_mozconfig(srcdir)
        finally:
            os.chdir(orig_dir)

        self.assertIn("exists in more than one of", str(e.exception))
        for d in dirs:
            self.assertIn(d, str(e.exception))
Ejemplo n.º 11
0
    def _output_mozconfig(self, application):
        # Like 'generate_browser_mozconfig' or 'generate_mobile_android_mozconfig'.
        mozconfig = getattr(self.instance, 'generate_%s_mozconfig' % application)()

        if mozconfig:
            mozconfig_path = find_mozconfig(self.mach_context.topdir)
            if not mozconfig_path:
                # No mozconfig file exists yet
                mozconfig_path = os.path.join(self.mach_context.topdir, 'mozconfig')
                with open(mozconfig_path, 'w') as mozconfig_file:
                    mozconfig_file.write(mozconfig)
                print('Your requested configuration has been written to "%s".'
                      % mozconfig_path)
            else:
                suggestion = MOZCONFIG_SUGGESTION_TEMPLATE % (mozconfig_path, mozconfig)
                print(suggestion)
Ejemplo n.º 12
0
    def test_find_relative_mozconfig(self):
        """Ensure a relative MOZCONFIG can be found in the srcdir."""
        relative_mozconfig = '.mconfig'
        os.environ['MOZCONFIG'] = relative_mozconfig

        srcdir = self.get_temp_dir()
        curdir = self.get_temp_dir()

        path = os.path.join(srcdir, relative_mozconfig)
        with open(path, 'w'):
            pass

        orig_dir = os.getcwd()
        try:
            os.chdir(curdir)
            self.assertEqual(os.path.normpath(find_mozconfig(srcdir)),
                             os.path.normpath(path))
        finally:
            os.chdir(orig_dir)
Ejemplo n.º 13
0
    def test_find_multiple_but_identical_configs(self):
        """Ensure multiple relative-path MOZCONFIGs pointing at the same file are OK."""
        relative_mozconfig = '../src/.mconfig'
        os.environ['MOZCONFIG'] = relative_mozconfig

        topdir = self.get_temp_dir()
        srcdir = os.path.join(topdir, 'src')
        os.mkdir(srcdir)
        curdir = os.path.join(topdir, 'obj')
        os.mkdir(curdir)

        path = os.path.join(srcdir, relative_mozconfig)
        with open(path, 'w'):
            pass

        orig_dir = os.getcwd()
        try:
            os.chdir(curdir)
            self.assertEqual(os.path.realpath(find_mozconfig(srcdir)),
                             os.path.realpath(path))
        finally:
            os.chdir(orig_dir)
Ejemplo n.º 14
0
    def read_mozconfig(self, path=None):
        """Read the contents of a mozconfig into a data structure.

        This takes the path to a mozconfig to load. If the given path is
        AUTODETECT, will try to find a mozconfig from the environment using
        find_mozconfig().

        mozconfig files are shell scripts. So, we can't just parse them.
        Instead, we run the shell script in a wrapper which allows us to record
        state from execution. Thus, the output from a mozconfig is a friendly
        static data structure.
        """
        if path is self.AUTODETECT:
            path = find_mozconfig(self.topsrcdir)

        result = {
            "path": path,
            "topobjdir": None,
            "configure_args": None,
            "make_flags": None,
            "make_extra": None,
            "env": None,
            "vars": None,
        }

        if path is None:
            if "MOZ_OBJDIR" in os.environ:
                result["topobjdir"] = os.environ["MOZ_OBJDIR"]
            return result

        path = mozpath.normsep(path)

        result["configure_args"] = []
        result["make_extra"] = []
        result["make_flags"] = []

        # Since mozconfig_loader is a shell script, running it "normally"
        # actually leads to two shell executions on Windows. Avoid this by
        # directly calling sh mozconfig_loader.
        shell = "sh"
        if "MOZILLABUILD" in os.environ:
            shell = os.environ["MOZILLABUILD"] + "/msys/bin/sh"
        if sys.platform == "win32":
            shell = shell + ".exe"

        command = [
            shell,
            mozpath.normsep(self._loader_script),
            mozpath.normsep(self.topsrcdir),
            path,
            sys.executable,
            mozpath.join(mozpath.dirname(self._loader_script), "action",
                         "dump_env.py"),
        ]

        try:
            env = dict(os.environ)
            env["PYTHONIOENCODING"] = "utf-8"
            # We need to capture stderr because that's where the shell sends
            # errors if execution fails.
            output = six.ensure_text(
                subprocess.check_output(
                    command,
                    stderr=subprocess.STDOUT,
                    cwd=self.topsrcdir,
                    env=env,
                    universal_newlines=True,
                ))
        except subprocess.CalledProcessError as e:
            lines = e.output.splitlines()

            # Output before actual execution shouldn't be relevant.
            try:
                index = lines.index("------END_BEFORE_SOURCE")
                lines = lines[index + 1:]
            except ValueError:
                pass

            raise MozconfigLoadException(path, MOZCONFIG_BAD_EXIT_CODE, lines)

        try:
            parsed = self._parse_loader_output(output)
        except AssertionError:
            # _parse_loader_output uses assertions to verify the
            # well-formedness of the shell output; when these fail, it
            # generally means there was a problem with the output, but we
            # include the assertion traceback just to be sure.
            print("Assertion failed in _parse_loader_output:")
            traceback.print_exc()
            raise MozconfigLoadException(path, MOZCONFIG_BAD_OUTPUT,
                                         output.splitlines())

        def diff_vars(vars_before, vars_after):
            set1 = set(vars_before.keys()) - self.IGNORE_SHELL_VARIABLES
            set2 = set(vars_after.keys()) - self.IGNORE_SHELL_VARIABLES
            added = set2 - set1
            removed = set1 - set2
            maybe_modified = set1 & set2
            changed = {
                "added": {},
                "removed": {},
                "modified": {},
                "unmodified": {}
            }

            for key in added:
                changed["added"][key] = vars_after[key]

            for key in removed:
                changed["removed"][key] = vars_before[key]

            for key in maybe_modified:
                if vars_before[key] != vars_after[key]:
                    changed["modified"][key] = (vars_before[key],
                                                vars_after[key])
                elif key in self.ENVIRONMENT_VARIABLES:
                    # In order for irrelevant environment variable changes not
                    # to incur in re-running configure, only a set of
                    # environment variables are stored when they are
                    # unmodified. Otherwise, changes such as using a different
                    # terminal window, or even rebooting, would trigger
                    # reconfigures.
                    changed["unmodified"][key] = vars_after[key]

            return changed

        result["env"] = diff_vars(parsed["env_before"], parsed["env_after"])

        # Environment variables also appear as shell variables, but that's
        # uninteresting duplication of information. Filter them out.
        def filt(x, y):
            return {k: v for k, v in x.items() if k not in y}

        result["vars"] = diff_vars(
            filt(parsed["vars_before"], parsed["env_before"]),
            filt(parsed["vars_after"], parsed["env_after"]),
        )

        result["configure_args"] = [self._expand(o) for o in parsed["ac"]]

        if "MOZ_OBJDIR" in parsed["env_before"]:
            result["topobjdir"] = parsed["env_before"]["MOZ_OBJDIR"]

        mk = [self._expand(o) for o in parsed["mk"]]

        for o in mk:
            match = self.RE_MAKE_VARIABLE.match(o)

            if match is None:
                result["make_extra"].append(o)
                continue

            name, value = match.group("var"), match.group("value")

            if name == "MOZ_MAKE_FLAGS":
                result["make_flags"] = value.split()
                continue

            if name == "MOZ_OBJDIR":
                result["topobjdir"] = value
                if parsed["env_before"].get("MOZ_PROFILE_GENERATE") == "1":
                    # If MOZ_OBJDIR is specified in the mozconfig, we need to
                    # make sure that the '/instrumented' directory gets appended
                    # for the first build to avoid an objdir mismatch when
                    # running 'mach package' on Windows.
                    result["topobjdir"] = mozpath.join(result["topobjdir"],
                                                       "instrumented")
                continue

            result["make_extra"].append(o)

        return result