]> git.decadent.org.uk Git - dak.git/blob - dak/generate_releases2.py
Merge remote branch 'ganneff/gr2' into g-r
[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', 'origin'), ('Label', 'label'), ('Suite', 'suite_name'),
113                 ('Version', 'version'), ('Codename', 'codename'), ('Description', 'description'))
114     # A "Sub" Release file has slightly different fields
115     subattribs=( ('Origin', 'origin'), ('Label', 'label'), ('Archive', 'suite_name'),
116                  ('Version', 'version'))
117     # Boolean stuff. If we find it true in database, write out "yes" into the release file
118     boolattrs=('notautomatic', 'butautomaticupgrades')
119     KEYWORD = 0
120     DBFIELD = 1
121
122     cnf = Config()
123
124     outfile=os.path.join(cnf["Dir::Root"], suite.suite_name, "Release")
125     print "Working on: %s" % (outfile)
126 #    out = open(outfile, "w")
127     out = open("/tmp/lala", "w")
128
129     for key in attribs:
130         if getattr(suite, key[DBFIELD]) is None:
131             continue
132         out.write("%s: %s\n" % (key[KEYWORD], getattr(suite, key[DBFIELD])))
133
134     out.write("Date: %s\n" % (time.strftime("%a, %d %b %Y %H:%M:%S UTC", time.gmtime(time.time()))))
135     if suite.validtime:
136         validtime=float(suite.validtime)
137         out.write("Valid-Until: %s\n" % (time.strftime("%a, %d %b %Y %H:%M:%S UTC", time.gmtime(time.time()+validtime))))
138
139     for key in boolattrs:
140         if hasattr(suite, key):
141             if getattr(suite, key):
142                 out.write("%s: yes\n" % (key.capitalize()))
143     out.write("Architectures: %s\n" % (" ".join([a.arch_string for a in architectures])))
144     suite_suffix = "%s" % (cnf.Find("Dinstall::SuiteSuffix"))
145     ## FIXME: Components need to be adjusted to whatever will be in the db. see comment above at SC
146     out.write("Components: %s\n" % ( " ".join(map(lambda x: "%s%s" % (suite_suffix, x), SC[suite.suite_name]  ))))
147
148     for comp in SC[suite.suite_name]:
149         for dirpath, dirnames, filenames in os.walk("%sdists/%s/%s" % (cnf["Dir::Root"], suite.suite_name, comp), topdown=True):
150             if not re_getsarelease.match(dirpath):
151                 continue
152
153             outfile=os.path.join(dirpath, "Release")
154             print "Processing %s" % (outfile)
155             # subrel = open(outfile, "w")
156             subrel = open("/tmp/lala2", "w")
157
158             ## FIXME: code dupe, line 127.
159             for key in subattribs:
160                 if getattr(suite, key[DBFIELD]) is None:
161                     continue
162                 subrel.write("%s: %s\n" % (key[KEYWORD], getattr(suite, key[DBFIELD])))
163
164             for key in boolattrs:
165                 if hasattr(suite, key):
166                     if getattr(suite, key):
167                         subrel.write("%s: yes\n" % (key.capitalize()))
168             subrel.write("Component: %s%s\n" % (suite_suffix, comp))
169             subrel.close()
170
171     # Now that we have done the groundwork, we want to get off and add the files with
172     # their checksums to the main Release file
173     files = []
174     oldcwd = os.getcwd()
175
176     os.chdir("%sdists/%s" % (cnf["Dir::Root"], suite.suite_name))
177
178     for dirpath, dirnames, filenames in os.walk(".", topdown=True):
179         if dirpath == '.':
180             continue
181         for entry in filenames:
182             if not re_includeinarelease.match(entry):
183                 continue
184             if entry.endswith(".gz"):
185                 filename="zcat|%s" % (os.path.join(dirpath.lstrip('./'), entry))
186             elif entry.endswith(".bz2"):
187                 filename="bzcat|%s" % (os.path.join(dirpath.lstrip('./'), entry))
188             else:
189                 filename=os.path.join(dirpath.lstrip('./'), entry)
190             files.append(filename)
191
192     decompressors = { 'zcat' : gzip.GzipFile,
193                       'bzcat' : bz2.BZ2File }
194
195     hashfuncs = { 'MD5Sum' : apt_pkg.md5sum,
196                   'SHA1' : apt_pkg.sha1sum,
197                   'SHA256' : apt_pkg.sha256sum }
198
199     for entry in files:
200         entryhash = ""
201         entrylen = ""
202         comp = None
203         if entry.find('|') > 0:
204             k=entry.split('|')
205             comp=k[0]
206             filename=k[1]
207         else:
208             filename=entry
209
210     os.chdir(oldcwd)
211     return
212
213
214 def main ():
215     global Options, Logger, results
216
217     cnf = Config()
218
219     for i in ["Help", "Suite", "Force"]:
220         if not cnf.has_key("Generate-Releases::Options::%s" % (i)):
221             cnf["Generate-Releases::Options::%s" % (i)] = ""
222
223     Arguments = [('h',"help","Generate-Releases::Options::Help"),
224                  ('s',"suite","Generate-Releases::Options::Suite"),
225                  ('f',"force","Generate-Releases::Options::Force")]
226
227     suite_names = apt_pkg.ParseCommandLine(cnf.Cnf, Arguments, sys.argv)
228     Options = cnf.SubTree("Generate-Releases::Options")
229
230     if Options["Help"]:
231         usage()
232
233     Logger = daklog.Logger(cnf, 'generate-releases')
234
235     session = DBConn().session()
236
237     if Options["Suite"]:
238         suites = []
239         for s in suite_names:
240             suite = get_suite(s.lower(), session)
241             if suite:
242                 suites.append(suite)
243             else:
244                 print "cannot find suite %s" % s
245                 Logger.log(['cannot find suite %s' % s])
246     else:
247         suites=session.query(Suite).filter(Suite.untouchable == False).all()
248
249     startdir = os.getcwd()
250     os.chdir(cnf["Dir::TempPath"])
251
252     broken=[]
253     # For each given suite, run one process
254     results=[]
255     for s in suites:
256         # Setup a multiprocessing Pool. As many workers as we have CPU cores.
257 #        pool = Pool()
258 #        Logger.log(['Release file for Suite: %s' % (s.suite_name)])
259 #        pool.apply_async(generate_release_files, (s, cnf["Dir::TempPath"]), callback=get_result)
260         # As long as we test, just one and not with mp module
261         generate_release_files(s, cnf["Dir::TempPath"])
262         break
263
264     # No more work will be added to our pool, close it and then wait for all to finish
265 #    pool.close()
266 #    pool.join()
267
268     if len(results) > 0:
269         Logger.log(['Release file generation broken: %s' % (results)])
270         print "Release file generation broken: %s" % (results)
271         sys.exit(1)
272
273     os.chdir(startdir)
274     # this script doesn't change the database
275     session.close()
276     Logger.close()
277
278 #######################################################################################
279
280 if __name__ == '__main__':
281     main()