]> git.decadent.org.uk Git - dak.git/blobdiff - jenna
(no commit message)
[dak.git] / jenna
diff --git a/jenna b/jenna
index 5579cfd862670d4d56dfb4f81e0d73d6857874f5..73fdf0cfd437e63a1ac82d354bd9485023b09c3e 100755 (executable)
--- a/jenna
+++ b/jenna
@@ -2,7 +2,7 @@
 
 # Generate file list which is then fed to apt-ftparchive to generate Packages and Sources files
 # Copyright (C) 2000, 2001  James Troup <james@nocrew.org>
-# $Id: jenna,v 1.9 2001-04-03 10:00:52 troup Exp $
+# $Id: jenna,v 1.15 2001-11-18 19:57:58 rmurray Exp $
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
-#######################################################################################
+################################################################################
 
 # BTAF: "GOD *DAMMIT*!!  What the FUCK happened to my free will??"
 #
 # -- http://www.angryflower.com/timelo.gif
 
-#######################################################################################
+################################################################################
 
 import pg, string, os, sys
 import apt_pkg
-import db_access, utils, claire
+import db_access, utils, claire, logging
+
+################################################################################
 
 projectB = None
 Cnf = None
+Logger = None;
+
+################################################################################
+
+def usage (exit_code=0):
+    print """Usage: jenna [OPTION]
+Write out file lists suitable for use with apt-ftparchive.
+
+  -a, --architecture=ARCH   only write file lists for this architecture
+  -c, --component=COMPONENT only write file lists for this component
+  -s, --suite=SUITE         only write file lists for this suite
+  -h, --help                show this help and exit
+
+ARCH, COMPONENT and SUITE can be space seperated lists, e.g.
+    --architecture=\"m68k i386\""""
+    sys.exit(exit_code)
+
+################################################################################
 
 def generate_src_list(suite, component, output, dislocated_files):
     sources = {}
 
     suite_id = db_access.get_suite_id(suite);
-    
+
     if component == "-":
         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"
                            % (suite_id));
@@ -52,7 +72,7 @@ def generate_src_list(suite, component, output, dislocated_files):
         else:
             filename = path + filename;
         if sources.has_key(source):
-            sys.stderr.write("E: %s in %s / %s / source is duplicated.  Gravity wins!\n" % (package, suite, component));
+            utils.warn("%s in %s / %s / source is duplicated." % (source, suite, component));
         else:
             sources[source] = filename;
 
@@ -61,14 +81,14 @@ def generate_src_list(suite, component, output, dislocated_files):
     source_keys.sort();
     for source in source_keys:
         output.write(sources[source]+'\n')
-    
+
 #########################################################################################
 
 def generate_bin_list(suite, component, architecture, output, type, dislocated_files):
     packages = {}
 
     suite_id = db_access.get_suite_id(suite);
-    
+
     if component == "-":
         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));
     else:
@@ -81,10 +101,10 @@ def generate_bin_list(suite, component, architecture, output, type, dislocated_f
         else:
             filename = path + filename;
         if packages.has_key(package):
-            sys.stderr.write("E: %s in %s / %s / %s / %s is duplicated.  Gravity wins!" % (package, suite, component, architecture, type));
+            utils.warn("%s in %s / %s / %s / %s is duplicated." % (package, suite, component, architecture, type));
         else:
             packages[package] = filename;
-        
+
     # Write the list of files out
     package_keys = packages.keys();
     package_keys.sort();
@@ -107,14 +127,48 @@ def generate_bin_list(suite, component, architecture, output, type, dislocated_f
 # <aj> yo momma was SQLin' like a pig last night!
 ##########
 
+# If something has gone from arch:all to arch:any or vice-versa,
+# clean out the old versions here.  The rest of jenna won't do this
+# because it's lame. I have no idea. </aj>
+
+def clean_duplicate_packages(suite):
+    Logger.log(["Cleaning duplicate packages", suite]);
+
+    suite_id = db_access.get_suite_id(suite)
+    q = projectB.query("""
+SELECT b1.package,
+       b1.id, b1.version, a1.arch_string,
+       b2.id, b2.version, a2.arch_string
+  FROM bin_associations ba1, binaries b1, architecture a1,
+       bin_associations ba2, binaries b2, architecture a2
+ WHERE ba1.suite = ba2.suite AND ba1.suite = %s
+   AND ba1.bin = b1.id AND b1.architecture = a1.id
+   AND ba2.bin = b2.id AND b2.architecture = a2.id
+   AND b1.package = b2.package
+   AND (a1.id = a2.id OR a1.arch_string = 'all' OR a2.arch_string = 'all')
+   AND b1.id != b2.id
+   AND versioncmp(b1.version, b2.version) <= 0
+ORDER BY b1.package, b1.version, a1.arch_string;""" % (suite_id))
+
+    ql = q.getresult()
+    seen = {}
+    for i in ql:
+       (package, oldid, oldver, oldarch, newid, newver, newarch) = i
+       if not seen.has_key(oldid):
+           seen[oldid] = newid
+           Logger.log(["Removing", package, oldver, oldarch, newver, newarch]);
+           projectB.query("DELETE FROM bin_associations WHERE suite = %s AND bin = %s" % (suite_id, oldid))
+       else:
+           Logger.log(["Superceded", package, oldver, oldarch, newver, newarch]);
+
 # If something has moved from one component to another we need to
 # clean out the old versions here.  The rest of jenna won't do this
 # because it works on a per-component level for flexibility.
 
 def clean_suite (suite):
-    print "Cleaning out packages for %s..." % (suite)
-    
-    suite_id = db_access.get_suite_id(suite);
+    Logger.log(["Cleaning out packages", suite]);
+
+    suite_id = db_access.get_suite_id(suite)
     q = projectB.query("""
 SELECT b.id, b.package, a.arch_string, b.version, l.path, f.filename, c.name
   FROM binaries b, bin_associations ba, files f, location l, architecture a, component c
@@ -148,63 +202,60 @@ SELECT s.id, s.source, 'source', s.version, l.path, f.filename, c.name
                     (delete_id, delete_version, delete_component) = (other_id, other_version, other_component)
                     d[key] = (version, component, id);
                 if not Cnf.Find("Suite::%s::Untouchable" % (suite)):
-                    print "deleting %s on %s (%s [%s]) in favour of newer version %s [%s]..." \
-                          % (package, architecture, delete_version, delete_component, keep_version, keep_component);
+                    Logger.log(["deleting", package, architecture, delete_version, delete_component, keep_version, keep_component]);
                     projectB.query("DELETE FROM %s WHERE suite = %s AND %s = %s" % (delete_table, suite_id, delete_col, delete_id));
                 else:
-                    print "[untouchable] would delete %s on %s (%s [%s]) in favour of newer version %s [%s]..." \
-                          % (package, architecture, delete_version, delete_component, keep_version, keep_component);
+                    Logger.log(["[untouchable]", package, architecture, delete_version, delete_component, keep_version, keep_component]);
             else:
                 d[key] = (version, component, id);
         else:
-            if not Cnf.Find("Suite::%s::Untouchable" % (suite)):
-                sys.stderr.write("WARNING: deleting %s because it doesn't exist.\n" % (filename));
-                projectB.query("DELETE FROM %s WHERE suite = %s AND %s = %s" % (delete_table, suite_id, delete_col, delete_id));
-            else:
-                sys.stderr.write("WARNING: [untouchable] would delete %s because it doesn't exist.\n" % (filename));
+            utils.warn("%s is in %s but doesn't appear to exist?" % (filename, suite));
 
 #########################################################################################
 
 def main():
-    global Cnf, projectB;
+    global Cnf, projectB, Logger;
     dislocated_files = {};
-    
-    apt_pkg.init();
-    
-    Cnf = apt_pkg.newConfiguration();
-    apt_pkg.ReadConfigFileISC(Cnf,utils.which_conf_file());
+
+    Cnf = utils.get_conf()
 
     Arguments = [('a',"architecture","Jenna::Options::Architecture", "HasArg"),
                  ('c',"component","Jenna::Options::Component", "HasArg"),
-                 ('d',"debug","Jenna::Options::Debug", "IntVal"),
                  ('h',"help","Jenna::Options::Help"),
-                 ('s',"suite", "Jenna::Options::Suite", "HasArg"),
-                 ('v',"verbose","Jenna::Options::Verbose"),
-                 ('V',"version","Jenna::Options::Version")];
+                 ('s',"suite", "Jenna::Options::Suite", "HasArg")];
+
+    for i in ["architecture", "component", "help", "suite" ]:
+       if not Cnf.has_key("Jenna::Options::%s" % (i)):
+           Cnf["Jenna::Options::%s" % (i)] = "";
 
     apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv);
+    Options = Cnf.SubTree("Jenna::Options");
+
+    if Options["Help"]:
+        usage();
 
     projectB = pg.connect(Cnf["DB::Name"], Cnf["DB::Host"], int(Cnf["DB::Port"]));
     db_access.init(Cnf, projectB);
+    Logger = logging.Logger(Cnf, "jenna");
 
-    if Cnf["Jenna::Options::Suite"] == "":
-        Cnf["Jenna::Options::Suite"] = string.join(Cnf.SubTree("Suite").List());
-    for suite in string.split(Cnf["Jenna::Options::Suite"]):
+    if Options["Suite"] == "":
+        Options["Suite"] = string.join(Cnf.SubTree("Suite").List());
+    for suite in string.split(Options["Suite"]):
         suite = string.lower(suite);
         if suite == 'stable':
-            print "Undoing dislocation..."
             dislocated_files = claire.find_dislocated_stable(Cnf, projectB);
         else:
             dislocated_files = {};
         clean_suite(suite);
-        components = Cnf["Jenna::Options::Component"];
+       clean_duplicate_packages(suite)
+        components = Options["Component"];
         if not Cnf.has_key("Suite::%s::Components" % (suite)):
             components = "-";
         if components == "":
             components = string.join(Cnf.SubTree("Suite::%s::Components" % (suite)).List());
         for component in string.split(components):
             component = string.lower(component)
-            architectures = Cnf["Jenna::Options::Architecture"];
+            architectures = Options["Architecture"];
             if architectures == "":
                 architectures = string.join(Cnf.SubTree("Suite::%s::Architectures" % (suite)).List());
             for architecture in string.split(architectures):
@@ -212,20 +263,21 @@ def main():
                 if architecture == "all":
                     continue
                 if architecture == "source":
-                    print "Processing dists/%s/%s/%s..." % (suite, component, architecture);
+                    Logger.log(["Processing dists/%s/%s/%s..." % (suite, component, architecture)]);
                     output = utils.open_file("%s/%s_%s_%s.list" % (Cnf["Dir::ListsDir"], suite, component, architecture), "w")
                     generate_src_list(suite, component, output, dislocated_files);
                     output.close();
                 else:
-                    print "Processing dists/%s/%s/binary-%s..." % (suite, component, architecture);
+                    Logger.log(["Processing dists/%s/%s/binary-%s..." % (suite, component, architecture)]);
                     output = utils.open_file("%s/%s_%s_binary-%s.list" % (Cnf["Dir::ListsDir"], suite, component, architecture), "w");
                     generate_bin_list(suite, component, architecture, output, "deb", dislocated_files);
                     output.close();
-                    if component == "main" and (suite == "unstable" or suite == "testing"): # FIXME: must be a cleaner way to say debian-installer is main only?
-                        print "Processing dists/%s/%s/debian-installer/binary-%s..." % (suite,component, architecture);
+                    if component == "main" and (suite == "unstable" or suite == "testing") and Cnf.has_key("Section::debian-installer"): # FIXME: must be a cleaner way to say debian-installer is main only?
+                        Logger.log(["Processing dists/%s/%s/debian-installer/binary-%s..." % (suite,component, architecture)]);
                         output = utils.open_file("%s/%s_%s_debian-installer_binary-%s.list" % (Cnf["Dir::ListsDir"], suite, component, architecture), "w");
                         generate_bin_list(suite, component, architecture, output, "udeb", dislocated_files);
                         output.close();
+    Logger.close();
 
 #########################################################################################