summaryrefslogtreecommitdiff
path: root/bin/update
diff options
context:
space:
mode:
Diffstat (limited to 'bin/update')
-rwxr-xr-xbin/update807
1 files changed, 0 insertions, 807 deletions
diff --git a/bin/update b/bin/update
index 23429508e..e69de29bb 100755
--- a/bin/update
+++ b/bin/update
@@ -1,807 +0,0 @@
-#! @PYTHON@
-#
-# Copyright (C) 1998-2005 by the Free Software Foundation, Inc.
-#
-# 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 the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-"""Perform all necessary upgrades.
-
-Usage: %(PROGRAM)s [options]
-
-Options:
- -f/--force
- Force running the upgrade procedures. Normally, if the version number
- of the installed Mailman matches the current version number (or a
- `downgrade' is detected), nothing will be done.
-
- -h/--help
- Print this text and exit.
-
-Use this script to help you update to the latest release of Mailman from
-some previous version. It knows about versions back to 1.0b4 (?).
-"""
-
-import os
-import md5
-import sys
-import time
-import errno
-import getopt
-import shutil
-import cPickle
-import marshal
-
-import paths
-import email
-
-from Mailman import mm_cfg
-from Mailman import Utils
-from Mailman import MailList
-from Mailman import Message
-from Mailman import Pending
-from Mailman.LockFile import TimeOutError
-from Mailman.i18n import _
-from Mailman.Queue.Switchboard import Switchboard
-from Mailman.OldStyleMemberships import OldStyleMemberships
-from Mailman.MemberAdaptor import BYBOUNCE, ENABLED
-
-FRESH = 0
-NOTFRESH = -1
-
-LMVFILE = os.path.join(mm_cfg.DATA_DIR, 'last_mailman_version')
-PROGRAM = sys.argv[0]
-
-
-
-def calcversions():
- # Returns a tuple of (lastversion, thisversion). If the last version
- # could not be determined, lastversion will be FRESH or NOTFRESH,
- # depending on whether this installation appears to be fresh or not. The
- # determining factor is whether there are files in the $var_prefix/logs
- # subdir or not. The version numbers are HEX_VERSIONs.
- #
- # See if we stored the last updated version
- lastversion = None
- thisversion = mm_cfg.HEX_VERSION
- try:
- fp = open(LMVFILE)
- data = fp.read()
- fp.close()
- lastversion = int(data, 16)
- except (IOError, ValueError):
- pass
- #
- # try to figure out if this is a fresh install
- if lastversion is None:
- lastversion = FRESH
- try:
- if os.listdir(mm_cfg.LOG_DIR):
- lastversion = NOTFRESH
- except OSError:
- pass
- return (lastversion, thisversion)
-
-
-
-def makeabs(relpath):
- return os.path.join(mm_cfg.PREFIX, relpath)
-
-def make_varabs(relpath):
- return os.path.join(mm_cfg.VAR_PREFIX, relpath)
-
-
-def move_language_templates(mlist):
- listname = mlist.internal_name()
- print _('Fixing language templates: %(listname)s')
- # Mailman 2.1 has a new cascading search for its templates, defined and
- # described in Utils.py:maketext(). Putting templates in the top level
- # templates/ subdir or the lists/<listname> subdir is deprecated and no
- # longer searched..
- #
- # What this means is that most templates can live in the global templates/
- # subdirectory, and only needs to be copied into the list-, vhost-, or
- # site-specific language directories when needed.
- #
- # Also, by default all standard (i.e. English) templates must now live in
- # the templates/en directory. This update cleans up all the templates,
- # deleting more-specific duplicates (as calculated by md5 checksums) in
- # favor of more-global locations.
- #
- # First, get rid of any lists/<list> template or lists/<list>/en template
- # that is identical to the global templates/* default.
- for gtemplate in os.listdir(os.path.join(mm_cfg.TEMPLATE_DIR, 'en')):
- # BAW: get rid of old templates, e.g. admlogin.txt and
- # handle_opts.html
- try:
- fp = open(os.path.join(mm_cfg.TEMPLATE_DIR, gtemplate))
- except IOError, e:
- if e.errno <> errno.ENOENT: raise
- # No global template
- continue
-
- gcksum = md5.new(fp.read()).digest()
- fp.close()
- # Match against the lists/<list>/* template
- try:
- fp = open(os.path.join(mlist.fullpath(), gtemplate))
- except IOError, e:
- if e.errno <> errno.ENOENT: raise
- else:
- tcksum = md5.new(fp.read()).digest()
- fp.close()
- if gcksum == tcksum:
- os.unlink(os.path.join(mlist.fullpath(), gtemplate))
- # Match against the lists/<list>/*.prev template
- try:
- fp = open(os.path.join(mlist.fullpath(), gtemplate + '.prev'))
- except IOError, e:
- if e.errno <> errno.ENOENT: raise
- else:
- tcksum = md5.new(fp.read()).digest()
- fp.close()
- if gcksum == tcksum:
- os.unlink(os.path.join(mlist.fullpath(), gtemplate + '.prev'))
- # Match against the lists/<list>/en/* templates
- try:
- fp = open(os.path.join(mlist.fullpath(), 'en', gtemplate))
- except IOError, e:
- if e.errno <> errno.ENOENT: raise
- else:
- tcksum = md5.new(fp.read()).digest()
- fp.close()
- if gcksum == tcksum:
- os.unlink(os.path.join(mlist.fullpath(), 'en', gtemplate))
- # Match against the templates/* template
- try:
- fp = open(os.path.join(mm_cfg.TEMPLATE_DIR, gtemplate))
- except IOError, e:
- if e.errno <> errno.ENOENT: raise
- else:
- tcksum = md5.new(fp.read()).digest()
- fp.close()
- if gcksum == tcksum:
- os.unlink(os.path.join(mm_cfg.TEMPLATE_DIR, gtemplate))
- # Match against the templates/*.prev template
- try:
- fp = open(os.path.join(mm_cfg.TEMPLATE_DIR, gtemplate + '.prev'))
- except IOError, e:
- if e.errno <> errno.ENOENT: raise
- else:
- tcksum = md5.new(fp.read()).digest()
- fp.close()
- if gcksum == tcksum:
- os.unlink(os.path.join(mm_cfg.TEMPLATE_DIR,
- gtemplate + '.prev'))
-
-
-
-def dolist(listname):
- errors = 0
- mlist = MailList.MailList(listname, lock=0)
- try:
- mlist.Lock(0.5)
- except TimeOutError:
- print >> sys.stderr, _('WARNING: could not acquire lock for list: '
- '%(listname)s')
- return 1
-
- # Sanity check the invariant that every BYBOUNCE disabled member must have
- # bounce information. Some earlier betas broke this. BAW: we're
- # submerging below the MemberAdaptor interface, so skip this if we're not
- # using OldStyleMemberships.
- if isinstance(mlist._memberadaptor, OldStyleMemberships):
- noinfo = {}
- for addr, (reason, when) in mlist.delivery_status.items():
- if reason == BYBOUNCE and not mlist.bounce_info.has_key(addr):
- noinfo[addr] = reason, when
- # What to do about these folks with a BYBOUNCE delivery status and no
- # bounce info? This number should be very small, and I think it's
- # fine to simple re-enable them and let the bounce machinery
- # re-disable them if necessary.
- n = len(noinfo)
- if n > 0:
- print _(
- 'Resetting %(n)s BYBOUNCEs disabled addrs with no bounce info')
- for addr in noinfo.keys():
- mlist.setDeliveryStatus(addr, ENABLED)
-
- # Update the held requests database
- print _("""Updating the held requests database.""")
- mlist._UpdateRecords()
-
- mbox_dir = make_varabs('archives/private/%s.mbox' % (listname))
- mbox_file = make_varabs('archives/private/%s.mbox/%s' % (listname,
- listname))
-
- o_pub_mbox_file = make_varabs('archives/public/%s' % (listname))
- o_pri_mbox_file = make_varabs('archives/private/%s' % (listname))
-
- html_dir = o_pri_mbox_file
- o_html_dir = makeabs('public_html/archives/%s' % (listname))
- #
- # make the mbox directory if it's not there.
- #
- if not os.path.exists(mbox_dir):
- ou = os.umask(0)
- os.mkdir(mbox_dir, 02775)
- os.umask(ou)
- else:
- # this shouldn't happen, but hey, just in case
- if not os.path.isdir(mbox_dir):
- print _("""\
-For some reason, %(mbox_dir)s exists as a file. This won't work with
-b6, so I'm renaming it to %(mbox_dir)s.tmp and proceeding.""")
- os.rename(mbox_dir, "%s.tmp" % (mbox_dir))
- ou = os.umask(0)
- os.mkdir(mbox_dir, 02775)
- os.umask(ou)
-
- # Move any existing mboxes around, but watch out for both a public and a
- # private one existing
- if os.path.isfile(o_pri_mbox_file) and os.path.isfile(o_pub_mbox_file):
- if mlist.archive_private:
- print _("""\
-
-%(listname)s has both public and private mbox archives. Since this list
-currently uses private archiving, I'm installing the private mbox archive
--- %(o_pri_mbox_file)s -- as the active archive, and renaming
- %(o_pub_mbox_file)s
-to
- %(o_pub_mbox_file)s.preb6
-
-You can integrate that into the archives if you want by using the 'arch'
-script.
-""") % (mlist._internal_name, o_pri_mbox_file, o_pub_mbox_file,
- o_pub_mbox_file)
- os.rename(o_pub_mbox_file, "%s.preb6" % (o_pub_mbox_file))
- else:
- print _("""\
-%s has both public and private mbox archives. Since this list
-currently uses public archiving, I'm installing the public mbox file
-archive file (%s) as the active one, and renaming
- %s
- to
- %s.preb6
-
-You can integrate that into the archives if you want by using the 'arch'
-script.
-""") % (mlist._internal_name, o_pub_mbox_file, o_pri_mbox_file,
- o_pri_mbox_file)
- os.rename(o_pri_mbox_file, "%s.preb6" % (o_pri_mbox_file))
- #
- # move private archive mbox there if it's around
- # and take into account all sorts of absurdities
- #
- print _('- updating old private mbox file')
- if os.path.exists(o_pri_mbox_file):
- if os.path.isfile(o_pri_mbox_file):
- os.rename(o_pri_mbox_file, mbox_file)
- elif not os.path.isdir(o_pri_mbox_file):
- newname = "%s.mm_install-dunno_what_this_was_but_its_in_the_way" \
- % o_pri_mbox_file
- os.rename(o_pri_mbox_file, newname)
- print _("""\
- unknown file in the way, moving
- %(o_pri_mbox_file)s
- to
- %(newname)s""")
- else:
- # directory
- print _("""\
- looks like you have a really recent CVS installation...
- you're either one brave soul, or you already ran me""")
-
-
- #
- # move public archive mbox there if it's around
- # and take into account all sorts of absurdities.
- #
- print _('- updating old public mbox file')
- if os.path.exists(o_pub_mbox_file):
- if os.path.isfile(o_pub_mbox_file):
- os.rename(o_pub_mbox_file, mbox_file)
- elif not os.path.isdir(o_pub_mbox_file):
- newname = "%s.mm_install-dunno_what_this_was_but_its_in_the_way" \
- % o_pub_mbox_file
- os.rename(o_pub_mbox_file, newname)
- print _("""\
- unknown file in the way, moving
- %(o_pub_mbox_file)s
- to
- %(newname)s""")
- else: # directory
- print _("""\
- looks like you have a really recent CVS installation...
- you're either one brave soul, or you already ran me""")
-
- #
- # move the html archives there
- #
- if os.path.isdir(o_html_dir):
- os.rename(o_html_dir, html_dir)
- #
- # chmod the html archives
- #
- os.chmod(html_dir, 02775)
- # BAW: Is this still necessary?!
- mlist.Save()
- #
- # check to see if pre-b4 list-specific templates are around
- # and move them to the new place if there's not already
- # a new one there
- #
- tmpl_dir = os.path.join(mm_cfg.PREFIX, "templates")
- list_dir = os.path.join(mm_cfg.PREFIX, "lists")
- b4_tmpl_dir = os.path.join(tmpl_dir, mlist._internal_name)
- new_tmpl_dir = os.path.join(list_dir, mlist._internal_name)
- if os.path.exists(b4_tmpl_dir):
- print _("""\
-- This list looks like it might have <= b4 list templates around""")
- for f in os.listdir(b4_tmpl_dir):
- o_tmpl = os.path.join(b4_tmpl_dir, f)
- n_tmpl = os.path.join(new_tmpl_dir, f)
- if os.path.exists(o_tmpl):
- if not os.path.exists(n_tmpl):
- os.rename(o_tmpl, n_tmpl)
- print _('- moved %(o_tmpl)s to %(n_tmpl)s')
- else:
- print _("""\
-- both %(o_tmpl)s and %(n_tmpl)s exist, leaving untouched""")
- else:
- print _("""\
-- %(o_tmpl)s doesn't exist, leaving untouched""")
- #
- # Move all the templates to the en language subdirectory as required for
- # Mailman 2.1
- #
- move_language_templates(mlist)
- # Avoid eating filehandles with the list lockfiles
- mlist.Unlock()
- return 0
-
-
-
-def archive_path_fixer(unused_arg, dir, files):
- # Passed to os.path.walk to fix the perms on old html archives.
- for f in files:
- abs = os.path.join(dir, f)
- if os.path.isdir(abs):
- if f == "database":
- os.chmod(abs, 02770)
- else:
- os.chmod(abs, 02775)
- elif os.path.isfile(abs):
- os.chmod(abs, 0664)
-
-def remove_old_sources(module):
- # Also removes old directories.
- src = '%s/%s' % (mm_cfg.PREFIX, module)
- pyc = src + "c"
- if os.path.isdir(src):
- print _('removing directory %(src)s and everything underneath')
- shutil.rmtree(src)
- elif os.path.exists(src):
- print _('removing %(src)s')
- try:
- os.unlink(src)
- except os.error, rest:
- print _("Warning: couldn't remove %(src)s -- %(rest)s")
- if module.endswith('.py') and os.path.exists(pyc):
- try:
- os.unlink(pyc)
- except os.error, rest:
- print _("couldn't remove old file %(pyc)s -- %(rest)s")
-
-
-def update_qfiles():
- print _('updating old qfiles')
- prefix = `time.time()` + '+'
- # Be sure the qfiles/in directory exists (we don't really need the
- # switchboard object, but it's convenient for creating the directory).
- sb = Switchboard(mm_cfg.INQUEUE_DIR)
- for filename in os.listdir(mm_cfg.QUEUE_DIR):
- # Updating means just moving the .db and .msg files to qfiles/in where
- # it should be dequeued, converted, and processed normally.
- if filename.endswith('.msg'):
- oldmsgfile = os.path.join(mm_cfg.QUEUE_DIR, filename)
- newmsgfile = os.path.join(mm_cfg.INQUEUE_DIR, prefix + filename)
- os.rename(oldmsgfile, newmsgfile)
- elif filename.endswith('.db'):
- olddbfile = os.path.join(mm_cfg.QUEUE_DIR, filename)
- newdbfile = os.path.join(mm_cfg.INQUEUE_DIR, prefix + filename)
- os.rename(olddbfile, newdbfile)
- # Now update for the Mailman 2.1.5 qfile format. For every filebase in
- # the qfiles/* directories that has both a .pck and a .db file, pull the
- # data out and re-queue them.
- for dirname in os.listdir(mm_cfg.QUEUE_DIR):
- dirpath = os.path.join(mm_cfg.QUEUE_DIR, dirname)
- if dirpath == mm_cfg.BADQUEUE_DIR:
- # The files in qfiles/bad can't possibly be pickles
- continue
- sb = Switchboard(dirpath)
- try:
- for filename in os.listdir(dirpath):
- filepath = os.path.join(dirpath, filename)
- filebase, ext = os.path.splitext(filepath)
- # Handle the .db metadata files as part of the handling of the
- # .pck or .msg message files.
- if ext not in ('.pck', '.msg'):
- continue
- msg, data = dequeue(filebase)
- if msg is not None and data is not None:
- sb.enqueue(msg, data)
- except EnvironmentError, e:
- if e.errno <> errno.ENOTDIR:
- raise
- print _('Warning! Not a directory: %(dirpath)s')
-
-
-
-# Implementations taken from the pre-2.1.5 Switchboard
-def ext_read(filename):
- fp = open(filename)
- d = marshal.load(fp)
- # Update from version 2 files
- if d.get('version', 0) == 2:
- del d['filebase']
- # Do the reverse conversion (repr -> float)
- for attr in ['received_time']:
- try:
- sval = d[attr]
- except KeyError:
- pass
- else:
- # Do a safe eval by setting up a restricted execution
- # environment. This may not be strictly necessary since we
- # know they are floats, but it can't hurt.
- d[attr] = eval(sval, {'__builtins__': {}})
- fp.close()
- return d
-
-
-def dequeue(filebase):
- # Calculate the .db and .msg filenames from the given filebase.
- msgfile = os.path.join(filebase + '.msg')
- pckfile = os.path.join(filebase + '.pck')
- dbfile = os.path.join(filebase + '.db')
- # Now we are going to read the message and metadata for the given
- # filebase. We want to read things in this order: first, the metadata
- # file to find out whether the message is stored as a pickle or as
- # plain text. Second, the actual message file. However, we want to
- # first unlink the message file and then the .db file, because the
- # qrunner only cues off of the .db file
- msg = None
- try:
- data = ext_read(dbfile)
- os.unlink(dbfile)
- except EnvironmentError, e:
- if e.errno <> errno.ENOENT: raise
- data = {}
- # Between 2.1b4 and 2.1b5, the `rejection-notice' key in the metadata
- # was renamed to `rejection_notice', since dashes in the keys are not
- # supported in METAFMT_ASCII.
- if data.has_key('rejection-notice'):
- data['rejection_notice'] = data['rejection-notice']
- del data['rejection-notice']
- msgfp = None
- try:
- try:
- msgfp = open(pckfile)
- msg = cPickle.load(msgfp)
- os.unlink(pckfile)
- except EnvironmentError, e:
- if e.errno <> errno.ENOENT: raise
- msgfp = None
- try:
- msgfp = open(msgfile)
- msg = email.message_from_file(msgfp, Message.Message)
- os.unlink(msgfile)
- except EnvironmentError, e:
- if e.errno <> errno.ENOENT: raise
- except (email.Errors.MessageParseError, ValueError), e:
- # This message was unparsable, most likely because its
- # MIME encapsulation was broken. For now, there's not
- # much we can do about it.
- print _('message is unparsable: %(filebase)s')
- msgfp.close()
- msgfp = None
- if mm_cfg.QRUNNER_SAVE_BAD_MESSAGES:
- # Cheapo way to ensure the directory exists w/ the
- # proper permissions.
- sb = Switchboard(mm_cfg.BADQUEUE_DIR)
- os.rename(msgfile, os.path.join(
- mm_cfg.BADQUEUE_DIR, filebase + '.txt'))
- else:
- os.unlink(msgfile)
- msg = data = None
- except EOFError:
- # For some reason the pckfile was empty. Just delete it.
- print _('Warning! Deleting empty .pck file: %(pckfile)s')
- os.unlink(pckfile)
- finally:
- if msgfp:
- msgfp.close()
- return msg, data
-
-
-
-def update_pending():
- file20 = os.path.join(mm_cfg.DATA_DIR, 'pending_subscriptions.db')
- file214 = os.path.join(mm_cfg.DATA_DIR, 'pending.pck')
- db = None
- # Try to load the Mailman 2.0 file
- try:
- fp = open(file20)
- except IOError, e:
- if e.errno <> errno.ENOENT: raise
- else:
- print _('Updating Mailman 2.0 pending_subscriptions.db database')
- db = marshal.load(fp)
- # Convert to the pre-Mailman 2.1.5 format
- db = Pending._update(db)
- if db is None:
- # Try to load the Mailman 2.1.x where x < 5, file
- try:
- fp = open(file214)
- except IOError, e:
- if e.errno <> errno.ENOENT: raise
- else:
- print _('Updating Mailman 2.1.4 pending.pck database')
- db = cPickle.load(fp)
- if db is None:
- print _('Nothing to do.')
- return
- # Now upgrade the database to the 2.1.5 format. Each list now has its own
- # pending.pck file, but only the RE_ENABLE operation actually recorded the
- # listname in the request. For the SUBSCRIPTION, UNSUBSCRIPTION, and
- # CHANGE_OF_ADDRESS operations, we know the address of the person making
- # the request so we can repend this request just for the lists the person
- # is a member of. For the HELD_MESSAGE operation, we can check the list's
- # requests.pck file for correlation. Evictions will take care of any
- # misdirected pendings.
- reenables_by_list = {}
- addrops_by_address = {}
- holds_by_id = {}
- subs_by_address = {}
- for key, val in db.items():
- if key in ('evictions', 'version'):
- continue
- try:
- op = val[0]
- data = val[1:]
- except (IndexError, ValueError):
- print _('Ignoring bad pended data: %(key)s: %(val)s')
- continue
- if op in (Pending.UNSUBSCRIPTION, Pending.CHANGE_OF_ADDRESS):
- # data[0] is the address being unsubscribed
- addrops_by_address.setdefault(data[0], []).append((key, val))
- elif op == Pending.SUBSCRIPTION:
- # data[0] is a UserDesc object
- addr = data[0].address
- subs_by_address.setdefault(addr, []).append((key, val))
- elif op == Pending.RE_ENABLE:
- # data[0] is the mailing list's internal name
- reenables_by_list.setdefault(data[0], []).append((key, val))
- elif op == Pending.HELD_MESSAGE:
- # data[0] is the hold id. There better only be one entry per id
- id = data[0]
- if holds_by_id.has_key(id):
- print _('WARNING: Ignoring duplicate pending ID: %(id)s.')
- else:
- holds_by_id[id] = (key, val)
- # Now we have to lock every list and re-pend all the appropriate
- # requests. Note that this will reset all the expiration dates, but that
- # should be fine.
- for listname in Utils.list_names():
- mlist = MailList.MailList(listname)
- # This is not the most efficient way to do this because it loads and
- # saves the pending.pck file each time. :(
- try:
- for cookie, data in reenables_by_list.get(listname, []):
- mlist.pend_repend(cookie, data)
- for id, (cookie, data) in holds_by_id.items():
- try:
- rec = mlist.GetRecord(id)
- except KeyError:
- # Not for this list
- pass
- else:
- mlist.pend_repend(cookie, data)
- del holds_by_id[id]
- for addr, recs in subs_by_address.items():
- # We shouldn't have a subscription confirmation if the address
- # is already a member of the mailing list.
- if mlist.isMember(addr):
- continue
- for cookie, data in recs:
- mlist.pend_repend(cookie, data)
- for addr, recs in addrops_by_address.items():
- # We shouldn't have unsubscriptions or change of address
- # requests for addresses which aren't members of the list.
- if not mlist.isMember(addr):
- continue
- for cookie, data in recs:
- mlist.pend_repend(cookie, data)
- mlist.Save()
- finally:
- mlist.Unlock()
- try:
- os.unlink(file20)
- except OSError, e:
- if e.errno <> errno.ENOENT: raise
- try:
- os.unlink(file214)
- except OSError, e:
- if e.errno <> errno.ENOENT: raise
-
-
-
-def main():
- errors = 0
- # get rid of old stuff
- print _('getting rid of old source files')
- for mod in ('Mailman/Archiver.py', 'Mailman/HyperArch.py',
- 'Mailman/HyperDatabase.py', 'Mailman/pipermail.py',
- 'Mailman/smtplib.py', 'Mailman/Cookie.py',
- 'bin/update_to_10b6', 'scripts/mailcmd',
- 'scripts/mailowner', 'mail/wrapper', 'Mailman/pythonlib',
- 'cgi-bin/archives', 'Mailman/MailCommandHandler'):
- remove_old_sources(mod)
- listnames = Utils.list_names()
- if not listnames:
- print _('no lists == nothing to do, exiting')
- return
- #
- # for people with web archiving, make sure the directories
- # in the archiving are set with proper perms for b6.
- #
- if os.path.isdir("%s/public_html/archives" % mm_cfg.PREFIX):
- print _("""\
-fixing all the perms on your old html archives to work with b6
-If your archives are big, this could take a minute or two...""")
- os.path.walk("%s/public_html/archives" % mm_cfg.PREFIX,
- archive_path_fixer, "")
- print _('done')
- for listname in listnames:
- print _('Updating mailing list: %(listname)s')
- errors = errors + dolist(listname)
- print
- print _('Updating Usenet watermarks')
- wmfile = os.path.join(mm_cfg.DATA_DIR, 'gate_watermarks')
- try:
- fp = open(wmfile)
- except IOError:
- print _('- nothing to update here')
- else:
- d = marshal.load(fp)
- fp.close()
- for listname in d.keys():
- if listname not in listnames:
- # this list no longer exists
- continue
- mlist = MailList.MailList(listname, lock=0)
- try:
- mlist.Lock(0.5)
- except TimeOutError:
- print >> sys.stderr, _(
- 'WARNING: could not acquire lock for list: %(listname)s')
- errors = errors + 1
- else:
- # Pre 1.0b7 stored 0 in the gate_watermarks file to indicate
- # that no gating had been done yet. Without coercing this to
- # None, the list could now suddenly get flooded.
- mlist.usenet_watermark = d[listname] or None
- mlist.Save()
- mlist.Unlock()
- os.unlink(wmfile)
- print _('- usenet watermarks updated and gate_watermarks removed')
- # In Mailman 2.1, the pending database format and file name changed, but
- # in Mailman 2.1.5 it changed again. This should update all existing
- # files to the 2.1.5 format.
- update_pending()
- # In Mailman 2.1, the qfiles directory has a different structure and a
- # different content. Also, in Mailman 2.1.5 we collapsed the message
- # files from separate .msg (pickled Message objects) and .db (marshalled
- # dictionaries) to a shared .pck file containing two pickles.
- update_qfiles()
- # This warning was necessary for the upgrade from 1.0b9 to 1.0b10.
- # There's no good way of figuring this out for releases prior to 2.0beta2
- # :(
- if lastversion == NOTFRESH:
- print _("""
-
-NOTE NOTE NOTE NOTE NOTE
-
- You are upgrading an existing Mailman installation, but I can't tell what
- version you were previously running.
-
- If you are upgrading from Mailman 1.0b9 or earlier you will need to
- manually update your mailing lists. For each mailing list you need to
- copy the file templates/options.html lists/<listname>/options.html.
-
- However, if you have edited this file via the Web interface, you will have
- to merge your changes into this file, otherwise you will lose your
- changes.
-
-NOTE NOTE NOTE NOTE NOTE
-
-""")
- return errors
-
-
-
-def usage(code, msg=''):
- if code:
- fd = sys.stderr
- else:
- fd = sys.stdout
- print >> fd, _(__doc__) % globals()
- if msg:
- print >> sys.stderr, msg
- sys.exit(code)
-
-
-
-if __name__ == '__main__':
- try:
- opts, args = getopt.getopt(sys.argv[1:], 'hf',
- ['help', 'force'])
- except getopt.error, msg:
- usage(1, msg)
-
- if args:
- usage(1, 'Unexpected arguments: %s' % args)
-
- force = 0
- for opt, arg in opts:
- if opt in ('-h', '--help'):
- usage(0)
- elif opt in ('-f', '--force'):
- force = 1
-
- # calculate the versions
- lastversion, thisversion = calcversions()
- hexlversion = hex(lastversion)
- hextversion = hex(thisversion)
- if lastversion == thisversion and not force:
- # nothing to do
- print _('No updates are necessary.')
- sys.exit(0)
- if lastversion > thisversion and not force:
- print _("""\
-Downgrade detected, from version %(hexlversion)s to version %(hextversion)s
-This is probably not safe.
-Exiting.""")
- sys.exit(1)
- print _('Upgrading from version %(hexlversion)s to %(hextversion)s')
- errors = main()
- if not errors:
- # Record the version we just upgraded to
- fp = open(LMVFILE, 'w')
- fp.write(hex(mm_cfg.HEX_VERSION) + '\n')
- fp.close()
- else:
- lockdir = mm_cfg.LOCK_DIR
- print _('''\
-
-ERROR:
-
-The locks for some lists could not be acquired. This means that either
-Mailman was still active when you upgraded, or there were stale locks in the
-%(lockdir)s directory.
-
-You must put Mailman into a quiescent state and remove all stale locks, then
-re-run "make update" manually. See the INSTALL and UPGRADE files for details.
-''')