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.11 2001-05-03 06:52:03 ajt Exp $
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.
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.
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
21 #######################################################################################
23 # BTAF: "GOD *DAMMIT*!! What the FUCK happened to my free will??"
25 # -- http://www.angryflower.com/timelo.gif
27 #######################################################################################
29 import pg, string, os, sys
31 import db_access, utils, claire
36 def generate_src_list(suite, component, output, dislocated_files):
39 suite_id = db_access.get_suite_id(suite);
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"
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();
49 (source, path, filename, file_id) = entry;
50 if dislocated_files.has_key(file_id):
51 filename = dislocated_files[file_id];
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" % (source, suite, component));
57 sources[source] = filename;
59 # Write the list of files out
60 source_keys = sources.keys();
62 for source in source_keys:
63 output.write(sources[source]+'\n')
65 #########################################################################################
67 def generate_bin_list(suite, component, architecture, output, type, dislocated_files):
70 suite_id = db_access.get_suite_id(suite);
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));
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();
78 (package, path, filename, file_id) = entry;
79 if dislocated_files.has_key(file_id):
80 filename = dislocated_files[file_id];
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));
86 packages[package] = filename;
88 # Write the list of files out
89 package_keys = packages.keys();
91 for package in package_keys:
92 output.write(packages[package]+'\n')
94 #########################################################################################
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
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!
110 # If something has gone from arch:all to arch:any or vice-versa,
111 # clean out the old versions here. The rest of jenna won't do this
112 # because it's lame. I have no idea. </aj>
114 def clean_duplicate_packages(suite):
115 print "Cleaning duplicate packages for %s..." % (suite)
117 suite_id = db_access.get_suite_id(suite)
118 q = projectB.query("""
120 b1.id, b1.version, a1.arch_string,
121 b2.id, b2.version, a2.arch_string
122 FROM bin_associations ba1, binaries b1, architecture a1,
123 bin_associations ba2, binaries b2, architecture a2
124 WHERE ba1.suite = ba2.suite AND ba1.suite = %s
125 AND ba1.bin = b1.id AND b1.architecture = a1.id
126 AND ba2.bin = b2.id AND b2.architecture = a2.id
127 AND b1.package = b2.package
128 AND (a1.id = a2.id OR a1.arch_string = 'all' OR a2.arch_string = 'all')
130 AND versioncmp(b1.version, b2.version) <= 0
131 ORDER BY b1.package, b1.version, a1.arch_string;""" % (suite_id))
136 (package, oldid, oldver, oldarch, newid, newver, newarch) = i
137 if not seen.has_key(oldid):
139 print "Removing %s %s on %s (ifo %s/%s)" % (package, oldver, oldarch, newver, newarch)
140 projectB.query("DELETE FROM bin_associations WHERE suite = %s AND bin = %s" % (suite_id, oldid))
142 print "%s %s on %s also superceded by %s/%s" % (package, oldver, oldarch, newver, newarch)
144 # If something has moved from one component to another we need to
145 # clean out the old versions here. The rest of jenna won't do this
146 # because it works on a per-component level for flexibility.
148 def clean_suite (suite):
149 print "Cleaning out packages for %s..." % (suite)
151 suite_id = db_access.get_suite_id(suite)
152 q = projectB.query("""
153 SELECT b.id, b.package, a.arch_string, b.version, l.path, f.filename, c.name
154 FROM binaries b, bin_associations ba, files f, location l, architecture a, component c
155 WHERE ba.suite = %s AND ba.bin = b.id AND b.file = f.id AND
156 f.location = l.id AND l.component = c.id AND b.architecture = a.id
158 SELECT s.id, s.source, 'source', s.version, l.path, f.filename, c.name
159 FROM source s, src_associations sa, files f, location l, component c
160 WHERE sa.suite = %s AND sa.source = s.id AND s.file = f.id AND
161 f.location = l.id AND l.component = c.id;""" % (suite_id, suite_id));
165 (id, package, architecture, version, path, filename, component) = i;
166 filename = path + filename;
167 if architecture == "source":
168 delete_table = "src_associations";
169 delete_col = "source";
171 delete_table = "bin_associations";
173 key = "%s~%s" % (package, architecture);
174 if os.path.exists(filename):
176 (other_version, other_component, other_id) = d[key];
177 if apt_pkg.VersionCompare(version, other_version) != 1:
178 (keep_version, keep_component) = (other_version, other_component)
179 (delete_id, delete_version, delete_component) = (id, version, component)
181 (keep_version, keep_component) = (version, component)
182 (delete_id, delete_version, delete_component) = (other_id, other_version, other_component)
183 d[key] = (version, component, id);
184 if not Cnf.Find("Suite::%s::Untouchable" % (suite)):
185 print "deleting %s on %s (%s [%s]) in favour of newer version %s [%s]..." \
186 % (package, architecture, delete_version, delete_component, keep_version, keep_component);
187 projectB.query("DELETE FROM %s WHERE suite = %s AND %s = %s" % (delete_table, suite_id, delete_col, delete_id));
189 print "[untouchable] would delete %s on %s (%s [%s]) in favour of newer version %s [%s]..." \
190 % (package, architecture, delete_version, delete_component, keep_version, keep_component);
192 d[key] = (version, component, id);
194 if not Cnf.Find("Suite::%s::Untouchable" % (suite)):
195 sys.stderr.write("WARNING: deleting %s because it doesn't exist.\n" % (filename));
196 projectB.query("DELETE FROM %s WHERE suite = %s AND %s = %s" % (delete_table, suite_id, delete_col, delete_id));
198 sys.stderr.write("WARNING: [untouchable] would delete %s because it doesn't exist.\n" % (filename));
200 #########################################################################################
203 global Cnf, projectB;
204 dislocated_files = {};
208 Cnf = apt_pkg.newConfiguration();
209 apt_pkg.ReadConfigFileISC(Cnf,utils.which_conf_file());
211 Arguments = [('a',"architecture","Jenna::Options::Architecture", "HasArg"),
212 ('c',"component","Jenna::Options::Component", "HasArg"),
213 ('d',"debug","Jenna::Options::Debug", "IntVal"),
214 ('h',"help","Jenna::Options::Help"),
215 ('s',"suite", "Jenna::Options::Suite", "HasArg"),
216 ('v',"verbose","Jenna::Options::Verbose"),
217 ('V',"version","Jenna::Options::Version")];
219 apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv);
221 projectB = pg.connect(Cnf["DB::Name"], Cnf["DB::Host"], int(Cnf["DB::Port"]));
222 db_access.init(Cnf, projectB);
224 if Cnf["Jenna::Options::Suite"] == "":
225 Cnf["Jenna::Options::Suite"] = string.join(Cnf.SubTree("Suite").List());
226 for suite in string.split(Cnf["Jenna::Options::Suite"]):
227 suite = string.lower(suite);
228 if suite == 'stable':
229 print "Undoing dislocation..."
230 dislocated_files = claire.find_dislocated_stable(Cnf, projectB);
232 dislocated_files = {};
234 clean_duplicate_packages(suite)
235 components = Cnf["Jenna::Options::Component"];
236 if not Cnf.has_key("Suite::%s::Components" % (suite)):
239 components = string.join(Cnf.SubTree("Suite::%s::Components" % (suite)).List());
240 for component in string.split(components):
241 component = string.lower(component)
242 architectures = Cnf["Jenna::Options::Architecture"];
243 if architectures == "":
244 architectures = string.join(Cnf.SubTree("Suite::%s::Architectures" % (suite)).List());
245 for architecture in string.split(architectures):
246 architecture = string.lower(architecture)
247 if architecture == "all":
249 if architecture == "source":
250 print "Processing dists/%s/%s/%s..." % (suite, component, architecture);
251 output = utils.open_file("%s/%s_%s_%s.list" % (Cnf["Dir::ListsDir"], suite, component, architecture), "w")
252 generate_src_list(suite, component, output, dislocated_files);
255 print "Processing dists/%s/%s/binary-%s..." % (suite, component, architecture);
256 output = utils.open_file("%s/%s_%s_binary-%s.list" % (Cnf["Dir::ListsDir"], suite, component, architecture), "w");
257 generate_bin_list(suite, component, architecture, output, "deb", dislocated_files);
259 if component == "main" and (suite == "unstable" or suite == "testing"): # FIXME: must be a cleaner way to say debian-installer is main only?
260 print "Processing dists/%s/%s/debian-installer/binary-%s..." % (suite,component, architecture);
261 output = utils.open_file("%s/%s_%s_debian-installer_binary-%s.list" % (Cnf["Dir::ListsDir"], suite, component, architecture), "w");
262 generate_bin_list(suite, component, architecture, output, "udeb", dislocated_files);
265 #########################################################################################
267 if __name__ == '__main__':