[CalendarServer-changes] [5242] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Thu Mar 4 09:41:22 PST 2010


Revision: 5242
          http://trac.macosforge.org/projects/calendarserver/changeset/5242
Author:   sagen at apple.com
Date:     2010-03-04 09:41:20 -0800 (Thu, 04 Mar 2010)
Log Message:
-----------
Adds calendarserver_purge_events command line utility

Modified Paths:
--------------
    CalendarServer/trunk/calendarserver/tools/purge.py
    CalendarServer/trunk/calendarserver/tools/test/test_purge.py

Added Paths:
-----------
    CalendarServer/trunk/bin/calendarserver_purge_events

Added: CalendarServer/trunk/bin/calendarserver_purge_events
===================================================================
--- CalendarServer/trunk/bin/calendarserver_purge_events	                        (rev 0)
+++ CalendarServer/trunk/bin/calendarserver_purge_events	2010-03-04 17:41:20 UTC (rev 5242)
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+##
+# Copyright (c) 2006-2010 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+import sys
+
+#PYTHONPATH
+
+if __name__ == "__main__":
+    if "PYTHONPATH" in globals():
+        sys.path.insert(0, PYTHONPATH)
+    else:
+        from os.path import dirname, abspath, join
+        from subprocess import Popen, PIPE
+
+        home = dirname(dirname(abspath(__file__)))
+        run = join(home, "run")
+
+        child = Popen((run, "-p"), stdout=PIPE)
+        path, stderr = child.communicate()
+
+        path = path.rstrip("\n")
+
+        if child.wait() == 0:
+            sys.path[0:0] = path.split(":")
+
+        sys.argv[1:1] = ["-f", join(home, "conf", "caldavd-dev.plist")]
+
+    from calendarserver.tools.purge import main
+    main()


Property changes on: CalendarServer/trunk/bin/calendarserver_purge_events
___________________________________________________________________
Added: svn:executable
   + *

Modified: CalendarServer/trunk/calendarserver/tools/purge.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/purge.py	2010-03-04 17:08:42 UTC (rev 5241)
+++ CalendarServer/trunk/calendarserver/tools/purge.py	2010-03-04 17:41:20 UTC (rev 5242)
@@ -16,22 +16,159 @@
 # limitations under the License.
 ##
 
+from pwd import getpwnam
+from twisted.python.util import switchUID
+from twistedcaldav.directory.directory import DirectoryError
+from grp import getgrnam
+from calendarserver.tap.util import FakeRequest
+from calendarserver.tap.util import getRootResource
+from calendarserver.tools.util import loadConfig, setupMemcached, setupNotifications
+from datetime import date, timedelta
+from getopt import getopt, GetoptError
 from twext.python.log import Logger
+from twisted.internet import reactor
+from twisted.internet.defer import inlineCallbacks, returnValue, Deferred
 from twistedcaldav import caldavxml
 from twistedcaldav.caldavxml import TimeRange
-from twistedcaldav.ical import Component as iComponent
+from twistedcaldav.config import config, ConfigurationError
 from twistedcaldav.method.delete_common import DeleteResource
-from twisted.internet.defer import inlineCallbacks, returnValue
-from calendarserver.tap.util import FakeRequest
+import os
+import sys
 
 log = Logger()
 
+def usage(e=None):
+
+    name = os.path.basename(sys.argv[0])
+    print "usage: %s [options]" % (name,)
+    print ""
+    print "  Remove old events from the calendar server"
+    print ""
+    print "options:"
+    print "  -h --help: print this help and exit"
+    print "  -d --days <number>: specify how many days in the past to retain"
+    print "  -f --config <path>: Specify caldavd.plist configuration path"
+    print "  -n --noprompt: don't prompt for confirmation"
+    print "  -v --verbose: print progress information"
+    print ""
+
+    if e:
+        sys.exit(64)
+    else:
+        sys.exit(0)
+
+
+def main():
+
+    try:
+        (optargs, args) = getopt(
+            sys.argv[1:], "hd:f:nv", [
+                "help",
+                "days=",
+                "config=",
+                "noprompt",
+                "verbose",
+            ],
+        )
+    except GetoptError, e:
+        usage(e)
+
+    #
+    # Get configuration
+    #
+    configFileName = None
+    days = 365
+    verbose = False
+    prompt = True
+
+    for opt, arg in optargs:
+        if opt in ("-h", "--help"):
+            usage()
+
+        elif opt in ("-d", "--days"):
+            try:
+                days = int(arg)
+            except ValueError, e:
+                print "Invalid value for --days: %s" % (arg,)
+                usage(e)
+
+        elif opt in ("-v", "--verbose"):
+            verbose = True
+
+        elif opt in ("-n", "--noprompt"):
+            prompt = False
+
+        elif opt in ("-f", "--config"):
+            configFileName = arg
+
+        else:
+            raise NotImplementedError(opt)
+
+    try:
+        loadConfig(configFileName)
+
+        # Shed privileges
+        if config.UserName and config.GroupName and os.getuid() == 0:
+            uid = getpwnam(config.UserName).pw_uid
+            gid = getgrnam(config.GroupName).gr_gid
+            switchUID(uid, uid, gid)
+
+        os.umask(config.umask)
+
+        try:
+            rootResource = getRootResource(config)
+            directory = rootResource.getDirectory()
+        except DirectoryError, e:
+            print "Error: %s" % (e,)
+            return
+        setupMemcached(config)
+        setupNotifications(config)
+    except ConfigurationError, e:
+        print "Error: %s" % (e,)
+        return
+
+    cutoff = (date.today() - timedelta(days=days)).strftime("%Y%m%dT000000Z")
+
+    if prompt:
+        response = raw_input("Are you sure you want to delete all events older than %d days? (yes/no) " % (days,))
+        if response != "yes":
+            print "Not deleting events"
+            sys.exit(0)
+
+    #
+    # Start the reactor
+    #
+    reactor.callLater(0, purgeThenStop, directory, rootResource, cutoff,
+        verbose=verbose)
+
+    # In the case where there are no events to be purged, these two lines
+    # seem to be necessary for reactor.run( ) to actually exit when we call
+    # stop( ):
+    d = Deferred()
+    reactor.callLater(0, d.callback, True)
+
+    reactor.run()
+
 @inlineCallbacks
-def purgeOldEvents(directory, root, date):
+def purgeThenStop(directory, rootResource, cutoff, verbose=False):
+    try:
+        count = (yield purgeOldEvents(directory, rootResource, cutoff,
+            verbose=verbose))
+        print "Purged %d events" % (count,)
+    finally:
+        reactor.stop()
 
+
+
+ at inlineCallbacks
+def purgeOldEvents(directory, root, date, verbose=False):
+
     calendars = root.getChild("calendars")
     uidsFPath = calendars.fp.child("__uids__")
 
+    if verbose:
+        print " Scanning calendar homes ...",
+
     records = []
     if uidsFPath.exists():
         for firstFPath in uidsFPath.children():
@@ -43,6 +180,8 @@
                             record = directory.recordWithUID(uid)
                             if record is not None:
                                 records.append(record)
+    if verbose:
+        print "%d calendar homes found" % (len(records),)
 
     log.info("Purging events from %d calendar homes" % (len(records),))
 
@@ -63,6 +202,10 @@
         principal = principalCollection.principalForRecord(record)
         calendarHome = principal.calendarHome()
 
+        if verbose:
+            print " %s ..." % (record.uid,),
+
+        homeEventCount = 0
         # For each collection in calendar home...
         for collName in calendarHome.listChildren():
             collection = calendarHome.getChild(collName)
@@ -85,13 +228,16 @@
                         name
                     )
                     try:
-                        response = (yield deleteResource(root, collection,
-                            resource, uri))
+                        (yield deleteResource(root, collection, resource, uri))
                         eventCount += 1
+                        homeEventCount += 1
                     except Exception, e:
                         log.error("Failed to purge old event: %s (%s)" %
                             (uri, e))
 
+        if verbose:
+            print "%d events purged" % (homeEventCount,)
+
     returnValue(eventCount)
 
 

Modified: CalendarServer/trunk/calendarserver/tools/test/test_purge.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/test/test_purge.py	2010-03-04 17:08:42 UTC (rev 5241)
+++ CalendarServer/trunk/calendarserver/tools/test/test_purge.py	2010-03-04 17:41:20 UTC (rev 5242)
@@ -16,13 +16,9 @@
 
 import os
 import zlib
-
-from twext.python.filepath import CachingFilePath as FilePath
-from twisted.internet import reactor
-from twisted.internet.defer import inlineCallbacks, Deferred, returnValue
-
 from twistedcaldav.config import config
 from twistedcaldav.test.util import TestCase
+from twisted.internet.defer import inlineCallbacks
 from calendarserver.tap.util import getRootResource
 from calendarserver.tools.purge import purgeOldEvents
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100304/d2fe6825/attachment.html>


More information about the calendarserver-changes mailing list