]> git.decadent.org.uk Git - dak.git/blob - dak/generate_releases2.py
start a new generate-releases
[dak.git] / dak / generate_releases2.py
1 #!/usr/bin/env python
2
3 """ Create all the Release files
4
5 @contact: Debian FTPMaster <ftpmaster@debian.org>
6 @copyright: 2011  Joerg Jaspert <joerg@debian.org>
7 @license: GNU General Public License version 2 or later
8
9 """
10
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 2 of the License, or
14 # (at your option) any later version.
15
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 # GNU General Public License for more details.
20
21 # You should have received a copy of the GNU General Public License
22 # along with this program; if not, write to the Free Software
23 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24
25 ################################################################################
26
27 # <mhy> I wish they wouldnt leave biscuits out, thats just tempting. Damnit.
28
29 ################################################################################
30
31 import sys
32 import os
33 import os.path
34 import stat
35 import time
36 import gzip
37 import bz2
38 import apt_pkg
39 from tempfile import mkstemp, mkdtemp
40 import commands
41 from multiprocessing import Pool, TimeoutError
42
43 from daklib import utils, daklog
44 from daklib.regexes import re_getsarelease, re_includeinarelease
45 from daklib.dak_exceptions import *
46 from daklib.dbconn import *
47 from daklib.config import Config
48
49 ################################################################################
50 Options = None                 #: Commandline arguments parsed into this
51 Logger = None                  #: Our logging object
52 results = []                   #: Results of the subprocesses
53
54 ################################################################################
55
56 def usage (exit_code=0):
57     """ Usage information"""
58
59     print """Usage: dak generate-releases [OPTIONS]
60 Generate the Release files
61
62   -s, --suite=SUITE(s)       process this suite
63                              Default: All suites not marked 'untouchable'
64   -f, --force                Allow processing of untouchable suites
65                              CAREFUL: Only to be used at (point) release time!
66   -h, --help                 show this help and exit
67
68 SUITE can be a space seperated list, e.g.
69    --suite=unstable testing
70   """
71     sys.exit(exit_code)
72
73 ########################################################################
74
75 def get_result(arg):
76     global results
77     if arg:
78         results.append(arg)
79
80 ## FIXME: Hardcoded for now. This needs to go via database, but mhy is working on that part.
81 ##        until that is done, we just hardcode it here.
82 SC = { "unstable": ("main", "contrib", "non-free"),
83        "oldstable": ("main", "contrib", "non-free"),
84        "testing": ("main", "contrib", "non-free"),
85        "testing-proposed-updates": ("main", "contrib", "non-free"),
86        "experimental": ("main", "contrib", "non-free"),
87        "proposed-updates": ("main", "contrib", "non-free"),
88        "oldstable-proposed-updates": ("main", "contrib", "non-free"),
89        "squeeze-updates": ("main", "contrib", "non-free"),
90        "stable": ("main", "contrib", "non-free"),
91        "squeeze-backports": ("main", "contrib", "non-free"),
92        "lenny-backports": ("main", "contrib", "non-free"),
93        "lenny-backports-sloppy": ("main", "contrib", "non-free"),
94        }
95
96
97 def generate_release_files(suite, tmppath):
98     """
99     Generate Release files for the given suite
100
101     @type suite: string
102     @param suite: Suite name
103
104     @type tmppath: string
105     @param tmppath: The temporary path to work in
106     """
107
108     architectures = get_suite_architectures(suite.suite_name, skipall=True, skipsrc=True)
109
110     # Attribs contains a list of field names to fetch from suite table. Should the entry in the
111     # suite table be named differently, |realname will help it out.
112     attribs=('origin', 'label', 'suite|suite_name', 'version', 'codename', 'description')
113     # A "Sub" Release file has slightly different fields
114     subattribs=('origin', 'label', 'archive|suite_name', 'version')
115     # Boolean stuff. If we find it true in database, write out "yes" into the release file
116     boolattrs=('notautomatic', 'butautomaticupgrades')
117
118     cnf = Config()
119
120     outfile=os.path.join(cnf["Dir::Root"], suite.suite_name, "Release")
121     print "Working on: %s" % (outfile)
122 #    out = open(outfile, "w")
123     out = open("/tmp/lala", "w")
124
125     for key in attribs:
126         query=pout=""
127         if key.find('|') > 0:
128             k=key.split('|')
129             pout=k[0]
130             query=k[1]
131         else:
132             query=pout=key
133
134         if getattr(suite, query) is None:
135             continue
136         out.write("%s: %s\n" % (pout.capitalize(), getattr(suite, query)))
137     out.write("Date: %s\n" % (time.strftime("%a, %d %b %Y %H:%M:%S UTC", time.gmtime(time.time()))))
138     if suite.validtime:
139         validtime=float(suite.validtime)
140         out.write("Valid-Until: %s\n" % (time.strftime("%a, %d %b %Y %H:%M:%S UTC", time.gmtime(time.time()+validtime))))
141
142     for key in boolattrs:
143         if hasattr(suite, key):
144             if getattr(suite, key):
145                 out.write("%s: yes\n" % (key.capitalize()))
146     out.write("Architectures: %s\n" % (" ".join([a.arch_string for a in architectures])))
147     suite_suffix = "%s" % (cnf.Find("Dinstall::SuiteSuffix"))
148     ## FIXME: Components need to be adjusted to whatever will be in the db. see comment above at SC
149     out.write("Components: %s\n" % ( " ".join(map(lambda x: "%s%s" % (suite_suffix, x), SC[suite.suite_name]  ))))
150
151     for comp in SC[suite.suite_name]:
152         for dirpath, dirnames, filenames in os.walk("%sdists/%s/%s" % (cnf["Dir::Root"], suite.suite_name, comp), topdown=True):
153             if not re_getsarelease.match(dirpath):
154                 continue
155
156             outfile=os.path.join(dirpath, "Release")
157             print "Processing %s" % (outfile)
158             # subrel = open(outfile, "w")
159             subrel = open("/tmp/lala2", "w")
160
161             ## FIXME: code dupe, line 127.
162             for key in attribs:
163                 query=pout=""
164                 if key.find('|') > 0:
165                     k=key.split('|')
166                     pout=k[0]
167                     query=k[1]
168                 else:
169                     query=pout=key
170
171                 if getattr(suite, query) is None:
172                     continue
173                 subrel.write("%s: %s\n" % (pout.capitalize(), getattr(suite, query)))
174             for key in boolattrs:
175                 if hasattr(suite, key):
176                     if getattr(suite, key):
177                         subrel.write("%s: yes\n" % (key.capitalize()))
178             subrel.write("Component: %s%s\n" % (suite_suffix, comp))
179             subrel.close()
180
181     # Now that we have done the groundwork, we want to get off and add the files with
182     # their checksums to the main Release file
183     files = []
184     oldcwd = os.getcwd()
185
186     os.chdir("%sdists/%s" % (cnf["Dir::Root"], suite.suite_name))
187
188     for dirpath, dirnames, filenames in os.walk(".", topdown=True):
189         if dirpath == '.':
190             continue
191         for entry in filenames:
192             if not re_includeinarelease.match(entry):
193                 continue
194             filename=os.path.join(dirpath.lstrip('./'), entry)
195             files.append(filename)
196
197
198     os.chdir(oldcwd)
199     return
200
201
202 def main ():
203     global Options, Logger, results
204
205     cnf = Config()
206
207     for i in ["Help", "Suite", "Force"]:
208         if not cnf.has_key("Generate-Releases::Options::%s" % (i)):
209             cnf["Generate-Releases::Options::%s" % (i)] = ""
210
211     Arguments = [('h',"help","Generate-Releases::Options::Help"),
212                  ('s',"suite","Generate-Releases::Options::Suite"),
213                  ('f',"force","Generate-Releases::Options::Force")]
214
215     suite_names = apt_pkg.ParseCommandLine(cnf.Cnf, Arguments, sys.argv)
216     Options = cnf.SubTree("Generate-Releases::Options")
217
218     if Options["Help"]:
219         usage()
220
221     Logger = daklog.Logger(cnf, 'generate-releases')
222
223     session = DBConn().session()
224
225     if Options["Suite"]:
226         suites = []
227         for s in suite_names:
228             suite = get_suite(s.lower(), session)
229             if suite:
230                 suites.append(suite)
231             else:
232                 print "cannot find suite %s" % s
233                 Logger.log(['cannot find suite %s' % s])
234     else:
235         suites=session.query(Suite).filter(Suite.untouchable == False).all()
236
237     startdir = os.getcwd()
238     os.chdir(cnf["Dir::TempPath"])
239
240     broken=[]
241     # For each given suite, run one process
242     results=[]
243     for s in suites:
244         # Setup a multiprocessing Pool. As many workers as we have CPU cores.
245 #        pool = Pool()
246 #        Logger.log(['Release file for Suite: %s' % (s.suite_name)])
247 #        pool.apply_async(generate_release_files, (s, cnf["Dir::TempPath"]), callback=get_result)
248         # As long as we test, just one and not with mp module
249         generate_release_files(s, cnf["Dir::TempPath"])
250         break
251
252     # No more work will be added to our pool, close it and then wait for all to finish
253 #    pool.close()
254 #    pool.join()
255
256     if len(results) > 0:
257         Logger.log(['Release file generation broken: %s' % (results)])
258         print "Release file generation broken: %s" % (results)
259         sys.exit(1)
260
261     os.chdir(startdir)
262     # this script doesn't change the database
263     session.close()
264     Logger.close()
265
266 #######################################################################################
267
268 if __name__ == '__main__':
269     main()