def check(self, is_dirty=True, all_pushed=True): """Check various status of current repository :param bool is_dirty: Default to True. To check whether there is uncommitted changes. :param bool all_pushed: Default to True. To check whether all changes are pushed. :raises rpkgError: if any unexpected status is detected. For example, if changes are not committed yet. NOTE: has_namespace is removed because it should belong to package metadata and be handled there using package repository information provided by this module. """ if is_dirty: if self.repo.is_dirty(): raise rpkgError('%s has uncommitted changes. Use git status ' 'to see details' % self.path) get_config = self.git.get_config if all_pushed: branch = self.repo.active_branch try: remote = get_config('branch.%s.remote' % branch) merge = get_config('branch.%s.merge' % branch).replace( 'refs/heads', remote) except git.GitCommandError: raise rpkgError( 'Branch {0} does not track remote branch.\n' 'Use the following command to fix that:\n' ' git branch -u origin/REMOTE_BRANCH_NAME'.format( branch)) if self.git.rev_list('%s...%s' % (merge, branch)): raise rpkgError('There are unpushed changes in your repo')
def load_nameverrel(self): """Set the release of a package module.""" cmd = ['rpm'] cmd.extend(self.rpmdefines) # We make sure there is a space at the end of our query so that # we can split it later. When there are subpackages, we get a # listing for each subpackage. We only care about the first. cmd.extend([ '-q', '--qf', '"%{NAME} %{EPOCH} %{VERSION} %{RELEASE}??"', '--specfile', '"%s/%s"' % (self.module_build_dir, self.spec) ]) joined_cmd = ' '.join(cmd) try: proc = subprocess.Popen(joined_cmd, shell=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output, err = proc.communicate() except Exception as e: if err: self.log.debug( 'Errors occoured while running following command to get N-V-R-E:' ) self.log.debug(joined_cmd) self.log.error(err) raise rpkgError('Could not query n-v-r of %s: %s' % (self.module_name, e)) if err: self.log.debug( 'Errors occoured while running following command to get N-V-R-E:' ) self.log.debug(joined_cmd) self.log.error(err) # Get just the output, then split it by ??, grab the first and split # again to get ver and rel first_line_output = output.split('??')[0] parts = first_line_output.split() if len(parts) != 4: raise rpkgError('Could not get n-v-r-e from %r' % first_line_output) (self._module_name_spec, self._epoch, self._ver, self._rel) = parts # Most packages don't include a "Epoch: 0" line, in which case RPM # returns '(none)' if self._epoch == "(none)": self._epoch = "0"
def load_kojisession(self, anon=False): """Initiate a koji session. The koji session can be logged in or anonymous """ koji_config = self.read_koji_config() # save the weburl and topurl for later use as well self._kojiweburl = koji_config['weburl'] self._topurl = koji_config['topurl'] self.log.debug('Initiating a %s session to %s', os.path.basename(self.build_client), koji_config['server']) # Build session options used to create instance of ClientSession session_opts = self.create_koji_session_opts(koji_config) try: session = koji.ClientSession(koji_config['server'], session_opts) except: raise rpkgError('Could not initiate %s session' % os.path.basename(self.build_client)) else: self._kojisession = session self.login_koji_session(koji_config, self._kojisession)
def load_spec(self): """This sets the spec attribute""" deadpackage = False # Get a list of files in the path we're looking at files = os.listdir(self.module_build_dir) # Search the files for the first one that ends with ".spec" for f in files: if f.endswith('.spec') and f.startswith( self.module_name) and not f.startswith('.'): self._spec = f return if f == 'dead.package': deadpackage = True if deadpackage: raise rpkgError('No spec file found. This package is retired') else: raise rpkgError('No spec file found.')
def mock_config(self, target=None, arch=None): """Generate a mock config based on branch data. Can use option target and arch to override autodiscovery. Will return the mock config file text. """ if (target is None): target = self.target if (arch is None): arch = self.arch # Figure out if we have a valid build target build_target = self.kojisession.getBuildTarget(target) if not build_target: raise rpkgError('Unknown build target: %s\n' 'Consider using the --target option' % target) try: repoid = self.kojisession.getRepo( build_target['build_tag_name'])['id'] except Exception: raise rpkgError('Could not find a valid build repo') proxy = '10.144.1.10:8080' with open("/etc/yum.conf") as f: for line in f: if 'proxy' in line: proxy = line.split('=')[1] # Generate the config config = koji.genMockConfig('%s-%s' % (target, arch), arch, distribution=self.disttag, tag_name=build_target['build_tag_name'], repoid=repoid, topurl=self.topurl, yum_proxy=proxy) # Return the mess return (config)
def load_cmd(self): """This sets up the cmd object""" # Set target if we got it as an option target = None if hasattr(self.args, 'target') and self.args.target: target = self.args.target # load items from the config file items = dict(self.config.items(self.name, raw=True)) try: dg_namespaced = self.config.getboolean(self.name, "distgit_namespaced") except ValueError: raise rpkgError('distgit_namespaced option must be a boolean') except configparser.NoOptionError: dg_namespaced = False # Read comma separated list of kerberos realms realms = [ realm for realm in items.get("kerberos_realms", '').split(',') if realm ] # Create the cmd object self._cmd = self.site.Commands(self.args.path, items['lookaside'], items['lookasidehash'], items['lookaside_cgi'], items['gitbaseurl'], items['anongiturl'], items['branchre'], items['kojiconfig'], items['build_client'], user=self.args.user, dist=self.args.dist or self.args.release, target=target, quiet=self.args.q, distgit_namespaced=dg_namespaced, realms=realms) self._cmd.module_name = self.args.module_name self._cmd.password = self.args.password self._cmd.runas = self.args.runas self._cmd.debug = self.args.debug self._cmd.verbose = self.args.v self._cmd.clone_config = items.get('clone_config') if hasattr(self.args, 'version_hash'): self._cmd.version_hash = self.args.version_hash
def load_branch_merge(self): """Find the remote tracking branch from the branch we're on. The goal of this function is to catch if we are on a branch we can make some assumptions about. If there is no merge point then we raise and ask the user to specify. NOTE: do not handle default branch merge. Command line option --release overrides return value from this method, which should be handled in caller side. """ try: local_branch = self.repo.active_branch.name except TypeError as e: raise rpkgError('Repo in inconsistent state: %s' % e) try: merge = self.git.get_config( 'branch.{0}.merge'.format(local_branch)) except git.GitCommandError: raise rpkgError('Unable to find remote branch. Use --release') # Trim off the refs/heads so that we're just working with # the branch name merge = merge.replace('refs/heads/', '', 1) self._branch_merge = merge
def git_clone(self, module, giturl, path=None, branch=None, bare_dir=None, anon=False, target=None): cmd = ['git', 'clone'] if self.quiet: cmd.append('-q') # do the clone if branch and bare_dir: raise rpkgError('Cannot combine bare cloning with a branch') elif branch: # For now we have to use switch branch self.log.debug('Checking out a specific branch %s', giturl) cmd.extend(['-b', branch, giturl]) elif bare_dir: self.log.debug('Cloning %s bare', giturl) cmd.extend(['--bare', giturl]) if not target: cmd.append(bare_dir) else: self.log.debug('Cloning %s', giturl) cmd.extend([giturl]) if not bare_dir: # --bare and --origin are incompatible cmd.extend(['--origin', self.default_branch_remote]) if target: self.log.debug('Cloning into: %s', target) cmd.append(target) self._run_command(cmd, cwd=path) if self.clone_config: base_module = self.get_base_module(module) git_dir = target if target else bare_dir if bare_dir else base_module conf_git = git.Git(os.path.join(path, git_dir)) self._clone_config(conf_git, module)
def load_push_url(self): """Find the pushurl or url of remote of branch we're on.""" try: url = self.repo.git.remote('get-url', '--push', self.branch_remote) except git.GitCommandError as e: try: url = self.git.get_config('remote.%s.pushurl' % self.branch_remote) except git.GitCommandError: try: url = self.git.get_config('remote.%s.url' % self.branch_remote) except git.GitCommandError as e: raise rpkgError( 'Unable to find remote push url: {0}'.format(e)) if isinstance(url, six.text_type): # GitPython >= 1.0 return unicode. It must be encoded to string. self._push_url = url else: self._push_url = url.decode('utf-8')
def build(self, skip_tag=False, scratch=False, background=False, url=None, chain=None, arches=None, sets=False, nvr_check=True): """Initiate a build of the module. Available options are: skip_tag: Skip the tag action after the build scratch: Perform a scratch build background: Perform the build with a low priority url: A url to an uploaded srpm to build from chain: A chain build set arches: A set of arches to limit the scratch build for sets: A boolean to let us know whether or not the chain has sets nvr_check: A boolean; locally construct NVR and submit a build only if NVR doesn't exist in a build system This function submits the task to koji and returns the taskID It is up to the client to wait or watch the task. """ # Ensure the repo exists as well as repo data and site data # build up the command that a user would issue cmd = [self.build_client] # construct the url url = "git+" + self.spec_file_git + '?#' if self.version_hash == None: url += rcppkg_utils.get_local_spec_head(self.module_build_dir) else: url += self.version_hash # Check to see if the target is valid build_target = self.kojisession.getBuildTarget(self.target) if not build_target: raise rpkgError('Unknown build target: %s' % self.target) # see if the dest tag is locked dest_tag = self.kojisession.getTag(build_target['dest_tag_name']) if not dest_tag: raise rpkgError('Unknown destination tag %s' % build_target['dest_tag_name']) if dest_tag['locked'] and not scratch: raise rpkgError('Destination tag %s is locked' % dest_tag['name']) # If we're chain building, make sure inheritance works if chain: cmd.append('chain-build') ancestors = self.kojisession.getFullInheritance( build_target['build_tag']) ancestors = [ancestor['parent_id'] for ancestor in ancestors] if dest_tag['id'] not in [build_target['build_tag']] + ancestors: raise rpkgError('Packages in destination tag ' '%(dest_tag_name)s are not inherited by' 'build tag %(build_tag_name)s' % build_target) else: cmd.append('build') # define our dictionary for options opts = {} # Set a placeholder for the build priority priority = None if skip_tag: opts['skip_tag'] = True cmd.append('--skip-tag') if scratch: opts['scratch'] = True cmd.append('--scratch') if background: cmd.append('--background') priority = 5 # magic koji number :/ if arches: if not scratch: raise rpkgError('Cannot override arches for non-scratch ' 'builds') for arch in arches: if not re.match(r'^[0-9a-zA-Z_.]+$', arch): raise rpkgError('Invalid architecture name: %s' % arch) cmd.append('--arch-override=%s' % ','.join(arches)) opts['arch_override'] = ' '.join(arches) cmd.append(self.target) if url.endswith('.src.rpm'): srpm = os.path.basename(url) build_reference = srpm else: try: build_reference = self.nvr except rpkgError as error: self.log.warning(error) if nvr_check: self.log.info('Note: You can skip NVR construction & NVR' ' check with --skip-nvr-check. See help for' ' more info.') raise rpkgError( 'Cannot continue without properly constructed NVR.') else: self.log.info('NVR checking will be skipped so I do not' ' care that I am not able to construct NVR.' ' I will refer this build by package name' ' in following messages.') build_reference = self.module_name # Now submit the task and get the task_id to return # Handle the chain build version if chain: self.log.debug('Adding %s to the chain', url) # If we're dealing with build sets the behaviour of the last # package changes, and we add it to the last (potentially empty) # set. Otherwise the last package just gets added to the end of # the chain. if sets: chain[-1].append(url) else: chain.append([url]) # This next list comp is ugly, but it's how we properly get a : # put in between each build set cmd.extend(' : '.join( [' '.join(build_sets) for build_sets in chain]).split()) self.log.info('Chain building %s + %s for %s', build_reference, chain[:-1], self.target) self.log.debug( 'Building chain %s for %s with options %s and a priority of %s', chain, self.target, opts, priority) self.log.debug(' '.join(cmd)) task_id = self.kojisession.chainBuild(chain, self.target, opts, priority=priority) # Now handle the normal build else: cmd.append(url) self.log.info('Building %s for %s', build_reference, self.target) self.log.debug( 'Building %s for %s with options %s and a priority of %s', url, self.target, opts, priority) self.log.debug(' '.join(cmd)) task_id = self.kojisession.build(url, self.target, opts, priority=priority) self.log.info('Created task: %s', task_id) self.log.info('Task info: %s/taskinfo?taskID=%s', self.kojiweburl, task_id) return task_id