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))
def finalize(self, var_man): """Resolve any remaining deferred variables, and generate the final run script.""" self.var_man.undefer(new_vars=var_man) self.config = resolver.TestConfigResolver.resolve_deferred( self.config, self.var_man) self._save_config() # Save our newly updated variables. self.var_man.save(self._variables_path) # Create files specified via run config key. files_to_create = self.config['run'].get('create_files', []) if files_to_create: for file, contents in files_to_create.items(): file_path = Path(self.build_path / file) # Prevent files from being written outside build directory. if not utils.dir_contains(file_path, self.build_path): raise TestRunError( "'create_file: {}': file path" " outside build context.".format(file_path)) # Prevent files from overwriting existing directories. if file_path.is_dir(): raise TestRunError( "'create_file: {}' clashes with" " existing directory in build dir.".format(file_path)) # Create file parent directory(ies). dirname = file_path.parent (self.build_path / dirname).mkdir(parents=True, exist_ok=True) # Don't try to overwrite a symlink without removing it first. if file_path.is_symlink(): file_path.unlink() # Write file. with PermissionsManager(file_path, self.group, self.umask), \ file_path.open('w') as file_: for line in contents: file_.write("{}\n".format(line)) if not self.skipped: self.skipped = self._get_skipped() self.save_attributes() self._write_script( 'run', self.run_script_path, self.config['run'], )