#!/usr/bin/python # rpmci_srpm_builder_main.py: # Implementation of rpm-vcs-mirror # # Licensed under the new-BSD license (http://www.opensource.org/licenses/bsd-license.php) # Copyright (C) 2010 Red Hat, Inc. # Written by Colin Walters import os import sys import time import shutil import optparse from ConfigParser import SafeConfigParser import logging import tempfile import subprocess import urllib import glib import gobject import gio from . import msgqueue from . import subtask from . import dynrepo from . import artifact from . import spec from . import lame_vcs_abstraction class SRPMBuilder(object): def __init__(self, options, config): self.config = config self._options = options mirror_dir = config.get('VCS', 'mirror_dir') vcs_msgqueue_dir = config.get('VCS', 'msgqueue') self._vcs_msgqueue = msgqueue.MessageQueue(vcs_msgqueue_dir) srpm_msgqueue_dir = config.get('SRPM', 'msgqueue') self._srpm_msgqueue = msgqueue.MessageQueue(srpm_msgqueue_dir) self._artifactset = artifact.ArtifactSet.from_config(config) self._target_vcs = {} for target in self._artifactset.get_build_targets(): fedora_url = artifact.fedora_git_url_for_build_target(self.config, target) upstream_url = artifact.upstream_vcs_url_for_build_target(self.config, target) fedora_vcs = lame_vcs_abstraction.Vcs.new_from_spec(fedora_url) fedora_vcs.set_directory(os.path.join(mirror_dir, urllib.quote(fedora_vcs.get_url_string(), ''))) upstream_vcs = lame_vcs_abstraction.Vcs.new_from_spec(upstream_url) upstream_vcs.set_directory(os.path.join(mirror_dir, urllib.quote(upstream_vcs.get_url_string(), ''))) self._target_vcs[target] = (fedora_vcs, upstream_vcs) self._srcdir = config.get('SRPM', 'srpm_dir') if not os.path.isdir(self._srcdir): os.makedirs(self._srcdir) self._srcrepo = dynrepo.Repo(self._srcdir) def start(self): self._vcs_msgqueue.connect(self._on_vcs_message) def _get_base_rpmbuild_args(self, src_dirpath): return ['--define', '_sourcedir ' + src_dirpath, '--define', '_specdir ' + src_dirpath, '--define', '_builddir ' + src_dirpath, '--define', '_srcrpmdir ' + src_dirpath, '--define', '_rpmdir ' + src_dirpath] def _on_vcs_message(self, q, messages): msg_list = list(messages) num_msgs = len(msg_list) logging.debug("Starting processing of %d messages" % (num_msgs, )) for msg in msg_list: url = msg.payload['url'] logging.debug("Processing update for VCS url %r" % (url, )) self._handle_vcs_message_url(q, url) q.consume(msg) logging.debug("Processed %d messages successfully" % (num_msgs, )) def _handle_vcs_message_url(self, q, url): is_fedora = False target = None valid_urls = [] for iter_target,(fedora_vcs, upstream_vcs) in self._target_vcs.iteritems(): fedora_url = fedora_vcs.get_url_string() is_fedora = (url == fedora_url) if not is_fedora: upstream_url = upstream_vcs.get_url_string() if not url == upstream_url: valid_urls.append(upstream_url) continue target = iter_target break assert target is not None, ("Couldn't find target for url %r; valid=%r" % (url, valid_urls)) (fedora_vcs, upstream_vcs) = self._target_vcs[target] work_dir = tempfile.mkdtemp('.tmp', 'srpm-builder') logging.debug("Creating new SRPM for %r in %r" % (target.module, work_dir)) fedora_dir = os.path.join(work_dir, target.module) fedora_vcs.export_directory('HEAD', fedora_dir, sys.stderr) specname = target.module + '.spec' target_spec_path = os.path.join(fedora_dir, specname) target_spec_obj = spec.Spec(target_spec_path) orig_spec_path = os.path.join(self._srcdir, specname) if os.path.isfile(orig_spec_path): # Okay, we have a previous build, so now we "merge" by taking everything # from the new spec file, except we use the Version/Release from the old # one. This is necessary to pacify RPM's insistence on globally # ordering versions, rather than simply having repository build versions. orig_spec_obj = spec.Spec(orig_spec_path) orig_version = orig_spec_obj.get_key('Version') orig_release = orig_spec_obj.get_key('Release') target_spec_obj.set_key('Version', orig_version) target_spec_obj.set_key('Release', orig_release) target_spec_obj.save() exec_basedir = os.path.dirname(sys.argv[0]) args = [os.path.abspath(os.path.join(exec_basedir, 'rpmci-spec-vcs')), '--vcsdir=' + upstream_vcs.get_directory(), 'set-revision', 'HEAD'] subtask.spawn_sync('rpmci-spec-vcs-%s' % (target.module, ), args, cwd=fedora_dir) args = ['rpmbuild'] args.extend(self._get_base_rpmbuild_args(fedora_dir)) args.extend(['-bs', specname]) subtask.spawn_sync('rpmbuild-srpm-%s' % (target.module, ), args, cwd=fedora_dir) srpm_path = None srpm_basename = None for filename in os.listdir(fedora_dir): if filename.endswith('.src.rpm'): srpm_basename = filename srpm_path = os.path.join(fedora_dir, filename) break assert srpm_path is not None os.rename(srpm_path, os.path.join(self._srcdir, srpm_basename)) self._srcrepo.update_repo_sync() self._srpm_msgqueue.append(msgqueue.Message(None, {'type': 'srpm'}, {'filename': srpm_basename})) def main(): glib.threads_init() opts = optparse.OptionParser("usage: %prog [options]") opts.add_option('-c', '--config', dest='config', help="Path to configuration file") opts.add_option('', '--debug', action='store_true', help="Print verbose debugging") (options, args) = opts.parse_args() if options.config is None: print "Must specify --config" sys.exit(1) config = SafeConfigParser({'home': os.environ['HOME']}) config.read(options.config) level = logging.DEBUG if options.debug else logging.INFO logging.basicConfig(stream=sys.stderr, level=level) subtask.global_configure(config) builder = SRPMBuilder(options, config) builder.start() logging.info("Awaiting events") loop = glib.MainLoop() loop.run()