]> git.decadent.org.uk Git - dak.git/blobdiff - shania
Add new top level directories
[dak.git] / shania
diff --git a/shania b/shania
index 7497b630530664149282a26075729788fe9eaf55..74a76055a02eab4c063a581be84e17df81c1cced 100755 (executable)
--- a/shania
+++ b/shania
@@ -1,8 +1,8 @@
 #!/usr/bin/env python
 
 # Clean incoming of old unused files
-# Copyright (C) 2000, 2001  James Troup <james@nocrew.org>
-# $Id: shania,v 1.3 2001-03-02 02:43:49 troup Exp $
+# Copyright (C) 2000, 2001, 2002  James Troup <james@nocrew.org>
+# $Id: shania,v 1.18 2005-03-06 21:51:51 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
 
-# Caveat Emptor: If run with -m/--mail argument, expects to be in
-# Incoming/REJECT or somewhere with .reason files.
-
 ################################################################################
 
-import os, re, stat, string, sys, time
-import utils
-import apt_pkg;
+# <aj> Bdale, a ham-er, and the leader,
+# <aj> Willy, a GCC maintainer,
+# <aj> Lamont-work, 'cause he's the top uploader....
+# <aj>         Penguin Puff' save the day!
+# <aj> Porting code, trying to build the world,
+# <aj> Here they come just in time...
+# <aj>         The Penguin Puff' Guys!
+# <aj> [repeat]
+# <aj> Penguin Puff'!
+# <aj> willy: btw, if you don't maintain gcc you need to start, since
+#      the lyrics fit really well that way
 
 ################################################################################
 
-re_ischanges = re.compile(r"\.changes$")
-re_isdsc = re.compile(r"\.dsc$")
+import os, stat, sys, time;
+import utils;
+import apt_pkg;
 
 ################################################################################
 
-def file_to_string (filename):
-    try:
-        file = utils.open_file(filename, 'r');
-    except utils.cant_open_exc:
-        return "";
-
-    contents = "";
-    for line in file.readlines():
-        contents = contents + line;
-    return contents;
+Cnf = None;
+Options = None;
+del_dir = None;
+delete_date = None;
 
 ################################################################################
 
-def main ():
-    Cnf = None;
-    all_files = {};
-    changes_files = [];
+def usage (exit_code=0):
+    print """Usage: shania [OPTIONS]
+Clean out incoming directories.
 
-    apt_pkg.init();
-    
-    Cnf = apt_pkg.newConfiguration();
-    apt_pkg.ReadConfigFileISC(Cnf,utils.which_conf_file());
+  -d, --days=DAYS            remove anything older than DAYS old
+  -i, --incoming=INCOMING    the incoming directory to clean
+  -n, --no-action            don't do anything
+  -v, --verbose              explain what is being done
+  -h, --help                 show this help and exit"""
 
-    Arguments = [('D',"debug","Shania::Options::Debug", "IntVal"),
-                 ('h',"help","Shania::Options::Help"),
-                 ('V',"version","Shania::Options::Version"),
-                 ('d',"days","Shania::Options::Days", "IntVal"),
-                 ('i',"incoming","Shania::Options::Incoming", "HasArg"),
-                 ('m',"mail","Shania::Options::Mail"),
-                 ('n',"no-action","Shania::Options::No-Action"),
-                 ('v',"verbose","Shania::Options::Verbose")];
+    sys.exit(exit_code)
 
-    apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv);
+################################################################################
 
-    delete_date = int(time.time())-(int(Cnf["Shania::Options::Days"])*84600);
-    del_dir = Cnf["Dir::Morgue"] + '/' + Cnf["Shania::MorgueSubDir"];
+def init ():
+    global delete_date, del_dir;
 
-    if not os.path.exists(del_dir):
-        sys.stderr.write("W: Creating morgue directory '%s'.\n" % (del_dir));
-        os.mkdir(del_dir);
-    elif not os.path.isdir(del_dir):
-        sys.stderr.write("E: %s must be a directory.\n" % (del_dir));
+    delete_date = int(time.time())-(int(Options["Days"])*84600);
 
-    incoming = Cnf["Shania::Options::Incoming"];
-    if incoming == "":
-        incoming = Cnf["Dir::IncomingDir"];
+    # Ensure a directory exists to remove files to
+    if not Options["No-Action"]:
+        date = time.strftime("%Y-%m-%d");
+        del_dir = Cnf["Dir::Morgue"] + '/' + Cnf["Shania::MorgueSubDir"] + '/' + date;
+        if not os.path.exists(del_dir):
+            os.makedirs(del_dir, 02775);
+        if not os.path.isdir(del_dir):
+            utils.fubar("%s must be a directory." % (del_dir));
 
+    # Move to the directory to clean
+    incoming = Options["Incoming"];
+    if incoming == "":
+        incoming = Cnf["Dir::Queue::Unchecked"];
     os.chdir(incoming);
 
+# Remove a file to the morgue
+def remove (file):
+    if os.access(file, os.R_OK):
+        dest_filename = del_dir + '/' + os.path.basename(file);
+        # If the destination file exists; try to find another filename to use
+        if os.path.exists(dest_filename):
+            dest_filename = utils.find_next_free(dest_filename, 10);
+        utils.move(file, dest_filename, 0660);
+    else:
+        utils.warn("skipping '%s', permission denied." % (os.path.basename(file)));
+
+# Removes any old files.
+# [Used for Incoming/REJECT]
+#
+def flush_old ():
+    for file in os.listdir('.'):
+        if os.path.isfile(file):
+            if os.stat(file)[stat.ST_MTIME] < delete_date:
+                if Options["No-Action"]:
+                    print "I: Would delete '%s'." % (os.path.basename(file));
+                else:
+                    if Options["Verbose"]:
+                        print "Removing '%s' (to '%s')."  % (os.path.basename(file), del_dir);
+                    remove(file);
+            else:
+                if Options["Verbose"]:
+                    print "Skipping, too new, '%s'." % (os.path.basename(file));
+
+# Removes any files which are old orphans (not associated with a valid .changes file).
+# [Used for Incoming]
+#
+def flush_orphans ():
+    all_files = {};
+    changes_files = [];
+
     # Build up the list of all files in the directory
     for i in os.listdir('.'):
         if os.path.isfile(i):
             all_files[i] = 1;
-            if re_ischanges.search(i) != None:
+            if i.endswith(".changes"):
                 changes_files.append(i);
 
     # Proces all .changes and .dsc files.
     for changes_filename in changes_files:
         try:
-            changes = utils.parse_changes(changes_filename, 0)
-        except:
-            continue;
-        try:
-            files = utils.build_file_list(changes, "");
+            changes = utils.parse_changes(changes_filename);
+            files = utils.build_file_list(changes);
         except:
+            utils.warn("error processing '%s'; skipping it. [Got %s]" % (changes_filename, sys.exc_type));
             continue;
 
         dsc_files = {};
         for file in files.keys():
-            if re_isdsc.search(file) != None:
+            if file.endswith(".dsc"):
                 try:
-                    dsc = utils.parse_changes(file, 0)
+                    dsc = utils.parse_changes(file);
+                    dsc_files = utils.build_file_list(dsc, is_a_dsc=1);
                 except:
-                    continue;
-                try:
-                    dsc_files = utils.build_file_list(dsc, 1)
-                except:
-                    continue;
-
-        # If passed -m/--mail, assume in REJECT/ and send appropriate mails
-        if Cnf["Shania::Options::Mail"]:
-            reason_filename = re_ischanges.sub('.reason', changes_filename);
-            if not os.access(reason_filename, os.R_OK):
-                sys.stderr.write("W: %s lacks a (readable) reason file ('%s').\n" % (changes_filename, reason_filename));
-                continue;
-            
-            if os.stat(reason_filename)[stat.ST_MTIME] > delete_date:
-                # Ensure the files aren't later deleted.
-                for keys in (files.keys(), dsc_files.keys(), changes_filename, reason_filename):
-                    for i in keys:
-                        if all_files.has_key(i):
-                            del all_files[i];
-            
-                # Grab a copy of the .changes and .reason files for inclusion in the mail
-                try:
-                    changes_contents = file_to_string(changes_filename);
-                except utils.cant_open_exc:
-                    sys.stderr.write("W: %s lacks a (readable) changes file ('%s').\n" % (changes_filename, changes_filename));
+                    utils.warn("error processing '%s'; skipping it. [Got %s]" % (file, sys.exc_type));
                     continue;
 
-                reason_contents = file_to_string(reason_filename);
-
-                # Fix the maintainer address to be RFC-822 compatible
-                (changes["maintainer822"], changes["maintainername"], changes["maintaineremail"]) = utils.fix_maintainer (changes["maintainer"])
-
-                if Cnf["Shania::Options::No-Action"]:
-                    print "Would send a reminder email to %s." % (changes["maintainer822"]);
-                else: # FIXME: need msg to be configurable
-                    mail_message = """Return-Path: %s
-From: %s
-To: %s
-Bcc: troup@auric.debian.org
-Subject: Reminder: %s was rejected
-
-This is an automated reminder.  Your Debian upload was rejected.  Its
-files are in %s/REJECT on %s.
-
-If the upload has been superceded, please delete it.  If not, please
-correct the error.  You do not have to reupload good files; simply
-move them from incoming/REJECT to incoming.  Do erase any bad files.
-This reminder is sent on Monday mornings.  After two reminders, the
-upload is deleted.
-
-----------------------------------------------------------------------
-%s
-----------------------------------------------------------------------
-
-----------------------------------------------------------------------
-%s
-----------------------------------------------------------------------
-
---
-Debian distribution maintenance software
-""" % (Cnf["Dinstall::MyEmailAddress"], Cnf["Dinstall::MyEmailAddress"], changes["maintainer822"], changes_filename, Cnf["Dir::IncomingDir"], Cnf["Archive::%s::OriginServer" % (utils.where_am_i())], changes_contents, reason_contents)
-                    utils.send_mail(mail_message, "");
-                    if Cnf["Shania::Options::Verbose"]:
-                        print "Sent reminder email to %s." % (changes["maintainer822"]);
-        else:
-            # Ensure the files aren't deleted
-            keys = [];
-            for i in (files.keys(), dsc_files.keys(), [changes_filename]):
-                keys.extend(i);
-            for key in keys:
-                if all_files.has_key(key):
-                    del all_files[key];
-
-    # Anthing left at this stage is not referenced by a .changes or
-    # .dsc and should be deleted if old enough.
+        # Ensure all the files we've seen aren't deleted
+        keys = [];
+        for i in (files.keys(), dsc_files.keys(), [changes_filename]):
+            keys.extend(i);
+        for key in keys:
+            if all_files.has_key(key):
+                if Options["Verbose"]:
+                    print "Skipping, has parents, '%s'." % (key);
+                del all_files[key];
+
+    # Anthing left at this stage is not referenced by a .changes (or
+    # a .dsc) and should be deleted if old enough.
     for file in all_files.keys():
         if os.stat(file)[stat.ST_MTIME] < delete_date:
-            if Cnf["Shania::Options::No-Action"]:
-                print "Would delete '%s'." % (os.path.basename(file));
+            if Options["No-Action"]:
+                print "I: Would delete '%s'." % (os.path.basename(file));
             else:
-                if Cnf["Shania::Options::Verbose"]:
+                if Options["Verbose"]:
                     print "Removing '%s' (to '%s')."  % (os.path.basename(file), del_dir);
-                utils.move(file, del_dir);
+                remove(file);
         else:
-            if Cnf["Shania::Options::Verbose"]:
+            if Options["Verbose"]:
                 print "Skipping, too new, '%s'." % (os.path.basename(file));
 
+################################################################################
+
+def main ():
+    global Cnf, Options;
+
+    Cnf = utils.get_conf()
+
+    for i in ["Help", "Incoming", "No-Action", "Verbose" ]:
+       if not Cnf.has_key("Shania::Options::%s" % (i)):
+           Cnf["Shania::Options::%s" % (i)] = "";
+    if not Cnf.has_key("Shania::Options::Days"):
+       Cnf["Shania::Options::Days"] = "14";
+
+    Arguments = [('h',"help","Shania::Options::Help"),
+                 ('d',"days","Shania::Options::Days", "IntLevel"),
+                 ('i',"incoming","Shania::Options::Incoming", "HasArg"),
+                 ('n',"no-action","Shania::Options::No-Action"),
+                 ('v',"verbose","Shania::Options::Verbose")];
+
+    apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv);
+    Options = Cnf.SubTree("Shania::Options")
+
+    if Options["Help"]:
+       usage();
+
+    init();
+
+    if Options["Verbose"]:
+        print "Processing incoming..."
+    flush_orphans();
+
+    reject = Cnf["Dir::Queue::Reject"]
+    if os.path.exists(reject) and os.path.isdir(reject):
+        if Options["Verbose"]:
+            print "Processing incoming/REJECT..."
+        os.chdir(reject);
+        flush_old();
+
 #######################################################################################
 
 if __name__ == '__main__':
-    main()
+    main();