# 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 $
+# $Id: shania,v 1.4 2001-06-22 23:23:59 troup 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 os, re, stat, string, sys, time, traceback
import utils
import apt_pkg;
################################################################################
-re_ischanges = re.compile(r"\.changes$")
-re_isdsc = re.compile(r"\.dsc$")
+# ``where security is not an option''
################################################################################
-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;
################################################################################
-def main ():
- Cnf = None;
- all_files = {};
- changes_files = [];
-
- apt_pkg.init();
+def init ():
+ global delete_date, del_dir;
- Cnf = apt_pkg.newConfiguration();
- apt_pkg.ReadConfigFileISC(Cnf,utils.which_conf_file());
-
- 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")];
-
- 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"];
-
- 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));
-
- incoming = Cnf["Shania::Options::Incoming"];
+ delete_date = int(time.time())-(int(Options["Days"])*84600);
+
+ # Ensure a directory exists to remove files to
+ if not Options["No-Action"]:
+ date = time.strftime("%Y-%m-%d", time.localtime(time.time()));
+ 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::IncomingDir"];
-
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);
+ 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[-8:] == ".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, "");
except:
+ utils.warn("error processing '%s'; skipping it. [Got %s]" % (file, sys.exc_type));
continue;
dsc_files = {};
for file in files.keys():
- if re_isdsc.search(file) != None:
+ if file[-4:] == ".dsc":
try:
dsc = utils.parse_changes(file, 0)
- except:
- continue;
- try:
dsc_files = utils.build_file_list(dsc, 1)
except:
+ utils.warn("error processing '%s'; skipping it. [Got %s]" % (file, sys.exc_type));
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));
- 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;
+
+ apt_pkg.init();
+
+ Cnf = apt_pkg.newConfiguration();
+ apt_pkg.ReadConfigFileISC(Cnf,utils.which_conf_file());
+
+ 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"),
+ ('n',"no-action","Shania::Options::No-Action"),
+ ('v',"verbose","Shania::Options::Verbose")];
+
+ apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv);
+ Options = Cnf.SubTree("Shania::Options")
+
+ init ();
+
+ if Options["Verbose"]:
+ print "Processing incoming..."
+ flush_orphans();
+
+ if os.path.exists("REJECT") and os.path.isdir("REJECT"):
+ if Options["Verbose"]:
+ print "Processing incoming/REJECT..."
+ os.chdir("REJECT");
+ flush_old();
#######################################################################################