75a3399fe872ba71e880394f94866728104fff77
[moonshot.git] / rpm-builder
1 #!/usr/bin/python
2
3 '''A script to buildMoonshot  potentially using a schroot for install testing.
4 '''
5
6 from contextlib import contextmanager
7 import os, subprocess, exceptions
8 import re
9 import sys
10 from optparse import OptionParser
11 from shutil import copy
12
13
14
15 # These variables can be overridden by options. If packages is not
16 # set, then it is read from the rpm_packages file
17 packages = []  # Set of packages to build
18 tar_file = None
19
20 class CommandError(exceptions.StandardError):
21     pass
22
23 # Centos 6.5 does not have collections.OrderedDict
24 # This implementation provides the minimal functionality of OrderedDict that we need
25 # It works here, but should not be counted on for anything else.
26 class OrderedDict(dict):
27
28     def __setitem__(self,k, v):
29         if k not in self:
30             self.keylist.append(k)
31         return             super(OrderedDict,self).__setitem__(k,v)
32
33     def __init__(self, *args, **kwargs):
34         super(OrderedDict,self).__init__(*args, **kwargs)
35         self.keylist = []
36
37     def values(self):
38         return map( lambda(elt): self[elt], self.keylist)
39
40 builder_by_type = {
41     '.tar.gz': lambda(t): run_cmd([ 'rpmbuild', '-ta', t]),
42     '.spec':
43     lambda(s): run_cmd(['rpmbuild', '--define', '_sourcedir '+os.getcwd(),
44                         '-ba', s]),
45     }
46
47
48 def find_type(name):
49     match = re.match('^.*(\\.tar\\.gz|\\.spec)$', name)
50     if match:
51         return match.group(1)
52     else: return None
53         
54
55 # The following regexp is not quite right.
56 # One place is the rpm_packages file.
57 # The other is the directory listing.
58 # The rpm_packages file might have entries like shibboleth/xmltooling
59 # Where as the distributions directory might have xmltooling-1.5.tar.gz
60 # Two requirements for correct operation:
61 # trim_target produces unique results for everything in rpm_packages
62 # trim_target correctly trims what's in the packages file to the same
63 # thing it trims the tar file or spec file to.
64 #
65 def trim_target(t):
66     match = re.match('([^/-]*/)?([^-/]+)', t)
67     if match is None: return ""
68     return match.group(2)
69
70     
71 @contextmanager
72 def current_directory(dir):
73     "Change the current directory as a context manager; when the context exits, return."
74     cwd = os.getcwd()
75     os.chdir(dir)
76     yield
77     os.chdir(cwd)
78
79
80 def run_cmd(args, **kwords):
81     rcode =  subprocess.call( args, **kwords)
82     if rcode <> 0:
83         raise CommandError(args)
84
85 def command_output(args) :
86     p = subprocess.Popen(args, stdout=subprocess.PIPE)
87     output = p.communicate()
88     output = output[0]
89     if p.returncode != 0:
90         raise CommandError(args)
91     return output.strip()
92
93 def build(package):
94     return builder_by_type[find_type(package)](package)
95
96
97
98 def read_packages():
99     '''Read in the packages file from rpm_packages
100     '''
101     try: pf = file("rpm_packages")
102     except IOError:
103         print "Error: rpm_packages file not found"
104         exit(1)
105     def is_comment(line):
106         if re.match("^\\s*#", line): return False
107         if "#" in line: raise ValueError(
108             "Source package line contains a comment but not at beginning")
109         return True
110     return map(lambda(x): x.rstrip(),
111         filter(is_comment, pf.readlines()))
112
113
114 # main program
115 opt = OptionParser()
116 opt.usage = "%prog [options] distributions_dir [packages]"
117 opt.add_option('--tar-file',
118                dest='tar_file',
119                help = 'Tar up resulting packages in given tar file',
120                default = None)
121 (options, args) = opt.parse_args()
122 tar_file = options.tar_file
123 if tar_file is not None:
124     tar_file = os.path.join(os.getcwd(), tar_file)
125 if len(args) == 0:
126     print "Distributions directory required"
127     exit(1)
128 dist_dir = args[0]
129 packages = args[1:]
130 if len(packages) == 0: packages = read_packages()
131 package_order = OrderedDict()
132 for t in packages:
133     package_order[trim_target(t)] = None
134
135 for t in os.listdir(dist_dir):
136     target_type = find_type(t)
137     if target_type is None: continue
138     trimmed = trim_target(t)
139     if target_type == ".spec":
140         package_order[trimmed] = t
141     else:
142         # Replace None but nothing else
143         if not package_order.get(trimmed): package_order[trimmed] = t
144
145     
146
147 os.umask(022)
148
149 try:
150     run_cmd([ 'rm', '-rf',
151               os.path.expanduser("~/rpmbuild")])
152     run_cmd([ 'rpmdev-setuptree'])
153     for f in os.listdir("rpm-sources"):
154         copy("rpm-sources/" + f, dist_dir)
155
156     with current_directory(dist_dir):
157         for t in package_order.values():
158             if t is None: continue
159             build(t)
160     if tar_file is not None:
161         with current_directory(os.path.expanduser("~/rpmbuild")):
162             run_cmd(['tar', '-cf', tar_file,
163                      './RPMS', './SRPMS'])
164
165 except CommandError as c:
166     print "Error:" + str(c.args)
167     exit(1)
168
169
170     
171