def commit(self) -> str: """ This method provides an easy way of getting the commit hash of the requested commit. It also stores the latest commit hash between method invocations, if the source goes away and the hash is needed again. Returns: str: commit hash """ logger = KtrLogger(LOG_PREFIX) # if sources are not accessible (anymore), return None or last saved rev if not os.access(self.dest, os.R_OK): if self.saved_commit is None: logger.dbg("Sources need to be get before commit hash can be read.") return None else: return self.saved_commit cmd = ["git", "rev-parse", "HEAD"] prev_dir = os.getcwd() os.chdir(self.dest) logger.log_command(cmd, 1) rev = subprocess.check_output(cmd).decode().rstrip("\n") os.chdir(prev_dir) self.saved_commit = rev return rev
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 do_release_bump(path: str, comment: str=None): """ This function calls `rpmdev-bumpspec` with the specified arguments to bump the release number and create a changelog entry with a given comment. Arguments: str comment: comment to be added to the changelog entry """ ktr = Kentauros() logger = KtrLogger(LOG_PREFIX) if not os.path.exists(path): raise FileNotFoundError() if comment is None: comment = "Automatic build by kentauros." # construct rpmdev-bumpspec command cmd = ["rpmdev-bumpspec"] # add --verbose or --quiet depending on settings if (ktr.verby == 0) or ktr.debug: cmd.append("--verbose") cmd.append(path) cmd.append('--comment="' + comment + '"') logger.log_command(cmd) subprocess.call(cmd)
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 build(self): """ This method executes the actual SRPM package assembly. It sets `$HOME` to the created temporary directory and executes `rpmbuild -bs` with the copy of the package spec file in `rpmbuild/SPECS`. After that, `$HOME` is reset to the old value. """ ktr = Kentauros() logger = KtrLogger(LOG_PREFIX) old_home = os.environ['HOME'] os.environ['HOME'] = self.tempdir # construct rpmbuild command cmd = ["rpmbuild"] # 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") cmd.append("-bs") cmd.append(os.path.join(self.specdir, self.cpkg.get_name() + ".spec")) logger.log_command(cmd) try: subprocess.call(cmd) finally: os.environ['HOME'] = old_home
def get(self) -> bool: """ This method attempts to copy the specified source from the location specified in the package configuration file to the determined destination. If the destination file already exists, nothing will be done. Returns: bool: *True* if source was copied successfully, *False* if not """ 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 seems to already exist, return False if os.access(self.dest, os.R_OK): logger.log("Sources already present.", 1) return False # copy file from origin to destination shutil.copy2(self.get_orig(), self.dest) return True
def rev(self) -> str: """ This method determines which revision the bzr repository associated with this :py:class:`BzrSource` currently is at and returns it as a string. Once run, it saves the last processed revision number in `self.saved_rev`, in case the revision needs to be determined when bzr repository might not be accessible anymore (e.g. if `bzr.keep=False` is set in configuration, so the repository is not kept after export to tarball). Returns: str: either revision string from repo, last stored rev string or `""` when unsuccessful """ # ktr = Kentauros() logger = KtrLogger(LOG_PREFIX) # if sources are not accessible (anymore), return "" or last saved rev if not os.access(self.dest, os.R_OK): if self.saved_rev is None: logger.dbg("Sources need to be get before rev can be determined.") return "" else: return self.saved_rev cmd = ["bzr", "revno"] prev_dir = os.getcwd() os.chdir(self.dest) logger.log_command(cmd, 0) rev = subprocess.check_output(cmd).decode().rstrip("\n") os.chdir(prev_dir) self.saved_rev = rev return rev
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 _get_last_release(self, spec: RPMSpec): """ This method tries to read the latest state from the state database - if that is not available, the .spec file is parsed as a fallback. Arguments: RPMSpec spec: rpm spec object Returns: str: last known release """ assert isinstance(spec, RPMSpec) ktr = Kentauros() logger = KtrLogger(LOG_PREFIX) saved_state = ktr.state_read(self.cpkg.get_conf_name()) if saved_state is None: logger.dbg("Package " + self.cpkg.get_conf_name() + " not yet in state database.") logger.dbg("Falling back to legacy release detection.") old_release = spec.get_release() elif "rpm_last_release" not in saved_state: logger.dbg("Package " + self.cpkg.get_conf_name() + " has no release set in state database.") logger.dbg("Falling back to legacy release detection.") old_release = spec.get_release() else: old_release = saved_state["rpm_last_release"] return old_release
def execute(self) -> bool: logger = KtrLogger(LOG_PREFIX) success = self.build() if not success: logger.log("Binary package building unsuccessful, aborting action.") return False success = self.export() if not success: logger.log("Binary package exporting unsuccessful, aborting action.") return False return success
def export(self): """ This method copies the assembled source packages from `rpmbuild/SRPMS` to the directory for built packages as specified in the kentauros configuration. If multiple SRPM packages are found, they all are copied. """ logger = KtrLogger(LOG_PREFIX) srpms = glob.glob(os.path.join(self.srpmdir, "*.src.rpm")) os.makedirs(self.pdir, exist_ok=True) for srpm in srpms: shutil.copy2(srpm, self.pdir) logger.log("File copied: " + srpm, 0)
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 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 execute(self) -> bool: """ This method executes the :py:meth:`Source.prepare()` method to execute source preparation. This includes downloading or copying to destination, updating if necessary, and exporting to tarball if necessary. Returns: bool: *True* when successful, *False* if sub-action fails """ logger = KtrLogger(LOGPREFIX) source = self.kpkg.get_module("source") if source is None: logger.log("This package doesn't define a source module. Aborting.") return True success = source.execute() 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 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 init(self): """ This method creates a temporary directory (which is then set to `$HOME` in the :py:meth:`SrpmConstructor.build()` method) and other necessary sub-directories (here: `SOURCES`, `SRPMS`, `SPECS`). """ logger = KtrLogger(LOG_PREFIX) # make sure to finally call self.clean()! self.tempdir = tempfile.mkdtemp() logger.log("Temporary directory " + self.tempdir + " created.", 1) self.rpmbdir = os.path.join(self.tempdir, "rpmbuild") self.specdir = os.path.join(self.tempdir, "rpmbuild", "SPECS") self.srpmdir = os.path.join(self.tempdir, "rpmbuild", "SRPMS") self.srcsdir = os.path.join(self.tempdir, "rpmbuild", "SOURCES") # create $TEMPDIR/rpmbuild if not os.path.exists(self.rpmbdir): os.mkdir(self.rpmbdir) logger.log("Temporary rpmbuild directory created: " + self.tempdir, 1) # create $TEMPDIR/rpmbuild/{SPECS,SRPMS,SOURCES} for directory in [self.specdir, self.srpmdir, self.srcsdir]: if not os.path.exists(directory): os.mkdir(directory) logger.log("Temporary 'SOURCES', 'SPECS', 'SRPMS' directories created.", 1)
def execute(self) -> bool: """ This method executes the :py:meth:`Uploader.upload()` method to execute the source upload, if possible - this only has effect for packages with a valid uploader specified in the package configuration file. Returns: bool: always *True*, future error checking still missing """ logger = KtrLogger(LOGPREFIX) uploader = self.kpkg.get_module("uploader") if uploader is None: logger.log("This package doesn't define an uploader module. Aborting.") return True success = uploader.execute() 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 execute(self) -> bool: """ This method cleans up the sources of to the package specified at initialisation. It executes the :py:meth:`Source.clean()` method of the :py:class:`Source` instance in the specified package. Returns: bool: always ``True`` at the moment """ logger = KtrLogger(LOGPREFIX) success = True for module in self.kpkg.get_modules(): cleanup = module.clean() if not cleanup: logger.log("Module '" + str(module) + "' did not clean up successfully.") success = success and cleanup if success: logger.log(self.kpkg.get_conf_name() + ": Success!") else: logger.log(self.kpkg.get_conf_name() + ": Not successful.") return success
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 upload(self) -> bool: """ This method executes the upload of the newest SRPM package found in the package directory. The invocation of `copr-cli` also includes the chroot settings set in the package configuration file. Returns: bool: returns *False* if anything goes wrong, *True* otherwise """ ktr = Kentauros() logger = KtrLogger(LOG_PREFIX) package_dir = os.path.join(ktr.conf.get_packdir(), self.upkg.get_conf_name()) # get all srpms in the package directory srpms = glob.glob(os.path.join(package_dir, self.upkg.get_name() + "*.src.rpm")) if not srpms: logger.log("No source packages were found. Construct them first.") return False # figure out which srpm to build srpms.sort(reverse=True) srpm = srpms[0] # construct copr-cli command cmd = ["copr-cli", "build", self.get_repo()] # append chroots (dists) for dist in self.get_dists(): cmd.append("--chroot") cmd.append(dist) # append --nowait if wait=False if not self.get_wait(): cmd.append("--nowait") # append package cmd.append(srpm) # check for connectivity to server if not is_connected(self.remote): logger.log("No connection to remote host detected. Cancelling upload.", 2) return False logger.log_command(cmd, 1) subprocess.call(cmd) # TODO: error handling # remove source package if keep=False is specified if not self.get_keep(): os.remove(srpm) return True
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 get_mock_cmd() -> str: """ This function tries to determine the correct mock binary path. If something is messing with the `$PATH` environment variable, it will try to account for that. If mock is not installed (or cannot be found within `$PATH`, this function will raise an Exception. Raises: subprocess.CalledProcessError Returns: str: path to the mock binary """ logger = KtrLogger(LOG_PREFIX) mock_cmd = subprocess.check_output(["which", "mock"]).decode().rstrip("\n") # check if the right binary is used or if something is messing up $PATH if mock_cmd == "/usr/sbin/mock": logger.log("Something is messing with your $PATH variable.", 2) mock_cmd = "/usr/bin/mock" return mock_cmd
def clean(self) -> bool: """ This method cleans up all of a package's sources - excluding other files in the packages's source directory, which may include patches or other, additional files - they are preserved. Returns: bool: *True* if successful """ ktr = Kentauros() logger = KtrLogger(LOG_PREFIX) if not os.path.exists(self.sdir): logger.log("Nothing here to be cleaned.", 0) return True # try to be careful with "rm -r" assert os.path.isabs(self.dest) assert ktr.conf.get_datadir() in self.dest # remove source destination first # if destination is a file (tarball): if os.path.isfile(self.dest): os.remove(self.dest) # if destination is a directory (VCS repo): elif os.path.isdir(self.dest): shutil.rmtree(self.dest) # if source directory is empty now (no patches, additional files, etc. left): # remove whole directory if not os.listdir(self.sdir): os.rmdir(self.sdir) return True
def build(self): """ This method starts the mock build (and waits for already running builds with the same chroot to finish before that). Returns: int: return code of the subprocess call """ logger = KtrLogger(LOG_PREFIX) dist_path = os.path.join("/var/lib/mock/", self.dist) lock_path = os.path.join(dist_path, "buildroot.lock") # wait 2 minutes for builds occupying the specified build chroot if os.path.isdir(dist_path): build_wait = True while build_wait: lock_file = open(lock_path, "a+") try: fcntl.lockf(lock_file.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB) except IOError: logger.log("The specified build chroot is busy, waiting.", 2) time.sleep(120) else: build_wait = False finally: lock_file.close() cmd = self.get_command() logger.log_command(cmd) ret = subprocess.call(cmd) return ret
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 get(self) -> bool: """ This method executes the download of the file specified by the URL to the package source directory. 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 seems to already exist, return False if os.access(self.dest, os.R_OK): logger.log("Sources already downloaded.", 1) return False # check for connectivity to server if not is_connected(self.get_orig()): logger.log("No connection to remote host detected. Cancelling source download.", 2) return False # construct wget commands cmd = ["wget"] # 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 and destination cmd.append(self.get_orig()) cmd.append("-O") cmd.append(self.dest) # wget source from origin to destination logger.log_command(cmd, 1) subprocess.call(cmd) return True
def execute(self) -> bool: logger = KtrLogger(LOGPREFIX) constructor = self.kpkg.get_module("constructor") if constructor is None: logger.log("This package doesn't define a constructor module. Aborting.") return True success = constructor.execute() 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 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 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