def verify(self) -> bool: """ This method runs several checks to ensure local copying can proceed. It is automatically executed at package initialisation. This includes: * checks if all expected keys are present in the configuration file Returns: bool: verification success """ logger = KtrLogger(LOG_PREFIX) success = True # check if the configuration file is valid expected_keys = ["keep", "orig"] for key in expected_keys: if key not in self.spkg.conf["local"]: logger.err("The [local] section in the package's .conf file doesn't set the '" + key + "' key.") success = False return success
def verify(self) -> bool: """ This method runs several checks to ensure copr uploads can proceed. It is automatically executed at package initialisation. This includes: * checks if all expected keys are present in the configuration file * checks if the `copr-cli` binary is installed and can be found on the system Returns: bool: verification success """ logger = KtrLogger(LOG_PREFIX) success = True # check if the configuration file is valid expected_keys = ["active", "dists", "keep", "repo", "wait"] for key in expected_keys: if key not in self.upkg.conf["copr"]: logger.err("The [copr] section in the package's .conf file doesn't set the '" + key + "' key.") success = False # check if copr is installed try: subprocess.check_output(["which", "copr-cli"]) except subprocess.CalledProcessError: logger.log("Install copr-cli to use the specified builder.") success = False return success
def ktr_mkdirp(path: str) -> bool: """ This function checks for directory existence and the ability to write to it. If the directory does not exist, it will be created. Arguments: str path: path of directory to check and create Returns: bool: success (or not) """ logger = KtrLogger(LOG_PREFIX) if os.path.exists(path): if os.access(path, os.W_OK): return True else: logger.err(path + " can't be written to.") return False else: logger.log(path + " directory doesn't exist and will be created.") try: os.makedirs(path) except OSError: logger.err(path + " directory could not be created.") return False return True
def verify(self) -> bool: """ This method runs several checks to ensure bzr commands can proceed. It is automatically executed at package initialisation. This includes: * checks if all expected keys are present in the configuration file * checks if the `bzr` binary is installed and can be found on the system Returns: bool: verification success """ logger = KtrLogger(LOG_PREFIX) success = True # check if the configuration file is valid expected_keys = ["branch", "keep", "keep_repo", "orig", "revno"] for key in expected_keys: if key not in self.spkg.conf["bzr"]: logger.err("The [bzr] section in the package's .conf file doesn't set the '" + key + "' key.") success = False # check if bzr is installed try: subprocess.check_output(["which", "bzr"]).decode().rstrip("\n") except subprocess.CalledProcessError: logger.log("Install bzr to use the specified source.") success = False return success
def update(self) -> bool: """ This method executes a git repository update as specified in the package configuration file. If a specific commit has been set in the config file, this method will not attempt to execute an update. Returns: bool: *True* if update available and successful, *False* if not """ ktr = Kentauros() logger = KtrLogger(LOG_PREFIX) # if specific commit is requested, do not pull updates (obviously) if self.get_commit() == "HEAD": return False # check for connectivity to server if not is_connected(self.get_orig()): logger.log("No connection to remote host detected. Cancelling source update.", 2) return False # construct git command cmd = ["git", "pull", "--rebase"] # add --verbose or --quiet depending on settings if (ktr.verby == 2) and not ktr.debug: cmd.append("--quiet") if (ktr.verby == 0) or ktr.debug: cmd.append("--verbose") # check if source directory exists before going there if not os.access(self.dest, os.W_OK): logger.err("Sources need to be get before an update can be run.") return False # get old commit ID rev_old = self.commit() # change to git repository directory prev_dir = os.getcwd() os.chdir(self.dest) # get updates logger.log_command(cmd, 1) subprocess.call(cmd) # go back to previous dir os.chdir(prev_dir) # get new commit ID rev_new = self.commit() self.date() # return True if update found, False if not return rev_new != rev_old
def clean(self) -> bool: if not os.path.exists(self.pdir): return True logger = KtrLogger(LOG_PREFIX) try: assert Kentauros().conf.get_packdir() in self.pdir assert os.path.isabs(self.pdir) shutil.rmtree(self.pdir) return True except AssertionError: logger.err("The Package exports directory looks weird. Doing nothing.") return False except OSError: logger.err("The Package exports directory couldn't be removed.") return False
def export(self) -> bool: """ This method copies the build results (if any) from the mock result directory to the directory specified for binary package exports. Returns: bool: *True* if successful, *False* if not """ if not self.get_active(): return True if not self.get_export(): return True logger = KtrLogger(LOG_PREFIX) os.makedirs(self.edir, exist_ok=True) if not os.path.exists(self.edir): logger.err("Package exports directory could not be created.") return False if not os.access(self.edir, os.W_OK): logger.err("Package exports directory can not be written to.") return False mock_result_dirs = list() for dist in self.get_dists(): path = get_dist_result_path(dist) if os.path.exists(path): mock_result_dirs.append(path) else: corrected_path = get_dist_result_path(get_dist_from_mock_config(dist)) mock_result_dirs.append(corrected_path) file_results = list() for result_dir in mock_result_dirs: file_results += glob.glob(os.path.join(result_dir, "*.rpm")) for file in file_results: shutil.copy2(file, self.edir) return True
def __init__(self, conf_name: str): assert isinstance(conf_name, str) ktr = Kentauros() logger = KtrLogger(LOG_PREFIX) self.file = os.path.join(ktr.conf.get_confdir(), conf_name + ".conf") self.conf = ConfigParser() self.conf_name = conf_name if not os.path.exists(self.file): raise FileNotFoundError("Package configuration file does not exist.") success = self.conf.read(self.file) if not success: logger.err("Package configuration could not be read.") logger.err("Path: " + self.file) raise PackageError("Package configuration could not be read.") if not self.verify(): raise PackageError("Package configuration file is invalid.") self.name = self.conf.get("package", "name") modules_str = str(self.conf.get("package", "modules")) module_type_list = modules_str.split(",") if module_type_list == [""]: module_type_list = [] self.modules = OrderedDict() for module_type in module_type_list: module_type_enum = PkgModuleType[module_type.upper()] module_implement = str(self.conf.get("modules", module_type)).upper() module = PKG_MODULE_DICT[module_type_enum][ PKG_MODULE_TYPE_DICT[module_type_enum][module_implement]](self) self.modules[module_type] = module for module in self.modules.values(): assert isinstance(module, PkgModule) module.verify()
def verify(self) -> bool: """ This method runs several checks to ensure git commands can proceed. It is automatically executed at package initialisation. This includes: * checks if all expected keys are present in the configuration file * checks that the configuration file is consistent (i.e. shallow clone and commit checkout are not compatible) * checks if the `git` binary is installed and can be found on the system Returns: bool: verification success """ logger = KtrLogger(LOG_PREFIX) success = True # check if the configuration file is valid expected_keys = ["branch", "commit", "keep", "keep_repo", "orig", "shallow"] for key in expected_keys: if key not in self.spkg.conf["git"]: logger.err("The [git] section in the package's .conf file doesn't set the '" + key + "' key.") success = False # shallow clones and checking out a specific commit is not supported if (self.get_commit() != "HEAD") and self.get_shallow(): logger.err("Shallow clones are not compatible with specifying a specific commit.") success = False # check if git is installed try: subprocess.check_output(["which", "git"]).decode().rstrip("\n") except subprocess.CalledProcessError: logger.log("Install git to use the specified source.") success = False return success
def verify(self) -> bool: """ This method runs several checks to ensure mock builds can proceed. It is automatically executed at package initialisation. This includes: * checks if all expected keys are present in the configuration file * checks if the `mock` binary is installed and can be found on the system * checks if the current user is allowed to run builds with mock * checks if the current user is root (building as root is strongly discouraged) Returns: bool: verification success """ logger = KtrLogger(LOG_PREFIX) success = True # check if the configuration file is valid expected_keys = ["active", "dists", "export", "keep"] for key in expected_keys: if key not in self.bpkg.conf["mock"]: logger.err("The [mock] section in the package's .conf file doesn't set the '" + key + "' key.") success = False # check if mock is installed try: subprocess.check_output(["which", "mock"]).decode().rstrip("\n") except subprocess.CalledProcessError: logger.log("Install mock to use the specified builder.") success = False # check if the user is in the "mock" group or is root mock_group = grp.getgrnam("mock") mock_user = os.getenv("USER") if mock_user not in mock_group.gr_mem: logger.err("The current user is not allowed to use mock.") logger.err("Add yourself to the 'mock' group, log out and back in.") success = False if mock_user == "root": logger.err("Don't attempt to run mock as root.") success = False return success
def execute(self) -> bool: """ This method runs the "chain reaction" corresponding to the package specified at initialisation, with the configuration from the package configuration file. Returns: bool: ``True`` if chain went all the way through, ``False`` if not """ ktr = Kentauros() logger = KtrLogger(LOGPREFIX) force = ktr.cli.get_force() success = True for module in self.kpkg.get_modules(): succeeded = module.execute() if not succeeded: logger.err("Execution of module '" + str(module) + "' wasn't successful.") if force: logger.log("Execution is forced to continue.") success = success and succeeded continue else: success = False break self.update_status() if success: logger.log(self.kpkg.get_conf_name() + ": Success!") else: logger.log(self.kpkg.get_conf_name() + ": Not successful.") return success
def verify(self) -> bool: """ This method runs several checks to ensure srpm builds can proceed. It is automatically executed at package initialisation. This includes: * checks if all expected keys are present in the configuration file * checks if the `mock` binary is installed and can be found on the system * checks if the current user is allowed to run builds with mock * checks if the current user is root (building as root is strongly discouraged) * checks if the .spec file is present at the expected location Returns: bool: verification success """ logger = KtrLogger(LOG_PREFIX) success = True # check if the configuration file is valid expected_keys = [] for key in expected_keys: if key not in self.cpkg.conf["srpm"]: logger.err("The [srpm] section in the package's .conf file doesn't set the '" + key + "' key.") success = False # check for .spec file presence if not os.path.exists(self.path): logger.err("Spec file has not been found at the expected location:") logger.err(self.path) success = False # check if rpmbuild and rpmdev-bumpspec are installed try: subprocess.check_output(["which", "rpmbuild"]).decode().rstrip("\n") except subprocess.CalledProcessError: logger.log("Install rpm-build to use the srpm constructor.") success = False try: subprocess.check_output(["which", "rpmdev-bumpspec"]).decode().rstrip("\n") except subprocess.CalledProcessError: logger.log("Install rpmdevtools to use the srpm constructor.") success = False return success
def prepare(self) -> bool: """ This method prepares all files necessary for source package assembly. This includes - copying every file (not directories) from package source directory to `rpmbuild/SOURCES`, - removing the latest tarball from the package source directory if it should not be kept, - copying the package configuration file to `rpmbuild/SOURCES` - preparing the `package.spec` file in `rpmbuild/SPECS` from the file in the spec directory, - defining macros for git and bzr version string additions, - setting `Version:` and `Release:` tags according to configuration, - appending a changelog entry automatically for every different build, - copying back the modified spec file to preserve added changelog entries. Returns: bool: returns `True` if the preparation was successful. """ ktr = Kentauros() logger = KtrLogger(LOG_PREFIX) spec = RPMSpec(self.path, self.cpkg.get_module("source")) if not os.path.exists(self.rpmbdir): warnings.warn("Make sure to call Constructor.init() before .prepare()!", Warning) self.init() # copy sources to rpmbuild/SOURCES for entry in os.listdir(self.cpkg.get_module("source").sdir): entry_path = os.path.join(self.cpkg.get_module("source").sdir, entry) if os.path.isfile(entry_path): shutil.copy2(entry_path, self.srcsdir) logger.log("File copied to SOURCES: " + entry_path, 1) # remove tarballs if they should not be kept if not self.cpkg.get_module("source").get_keep(): # if source is a tarball (or similar) from the beginning: if os.path.isfile(self.cpkg.get_module("source").dest): os.remove(self.cpkg.get_module("source").dest) # otherwise it is in kentauros' standard .tar.gz format: else: tarballs = glob.glob(os.path.join(self.cpkg.get_module("source").sdir, self.cpkg.get_name()) + "*.tar.gz") # remove only the newest one to be safe tarballs.sort(reverse=True) if os.path.isfile(tarballs[0]): assert self.cpkg.get_module("source").sdir in tarballs[0] os.remove(tarballs[0]) logger.log("Tarball removed: " + tarballs[0], 1) # copy package.conf to rpmbuild/SOURCES shutil.copy2(self.cpkg.file, self.srcsdir) logger.log("Package configuration copied to SOURCES: " + self.cpkg.file, 1) # construct preamble and new version string old_version = self._get_last_version(spec) old_release = self._get_last_release(spec) new_version = self.cpkg.get_version() # TODO: check if release resetting / incrementing logic works now spec.set_version() spec.set_source() # if old version and new version are different, force release reset to 0 rel_reset = (new_version != old_version) # start constructing release string from old release string if rel_reset: spec.do_release_reset() # write preamble to new spec file preamble = spec.build_preamble_string() # calculate absolute path of new spec file and copy it over new_spec_path = os.path.join(self.specdir, self.cpkg.get_name() + ".spec") spec.export_to_file(new_spec_path) # use "rpmdev-bumpspec" to increment release number and create changelog entries force = ktr.cli.get_force() logger.dbg("Old Version: " + old_version) logger.dbg("New Version: " + new_version) logger.dbg("Old Release: " + old_release) # if major version has changed, put it into the changelog if (old_version != new_version) or (old_release[0] == "0"): do_release_bump(new_spec_path, "Update to version " + self.cpkg.get_version() + ".") new_rpm_spec = RPMSpec(new_spec_path, self.cpkg.get_module("source")) # else if nothing changed but "force" was set (packaging changes) # old_version =!= new_version, rel_reset !=!= True elif force: message = ktr.cli.get_message() if message is None: do_release_bump(new_spec_path, "Update for packaging changes.") else: do_release_bump(new_spec_path, message) new_rpm_spec = RPMSpec(new_spec_path, self.cpkg.get_module("source")) # else if version has not changed, but snapshot has been updated: # old_version =!= new_version elif rel_reset: new_rpm_spec = RPMSpec(new_spec_path, self.cpkg.get_module("source")) new_rpm_spec.do_release_reset() do_release_bump(new_spec_path, "Update to latest snapshot.") new_rpm_spec = RPMSpec(new_spec_path, self.cpkg.get_module("source")) else: logger.err("Something went wrong.") return False self.last_release = new_rpm_spec.get_release() self.last_version = new_rpm_spec.get_version() # copy new spec file back to ktr/specdir to preserve version tracking, # release number and changelog consistency (keep old version once as backup) # BUT: remove preamble again, it would break things otherwise new_rpm_spec.contents = new_rpm_spec.contents.replace(preamble, "") shutil.copy2(self.path, self.path + ".old") new_rpm_spec.export_to_file(self.path) return True
def get(self) -> bool: """ This method executes the git repository download to the package source directory. This respects the branch and commit set in the package configuration file. Returns: bool: *True* if successful, *False* if not or source pre-exists """ ktr = Kentauros() logger = KtrLogger(LOG_PREFIX) # check if $KTR_BASE_DIR/sources/$PACKAGE exists and create if not if not os.access(self.sdir, os.W_OK): os.makedirs(self.sdir) # if source directory seems to already exist, return False if os.access(self.dest, os.R_OK): rev = self.commit() logger.log("Sources already downloaded. Latest commit id:", 2) logger.log(rev, 2) return False # check for connectivity to server if not is_connected(self.get_orig()): logger.log("No connection to remote host detected. Cancelling source checkout.", 2) return False # construct clone command cmd_clone = ["git", "clone"] # add --verbose or --quiet depending on settings if (ktr.verby == 2) and not ktr.debug: cmd_clone.append("--quiet") if (ktr.verby == 0) or ktr.debug: cmd_clone.append("--verbose") # set --depth==1 if shallow is specified if self.get_shallow(): cmd_clone.append("--depth=1") # set branch if specified if self.get_branch(): cmd_clone.append("--branch") cmd_clone.append(self.get_branch()) # set origin and destination cmd_clone.append(self.get_orig()) cmd_clone.append(self.dest) # clone git repo from origin to destination logger.log_command(cmd_clone, 1) subprocess.call(cmd_clone) # if commit is specified: checkout commit if self.get_commit(): # construct checkout command cmd_checkout = ["git", "checkout", self.get_commit()] # go to git repo and remember old cwd prev_dir = os.getcwd() os.chdir(self.dest) # checkout commit logger.log_command(cmd_checkout, 1) subprocess.call(cmd_checkout) # go to previous dir os.chdir(prev_dir) # get commit ID rev = self.commit() self.date() # check if checkout worked if self.get_commit() != "HEAD": if self.get_commit() != rev: logger.err("Something went wrong, requested commit not checked out.") return False # return True if successful return True
def verify(self) -> bool: """ This method verifies that the absolute minimum for proceeding with package initialisation is set. This also ensures the validity of some entries. Returns: bool: *True* if configuration is minimally valid, *False* if entries are missing """ assert isinstance(self.conf, ConfigParser) logger = KtrLogger(LOG_PREFIX) success = True # [package] if "package" not in self.conf.sections(): logger.err("Package configuration file does not have a 'package' section.") success = False # name = if "name" not in self.conf["package"]: logger.err("Package configuration file doesn't set 'name' in the 'package' section.") success = False if self.conf.get("package", "name") == "": logger.err("Package configuration file doesn't set 'name' in the 'package' section.") success = False # version = if "version" not in self.conf["package"]: logger.err("Package configuration file doesn't set 'version' in the 'package' section.") success = False if "-" in self.conf.get("package", "version"): logger.err("Hyphens are not a valid part of a version string.") logger.err("Replace it with another character, e.g. '~' or '+'.") success = False # modules = if self.conf.get("package", "modules") == "": logger.err("Package configuration file doesn't set 'modules' in the 'package' section.") success = False # [modules] if "modules" not in self.conf.sections(): logger.err("Package configuration file does not have a 'modules' section.") success = False modules_str = str(self.conf.get("package", "modules")) module_list = modules_str.split(",") if module_list == [""]: module_list = [] # check if the module is recognised for module in module_list: try: PkgModuleType[module.upper()] except KeyError: raise PackageError("Module '" + module + "' is not one of the recognised modules.") # check if modules are defined in the [modules] section for module in module_list: if module not in self.conf["modules"]: logger.err("Package configuration file doesn't define module '" + module + "' in the 'modules' section.") success = False # check if each module has its configuration section for module in module_list: if self.conf.get("modules", module) not in self.conf.sections(): logger.err("Package configuration file doesn't have a section for module '" + module + "'.") success = False return success
def export(self) -> bool: """ This method executes the export from the package source repository to a tarball with pretty file name. It also respects the `git.keep=False` setting in the package configuration file - the git repository will be deleted from disk after the export if this flag is set. Returns: bool: *True* if successful or already done, *False* at failure """ ktr = Kentauros() logger = KtrLogger(LOG_PREFIX) def remove_not_keep(): """ This local function removes the git repository and is called after source export, if not keeping the repository around was specified in the configuration file. """ if not self.get_keep(): # try to be careful with "rm -r" assert os.path.isabs(self.dest) assert ktr.conf.get_datadir() in self.dest shutil.rmtree(self.dest) logger.log("git repository has been deleted after exporting to tarball.", 1) # construct git command to export HEAD or specified commit cmd = ["git", "archive", self.get_commit()] # check if git repo exists if not os.access(self.dest, os.R_OK): logger.err("Sources need to be get before they can be exported.") return False version = self.formatver() name_version = self.spkg.get_name() + "-" + version # add prefix cmd.append("--prefix=" + name_version + "/") file_name = os.path.join(self.sdir, name_version + ".tar.gz") cmd.append("--output") cmd.append(file_name) # check if file has already been exported if os.path.exists(file_name): logger.log("Tarball has already been exported.", 1) # remove git repo if keep is False remove_not_keep() return True # remember previous directory prev_dir = os.getcwd() # change to git repository directory os.chdir(self.dest) # export tar.gz to $KTR_DATA_DIR/$PACKAGE/*.tar.gz logger.log_command(cmd, 1) subprocess.call(cmd) # update saved rev and date self.commit() self.date() # remove git repo if keep is False remove_not_keep() os.chdir(prev_dir) return True
def export(self) -> bool: """ This method executes the export from the package source repository to a tarball with pretty file name. It also respects the `bzr.keep=False` setting in the package configuration file - the bzr repository will be deleted from disk after the export if this flag is set. Returns: bool: `True` if successful, `False` if not or already exported """ ktr = Kentauros() logger = KtrLogger(LOG_PREFIX) def remove_not_keep(): """ This local function removes the bzr repository and is called after source export, if not keeping the repository around was specified in the configuration file. """ if not self.get_keep_repo(): # try to be careful with "rm -r" assert os.path.isabs(self.dest) assert ktr.conf.get_datadir() in self.dest shutil.rmtree(self.dest) logger.log("bzr repository deleted after export to tarball", 1) # construct bzr command cmd = ["bzr", "export"] # add --verbose or --quiet depending on settings if (ktr.verby == 2) and not ktr.debug: cmd.append("--quiet") if (ktr.verby == 0) or ktr.debug: cmd.append("--verbose") # export HEAD or specified commit if self.get_revno(): cmd.append("--revision") cmd.append(self.get_revno()) # check if bzr repo exists if not os.access(self.dest, os.R_OK): logger.err("Sources need to be get before they can be exported.") return False version = self.formatver() name_version = self.spkg.get_name() + "-" + version file_name = os.path.join(self.sdir, name_version + ".tar.gz") cmd.append(file_name) # check if file has already been exported if os.path.exists(file_name): logger.log("Tarball has already been exported.", 1) # remove bzr repo if keep is False remove_not_keep() return False # remember previous directory prev_dir = os.getcwd() # change to git repository directory os.chdir(self.dest) # export tar.gz to $KTR_DATA_DIR/$PACKAGE/*.tar.gz logger.log_command(cmd, 1) subprocess.call(cmd) # update saved rev self.rev() # remove bzr repo if keep is False remove_not_keep() os.chdir(prev_dir) return True
def get(self) -> bool: """ This method executes the bzr repository download to the package source directory. This respects the branch and revision set in the package configuration file. Returns: bool: `True` if successful, `False` if not or source already exists """ ktr = Kentauros() logger = KtrLogger(LOG_PREFIX) # check if $KTR_BASE_DIR/sources/$PACKAGE exists and create if not if not os.access(self.sdir, os.W_OK): os.makedirs(self.sdir) # if source directory seems to already exist, return False if os.access(self.dest, os.R_OK): rev = self.rev() logger.log("Sources already downloaded. Latest revision: " + str(rev), 1) return False # check for connectivity to server if not is_connected(self.remote): logger.log("No connection to remote host detected. Cancelling source checkout.", 2) return False # construct bzr command cmd = ["bzr", "branch"] # add --verbose or --quiet depending on settings if (ktr.verby == 2) and not ktr.debug: cmd.append("--quiet") if (ktr.verby == 0) or ktr.debug: cmd.append("--verbose") # set origin if not self.get_branch(): cmd.append(self.get_orig()) else: cmd.append(self.get_orig() + "/" + self.get_branch()) # set revision is specified if self.get_revno(): cmd.append("--revision") cmd.append(self.get_revno()) # set destination cmd.append(self.dest) # branch bzr repo from origin to destination logger.log_command(cmd, 1) subprocess.call(cmd) # get commit ID rev = self.rev() # check if checkout worked if self.get_revno(): if self.get_revno() != rev: logger.err("Something went wrong, requested commit not available.") return False # return True if successful return True
def run(): """ This function is corresponding to (one of) the "main" function of the `kentauros` package and is the entry point used by the `ktr.py` script from git and the script installed at installation. """ ktr = Kentauros() logger = KtrLogger(LOG_PREFIX) print_parameters() # if no action is specified: exit if ktr.cli.get_action() is None: logger.log("No action specified. Exiting.") logger.log("Use 'ktr --help' for more information.") print_flush() return if not ktr_bootstrap(): raise SystemExit() packages = list() # if only specified packages are to be processed: process packages from CLI only if not ktr.cli.get_packages_all(): packages = ktr.cli.get_packages().copy() for pkg in packages: pkg_conf_path = os.path.join(ktr.conf.get_confdir(), pkg + ".conf") if not os.path.exists(pkg_conf_path): logger.err("Package configuration for '" + pkg + "' could not be found.") packages.remove(pkg) # if all package are to be processed: get package configs present in the package configuration # directory else: pkg_conf_paths = glob.glob(os.path.join(ktr.conf.get_confdir(), "*.conf")) for pkg_conf_path in pkg_conf_paths: packages.append(os.path.basename(pkg_conf_path).replace(".conf", "")) if not packages: logger.log("No packages have been specified or found. Exiting.") print_flush() raise SystemExit() packages.sort() # log list of found packages logger.log_list("Packages", packages) print_flush() # generate package objects for name in packages: assert isinstance(name, str) try: pkg = Package(name) ktr.add_package(name, pkg) except PackageError: logger.log("Package with configuration file '" + name + "' is invalid, skipping.") continue actions_success = list() actions_failure = list() # run action for every specified package for name in ktr.get_package_names(): assert isinstance(name, str) if ktr.state_read(name) is None: logger.log("Importing new package into the database.") import_action = ImportAction(name) import_action.execute() action_type = ktr.cli.get_action() action = ACTION_DICT[action_type](name) success = action.execute() if success: actions_success.append(name) else: actions_failure.append(name) print_flush() if actions_success: logger.log_list("Successful actions", actions_success) if actions_failure: logger.log_list("Failed actions", actions_failure) print_flush() raise SystemExit()