예제 #1
0
    def load_remote_configuration(self, pkg):
        """
        attempt to load any remote configuration options for a package

        This call will scan select output locations of a package's content for
        any releng-tool-specific package configurations to late-load into a
        package definition.

        Args:
            pkg: the package

        Raises:
            RelengToolInvalidPackageConfiguration: when an error has been
                                                    detected loading any of the
                                                    package's extended options
        """

        target_remote_configurations = [
            os.path.join(pkg.build_dir, RELENG_CONF_EXTENDED_NAME)
        ]

        if pkg.build_subdir:
            target_remote_configurations.append(
                os.path.join(pkg.build_subdir, RELENG_CONF_EXTENDED_NAME))

        # find the first available script to load from
        for target in target_remote_configurations:
            pkg_script, pkg_script_exists = opt_file(target)
            if pkg_script_exists:
                # attempt to finalize the package
                self.finalize_package(pkg, pkg_script)
                break
예제 #2
0
def install(opts):
    """
    support installation project-defined scripts

    With provided installation options (``RelengInstallOptions``), the
    installation stage will be processed.

    Args:
        opts: installation options

    Returns:
        ``True`` if the installation stage is completed; ``False`` otherwise
    """

    assert opts
    build_dir = opts.build_dir
    def_dir = opts.def_dir
    env = opts.env

    install_script_filename = '{}-{}'.format(opts.name, INSTALL_SCRIPT)
    install_script = os.path.join(def_dir, install_script_filename)
    install_script, install_script_exists = opt_file(install_script)
    if not install_script_exists:
        if (opts._skip_remote_scripts or
                'releng.disable_remote_scripts' in opts._quirks):
            return True

        install_script_filename = '{}-{}'.format('releng', INSTALL_SCRIPT)
        install_script = os.path.join(build_dir, install_script_filename)
        install_script, install_script_exists = opt_file(install_script)
        if not install_script_exists:
            return True

    if not run_script(install_script, env, subject='install'):
        return False

    verbose('install script executed: ' + install_script)
    return True
예제 #3
0
def configure(opts):
    """
    support configuration project-defined scripts

    With provided configuration options (``RelengConfigureOptions``), the
    configuration stage will be processed.

    Args:
        opts: configuration options

    Returns:
        ``True`` if the configuration stage is completed; ``False`` otherwise
    """

    assert opts
    build_dir = opts.build_dir
    def_dir = opts.def_dir
    env = opts.env

    configure_script_filename = '{}-{}'.format(opts.name, CONFIGURE_SCRIPT)
    configure_script = os.path.join(def_dir, configure_script_filename)
    configure_script, configure_script_exists = opt_file(configure_script)
    if not configure_script_exists:
        if (opts._skip_remote_scripts
                or 'releng.disable_remote_scripts' in opts._quirks):
            return True

        configure_script_filename = '{}-{}'.format('releng', CONFIGURE_SCRIPT)
        configure_script = os.path.join(build_dir, configure_script_filename)
        configure_script, configure_script_exists = opt_file(configure_script)
        if not configure_script_exists:
            return True

    if not run_script(configure_script, env, subject='configure'):
        return False

    verbose('install script executed: ' + configure_script)
    return True
예제 #4
0
def build(opts):
    """
    support building project-defined scripts

    With provided build options (``RelengBuildOptions``), the build stage will
    be processed.

    Args:
        opts: build options

    Returns:
        ``True`` if the building stage is completed; ``False`` otherwise
    """

    assert opts
    build_dir = opts.build_dir
    def_dir = opts.def_dir
    env = opts.env

    build_script_filename = '{}-{}'.format(opts.name, BUILD_SCRIPT)
    build_script = os.path.join(def_dir, build_script_filename)
    build_script, build_script_exists = opt_file(build_script)
    if not build_script_exists:
        if (opts._skip_remote_scripts or
                'releng.disable_remote_scripts' in opts._quirks):
            return True

        build_script_filename = '{}-{}'.format('releng', BUILD_SCRIPT)
        build_script = os.path.join(build_dir, build_script_filename)
        build_script, build_script_exists = opt_file(build_script)
        if not build_script_exists:
            return True

    if not run_script(build_script, env, subject='build'):
        return False

    verbose('install script executed: ' + build_script)
    return True
예제 #5
0
    def test_utilio_optfile(self):
        with prepare_workdir() as work_dir:
            def _(*args):
                return os.path.join(work_dir, *args)

            # setup
            files = [
                _('file1'),
                _('file2.py'),
                _('file3'),
                _('file3.py'),
            ]
            for file in files:
                with open(file, 'a') as f:
                    f.write(file)

            # checks
            src = _('file1')
            target, existence = opt_file(src)
            self.assertTrue(existence)
            self.assertEqual(target, src)

            src = _('file2')
            opt = _('file2.py')
            target, existence = opt_file(src)
            self.assertTrue(existence)
            self.assertEqual(target, opt)

            src = _('file3')
            target, existence = opt_file(src)
            self.assertTrue(existence)
            self.assertEqual(target, src)

            src = _('file4')
            target, existence = opt_file(src)
            self.assertFalse(existence)
            self.assertEqual(target, src)
예제 #6
0
def stage(engine, pkg, script_env):
    """
    handles the post-processing stage for a package

    With a provided engine and package instance, the post-processing stage will
    be processed. This stage is typically not advertised and is for advanced
    cases where a developer wishes to manipulate their build environment after
    package has completed each of its phases.

    Args:
        engine: the engine
        pkg: the package being built
        script_env: script environment information

    Returns:
        ``True`` if the post-processing stage is completed; ``False`` otherwise
    """

    verbose('post-processing {}...', pkg.name)
    sys.stdout.flush()

    post_script_filename = '{}-{}'.format(pkg.name, POST_SCRIPT)
    post_script = os.path.join(pkg.def_dir, post_script_filename)
    post_script, post_script_exists = opt_file(post_script)
    if not post_script_exists:
        return True

    if pkg.build_subdir:
        build_dir = pkg.build_subdir
    else:
        build_dir = pkg.build_dir

    with interim_working_dir(build_dir):
        if not run_script(post_script, script_env, subject='post-processing'):
            return False

    verbose('post-processing script executed: ' + post_script)
    return True
예제 #7
0
    def load(self, names):
        """
        load one or more packages from the provided collection of names

        Attempts to load and return a series of ordered package instances using
        the collection of names provided. Each name will be used to find a
        package definition on the system. Package scripts are found, loaded and
        parsed. Packages with dependencies will have their dependent packages
        loaded as well (either from the explicitly from the ``names`` or
        implicitly from the package's configuration file). The returned package
        list will be an ordered package list based on configured dependencies
        outlined in the user's package definitions. When package dependencies do
        not play a role in the required order of the releng process, a
        first-configured first-returned approach is used.

        Args:
            names: the names of packages to load

        Returns:
            returns an ordered list of packages to use

        Raises:
            RelengToolInvalidPackageConfiguration: when an error has been
                                                    detected loading the package
        """
        pkgs = OrderedDict()
        final_deps = {}

        # cycle through all pending packages until the complete list is known
        names_left = list(names)
        while names_left:
            name = names_left.pop(0)

            # attempt to load the package from a user defined external directory
            pkg = None
            for pkg_dir in self.opts.extern_pkg_dirs:
                pkg_script = os.path.join(pkg_dir, name, name)
                pkg_script, pkg_script_exists = opt_file(pkg_script)
                if pkg_script_exists:
                    pkg, env, deps = self.load_package(name, pkg_script)

            # if a package location has not been found, finally check the
            # default package directory
            if not pkg:
                pkg_script = os.path.join(self.opts.default_pkg_dir, name,
                                          name)
                pkg_script, _ = opt_file(pkg_script)

                pkg, env, deps = self.load_package(name, pkg_script)

            pkgs[pkg.name] = pkg
            for dep in deps:
                # if this is an unknown package and is not in out current list,
                # append it to the list of names to process
                if dep == name:
                    raise RelengToolCyclicPackageDependency({
                        'pkg_name': name,
                    })
                elif dep not in pkgs:
                    if dep not in names_left:
                        verbose('adding implicitly defined package: {}', dep)
                        names_left.append(dep)

                    if pkg not in final_deps:
                        final_deps[pkg] = []
                    final_deps[pkg].append(dep)
                else:
                    pkg.deps.append(pkgs[dep])
            extend_script_env(self.script_env, env)

        # for packages which have a dependency but have not been bound yet,
        # bind the dependencies now
        for pkg, deps in final_deps.items():
            for dep in deps:
                assert pkgs[dep]
                pkg.deps.append(pkgs[dep])

        debug('sorting packages...')

        def fetch_deps(pkg):
            return pkg.deps

        sorter = TopologicalSorter(fetch_deps)
        sorted_pkgs = []
        for pkg in pkgs.values():
            sorted_pkgs = sorter.sort(pkg)
            if sorted_pkgs is None:
                raise RelengToolCyclicPackageDependency({
                    'pkg_name': name,
                })
        debug('sorted packages)')
        for pkg in sorted_pkgs:
            debug(' {}', pkg.name)

        return sorted_pkgs