]> git.decadent.org.uk Git - dak.git/blob - dak/clean_queues.py
Remove use of Dir::Queue::Unchecked in config file
[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, os.path, stat, sys, time
37 import apt_pkg
38 from daklib import utils
39 from daklib import daklog
40 from daklib.config import Config
41 from daklib.dbconn import get_policy_queue
42
43 ################################################################################
44
45 Options = None
46 Logger = None
47 del_dir = None
48 delete_date = None
49
50 ################################################################################
51
52 def usage (exit_code=0):
53     print """Usage: dak clean-queues [OPTIONS]
54 Clean out incoming directories.
55
56   -d, --days=DAYS            remove anything older than DAYS old
57   -i, --incoming=INCOMING    the incoming directory to clean
58   -n, --no-action            don't do anything
59   -v, --verbose              explain what is being done
60   -h, --help                 show this help and exit"""
61
62     sys.exit(exit_code)
63
64 ################################################################################
65
66 def init (cnf):
67     global delete_date, del_dir
68
69     delete_date = int(time.time())-(int(Options["Days"])*84600)
70     date = time.strftime("%Y-%m-%d")
71     del_dir = os.path.join(cnf["Dir::Morgue"], cnf["Clean-Queues::MorgueSubDir"], date)
72
73     # Ensure a directory exists to remove files to
74     if not Options["No-Action"]:
75         if not os.path.exists(del_dir):
76             os.makedirs(del_dir, 02775)
77         if not os.path.isdir(del_dir):
78             utils.fubar("%s must be a directory." % (del_dir))
79
80     # Move to the directory to clean
81     incoming = Options["Incoming"]
82     if incoming == "":
83         incoming_queue = get_policy_queue('unchecked')
84         if not incoming_queue:
85             utils.fubar("Cannot find 'unchecked' queue")
86         incoming = incoming_queue.path
87
88     try:
89         os.chdir(incoming)
90     except OSError, e:
91         utils.fubar("Cannot chdir to %s" % incoming)
92
93 # Remove a file to the morgue
94 def remove (from_dir, f):
95     fname = os.path.basename(f)
96     if os.access(f, os.R_OK):
97         Logger.log(["move file to morgue", from_dir, fname, del_dir])
98         if Options["Verbose"]:
99             print "Removing '%s' (to '%s')."  % (fname, del_dir)
100         if Options["No-Action"]:
101             return
102
103         dest_filename = os.path.join(del_dir, fname)
104         # If the destination file exists; try to find another filename to use
105         if os.path.exists(dest_filename):
106             dest_filename = utils.find_next_free(dest_filename, 10)
107             Logger.log(["change destination file name", os.path.basename(dest_filename)])
108         utils.move(f, dest_filename, 0660)
109     else:
110         Logger.log(["skipping file because of permission problem", fname])
111         utils.warn("skipping '%s', permission denied." % fname)
112
113 # Removes any old files.
114 # [Used for Incoming/REJECT]
115 #
116 def flush_old ():
117     Logger.log(["check Incoming/REJECT for old files", os.getcwd()])
118     for f in os.listdir('.'):
119         if os.path.isfile(f):
120             if os.stat(f)[stat.ST_MTIME] < delete_date:
121                 remove('Incoming/REJECT', f)
122             else:
123                 if Options["Verbose"]:
124                     print "Skipping, too new, '%s'." % (os.path.basename(f))
125
126 # Removes any files which are old orphans (not associated with a valid .changes file).
127 # [Used for Incoming]
128 #
129 def flush_orphans ():
130     all_files = {}
131     changes_files = []
132
133     Logger.log(["check Incoming for old orphaned files", os.getcwd()])
134     # Build up the list of all files in the directory
135     for i in os.listdir('.'):
136         if os.path.isfile(i):
137             all_files[i] = 1
138             if i.endswith(".changes"):
139                 changes_files.append(i)
140
141     # Proces all .changes and .dsc files.
142     for changes_filename in changes_files:
143         try:
144             changes = utils.parse_changes(changes_filename)
145             files = utils.build_file_list(changes)
146         except:
147             utils.warn("error processing '%s'; skipping it. [Got %s]" % (changes_filename, sys.exc_type))
148             continue
149
150         dsc_files = {}
151         for f in files.keys():
152             if f.endswith(".dsc"):
153                 try:
154                     dsc = utils.parse_changes(f, dsc_file=1)
155                     dsc_files = utils.build_file_list(dsc, is_a_dsc=1)
156                 except:
157                     utils.warn("error processing '%s'; skipping it. [Got %s]" % (f, sys.exc_type))
158                     continue
159
160         # Ensure all the files we've seen aren't deleted
161         keys = []
162         for i in (files.keys(), dsc_files.keys(), [changes_filename]):
163             keys.extend(i)
164         for key in keys:
165             if all_files.has_key(key):
166                 if Options["Verbose"]:
167                     print "Skipping, has parents, '%s'." % (key)
168                 del all_files[key]
169
170     # Anthing left at this stage is not referenced by a .changes (or
171     # a .dsc) and should be deleted if old enough.
172     for f in all_files.keys():
173         if os.stat(f)[stat.ST_MTIME] < delete_date:
174             remove('Incoming', f)
175         else:
176             if Options["Verbose"]:
177                 print "Skipping, too new, '%s'." % (os.path.basename(f))
178
179 ################################################################################
180
181 def main ():
182     global Options, Logger
183
184     cnf = Config()
185
186     for i in ["Help", "Incoming", "No-Action", "Verbose" ]:
187         if not cnf.has_key("Clean-Queues::Options::%s" % (i)):
188             cnf["Clean-Queues::Options::%s" % (i)] = ""
189     if not cnf.has_key("Clean-Queues::Options::Days"):
190         cnf["Clean-Queues::Options::Days"] = "14"
191
192     Arguments = [('h',"help","Clean-Queues::Options::Help"),
193                  ('d',"days","Clean-Queues::Options::Days", "IntLevel"),
194                  ('i',"incoming","Clean-Queues::Options::Incoming", "HasArg"),
195                  ('n',"no-action","Clean-Queues::Options::No-Action"),
196                  ('v',"verbose","Clean-Queues::Options::Verbose")]
197
198     apt_pkg.ParseCommandLine(cnf.Cnf,Arguments,sys.argv)
199     Options = cnf.SubTree("Clean-Queues::Options")
200
201     if Options["Help"]:
202         usage()
203
204     Logger = daklog.Logger('clean-queues', Options['No-Action'])
205
206     init(cnf)
207
208     if Options["Verbose"]:
209         print "Processing incoming..."
210     flush_orphans()
211
212     reject = cnf["Dir::Reject"]
213     if os.path.exists(reject) and os.path.isdir(reject):
214         if Options["Verbose"]:
215             print "Processing reject directory..."
216         os.chdir(reject)
217         flush_old()
218
219     Logger.close()
220
221 #######################################################################################
222
223 if __name__ == '__main__':
224     main()