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