]> git.decadent.org.uk Git - dak.git/blob - dak/clean_queues.py
Fixes
[dak.git] / dak / clean_queues.py
1 #!/usr/bin/env python
2
3 """ Clean incoming of old unused files """
4 # Copyright (C) 2000, 2001, 2002, 2006  James Troup <james@nocrew.org>
5
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20 ################################################################################
21
22 # <aj> Bdale, a ham-er, and the leader,
23 # <aj> Willy, a GCC maintainer,
24 # <aj> Lamont-work, 'cause he's the top uploader....
25 # <aj>         Penguin Puff' save the day!
26 # <aj> Porting code, trying to build the world,
27 # <aj> Here they come just in time...
28 # <aj>         The Penguin Puff' Guys!
29 # <aj> [repeat]
30 # <aj> Penguin Puff'!
31 # <aj> willy: btw, if you don't maintain gcc you need to start, since
32 #      the lyrics fit really well that way
33
34 ################################################################################
35
36 import os, stat, sys, time
37 import apt_pkg
38 from daklib import utils
39
40 ################################################################################
41
42 Cnf = None
43 Options = None
44 del_dir = None
45 delete_date = None
46
47 ################################################################################
48
49 def usage (exit_code=0):
50     print """Usage: dak clean-queues [OPTIONS]
51 Clean out incoming directories.
52
53   -d, --days=DAYS            remove anything older than DAYS old
54   -i, --incoming=INCOMING    the incoming directory to clean
55   -n, --no-action            don't do anything
56   -v, --verbose              explain what is being done
57   -h, --help                 show this help and exit"""
58
59     sys.exit(exit_code)
60
61 ################################################################################
62
63 def init ():
64     global delete_date, del_dir
65
66     delete_date = int(time.time())-(int(Options["Days"])*84600)
67
68     # Ensure a directory exists to remove files to
69     if not Options["No-Action"]:
70         date = time.strftime("%Y-%m-%d")
71         del_dir = Cnf["Dir::Morgue"] + '/' + Cnf["Clean-Queues::MorgueSubDir"] + '/' + date
72         if not os.path.exists(del_dir):
73             os.makedirs(del_dir, 02775)
74         if not os.path.isdir(del_dir):
75             utils.fubar("%s must be a directory." % (del_dir))
76
77     # Move to the directory to clean
78     incoming = Options["Incoming"]
79     if incoming == "":
80         incoming = Cnf["Dir::Queue::Unchecked"]
81     os.chdir(incoming)
82
83 # Remove a file to the morgue
84 def remove (f):
85     if os.access(f, os.R_OK):
86         dest_filename = del_dir + '/' + os.path.basename(f)
87         # If the destination file exists; try to find another filename to use
88         if os.path.exists(dest_filename):
89             dest_filename = utils.find_next_free(dest_filename, 10)
90         utils.move(f, dest_filename, 0660)
91     else:
92         utils.warn("skipping '%s', permission denied." % (os.path.basename(f)))
93
94 # Removes any old files.
95 # [Used for Incoming/REJECT]
96 #
97 def flush_old ():
98     for f in os.listdir('.'):
99         if os.path.isfile(f):
100             if os.stat(f)[stat.ST_MTIME] < delete_date:
101                 if Options["No-Action"]:
102                     print "I: Would delete '%s'." % (os.path.basename(f))
103                 else:
104                     if Options["Verbose"]:
105                         print "Removing '%s' (to '%s')."  % (os.path.basename(f), del_dir)
106                     remove(f)
107             else:
108                 if Options["Verbose"]:
109                     print "Skipping, too new, '%s'." % (os.path.basename(f))
110
111 # Removes any files which are old orphans (not associated with a valid .changes file).
112 # [Used for Incoming]
113 #
114 def flush_orphans ():
115     all_files = {}
116     changes_files = []
117
118     # Build up the list of all files in the directory
119     for i in os.listdir('.'):
120         if os.path.isfile(i):
121             all_files[i] = 1
122             if i.endswith(".changes"):
123                 changes_files.append(i)
124
125     # Proces all .changes and .dsc files.
126     for changes_filename in changes_files:
127         try:
128             changes = utils.parse_changes(changes_filename)
129             files = utils.build_file_list(changes)
130         except:
131             utils.warn("error processing '%s'; skipping it. [Got %s]" % (changes_filename, sys.exc_type))
132             continue
133
134         dsc_files = {}
135         for f in files.keys():
136             if f.endswith(".dsc"):
137                 try:
138                     dsc = utils.parse_changes(f)
139                     dsc_files = utils.build_file_list(dsc, is_a_dsc=1)
140                 except:
141                     utils.warn("error processing '%s'; skipping it. [Got %s]" % (f, sys.exc_type))
142                     continue
143
144         # Ensure all the files we've seen aren't deleted
145         keys = []
146         for i in (files.keys(), dsc_files.keys(), [changes_filename]):
147             keys.extend(i)
148         for key in keys:
149             if all_files.has_key(key):
150                 if Options["Verbose"]:
151                     print "Skipping, has parents, '%s'." % (key)
152                 del all_files[key]
153
154     # Anthing left at this stage is not referenced by a .changes (or
155     # a .dsc) and should be deleted if old enough.
156     for f in all_files.keys():
157         if os.stat(f)[stat.ST_MTIME] < delete_date:
158             if Options["No-Action"]:
159                 print "I: Would delete '%s'." % (os.path.basename(f))
160             else:
161                 if Options["Verbose"]:
162                     print "Removing '%s' (to '%s')."  % (os.path.basename(f), del_dir)
163                 remove(f)
164         else:
165             if Options["Verbose"]:
166                 print "Skipping, too new, '%s'." % (os.path.basename(f))
167
168 ################################################################################
169
170 def main ():
171     global Cnf, Options
172
173     Cnf = utils.get_conf()
174
175     for i in ["Help", "Incoming", "No-Action", "Verbose" ]:
176         if not Cnf.has_key("Clean-Queues::Options::%s" % (i)):
177             Cnf["Clean-Queues::Options::%s" % (i)] = ""
178     if not Cnf.has_key("Clean-Queues::Options::Days"):
179         Cnf["Clean-Queues::Options::Days"] = "14"
180
181     Arguments = [('h',"help","Clean-Queues::Options::Help"),
182                  ('d',"days","Clean-Queues::Options::Days", "IntLevel"),
183                  ('i',"incoming","Clean-Queues::Options::Incoming", "HasArg"),
184                  ('n',"no-action","Clean-Queues::Options::No-Action"),
185                  ('v',"verbose","Clean-Queues::Options::Verbose")]
186
187     apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv)
188     Options = Cnf.SubTree("Clean-Queues::Options")
189
190     if Options["Help"]:
191         usage()
192
193     init()
194
195     if Options["Verbose"]:
196         print "Processing incoming..."
197     flush_orphans()
198
199     reject = Cnf["Dir::Queue::Reject"]
200     if os.path.exists(reject) and os.path.isdir(reject):
201         if Options["Verbose"]:
202             print "Processing incoming/REJECT..."
203         os.chdir(reject)
204         flush_old()
205
206 #######################################################################################
207
208 if __name__ == '__main__':
209     main()