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 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 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 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 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(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 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 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 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 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 date(self) -> str: """ This method provides an easy way of getting the date and time of the requested commit in a standardised format (``YYMMDD.HHmmSS``). It also stores the latest parsed date between method invocations, if the source goes away and the commit datetime string is needed again. Returns: str: commit date.time string (``YYMMDD.HHmmSS``) """ def prepend_zero(string): """ This local function prepends '0' to one-digit time value strings. """ if len(string) == 1: return "0" + string else: return string def date_str_from_raw(raw_date: str): """ This local function parses a datetime object and returns a simple string. """ assert isinstance(raw_date, str) date_obj = dateutil.parser.parse(raw_date) year_str = str(date_obj.year)[2:] month_str = prepend_zero(str(date_obj.month)) day_str = prepend_zero(str(date_obj.day)) hour_str = prepend_zero(str(date_obj.hour)) minute_str = prepend_zero(str(date_obj.minute)) second_str = prepend_zero(str(date_obj.second)) date_str = year_str + month_str + day_str + "." + hour_str + minute_str + second_str return date_str # ktr = Kentauros() 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_date is None: logger.dbg("Sources need to be get before their age can be read.") return None else: return self.saved_date cmd = ["git", "show", "-s", "--date=short", "--format=%cI"] prev_dir = os.getcwd() os.chdir(self.dest) logger.log_command(cmd, 1) date_raw = subprocess.check_output(cmd).decode().rstrip('\r\n') os.chdir(prev_dir) date = date_str_from_raw(date_raw) self.saved_date = date # ktr.state_write(self.spkg.get_conf_name(), dict(git_last_date=date)) return date