]> git.decadent.org.uk Git - dak.git/blob - jenna
missing \n
[dak.git] / jenna
1 #!/usr/bin/env python
2
3 # Generate file list which is then fed to apt-ftparchive to generate Packages and Sources files
4 # Copyright (C) 2000, 2001  James Troup <james@nocrew.org>
5 # $Id: jenna,v 1.9 2001-04-03 10:00:52 troup Exp $
6
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
11
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
21 #######################################################################################
22
23 # BTAF: "GOD *DAMMIT*!!  What the FUCK happened to my free will??"
24 #
25 # -- http://www.angryflower.com/timelo.gif
26
27 #######################################################################################
28
29 import pg, string, os, sys
30 import apt_pkg
31 import db_access, utils, claire
32
33 projectB = None
34 Cnf = None
35
36 def generate_src_list(suite, component, output, dislocated_files):
37     sources = {}
38
39     suite_id = db_access.get_suite_id(suite);
40     
41     if component == "-":
42         q = projectB.query("SELECT s.source, l.path, f.filename, f.id FROM source s, src_associations sa, location l, files f WHERE sa.source = s.id AND sa.suite = '%d' AND l.id = f.location AND s.file = f.id ORDER BY s.source, s.version"
43                            % (suite_id));
44     else:
45         q = projectB.query("SELECT s.source, l.path, f.filename, f.id FROM source s, src_associations sa, location l, component c, files f WHERE lower(c.name) = '%s' AND (c.id = l.component OR l.component = NULL) AND sa.source = s.id AND sa.suite = '%d' AND l.id = f.location AND s.file = f.id ORDER BY s.source, s.version"
46                            % (component, suite_id));
47     entries = q.getresult();
48     for entry in entries:
49         (source, path, filename, file_id) = entry;
50         if dislocated_files.has_key(file_id):
51             filename = dislocated_files[file_id];
52         else:
53             filename = path + filename;
54         if sources.has_key(source):
55             sys.stderr.write("E: %s in %s / %s / source is duplicated.  Gravity wins!\n" % (package, suite, component));
56         else:
57             sources[source] = filename;
58
59     # Write the list of files out
60     source_keys = sources.keys();
61     source_keys.sort();
62     for source in source_keys:
63         output.write(sources[source]+'\n')
64     
65 #########################################################################################
66
67 def generate_bin_list(suite, component, architecture, output, type, dislocated_files):
68     packages = {}
69
70     suite_id = db_access.get_suite_id(suite);
71     
72     if component == "-":
73         q = projectB.query("SELECT b.package, l.path, f.filename, f.id FROM architecture a, binaries b, bin_associations ba, location l, files f WHERE ( a.arch_string = '%s' OR a.arch_string = 'all' ) AND a.id = b.architecture AND ba.bin = b.id AND ba.suite = '%d' AND l.id = f.location AND b.file = f.id AND b.type = '%s' ORDER BY b.package, b.version, a.arch_string" % (architecture, suite_id, type));
74     else:
75         q = projectB.query("SELECT b.package, l.path, f.filename, f.id FROM architecture a, binaries b, bin_associations ba, location l, component c, files f WHERE lower(c.name) = '%s' AND (c.id = l.component OR l.component = NULL) AND (a.arch_string = '%s' OR a.arch_string = 'all') AND a.id = b.architecture AND ba.bin = b.id AND ba.suite = '%d' AND l.id = f.location AND b.file = f.id AND b.type = '%s' ORDER BY b.package, b.version, a.arch_string" % (component, architecture, suite_id, type));
76     entries = q.getresult();
77     for entry in entries:
78         (package, path, filename, file_id) = entry;
79         if dislocated_files.has_key(file_id):
80             filename = dislocated_files[file_id];
81         else:
82             filename = path + filename;
83         if packages.has_key(package):
84             sys.stderr.write("E: %s in %s / %s / %s / %s is duplicated.  Gravity wins!" % (package, suite, component, architecture, type));
85         else:
86             packages[package] = filename;
87         
88     # Write the list of files out
89     package_keys = packages.keys();
90     package_keys.sort();
91     for package in package_keys:
92         output.write(packages[package]+'\n')
93
94 #########################################################################################
95
96 ##########
97 # <elmo> I'm doing it in python btw.. nothing against your monster
98 #        SQL, but the python wins in terms of speed and readiblity
99 # <aj> bah
100 # <aj> you suck!!!!!
101 # <elmo> sorry :(
102 # <aj> you are not!!!
103 # <aj> you mock my SQL!!!!
104 # <elmo> you want have contest of skillz??????
105 # <aj> all your skillz are belong to my sql!!!!
106 # <elmo> yo momma are belong to my python!!!!
107 # <aj> yo momma was SQLin' like a pig last night!
108 ##########
109
110 # If something has moved from one component to another we need to
111 # clean out the old versions here.  The rest of jenna won't do this
112 # because it works on a per-component level for flexibility.
113
114 def clean_suite (suite):
115     print "Cleaning out packages for %s..." % (suite)
116     
117     suite_id = db_access.get_suite_id(suite);
118     q = projectB.query("""
119 SELECT b.id, b.package, a.arch_string, b.version, l.path, f.filename, c.name
120   FROM binaries b, bin_associations ba, files f, location l, architecture a, component c
121   WHERE ba.suite = %s AND ba.bin = b.id AND b.file = f.id AND
122         f.location = l.id AND l.component = c.id AND b.architecture = a.id
123 UNION
124 SELECT s.id, s.source, 'source', s.version, l.path, f.filename, c.name
125   FROM source s, src_associations sa, files f, location l, component c
126   WHERE sa.suite = %s AND sa.source = s.id AND s.file = f.id AND
127         f.location = l.id AND l.component = c.id;""" % (suite_id, suite_id));
128     ql = q.getresult();
129     d = {};
130     for i in ql:
131         (id, package, architecture, version, path, filename, component) = i;
132         filename = path + filename;
133         if architecture == "source":
134             delete_table = "src_associations";
135             delete_col = "source";
136         else:
137             delete_table = "bin_associations";
138             delete_col = "bin";
139         key = "%s~%s" % (package, architecture);
140         if os.path.exists(filename):
141             if d.has_key(key):
142                 (other_version, other_component, other_id) = d[key];
143                 if apt_pkg.VersionCompare(version, other_version) != 1:
144                     (keep_version, keep_component) = (other_version, other_component)
145                     (delete_id, delete_version, delete_component) = (id, version, component)
146                 else:
147                     (keep_version, keep_component) = (version, component)
148                     (delete_id, delete_version, delete_component) = (other_id, other_version, other_component)
149                     d[key] = (version, component, id);
150                 if not Cnf.Find("Suite::%s::Untouchable" % (suite)):
151                     print "deleting %s on %s (%s [%s]) in favour of newer version %s [%s]..." \
152                           % (package, architecture, delete_version, delete_component, keep_version, keep_component);
153                     projectB.query("DELETE FROM %s WHERE suite = %s AND %s = %s" % (delete_table, suite_id, delete_col, delete_id));
154                 else:
155                     print "[untouchable] would delete %s on %s (%s [%s]) in favour of newer version %s [%s]..." \
156                           % (package, architecture, delete_version, delete_component, keep_version, keep_component);
157             else:
158                 d[key] = (version, component, id);
159         else:
160             if not Cnf.Find("Suite::%s::Untouchable" % (suite)):
161                 sys.stderr.write("WARNING: deleting %s because it doesn't exist.\n" % (filename));
162                 projectB.query("DELETE FROM %s WHERE suite = %s AND %s = %s" % (delete_table, suite_id, delete_col, delete_id));
163             else:
164                 sys.stderr.write("WARNING: [untouchable] would delete %s because it doesn't exist.\n" % (filename));
165
166 #########################################################################################
167
168 def main():
169     global Cnf, projectB;
170     dislocated_files = {};
171     
172     apt_pkg.init();
173     
174     Cnf = apt_pkg.newConfiguration();
175     apt_pkg.ReadConfigFileISC(Cnf,utils.which_conf_file());
176
177     Arguments = [('a',"architecture","Jenna::Options::Architecture", "HasArg"),
178                  ('c',"component","Jenna::Options::Component", "HasArg"),
179                  ('d',"debug","Jenna::Options::Debug", "IntVal"),
180                  ('h',"help","Jenna::Options::Help"),
181                  ('s',"suite", "Jenna::Options::Suite", "HasArg"),
182                  ('v',"verbose","Jenna::Options::Verbose"),
183                  ('V',"version","Jenna::Options::Version")];
184
185     apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv);
186
187     projectB = pg.connect(Cnf["DB::Name"], Cnf["DB::Host"], int(Cnf["DB::Port"]));
188     db_access.init(Cnf, projectB);
189
190     if Cnf["Jenna::Options::Suite"] == "":
191         Cnf["Jenna::Options::Suite"] = string.join(Cnf.SubTree("Suite").List());
192     for suite in string.split(Cnf["Jenna::Options::Suite"]):
193         suite = string.lower(suite);
194         if suite == 'stable':
195             print "Undoing dislocation..."
196             dislocated_files = claire.find_dislocated_stable(Cnf, projectB);
197         else:
198             dislocated_files = {};
199         clean_suite(suite);
200         components = Cnf["Jenna::Options::Component"];
201         if not Cnf.has_key("Suite::%s::Components" % (suite)):
202             components = "-";
203         if components == "":
204             components = string.join(Cnf.SubTree("Suite::%s::Components" % (suite)).List());
205         for component in string.split(components):
206             component = string.lower(component)
207             architectures = Cnf["Jenna::Options::Architecture"];
208             if architectures == "":
209                 architectures = string.join(Cnf.SubTree("Suite::%s::Architectures" % (suite)).List());
210             for architecture in string.split(architectures):
211                 architecture = string.lower(architecture)
212                 if architecture == "all":
213                     continue
214                 if architecture == "source":
215                     print "Processing dists/%s/%s/%s..." % (suite, component, architecture);
216                     output = utils.open_file("%s/%s_%s_%s.list" % (Cnf["Dir::ListsDir"], suite, component, architecture), "w")
217                     generate_src_list(suite, component, output, dislocated_files);
218                     output.close();
219                 else:
220                     print "Processing dists/%s/%s/binary-%s..." % (suite, component, architecture);
221                     output = utils.open_file("%s/%s_%s_binary-%s.list" % (Cnf["Dir::ListsDir"], suite, component, architecture), "w");
222                     generate_bin_list(suite, component, architecture, output, "deb", dislocated_files);
223                     output.close();
224                     if component == "main" and (suite == "unstable" or suite == "testing"): # FIXME: must be a cleaner way to say debian-installer is main only?
225                         print "Processing dists/%s/%s/debian-installer/binary-%s..." % (suite,component, architecture);
226                         output = utils.open_file("%s/%s_%s_debian-installer_binary-%s.list" % (Cnf["Dir::ListsDir"], suite, component, architecture), "w");
227                         generate_bin_list(suite, component, architecture, output, "udeb", dislocated_files);
228                         output.close();
229
230 #########################################################################################
231
232 if __name__ == '__main__':
233     main()