Example #1
0
    def __init__(self, pav_cfg, test, mb_tracker, build_name=None):
        """Inititalize the build object.
        :param pav_cfg: The Pavilion config object
        :param pavilion.test_run.TestRun test: The test run responsible for
        starting this build.
        :param MultiBuildTracker mb_tracker: A thread-safe tracker object for
        keeping info on what the build is doing.
        :param str build_name: The build name, if this is a build that already
        exists.
        :raises TestBuilderError: When the builder can't be initialized.
        """

        if mb_tracker is None:
            mb_tracker = MultiBuildTracker(log=False)
        self.tracker = mb_tracker.register(self, test.status)

        self._pav_cfg = pav_cfg
        self._config = test.config.get('build', {})
        self._group = test.group
        self._umask = test.umask
        self._script_path = test.build_script_path
        self.test = test
        self._timeout = test.build_timeout
        self._timeout_file = test.build_timeout_file

        self._fix_source_path()

        if not test.build_local:
            self.tracker.update(state=STATES.BUILD_DEFERRED,
                                note="Build will run on nodes.")

        if build_name is None:
            self.name = self.name_build()
            self.tracker.update(state=STATES.BUILD_CREATED,
                                note="Builder created.")
        else:
            self.name = build_name

        self.path = pav_cfg.working_dir / 'builds' / self.name  # type: Path
        self.tmp_log_path = self.path.with_suffix('.log')
        self.log_path = self.path / self.LOG_NAME
        fail_name = 'fail.{}.{}'.format(self.name, self.test.id)
        self.fail_path = pav_cfg.working_dir / 'builds' / fail_name
        self.finished_path = self.path.with_suffix(self.FINISHED_SUFFIX)

        if self._timeout_file is not None:
            self._timeout_file = self.path / self._timeout_file
        else:
            self._timeout_file = self.tmp_log_path

        # Don't allow a file to be written outside of the build context dir.
        files_to_create = self._config.get('create_files')
        if files_to_create:
            for file, contents in files_to_create.items():
                file_path = Path(utils.resolve_path(self.path / file))
                if not utils.dir_contains(file_path,
                                          utils.resolve_path(self.path)):
                    raise TestBuilderError(
                        "'create_file: {}': file path"
                        " outside build context.".format(file_path))
Example #2
0
 def filter_series(path: Path) -> bool:
     """Return True if the series does not have any valid symlinked tests.
     """
     for test_path in path.iterdir():
         if (test_path.is_symlink() and test_path.exists()
                 and utils.resolve_path(test_path).exists()):
             return False
     return True
Example #3
0
def _get_used_build_paths(tests_dir: Path) -> set:
    """Generate a set of all build paths currently used by one or more test
    runs."""

    used_builds = set()

    for path in dir_db.select(tests_dir).paths:
        build_origin_symlink = path / 'build_origin'
        build_origin = None
        if (build_origin_symlink.exists()
                and build_origin_symlink.is_symlink()
                and utils.resolve_path(build_origin_symlink).exists()):
            build_origin = build_origin_symlink.resolve()

        if build_origin is not None:
            used_builds.add(build_origin.name)

    return used_builds
Example #4
0
    def _setup_build_dir(self, dest):
        """Setup the build directory, by extracting or copying the source
            and any extra files.
        :param dest: Path to the intended build directory. This is generally a
        temporary location.
        :return: None
        """

        raw_src_path = self._config.get('source_path')
        if raw_src_path is None:
            src_path = None
        else:
            src_path = self._find_file(Path(raw_src_path), 'test_src')
            if src_path is None:
                raise TestBuilderError(
                    "Could not find source file '{}'".format(raw_src_path))

            # Resolve any softlinks to get the real file.
            src_path = src_path.resolve()

        if src_path is None:
            # If there is no source archive or data, just make the build
            # directory.
            dest.mkdir()

        elif src_path.is_dir():
            # Recursively copy the src directory to the build directory.
            self.tracker.update(
                state=STATES.BUILDING,
                note=("Copying source directory {} for build {} "
                      "as the build directory.".format(src_path, dest)))

            shutil.copytree(src_path.as_posix(),
                            dest.as_posix(),
                            symlinks=True)

        elif src_path.is_file():
            # Handle decompression of a stream compressed file. The interfaces
            # for the libs are all the same; we just have to choose the right
            # one to use. Zips are handled as an archive, below.
            category, subtype = utils.get_mime_type(src_path)

            if category == 'application' and subtype in self.TAR_SUBTYPES:

                if tarfile.is_tarfile(src_path.as_posix()):
                    self.tracker.update(
                        state=STATES.BUILDING,
                        note=("Extracting tarfile {} for build {}".format(
                            src_path, dest)))
                    extract.extract_tarball(src_path, dest)
                else:
                    self.tracker.update(
                        state=STATES.BUILDING,
                        note=("Extracting {} file {} for build {} into the "
                              "build directory.".format(
                                  subtype, src_path, dest)))
                    extract.decompress_file(src_path, dest, subtype)
            elif category == 'application' and subtype == 'zip':
                self.tracker.update(
                    state=STATES.BUILDING,
                    note=("Extracting zip file {} for build {}.".format(
                        src_path, dest)))
                extract.unzip_file(src_path, dest)

            else:
                # Finally, simply copy any other types of files into the build
                # directory.
                self.tracker.update(
                    state=STATES.BUILDING,
                    note="Copying file {} for build {} into the build "
                    "directory.".format(src_path, dest))

                copy_dest = dest / src_path.name
                try:
                    dest.mkdir()
                    shutil.copy(src_path.as_posix(), copy_dest.as_posix())
                except OSError as err:
                    raise TestBuilderError(
                        "Could not copy test src '{}' to '{}': {}".format(
                            src_path, dest, err))

        # Create build time file(s).
        files_to_create = self._config.get('create_files')
        if files_to_create:
            for file, contents in files_to_create.items():
                file_path = Path(utils.resolve_path(dest / file))
                # Do not allow file to clash with existing directory.
                if file_path.is_dir():
                    raise TestBuilderError(
                        "'create_file: {}' clashes with"
                        " existing directory in test source.".format(
                            str(file_path)))
                dirname = file_path.parent
                (dest / dirname).mkdir(parents=True, exist_ok=True)
                with file_path.open('w') as file_:
                    for line in contents:
                        file_.write("{}\n".format(line))

        # Now we just need to copy over all of the extra files.
        for extra in self._config.get('extra_files', []):
            extra = Path(extra)
            path = self._find_file(extra, 'test_src')
            final_dest = dest / path.name
            try:
                shutil.copy(path.as_posix(), final_dest.as_posix())
            except OSError as err:
                raise TestBuilderError(
                    "Could not copy extra file '{}' to dest '{}': {}".format(
                        path, dest, err))