Apply 79_archiver_slash.patch
[mspang/vmailman.git] / bin / arch
1 #! @PYTHON@
2 #
3 # Copyright (C) 1998,1999,2000,2001,2002 by the Free Software Foundation, Inc.
4 #
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
19 """Rebuild a list's archive.
20
21 Use this command to rebuild the archives for a mailing list.  You may want to
22 do this if you edit some messages in an archive, or remove some messages from
23 an archive.
24
25 Usage: %(PROGRAM)s [options] <listname> [<mbox>]
26
27 Where options are:
28     -h / --help
29         Print this help message and exit.
30
31     -q / --quiet
32         Make the archiver output less verbose.
33
34     --wipe
35         First wipe out the original archive before regenerating.  You usually
36         want to specify this argument unless you're generating the archive in
37         chunks.
38
39     -s N
40     --start=N
41         Start indexing at article N, where article 0 is the first in the mbox.
42         Defaults to 0.
43
44     -e M
45     --end=M
46         End indexing at article M.  This script is not very efficient with
47         respect to memory management, and for large archives, it may not be
48         possible to index the mbox entirely.  For that reason, you can specify
49         the start and end article numbers.
50
51 Where <mbox> is the path to a list's complete mbox archive.  Usually this will
52 be some path in the archives/private directory.  For example:
53
54 %% bin/arch mylist archives/private/mylist.mbox/mylist.mbox
55
56 <mbox> is optional.  If it is missing, it is calculated.
57 """
58
59 import os
60 import sys
61 import getopt
62 import shutil
63
64 import paths
65 from Mailman import mm_cfg
66 from Mailman import Errors
67
68 from Mailman.MailList import MailList
69 from Mailman.Archiver.HyperArch import HyperArchive
70 from Mailman.LockFile import LockFile
71 from Mailman import i18n
72
73 _ = i18n._
74
75 PROGRAM = sys.argv[0]
76 i18n.set_language(mm_cfg.DEFAULT_SERVER_LANGUAGE)
77
78
79 \f
80 def usage(code, msg=''):
81     if code:
82         fd = sys.stderr
83     else:
84         fd = sys.stdout
85     print >> fd, _(__doc__)
86     if msg:
87         print >> fd, msg
88     sys.exit(code)
89
90
91 \f
92 def main():
93     # get command line arguments
94     try:
95         opts, args = getopt.getopt(
96             sys.argv[1:], 'hs:e:q',
97             ['help', 'start=', 'end=', 'quiet', 'wipe'])
98     except getopt.error, msg:
99         usage(1, msg)
100
101     start = None
102     end = None
103     verbose = 1
104     wipe = 0
105     for opt, arg in opts:
106         if opt in ('-h', '--help'):
107             usage(0)
108         elif opt in ('-s', '--start'):
109             try:
110                 start = int(arg)
111             except ValueError:
112                 usage(1)
113         elif opt in ('-e', '--end'):
114             try:
115                 end = int(arg)
116             except ValueError:
117                 usage(1)
118         elif opt in ('-q', '--quiet'):
119             verbose = 0
120         elif opt == '--wipe':
121             wipe = 1
122
123     # grok arguments
124     if len(args) < 1:
125         usage(1, _('listname is required'))
126     listname = args[0].lower().strip()
127
128     if len(args) < 2:
129         mbox = None
130     else:
131         mbox = args[1]
132
133     if len(args) > 2:
134         usage(1)
135
136     # open the mailing list object
137     mlist = None
138     lock = None
139     try:
140         try:
141             mlist = MailList(listname)
142         except Errors.MMListError, e:
143             usage(2, _('No such list "%(listname)s"\n%(e)s'))
144         if mbox is None:
145             mbox = mlist.ArchiveFileName()
146
147         i18n.set_language(mlist.preferred_language)
148         # lay claim to the archive's lock file.  this is so no other post can
149         # mess up the archive while we're glomming it.  we pick a suitably
150         # long period of time for the lock lifetime, however we really don't
151         # know how long it will take.
152         #
153         # XXX: processUnixMailbox() should refresh the lock.
154         #
155         # XXX: this may not be necessary because I think we lay claim to the
156         # list lock up above, although that may be too short to be of use (and
157         # maybe we don't really want to lock the list anyway).
158         #
159         lockfile = os.path.join(mm_cfg.LOCK_DIR, mlist._internal_name) + \
160                    '.archiver.lock'
161         # set the lock lifetime to 3 hours.  XXX is this reasonable???
162         lock = LockFile(lockfile, lifetime=3*60*60)
163         lock.lock()
164         # Maybe wipe the old archives
165         if wipe:
166             if mlist.scrub_nondigest:
167                 # TK: save the attachments dir because they are not in mbox
168                 saved = 0
169                 try:
170                     atchdir = os.path.join(mlist.archive_dir(), 'attachments')
171                     savedir = os.path.join(mlist.archive_dir() + '.mbox',
172                                            'attachments')
173                     os.rename(atchdir, savedir)
174                     saved = 1
175                 except:
176                     pass
177             shutil.rmtree(mlist.archive_dir())
178             if mlist.scrub_nondigest and saved:
179                 os.renames(savedir, atchdir)
180         try:
181             fp = open(mbox)
182         except IOError, msg:
183             usage(3, _('Cannot open mbox file %(mbox)s: %(msg)s'))
184
185         archiver = HyperArchive(mlist)
186         archiver.VERBOSE = verbose
187         try:
188             archiver.processUnixMailbox(fp, start, end)
189         finally:
190             archiver.close()
191         fp.close()
192     finally:
193         if lock:
194             lock.unlock()
195         if mlist:
196             mlist.Unlock()
197
198 \f
199 if __name__ == '__main__':
200     main()