3 # Check for obsolete binary packages
4 # Copyright (C) 2000, 2001, 2002, 2003 James Troup <james@nocrew.org>
5 # $Id: rene,v 1.20 2003-03-14 19:03:32 troup 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 # ``If you're claiming that's a "problem" that needs to be "fixed",
24 # you might as well write some letters to God about how unfair entropy
25 # is while you're at it.'' -- 20020802143104.GA5628@azure.humbug.org.au
27 ## TODO: fix NBS looping for version, implement Dubious NBS, fix up output of duplicate source package stuff, improve experimental ?, add support for non-US ?, add overrides, avoid ANAIS for duplicated packages
29 ################################################################################
31 import commands, pg, os, string, sys, tempfile, time;
32 import utils, db_access;
35 ################################################################################
40 no_longer_in_suite = {}; # Really should be static to add_nbs, but I'm lazy
42 ################################################################################
44 def usage(exit_code=0):
46 Check for obsolete or duplicated packages.
48 -h, --help show this help and exit."""
51 ################################################################################
53 def add_nbs(nbs_d, source, version, package):
54 # Ensure the package is still unstable (someone may have already removed it)
55 if no_longer_in_suite.has_key(package):
58 q = projectB.query("SELECT b.id FROM binaries b, bin_associations ba WHERE ba.bin = b.id AND ba.suite = %s AND b.package = '%s' LIMIT 1" % (suite_id, package));
60 no_longer_in_suite[package] = "";
63 if not nbs_d.has_key(source):
65 if not nbs_d[source].has_key(version):
66 nbs_d[source][version] = {};
67 nbs_d[source][version][package] = "";
69 ################################################################################
72 global Cnf, projectB, suite_id;
74 Cnf = utils.get_conf();
76 Arguments = [('h',"help","Rene::Options::Help")];
78 if not Cnf.has_key("Rene::Options::%s" % (i)):
79 Cnf["Rene::Options::%s" % (i)] = "";
81 apt_pkg.ParseCommandLine(Cnf, Arguments, sys.argv);
83 Options = Cnf.SubTree("Rene::Options")
87 projectB = pg.connect(Cnf["DB::Name"], Cnf["DB::Host"], int(Cnf["DB::Port"]));
88 db_access.init(Cnf, projectB);
101 suite_id = db_access.get_suite_id(suite);
105 # Initalize a large hash table of all binary packages
106 before = time.time();
107 sys.stderr.write("[Getting a list of binary packages in %s..." % (suite));
108 q = projectB.query("SELECT distinct b.package FROM binaries b, bin_associations ba WHERE ba.suite = 5 AND ba.bin = b.id");
110 sys.stderr.write("done. (%d seconds)]\n" % (int(time.time()-before)));
112 bins_in_suite[i[0]] = "";
114 components = Cnf.ValueList("Suite::%s::Components" % (suite));
115 for component in components:
116 filename = "%s/dists/%s/%s/source/Sources.gz" % (Cnf["Dir::Root"], suite, component);
117 # apt_pkg.ParseTagFile needs a real file handle and can't handle a GzipFile instance...
118 temp_filename = tempfile.mktemp();
119 fd = os.open(temp_filename, os.O_RDWR|os.O_CREAT|os.O_EXCL, 0700);
121 (result, output) = commands.getstatusoutput("gunzip -c %s > %s" % (filename, temp_filename));
123 sys.stderr.write("Gunzip invocation failed!\n%s\n" % (output));
125 sources = utils.open_file(temp_filename);
126 Sources = apt_pkg.ParseTagFile(sources);
127 while Sources.Step():
128 source = Sources.Section.Find('Package');
129 source_version = Sources.Section.Find('Version');
130 architecture = Sources.Section.Find('Architecture');
131 binaries = Sources.Section.Find('Binary');
132 binaries_list = map(string.strip, binaries.split(','));
134 # Check for binaries not built on any architecture.
135 for binary in binaries_list:
136 if not bins_in_suite.has_key(binary):
137 if not bin_not_built.has_key(source):
138 bin_not_built[source] = {};
139 bin_not_built[source][binary] = "";
141 # Check for packages built on architectures they shouldn't be.
142 if architecture != "any" and architecture != "all":
144 for arch in architecture.split():
145 architectures[arch.strip()] = "";
146 for binary in binaries_list:
147 q = projectB.query("SELECT a.arch_string, b.version FROM binaries b, bin_associations ba, architecture a WHERE ba.suite = %s AND ba.bin = b.id AND b.architecture = a.id AND b.package = '%s'" % (suite_id, binary));
153 if architectures.has_key(arch):
154 versions.append(version);
155 versions.sort(apt_pkg.VersionCompare);
157 latest_version = versions.pop()
159 latest_version = None;
160 # Check for 'invalid' architectures
165 if not architectures.has_key(arch):
166 if not versions_d.has_key(version):
167 versions_d[version] = [];
168 versions_d[version].append(arch)
171 anais_output += "\n (*) %s_%s [%s]: %s\n" % (binary, latest_version, source, architecture);
172 versions = versions_d.keys();
173 versions.sort(apt_pkg.VersionCompare);
174 for version in versions:
175 arches = versions_d[version];
177 anais_output += " o %s: %s\n" % (version, ", ".join(arches));
179 # Check for duplicated packages and build indices for checking "no source" later
180 source_index = component + '/' + source;
181 if src_pkgs.has_key(source):
182 print " %s is a duplicated source package (%s and %s)" % (source, source_index, src_pkgs[source]);
183 src_pkgs[source] = source_index;
184 for binary in binaries_list:
185 if bin_pkgs.has_key(binary):
186 key = "%s~%s" % (source, bin_pkgs[binary]);
187 if not duplicate_bins.has_key(key):
188 duplicate_bins[key] = [];
189 duplicate_bins[key].append(binary);
190 bin_pkgs[binary] = source;
191 source_binaries[source] = binaries;
192 source_versions[source] = source_version;
195 os.unlink(temp_filename);
197 for component in components:
198 architectures = filter(utils.real_arch, Cnf.ValueList("Suite::%s::Architectures" % (suite)));
199 for architecture in architectures:
200 filename = "%s/dists/%s/%s/binary-%s/Packages" % (Cnf["Dir::Root"], suite, component, architecture);
201 packages = utils.open_file(filename);
202 Packages = apt_pkg.ParseTagFile(packages);
203 while Packages.Step():
204 package = Packages.Section.Find('Package');
205 source = Packages.Section.Find('Source', "");
206 version = Packages.Section.Find('Version');
209 if source.find("(") != -1:
210 m = utils.re_extract_src_version.match(source);
212 version = m.group(2);
213 if not bin_pkgs.has_key(package):
214 if not nbs.has_key(source):
216 if not nbs[source].has_key(package):
217 nbs[source][package] = {};
218 nbs[source][package][version] = "";
223 for source in nbs.keys():
224 for package in nbs[source].keys():
225 versions = nbs[source][package].keys();
226 versions.sort(apt_pkg.VersionCompare);
227 latest_version = versions.pop();
228 source_version = source_versions.get(source,"0");
229 if apt_pkg.VersionCompare(latest_version, source_version) == 0:
230 add_nbs(dubious_nbs, source, latest_version, package);
232 add_nbs(real_nbs, source, latest_version, package);
234 # Check for packages in experimental obsoleted by versions in unstable
235 suite_id = db_access.get_suite_id("unstable");
236 q = projectB.query("""
237 SELECT s.source, s.version AS experimental, s2.version AS unstable
238 FROM src_associations sa, source s, source s2, src_associations sa2
239 WHERE sa.suite = 1 AND sa2.suite = %d AND sa.source = s.id
240 AND sa2.source = s2.id AND s.source = s2.source
241 AND versioncmp(s.version, s2.version) < 0""" % (suite_id));
245 print "Newer version in unstable";
246 print "-------------------------";
249 (source, experimental_version, unstable_version) = i;
250 print " o %s (%s, %s)" % (source, experimental_version, unstable_version);
251 nviu_to_remove.append(source);
253 print "Suggested command:"
254 print " melanie -m \"[rene] NVIU\" -s experimental %s" % (" ".join(nviu_to_remove));
257 print "Not Built from Source";
258 print "---------------------";
262 nbs_keys = real_nbs.keys();
264 for source in nbs_keys:
265 binaries = source_binaries.get(source, "(source does not exist)")
266 print " * %s_%s builds: %s" % (source,
267 source_versions.get(source, "??"),
268 source_binaries.get(source, "(source does not exist)"));
269 print " but no longer builds:"
270 versions = real_nbs[source].keys();
271 versions.sort(apt_pkg.VersionCompare);
272 for version in versions:
273 packages = real_nbs[source][version].keys();
277 if pkg.find("pcmcia") == -1:
278 nbs_to_remove.append(pkg);
279 print " o %s: %s" % (version, ", ".join(packages));
284 print "Suggested command:"
285 print " melanie -m \"[rene] NBS\" -b %s" % (" ".join(nbs_to_remove));
291 print "Unbuilt binary packages";
292 print "-----------------------";
294 keys = bin_not_built.keys();
297 binaries = bin_not_built[source].keys();
299 print " o %s: %s" % (source, ", ".join(binaries));
302 print "Built from multiple source packages";
303 print "-----------------------------------";
305 keys = duplicate_bins.keys();
308 (source_a, source_b) = key.split("~");
309 print " o %s & %s => %s" % (source_a, source_b, ", ".join(duplicate_bins[key]));
312 print "Architecture Not Allowed In Source";
313 print "----------------------------------";
321 dubious_nbs_keys = dubious_nbs.keys();
322 dubious_nbs_keys.sort();
323 for source in dubious_nbs_keys:
324 binaries = source_binaries.get(source, "(source does not exist)")
325 print " * %s_%s builds: %s" % (source,
326 source_versions.get(source, "??"),
327 source_binaries.get(source, "(source does not exist)"));
328 print " won't admit to building:"
329 versions = dubious_nbs[source].keys();
330 versions.sort(apt_pkg.VersionCompare);
331 for version in versions:
332 packages = dubious_nbs[source][version].keys();
334 print " o %s: %s" % (version, ", ".join(packages));
339 ################################################################################
341 if __name__ == '__main__':