summaryrefslogtreecommitdiffstats
path: root/rpmci/rpmci_srpm_builder_main.py
blob: d0e554ef89aa63b53a86b983ed2dcd7ace8099a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#!/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 <walters@verbum.org>

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()