예제 #1
0
    def _run_step(self, step, part, part_names):
        common.reset_env()
        prereqs = self.parts_config.get_prereqs(part.name)
        unstaged_prereqs = {p for p in prereqs
                            if 'stage' not in self._steps_run[p]}

        if unstaged_prereqs and not unstaged_prereqs.issubset(part_names):
            missing_parts = [part_name for part_name in self.config.part_names
                             if part_name in unstaged_prereqs]
            if missing_parts:
                raise RuntimeError(
                    'Requested {!r} of {!r} but there are unsatisfied '
                    'prerequisites: {!r}'.format(
                        step, part.name, ' '.join(missing_parts)))
        elif unstaged_prereqs:
            # prerequisites need to build all the way to the staging
            # step to be able to share the common assets that make them
            # a dependency.
            logger.info(
                '{!r} has prerequisites that need to be staged: '
                '{}'.format(part.name, ' '.join(unstaged_prereqs)))
            self.run('stage', unstaged_prereqs)

        # Run the preparation function for this step (if implemented)
        with contextlib.suppress(AttributeError):
            getattr(part, 'prepare_{}'.format(step))()

        common.env = self.parts_config.build_env_for_part(part)
        common.env.extend(self.config.project_env())

        part = _replace_in_part(part)

        getattr(part, step)()
예제 #2
0
    def _prepare_step(self, *, step: steps.Step,
                      part: pluginhandler.PluginHandler):
        common.reset_env()
        all_dependencies = self.parts_config.get_dependencies(part.name)

        # Filter dependencies down to only those that need to run the
        # prerequisite step
        prerequisite_step = steps.get_dependency_prerequisite_step(step)
        dependencies = {
            p
            for p in all_dependencies
            if self._cache.should_step_run(p, prerequisite_step)
        }

        if dependencies:
            dependency_names = {p.name for p in dependencies}
            # Dependencies need to go all the way to the prerequisite step to
            # be able to share the common assets that make them a dependency
            logger.info("{!r} has dependencies that need to be {}d: {}".format(
                part.name, prerequisite_step.name, " ".join(dependency_names)))
            self.run(prerequisite_step, dependency_names)

        # Run the preparation function for this step (if implemented)
        preparation_function = getattr(part, "prepare_{}".format(step.name),
                                       None)
        if preparation_function:
            notify_part_progress(part,
                                 "Preparing to {}".format(step.name),
                                 debug=True)
            preparation_function()

        common.env = self.parts_config.build_env_for_part(part)
        common.env.extend(self.config.project_env())

        part = _replace_in_part(part)
예제 #3
0
    def _assemble_runtime_environment(self) -> str:
        # Classic confinement or building on a host that does not match the target base
        # means we cannot setup an environment that will work.
        if self._config_data["confinement"] == "classic":
            # Temporary workaround for snapd bug not expanding PATH:
            # We generate an empty runner which addresses the issue.
            # https://bugs.launchpad.net/snapd/+bug/1860369
            return ""

        env = list()
        if self._project_config.project._snap_meta.base in ("core", "core16", "core18"):
            common.env = self._project_config.snap_env()
            assembled_env = common.assemble_env()
            common.reset_env()

            assembled_env = assembled_env.replace(self._prime_dir, "$SNAP")
            env.append(self._install_path_pattern.sub("$SNAP", assembled_env))
        else:
            # TODO use something local to the meta package and
            # only add paths for directory items that actually exist.
            runtime_env = project_loader.runtime_env(
                self._prime_dir, self._project_config.project.arch_triplet
            )
            for e in runtime_env:
                env.append(re.sub(self._prime_dir, "$SNAP", e))

        env.append("export LD_LIBRARY_PATH=$SNAP_LIBRARY_PATH:$LD_LIBRARY_PATH")

        return "\n".join(env)
예제 #4
0
    def _run_step(self, *, step: steps.Step, part, progress, hint='',
                  prerequisite_step: steps.Step=steps.STAGE):
        common.reset_env()
        prereqs = self.parts_config.get_prereqs(part.name)

        step_prereqs = {p for p in prereqs
                        if prerequisite_step not in self._steps_run[p]}

        if step_prereqs:
            # prerequisites need to go all the way to the prerequisite step to
            # be able to share the common assets that make them a dependency.
            logger.info(
                '{!r} has prerequisites that need to be {}d: {}'.format(
                    part.name, prerequisite_step.name, ' '.join(step_prereqs)))
            self.run(prerequisite_step, step_prereqs)

        # Run the preparation function for this step (if implemented)
        preparation_function = getattr(
            part, 'prepare_{}'.format(step.name), None)
        if preparation_function:
            notify_part_progress(
                part, 'Preparing to {}'.format(step.name), debug=True)
            preparation_function()

        common.env = self.parts_config.build_env_for_part(part)
        common.env.extend(self.config.project_env())

        part = _replace_in_part(part)

        notify_part_progress(part, progress, hint)
        getattr(part, step.name)()
        self._steps_run[part.name].add(step)
        self.steps_were_run = True
예제 #5
0
    def _run_step(self, step, part, part_names, dirty, recursed):
        common.reset_env()
        prereqs = self.config.part_prereqs(part.name)
        if recursed:
            prereqs = prereqs & dirty
        if prereqs and not prereqs.issubset(part_names):
            for prereq in self.config.all_parts:
                if prereq.name in prereqs and prereq.should_step_run('stage'):
                    raise RuntimeError(
                        'Requested {!r} of {!r} but there are unsatisfied '
                        'prerequisites: {!r}'.format(
                            step, part.name, ' '.join(prereqs)))
        elif prereqs:
            # prerequisites need to build all the way to the staging
            # step to be able to share the common assets that make them
            # a dependency.
            logger.info(
                '{!r} has prerequisites that need to be staged: '
                '{}'.format(part.name, ' '.join(prereqs)))
            self.run('stage', prereqs, recursed=True)

        if part.is_dirty(step):
            self._handle_dirty(part, step)

        if not part.should_step_run(step):
            part.notify_part_progress('Skipping {}'.format(step),
                                      '(already ran)')
            return

        # Run the preparation function for this step (if implemented)
        with contextlib.suppress(AttributeError):
            getattr(part, 'prepare_{}'.format(step))()

        common.env = self.config.build_env_for_part(part)
        getattr(part, step)()
예제 #6
0
    def _run_step(self, step, part, part_names, dirty, recursed):
        common.reset_env()
        prereqs = self.parts_config.get_prereqs(part.name)
        if recursed:
            prereqs = prereqs & dirty
        if prereqs and not prereqs.issubset(part_names):
            for prereq in self.config.all_parts:
                if prereq.name in prereqs and prereq.should_step_run('stage'):
                    raise RuntimeError(
                        'Requested {!r} of {!r} but there are unsatisfied '
                        'prerequisites: {!r}'.format(step, part.name,
                                                     ' '.join(prereqs)))
        elif prereqs:
            # prerequisites need to build all the way to the staging
            # step to be able to share the common assets that make them
            # a dependency.
            logger.info('{!r} has prerequisites that need to be staged: '
                        '{}'.format(part.name, ' '.join(prereqs)))
            self.run('stage', prereqs, recursed=True)

        if part.is_dirty(step):
            self._handle_dirty(part, step)

        if not part.should_step_run(step):
            part.notify_part_progress('Skipping {}'.format(step),
                                      '(already ran)')
            return

        # Run the preparation function for this step (if implemented)
        with contextlib.suppress(AttributeError):
            getattr(part, 'prepare_{}'.format(step))()

        common.env = self.parts_config.build_env_for_part(part)
        getattr(part, step)()
예제 #7
0
    def _run_step(self, step, part, part_names):
        common.reset_env()
        prereqs = self.parts_config.get_prereqs(part.name)
        unstaged_prereqs = {p for p in prereqs
                            if 'stage' not in self._steps_run[p]}

        if unstaged_prereqs and not unstaged_prereqs.issubset(part_names):
            missing_parts = [part_name for part_name in self.config.part_names
                             if part_name in unstaged_prereqs]
            if missing_parts:
                raise RuntimeError(
                    'Requested {!r} of {!r} but there are unsatisfied '
                    'prerequisites: {!r}'.format(
                        step, part.name, ' '.join(missing_parts)))
        elif unstaged_prereqs:
            # prerequisites need to build all the way to the staging
            # step to be able to share the common assets that make them
            # a dependency.
            logger.info(
                '{!r} has prerequisites that need to be staged: '
                '{}'.format(part.name, ' '.join(unstaged_prereqs)))
            self.run('stage', unstaged_prereqs)

        # Run the preparation function for this step (if implemented)
        with contextlib.suppress(AttributeError):
            getattr(part, 'prepare_{}'.format(step))()

        common.env = self.parts_config.build_env_for_part(part)
        common.env.extend(self.config.project_env())

        part = _replace_in_part(part)
        getattr(part, step)()
예제 #8
0
    def _generate_snapcraft_runner(self) -> Optional[str]:
        """Create runner if required.

        Return path relative to prime directory, if created."""

        # Classic confinement or building on a host that does not match the target base
        # means we cannot setup an environment that will work.
        if (self._config_data["confinement"] == "classic"
                or not self._is_host_compatible_with_base
                or not self._snap_meta.apps):
            return None

        meta_runner = os.path.join(self._prime_dir, "snap", "command-chain",
                                   "snapcraft-runner")

        common.env = self._project_config.snap_env()
        assembled_env = common.assemble_env()
        assembled_env = assembled_env.replace(self._prime_dir, "$SNAP")
        assembled_env = self._install_path_pattern.sub("$SNAP", assembled_env)

        if assembled_env:
            os.makedirs(os.path.dirname(meta_runner), exist_ok=True)
            with open(meta_runner, "w") as f:
                print("#!/bin/sh", file=f)
                print(assembled_env, file=f)
                print(
                    "export LD_LIBRARY_PATH=$SNAP_LIBRARY_PATH:$LD_LIBRARY_PATH",
                    file=f)
                print('exec "$@"', file=f)
            os.chmod(meta_runner, 0o755)

        common.reset_env()
        return os.path.relpath(meta_runner, self._prime_dir)
예제 #9
0
파일: _runner.py 프로젝트: mvo5/snapcraft
    def _prepare_step(self, *, step: steps.Step, part: pluginhandler.PluginHandler):
        common.reset_env()
        all_dependencies = self.parts_config.get_dependencies(part.name)

        # Filter dependencies down to only those that need to run the
        # prerequisite step
        prerequisite_step = steps.get_dependency_prerequisite_step(step)
        dependencies = {
            p
            for p in all_dependencies
            if self._cache.should_step_run(p, prerequisite_step)
        }

        if dependencies:
            dependency_names = {p.name for p in dependencies}
            # Dependencies need to go all the way to the prerequisite step to
            # be able to share the common assets that make them a dependency
            logger.info(
                "{!r} has dependencies that need to be {}d: {}".format(
                    part.name, prerequisite_step.name, " ".join(dependency_names)
                )
            )
            self.run(prerequisite_step, dependency_names)

        # Run the preparation function for this step (if implemented)
        preparation_function = getattr(part, "prepare_{}".format(step.name), None)
        if preparation_function:
            notify_part_progress(part, "Preparing to {}".format(step.name), debug=True)
            preparation_function()

        common.env = self.parts_config.build_env_for_part(part)
        common.env.extend(self.config.project_env())

        part = _replace_in_part(part)
예제 #10
0
    def _run_step(self, step, part, part_names):
        common.reset_env()
        prereqs = self.parts_config.get_prereqs(part.name)

        # Dependencies need to be primed to have paths to.
        if step == 'prime':
            required_step = 'prime'
        # Or staged to be built with.
        else:
            required_step = 'stage'

        step_prereqs = {
            p
            for p in prereqs if required_step not in self._steps_run[p]
        }

        if step_prereqs:
            # prerequisites need to build all the way to the staging
            # step to be able to share the common assets that make them
            # a dependency.
            logger.info('{!r} has prerequisites that need to be {}d: '
                        '{}'.format(part.name, required_step,
                                    ' '.join(step_prereqs)))
            self.run(required_step, step_prereqs)

        # Run the preparation function for this step (if implemented)
        with contextlib.suppress(AttributeError):
            getattr(part, 'prepare_{}'.format(step))()

        common.env = self.parts_config.build_env_for_part(part)
        common.env.extend(self.config.project_env())

        part = _replace_in_part(part)

        getattr(part, step)()
예제 #11
0
    def write_snap_yaml(self) -> str:
        common.env = self._project_config.snap_env()
        try:
            package_snap_path = os.path.join(self.meta_dir, "snap.yaml")
            snap_yaml = self._compose_snap_yaml()

            with open(package_snap_path, "w") as f:
                yaml_utils.dump(snap_yaml, stream=f)

            return snap_yaml
        finally:
            common.reset_env()
예제 #12
0
    def _prepare_step(self, *, step: steps.Step, part: pluginhandler.PluginHandler):
        common.reset_env()

        self._handle_part_dependencies(step=step, part=part)

        # Run the preparation function for this step (if implemented)
        preparation_function = getattr(part, "prepare_{}".format(step.name), None)
        if preparation_function:
            notify_part_progress(part, "Preparing to {}".format(step.name), debug=True)
            preparation_function()

        if isinstance(part.plugin, plugins.v1.PluginV1):
            common.env = self.parts_config.build_env_for_part(part)
            common.env.extend(self.config.project_env())

        part = _replace_in_part(part)
예제 #13
0
    def write_snap_yaml(self) -> str:
        common.env = self._project_config.snap_env()

        try:
            # Only generate the meta command chain if there are apps that need it
            if self._config_data.get("apps", None):
                self._generate_command_chain()

            package_snap_path = os.path.join(self.meta_dir, "snap.yaml")
            snap_yaml = self._compose_snap_yaml()

            with open(package_snap_path, "w") as f:
                yaml_utils.dump(snap_yaml, stream=f)

            return snap_yaml
        finally:
            common.reset_env()
예제 #14
0
    def _assemble_runtime_environment(self) -> str:
        # Classic confinement or building on a host that does not match the target base
        # means we cannot setup an environment that will work.
        if self._config_data["confinement"] == "classic":
            # Temporary workaround for snapd bug not expanding PATH:
            # We generate an empty runner which addresses the issue.
            # https://bugs.launchpad.net/snapd/+bug/1860369
            return ""

        common.env = self._project_config.snap_env()
        assembled_env = common.assemble_env()
        common.reset_env()

        assembled_env = assembled_env.replace(self._prime_dir, "$SNAP")
        assembled_env = self._install_path_pattern.sub("$SNAP", assembled_env)
        ld_library_env = "export LD_LIBRARY_PATH=$SNAP_LIBRARY_PATH:$LD_LIBRARY_PATH"
        return "\n".join([assembled_env, ld_library_env])
예제 #15
0
    def _assemble_runtime_environment(self) -> str:
        # Classic confinement or building on a host that does not match the target base
        # means we cannot setup an environment that will work.
        if self._config_data["confinement"] == "classic":
            # Temporary workaround for snapd bug not expanding PATH:
            # We generate an empty runner which addresses the issue.
            # https://bugs.launchpad.net/snapd/+bug/1860369
            return ""

        env = list()
        if self._project_config.project._snap_meta.base == "core18":
            common.env = self._project_config.snap_env()
            assembled_env = common.assemble_env()
            common.reset_env()

            assembled_env = assembled_env.replace(self._prime_dir, "$SNAP")
            env.append(self._install_path_pattern.sub("$SNAP", assembled_env))
        else:
            # TODO use something local to the meta package and
            # only add paths for directory items that actually exist.
            runtime_env = project_loader.runtime_env(
                self._prime_dir, self._project_config.project.arch_triplet
            )
            for e in runtime_env:
                env.append(re.sub(self._prime_dir, "$SNAP", e))

        if all(
            [
                part._build_attributes.enable_patchelf()
                for part in self._project_config.all_parts
            ]
        ):
            # All ELF files have had rpath and interpreter patched. Strip all LD_LIBRARY_PATH variables
            env = [e for e in env if not e.startswith("export LD_LIBRARY_PATH=")]
        else:
            env.append(
                'export LD_LIBRARY_PATH="$SNAP_LIBRARY_PATH${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"'
            )

        return "\n".join(env)