[CalendarServer-changes] [8349] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Mon Nov 28 19:27:44 PST 2011


Revision: 8349
          http://trac.macosforge.org/projects/calendarserver/changeset/8349
Author:   cdaboo at apple.com
Date:     2011-11-28 19:27:44 -0800 (Mon, 28 Nov 2011)
Log Message:
-----------
Merge split-collections branch to trunk.

Modified Paths:
--------------
    CalendarServer/trunk/calendarserver/tap/caldav.py
    CalendarServer/trunk/twistedcaldav/caldavxml.py
    CalendarServer/trunk/twistedcaldav/customxml.py
    CalendarServer/trunk/twistedcaldav/method/copymove.py
    CalendarServer/trunk/twistedcaldav/method/mkcalendar.py
    CalendarServer/trunk/twistedcaldav/method/mkcol.py
    CalendarServer/trunk/twistedcaldav/method/put_common.py
    CalendarServer/trunk/twistedcaldav/resource.py
    CalendarServer/trunk/twistedcaldav/schedule.py
    CalendarServer/trunk/twistedcaldav/scheduling/processing.py
    CalendarServer/trunk/twistedcaldav/stdconfig.py
    CalendarServer/trunk/twistedcaldav/storebridge.py
    CalendarServer/trunk/twistedcaldav/test/test_props.py
    CalendarServer/trunk/twistedcaldav/test/test_schedule.py
    CalendarServer/trunk/twistedcaldav/test/test_validation.py
    CalendarServer/trunk/txdav/base/propertystore/base.py
    CalendarServer/trunk/txdav/base/propertystore/sql.py
    CalendarServer/trunk/txdav/base/propertystore/test/base.py
    CalendarServer/trunk/txdav/base/propertystore/test/test_sql.py
    CalendarServer/trunk/txdav/base/propertystore/test/test_xattr.py
    CalendarServer/trunk/txdav/base/propertystore/xattr.py
    CalendarServer/trunk/txdav/caldav/datastore/file.py
    CalendarServer/trunk/txdav/caldav/datastore/index_file.py
    CalendarServer/trunk/txdav/caldav/datastore/scheduling.py
    CalendarServer/trunk/txdav/caldav/datastore/sql.py
    CalendarServer/trunk/txdav/caldav/datastore/test/common.py
    CalendarServer/trunk/txdav/caldav/datastore/test/test_scheduling.py
    CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py
    CalendarServer/trunk/txdav/caldav/datastore/util.py
    CalendarServer/trunk/txdav/carddav/datastore/sql.py
    CalendarServer/trunk/txdav/carddav/datastore/test/test_sql.py
    CalendarServer/trunk/txdav/common/datastore/sql.py
    CalendarServer/trunk/txdav/common/datastore/sql_schema/current.sql
    CalendarServer/trunk/txdav/common/datastore/test/util.py

Added Paths:
-----------
    CalendarServer/trunk/doc/RFC/draft-daboo-caldav-extensions.txt
    CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/
    CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/
    CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/1.ics
    CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/2.ics
    CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/3.ics
    CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/
    CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/1.ics
    CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/2.ics
    CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/3.ics
    CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/4.ics
    CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/5.ics
    CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits_shared/
    CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits_shared/calendar_1/
    CalendarServer/trunk/txdav/common/datastore/sql_schema/old/v5.sql
    CalendarServer/trunk/txdav/common/datastore/sql_schema/old/v6.sql
    CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_5_to_6.sql
    CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_6_to_7.sql
    CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_5_to_6.sql
    CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_6_to_7.sql
    CalendarServer/trunk/txdav/common/datastore/upgrade/
    CalendarServer/trunk/txdav/common/datastore/upgrade/__init__.py
    CalendarServer/trunk/txdav/common/datastore/upgrade/file/
    CalendarServer/trunk/txdav/common/datastore/upgrade/file/__init__.py
    CalendarServer/trunk/txdav/common/datastore/upgrade/migrate.py
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/__init__.py
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/__init__.py
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema1/
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema1/current.sql
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema1/upgrades/
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema1/upgrades/fake_dialect/
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema1/upgrades/fake_dialect/upgrade_from_3_to_4.sql
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/current.sql
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_3_to_4.sql
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_3_to_5.sql
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_4_to_5.sql
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/current.sql
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/upgrades/
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/upgrades/fake_dialect/
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/upgrades/fake_dialect/upgrade_from_3_to_4.sql
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/upgrades/fake_dialect/upgrade_from_4_to_5.sql
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/test_upgrade.py
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrade.py
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/__init__.py
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_1_to_2.py
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/util.py
    CalendarServer/trunk/txdav/common/datastore/upgrade/test/
    CalendarServer/trunk/txdav/common/datastore/upgrade/test/__init__.py
    CalendarServer/trunk/txdav/common/datastore/upgrade/test/test_migrate.py

Removed Paths:
-------------
    CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/
    CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/1.ics
    CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/2.ics
    CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/3.ics
    CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/
    CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/1.ics
    CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/2.ics
    CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/3.ics
    CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/4.ics
    CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/5.ics
    CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits_shared/calendar_1/
    CalendarServer/trunk/txdav/common/datastore/sql_schema/old/v5.sql
    CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_5_to_6.sql
    CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_5_to_6.sql
    CalendarServer/trunk/txdav/common/datastore/test/fake_schema1/
    CalendarServer/trunk/txdav/common/datastore/test/fake_schema2/
    CalendarServer/trunk/txdav/common/datastore/test/fake_schema3/
    CalendarServer/trunk/txdav/common/datastore/test/test_util.py
    CalendarServer/trunk/txdav/common/datastore/upgrade/__init__.py
    CalendarServer/trunk/txdav/common/datastore/upgrade/file/
    CalendarServer/trunk/txdav/common/datastore/upgrade/file/__init__.py
    CalendarServer/trunk/txdav/common/datastore/upgrade/migrate.py
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/__init__.py
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/__init__.py
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema1/
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema1/current.sql
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema1/upgrades/
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema1/upgrades/fake_dialect/
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema1/upgrades/fake_dialect/upgrade_from_3_to_4.sql
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/current.sql
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_3_to_4.sql
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_3_to_5.sql
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_4_to_5.sql
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/current.sql
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/upgrades/
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/upgrades/fake_dialect/
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/upgrades/fake_dialect/upgrade_from_3_to_4.sql
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/upgrades/fake_dialect/upgrade_from_4_to_5.sql
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/test_upgrade.py
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrade.py
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/__init__.py
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_1_to_2.py
    CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/util.py
    CalendarServer/trunk/txdav/common/datastore/upgrade/test/
    CalendarServer/trunk/txdav/common/datastore/upgrade/test/__init__.py
    CalendarServer/trunk/txdav/common/datastore/upgrade/test/test_migrate.py
    CalendarServer/trunk/txdav/common/datastore/util.py

Property Changed:
----------------
    CalendarServer/trunk/
    CalendarServer/trunk/support/build.sh
    CalendarServer/trunk/txdav/caldav/datastore/index_file.py
    CalendarServer/trunk/txdav/caldav/datastore/test/test_index_file.py
    CalendarServer/trunk/txdav/carddav/datastore/index_file.py
    CalendarServer/trunk/txdav/carddav/datastore/test/test_index_file.py


Property changes on: CalendarServer/trunk
___________________________________________________________________
Modified: svn:mergeinfo
   - /CalendarServer/branches/config-separation:4379-4443
/CalendarServer/branches/egg-info-351:4589-4625
/CalendarServer/branches/generic-sqlstore:6167-6191
/CalendarServer/branches/new-store:5594-5934
/CalendarServer/branches/new-store-no-caldavfile:5911-5935
/CalendarServer/branches/new-store-no-caldavfile-2:5936-5981
/CalendarServer/branches/users/cdaboo/batchupload-6699:6700-7198
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692:5693-5702
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627:3628-3644
/CalendarServer/branches/users/cdaboo/implicituidrace:8137-8141
/CalendarServer/branches/users/cdaboo/more-sharing-5591:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464:4465-4957
/CalendarServer/branches/users/cdaboo/pods:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar:7085-7206
/CalendarServer/branches/users/cdaboo/pycard:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070:5071-5105
/CalendarServer/branches/users/cdaboo/shared-calendars-5187:5188-5440
/CalendarServer/branches/users/cdaboo/timezones:7443-7699
/CalendarServer/branches/users/glyph/conn-limit:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge:4971-5080
/CalendarServer/branches/users/glyph/dalify:6932-7023
/CalendarServer/branches/users/glyph/db-reconnect:6824-6876
/CalendarServer/branches/users/glyph/deploybuild:7563-7572
/CalendarServer/branches/users/glyph/disable-quota:7718-7727
/CalendarServer/branches/users/glyph/dont-start-postgres:6592-6614
/CalendarServer/branches/users/glyph/imip-and-admin-html:7866-7984
/CalendarServer/branches/users/glyph/linux-tests:6893-6900
/CalendarServer/branches/users/glyph/misc-portability-fixes:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6:6322-6368
/CalendarServer/branches/users/glyph/more-deferreds-7:6369-6445
/CalendarServer/branches/users/glyph/multiget-delete:8321-8330
/CalendarServer/branches/users/glyph/new-export:7444-7485
/CalendarServer/branches/users/glyph/oracle:7106-7155
/CalendarServer/branches/users/glyph/oracle-nulls:7340-7351
/CalendarServer/branches/users/glyph/other-html:8062-8091
/CalendarServer/branches/users/glyph/parallel-sim:8240-8251
/CalendarServer/branches/users/glyph/quota:7604-7637
/CalendarServer/branches/users/glyph/sendfdport:5388-5424
/CalendarServer/branches/users/glyph/shared-pool-take2:8155-8174
/CalendarServer/branches/users/glyph/sharedpool:6490-6550
/CalendarServer/branches/users/glyph/sql-store:5929-6073
/CalendarServer/branches/users/glyph/subtransactions:7248-7258
/CalendarServer/branches/users/glyph/uidexport:7673-7676
/CalendarServer/branches/users/glyph/use-system-twisted:5084-5149
/CalendarServer/branches/users/glyph/xattrs-from-files:7757-7769
/CalendarServer/branches/users/sagen/applepush:8126-8184
/CalendarServer/branches/users/sagen/inboxitems:7380-7381
/CalendarServer/branches/users/sagen/locations-resources:5032-5051
/CalendarServer/branches/users/sagen/locations-resources-2:5052-5061
/CalendarServer/branches/users/sagen/purge_old_events:6735-6746
/CalendarServer/branches/users/sagen/resource-delegates-4038:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066:4068-4075
/CalendarServer/branches/users/sagen/resources-2:5084-5093
/CalendarServer/branches/users/wsanchez/transations:5515-5593
   + /CalendarServer/branches/config-separation:4379-4443
/CalendarServer/branches/egg-info-351:4589-4625
/CalendarServer/branches/generic-sqlstore:6167-6191
/CalendarServer/branches/new-store:5594-5934
/CalendarServer/branches/new-store-no-caldavfile:5911-5935
/CalendarServer/branches/new-store-no-caldavfile-2:5936-5981
/CalendarServer/branches/users/cdaboo/batchupload-6699:6700-7198
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692:5693-5702
/CalendarServer/branches/users/cdaboo/component-set-fixes:8130-8346
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627:3628-3644
/CalendarServer/branches/users/cdaboo/implicituidrace:8137-8141
/CalendarServer/branches/users/cdaboo/more-sharing-5591:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464:4465-4957
/CalendarServer/branches/users/cdaboo/pods:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar:7085-7206
/CalendarServer/branches/users/cdaboo/pycard:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070:5071-5105
/CalendarServer/branches/users/cdaboo/shared-calendars-5187:5188-5440
/CalendarServer/branches/users/cdaboo/timezones:7443-7699
/CalendarServer/branches/users/glyph/conn-limit:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge:4971-5080
/CalendarServer/branches/users/glyph/dalify:6932-7023
/CalendarServer/branches/users/glyph/db-reconnect:6824-6876
/CalendarServer/branches/users/glyph/deploybuild:7563-7572
/CalendarServer/branches/users/glyph/disable-quota:7718-7727
/CalendarServer/branches/users/glyph/dont-start-postgres:6592-6614
/CalendarServer/branches/users/glyph/imip-and-admin-html:7866-7984
/CalendarServer/branches/users/glyph/linux-tests:6893-6900
/CalendarServer/branches/users/glyph/misc-portability-fixes:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6:6322-6368
/CalendarServer/branches/users/glyph/more-deferreds-7:6369-6445
/CalendarServer/branches/users/glyph/multiget-delete:8321-8330
/CalendarServer/branches/users/glyph/new-export:7444-7485
/CalendarServer/branches/users/glyph/oracle:7106-7155
/CalendarServer/branches/users/glyph/oracle-nulls:7340-7351
/CalendarServer/branches/users/glyph/other-html:8062-8091
/CalendarServer/branches/users/glyph/parallel-sim:8240-8251
/CalendarServer/branches/users/glyph/quota:7604-7637
/CalendarServer/branches/users/glyph/sendfdport:5388-5424
/CalendarServer/branches/users/glyph/shared-pool-take2:8155-8174
/CalendarServer/branches/users/glyph/sharedpool:6490-6550
/CalendarServer/branches/users/glyph/sql-store:5929-6073
/CalendarServer/branches/users/glyph/subtransactions:7248-7258
/CalendarServer/branches/users/glyph/uidexport:7673-7676
/CalendarServer/branches/users/glyph/use-system-twisted:5084-5149
/CalendarServer/branches/users/glyph/xattrs-from-files:7757-7769
/CalendarServer/branches/users/sagen/applepush:8126-8184
/CalendarServer/branches/users/sagen/inboxitems:7380-7381
/CalendarServer/branches/users/sagen/locations-resources:5032-5051
/CalendarServer/branches/users/sagen/locations-resources-2:5052-5061
/CalendarServer/branches/users/sagen/purge_old_events:6735-6746
/CalendarServer/branches/users/sagen/resource-delegates-4038:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066:4068-4075
/CalendarServer/branches/users/sagen/resources-2:5084-5093
/CalendarServer/branches/users/wsanchez/transations:5515-5593

Modified: CalendarServer/trunk/calendarserver/tap/caldav.py
===================================================================
--- CalendarServer/trunk/calendarserver/tap/caldav.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/calendarserver/tap/caldav.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -57,8 +57,9 @@
 from twext.web2.channel.http import LimitingHTTPFactory, SSLRedirectRequest
 from twext.web2.metafd import ConnectionLimiter, ReportingHTTPService
 
-from txdav.common.datastore.util import UpgradeToDatabaseService,\
-    UpgradeDatabaseSchemaService
+from txdav.common.datastore.upgrade.migrate import UpgradeToDatabaseService
+from txdav.common.datastore.upgrade.sql.upgrade import UpgradeDatabaseSchemaService,\
+    UpgradeDatabaseDataService
 
 from twistedcaldav.config import ConfigurationError
 from twistedcaldav.config import config
@@ -942,9 +943,12 @@
             mainService = createMainService(cp, store)
             upgradeSvc = UpgradeFileSystemFormatService(config,
                 UpgradeDatabaseSchemaService.wrapService(
-                    UpgradeToDatabaseService.wrapService(
-                        CachingFilePath(config.DocumentRoot),
-                        PostDBImportService(config, store, mainService),
+                    UpgradeDatabaseDataService.wrapService(
+                        UpgradeToDatabaseService.wrapService(
+                            CachingFilePath(config.DocumentRoot),
+                            PostDBImportService(config, store, mainService),
+                            store, uid=uid, gid=gid
+                        ),
                         store, uid=uid, gid=gid
                     ),
                     store, uid=uid, gid=gid

Copied: CalendarServer/trunk/doc/RFC/draft-daboo-caldav-extensions.txt (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/doc/RFC/draft-daboo-caldav-extensions.txt)
===================================================================
--- CalendarServer/trunk/doc/RFC/draft-daboo-caldav-extensions.txt	                        (rev 0)
+++ CalendarServer/trunk/doc/RFC/draft-daboo-caldav-extensions.txt	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,672 @@
+
+
+
+Network Working Group                                           C. Daboo
+Internet-Draft                                                     Apple
+Intended status: Standards Track                        October 28, 2011
+Expires: April 30, 2012
+
+
+                     Collected Extensions to CalDAV
+                    draft-daboo-caldav-extensions-01
+
+Abstract
+
+   This document defines a set of extensions to the CalDAV calendar
+   access protocol.
+
+Status of this Memo
+
+   This Internet-Draft is submitted in full conformance with the
+   provisions of BCP 78 and BCP 79.
+
+   Internet-Drafts are working documents of the Internet Engineering
+   Task Force (IETF).  Note that other groups may also distribute
+   working documents as Internet-Drafts.  The list of current Internet-
+   Drafts is at http://datatracker.ietf.org/drafts/current/.
+
+   Internet-Drafts are draft documents valid for a maximum of six months
+   and may be updated, replaced, or obsoleted by other documents at any
+   time.  It is inappropriate to use Internet-Drafts as reference
+   material or to cite them other than as "work in progress."
+
+   This Internet-Draft will expire on April 30, 2012.
+
+Copyright Notice
+
+   Copyright (c) 2011 IETF Trust and the persons identified as the
+   document authors.  All rights reserved.
+
+   This document is subject to BCP 78 and the IETF Trust's Legal
+   Provisions Relating to IETF Documents
+   (http://trustee.ietf.org/license-info) in effect on the date of
+   publication of this document.  Please review these documents
+   carefully, as they describe your rights and restrictions with respect
+   to this document.  Code Components extracted from this document must
+   include Simplified BSD License text as described in Section 4.e of
+   the Trust Legal Provisions and are provided without warranty as
+   described in the Simplified BSD License.
+
+
+
+
+
+
+Daboo                    Expires April 30, 2012                 [Page 1]
+
+Internet-Draft              CalDAV Extensions               October 2011
+
+
+Table of Contents
+
+   1.  Introduction . . . . . . . . . . . . . . . . . . . . . . . . .  3
+   2.  Conventions Used in This Document  . . . . . . . . . . . . . .  3
+   3.  Extended Calendar Query Report . . . . . . . . . . . . . . . .  3
+     3.1.  CALDAV:comp-filter XML Element . . . . . . . . . . . . . .  4
+     3.2.  CALDAV:prop-filter XML Element . . . . . . . . . . . . . .  5
+     3.3.  CALDAV:text-match XML Element  . . . . . . . . . . . . . .  5
+     3.4.  Examples . . . . . . . . . . . . . . . . . . . . . . . . .  6
+   4.  Advertising Supported Calendar Component Sets  . . . . . . . .  7
+     4.1.  CALDAV:supported-calendar-component-sets Property  . . . .  8
+   5.  Filtering by Calendar Component Type . . . . . . . . . . . . .  9
+   6.  Security Considerations  . . . . . . . . . . . . . . . . . . . 10
+   7.  IANA Considerations  . . . . . . . . . . . . . . . . . . . . . 10
+   8.  Acknowledgments  . . . . . . . . . . . . . . . . . . . . . . . 10
+   9.  References . . . . . . . . . . . . . . . . . . . . . . . . . . 11
+     9.1.  Normative References . . . . . . . . . . . . . . . . . . . 11
+     9.2.  Informative References . . . . . . . . . . . . . . . . . . 11
+   Appendix A.  Change History (To be removed by RFC Editor
+                before publication) . . . . . . . . . . . . . . . . . 11
+   Author's Address . . . . . . . . . . . . . . . . . . . . . . . . . 12
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Daboo                    Expires April 30, 2012                 [Page 2]
+
+Internet-Draft              CalDAV Extensions               October 2011
+
+
+1.  Introduction
+
+   [RFC4791] defines the CalDAV Calendar Access protocol for accessing
+   calendar data stored on a server.  With the popularity of CalDAV
+   increasing, a number of useful extensions have been proposed to
+   improve the protocol.  This specification collects several of those
+   extensions into one document for convenience.  Each extension defined
+   in this specification can be implemented independently of any of the
+   others.
+
+   Discussion of this Internet-Draft is taking place on the mailing list
+   <https://www.ietf.org/mailman/listinfo/caldav>.
+
+
+2.  Conventions Used in This Document
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
+   "OPTIONAL" in this document are to be interpreted as described in
+   [RFC2119].
+
+   Other notations used in this memo follow the notations of [RFC4791].
+
+
+3.  Extended Calendar Query Report
+
+   The CALDAV:calendar-query report defined in Section 7.8 of [RFC4791]
+   allows a client to search calendar data for a match to iCalendar
+   component, property or parameter details.  As defined, this option
+   supports querying multiple attributes of the iCalendar data at
+   various "nesting" levels based on the syntactic structure of
+   iCalendar itself.  When multiple attributes are queried at the same
+   level, each has to match for the query to be successful - effectively
+   defining a logical "and" operation.  This does not allow clients to
+   execute a single query to match different attributes of different
+   component types (e.g., clients cannot search for VEVENTs with a
+   particular time-range, or VTODOs that are not completed).  Since
+   there is a need to be able to execute such queries, a logical "or"
+   operation is needed.
+
+   This specification adds a "test" XML attribute to the CALDAV:comp-
+   filter and CALDAV:prop-filter XML elements that accepts values of
+   "allof" or "anyof" to indicate logical "and" or "or" operations
+   respectively.  This copies the behavior defined for CARDDAV:
+   addressbook-query reports defined in Section 10.5 of [RFC6352], with
+   the exception that the default value for the attribute is "allof" to
+   match the current behavior.
+
+
+
+
+Daboo                    Expires April 30, 2012                 [Page 3]
+
+Internet-Draft              CalDAV Extensions               October 2011
+
+
+   The text comparison operation in [RFC4791] is a simple "contains"
+   operation, however more sophisticated comparisons are sometimes
+   needed (e.g., 'starts with', 'equals', etc).
+
+   This specification adds a "match-type" XML attribute to the CALDAV:
+   text-match XML element that accepts values of "equals", "contains",
+   "starts-with", or "ends-with", to indicate the comparison operation
+   to be used.  This copies the behavior defined for CARDDAV:
+   addressbook-query reports defined in Section 10.5.4 of [RFC6352].
+
+   Sometimes clients want to search all component types for a match
+   (e.g., clients cannot find all calendar object resources that contain
+   a SUMMARY property value matching some text irrespective of the top-
+   level component type).
+
+   This specification allows the use of a single "*" character in the
+   "name" attribute of "comp-filter" elements to require the server to
+   match any component type.
+
+   Servers advertise support for this extension by including the token
+   "calendar-query-extended" in the DAV response header to an OPTIONS
+   request on any resource supporting the extended query report.
+   Clients MUST check for the presence of that token before using the
+   "test" or "match-type" XML attributes.
+
+   This specification extends the [RFC4791] XML syntax for the CALDAV:
+   comp-filter, CALDAV:prop-filter and CALDAV:text-match XML elements as
+   follows.
+
+3.1.  CALDAV:comp-filter XML Element
+
+   XML Element:  CALDAV:comp-filter
+
+   Updated Definition:
+
+   <!ELEMENT comp-filter (is-not-defined | (time-range?,
+                          prop-filter*, comp-filter*))>
+
+   <!ATTLIST comp-filter name CDATA #REQUIRED
+                         test (allof | anyof) "allof">
+   <!-- name value:
+           a calendar object or calendar component type (e.g., VEVENT),
+           or the value "*" to indicate a match against any type
+
+        test value:
+           allof logical AND for matches
+           anyof logical OR for matches
+    -->
+
+
+
+Daboo                    Expires April 30, 2012                 [Page 4]
+
+Internet-Draft              CalDAV Extensions               October 2011
+
+
+   Additional Description:  The "test" attribute specifies whether any
+      (logical OR) or all (logical AND) of the is-not-defined, time-
+      range, comp-filter or param-filter tests need to match in order
+      for the overall filter to match.
+
+3.2.  CALDAV:prop-filter XML Element
+
+   XML Element:  CALDAV:prop-filter
+
+   Updated Definition:
+
+   <!ELEMENT prop-filter (is-not-defined |
+                          ((time-range | text-match)?,
+                           param-filter*))>
+
+   <!ATTLIST prop-filter name CDATA #REQUIRED
+                         test (allof | anyof) "allof">
+   <!-- name value:
+           a calendar property name (e.g., ATTENDEE)
+
+        test value:
+           allof logical AND for matches
+           anyof logical OR for matches
+    -->
+
+   Additional Description:  The "test" attribute specifies whether any
+      (logical OR) or all (logical AND) of the is-not-defined, time-
+      range, text-filter or param-filter tests need to match in order
+      for the overall filter to match.
+
+3.3.  CALDAV:text-match XML Element
+
+   XML Element:  CALDAV:text-match
+
+   Updated Definition:
+
+   <!ELEMENT text-match (#PCDATA)>
+   <!-- PCDATA value: string -->
+
+   <!ATTLIST text-match
+       collation        CDATA "i;ascii-casemap"
+       negate-condition (yes | no) "no"
+       match-type (equals|contains|starts-with|ends-with) "contains">
+
+   Additional Description:  The "match-type" attribute is used to
+      indicate the type of match operation to use.  Possible choices
+      are:
+
+
+
+
+Daboo                    Expires April 30, 2012                 [Page 5]
+
+Internet-Draft              CalDAV Extensions               October 2011
+
+
+         "equals" - an exact match to the target string
+
+         "contains" - a substring match, matching anywhere within the
+         target string
+
+         "starts-with" - a substring match, matching only at the start
+         of the target string
+
+         "ends-with" - a substring match, matching only at the end of
+         the target string
+
+3.4.  Examples
+
+   In this request, the client is querying for VEVENTs that start on or
+   after a specific date, or VTODOs that are not completed and not
+   cancelled.
+
+   REPORT /bernard/work/ HTTP/1.1
+   Host: cal.example.com
+   Depth: 1
+   Content-Type: application/xml; charset="utf-8"
+   Content-Length: xxxx
+
+   <?xml version="1.0" encoding="utf-8" ?>
+   <C:calendar-query xmlns:D="DAV:"
+                 xmlns:C="urn:ietf:params:xml:ns:caldav">
+     <D:prop>
+       <D:getetag/>
+     </D:prop>
+     <C:filter>
+       <C:comp-filter name="VCALENDAR" test="anyof">
+         <C:comp-filter name="VEVENT">
+           <C:time-range start="20110101T000000Z"/>
+         </C:comp-filter>
+         <C:comp-filter name="VTODO" test="allof">
+           <C:prop-filter name="COMPLETED">
+             <C:is-not-defined/>
+           </C:prop-filter>
+           <C:prop-filter name="STATUS">
+             <C:text-match
+                negate-condition="yes"
+                match-type="equals">CANCELLED</C:text-match>
+           </C:prop-filter>
+         </C:comp-filter>
+       </C:comp-filter>
+     </C:filter>
+   </C:calendar-query>
+
+
+
+
+Daboo                    Expires April 30, 2012                 [Page 6]
+
+Internet-Draft              CalDAV Extensions               October 2011
+
+
+   In this request, the client is querying for any component that
+   contains a VALARM sub-component.
+
+   REPORT /bernard/work/ HTTP/1.1
+   Host: cal.example.com
+   Depth: 1
+   Content-Type: application/xml; charset="utf-8"
+   Content-Length: xxxx
+
+   <?xml version="1.0" encoding="utf-8" ?>
+   <C:calendar-query xmlns:D="DAV:"
+                 xmlns:C="urn:ietf:params:xml:ns:caldav">
+     <D:prop>
+       <D:getetag/>
+     </D:prop>
+     <C:filter>
+       <C:comp-filter name="VCALENDAR">
+         <C:comp-filter name="*">
+           <C:comp-filter name="VALARM" />
+         </C:comp-filter>
+       </C:comp-filter>
+     </C:filter>
+   </C:calendar-query>
+
+
+4.  Advertising Supported Calendar Component Sets
+
+   CalDAV [RFC4791] supports the notion of calendar collections that are
+   restricted to only containing components of a certain type, or set of
+   types.  The protocol allows clients to specify the restricted
+   component sets by supplying a CALDAV:supported-calendar-component-set
+   WebDAV property in an MKCALENDAR or extended MKCOL [RFC5689] request
+   that creates a calendar collection.  However, servers themselves
+   might need to restrict the allowed sets of components that can be
+   used in any one calendar (e.g., some servers might only support
+   calendar collections containing components of one type).  Currently
+   there is no way for a client to determine what the allowed
+   combination of component types is for use with MKCALENDAR or extended
+   MKCOL.
+
+   This specification adds a new CALDAV:supported-calendar-component-
+   sets WebDAV property for use on calendar home collections.  This
+   property enumerates the allowed sets of calendar components that the
+   server will support for use with MKCALENDAR or extended MKCOL
+   requests.  Clients SHOULD check for the presence of this property
+   before issuing an MKCALENDAR or extended MKCOL request that includes
+   a CALDAV:supported-calendar-component-set WebDAV property.  When the
+   new property is found on a calendar home, clients MUST only use a
+
+
+
+Daboo                    Expires April 30, 2012                 [Page 7]
+
+Internet-Draft              CalDAV Extensions               October 2011
+
+
+   CALDAV:supported-calendar-component-set is one advertised as being
+   supported.
+
+4.1.  CALDAV:supported-calendar-component-sets Property
+
+   Name:  supported-calendar-component-sets
+
+   Namespace:  urn:ietf:params:xml:ns:caldav
+
+   Purpose:  Enumerates the sets of component restrictions the server is
+      willing to allow the client to specify in MKCALENDAR or extended
+      MKCOL requests.
+
+   Protected:  This property MUST be protected and SHOULD NOT be
+      returned by a PROPFIND allprop request (as defined in Section 14.2
+      of [RFC4918]).
+
+   COPY/MOVE behavior:  This property value MUST be preserved in COPY
+      and MOVE operations.
+
+   Description:  If servers apply restrictions on the allowed calendar
+      component sets used when creating a calendar, then those servers
+      SHOULD advertise this property on each calendar home collection
+      within which the restrictions apply.  In the absence of this
+      property, clients cannot assume anything about whether the server
+      will enforce a set of restrictions or not - in that case clients
+      need to handle the server rejecting certain combinations of
+      restricted component sets.  If this property is present, but
+      contains no child XML elements, then clients can assume that the
+      server imposes no restrictions on the combinations of component
+      types it is willing to accept.  If present, each CALDAV:supported-
+      calendar-component-set element represents a valid restriction the
+      client can use in an MKCALENDAR or extended MKCOL request when
+      creating a calendar.
+
+   Definition:
+
+      <!ELEMENT supported-calendar-component-sets
+                (supported-calendar-component-set*) >
+      <!-- supported-calendar-component-set defined in RFC4791 -->
+
+   Example:
+
+
+
+
+
+
+
+
+
+Daboo                    Expires April 30, 2012                 [Page 8]
+
+Internet-Draft              CalDAV Extensions               October 2011
+
+
+   <C:supported-calendar-component-sets
+        xmlns:C="urn:ietf:params:xml:ns:caldav">
+
+     <!-- Calendars with any standard iCalendar component -->
+     <C:supported-calendar-component-set>
+       <C:comp name="VEVENT" />
+       <C:comp name="VFREEBUSY" />
+       <C:comp name="VJOURNAL" />
+       <C:comp name="VTODO" />
+     </C:supported-calendar-component-set>
+
+     <!-- Calendars with just VEVENT or VFREEBUSY -->
+     <C:supported-calendar-component-set>
+       <C:comp name="VEVENT" />
+       <C:comp name="VFREEBUSY" />
+     </C:supported-calendar-component-set>
+
+     <!-- Calendars with just VEVENT -->
+     <C:supported-calendar-component-set>
+       <C:comp name="VEVENT" />
+     </C:supported-calendar-component-set>
+
+     <!-- Calendars with just VTODO -->
+     <C:supported-calendar-component-set>
+       <C:comp name="VTODO" />
+     </C:supported-calendar-component-set>
+   </C:supported-calendar-component-sets>
+
+
+5.  Filtering by Calendar Component Type
+
+   Calendar clients are sometimes "scoped" to only utilize one type of
+   main calendar component type (e.g., a scheduling client that only
+   handles "VEVENT" components, or a task manager that only handles
+   "VTODO" components).  CalDAV provides a calendar query report that
+   allows clients to find only calendar object resources that contain a
+   specified main component type, which is useful when initially loading
+   the contents of a calendar into a local cache.  However, clients also
+   need to keep that cache updated as changes occur on the server.  One
+   way to do that is to use the WebDAV sync report
+   [I-D.daboo-webdav-sync], but that report will return changes for all
+   calendar object resources within a calendar collection.  Thus
+   "scoped" clients will be forced to load calendar object resources
+   containing component types they do not care about to discover what
+   type they are, or issue additional queries to see whether the changes
+   reported by the sync report are for component types it handles.  A
+   better approach would be to have a way for the WebDAV sync report
+   response to include details of the calendar component type for each
+
+
+
+Daboo                    Expires April 30, 2012                 [Page 9]
+
+Internet-Draft              CalDAV Extensions               October 2011
+
+
+   calendar object resource that it reports as changed.
+
+   To better "scope" a WebDAV sync report, this specification recommends
+   that servers SHOULD always include a "component=" parameter (as
+   defined in Section 8.1 of [RFC5545]) in the DAV:getcontenttype WebDAV
+   property media-type value reported for calendar object resources.
+   Clients can then request that property be returned in the WebDAV sync
+   report response for each resource, and thus quickly determine which
+   changes are relevant to them based on component type.
+
+   Example partial WebDAV sync report response with a component type
+   included.
+
+   <D:response>
+     <D:href
+   >http://calendar.example.com/cyrusdaboo/calendar.ics</D:href>
+     <D:propstat>
+       <D:prop>
+         <D:getetag>"00003-abcd1"</D:getetag>
+         <D:getcontenttype
+         >text/calendar;charset=utf-8;component=vevent<
+         /D:getcontenttype>
+       </D:prop>
+       <D:status>HTTP/1.1 200 OK</D:status>
+     </D:propstat>
+    </D:response>
+
+
+6.  Security Considerations
+
+   This specification does not introduce any new security concerns
+   beyond those addressed in CalDAV [RFC4791] and iCalendar [RFC5545].
+
+
+7.  IANA Considerations
+
+   No IANA actions are needed.
+
+
+8.  Acknowledgments
+
+   Thanks to Bernard Desruisseaux, Mike Douglass, Jeffrey Harris, Arnaud
+   Quillaud, and Nick Zitzmann.  This specification came about via
+   discussions at the Calendaring and Scheduling Consortium.
+
+
+9.  References
+
+
+
+
+Daboo                    Expires April 30, 2012                [Page 10]
+
+Internet-Draft              CalDAV Extensions               October 2011
+
+
+9.1.  Normative References
+
+   [I-D.daboo-webdav-sync]
+              Daboo, C. and A. Quillaud, "Collection Synchronization for
+              WebDAV", draft-daboo-webdav-sync-06 (work in progress),
+              July 2011.
+
+   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
+              Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [RFC4791]  Daboo, C., Desruisseaux, B., and L. Dusseault,
+              "Calendaring Extensions to WebDAV (CalDAV)", RFC 4791,
+              March 2007.
+
+   [RFC4918]  Dusseault, L., "HTTP Extensions for Web Distributed
+              Authoring and Versioning (WebDAV)", RFC 4918, June 2007.
+
+   [RFC5545]  Desruisseaux, B., "Internet Calendaring and Scheduling
+              Core Object Specification (iCalendar)", RFC 5545,
+              September 2009.
+
+   [RFC5689]  Daboo, C., "Extended MKCOL for Web Distributed Authoring
+              and Versioning (WebDAV)", RFC 5689, September 2009.
+
+9.2.  Informative References
+
+   [RFC6352]  Daboo, C., "CardDAV: vCard Extensions to Web Distributed
+              Authoring and Versioning (WebDAV)", RFC 6352, August 2011.
+
+
+Appendix A.  Change History (To be removed by RFC Editor before
+             publication)
+
+   Changes in -01:
+
+   1.  Changed description of COPY/MOVE for supported-calendar-
+       component-sets property
+
+   2.  Removed bogus text in property description.
+
+   3.  Changed supported-calendar-component-sets to use supported-
+       calendar-component-set as a child element.
+
+   4.  Added recommendation to use "component=" parameter in DAV:
+       getcontenttype WebDAV properties on calendar object resources.
+
+
+
+
+
+
+Daboo                    Expires April 30, 2012                [Page 11]
+
+Internet-Draft              CalDAV Extensions               October 2011
+
+
+Author's Address
+
+   Cyrus Daboo
+   Apple Inc.
+   1 Infinite Loop
+   Cupertino, CA  95014
+   USA
+
+   Email: cyrus at daboo.name
+   URI:   http://www.apple.com/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Daboo                    Expires April 30, 2012                [Page 12]
+


Property changes on: CalendarServer/trunk/support/build.sh
___________________________________________________________________
Modified: svn:mergeinfo
   - /CalendarServer/branches/config-separation/support/build.sh:4379-4443
/CalendarServer/branches/egg-info-351/support/build.sh:4589-4615
/CalendarServer/branches/generic-sqlstore/support/build.sh:6167-6191
/CalendarServer/branches/new-store-no-caldavfile-2/support/build.sh:5936-5981
/CalendarServer/branches/new-store-no-caldavfile/support/build.sh:5911-5935
/CalendarServer/branches/new-store/support/build.sh:5594-5934
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692/support/build.sh:5693-5702
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627/support/build.sh:3628-3644
/CalendarServer/branches/users/cdaboo/implicituidrace/support/build.sh:8137-8141
/CalendarServer/branches/users/cdaboo/more-sharing-5591/support/build.sh:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464/support/build.sh:4465-4957
/CalendarServer/branches/users/cdaboo/pods/support/build.sh:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar/support/build.sh:7085-7206
/CalendarServer/branches/users/cdaboo/pycard/support/build.sh:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes/support/build.sh:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070/support/build.sh:5071-5105
/CalendarServer/branches/users/cdaboo/shared-calendars-5187/support/build.sh:5188-5440
/CalendarServer/branches/users/cdaboo/timezones/support/build.sh:7443-7699
/CalendarServer/branches/users/glyph/conn-limit/support/build.sh:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge/support/build.sh:4971-5080
/CalendarServer/branches/users/glyph/dalify/support/build.sh:6932-7023
/CalendarServer/branches/users/glyph/db-reconnect/support/build.sh:6824-6876
/CalendarServer/branches/users/glyph/deploybuild/support/build.sh:7563-7572
/CalendarServer/branches/users/glyph/dont-start-postgres/support/build.sh:6592-6614
/CalendarServer/branches/users/glyph/linux-tests/support/build.sh:6893-6900
/CalendarServer/branches/users/glyph/misc-portability-fixes/support/build.sh:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6/support/build.sh:6322-6368
/CalendarServer/branches/users/glyph/more-deferreds-7/support/build.sh:6369-6445
/CalendarServer/branches/users/glyph/new-export/support/build.sh:7444-7485
/CalendarServer/branches/users/glyph/oracle-nulls/support/build.sh:7340-7351
/CalendarServer/branches/users/glyph/sendfdport/support/build.sh:5388-5424
/CalendarServer/branches/users/glyph/sharedpool/support/build.sh:6490-6550
/CalendarServer/branches/users/glyph/sql-store/support/build.sh:5929-6073
/CalendarServer/branches/users/glyph/subtransactions/support/build.sh:7248-7258
/CalendarServer/branches/users/glyph/use-system-twisted/support/build.sh:5084-5149
/CalendarServer/branches/users/sagen/applepush/support/build.sh:8126-8184
/CalendarServer/branches/users/sagen/inboxitems/support/build.sh:7380-7381
/CalendarServer/branches/users/sagen/locations-resources-2/support/build.sh:5052-5061
/CalendarServer/branches/users/sagen/locations-resources/support/build.sh:5032-5051
/CalendarServer/branches/users/sagen/purge_old_events/support/build.sh:6735-6746
/CalendarServer/branches/users/sagen/resource-delegates-4038/support/build.sh:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066/support/build.sh:4068-4075
/CalendarServer/branches/users/sagen/resources-2/support/build.sh:5084-5093
/CalendarServer/branches/users/wsanchez/transations/support/build.sh:5515-5593
   + /CalendarServer/branches/config-separation/support/build.sh:4379-4443
/CalendarServer/branches/egg-info-351/support/build.sh:4589-4615
/CalendarServer/branches/generic-sqlstore/support/build.sh:6167-6191
/CalendarServer/branches/new-store-no-caldavfile-2/support/build.sh:5936-5981
/CalendarServer/branches/new-store-no-caldavfile/support/build.sh:5911-5935
/CalendarServer/branches/new-store/support/build.sh:5594-5934
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692/support/build.sh:5693-5702
/CalendarServer/branches/users/cdaboo/component-set-fixes/support/build.sh:8130-8346
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627/support/build.sh:3628-3644
/CalendarServer/branches/users/cdaboo/implicituidrace/support/build.sh:8137-8141
/CalendarServer/branches/users/cdaboo/more-sharing-5591/support/build.sh:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464/support/build.sh:4465-4957
/CalendarServer/branches/users/cdaboo/pods/support/build.sh:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar/support/build.sh:7085-7206
/CalendarServer/branches/users/cdaboo/pycard/support/build.sh:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes/support/build.sh:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070/support/build.sh:5071-5105
/CalendarServer/branches/users/cdaboo/shared-calendars-5187/support/build.sh:5188-5440
/CalendarServer/branches/users/cdaboo/timezones/support/build.sh:7443-7699
/CalendarServer/branches/users/glyph/conn-limit/support/build.sh:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge/support/build.sh:4971-5080
/CalendarServer/branches/users/glyph/dalify/support/build.sh:6932-7023
/CalendarServer/branches/users/glyph/db-reconnect/support/build.sh:6824-6876
/CalendarServer/branches/users/glyph/deploybuild/support/build.sh:7563-7572
/CalendarServer/branches/users/glyph/dont-start-postgres/support/build.sh:6592-6614
/CalendarServer/branches/users/glyph/linux-tests/support/build.sh:6893-6900
/CalendarServer/branches/users/glyph/misc-portability-fixes/support/build.sh:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6/support/build.sh:6322-6368
/CalendarServer/branches/users/glyph/more-deferreds-7/support/build.sh:6369-6445
/CalendarServer/branches/users/glyph/new-export/support/build.sh:7444-7485
/CalendarServer/branches/users/glyph/oracle-nulls/support/build.sh:7340-7351
/CalendarServer/branches/users/glyph/sendfdport/support/build.sh:5388-5424
/CalendarServer/branches/users/glyph/sharedpool/support/build.sh:6490-6550
/CalendarServer/branches/users/glyph/sql-store/support/build.sh:5929-6073
/CalendarServer/branches/users/glyph/subtransactions/support/build.sh:7248-7258
/CalendarServer/branches/users/glyph/use-system-twisted/support/build.sh:5084-5149
/CalendarServer/branches/users/sagen/applepush/support/build.sh:8126-8184
/CalendarServer/branches/users/sagen/inboxitems/support/build.sh:7380-7381
/CalendarServer/branches/users/sagen/locations-resources-2/support/build.sh:5052-5061
/CalendarServer/branches/users/sagen/locations-resources/support/build.sh:5032-5051
/CalendarServer/branches/users/sagen/purge_old_events/support/build.sh:6735-6746
/CalendarServer/branches/users/sagen/resource-delegates-4038/support/build.sh:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066/support/build.sh:4068-4075
/CalendarServer/branches/users/sagen/resources-2/support/build.sh:5084-5093
/CalendarServer/branches/users/wsanchez/transations/support/build.sh:5515-5593

Modified: CalendarServer/trunk/twistedcaldav/caldavxml.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/caldavxml.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/twistedcaldav/caldavxml.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -188,10 +188,21 @@
     name = "calendar-timezone"
     hidden = True
 
+class SupportedCalendarComponentSets (CalDAVElement):
+    """
+    Indicates what set of calendar components the server is willing to allow
+    the client to use in MKCALENDAR.
+    (CalDAV-extensions, draft-daboo-caldav-extensions section XXX)
+    """
+    name = "supported-calendar-component-sets"
+    hidden = True
+    protected = True
+
+    allowed_children = { (caldav_namespace, "supported-calendar-component-set"): (0, None) }
+
 class SupportedCalendarComponentSet (CalDAVElement):
     """
-    Provides a human-readable description of what this calendar collection
-    represents.
+    Indicates what set of calendar components are allowed in a collection.
     (CalDAV-access, RFC 4791 section 5.2.3)
     """
     name = "supported-calendar-component-set"

Modified: CalendarServer/trunk/twistedcaldav/customxml.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/customxml.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/twistedcaldav/customxml.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -60,6 +60,17 @@
     "calendarserver-sharing-no-scheduling",
 )
 
+class TwistedCalendarSupportedComponents (davxml.WebDAVTextElement):
+    """
+    Contains the calendar supported components list.
+    """
+    namespace = twisted_dav_namespace
+    name = "calendar-supported-components"
+    hidden = True
+
+    def getValue(self):
+        return str(self)
+
 class TwistedCalendarAccessProperty (davxml.WebDAVTextElement):
     """
     Contains the calendar access level (private events) for the resource.
@@ -507,6 +518,15 @@
         (calendarserver_namespace, "action" )      : (0, 1), # Have to allow 0 as element is empty in PROPFIND requests
     }
 
+class ScheduleDefaultTasksURL (davxml.WebDAVElement):
+    """
+    A single href indicating which calendar is the default for VTODO scheduling.
+    """
+    namespace = calendarserver_namespace
+    name = "schedule-default-tasks-URL"
+
+    allowed_children = { (davxml.dav_namespace, "href"): (0, 1) }
+
 class DTStamp (davxml.WebDAVTextElement):
     """
     A UTC timestamp in iCal format.

Modified: CalendarServer/trunk/twistedcaldav/method/copymove.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/copymove.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/twistedcaldav/method/copymove.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -131,7 +131,7 @@
     result, sourcecal, sourceparent, destination_uri, destination, destinationcal, destinationparent = (yield checkForCalendarAction(self, request))
     if not result:
         is_calendar_collection = isPseudoCalendarCollectionResource(self)
-        defaultCalendar = (yield self.isDefaultCalendar(request)) if is_calendar_collection else False
+        defaultCalendarType = (yield self.isDefaultCalendar(request)) if is_calendar_collection else None
         is_addressbook_collection = isAddressBookCollectionResource(self)
         defaultAddressBook = (yield self.isDefaultAddressBook(request)) if is_addressbook_collection else False
 
@@ -146,7 +146,7 @@
         if result == responsecode.NO_CONTENT:
             if is_calendar_collection:
                 # Do some clean up
-                yield self.movedCalendar(request, defaultCalendar, destination, destination_uri)
+                yield self.movedCalendar(request, defaultCalendarType, destination, destination_uri)
             elif is_addressbook_collection:
                 # Do some clean up
                 yield self.movedAddressBook(request, defaultAddressBook, destination, destination_uri)

Modified: CalendarServer/trunk/twistedcaldav/method/mkcalendar.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/mkcalendar.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/twistedcaldav/method/mkcalendar.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -13,6 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 ##
+from twistedcaldav.config import config
 
 """
 CalDAV MKCALENDAR method.
@@ -76,6 +77,7 @@
         log.err("Error while handling MKCALENDAR: %s" % (e,))
         raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, str(e)))
 
+    set_supported_component_set = False
     if doc is not None:
         makecalendar = doc.root_element
         if not isinstance(makecalendar, caldavxml.MakeCalendar):
@@ -92,7 +94,8 @@
             for property in makecalendar.children[0].children[0].children:
                 try:
                     if property.qname() == (caldavxml.caldav_namespace, "supported-calendar-component-set"):
-                        self.writeDeadProperty(property)
+                        yield self.setSupportedComponentSet(property)
+                        set_supported_component_set = True
                     else:
                         yield self.writeProperty(property, request)
                 except HTTPError:
@@ -106,5 +109,10 @@
             self.transactionError()
             errors.error()
             raise HTTPError(MultiStatusResponse([errors.response()]))
+        
+    # When calendar collections are single component only, default MKCALENDAR is VEVENT only
+    if not set_supported_component_set and config.RestrictCalendarsToOneComponentType:
+        yield self.setSupportedComponents(("VEVENT",))
+            
 
     returnValue(responsecode.CREATED)

Modified: CalendarServer/trunk/twistedcaldav/method/mkcol.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/mkcol.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/twistedcaldav/method/mkcol.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -122,6 +122,7 @@
         errors = PropertyStatusResponseQueue("PROPPATCH", request.uri, responsecode.NO_CONTENT)
         got_an_error = False
     
+        set_supported_component_set = False
         if mkcol.children:
             # mkcol -> set -> prop -> property*
             properties = mkcol.children[0].children[0].children
@@ -166,7 +167,8 @@
             for property in mkcol.children[0].children[0].children:
                 try:
                     if rtype == "calendar" and property.qname() == (caldavxml.caldav_namespace, "supported-calendar-component-set"):
-                        self.writeDeadProperty(property)
+                        yield self.setSupportedComponentSet(property)
+                        set_supported_component_set = True
                     else:
                         yield self.writeProperty(property, request)
                 except HTTPError:
@@ -183,6 +185,10 @@
                     code=responsecode.FORBIDDEN,
                     stream=mkcolxml.MakeCollectionResponse(errors.response()).toxml()
             ))
+        
+        # When calendar collections are single component only, default MKCALENDAR is VEVENT only
+        if rtype == "calendar" and not set_supported_component_set and config.RestrictCalendarsToOneComponentType:
+            yield self.setSupportedComponents(("VEVENT",))
 
         yield returnValue(responsecode.CREATED)
     

Modified: CalendarServer/trunk/twistedcaldav/method/put_common.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/put_common.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/twistedcaldav/method/put_common.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -302,6 +302,16 @@
                         "Invalid calendar data",
                     ))
 
+                # Valid calendar component for check
+                result, message = self.validComponentType()
+                if not result:
+                    log.err(message)
+                    raise HTTPError(ErrorResponse(
+                        responsecode.FORBIDDEN,
+                        (caldav_namespace, "supported-component"),
+                        "Invalid calendar data",
+                    ))
+
                 # Valid attendee list size check
                 result, message = self.validAttendeeListSizeCheck()
                 if not result:
@@ -492,6 +502,19 @@
         
         return result, message
     
+    def validComponentType(self):
+        """
+        Make sure that any limits on the number of resources in a collection are enforced.
+        """
+        result = True
+        message = ""
+        
+        if not self.destinationparent.isSupportedComponent(self.calendar.mainType()):
+            result = False
+            message = "Invalid component type %s for calendar: %s" % (self.calendar.mainType(), self.destinationparent,)
+
+        return result, message
+        
     def validSizeCheck(self):
         """
         Make sure that the content-type of the source resource is text/calendar.

Modified: CalendarServer/trunk/twistedcaldav/resource.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/resource.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/twistedcaldav/resource.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -71,7 +71,6 @@
     PropertyNotFoundError, DAVResourceWithChildrenMixin
 from twistedcaldav.ical import Component
 
-from twistedcaldav.ical import allowedComponents
 from twistedcaldav.icaldav import ICalDAVResource, ICalendarPrincipalResource
 from twistedcaldav.linkresource import LinkResource
 from twistedcaldav.notify import (
@@ -447,10 +446,6 @@
                 
         return super(CalDAVResource, self).liveProperties() + baseProperties
 
-    supportedCalendarComponentSet = caldavxml.SupportedCalendarComponentSet(
-        *[caldavxml.CalendarComponent(name=item) for item in allowedComponents]
-    )
-
     def isShadowableProperty(self, qname):
         """
         Shadowable properties are ones on shared resources where a "default" exists until
@@ -595,12 +590,10 @@
             url = (yield self.canonicalURL(request))
             returnValue(davxml.AddMember(davxml.HRef.fromString(url + "/;add-member")))
 
-        elif qname == caldavxml.SupportedCalendarComponentSet.qname():
-            if self.hasDeadProperty(qname):
-                returnValue(self.readDeadProperty(qname))
-            returnValue(self.supportedCalendarComponentSet)
+        elif qname == caldavxml.SupportedCalendarComponentSet.qname() and self.isPseudoCalendarCollection():
+            returnValue(self.getSupportedComponentSet())
 
-        elif qname == caldavxml.SupportedCalendarData.qname():
+        elif qname == caldavxml.SupportedCalendarData.qname() and self.isPseudoCalendarCollection():
             returnValue(caldavxml.SupportedCalendarData(
                 caldavxml.CalendarData(**{
                     "content-type": "text/calendar",
@@ -608,19 +601,19 @@
                 }),
             ))
 
-        elif qname == caldavxml.MaxResourceSize.qname():
+        elif qname == caldavxml.MaxResourceSize.qname() and self.isPseudoCalendarCollection():
             if config.MaxResourceSize:
                 returnValue(caldavxml.MaxResourceSize.fromString(
                     str(config.MaxResourceSize)
                 ))
 
-        elif qname == caldavxml.MaxInstances.qname():
+        elif qname == caldavxml.MaxInstances.qname() and self.isPseudoCalendarCollection():
             if config.MaxAllowedInstances:
                 returnValue(caldavxml.MaxInstances.fromString(
                     str(config.MaxAllowedInstances)
                 ))
 
-        elif qname == caldavxml.MaxAttendeesPerInstance.qname():
+        elif qname == caldavxml.MaxAttendeesPerInstance.qname() and self.isPseudoCalendarCollection():
             if config.MaxAttendeesPerInstance:
                 returnValue(caldavxml.MaxAttendeesPerInstance.fromString(
                     str(config.MaxAttendeesPerInstance)
@@ -633,10 +626,10 @@
                     self.scheduleTag
                 ))
 
-        elif qname == caldavxml.ScheduleCalendarTransp.qname():
+        elif qname == caldavxml.ScheduleCalendarTransp.qname() and self.isCalendarCollection():
             # For backwards compatibility, if the property does not exist we need to create
             # it and default to the old free-busy-set value.
-            if self.isCalendarCollection() and not self.hasDeadProperty(property):
+            if not self.hasDeadProperty(property):
                 # For backwards compatibility we need to sync this up with the calendar-free-busy-set on the inbox
                 principal = (yield self.resourceOwnerPrincipal(request))
                 fbset = (yield principal.calendarFreeBusyURIs(request))
@@ -646,7 +639,7 @@
                 opaque = url in fbset
                 self.writeDeadProperty(caldavxml.ScheduleCalendarTransp(caldavxml.Opaque() if opaque else caldavxml.Transparent()))
 
-        elif qname == carddavxml.SupportedAddressData.qname():
+        elif qname == carddavxml.SupportedAddressData.qname() and self.isAddressBookCollection():
             # CardDAV, section 6.2.2
             returnValue(carddavxml.SupportedAddressData(
                 carddavxml.AddressDataType(**{
@@ -655,7 +648,7 @@
                 }),
             ))
 
-        elif qname == carddavxml.MaxResourceSize.qname():
+        elif qname == carddavxml.MaxResourceSize.qname() and self.isAddressBookCollection():
             # CardDAV, section 6.2.3
             if config.MaxResourceSize:
                 returnValue(carddavxml.MaxResourceSize.fromString(
@@ -1076,7 +1069,7 @@
             inbox.processFreeBusyCalendar(request.path, False)
 
     @inlineCallbacks
-    def movedCalendar(self, request, defaultCalendar, destination, destination_uri):
+    def movedCalendar(self, request, defaultCalendarType, destination, destination_uri):
         """
         Calendar has been moved. Need to do some extra clean-up.
         """
@@ -1092,8 +1085,8 @@
             inbox.processFreeBusyCalendar(destination_uri, destination.isCalendarOpaque())
             
             # Adjust the default calendar setting if necessary
-            if defaultCalendar:
-                yield inbox.writeProperty(caldavxml.ScheduleDefaultCalendarURL(davxml.HRef(destination_path)), request)               
+            if defaultCalendarType is not None:
+                yield inbox.writeProperty(defaultCalendarType(davxml.HRef(destination_path)), request)               
 
     def isCalendarOpaque(self):
         
@@ -1115,13 +1108,10 @@
         inboxURL = principal.scheduleInboxURL()
         if inboxURL:
             inbox = (yield request.locateResource(inboxURL))
-            default = (yield inbox.readProperty((caldav_namespace, "schedule-default-calendar-URL"), request))
-            if default and len(default.children) == 1:
-                defaultURL = normalizeURL(str(default.children[0]))
-                myURL = (yield self.canonicalURL(request))
-                returnValue(defaultURL == myURL)
+            result = (yield inbox.isDefaultCalendar(request, self))
+            returnValue(result)
 
-        returnValue(False)
+        returnValue(None)
 
     @inlineCallbacks
     def iCalendarForUser(self, request):
@@ -2408,6 +2398,45 @@
         returnValue((storeHome, created))
 
 
+    def liveProperties(self):
+        
+        existing = super(CalendarHomeResource, self).liveProperties()
+        existing += (caldavxml.SupportedCalendarComponentSets.qname(),)
+        existing += (
+            (customxml.calendarserver_namespace, "xmpp-uri"),
+            (customxml.calendarserver_namespace, "xmpp-heartbeat-uri"),
+            (customxml.calendarserver_namespace, "xmpp-server"),
+        )
+        return existing
+
+    @inlineCallbacks
+    def readProperty(self, property, request):
+        if type(property) is tuple:
+            qname = property
+        else:
+            qname = property.qname()
+
+        if qname == caldavxml.SupportedCalendarComponentSets.qname():
+            if config.RestrictCalendarsToOneComponentType:
+                prop = caldavxml.SupportedCalendarComponentSets(
+                    caldavxml.SupportedCalendarComponentSet(
+                        caldavxml.CalendarComponent(
+                            name="VEVENT",
+                        ),
+                    ),
+                    caldavxml.SupportedCalendarComponentSet(
+                        caldavxml.CalendarComponent(
+                            name="VTODO",
+                        ),
+                    ),
+                )
+            else:
+                prop = caldavxml.SupportedCalendarComponentSets()
+            returnValue(prop)
+            
+        result = (yield super(CalendarHomeResource, self).readProperty(property, request))
+        returnValue(result)
+
     def _setupProvisions(self):
 
         # Cache children which must be of a specific type
@@ -2590,14 +2619,6 @@
         returnValue((changed, deleted, notallowed))
 
 
-    def liveProperties(self):
-
-        return super(CalendarHomeResource, self).liveProperties() + (
-            (customxml.calendarserver_namespace, "xmpp-uri"),
-            (customxml.calendarserver_namespace, "xmpp-heartbeat-uri"),
-            (customxml.calendarserver_namespace, "xmpp-server"),
-        )
-
 class AddressBookHomeResource (CommonHomeResource):
     """
     Address book home collection resource.

Modified: CalendarServer/trunk/twistedcaldav/schedule.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/schedule.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/twistedcaldav/schedule.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -40,11 +40,12 @@
 
 from twisted.internet.defer import inlineCallbacks, returnValue, succeed
 
-from twistedcaldav import caldavxml
+from twistedcaldav import caldavxml, customxml
 from twistedcaldav.caldavxml import caldav_namespace, Opaque,\
     CalendarFreeBusySet, ScheduleCalendarTransp
 from twistedcaldav.config import config
 from twistedcaldav.customxml import calendarserver_namespace
+from twistedcaldav.ical import allowedComponents
 from twistedcaldav.extensions import DAVResource
 from twistedcaldav.resource import CalDAVResource, ReadOnlyNoCopyResourceMixIn
 from twistedcaldav.resource import isCalendarCollectionResource
@@ -135,8 +136,9 @@
     def liveProperties(self):
         
         return super(ScheduleInboxResource, self).liveProperties() + (
-            (caldav_namespace, "calendar-free-busy-set"),
-            (caldav_namespace, "schedule-default-calendar-URL"),
+            caldavxml.CalendarFreeBusySet.qname(),
+            caldavxml.ScheduleDefaultCalendarURL.qname(),
+            customxml.ScheduleDefaultTasksURL.qname(),
         )
 
     def resourceType(self):
@@ -149,7 +151,7 @@
         else:
             qname = property.qname()
 
-        if qname == (caldav_namespace, "calendar-free-busy-set"):
+        if qname == caldavxml.CalendarFreeBusySet.qname():
             # Always return at least an empty list
             if not self.hasDeadProperty(property):
                 top = self.parent.url()
@@ -159,22 +161,10 @@
                     if prop == ScheduleCalendarTransp(Opaque()):
                         values.append(HRef(joinURL(top, cal.name())))
                 returnValue(CalendarFreeBusySet(*values))
-        elif qname == (caldav_namespace, "schedule-default-calendar-URL"):
-            # Must have a valid default
-            try:
-                defaultCalendarProperty = self.readDeadProperty(property)
-            except HTTPError:
-                defaultCalendarProperty = None
-            if defaultCalendarProperty and len(defaultCalendarProperty.children) == 1:
-                defaultCalendar = str(defaultCalendarProperty.children[0])
-                cal = (yield request.locateResource(str(defaultCalendar)))
-                if cal is not None and isCalendarCollectionResource(cal) and cal.exists() and not cal.isVirtualShare():
-                    returnValue(defaultCalendarProperty) 
+        elif qname in (caldavxml.ScheduleDefaultCalendarURL.qname(), customxml.ScheduleDefaultTasksURL.qname()):
+            result = (yield self.readDefaultCalendarProperty(request, qname))
+            returnValue(result)
             
-            # Default is not valid - we have to try to pick one
-            defaultCalendarProperty = (yield self.pickNewDefaultCalendar(request))
-            returnValue(defaultCalendarProperty)
-            
         result = (yield super(ScheduleInboxResource, self).readProperty(property, request))
         returnValue(result)
 
@@ -186,7 +176,7 @@
         # server enforces what can be stored, however it need not actually
         # exist so we cannot list it in liveProperties on this resource, since its
         # its presence there means that hasProperty will always return True for it.
-        if property.qname() == (calendarserver_namespace, "calendar-availability"):
+        if property.qname() == customxml.CalendarAvailability.qname():
             if not property.valid():
                 raise HTTPError(ErrorResponse(
                     responsecode.CONFLICT,
@@ -194,7 +184,7 @@
                     description="Invalid property"
                 ))
 
-        elif property.qname() == (caldav_namespace, "calendar-free-busy-set"):
+        elif property.qname() == caldavxml.CalendarFreeBusySet.qname():
             # Verify that the calendars added in the PROPPATCH are valid. We do not check
             # whether existing items in the property are still valid - only new ones.
             property.children = [davxml.HRef(normalizeURL(str(href))) for href in property.children]
@@ -214,36 +204,18 @@
                         "Invalid URI",
                     ))
 
-        elif property.qname() == (caldav_namespace, "schedule-default-calendar-URL"):
-            # Verify that the calendar added in the PROPPATCH is valid.
-            property.children = [davxml.HRef(normalizeURL(str(href))) for href in property.children]
-            new_calendar = [str(href) for href in property.children]
-            cal = None
-            if len(new_calendar) == 1:
-                calURI = str(new_calendar[0])
-                cal = (yield request.locateResource(str(new_calendar[0])))
-            # TODO: check that owner of the new calendar is the same as owner of this inbox
-            if cal is None or not cal.exists() or not isCalendarCollectionResource(cal) or cal.isVirtualShare():
-                # Validate that href's point to a valid calendar.
-                raise HTTPError(ErrorResponse(
-                    responsecode.CONFLICT,
-                    (caldav_namespace, "valid-schedule-default-calendar-URL"),
-                    "Invalid URI",
-                ))
-            else:
-                # Canonicalize the URL to __uids__ form
-                calURI = (yield cal.canonicalURL(request))
-                property = caldavxml.ScheduleDefaultCalendarURL(davxml.HRef(calURI))
+        elif property.qname() in (caldavxml.ScheduleDefaultCalendarURL.qname(), customxml.ScheduleDefaultTasksURL.qname()):
+            property = (yield self.writeDefaultCalendarProperty(request, property))
 
         yield super(ScheduleInboxResource, self).writeProperty(property, request)
 
     def processFreeBusyCalendar(self, uri, addit):
         uri = normalizeURL(uri)
 
-        if not self.hasDeadProperty((caldav_namespace, "calendar-free-busy-set")):
+        if not self.hasDeadProperty(caldavxml.CalendarFreeBusySet.qname()):
             fbset = set()
         else:
-            fbset = set([normalizeURL(str(href)) for href in self.readDeadProperty((caldav_namespace, "calendar-free-busy-set")).children])
+            fbset = set([normalizeURL(str(href)) for href in self.readDeadProperty(caldavxml.CalendarFreeBusySet.qname()).children])
         if addit:
             if uri not in fbset:
                 fbset.add(uri)
@@ -254,36 +226,158 @@
                 self.writeDeadProperty(caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in fbset]))
 
     @inlineCallbacks
-    def pickNewDefaultCalendar(self, request):
+    def readDefaultCalendarProperty(self, request, qname):
         """
-        First see if "calendar" exists in the calendar home and pick that. Otherwise
-        create "calendar" in the calendar home.
+        Read either the default VEVENT or VTODO calendar property. Try to pick one if not present.
         """
+        
+        tasks = qname == customxml.ScheduleDefaultTasksURL.qname()
+
+        # Must have a valid default
+        try:
+            defaultCalendarProperty = self.readDeadProperty(qname)
+        except HTTPError:
+            defaultCalendarProperty = None
+        if defaultCalendarProperty and len(defaultCalendarProperty.children) == 1:
+            defaultCalendar = str(defaultCalendarProperty.children[0])
+            cal = (yield request.locateResource(str(defaultCalendar)))
+            if cal is not None and isCalendarCollectionResource(cal) and cal.exists() and not cal.isVirtualShare():
+                returnValue(defaultCalendarProperty) 
+        
+        # Default is not valid - we have to try to pick one
+        defaultCalendarProperty = (yield self.pickNewDefaultCalendar(request, tasks=tasks))
+        returnValue(defaultCalendarProperty)
+
+    @inlineCallbacks
+    def writeDefaultCalendarProperty(self, request, property):
+        """
+        Write either the default VEVENT or VTODO calendar property, validating and canonicalizing the value
+        """
+        tasks = property.qname() == customxml.ScheduleDefaultTasksURL
+        componentType = "VTODO" if tasks else "VEVENT"
+        prop_to_set = customxml.ScheduleDefaultTasksURL if tasks else caldavxml.ScheduleDefaultCalendarURL
+        error_element = (calendarserver_namespace, "valid-schedule-default-tasks-URL") if tasks else (caldav_namespace, "valid-schedule-default-calendar-URL")
+
+        # Verify that the calendar added in the PROPPATCH is valid.
+        property.children = [davxml.HRef(normalizeURL(str(href))) for href in property.children]
+        new_calendar = [str(href) for href in property.children]
+        cal = None
+        if len(new_calendar) == 1:
+            calURI = str(new_calendar[0])
+            cal = (yield request.locateResource(str(new_calendar[0])))
+
+        # TODO: check that owner of the new calendar is the same as owner of this inbox
+        if cal is None or not cal.exists() or not isCalendarCollectionResource(cal) or \
+            cal.isVirtualShare() or not cal.isSupportedComponent(componentType):
+            # Validate that href's point to a valid calendar.
+            raise HTTPError(ErrorResponse(
+                responsecode.CONFLICT,
+                error_element,
+                "Invalid URI",
+            ))
+        else:
+            # Canonicalize the URL to __uids__ form
+            calURI = (yield cal.canonicalURL(request))
+            property = prop_to_set(davxml.HRef(calURI))
+            returnValue(property)
+
+    @inlineCallbacks
+    def pickNewDefaultCalendar(self, request, tasks=False):
+        """
+        First see if default provisioned calendar exists in the calendar home and pick that. Otherwise
+        pick another from the calendar home.
+        """
+        
+        componentType = "VTODO" if tasks else "VEVENT"
+        test_name = "tasks" if tasks else "calendar"
+        prop_to_set = customxml.ScheduleDefaultTasksURL if tasks else caldavxml.ScheduleDefaultCalendarURL
+
         calendarHomeURL = self.parent.url()
-        defaultCalendarURL = joinURL(calendarHomeURL, "calendar")
+        defaultCalendarURL = joinURL(calendarHomeURL, test_name)
         defaultCalendar = (yield request.locateResource(defaultCalendarURL))
         if defaultCalendar is None or not defaultCalendar.exists():
             # FIXME: the back-end should re-provision a default calendar here.
             # Really, the dead property shouldn't be necessary, and this should
             # be entirely computed by a back-end method like 'defaultCalendar()'
             for calendarName in (yield self.parent._newStoreHome.listCalendars()):  # These are only unshared children
-                if calendarName != "inbox":
-                    aCalendar = calendarName
-                    break
+                if calendarName == "inbox":
+                    continue
+                calendar = (yield self.parent._newStoreHome.calendarWithName(calendarName))
+                if not calendar.isSupportedComponent(componentType):
+                    continue
+                break
             else:
-                raise RuntimeError("No valid calendars to use as a default calendar.")
+                raise RuntimeError("No valid calendars to use as a default %s calendar." % (componentType,))
 
-            defaultCalendarURL = joinURL(calendarHomeURL, aCalendar)
+            defaultCalendarURL = joinURL(calendarHomeURL, calendarName)
 
-        self.writeDeadProperty(
-            caldavxml.ScheduleDefaultCalendarURL(
-                davxml.HRef(defaultCalendarURL)
-            )
-        )
-        returnValue(caldavxml.ScheduleDefaultCalendarURL(
-            davxml.HRef(defaultCalendarURL))
-        )
+        prop = prop_to_set(davxml.HRef(defaultCalendarURL))
+        self.writeDeadProperty(prop)
+        returnValue(prop)
 
+    @inlineCallbacks
+    def defaultCalendar(self, request, componentType):
+        """
+        Find the default calendar for the supplied iCalendar component type. If one does
+        not exist, automatically provision it. 
+        """
+
+        # Check any default calendar property first
+        default = (yield self.readProperty(caldavxml.ScheduleDefaultCalendarURL.qname(), request))
+        if len(default.children) == 1:
+            defaultURL = str(default.children[0])
+            default = (yield request.locateResource(defaultURL))
+        else:
+            default = None
+
+        # Check that default handles the component type
+        if default is not None:
+            if not default.isSupportedComponent(componentType):
+                default = None
+        
+        # Must have a default - provision one if not
+        if default is None:
+            
+            # Try to find a calendar supporting the required component type. If there are multiple, pick
+            # the one with the oldest created timestamp as that will likely be the initial provision.
+            for calendarName in (yield self.parent._newStoreHome.listCalendars()):  # These are only unshared children
+                if calendarName == "inbox":
+                    continue
+                calendar = (yield self.parent._newStoreHome.calendarWithName(calendarName))
+                if not calendar.isSupportedComponent(componentType):
+                    continue
+                if default is None or calendar.created() < default.created():
+                    default = calendar
+            
+            # If none can be found, provision one
+            if default is None:
+                new_name = "%ss" % (componentType.lower()[1:],)
+                default = yield self.parent._newStoreHome.createCalendarWithName(new_name)
+                default.setSupportedComponents(componentType.upper())
+            
+            # Need L{DAVResource} object to return not new store object
+            default = (yield request.locateResource(joinURL(self.parent.url(), default.name())))
+        
+        returnValue(default)
+
+    @inlineCallbacks
+    def isDefaultCalendar(self, request, calendar):
+        """
+        Is the supplied calendar one of the possible default calendars.
+        """
+        assert calendar.isCalendarCollection()
+        
+        # Not allowed to delete the default calendar
+        for default_prop in (caldavxml.ScheduleDefaultCalendarURL, customxml.ScheduleDefaultTasksURL,):
+            default = (yield self.readProperty(default_prop.qname(), request))
+            if default and len(default.children) == 1:
+                defaultURL = normalizeURL(str(default.children[0]))
+                myURL = (yield calendar.canonicalURL(request))
+                if defaultURL == myURL:
+                    returnValue(default_prop)
+
+        returnValue(None)
+
     ##
     # ACL
     ##
@@ -317,6 +411,11 @@
     def resourceType(self):
         return davxml.ResourceType.scheduleOutbox
 
+    def getSupportedComponentSet(self):
+        return caldavxml.SupportedCalendarComponentSet(
+            *[caldavxml.CalendarComponent(name=item) for item in allowedComponents]
+        )
+
     @inlineCallbacks
     def http_POST(self, request):
         """

Modified: CalendarServer/trunk/twistedcaldav/scheduling/processing.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/processing.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/twistedcaldav/scheduling/processing.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -433,14 +433,7 @@
         if self.new_resource:
             
             # Check for default calendar
-            default = (yield self.recipient.inbox.readProperty((caldav_namespace, "schedule-default-calendar-URL"), self.request))
-            if len(default.children) == 1:
-                defaultURL = str(default.children[0])
-                default = (yield self.request.locateResource(defaultURL))
-            else:
-                default = None
-            
-            # Must have a default calendar
+            default = (yield self.recipient.inbox.defaultCalendar(self.request, self.message.mainType()))
             if default is None:
                 log.error("No default calendar for recipient: '%s'." % (self.recipient.cuaddr,))
                 raise ImplicitProcessorException(iTIPRequestStatus.NO_USER_SUPPORT)
@@ -449,13 +442,13 @@
             autoprocessed = self.recipient.principal.getAutoSchedule()
             store_inbox = not autoprocessed or self.recipient.principal.getCUType() == "INDIVIDUAL"
             new_calendar = iTipProcessing.processNewRequest(self.message, self.recipient.cuaddr, autoprocessing=autoprocessed)
-            name =  md5(str(new_calendar) + str(time.time()) + defaultURL).hexdigest() + ".ics"
+            name =  md5(str(new_calendar) + str(time.time()) + default.url()).hexdigest() + ".ics"
             
             # Handle auto-reply behavior
             if autoprocessed:
                 send_reply, partstat = (yield self.checkAttendeeAutoReply(new_calendar))
 
-            new_resource = (yield self.writeCalendarResource(defaultURL, default, name, new_calendar))
+            new_resource = (yield self.writeCalendarResource(default.url(), default, name, new_calendar))
             
             if autoprocessed and send_reply:
                 # Track outstanding auto-reply processing

Modified: CalendarServer/trunk/twistedcaldav/stdconfig.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/stdconfig.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/twistedcaldav/stdconfig.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -524,6 +524,12 @@
             "Enabled"         : True,  # Address Books on/off switch
         }        
     },
+    
+    "RestrictCalendarsToOneComponentType" : True,  # Only allow calendars to be created with a single component type
+                                                   # If this is on, it will also trigger an upgrade behavior that will
+                                                   # split existing calendars into multiples based on component type.
+                                                   # If on, it will also cause new accounts to provision with separate
+                                                   # calendars for events and tasks.
 
     # CardDAV Features
     "DirectoryAddressBook": {

Modified: CalendarServer/trunk/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/storebridge.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/twistedcaldav/storebridge.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -43,7 +43,7 @@
 from twistedcaldav.carddavxml import carddav_namespace
 from twistedcaldav.config import config
 from twistedcaldav.ical import Component as VCalendar, Property as VProperty,\
-    InvalidICalendarDataError, iCalendarProductID
+    InvalidICalendarDataError, iCalendarProductID, allowedComponents
 from twistedcaldav.memcachelock import MemcacheLock, MemcacheLockTimeoutError
 from twistedcaldav.method.put_addressbook_common import StoreAddressObjectResource
 from twistedcaldav.method.put_common import StoreCalendarObjectResource
@@ -890,8 +890,67 @@
     def notifyChanged(self):
         self._newStoreObject.notifyChanged()
 
-class CalendarCollectionResource(_CommonHomeChildCollectionMixin, CalDAVResource):
+class _CalendarCollectionBehaviorMixin():
     """
+    Functions common to calendar and inbox collections
+    """
+    
+    # Support component set behaviors
+    def setSupportedComponentSet(self, support_components_property):
+        """
+        Parse out XML property into list of components and give to store.
+        """
+        support_components = tuple([comp.attributes["name"].upper() for comp in support_components_property.children])
+        return self.setSupportedComponents(support_components)
+    
+    def getSupportedComponentSet(self):
+        comps = self._newStoreObject.getSupportedComponents()
+        if comps:
+            comps = comps.split(",")
+        else:
+            comps = allowedComponents
+        return caldavxml.SupportedCalendarComponentSet(
+            *[caldavxml.CalendarComponent(name=item) for item in comps]
+        )
+
+    def setSupportedComponents(self, components):
+        """
+        Set the allowed component set for this calendar.
+
+        @param components: list of names of components to support
+        @type components: C{list}
+        """
+        
+        # Validate them first - raise on failure
+        if not self.validSupportedComponents(components):
+            raise HTTPError(StatusResponse(responsecode.FORBIDDEN, "Invalid CALDAV:supported-calendar-component-set"))
+
+        support_components = ",".join(sorted([comp.upper() for comp in components]))
+        return maybeDeferred(self._newStoreObject.setSupportedComponents, support_components)
+    
+    def getSupportedComponents(self):
+        comps = self._newStoreObject.getSupportedComponents()
+        if comps:
+            comps = comps.split(",")
+        else:
+            comps = allowedComponents
+        return comps
+
+    def isSupportedComponent(self, componentType):
+        return self._newStoreObject.isSupportedComponent(componentType)
+
+    def validSupportedComponents(self, components):
+        """
+        Test whether the supplied set of components is valid for the current server's component set
+        restrictions.
+        """
+        if config.RestrictCalendarsToOneComponentType:
+            return components in (("VEVENT",), ("VTODO",),)
+        return True
+
+    
+class CalendarCollectionResource(_CalendarCollectionBehaviorMixin, _CommonHomeChildCollectionMixin, CalDAVResource):
+    """
     Wrapper around a L{txdav.caldav.icalendar.ICalendar}.
     """
 
@@ -929,7 +988,6 @@
         """
         return True
 
-
     @inlineCallbacks
     def iCalendarRolledup(self, request):
         # FIXME: uncached: implement cache in the storage layer
@@ -1122,18 +1180,18 @@
         Moving a calendar collection is allowed for the purposes of changing
         that calendar's name.
         """
-        defaultCalendar = (yield self.isDefaultCalendar(request))
+        defaultCalendarType = (yield self.isDefaultCalendar(request))
         
         result = (yield super(CalendarCollectionResource, self).http_MOVE(request))
         if result == NO_CONTENT:
             destinationURI = urlsplit(request.headers.getHeader("destination"))[2]
             destination = yield request.locateResource(destinationURI)
-            yield self.movedCalendar(request, defaultCalendar,
+            yield self.movedCalendar(request, defaultCalendarType,
                                destination, destinationURI)
         returnValue(result)
 
 
-class StoreScheduleInboxResource(_CommonHomeChildCollectionMixin, ScheduleInboxResource):
+class StoreScheduleInboxResource(_CalendarCollectionBehaviorMixin, _CommonHomeChildCollectionMixin, ScheduleInboxResource):
 
     def __init__(self, *a, **kw):
 

Modified: CalendarServer/trunk/twistedcaldav/test/test_props.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_props.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/twistedcaldav/test/test_props.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -74,7 +74,7 @@
                     if not supported_components:
                         self.fail("Expected CalDAV:supported-calendar-component-set element; but got none.")
 
-                    supported = set(("VEVENT", "VTODO", "VFREEBUSY"))
+                    supported = set(("VEVENT",))
 
                     for component in supported_components.children:
                         if component.type in supported:

Modified: CalendarServer/trunk/twistedcaldav/test/test_schedule.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_schedule.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/twistedcaldav/test/test_schedule.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -24,7 +24,7 @@
 
 from twisted.internet.defer import inlineCallbacks
 
-from twistedcaldav import caldavxml
+from twistedcaldav import caldavxml, customxml
 from twistedcaldav.test.util import HomeTestCase, TestCase
 
 class Properties (HomeTestCase):
@@ -91,12 +91,11 @@
         self.setupCalendars()
 
     @inlineCallbacks
-    def test_pick_default_calendar(self):
+    def test_pick_default_vevent_calendar(self):
         """
         Make calendar
         """
         
-
         request = SimpleRequest(self.site, "GET", "/calendars/users/wsanchez/")
         inbox = yield request.locateResource("/calendars/users/wsanchez/inbox")
 
@@ -120,6 +119,34 @@
         request._newStoreTransaction.abort()
 
     @inlineCallbacks
+    def test_pick_default_vtodo_calendar(self):
+        """
+        Make calendar
+        """
+        
+        request = SimpleRequest(self.site, "GET", "/calendars/users/wsanchez/")
+        inbox = yield request.locateResource("/calendars/users/wsanchez/inbox")
+
+        # default property initially not present
+        try:
+            inbox.readDeadProperty(customxml.ScheduleDefaultTasksURL)
+        except HTTPError:
+            pass
+        else:
+            self.fail("customxml.ScheduleDefaultTasksURL is not empty")
+
+        yield inbox.pickNewDefaultCalendar(request, tasks=True)
+
+        try:
+            default = inbox.readDeadProperty(customxml.ScheduleDefaultTasksURL)
+        except HTTPError:
+            self.fail("customxml.ScheduleDefaultTasksURL is not present")
+        else:
+            self.assertEqual(str(default.children[0]), "/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/tasks")
+
+        request._newStoreTransaction.abort()
+
+    @inlineCallbacks
     def test_pick_default_other(self):
         """
         Make calendar
@@ -206,3 +233,71 @@
             self.assertEqual(str(default.children[0]), "/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar")
 
         request._newStoreTransaction.abort()
+
+    @inlineCallbacks
+    def test_set_default_vevent_other(self):
+        """
+        Test that the default URL can be set to another VEVENT calendar
+        """
+
+        request = SimpleRequest(self.site, "GET", "/calendars/users/wsanchez/")
+        inbox = yield request.locateResource("/calendars/users/wsanchez/inbox")
+
+        # default property not present
+        try:
+            inbox.readDeadProperty(caldavxml.ScheduleDefaultCalendarURL)
+        except HTTPError:
+            pass
+        else:
+            self.fail("caldavxml.ScheduleDefaultCalendarURL is not empty")
+
+        # Create a new default calendar
+        newcalendar = yield request.locateResource("/calendars/users/wsanchez/newcalendar")
+        yield newcalendar.createCalendarCollection()
+        yield newcalendar.setSupportedComponents(("VEVENT",))
+        request._newStoreTransaction.commit()
+        
+        request = SimpleRequest(self.site, "GET", "/calendars/users/wsanchez/")
+        inbox = yield request.locateResource("/calendars/users/wsanchez/inbox")
+        yield inbox.writeProperty(caldavxml.ScheduleDefaultCalendarURL(davxml.HRef("/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/newcalendar")), request)
+
+        try:
+            default = inbox.readDeadProperty(caldavxml.ScheduleDefaultCalendarURL)
+        except HTTPError:
+            self.fail("caldavxml.ScheduleDefaultCalendarURL is not present")
+        else:
+            self.assertEqual(str(default.children[0]), "/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/newcalendar")
+
+        request._newStoreTransaction.commit()
+
+    @inlineCallbacks
+    def test_is_default_calendar(self):
+        """
+        Test .isDefaultCalendar() returns the proper class or None.
+        """
+        
+        # Create a new non-default calendar
+        request = SimpleRequest(self.site, "GET", "/calendars/users/wsanchez/")
+        newcalendar = yield request.locateResource("/calendars/users/wsanchez/newcalendar")
+        yield newcalendar.createCalendarCollection()
+        yield newcalendar.setSupportedComponents(("VEVENT",))
+        inbox = yield request.locateResource("/calendars/users/wsanchez/inbox")
+        yield inbox.pickNewDefaultCalendar(request)
+        request._newStoreTransaction.commit()
+        
+        request = SimpleRequest(self.site, "GET", "/calendars/users/wsanchez/")
+        inbox = yield request.locateResource("/calendars/users/wsanchez/inbox")
+        calendar = yield request.locateResource("/calendars/users/wsanchez/calendar")
+        newcalendar = yield request.locateResource("/calendars/users/wsanchez/newcalendar")
+        tasks = yield request.locateResource("/calendars/users/wsanchez/tasks")
+
+        result = yield inbox.isDefaultCalendar(request, calendar)
+        self.assertEqual(result, caldavxml.ScheduleDefaultCalendarURL)
+        
+        result = yield inbox.isDefaultCalendar(request, newcalendar)
+        self.assertEqual(result, None)
+        
+        result = yield inbox.isDefaultCalendar(request, tasks)
+        self.assertEqual(result, customxml.ScheduleDefaultTasksURL)
+
+        request._newStoreTransaction.commit()

Modified: CalendarServer/trunk/twistedcaldav/test/test_validation.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_validation.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/twistedcaldav/test/test_validation.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -44,6 +44,7 @@
         self.destination.name = lambda : '1'
         self.destinationParent = CalDAVResource()
         self.destinationParent.name = lambda : '2'
+        self.destinationParent.isSupportedComponent = lambda x: True
 
     def _getSampleCalendar(self):
         return Component.fromString("""BEGIN:VCALENDAR

Modified: CalendarServer/trunk/txdav/base/propertystore/base.py
===================================================================
--- CalendarServer/trunk/txdav/base/propertystore/base.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/txdav/base/propertystore/base.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -212,6 +212,13 @@
     def isGlobalProperty(self, key):
         return key in self._globalKeys
 
+    def copyAllProperties(self, other):
+        """
+        Copy all the properties from another store into this one. This needs to be done
+        independently of the UID. Each underlying store will need to implement this.
+        """
+        pass
+        
 # FIXME: Actually, we should replace this with calls to IPropertyName()
 def validKey(key):
     # Used by implementations to verify that keys are valid

Modified: CalendarServer/trunk/txdav/base/propertystore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/base/propertystore/sql.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/txdav/base/propertystore/sql.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -235,3 +235,27 @@
         self._deleteResourceQuery.on(self._txn, resourceID=self._resourceID)
         self._cacher.delete(str(self._resourceID))
 
+    @inlineCallbacks
+    def copyAllProperties(self, other):
+        """
+        Copy all the properties from another store into this one. This needs to be done
+        independently of the UID.
+        """
+
+        rows = yield other._allWithID.on(other._txn, resourceID=other._resourceID)
+        for key_str, uid, value_str in rows:
+            wasCached = [(key_str, uid) in self._cached]
+            if wasCached[0]:
+                yield self._updateQuery.on(
+                    self._txn, resourceID=self._resourceID, value=value_str,
+                    name=key_str, uid=uid)
+            else:
+                yield self._insertQuery.on(
+                    self._txn, resourceID=self._resourceID, value=value_str,
+                    name=key_str, uid=uid)
+                
+
+        # Reload from the DB
+        self._cached = {}
+        self._cacher.delete(str(self._resourceID))
+        yield self._refresh(self._txn)

Modified: CalendarServer/trunk/txdav/base/propertystore/test/base.py
===================================================================
--- CalendarServer/trunk/txdav/base/propertystore/test/base.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/txdav/base/propertystore/test/base.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -304,8 +304,7 @@
         yield self._changed(self.propertyStore1)
 
         self.failUnless(name in self.propertyStore2.keys())
-
-
+ 
 def propertyName(name):
     return PropertyName("http://calendarserver.org/ns/test/", name)
 

Modified: CalendarServer/trunk/txdav/base/propertystore/test/test_sql.py
===================================================================
--- CalendarServer/trunk/txdav/base/propertystore/test/test_sql.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/txdav/base/propertystore/test/test_sql.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -133,7 +133,7 @@
         race = []
         def tiebreaker(label):
             # Let's not get into the business of figuring out who the database
-            # concurrency rules are suppsoed to pick; it might differ.  We just
+            # concurrency rules are supposed to pick; it might differ.  We just
             # take the answer we're given for who gets to be the final writer,
             # and make sure that matches the property read in the next
             # transaction.
@@ -151,8 +151,51 @@
                   'b': pval2}[race[-1]]
         self.assertEquals(self.propertyStore[pname], winner)
 
+    @inlineCallbacks
+    def test_copy(self):
 
+        # Existing store
+        store1_user1 = yield PropertyStore.load("user01", self._txn, 2)
+        store1_user2 = yield PropertyStore.load("user01", self._txn, 2)
+        store1_user2._setPerUserUID("user02")
 
+        # Populate current store with data
+        props_user1 = (
+            (propertyName("dummy1"), propertyValue("value1-user1")),
+            (propertyName("dummy2"), propertyValue("value2-user1")),
+        )
+        props_user2 = (
+            (propertyName("dummy1"), propertyValue("value1-user2")),
+            (propertyName("dummy3"), propertyValue("value3-user2")),
+        )
+
+        for name, value in props_user1:
+            store1_user1[name] = value
+        for name, value in props_user2:
+            store1_user2[name] = value
+
+        yield self._txn.commit()
+
+        self._txn = self.store.newTransaction()
+
+        # Existing store
+        store1_user1 = yield PropertyStore.load("user01", self._txn, 2)
+
+        # New store
+        store2_user1 = yield PropertyStore.load("user01", self._txn, 3)
+
+        # Do copy and check results
+        yield store2_user1.copyAllProperties(store1_user1)
+        
+        self.assertEqual(store1_user1.keys(), store2_user1.keys())
+
+        store1_user2 = yield PropertyStore.load("user01", self._txn, 2)
+        store1_user2._setPerUserUID("user02")
+        store2_user2 = yield PropertyStore.load("user01", self._txn, 3)
+        store2_user2._setPerUserUID("user02")
+        self.assertEqual(store1_user2.keys(), store2_user2.keys())
+
+
 if PropertyStore is None:
     PropertyStoreTest.skip = importErrorMessage
 

Modified: CalendarServer/trunk/txdav/base/propertystore/test/test_xattr.py
===================================================================
--- CalendarServer/trunk/txdav/base/propertystore/test/test_xattr.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/txdav/base/propertystore/test/test_xattr.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -13,13 +13,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 ##
-from twext.web2.dav.element.base import WebDAVTextElement
 
 """
 Property store tests.
 """
 
 from twext.python.filepath import CachingFilePath as FilePath
+from twext.web2.dav.element.base import WebDAVTextElement
 from txdav.base.propertystore.base import PropertyName
 from txdav.base.propertystore.test import base
 
@@ -82,5 +82,58 @@
         self.assertEqual(self.propertyStore[name], DummyProperty.fromString("data"))
         self.assertRaises(KeyError, lambda: self.propertyStore.attrs[uncompressedKey])
 
+    def test_copy(self):
+
+        tempDir = FilePath(self.mktemp())
+        tempDir.makedirs()
+        tempFile1 = tempDir.child("test1")
+        tempFile1.touch()
+        tempFile2 = tempDir.child("test2")
+        tempFile2.touch()
+        
+        # Existing store
+        store1_user1 = PropertyStore("user01", lambda : tempFile1)
+        store1_user2 = PropertyStore("user01", lambda : tempFile1)
+        store1_user2._setPerUserUID("user02")
+
+        # New store
+        store2_user1 = PropertyStore("user01", lambda : tempFile2)
+        store2_user2 = PropertyStore("user01", lambda : tempFile2)
+        store2_user2._setPerUserUID("user02")
+
+        # Populate current store with data
+        class DummyProperty1(WebDAVTextElement):
+            namespace = "http://calendarserver.org/ns/"
+            name = "dummy1"
+        class DummyProperty2(WebDAVTextElement):
+            namespace = "http://calendarserver.org/ns/"
+            name = "dummy2"
+        class DummyProperty3(WebDAVTextElement):
+            namespace = "http://calendarserver.org/ns/"
+            name = "dummy3"
+
+        props_user1 = (
+            DummyProperty1.fromString("value1-user1"),
+            DummyProperty2.fromString("value2-user1"),
+        )
+        props_user2 = (
+            DummyProperty1.fromString("value1-user2"),
+            DummyProperty3.fromString("value3-user2"),
+        )
+
+        for prop in props_user1:
+            store1_user1[PropertyName.fromElement(prop)] = prop
+        for prop in props_user2:
+            store1_user2[PropertyName.fromElement(prop)] = prop
+        store1_user1.flush()
+        store1_user2.flush()
+
+        # Do copy and check results
+        store2_user1.copyAllProperties(store1_user1)
+        store2_user1.flush()
+        
+        self.assertEqual(store1_user1.attrs.items(), store2_user1.attrs.items())
+        self.assertEqual(store1_user2.attrs.items(), store2_user2.attrs.items())
+
 if PropertyStore is None:
     PropertyStoreTest.skip = importErrorMessage

Modified: CalendarServer/trunk/txdav/base/propertystore/xattr.py
===================================================================
--- CalendarServer/trunk/txdav/base/propertystore/xattr.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/txdav/base/propertystore/xattr.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -312,3 +312,20 @@
     def abort(self):
         self.removed.clear()
         self.modified.clear()
+
+    def copyAllProperties(self, other):
+        """
+        Copy all the properties from another store into this one. This needs to be done
+        independently of the UID.
+        """
+        try:
+            iterattr = iter(other.attrs)
+        except IOError, e:
+            if e.errno != errno.ENOENT:
+                raise
+            iterattr = iter(())
+
+        for key in iterattr:
+            if not key.startswith(self.deadPropertyXattrPrefix):
+                continue
+            self.attrs[key] = other.attrs[key]

Modified: CalendarServer/trunk/txdav/caldav/datastore/file.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/file.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/txdav/caldav/datastore/file.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -14,7 +14,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 ##
-from twistedcaldav.ical import InvalidICalendarDataError
 
 """
 File calendar store.
@@ -44,6 +43,8 @@
 
 from twistedcaldav import caldavxml, customxml
 from twistedcaldav.caldavxml import ScheduleCalendarTransp, Opaque
+from twistedcaldav.config import config
+from twistedcaldav.ical import InvalidICalendarDataError
 from twistedcaldav.sharing import InvitesDatabase
 
 from txdav.caldav.icalendarstore import IAttachment
@@ -181,14 +182,24 @@
 
 
     def createdHome(self):
+
+        # Default calendar
         defaultCal = self.createCalendarWithName("calendar")
         props = defaultCal.properties()
-        props[PropertyName(*ScheduleCalendarTransp.qname())] = ScheduleCalendarTransp(
-            Opaque())
+        props[PropertyName(*ScheduleCalendarTransp.qname())] = ScheduleCalendarTransp(Opaque())
+        
+        # Check whether components type must be separate
+        if config.RestrictCalendarsToOneComponentType:
+            defaultCal.setSupportedComponents("VEVENT")
+            
+            # Default tasks
+            defaultTasks = self.createCalendarWithName("tasks")
+            props = defaultTasks.properties()
+            defaultTasks.setSupportedComponents("VTODO")
+            
         self.createCalendarWithName("inbox")
 
 
-
 class Calendar(CommonHomeChild):
     """
     File-based implementation of L{ICalendar}.
@@ -241,6 +252,29 @@
         raise NotImplementedError()
 
 
+    def setSupportedComponents(self, supported_components):
+        """
+        Update the private property with the supported components. Technically this should only happen once
+        on collection creation, but for migration we may need to change after the fact - hence a separate api.
+        """
+        
+        pname = PropertyName.fromElement(customxml.TwistedCalendarSupportedComponents)
+        if supported_components:
+            self.properties()[pname] = customxml.TwistedCalendarSupportedComponents.fromString(supported_components)
+        elif pname in self.properties():
+            del self.properties()[pname]
+
+    def getSupportedComponents(self):
+        result = str(self.properties().get(PropertyName.fromElement(customxml.TwistedCalendarSupportedComponents), ""))
+        return result if result else None
+
+    def isSupportedComponent(self, componentType):
+        supported = self.getSupportedComponents()
+        if supported:
+            return componentType.upper() in supported.split(",")
+        else:
+            return True
+
     def initPropertyStore(self, props):
         # Setup peruser special properties
         props.setSpecialProperties(
@@ -260,8 +294,55 @@
         """
         return MimeType.fromString("text/calendar; charset=utf-8")
 
+    def splitCollectionByComponentTypes(self):
+        """
+        If the calendar contains iCalendar data with different component types, then split it into separate collections
+        each containing only one component type. When doing this make sure properties and sharing state are preserved
+        on any new calendars created.
+        """
+        
+        # TODO: implement this for filestore
+        pass
 
+    def _countComponentTypes(self):
+        """
+        Count each component type in this calendar.
+        
+        @return: a C{tuple} of C{tuple} containing the component type name and count. 
+        """
 
+        rows = self._index._oldIndex.componentTypeCounts()
+        result = tuple([(componentType, componentCount) for componentType, componentCount in sorted(rows, key=lambda x:x[0])])
+        return result
+
+    def _splitComponentType(self, component):
+        """
+        Create a new calendar and move all components of the specified component type into the new one.
+        Make sure properties and sharing state is preserved on the new calendar.
+        
+        @param component: Component type to split out
+        @type component: C{str}
+        """
+        
+        # TODO: implement this for filestore
+        pass
+
+    def _transferSharingDetails(self, newcalendar, component):
+        """
+        If the current calendar is shared, make the new calendar shared in the same way, but tweak the name.
+        """
+        
+        # TODO: implement this for filestore
+        pass
+    
+    def _transferCalendarObjects(self, newcalendar, component):
+        """
+        Move all calendar components of the specified type to the specified calendar.
+        """
+        
+        # TODO: implement this for filestore
+        pass
+
 class CalendarObject(CommonObjectResource, CalendarObjectBase):
     """
     @ivar _path: The path of the .ics file on disk

Modified: CalendarServer/trunk/txdav/caldav/datastore/index_file.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/index_file.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/txdav/caldav/datastore/index_file.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -185,6 +185,12 @@
 
         return uid
 
+    def componentTypeCounts(self):
+        """
+        Count each type of component.
+        """
+        return self._db_execute("select TYPE, COUNT(TYPE) from RESOURCE group by TYPE")
+
     def addResource(self, name, calendar, fast=False, reCreate=False):
         """
         Adding or updating an existing resource.


Property changes on: CalendarServer/trunk/txdav/caldav/datastore/index_file.py
___________________________________________________________________
Modified: svn:mergeinfo
   - /CalendarServer/branches/config-separation/txdav/caldav/datastore/index_file.py:4379-4443
/CalendarServer/branches/egg-info-351/txdav/caldav/datastore/index_file.py:4589-4625
/CalendarServer/branches/generic-sqlstore/txdav/caldav/datastore/index_file.py:6167-6191
/CalendarServer/branches/new-store-no-caldavfile-2/txdav/caldav/datastore/index_file.py:5936-5981
/CalendarServer/branches/new-store-no-caldavfile/txdav/caldav/datastore/index_file.py:5911-5935
/CalendarServer/branches/new-store/txdav/caldav/datastore/index_file.py:5594-5934
/CalendarServer/branches/users/cdaboo/batchupload-6699/txdav/caldav/datastore/index_file.py:6700-7198
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692/txdav/caldav/datastore/index_file.py:5693-5702
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627/txdav/caldav/datastore/index_file.py:3628-3644
/CalendarServer/branches/users/cdaboo/implicituidrace/txdav/caldav/datastore/index_file.py:8137-8141
/CalendarServer/branches/users/cdaboo/more-sharing-5591/txdav/caldav/datastore/index_file.py:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464/txdav/caldav/datastore/index_file.py:4465-4957
/CalendarServer/branches/users/cdaboo/pods/txdav/caldav/datastore/index_file.py:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/datastore/index_file.py:7085-7206
/CalendarServer/branches/users/cdaboo/pycard/txdav/caldav/datastore/index_file.py:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes/txdav/caldav/datastore/index_file.py:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070/txdav/caldav/datastore/index_file.py:5071-5105
/CalendarServer/branches/users/cdaboo/shared-calendars-5187/txdav/caldav/datastore/index_file.py:5188-5440
/CalendarServer/branches/users/cdaboo/timezones/txdav/caldav/datastore/index_file.py:7443-7699
/CalendarServer/branches/users/glyph/conn-limit/txdav/caldav/datastore/index_file.py:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge/txdav/caldav/datastore/index_file.py:4971-5080
/CalendarServer/branches/users/glyph/dalify/txdav/caldav/datastore/index_file.py:6932-7023
/CalendarServer/branches/users/glyph/deploybuild/txdav/caldav/datastore/index_file.py:7563-7572
/CalendarServer/branches/users/glyph/dont-start-postgres/txdav/caldav/datastore/index_file.py:6592-6614
/CalendarServer/branches/users/glyph/linux-tests/txdav/caldav/datastore/index_file.py:6893-6900
/CalendarServer/branches/users/glyph/misc-portability-fixes/txdav/caldav/datastore/index_file.py:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6/txdav/caldav/datastore/index_file.py:6322-6334
/CalendarServer/branches/users/glyph/more-deferreds-7/txdav/caldav/datastore/index_file.py:6369
/CalendarServer/branches/users/glyph/new-export/txdav/caldav/datastore/index_file.py:7444-7485
/CalendarServer/branches/users/glyph/oracle-nulls/txdav/caldav/datastore/index_file.py:7340-7351
/CalendarServer/branches/users/glyph/oracle/txdav/caldav/datastore/index_file.py:7106-7155
/CalendarServer/branches/users/glyph/sendfdport/txdav/caldav/datastore/index_file.py:5388-5424
/CalendarServer/branches/users/glyph/sharedpool/txdav/caldav/datastore/index_file.py:6490-6550
/CalendarServer/branches/users/glyph/sql-store/txdav/caldav/datastore/index_file.py:5929-6073
/CalendarServer/branches/users/glyph/subtransactions/txdav/caldav/datastore/index_file.py:7248-7258
/CalendarServer/branches/users/glyph/use-system-twisted/txdav/caldav/datastore/index_file.py:5084-5149
/CalendarServer/branches/users/sagen/applepush/txdav/caldav/datastore/index_file.py:8126-8184
/CalendarServer/branches/users/sagen/inboxitems/txdav/caldav/datastore/index_file.py:7380-7381
/CalendarServer/branches/users/sagen/locations-resources-2/txdav/caldav/datastore/index_file.py:5052-5061
/CalendarServer/branches/users/sagen/locations-resources/txdav/caldav/datastore/index_file.py:5032-5051
/CalendarServer/branches/users/sagen/purge_old_events/txdav/caldav/datastore/index_file.py:6735-6746
/CalendarServer/branches/users/sagen/resource-delegates-4038/txdav/caldav/datastore/index_file.py:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066/txdav/caldav/datastore/index_file.py:4068-4075
/CalendarServer/branches/users/sagen/resources-2/txdav/caldav/datastore/index_file.py:5084-5093
/CalendarServer/branches/users/wsanchez/transations/txdav/caldav/datastore/index_file.py:5515-5593
/CalendarServer/trunk/twistedcaldav/index.py:6322-6394
   + /CalendarServer/branches/config-separation/txdav/caldav/datastore/index_file.py:4379-4443
/CalendarServer/branches/egg-info-351/txdav/caldav/datastore/index_file.py:4589-4625
/CalendarServer/branches/generic-sqlstore/txdav/caldav/datastore/index_file.py:6167-6191
/CalendarServer/branches/new-store-no-caldavfile-2/txdav/caldav/datastore/index_file.py:5936-5981
/CalendarServer/branches/new-store-no-caldavfile/txdav/caldav/datastore/index_file.py:5911-5935
/CalendarServer/branches/new-store/txdav/caldav/datastore/index_file.py:5594-5934
/CalendarServer/branches/users/cdaboo/batchupload-6699/txdav/caldav/datastore/index_file.py:6700-7198
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692/txdav/caldav/datastore/index_file.py:5693-5702
/CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/caldav/datastore/index_file.py:8130-8346
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627/txdav/caldav/datastore/index_file.py:3628-3644
/CalendarServer/branches/users/cdaboo/implicituidrace/txdav/caldav/datastore/index_file.py:8137-8141
/CalendarServer/branches/users/cdaboo/more-sharing-5591/txdav/caldav/datastore/index_file.py:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464/txdav/caldav/datastore/index_file.py:4465-4957
/CalendarServer/branches/users/cdaboo/pods/txdav/caldav/datastore/index_file.py:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/datastore/index_file.py:7085-7206
/CalendarServer/branches/users/cdaboo/pycard/txdav/caldav/datastore/index_file.py:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes/txdav/caldav/datastore/index_file.py:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070/txdav/caldav/datastore/index_file.py:5071-5105
/CalendarServer/branches/users/cdaboo/shared-calendars-5187/txdav/caldav/datastore/index_file.py:5188-5440
/CalendarServer/branches/users/cdaboo/timezones/txdav/caldav/datastore/index_file.py:7443-7699
/CalendarServer/branches/users/glyph/conn-limit/txdav/caldav/datastore/index_file.py:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge/txdav/caldav/datastore/index_file.py:4971-5080
/CalendarServer/branches/users/glyph/dalify/txdav/caldav/datastore/index_file.py:6932-7023
/CalendarServer/branches/users/glyph/deploybuild/txdav/caldav/datastore/index_file.py:7563-7572
/CalendarServer/branches/users/glyph/dont-start-postgres/txdav/caldav/datastore/index_file.py:6592-6614
/CalendarServer/branches/users/glyph/linux-tests/txdav/caldav/datastore/index_file.py:6893-6900
/CalendarServer/branches/users/glyph/misc-portability-fixes/txdav/caldav/datastore/index_file.py:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6/txdav/caldav/datastore/index_file.py:6322-6334
/CalendarServer/branches/users/glyph/more-deferreds-7/txdav/caldav/datastore/index_file.py:6369
/CalendarServer/branches/users/glyph/new-export/txdav/caldav/datastore/index_file.py:7444-7485
/CalendarServer/branches/users/glyph/oracle-nulls/txdav/caldav/datastore/index_file.py:7340-7351
/CalendarServer/branches/users/glyph/oracle/txdav/caldav/datastore/index_file.py:7106-7155
/CalendarServer/branches/users/glyph/sendfdport/txdav/caldav/datastore/index_file.py:5388-5424
/CalendarServer/branches/users/glyph/sharedpool/txdav/caldav/datastore/index_file.py:6490-6550
/CalendarServer/branches/users/glyph/sql-store/txdav/caldav/datastore/index_file.py:5929-6073
/CalendarServer/branches/users/glyph/subtransactions/txdav/caldav/datastore/index_file.py:7248-7258
/CalendarServer/branches/users/glyph/use-system-twisted/txdav/caldav/datastore/index_file.py:5084-5149
/CalendarServer/branches/users/sagen/applepush/txdav/caldav/datastore/index_file.py:8126-8184
/CalendarServer/branches/users/sagen/inboxitems/txdav/caldav/datastore/index_file.py:7380-7381
/CalendarServer/branches/users/sagen/locations-resources-2/txdav/caldav/datastore/index_file.py:5052-5061
/CalendarServer/branches/users/sagen/locations-resources/txdav/caldav/datastore/index_file.py:5032-5051
/CalendarServer/branches/users/sagen/purge_old_events/txdav/caldav/datastore/index_file.py:6735-6746
/CalendarServer/branches/users/sagen/resource-delegates-4038/txdav/caldav/datastore/index_file.py:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066/txdav/caldav/datastore/index_file.py:4068-4075
/CalendarServer/branches/users/sagen/resources-2/txdav/caldav/datastore/index_file.py:5084-5093
/CalendarServer/branches/users/wsanchez/transations/txdav/caldav/datastore/index_file.py:5515-5593
/CalendarServer/trunk/twistedcaldav/index.py:6322-6394

Modified: CalendarServer/trunk/txdav/caldav/datastore/scheduling.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/scheduling.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/txdav/caldav/datastore/scheduling.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -137,6 +137,7 @@
     def __init__(self, parentHome, subCalendar):
         self._parentHome = parentHome
         self._subCalendar = subCalendar
+        self._supportedComponents = None
 
 #    def ownerCalendarHome(self):
 #        return self._parentHome
@@ -162,7 +163,16 @@
 #        #FIXME: wrap
 #        return self._subCalendar.calendarObjectWithName(name)
 
+    def setSupportedComponents(self, supported_components):
+        """
+        Update the database column with the supported components. Technically this should only happen once
+        on collection creation, but for migration we may need to change after the fact - hence a separate api.
+        """
+        self._supportedComponents = supported_components
 
+    def getSupportedComponents(self):
+        return self._supportedComponents
+
 class ImplicitStore(proxyForInterface(ICalendarStore, "_calendarStore")):
     """
     This is a wrapper around an L{ICalendarStore} that implements implicit

Modified: CalendarServer/trunk/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/sql.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/txdav/caldav/datastore/sql.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -25,6 +25,7 @@
     "CalendarObject",
 ]
 
+from twext.python.clsprop import classproperty
 from twext.python.vcomponent import VComponent
 from twext.web2.dav.element.rfc2518 import ResourceType
 from twext.web2.http_headers import MimeType, generateContentType
@@ -59,7 +60,7 @@
     CALENDAR_HOME_TABLE, CALENDAR_HOME_METADATA_TABLE,\
     CALENDAR_AND_CALENDAR_BIND, CALENDAR_OBJECT_REVISIONS_AND_BIND_TABLE,\
     CALENDAR_OBJECT_AND_BIND_TABLE, schema
-from twext.enterprise.dal.syntax import Select
+from twext.enterprise.dal.syntax import Select, Count, ColumnSyntax
 from twext.enterprise.dal.syntax import Insert
 from twext.enterprise.dal.syntax import Update
 from twext.enterprise.dal.syntax import Delete
@@ -72,7 +73,8 @@
 
 from txdav.caldav.datastore.util import StorageTransportBase
 from txdav.common.icommondatastore import IndexedSearchException,\
-    InternalDataStoreError
+    InternalDataStoreError, HomeChildNameAlreadyExistsError,\
+    HomeChildNameNotAllowedError
 
 from pycalendar.datetime import PyCalendarDateTime
 from pycalendar.duration import PyCalendarDuration
@@ -100,6 +102,8 @@
     _notifierPrefix = "CalDAV"
     _revisionsTable = CALENDAR_OBJECT_REVISIONS_TABLE
 
+    _dataVersionKey = "CALENDAR-DATAVERSION"
+
     _cacher = Memcacher("SQL.calhome", pickle=True, key_normalization=False)
 
     def __init__(self, transaction, ownerUID, notifiers):
@@ -211,14 +215,39 @@
 
     @inlineCallbacks
     def createdHome(self):
+        
+        # Default calendar
         defaultCal = yield self.createCalendarWithName("calendar")
         props = defaultCal.properties()
-        props[PropertyName(*ScheduleCalendarTransp.qname())] = ScheduleCalendarTransp(
-            Opaque())
+        props[PropertyName(*ScheduleCalendarTransp.qname())] = ScheduleCalendarTransp(Opaque())
+        
+        # Check whether components type must be separate
+        if config.RestrictCalendarsToOneComponentType:
+            defaultCal.setSupportedComponents("VEVENT")
+            
+            # Default tasks
+            defaultTasks = yield self.createCalendarWithName("tasks")
+            defaultTasks.setSupportedComponents("VTODO")
+            
         yield self.createCalendarWithName("inbox")
 
+    @inlineCallbacks
+    def splitCalendars(self):
+        """
+        Split all regular calendars by component type
+        """
+        
+        # Make sure the loop does not operate on any new calendars created during the loop
+        self.log_warn("Splitting calendars for user %s" % (self._ownerUID,))
+        calendars = yield self.calendars()
+        for calendar in calendars:
+            
+            # Ignore inbox - also shared calendars are not part of .calendars() 
+            if calendar.name() == "inbox":
+                continue
+            split_count = yield calendar.splitCollectionByComponentTypes()
+            self.log_warn("  Calendar: '%s', split into %d" % (calendar.name(), split_count+1,))
 
-
 class Calendar(CommonHomeChild):
     """
     File-based implementation of L{ICalendar}.
@@ -230,6 +259,7 @@
     _homeChildSchema = schema.CALENDAR
     _revisionsSchema = schema.CALENDAR_OBJECT_REVISIONS
     _objectSchema = schema.CALENDAR_OBJECT
+    _timeRangeSchema = schema.TIME_RANGE
 
     # string mappings (old, removing)
     _bindTable = CALENDAR_BIND_TABLE
@@ -257,8 +287,42 @@
             self._index = PostgresLegacyIndexEmulator(self)
         self._invites = SQLLegacyCalendarInvites(self)
         self._objectResourceClass = CalendarObject
+        
+        self._supportedComponents = None
 
 
+    @classmethod
+    def metadataColumns(cls):
+        """
+        Return a list of column name for retrieval of metadata. This allows
+        different child classes to have their own type specific data, but still make use of the
+        common base logic.
+        """
+        
+        # Common behavior is to have created and modified
+        
+        return (
+            cls._homeChildSchema.CREATED,
+            cls._homeChildSchema.MODIFIED,
+            cls._homeChildSchema.SUPPORTED_COMPONENTS,
+        )
+        
+    @classmethod
+    def metadataAttributes(cls):
+        """
+        Return a list of attribute names for retrieval of metadata. This allows
+        different child classes to have their own type specific data, but still make use of the
+        common base logic.
+        """
+        
+        # Common behavior is to have created and modified
+        
+        return (
+            "_created",
+            "_modified",
+            "_supportedComponents",
+        )
+        
     @property
     def _calendarHome(self):
         return self._home
@@ -291,6 +355,31 @@
         """
         return self._name == "inbox"
 
+    @inlineCallbacks
+    def setSupportedComponents(self, supported_components):
+        """
+        Update the database column with the supported components. Technically this should only happen once
+        on collection creation, but for migration we may need to change after the fact - hence a separate api.
+        """
+        
+        cal = self._homeChildSchema
+        yield Update(
+            {
+                cal.SUPPORTED_COMPONENTS : supported_components
+            },
+            Where=(cal.RESOURCE_ID == self._resourceID)
+        ).on(self._txn)
+        self._supportedComponents = supported_components
+
+    def getSupportedComponents(self):
+        return self._supportedComponents
+
+    def isSupportedComponent(self, componentType):
+        if self._supportedComponents:
+            return componentType.upper() in self._supportedComponents.split(",")
+        else:
+            return True
+
     def initPropertyStore(self, props):
         # Setup peruser special properties
         props.setSpecialProperties(
@@ -312,6 +401,178 @@
         """
         return MimeType.fromString("text/calendar; charset=utf-8")
 
+    @inlineCallbacks
+    def splitCollectionByComponentTypes(self):
+        """
+        If the calendar contains iCalendar data with different component types, then split it into separate collections
+        each containing only one component type. When doing this make sure properties and sharing state are preserved
+        on any new calendars created. Also restrict the new calendars to only the one appropriate component type. Return
+        the number of splits done.
+        """
+        
+        # First see how many different component types there are
+        split_count = 0
+        components = yield self._countComponentTypes()
+        if len(components) <= 1:
+
+            # Restrict calendar to single component type
+            component = components[0][0] if components else "VEVENT"
+            yield self.setSupportedComponents(component.upper())
+
+            returnValue(split_count)
+        
+        # We will leave the component type with the highest count in the current calendar and create new calendars
+        # for the others which will be moved over
+        maxComponent = max(components, key=lambda x:x[1])[0]
+        
+        for component, _ignore_count in components:
+            if component == maxComponent:
+                continue
+            split_count += 1
+            yield self._splitComponentType(component)
+
+        # Restrict calendar to single component type
+        yield self.setSupportedComponents(maxComponent.upper())
+
+        returnValue(split_count)
+
+    @inlineCallbacks
+    def _countComponentTypes(self):
+        """
+        Count each component type in this calendar.
+        
+        @return: a C{tuple} of C{tuple} containing the component type name and count. 
+        """
+
+        ob = self._objectSchema
+        _componentsQuery = Select(
+            [ob.ICALENDAR_TYPE, Count(ob.ICALENDAR_TYPE)],
+            From=ob,
+            Where=ob.CALENDAR_RESOURCE_ID == Parameter('calID'),
+            GroupBy=ob.ICALENDAR_TYPE
+        )
+
+        rows = yield _componentsQuery.on(self._txn, calID=self._resourceID)
+        result = tuple([(componentType, componentCount) for componentType, componentCount in sorted(rows, key=lambda x:x[0])])
+        returnValue(result)
+        
+    @inlineCallbacks
+    def _splitComponentType(self, component):
+        """
+        Create a new calendar and move all components of the specified component type into the new one.
+        Make sure properties and sharing state is preserved on the new calendar.
+        
+        @param component: Component type to split out
+        @type component: C{str}
+        """
+        
+        # Create the new calendar
+        try:
+            newcalendar = yield self._home.createCalendarWithName("%s-%s" % (self._name, component.lower(),))
+        except HomeChildNameAlreadyExistsError:
+            # If the name we want exists, try repeating with up to ten more
+            for ctr in range(10):
+                try:
+                    newcalendar = yield self._home.createCalendarWithName("%s-%s-%d" % (self._name, component.lower(), ctr+1,))
+                except HomeChildNameAlreadyExistsError:
+                    continue
+            else:
+                # At this point we are stuck
+                raise HomeChildNameNotAllowedError
+        
+        # Restrict calendar to single component type
+        yield newcalendar.setSupportedComponents(component.upper())
+        
+        # Transfer properties over
+        yield self._properties.copyAllProperties(newcalendar._properties)
+        
+        # Transfer sharing
+        yield self._transferSharingDetails(newcalendar, component)
+        
+        # Now move calendar data over
+        yield self._transferCalendarObjects(newcalendar, component)
+        
+    @inlineCallbacks
+    def _transferSharingDetails(self, newcalendar, component):
+        """
+        If the current calendar is shared, make the new calendar shared in the same way, but tweak the name.
+        """
+
+        cb = self._bindSchema
+        columns = [ColumnSyntax(item) for item in self._bindSchema.model.columns]
+        _bindQuery = Select(
+            columns,
+            From=cb,
+            Where=(cb.CALENDAR_RESOURCE_ID == Parameter('calID')).And(
+                cb.CALENDAR_HOME_RESOURCE_ID != Parameter('homeID'))
+        )
+        
+        rows = yield _bindQuery.on(
+            self._txn,
+            calID=self._resourceID,
+            homeID=self._home._resourceID,
+        )
+        
+        if len(rows) == 0:
+            returnValue(None)
+        
+        for row in rows:
+            columnMap = dict(zip(columns, row))
+            columnMap[cb.CALENDAR_RESOURCE_ID] = newcalendar._resourceID
+            columnMap[cb.CALENDAR_RESOURCE_NAME] = "%s-%s" % (columnMap[cb.CALENDAR_RESOURCE_NAME], component.lower(),)
+            yield Insert(columnMap).on(self._txn)   
+
+    @inlineCallbacks
+    def _transferCalendarObjects(self, newcalendar, component):
+        """
+        Move all calendar components of the specified type to the specified calendar.
+        """
+
+        # Find resource-ids for all matching components
+        ob = self._objectSchema
+        _componentsQuery = Select(
+            [ob.RESOURCE_ID],
+            From=ob,
+            Where=(ob.CALENDAR_RESOURCE_ID == Parameter('calID')).And(
+                ob.ICALENDAR_TYPE == Parameter('componentType'))
+        )
+
+        rows = yield _componentsQuery.on(
+            self._txn,
+            calID=self._resourceID,
+            componentType=component,
+        )
+        
+        if len(rows) == 0:
+            returnValue(None)
+        
+        for row in rows:
+            resourceID = row[0]
+            child = yield self.objectResourceWithID(resourceID)
+            yield self.moveObjectResource(child, newcalendar)
+
+    @classproperty
+    def _moveTimeRangeUpdateQuery(cls): #@NoSelf
+        """
+        DAL query to update a child to be in a new parent.
+        """
+        tr = cls._timeRangeSchema
+        return Update(
+            {tr.CALENDAR_RESOURCE_ID: Parameter("newParentID")},
+            Where=tr.CALENDAR_OBJECT_RESOURCE_ID == Parameter("resourceID")
+        )
+
+    @inlineCallbacks
+    def _movedObjectResource(self, child, newparent):
+        """
+        Make sure time range entries have the new parent resource id.
+        """
+        yield self._moveTimeRangeUpdateQuery.on(
+            self._txn,
+            newParentID=newparent._resourceID,
+            resourceID=child._resourceID
+        )
+        
 icalfbtype_to_indexfbtype = {
     "UNKNOWN"         : 0,
     "FREE"            : 1,

Deleted: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/1.ics
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/1.ics	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/1.ics	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,32 +0,0 @@
-BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//Apple Inc.//iCal 4.0.1//EN
-CALSCALE:GREGORIAN
-BEGIN:VTIMEZONE
-TZID:US/Pacific
-BEGIN:DAYLIGHT
-TZOFFSETFROM:-0800
-RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
-DTSTART:20070311T020000
-TZNAME:PDT
-TZOFFSETTO:-0700
-END:DAYLIGHT
-BEGIN:STANDARD
-TZOFFSETFROM:-0700
-RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
-DTSTART:20071104T020000
-TZNAME:PST
-TZOFFSETTO:-0800
-END:STANDARD
-END:VTIMEZONE
-BEGIN:VEVENT
-DTEND;TZID=US/Pacific:20090324T124500
-UID:uid1
-DTSTAMP:20090326T145447Z
-X-APPLE-DROPBOX:/calendars/__uids__/user01/dropbox/uid1.dropbox
-ATTACH;VALUE=URI:/calendars/__uids__/user01/dropbox/uid1.dropbox/test.txt
-SUMMARY:CalDAV protocol updates
-DTSTART;TZID=US/Pacific:20090324T121500
-CREATED:20090326T145440Z
-END:VEVENT
-END:VCALENDAR

Copied: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/1.ics (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/1.ics)
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/1.ics	                        (rev 0)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/1.ics	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,32 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VTIMEZONE
+TZID:US/Pacific
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0800
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
+DTSTART:20070311T020000
+TZNAME:PDT
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:-0700
+RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+DTSTART:20071104T020000
+TZNAME:PST
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTEND;TZID=US/Pacific:20090324T124500
+UID:uid1
+DTSTAMP:20090326T145447Z
+X-APPLE-DROPBOX:/calendars/__uids__/user01/dropbox/uid1.dropbox
+ATTACH;VALUE=URI:/calendars/__uids__/user01/dropbox/uid1.dropbox/test.txt
+SUMMARY:CalDAV protocol updates
+DTSTART;TZID=US/Pacific:20090324T121500
+CREATED:20090326T145440Z
+END:VEVENT
+END:VCALENDAR

Deleted: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/2.ics
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/2.ics	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/2.ics	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,32 +0,0 @@
-BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//Apple Inc.//iCal 4.0.1//EN
-CALSCALE:GREGORIAN
-BEGIN:VTIMEZONE
-TZID:US/Pacific
-BEGIN:DAYLIGHT
-TZOFFSETFROM:-0800
-RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
-DTSTART:20070311T020000
-TZNAME:PDT
-TZOFFSETTO:-0700
-END:DAYLIGHT
-BEGIN:STANDARD
-TZOFFSETFROM:-0700
-RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
-DTSTART:20071104T020000
-TZNAME:PST
-TZOFFSETTO:-0800
-END:STANDARD
-END:VTIMEZONE
-BEGIN:VEVENT
-DTEND;TZID=US/Pacific:20090324T124500
-UID:uid2
-DTSTAMP:20090326T145447Z
-X-APPLE-DROPBOX:/calendars/__uids__/user01/dropbox/uid2.dropbox
-ATTACH;VALUE=URI:/calendars/__uids__/user01/dropbox/uid2.dropbox/test.txt
-SUMMARY:CalDAV protocol updates
-DTSTART;TZID=US/Pacific:20090324T121500
-CREATED:20090326T145440Z
-END:VEVENT
-END:VCALENDAR

Copied: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/2.ics (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/2.ics)
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/2.ics	                        (rev 0)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/2.ics	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,32 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VTIMEZONE
+TZID:US/Pacific
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0800
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
+DTSTART:20070311T020000
+TZNAME:PDT
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:-0700
+RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+DTSTART:20071104T020000
+TZNAME:PST
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTEND;TZID=US/Pacific:20090324T124500
+UID:uid2
+DTSTAMP:20090326T145447Z
+X-APPLE-DROPBOX:/calendars/__uids__/user01/dropbox/uid2.dropbox
+ATTACH;VALUE=URI:/calendars/__uids__/user01/dropbox/uid2.dropbox/test.txt
+SUMMARY:CalDAV protocol updates
+DTSTART;TZID=US/Pacific:20090324T121500
+CREATED:20090326T145440Z
+END:VEVENT
+END:VCALENDAR

Deleted: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/3.ics
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/3.ics	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/3.ics	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,32 +0,0 @@
-BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//Apple Inc.//iCal 4.0.1//EN
-CALSCALE:GREGORIAN
-BEGIN:VTIMEZONE
-TZID:US/Pacific
-BEGIN:DAYLIGHT
-TZOFFSETFROM:-0800
-RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
-DTSTART:20070311T020000
-TZNAME:PDT
-TZOFFSETTO:-0700
-END:DAYLIGHT
-BEGIN:STANDARD
-TZOFFSETFROM:-0700
-RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
-DTSTART:20071104T020000
-TZNAME:PST
-TZOFFSETTO:-0800
-END:STANDARD
-END:VTIMEZONE
-BEGIN:VEVENT
-DTEND;TZID=US/Pacific:20090324T124500
-UID:uid3
-DTSTAMP:20090326T145447Z
-X-APPLE-DROPBOX:/calendars/__uids__/user01/dropbox/uid2.dropbox
-ATTACH;VALUE=URI:/calendars/__uids__/user01/dropbox/uid2.dropbox/test.txt
-SUMMARY:CalDAV protocol updates
-DTSTART;TZID=US/Pacific:20090324T121500
-CREATED:20090326T145440Z
-END:VEVENT
-END:VCALENDAR

Copied: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/3.ics (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/3.ics)
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/3.ics	                        (rev 0)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/3.ics	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,32 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VTIMEZONE
+TZID:US/Pacific
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0800
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
+DTSTART:20070311T020000
+TZNAME:PDT
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:-0700
+RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+DTSTART:20071104T020000
+TZNAME:PST
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTEND;TZID=US/Pacific:20090324T124500
+UID:uid3
+DTSTAMP:20090326T145447Z
+X-APPLE-DROPBOX:/calendars/__uids__/user01/dropbox/uid2.dropbox
+ATTACH;VALUE=URI:/calendars/__uids__/user01/dropbox/uid2.dropbox/test.txt
+SUMMARY:CalDAV protocol updates
+DTSTART;TZID=US/Pacific:20090324T121500
+CREATED:20090326T145440Z
+END:VEVENT
+END:VCALENDAR

Deleted: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/1.ics
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/1.ics	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/1.ics	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,32 +0,0 @@
-BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//Apple Inc.//iCal 4.0.1//EN
-CALSCALE:GREGORIAN
-BEGIN:VTIMEZONE
-TZID:US/Pacific
-BEGIN:DAYLIGHT
-TZOFFSETFROM:-0800
-RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
-DTSTART:20070311T020000
-TZNAME:PDT
-TZOFFSETTO:-0700
-END:DAYLIGHT
-BEGIN:STANDARD
-TZOFFSETFROM:-0700
-RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
-DTSTART:20071104T020000
-TZNAME:PST
-TZOFFSETTO:-0800
-END:STANDARD
-END:VTIMEZONE
-BEGIN:VEVENT
-DTEND;TZID=US/Pacific:20090324T124500
-UID:uid2-1
-DTSTAMP:20090326T145447Z
-X-APPLE-DROPBOX:/calendars/__uids__/user01/dropbox/uid1.dropbox
-ATTACH;VALUE=URI:/calendars/__uids__/user01/dropbox/uid1.dropbox/test.txt
-SUMMARY:CalDAV protocol updates
-DTSTART;TZID=US/Pacific:20090324T121500
-CREATED:20090326T145440Z
-END:VEVENT
-END:VCALENDAR

Copied: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/1.ics (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/1.ics)
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/1.ics	                        (rev 0)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/1.ics	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,32 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VTIMEZONE
+TZID:US/Pacific
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0800
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
+DTSTART:20070311T020000
+TZNAME:PDT
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:-0700
+RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+DTSTART:20071104T020000
+TZNAME:PST
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTEND;TZID=US/Pacific:20090324T124500
+UID:uid2-1
+DTSTAMP:20090326T145447Z
+X-APPLE-DROPBOX:/calendars/__uids__/user01/dropbox/uid1.dropbox
+ATTACH;VALUE=URI:/calendars/__uids__/user01/dropbox/uid1.dropbox/test.txt
+SUMMARY:CalDAV protocol updates
+DTSTART;TZID=US/Pacific:20090324T121500
+CREATED:20090326T145440Z
+END:VEVENT
+END:VCALENDAR

Deleted: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/2.ics
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/2.ics	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/2.ics	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,32 +0,0 @@
-BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//Apple Inc.//iCal 4.0.1//EN
-CALSCALE:GREGORIAN
-BEGIN:VTIMEZONE
-TZID:US/Pacific
-BEGIN:DAYLIGHT
-TZOFFSETFROM:-0800
-RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
-DTSTART:20070311T020000
-TZNAME:PDT
-TZOFFSETTO:-0700
-END:DAYLIGHT
-BEGIN:STANDARD
-TZOFFSETFROM:-0700
-RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
-DTSTART:20071104T020000
-TZNAME:PST
-TZOFFSETTO:-0800
-END:STANDARD
-END:VTIMEZONE
-BEGIN:VEVENT
-DTEND;TZID=US/Pacific:20090324T124500
-UID:uid2-2
-DTSTAMP:20090326T145447Z
-X-APPLE-DROPBOX:/calendars/__uids__/user01/dropbox/uid2.dropbox
-ATTACH;VALUE=URI:/calendars/__uids__/user01/dropbox/uid2.dropbox/test.txt
-SUMMARY:CalDAV protocol updates
-DTSTART;TZID=US/Pacific:20090324T121500
-CREATED:20090326T145440Z
-END:VEVENT
-END:VCALENDAR

Copied: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/2.ics (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/2.ics)
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/2.ics	                        (rev 0)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/2.ics	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,32 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VTIMEZONE
+TZID:US/Pacific
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0800
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
+DTSTART:20070311T020000
+TZNAME:PDT
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:-0700
+RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+DTSTART:20071104T020000
+TZNAME:PST
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTEND;TZID=US/Pacific:20090324T124500
+UID:uid2-2
+DTSTAMP:20090326T145447Z
+X-APPLE-DROPBOX:/calendars/__uids__/user01/dropbox/uid2.dropbox
+ATTACH;VALUE=URI:/calendars/__uids__/user01/dropbox/uid2.dropbox/test.txt
+SUMMARY:CalDAV protocol updates
+DTSTART;TZID=US/Pacific:20090324T121500
+CREATED:20090326T145440Z
+END:VEVENT
+END:VCALENDAR

Deleted: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/3.ics
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/3.ics	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/3.ics	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,29 +0,0 @@
-BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//Apple Inc.//iCal 4.0.1//EN
-CALSCALE:GREGORIAN
-BEGIN:VTIMEZONE
-TZID:US/Pacific
-BEGIN:DAYLIGHT
-TZOFFSETFROM:-0800
-RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
-DTSTART:20070311T020000
-TZNAME:PDT
-TZOFFSETTO:-0700
-END:DAYLIGHT
-BEGIN:STANDARD
-TZOFFSETFROM:-0700
-RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
-DTSTART:20071104T020000
-TZNAME:PST
-TZOFFSETTO:-0800
-END:STANDARD
-END:VTIMEZONE
-BEGIN:VTODO
-UID:uid2-3
-DTSTAMP:20090326T145447Z
-SUMMARY:Do something...
-DUE;TZID=US/Pacific:20110324T121500
-CREATED:20090326T145440Z
-END:VTODO
-END:VCALENDAR

Copied: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/3.ics (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/3.ics)
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/3.ics	                        (rev 0)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/3.ics	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,29 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VTIMEZONE
+TZID:US/Pacific
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0800
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
+DTSTART:20070311T020000
+TZNAME:PDT
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:-0700
+RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+DTSTART:20071104T020000
+TZNAME:PST
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VTODO
+UID:uid2-3
+DTSTAMP:20090326T145447Z
+SUMMARY:Do something...
+DUE;TZID=US/Pacific:20110324T121500
+CREATED:20090326T145440Z
+END:VTODO
+END:VCALENDAR

Deleted: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/4.ics
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/4.ics	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/4.ics	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,30 +0,0 @@
-BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//Apple Inc.//iCal 4.0.1//EN
-CALSCALE:GREGORIAN
-BEGIN:VTIMEZONE
-TZID:US/Pacific
-BEGIN:DAYLIGHT
-TZOFFSETFROM:-0800
-RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
-DTSTART:20070311T020000
-TZNAME:PDT
-TZOFFSETTO:-0700
-END:DAYLIGHT
-BEGIN:STANDARD
-TZOFFSETFROM:-0700
-RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
-DTSTART:20071104T020000
-TZNAME:PST
-TZOFFSETTO:-0800
-END:STANDARD
-END:VTIMEZONE
-BEGIN:VEVENT
-DTEND;TZID=US/Pacific:20100324T124500
-UID:uid4-2
-DTSTAMP:20090326T145447Z
-SUMMARY:CalDAV protocol updates 2010
-DTSTART;TZID=US/Pacific:20100324T121500
-CREATED:20090326T145440Z
-END:VEVENT
-END:VCALENDAR

Copied: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/4.ics (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/4.ics)
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/4.ics	                        (rev 0)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/4.ics	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,30 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VTIMEZONE
+TZID:US/Pacific
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0800
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
+DTSTART:20070311T020000
+TZNAME:PDT
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:-0700
+RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+DTSTART:20071104T020000
+TZNAME:PST
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTEND;TZID=US/Pacific:20100324T124500
+UID:uid4-2
+DTSTAMP:20090326T145447Z
+SUMMARY:CalDAV protocol updates 2010
+DTSTART;TZID=US/Pacific:20100324T121500
+CREATED:20090326T145440Z
+END:VEVENT
+END:VCALENDAR

Deleted: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/5.ics
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/5.ics	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/5.ics	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,29 +0,0 @@
-BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//Apple Inc.//iCal 4.0.1//EN
-CALSCALE:GREGORIAN
-BEGIN:VTIMEZONE
-TZID:US/Pacific
-BEGIN:DAYLIGHT
-TZOFFSETFROM:-0800
-RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
-DTSTART:20070311T020000
-TZNAME:PDT
-TZOFFSETTO:-0700
-END:DAYLIGHT
-BEGIN:STANDARD
-TZOFFSETFROM:-0700
-RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
-DTSTART:20071104T020000
-TZNAME:PST
-TZOFFSETTO:-0800
-END:STANDARD
-END:VTIMEZONE
-BEGIN:VTODO
-UID:uid2-5
-DTSTAMP:20090326T145447Z
-SUMMARY:Do something...2012
-DUE;TZID=US/Pacific:20120324T121500
-CREATED:20090326T145440Z
-END:VTODO
-END:VCALENDAR

Copied: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/5.ics (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/5.ics)
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/5.ics	                        (rev 0)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/5.ics	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,29 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VTIMEZONE
+TZID:US/Pacific
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0800
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
+DTSTART:20070311T020000
+TZNAME:PDT
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:-0700
+RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+DTSTART:20071104T020000
+TZNAME:PST
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VTODO
+UID:uid2-5
+DTSTAMP:20090326T145447Z
+SUMMARY:Do something...2012
+DUE;TZID=US/Pacific:20120324T121500
+CREATED:20090326T145440Z
+END:VTODO
+END:VCALENDAR

Modified: CalendarServer/trunk/txdav/caldav/datastore/test/common.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/common.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/common.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -57,13 +57,17 @@
 from txdav.common.datastore.test.util import withSpecialQuota
 from txdav.common.icommondatastore import ConcurrentModification
 from twistedcaldav.ical import Component
+from twistedcaldav.config import config
 
 storePath = FilePath(__file__).parent().child("calendar_store")
 
 homeRoot = storePath.child("ho").child("me").child("home1")
-
 cal1Root = homeRoot.child("calendar_1")
 
+homeSplitsRoot = storePath.child("ho").child("me").child("home_splits")
+cal1SplitsRoot = homeSplitsRoot.child("calendar_1")
+cal2SplitsRoot = homeSplitsRoot.child("calendar_2")
+
 calendar1_objectNames = [
     "1.ics",
     "2.ics",
@@ -203,17 +207,25 @@
     }
     metadata4 = {
         "accessMode": "PUBLIC",
-        "isScheduleObject": None,
-        "scheduleTag": "abc",
+        "isScheduleObject": True,
+        "scheduleTag": "abc4",
         "scheduleEtags": (),
-        "hasPrivateComment": True,
+        "hasPrivateComment": False,
     }
+    metadata5 = {
+        "accessMode": "PUBLIC",
+        "isScheduleObject": True,
+        "scheduleTag": "abc5",
+        "scheduleEtags": (),
+        "hasPrivateComment": False,
+    }
 
     md5Values = (
         hashlib.md5("1234").hexdigest(),
         hashlib.md5("5678").hexdigest(),
         hashlib.md5("9ABC").hexdigest(),
-        hashlib.md5("EFGH").hexdigest(),
+        hashlib.md5("DEFG").hexdigest(),
+        hashlib.md5("HIJK").hexdigest(),
     )
     requirements = {
         "home1": {
@@ -227,7 +239,24 @@
             "calendar_empty": {},
             "not_a_calendar": None
         },
-        "not_a_home": None
+        "not_a_home": None,
+        "home_splits": {
+            "calendar_1": {
+                "1.ics": (cal1SplitsRoot.child("1.ics").getContent(), metadata1),
+                "2.ics": (cal1SplitsRoot.child("2.ics").getContent(), metadata2),
+                "3.ics": (cal1SplitsRoot.child("3.ics").getContent(), metadata3),
+            },
+            "calendar_2": {
+                "1.ics": (cal2SplitsRoot.child("1.ics").getContent(), metadata1),
+                "2.ics": (cal2SplitsRoot.child("2.ics").getContent(), metadata2),
+                "3.ics": (cal2SplitsRoot.child("3.ics").getContent(), metadata3),
+                "4.ics": (cal2SplitsRoot.child("4.ics").getContent(), metadata4),
+                "5.ics": (cal2SplitsRoot.child("5.ics").getContent(), metadata4),
+            },
+        },
+        "home_splits_shared": {
+            "calendar_1": {},
+        },
     }
     md5s = {
         "home1": {
@@ -241,7 +270,21 @@
             "calendar_empty": {},
             "not_a_calendar": None
         },
-        "not_a_home": None
+        "not_a_home": None,
+        "home_splits": {
+            "calendar_1": {
+                "1.ics": md5Values[0],
+                "2.ics": md5Values[1],
+                "3.ics": md5Values[2],
+            },
+            "calendar_2": {
+                "1.ics": md5Values[0],
+                "2.ics": md5Values[1],
+                "3.ics": md5Values[2],
+                "4.ics": md5Values[3],
+                "5.ics": md5Values[4],
+            },
+        },
     }
 
 
@@ -546,6 +589,34 @@
 
 
     @inlineCallbacks
+    def test_calendarTasks_exists(self):
+        """
+        L{ICalendarHome.createdHome} creates a calendar only, or a calendar and tasks
+        collection only, in addition to inbox.
+        """
+        self.patch(config, "RestrictCalendarsToOneComponentType", False)
+        home1 = yield self.transactionUnderTest().calendarHomeWithUID("home_provision1", create=True)
+        for name in ("calendar", "inbox",):
+            calendar = yield home1.calendarWithName(name)
+            if calendar is None:
+                self.fail("calendar %r didn't exist" % (name,))
+            self.assertProvides(ICalendar, calendar)
+            self.assertEquals(calendar.name(), name)
+        for name in ("tasks",):
+            calendar = yield home1.calendarWithName(name)
+            if calendar is not None:
+                self.fail("calendar %r exists" % (name,))
+
+        self.patch(config, "RestrictCalendarsToOneComponentType", True)
+        home2 = yield self.transactionUnderTest().calendarHomeWithUID("home_provision2", create=True)
+        for name in ("calendar", "tasks", "inbox",):
+            calendar = yield home2.calendarWithName(name)
+            if calendar is None:
+                self.fail("calendar %r didn't exist" % (name,))
+            self.assertProvides(ICalendar, calendar)
+            self.assertEquals(calendar.name(), name)
+
+    @inlineCallbacks
     def test_calendarWithName_exists(self):
         """
         L{ICalendarHome.calendarWithName} returns an L{ICalendar} provider,
@@ -695,6 +766,41 @@
 
 
     @inlineCallbacks
+    def test_supportedComponentSet(self):
+        """
+        Attempt to remove an non-existing calendar object should raise.
+        """
+        calendar = yield self.calendarUnderTest()
+
+        result = yield maybeDeferred(calendar.getSupportedComponents)
+        self.assertEquals(result, None)
+
+        yield maybeDeferred(calendar.setSupportedComponents, "VEVENT,VTODO")
+        result = yield maybeDeferred(calendar.getSupportedComponents)
+        self.assertEquals(result, "VEVENT,VTODO")
+
+        yield maybeDeferred(calendar.setSupportedComponents, None)
+        result = yield maybeDeferred(calendar.getSupportedComponents)
+        self.assertEquals(result, None)
+
+    @inlineCallbacks
+    def test_countComponentTypes(self):
+        """
+        Test Calendar._countComponentTypes to make sure correct counts are returned.
+        """
+        
+        tests = (
+            ("calendar_1", (("VEVENT", 3),)),
+            ("calendar_2", (("VEVENT", 3), ("VTODO", 2))),
+        )
+        
+        for calname, results in tests:
+            testalendar = yield (yield self.transactionUnderTest().calendarHomeWithUID(
+                "home_splits")).calendarWithName(calname)
+            result = yield maybeDeferred(testalendar._countComponentTypes)
+            self.assertEquals(result, results)
+
+    @inlineCallbacks
     def test_calendarObjects(self):
         """
         L{ICalendar.calendarObjects} will enumerate the calendar objects present


Property changes on: CalendarServer/trunk/txdav/caldav/datastore/test/test_index_file.py
___________________________________________________________________
Modified: svn:mergeinfo
   - /CalendarServer/branches/config-separation/txdav/caldav/datastore/test/test_index_file.py:4379-4443
/CalendarServer/branches/egg-info-351/txdav/caldav/datastore/test/test_index_file.py:4589-4625
/CalendarServer/branches/generic-sqlstore/txdav/caldav/datastore/test/test_index_file.py:6167-6191
/CalendarServer/branches/new-store-no-caldavfile-2/txdav/caldav/datastore/test/test_index_file.py:5936-5981
/CalendarServer/branches/new-store-no-caldavfile/txdav/caldav/datastore/test/test_index_file.py:5911-5935
/CalendarServer/branches/new-store/txdav/caldav/datastore/test/test_index_file.py:5594-5934
/CalendarServer/branches/users/cdaboo/batchupload-6699/txdav/caldav/datastore/test/test_index_file.py:6700-7198
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692/txdav/caldav/datastore/test/test_index_file.py:5693-5702
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627/txdav/caldav/datastore/test/test_index_file.py:3628-3644
/CalendarServer/branches/users/cdaboo/more-sharing-5591/txdav/caldav/datastore/test/test_index_file.py:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464/txdav/caldav/datastore/test/test_index_file.py:4465-4957
/CalendarServer/branches/users/cdaboo/pods/txdav/caldav/datastore/test/test_index_file.py:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/datastore/test/test_index_file.py:7085-7206
/CalendarServer/branches/users/cdaboo/pycard/txdav/caldav/datastore/test/test_index_file.py:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes/txdav/caldav/datastore/test/test_index_file.py:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070/txdav/caldav/datastore/test/test_index_file.py:5071-5105
/CalendarServer/branches/users/cdaboo/shared-calendars-5187/txdav/caldav/datastore/test/test_index_file.py:5188-5440
/CalendarServer/branches/users/cdaboo/timezones/txdav/caldav/datastore/test/test_index_file.py:7443-7699
/CalendarServer/branches/users/glyph/conn-limit/txdav/caldav/datastore/test/test_index_file.py:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge/txdav/caldav/datastore/test/test_index_file.py:4971-5080
/CalendarServer/branches/users/glyph/dalify/txdav/caldav/datastore/test/test_index_file.py:6932-7023
/CalendarServer/branches/users/glyph/deploybuild/txdav/caldav/datastore/test/test_index_file.py:7563-7572
/CalendarServer/branches/users/glyph/dont-start-postgres/txdav/caldav/datastore/test/test_index_file.py:6592-6614
/CalendarServer/branches/users/glyph/linux-tests/txdav/caldav/datastore/test/test_index_file.py:6893-6900
/CalendarServer/branches/users/glyph/misc-portability-fixes/txdav/caldav/datastore/test/test_index_file.py:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6/txdav/caldav/datastore/test/test_index_file.py:6322-6334
/CalendarServer/branches/users/glyph/more-deferreds-7/txdav/caldav/datastore/test/test_index_file.py:6369
/CalendarServer/branches/users/glyph/new-export/txdav/caldav/datastore/test/test_index_file.py:7444-7485
/CalendarServer/branches/users/glyph/oracle-nulls/txdav/caldav/datastore/test/test_index_file.py:7340-7351
/CalendarServer/branches/users/glyph/oracle/txdav/caldav/datastore/test/test_index_file.py:7106-7155
/CalendarServer/branches/users/glyph/sendfdport/txdav/caldav/datastore/test/test_index_file.py:5388-5424
/CalendarServer/branches/users/glyph/sharedpool/txdav/caldav/datastore/test/test_index_file.py:6490-6550
/CalendarServer/branches/users/glyph/sql-store/txdav/caldav/datastore/test/test_index_file.py:5929-6073
/CalendarServer/branches/users/glyph/subtransactions/txdav/caldav/datastore/test/test_index_file.py:7248-7258
/CalendarServer/branches/users/glyph/use-system-twisted/txdav/caldav/datastore/test/test_index_file.py:5084-5149
/CalendarServer/branches/users/sagen/applepush/txdav/caldav/datastore/test/test_index_file.py:8126-8184
/CalendarServer/branches/users/sagen/inboxitems/txdav/caldav/datastore/test/test_index_file.py:7380-7381
/CalendarServer/branches/users/sagen/locations-resources-2/txdav/caldav/datastore/test/test_index_file.py:5052-5061
/CalendarServer/branches/users/sagen/locations-resources/txdav/caldav/datastore/test/test_index_file.py:5032-5051
/CalendarServer/branches/users/sagen/purge_old_events/txdav/caldav/datastore/test/test_index_file.py:6735-6746
/CalendarServer/branches/users/sagen/resource-delegates-4038/txdav/caldav/datastore/test/test_index_file.py:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066/txdav/caldav/datastore/test/test_index_file.py:4068-4075
/CalendarServer/branches/users/sagen/resources-2/txdav/caldav/datastore/test/test_index_file.py:5084-5093
/CalendarServer/branches/users/wsanchez/transations/txdav/caldav/datastore/test/test_index_file.py:5515-5593
/CalendarServer/trunk/twistedcaldav/test/test_index.py:6322-6394
   + /CalendarServer/branches/config-separation/txdav/caldav/datastore/test/test_index_file.py:4379-4443
/CalendarServer/branches/egg-info-351/txdav/caldav/datastore/test/test_index_file.py:4589-4625
/CalendarServer/branches/generic-sqlstore/txdav/caldav/datastore/test/test_index_file.py:6167-6191
/CalendarServer/branches/new-store-no-caldavfile-2/txdav/caldav/datastore/test/test_index_file.py:5936-5981
/CalendarServer/branches/new-store-no-caldavfile/txdav/caldav/datastore/test/test_index_file.py:5911-5935
/CalendarServer/branches/new-store/txdav/caldav/datastore/test/test_index_file.py:5594-5934
/CalendarServer/branches/users/cdaboo/batchupload-6699/txdav/caldav/datastore/test/test_index_file.py:6700-7198
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692/txdav/caldav/datastore/test/test_index_file.py:5693-5702
/CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/caldav/datastore/test/test_index_file.py:8130-8346
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627/txdav/caldav/datastore/test/test_index_file.py:3628-3644
/CalendarServer/branches/users/cdaboo/more-sharing-5591/txdav/caldav/datastore/test/test_index_file.py:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464/txdav/caldav/datastore/test/test_index_file.py:4465-4957
/CalendarServer/branches/users/cdaboo/pods/txdav/caldav/datastore/test/test_index_file.py:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar/txdav/caldav/datastore/test/test_index_file.py:7085-7206
/CalendarServer/branches/users/cdaboo/pycard/txdav/caldav/datastore/test/test_index_file.py:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes/txdav/caldav/datastore/test/test_index_file.py:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070/txdav/caldav/datastore/test/test_index_file.py:5071-5105
/CalendarServer/branches/users/cdaboo/shared-calendars-5187/txdav/caldav/datastore/test/test_index_file.py:5188-5440
/CalendarServer/branches/users/cdaboo/timezones/txdav/caldav/datastore/test/test_index_file.py:7443-7699
/CalendarServer/branches/users/glyph/conn-limit/txdav/caldav/datastore/test/test_index_file.py:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge/txdav/caldav/datastore/test/test_index_file.py:4971-5080
/CalendarServer/branches/users/glyph/dalify/txdav/caldav/datastore/test/test_index_file.py:6932-7023
/CalendarServer/branches/users/glyph/deploybuild/txdav/caldav/datastore/test/test_index_file.py:7563-7572
/CalendarServer/branches/users/glyph/dont-start-postgres/txdav/caldav/datastore/test/test_index_file.py:6592-6614
/CalendarServer/branches/users/glyph/linux-tests/txdav/caldav/datastore/test/test_index_file.py:6893-6900
/CalendarServer/branches/users/glyph/misc-portability-fixes/txdav/caldav/datastore/test/test_index_file.py:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6/txdav/caldav/datastore/test/test_index_file.py:6322-6334
/CalendarServer/branches/users/glyph/more-deferreds-7/txdav/caldav/datastore/test/test_index_file.py:6369
/CalendarServer/branches/users/glyph/new-export/txdav/caldav/datastore/test/test_index_file.py:7444-7485
/CalendarServer/branches/users/glyph/oracle-nulls/txdav/caldav/datastore/test/test_index_file.py:7340-7351
/CalendarServer/branches/users/glyph/oracle/txdav/caldav/datastore/test/test_index_file.py:7106-7155
/CalendarServer/branches/users/glyph/sendfdport/txdav/caldav/datastore/test/test_index_file.py:5388-5424
/CalendarServer/branches/users/glyph/sharedpool/txdav/caldav/datastore/test/test_index_file.py:6490-6550
/CalendarServer/branches/users/glyph/sql-store/txdav/caldav/datastore/test/test_index_file.py:5929-6073
/CalendarServer/branches/users/glyph/subtransactions/txdav/caldav/datastore/test/test_index_file.py:7248-7258
/CalendarServer/branches/users/glyph/use-system-twisted/txdav/caldav/datastore/test/test_index_file.py:5084-5149
/CalendarServer/branches/users/sagen/applepush/txdav/caldav/datastore/test/test_index_file.py:8126-8184
/CalendarServer/branches/users/sagen/inboxitems/txdav/caldav/datastore/test/test_index_file.py:7380-7381
/CalendarServer/branches/users/sagen/locations-resources-2/txdav/caldav/datastore/test/test_index_file.py:5052-5061
/CalendarServer/branches/users/sagen/locations-resources/txdav/caldav/datastore/test/test_index_file.py:5032-5051
/CalendarServer/branches/users/sagen/purge_old_events/txdav/caldav/datastore/test/test_index_file.py:6735-6746
/CalendarServer/branches/users/sagen/resource-delegates-4038/txdav/caldav/datastore/test/test_index_file.py:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066/txdav/caldav/datastore/test/test_index_file.py:4068-4075
/CalendarServer/branches/users/sagen/resources-2/txdav/caldav/datastore/test/test_index_file.py:5084-5093
/CalendarServer/branches/users/wsanchez/transations/txdav/caldav/datastore/test/test_index_file.py:5515-5593
/CalendarServer/trunk/twistedcaldav/test/test_index.py:6322-6394

Modified: CalendarServer/trunk/txdav/caldav/datastore/test/test_scheduling.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/test_scheduling.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/test_scheduling.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -61,6 +61,7 @@
         raise SkipTest("No private attribute tests.")
 
     test_calendarObjectsWithDotFile = skipit
+    test_countComponentTypes = skipit
     test_init = skipit
 
 del FileStorageTests

Modified: CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -25,7 +25,7 @@
 from twisted.python import hashlib
 from twisted.trial import unittest
 
-from twext.enterprise.dal.syntax import Select, Parameter
+from twext.enterprise.dal.syntax import Select, Parameter, Insert
 from twext.python.vcomponent import VComponent
 from twext.web2.dav.element.rfc2518 import GETContentLanguage, ResourceType
 
@@ -35,7 +35,8 @@
 from txdav.caldav.datastore.test.test_file import setUpCalendarStore
 from txdav.caldav.datastore.util import _migrateCalendar, migrateHome
 from txdav.common.datastore.sql import ECALENDARTYPE
-from txdav.common.datastore.sql_tables import schema
+from txdav.common.datastore.sql_tables import schema, _BIND_MODE_DIRECT,\
+    _BIND_STATUS_ACCEPTED
 from txdav.common.datastore.test.util import buildStore, populateCalendarsFrom
 
 from twistedcaldav import caldavxml
@@ -256,6 +257,28 @@
         self.assertPropertiesSimilar(fromHome, toHome, builtinProperties)
 
 
+    def test_calendarHomeVersion(self):
+        """
+        The DATAVERSION column for new calendar homes must match the
+        CALENDAR-DATAVERSION value.
+        """
+        
+        home = yield self.transactionUnderTest().calendarHomeWithUID("home_version")
+        self.assertTrue(home is not None)
+        yield self.transactionUnderTest().commit
+        
+        txn = yield self.transactionUnderTest()
+        version = yield txn.calendarserverValue("CALENDAR-DATAVERSION")[0][0]
+        ch = schema.CALENDAR_HOME
+        homeVersion = yield Select(
+            [ch.DATAVERSION,],
+            From=ch,
+            Where=ch.OWNER_UID == "home_version",
+        ).on(txn)[0][0]
+        self.assertEqual(int(homeVersion, version))
+        
+        
+
     def test_eachCalendarHome(self):
         """
         L{ICalendarStore.eachCalendarHome} is currently stubbed out by
@@ -688,3 +711,124 @@
         yield d1
         yield d2
 
+    @inlineCallbacks
+    def test_transferSharingDetails(self):
+        """
+        Test Calendar._transferSharingDetails to make sure sharing details are transferred.
+        """
+        
+        shareeHome = yield self.transactionUnderTest().calendarHomeWithUID("home_splits_shared")
+
+        calendar = yield (yield self.transactionUnderTest().calendarHomeWithUID(
+            "home_splits")).calendarWithName("calendar_1")
+        
+        # Fake a shared binding on the original calendar
+        bind = calendar._bindSchema
+        _bindCreate = Insert({
+            bind.HOME_RESOURCE_ID: shareeHome._resourceID,
+            bind.RESOURCE_ID: calendar._resourceID, 
+            bind.RESOURCE_NAME: "shared_1",
+            bind.MESSAGE: "Shared to you",
+            bind.BIND_MODE: _BIND_MODE_DIRECT,
+            bind.BIND_STATUS: _BIND_STATUS_ACCEPTED,
+            bind.SEEN_BY_OWNER: True,
+            bind.SEEN_BY_SHAREE: True,
+        })
+        yield _bindCreate.on(self.transactionUnderTest())
+        sharedCalendar = yield shareeHome.sharedChildWithName("shared_1")
+        self.assertTrue(sharedCalendar is not None)
+        sharedCalendar = yield shareeHome.sharedChildWithName("shared_1_vtodo")
+        self.assertTrue(sharedCalendar is None)
+
+        # Now do the transfer and see if a new binding exists
+        newcalendar = yield (yield self.transactionUnderTest().calendarHomeWithUID(
+            "home_splits")).createCalendarWithName("calendar_new")
+        yield calendar._transferSharingDetails(newcalendar, "VTODO")
+
+        sharedCalendar = yield shareeHome.sharedChildWithName("shared_1")
+        self.assertTrue(sharedCalendar is not None)
+        self.assertEqual(sharedCalendar._resourceID, calendar._resourceID)
+
+        sharedCalendar = yield shareeHome.sharedChildWithName("shared_1-vtodo")
+        self.assertTrue(sharedCalendar is not None)
+        self.assertEqual(sharedCalendar._resourceID, newcalendar._resourceID)
+
+    @inlineCallbacks
+    def test_moveCalendarObjectResource(self):
+        """
+        Test Calendar._transferSharingDetails to make sure sharing details are transferred.
+        """
+        
+        calendar1 = yield (yield self.transactionUnderTest().calendarHomeWithUID(
+            "home_splits")).calendarWithName("calendar_1")
+        calendar2 = yield (yield self.transactionUnderTest().calendarHomeWithUID(
+            "home_splits")).calendarWithName("calendar_2")
+        
+        child = yield calendar2.calendarObjectWithName("5.ics")
+        
+        yield calendar2.moveObjectResource(child, calendar1)
+        
+        child = yield calendar2.calendarObjectWithName("5.ics")
+        self.assertTrue(child is None)
+        
+        child = yield calendar1.calendarObjectWithName("5.ics")
+        self.assertTrue(child is not None)
+
+    @inlineCallbacks
+    def test_splitCalendars(self):
+        """
+        Test Calendar.splitCollectionByComponentTypes to make sure components are split out,
+        sync information is updated.
+        """
+        
+        # calendar_1 no change
+        home = yield self.transactionUnderTest().calendarHomeWithUID("home_splits")
+        calendar1 = yield home.calendarWithName("calendar_1")
+        original_sync_token1 = yield calendar1.syncToken()
+        yield calendar1.splitCollectionByComponentTypes()
+        yield self.commit()
+
+        home = yield self.transactionUnderTest().calendarHomeWithUID("home_splits")
+
+        child = yield home.calendarWithName("calendar_1-vtodo")
+        self.assertTrue(child is None)
+
+        calendar1 = yield home.calendarWithName("calendar_1")        
+        children = yield calendar1.listCalendarObjects()
+        self.assertEqual(len(children), 3)
+        new_sync_token1 = yield calendar1.syncToken()
+        self.assertEqual(new_sync_token1, original_sync_token1)
+        result = yield calendar1.getSupportedComponents()
+        self.assertEquals(result, "VEVENT")
+
+        yield self.commit()
+
+        # calendar_2 does split
+        home = yield self.transactionUnderTest().calendarHomeWithUID("home_splits")
+        calendar2 = yield home.calendarWithName("calendar_2")        
+        original_sync_token2 = yield calendar2.syncToken()
+        yield calendar2.splitCollectionByComponentTypes()
+        yield self.commit()
+
+        home = yield self.transactionUnderTest().calendarHomeWithUID("home_splits")
+
+        calendar2_vtodo = yield home.calendarWithName("calendar_2-vtodo")
+        self.assertTrue(calendar2_vtodo is not None)
+        children = yield calendar2_vtodo.listCalendarObjects()
+        self.assertEqual(len(children), 2)
+        changed, deleted = yield calendar2_vtodo.resourceNamesSinceToken(None)
+        self.assertEqual(sorted(changed), ["3.ics", "5.ics"])
+        self.assertEqual(len(deleted), 0)
+        result = yield calendar2_vtodo.getSupportedComponents()
+        self.assertEquals(result, "VTODO")
+
+        calendar2 = yield home.calendarWithName("calendar_2")        
+        children = yield calendar2.listCalendarObjects()
+        self.assertEqual(len(children), 3)
+        new_sync_token2 = yield calendar2.syncToken()
+        self.assertNotEqual(new_sync_token2, original_sync_token2)
+        changed, deleted = yield calendar2.resourceNamesSinceToken(original_sync_token2)
+        self.assertEqual(len(changed), 0)
+        self.assertEqual(sorted(deleted), ["3.ics", "5.ics"])
+        result = yield calendar2.getSupportedComponents()
+        self.assertEquals(result, "VEVENT")

Modified: CalendarServer/trunk/txdav/caldav/datastore/util.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/util.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/txdav/caldav/datastore/util.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -14,6 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 ##
+from twistedcaldav.config import config
 
 """
 Utility logic common to multiple backend implementations.
@@ -277,6 +278,8 @@
         a calendar in outHome).
     """
     yield outHome.removeCalendarWithName("calendar")
+    if config.RestrictCalendarsToOneComponentType:
+        yield outHome.removeCalendarWithName("tasks")
     yield outHome.removeCalendarWithName("inbox")
     outHome.properties().update(inHome.properties())
     inCalendars = yield inHome.calendars()


Property changes on: CalendarServer/trunk/txdav/carddav/datastore/index_file.py
___________________________________________________________________
Modified: svn:mergeinfo
   - /CalendarServer/branches/config-separation/txdav/carddav/datastore/index_file.py:4379-4443
/CalendarServer/branches/egg-info-351/txdav/carddav/datastore/index_file.py:4589-4625
/CalendarServer/branches/generic-sqlstore/txdav/carddav/datastore/index_file.py:6167-6191
/CalendarServer/branches/new-store-no-caldavfile-2/txdav/carddav/datastore/index_file.py:5936-5981
/CalendarServer/branches/new-store-no-caldavfile/txdav/carddav/datastore/index_file.py:5911-5935
/CalendarServer/branches/new-store/txdav/carddav/datastore/index_file.py:5594-5934
/CalendarServer/branches/users/cdaboo/batchupload-6699/txdav/carddav/datastore/index_file.py:6700-7198
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692/txdav/carddav/datastore/index_file.py:5693-5702
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627/txdav/carddav/datastore/index_file.py:3628-3644
/CalendarServer/branches/users/cdaboo/implicituidrace/txdav/carddav/datastore/index_file.py:8137-8141
/CalendarServer/branches/users/cdaboo/more-sharing-5591/txdav/carddav/datastore/index_file.py:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464/txdav/carddav/datastore/index_file.py:4465-4957
/CalendarServer/branches/users/cdaboo/pods/txdav/carddav/datastore/index_file.py:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar/txdav/carddav/datastore/index_file.py:7085-7206
/CalendarServer/branches/users/cdaboo/pycard/txdav/carddav/datastore/index_file.py:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes/txdav/carddav/datastore/index_file.py:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070/txdav/carddav/datastore/index_file.py:5071-5105
/CalendarServer/branches/users/cdaboo/shared-calendars-5187/txdav/carddav/datastore/index_file.py:5188-5440
/CalendarServer/branches/users/cdaboo/timezones/txdav/carddav/datastore/index_file.py:7443-7699
/CalendarServer/branches/users/glyph/conn-limit/txdav/carddav/datastore/index_file.py:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge/txdav/carddav/datastore/index_file.py:4971-5080
/CalendarServer/branches/users/glyph/dalify/txdav/carddav/datastore/index_file.py:6932-7023
/CalendarServer/branches/users/glyph/deploybuild/txdav/carddav/datastore/index_file.py:7563-7572
/CalendarServer/branches/users/glyph/dont-start-postgres/txdav/carddav/datastore/index_file.py:6592-6614
/CalendarServer/branches/users/glyph/linux-tests/txdav/carddav/datastore/index_file.py:6893-6900
/CalendarServer/branches/users/glyph/misc-portability-fixes/txdav/carddav/datastore/index_file.py:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6/txdav/carddav/datastore/index_file.py:6322-6334
/CalendarServer/branches/users/glyph/more-deferreds-7/txdav/carddav/datastore/index_file.py:6369
/CalendarServer/branches/users/glyph/new-export/txdav/carddav/datastore/index_file.py:7444-7485
/CalendarServer/branches/users/glyph/oracle-nulls/txdav/carddav/datastore/index_file.py:7340-7351
/CalendarServer/branches/users/glyph/oracle/txdav/carddav/datastore/index_file.py:7106-7155
/CalendarServer/branches/users/glyph/sendfdport/txdav/carddav/datastore/index_file.py:5388-5424
/CalendarServer/branches/users/glyph/sharedpool/txdav/carddav/datastore/index_file.py:6490-6550
/CalendarServer/branches/users/glyph/sql-store/txdav/carddav/datastore/index_file.py:5929-6073
/CalendarServer/branches/users/glyph/subtransactions/txdav/carddav/datastore/index_file.py:7248-7258
/CalendarServer/branches/users/glyph/use-system-twisted/txdav/carddav/datastore/index_file.py:5084-5149
/CalendarServer/branches/users/sagen/applepush/txdav/carddav/datastore/index_file.py:8126-8184
/CalendarServer/branches/users/sagen/inboxitems/txdav/carddav/datastore/index_file.py:7380-7381
/CalendarServer/branches/users/sagen/locations-resources-2/txdav/carddav/datastore/index_file.py:5052-5061
/CalendarServer/branches/users/sagen/locations-resources/txdav/carddav/datastore/index_file.py:5032-5051
/CalendarServer/branches/users/sagen/purge_old_events/txdav/carddav/datastore/index_file.py:6735-6746
/CalendarServer/branches/users/sagen/resource-delegates-4038/txdav/carddav/datastore/index_file.py:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066/txdav/carddav/datastore/index_file.py:4068-4075
/CalendarServer/branches/users/sagen/resources-2/txdav/carddav/datastore/index_file.py:5084-5093
/CalendarServer/branches/users/wsanchez/transations/txdav/carddav/datastore/index_file.py:5515-5593
/CalendarServer/trunk/twistedcaldav/vcardindex.py:6322-6394
   + /CalendarServer/branches/config-separation/txdav/carddav/datastore/index_file.py:4379-4443
/CalendarServer/branches/egg-info-351/txdav/carddav/datastore/index_file.py:4589-4625
/CalendarServer/branches/generic-sqlstore/txdav/carddav/datastore/index_file.py:6167-6191
/CalendarServer/branches/new-store-no-caldavfile-2/txdav/carddav/datastore/index_file.py:5936-5981
/CalendarServer/branches/new-store-no-caldavfile/txdav/carddav/datastore/index_file.py:5911-5935
/CalendarServer/branches/new-store/txdav/carddav/datastore/index_file.py:5594-5934
/CalendarServer/branches/users/cdaboo/batchupload-6699/txdav/carddav/datastore/index_file.py:6700-7198
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692/txdav/carddav/datastore/index_file.py:5693-5702
/CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/carddav/datastore/index_file.py:8130-8346
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627/txdav/carddav/datastore/index_file.py:3628-3644
/CalendarServer/branches/users/cdaboo/implicituidrace/txdav/carddav/datastore/index_file.py:8137-8141
/CalendarServer/branches/users/cdaboo/more-sharing-5591/txdav/carddav/datastore/index_file.py:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464/txdav/carddav/datastore/index_file.py:4465-4957
/CalendarServer/branches/users/cdaboo/pods/txdav/carddav/datastore/index_file.py:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar/txdav/carddav/datastore/index_file.py:7085-7206
/CalendarServer/branches/users/cdaboo/pycard/txdav/carddav/datastore/index_file.py:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes/txdav/carddav/datastore/index_file.py:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070/txdav/carddav/datastore/index_file.py:5071-5105
/CalendarServer/branches/users/cdaboo/shared-calendars-5187/txdav/carddav/datastore/index_file.py:5188-5440
/CalendarServer/branches/users/cdaboo/timezones/txdav/carddav/datastore/index_file.py:7443-7699
/CalendarServer/branches/users/glyph/conn-limit/txdav/carddav/datastore/index_file.py:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge/txdav/carddav/datastore/index_file.py:4971-5080
/CalendarServer/branches/users/glyph/dalify/txdav/carddav/datastore/index_file.py:6932-7023
/CalendarServer/branches/users/glyph/deploybuild/txdav/carddav/datastore/index_file.py:7563-7572
/CalendarServer/branches/users/glyph/dont-start-postgres/txdav/carddav/datastore/index_file.py:6592-6614
/CalendarServer/branches/users/glyph/linux-tests/txdav/carddav/datastore/index_file.py:6893-6900
/CalendarServer/branches/users/glyph/misc-portability-fixes/txdav/carddav/datastore/index_file.py:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6/txdav/carddav/datastore/index_file.py:6322-6334
/CalendarServer/branches/users/glyph/more-deferreds-7/txdav/carddav/datastore/index_file.py:6369
/CalendarServer/branches/users/glyph/new-export/txdav/carddav/datastore/index_file.py:7444-7485
/CalendarServer/branches/users/glyph/oracle-nulls/txdav/carddav/datastore/index_file.py:7340-7351
/CalendarServer/branches/users/glyph/oracle/txdav/carddav/datastore/index_file.py:7106-7155
/CalendarServer/branches/users/glyph/sendfdport/txdav/carddav/datastore/index_file.py:5388-5424
/CalendarServer/branches/users/glyph/sharedpool/txdav/carddav/datastore/index_file.py:6490-6550
/CalendarServer/branches/users/glyph/sql-store/txdav/carddav/datastore/index_file.py:5929-6073
/CalendarServer/branches/users/glyph/subtransactions/txdav/carddav/datastore/index_file.py:7248-7258
/CalendarServer/branches/users/glyph/use-system-twisted/txdav/carddav/datastore/index_file.py:5084-5149
/CalendarServer/branches/users/sagen/applepush/txdav/carddav/datastore/index_file.py:8126-8184
/CalendarServer/branches/users/sagen/inboxitems/txdav/carddav/datastore/index_file.py:7380-7381
/CalendarServer/branches/users/sagen/locations-resources-2/txdav/carddav/datastore/index_file.py:5052-5061
/CalendarServer/branches/users/sagen/locations-resources/txdav/carddav/datastore/index_file.py:5032-5051
/CalendarServer/branches/users/sagen/purge_old_events/txdav/carddav/datastore/index_file.py:6735-6746
/CalendarServer/branches/users/sagen/resource-delegates-4038/txdav/carddav/datastore/index_file.py:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066/txdav/carddav/datastore/index_file.py:4068-4075
/CalendarServer/branches/users/sagen/resources-2/txdav/carddav/datastore/index_file.py:5084-5093
/CalendarServer/branches/users/wsanchez/transations/txdav/carddav/datastore/index_file.py:5515-5593
/CalendarServer/trunk/twistedcaldav/vcardindex.py:6322-6394

Modified: CalendarServer/trunk/txdav/carddav/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/sql.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/txdav/carddav/datastore/sql.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -82,6 +82,8 @@
     _notifierPrefix = "CardDAV"
     _revisionsTable = ADDRESSBOOK_OBJECT_REVISIONS_TABLE
 
+    _dataVersionKey = "ADDRESSBOOK-DATAVERSION"
+
     _cacher = Memcacher("SQL.adbkhome", pickle=True, key_normalization=False)
 
     def __init__(self, transaction, ownerUID, notifiers):


Property changes on: CalendarServer/trunk/txdav/carddav/datastore/test/test_index_file.py
___________________________________________________________________
Modified: svn:mergeinfo
   - /CalendarServer/branches/config-separation/txdav/carddav/datastore/test/test_index_file.py:4379-4443
/CalendarServer/branches/egg-info-351/txdav/carddav/datastore/test/test_index_file.py:4589-4625
/CalendarServer/branches/generic-sqlstore/txdav/carddav/datastore/test/test_index_file.py:6167-6191
/CalendarServer/branches/new-store-no-caldavfile-2/txdav/carddav/datastore/test/test_index_file.py:5936-5981
/CalendarServer/branches/new-store-no-caldavfile/txdav/carddav/datastore/test/test_index_file.py:5911-5935
/CalendarServer/branches/new-store/txdav/carddav/datastore/test/test_index_file.py:5594-5934
/CalendarServer/branches/users/cdaboo/batchupload-6699/txdav/carddav/datastore/test/test_index_file.py:6700-7198
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692/txdav/carddav/datastore/test/test_index_file.py:5693-5702
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627/txdav/carddav/datastore/test/test_index_file.py:3628-3644
/CalendarServer/branches/users/cdaboo/more-sharing-5591/txdav/carddav/datastore/test/test_index_file.py:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464/txdav/carddav/datastore/test/test_index_file.py:4465-4957
/CalendarServer/branches/users/cdaboo/pods/txdav/carddav/datastore/test/test_index_file.py:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar/txdav/carddav/datastore/test/test_index_file.py:7085-7206
/CalendarServer/branches/users/cdaboo/pycard/txdav/carddav/datastore/test/test_index_file.py:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes/txdav/carddav/datastore/test/test_index_file.py:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070/txdav/carddav/datastore/test/test_index_file.py:5071-5105
/CalendarServer/branches/users/cdaboo/shared-calendars-5187/txdav/carddav/datastore/test/test_index_file.py:5188-5440
/CalendarServer/branches/users/cdaboo/timezones/txdav/carddav/datastore/test/test_index_file.py:7443-7699
/CalendarServer/branches/users/glyph/conn-limit/txdav/carddav/datastore/test/test_index_file.py:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge/txdav/carddav/datastore/test/test_index_file.py:4971-5080
/CalendarServer/branches/users/glyph/dalify/txdav/carddav/datastore/test/test_index_file.py:6932-7023
/CalendarServer/branches/users/glyph/deploybuild/txdav/carddav/datastore/test/test_index_file.py:7563-7572
/CalendarServer/branches/users/glyph/dont-start-postgres/txdav/carddav/datastore/test/test_index_file.py:6592-6614
/CalendarServer/branches/users/glyph/linux-tests/txdav/carddav/datastore/test/test_index_file.py:6893-6900
/CalendarServer/branches/users/glyph/misc-portability-fixes/txdav/carddav/datastore/test/test_index_file.py:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6/txdav/carddav/datastore/test/test_index_file.py:6322-6334
/CalendarServer/branches/users/glyph/more-deferreds-7/txdav/carddav/datastore/test/test_index_file.py:6369
/CalendarServer/branches/users/glyph/new-export/txdav/carddav/datastore/test/test_index_file.py:7444-7485
/CalendarServer/branches/users/glyph/oracle-nulls/txdav/carddav/datastore/test/test_index_file.py:7340-7351
/CalendarServer/branches/users/glyph/oracle/txdav/carddav/datastore/test/test_index_file.py:7106-7155
/CalendarServer/branches/users/glyph/sendfdport/txdav/carddav/datastore/test/test_index_file.py:5388-5424
/CalendarServer/branches/users/glyph/sharedpool/txdav/carddav/datastore/test/test_index_file.py:6490-6550
/CalendarServer/branches/users/glyph/sql-store/txdav/carddav/datastore/test/test_index_file.py:5929-6073
/CalendarServer/branches/users/glyph/subtransactions/txdav/carddav/datastore/test/test_index_file.py:7248-7258
/CalendarServer/branches/users/glyph/use-system-twisted/txdav/carddav/datastore/test/test_index_file.py:5084-5149
/CalendarServer/branches/users/sagen/applepush/txdav/carddav/datastore/test/test_index_file.py:8126-8184
/CalendarServer/branches/users/sagen/inboxitems/txdav/carddav/datastore/test/test_index_file.py:7380-7381
/CalendarServer/branches/users/sagen/locations-resources-2/txdav/carddav/datastore/test/test_index_file.py:5052-5061
/CalendarServer/branches/users/sagen/locations-resources/txdav/carddav/datastore/test/test_index_file.py:5032-5051
/CalendarServer/branches/users/sagen/purge_old_events/txdav/carddav/datastore/test/test_index_file.py:6735-6746
/CalendarServer/branches/users/sagen/resource-delegates-4038/txdav/carddav/datastore/test/test_index_file.py:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066/txdav/carddav/datastore/test/test_index_file.py:4068-4075
/CalendarServer/branches/users/sagen/resources-2/txdav/carddav/datastore/test/test_index_file.py:5084-5093
/CalendarServer/branches/users/wsanchez/transations/txdav/carddav/datastore/test/test_index_file.py:5515-5593
/CalendarServer/trunk/twistedcaldav/test/test_vcardindex.py:6322-6394
   + /CalendarServer/branches/config-separation/txdav/carddav/datastore/test/test_index_file.py:4379-4443
/CalendarServer/branches/egg-info-351/txdav/carddav/datastore/test/test_index_file.py:4589-4625
/CalendarServer/branches/generic-sqlstore/txdav/carddav/datastore/test/test_index_file.py:6167-6191
/CalendarServer/branches/new-store-no-caldavfile-2/txdav/carddav/datastore/test/test_index_file.py:5936-5981
/CalendarServer/branches/new-store-no-caldavfile/txdav/carddav/datastore/test/test_index_file.py:5911-5935
/CalendarServer/branches/new-store/txdav/carddav/datastore/test/test_index_file.py:5594-5934
/CalendarServer/branches/users/cdaboo/batchupload-6699/txdav/carddav/datastore/test/test_index_file.py:6700-7198
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692/txdav/carddav/datastore/test/test_index_file.py:5693-5702
/CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/carddav/datastore/test/test_index_file.py:8130-8346
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627/txdav/carddav/datastore/test/test_index_file.py:3628-3644
/CalendarServer/branches/users/cdaboo/more-sharing-5591/txdav/carddav/datastore/test/test_index_file.py:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464/txdav/carddav/datastore/test/test_index_file.py:4465-4957
/CalendarServer/branches/users/cdaboo/pods/txdav/carddav/datastore/test/test_index_file.py:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar/txdav/carddav/datastore/test/test_index_file.py:7085-7206
/CalendarServer/branches/users/cdaboo/pycard/txdav/carddav/datastore/test/test_index_file.py:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes/txdav/carddav/datastore/test/test_index_file.py:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070/txdav/carddav/datastore/test/test_index_file.py:5071-5105
/CalendarServer/branches/users/cdaboo/shared-calendars-5187/txdav/carddav/datastore/test/test_index_file.py:5188-5440
/CalendarServer/branches/users/cdaboo/timezones/txdav/carddav/datastore/test/test_index_file.py:7443-7699
/CalendarServer/branches/users/glyph/conn-limit/txdav/carddav/datastore/test/test_index_file.py:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge/txdav/carddav/datastore/test/test_index_file.py:4971-5080
/CalendarServer/branches/users/glyph/dalify/txdav/carddav/datastore/test/test_index_file.py:6932-7023
/CalendarServer/branches/users/glyph/deploybuild/txdav/carddav/datastore/test/test_index_file.py:7563-7572
/CalendarServer/branches/users/glyph/dont-start-postgres/txdav/carddav/datastore/test/test_index_file.py:6592-6614
/CalendarServer/branches/users/glyph/linux-tests/txdav/carddav/datastore/test/test_index_file.py:6893-6900
/CalendarServer/branches/users/glyph/misc-portability-fixes/txdav/carddav/datastore/test/test_index_file.py:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6/txdav/carddav/datastore/test/test_index_file.py:6322-6334
/CalendarServer/branches/users/glyph/more-deferreds-7/txdav/carddav/datastore/test/test_index_file.py:6369
/CalendarServer/branches/users/glyph/new-export/txdav/carddav/datastore/test/test_index_file.py:7444-7485
/CalendarServer/branches/users/glyph/oracle-nulls/txdav/carddav/datastore/test/test_index_file.py:7340-7351
/CalendarServer/branches/users/glyph/oracle/txdav/carddav/datastore/test/test_index_file.py:7106-7155
/CalendarServer/branches/users/glyph/sendfdport/txdav/carddav/datastore/test/test_index_file.py:5388-5424
/CalendarServer/branches/users/glyph/sharedpool/txdav/carddav/datastore/test/test_index_file.py:6490-6550
/CalendarServer/branches/users/glyph/sql-store/txdav/carddav/datastore/test/test_index_file.py:5929-6073
/CalendarServer/branches/users/glyph/subtransactions/txdav/carddav/datastore/test/test_index_file.py:7248-7258
/CalendarServer/branches/users/glyph/use-system-twisted/txdav/carddav/datastore/test/test_index_file.py:5084-5149
/CalendarServer/branches/users/sagen/applepush/txdav/carddav/datastore/test/test_index_file.py:8126-8184
/CalendarServer/branches/users/sagen/inboxitems/txdav/carddav/datastore/test/test_index_file.py:7380-7381
/CalendarServer/branches/users/sagen/locations-resources-2/txdav/carddav/datastore/test/test_index_file.py:5052-5061
/CalendarServer/branches/users/sagen/locations-resources/txdav/carddav/datastore/test/test_index_file.py:5032-5051
/CalendarServer/branches/users/sagen/purge_old_events/txdav/carddav/datastore/test/test_index_file.py:6735-6746
/CalendarServer/branches/users/sagen/resource-delegates-4038/txdav/carddav/datastore/test/test_index_file.py:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066/txdav/carddav/datastore/test/test_index_file.py:4068-4075
/CalendarServer/branches/users/sagen/resources-2/txdav/carddav/datastore/test/test_index_file.py:5084-5093
/CalendarServer/branches/users/wsanchez/transations/txdav/carddav/datastore/test/test_index_file.py:5515-5593
/CalendarServer/trunk/twistedcaldav/test/test_vcardindex.py:6322-6394

Modified: CalendarServer/trunk/txdav/carddav/datastore/test/test_sql.py
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/test/test_sql.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/test_sql.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -201,6 +201,28 @@
         self.assertPropertiesSimilar(fromHome, toHome, builtinProperties)
 
 
+    def test_addressBookHomeVersion(self):
+        """
+        The DATAVERSION column for new calendar homes must match the
+        ADDRESSBOOK-DATAVERSION value.
+        """
+        
+        home = yield self.transactionUnderTest().addressbookHomeWithUID("home_version")
+        self.assertTrue(home is not None)
+        yield self.transactionUnderTest().commit
+        
+        txn = yield self.transactionUnderTest()
+        version = yield txn.calendarserverValue("ADDRESSBOOK-DATAVERSION")[0][0]
+        ch = schema.ADDRESSBOOK_HOME
+        homeVersion = yield Select(
+            [ch.DATAVERSION,],
+            From=ch,
+            Where=ch.OWNER_UID == "home_version",
+        ).on(txn)[0][0]
+        self.assertEqual(int(homeVersion, version))
+        
+        
+
     def test_eachAddressbookHome(self):
         """
         L{IAddressbookStore.eachAddressbookHome} is currently stubbed out by

Modified: CalendarServer/trunk/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/txdav/common/datastore/sql.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -272,23 +272,20 @@
 
 
     @classproperty
-    def _schemaVersion(cls): #@NoSelf
+    def _calendarserver(cls): #@NoSelf
         cs = schema.CALENDARSERVER
         return Select(
             [cs.VALUE,],
             From=cs,
-            Where=cs.NAME == "VERSION",
+            Where=cs.NAME == Parameter('name'),
         )
 
     @inlineCallbacks
-    def schemaVersion(self):
-        result = yield self._schemaVersion.on(self)
+    def calendarserverValue(self, key):
+        result = yield self._calendarserver.on(self, name=key)
         if result and len(result) == 1:
-            try:
-                returnValue(int(result[0][0]))
-            except ValueError:
-                pass
-        raise RuntimeError("Database schema version cannot be determined.")
+            returnValue(result[0][0])
+        raise RuntimeError("Database key %s cannot be determined." % (key,))
         
 
     @memoizedKey('uid', '_calendarHomes')
@@ -701,6 +698,9 @@
     _revisionsTable = None
     _notificationRevisionsTable = NOTIFICATION_OBJECT_REVISIONS_TABLE
     
+    _dataVersionKey = None
+    _dataVersionValue = None
+    
     _cacher = None  # Initialize in derived classes
 
     def __init__(self, transaction, ownerUID, notifiers):
@@ -783,9 +783,14 @@
             savepoint = SavepointAction("homeWithUID")
             yield savepoint.acquire(txn)
 
+            if cls._dataVersionValue is None:
+                cls._dataVersionValue = yield txn.calendarserverValue(cls._dataVersionKey)
             try:
                 resourceid = (yield Insert(
-                    {cls._homeSchema.OWNER_UID: uid},
+                    {
+                        cls._homeSchema.OWNER_UID: uid,
+                        cls._homeSchema.DATAVERSION: cls._dataVersionValue,
+                    },
                     Return=cls._homeSchema.RESOURCE_ID).on(txn))[0][0]
                 yield Insert(
                     {cls._homeMetaDataSchema.RESOURCE_ID: resourceid}).on(txn)
@@ -1264,6 +1269,10 @@
                       Where=rev.RESOURCE_ID == Parameter("resourceID"))
 
 
+    def revisionFromToken(self, token):
+        _ignore_uuid, revision = token.split("_", 1)
+        return int(revision)
+
     @inlineCallbacks
     def syncToken(self):
         if self._syncTokenRevision is None:
@@ -1290,6 +1299,12 @@
 
     @inlineCallbacks
     def resourceNamesSinceToken(self, token):
+        
+        if token is None:
+            token = 0
+        elif isinstance(token, str):
+            token = self.revisionFromToken(token)
+
         results = [
             (name if name else "", deleted)
             for name, deleted in
@@ -1589,6 +1604,36 @@
                                  bind.BIND_MODE == _BIND_MODE_OWN))
 
 
+    @classmethod
+    def metadataColumns(cls):
+        """
+        Return a list of column name for retrieval of metadata. This allows
+        different child classes to have their own type specific data, but still make use of the
+        common base logic.
+        """
+        
+        # Common behavior is to have created and modified
+        
+        return (
+            cls._homeChildSchema.CREATED,
+            cls._homeChildSchema.MODIFIED,
+        )
+        
+    @classmethod
+    def metadataAttributes(cls):
+        """
+        Return a list of attribute names for retrieval of metadata. This allows
+        different child classes to have their own type specific data, but still make use of the
+        common base logic.
+        """
+        
+        # Common behavior is to have created and modified
+        
+        return (
+            "_created",
+            "_modified",
+        )
+        
     @classproperty
     def _sharedChildListQuery(cls): #@NoSelf
         bind = cls._bindSchema
@@ -1598,7 +1643,6 @@
                                  bind.BIND_MODE != _BIND_MODE_OWN).And(
                                  bind.RESOURCE_NAME != None))
 
-
     @classmethod
     @inlineCallbacks
     def listObjects(cls, home, owned):
@@ -1627,10 +1671,10 @@
         else:
             ownedPiece = (bind.BIND_MODE != _BIND_MODE_OWN).And(
                 bind.RESOURCE_NAME != None)
-        return Select([child.RESOURCE_ID,
-                       bind.RESOURCE_NAME,
-                       child.CREATED,
-                       child.MODIFIED],
+        
+        columns = [child.RESOURCE_ID, bind.RESOURCE_NAME,]
+        columns.extend(cls.metadataColumns())
+        return Select(columns,
                      From=child.join(
                          bind, child.RESOURCE_ID == bind.RESOURCE_ID,
                          'left outer'),
@@ -1691,10 +1735,12 @@
             revisions = dict(revisions)
 
         # Create the actual objects merging in properties
-        for resourceID, resource_name, created, modified in dataRows:
+        for items in dataRows:
+            resourceID, resource_name = items[:2]
+            metadata = items[2:]
             child = cls(home, resource_name, resourceID, owned)
-            child._created = created
-            child._modified = modified
+            for attr, value in zip(cls.metadataAttributes(), metadata):
+                setattr(child, attr, value)
             child._syncTokenRevision = revisions[resourceID]
             propstore = propertyStores.get(resourceID, None)
             yield child._loadPropertyStore(propstore)
@@ -1865,12 +1911,12 @@
 
 
     @classproperty
-    def _datesByIDQuery(cls): #@NoSelf
+    def _metadataByIDQuery(cls): #@NoSelf
         """
         DAL query to retrieve created/modified dates based on a resource ID.
         """
         child = cls._homeChildSchema
-        return Select([child.CREATED, child.MODIFIED],
+        return Select(cls.metadataColumns(),
                       From=child,
                       Where=child.RESOURCE_ID == Parameter("resourceID"))
 
@@ -1882,9 +1928,11 @@
         resource ID. We read in and cache all the extra metadata from the DB to
         avoid having to do DB queries for those individually later.
         """
-        self._created, self._modified = (
-            yield self._datesByIDQuery.on(self._txn,
+        dataRows = (
+            yield self._metadataByIDQuery.on(self._txn,
                                           resourceID=self._resourceID))[0]
+        for attr, value in zip(self.metadataAttributes(), dataRows):
+            setattr(self, attr, value)
         yield self._loadPropertyStore()
 
 
@@ -2201,7 +2249,62 @@
             yield self._deleteRevision(name)
             self.notifyChanged()
 
+    @classproperty
+    def _moveParentUpdateQuery(cls): #@NoSelf
+        """
+        DAL query to update a child to be in a new parent.
+        """
+        obj = cls._objectSchema
+        return Update(
+            {obj.PARENT_RESOURCE_ID: Parameter("newParentID")},
+            Where=obj.RESOURCE_ID == Parameter("resourceID")
+        )
 
+    def _movedObjectResource(self, child, newparent):
+        """
+        Method that subclasses can override to do an extra DB adjustments when a resource
+        is moved.
+        """
+        return succeed(True)
+
+    @inlineCallbacks
+    def moveObjectResource(self, child, newparent):
+        """
+        Move a child of this collection into another collection without actually removing/re-inserting the data.
+        Make sure sync and cache details for both collections are updated.
+        
+        TODO: check that the resource name does not exist in the new parent, or that the UID
+        does not exist there too.
+
+        @param child: the child resource to move
+        @type child: L{CommonObjectResource}
+        @param newparent: the parent to move to
+        @type newparent: L{CommonHomeChild}
+        """
+
+        name = child.name()
+        uid = child.uid()
+
+        # Clean this collections cache and signal sync change
+        self._objects.pop(name, None)
+        self._objects.pop(uid, None)
+        self._objects.pop(child._resourceID, None)
+        yield self._deleteRevision(name)
+        self.notifyChanged()
+        
+        # Adjust the child to be a child of the new parent and update ancillary tables
+        yield self._moveParentUpdateQuery.on(
+            self._txn,
+            newParentID=newparent._resourceID,
+            resourceID=child._resourceID
+        )
+        yield self._movedObjectResource(child, newparent)
+        child._parentCollection = newparent
+
+        # Signal sync change on new collection
+        yield newparent._insertRevision(name)
+        newparent.notifyChanged()
+
     def objectResourcesHaveProperties(self):
         return False
 

Modified: CalendarServer/trunk/txdav/common/datastore/sql_schema/current.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/current.sql	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/current.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -29,7 +29,8 @@
 
 create table CALENDAR_HOME (
   RESOURCE_ID      integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
-  OWNER_UID        varchar(255) not null unique                                 -- implicit index
+  OWNER_UID        varchar(255) not null unique,                                 -- implicit index
+  DATAVERSION	   integer      default 0 not null
 );
 
 ----------------------------
@@ -47,8 +48,9 @@
 
 create table CALENDAR (
   RESOURCE_ID integer   primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
-  CREATED     timestamp default timezone('UTC', CURRENT_TIMESTAMP),
-  MODIFIED    timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+  SUPPORTED_COMPONENTS  varchar(255) default null,
+  CREATED               timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED              timestamp default timezone('UTC', CURRENT_TIMESTAMP)
 );
 
 
@@ -312,7 +314,8 @@
 
 create table ADDRESSBOOK_HOME (
   RESOURCE_ID      integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
-  OWNER_UID        varchar(255) not null unique                                 -- implicit index
+  OWNER_UID        varchar(255) not null unique,                                -- implicit index
+  DATAVERSION	   integer      default 0 not null
 );
 
 --------------------------------
@@ -460,5 +463,6 @@
   VALUE                         varchar(255)
 );
 
-insert into CALENDARSERVER values ('VERSION', '6');
-
+insert into CALENDARSERVER values ('VERSION', '7');
+insert into CALENDARSERVER values ('CALENDAR-DATAVERSION', '2');
+insert into CALENDARSERVER values ('ADDRESSBOOK-DATAVERSION', '1');

Deleted: CalendarServer/trunk/txdav/common/datastore/sql_schema/old/v5.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/old/v5.sql	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/old/v5.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,448 +0,0 @@
--- -*- test-case-name: txdav.caldav.datastore.test.test_sql,txdav.carddav.datastore.test.test_sql -*-
-
-----
--- Copyright (c) 2010-2011 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.
-----
-
------------------
--- Resource ID --
------------------
-
-create sequence RESOURCE_ID_SEQ;
-
-
--------------------
--- Calendar Home --
--------------------
-
-create table CALENDAR_HOME (
-  RESOURCE_ID      integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
-  OWNER_UID        varchar(255) not null unique                                 -- implicit index
-);
-
-----------------------------
--- Calendar Home Metadata --
-----------------------------
-
-create table CALENDAR_HOME_METADATA (
-  RESOURCE_ID      integer      primary key references CALENDAR_HOME on delete cascade, -- implicit index
-  QUOTA_USED_BYTES integer      default 0 not null
-);
-
---------------
--- Calendar --
---------------
-
-create table CALENDAR (
-  RESOURCE_ID integer   primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
-  CREATED     timestamp default timezone('UTC', CURRENT_TIMESTAMP),
-  MODIFIED    timestamp default timezone('UTC', CURRENT_TIMESTAMP)
-);
-
-
-------------------------
--- Sharing Invitation --
-------------------------
-
-create table INVITE (
-    INVITE_UID         varchar(255) not null,
-    NAME               varchar(255) not null,
-    RECIPIENT_ADDRESS  varchar(255) not null,
-    HOME_RESOURCE_ID   integer      not null,
-    RESOURCE_ID        integer      not null
-    
-    -- Need primary key on (INVITE_UID, NAME, RECIPIENT_ADDRESS)?
-);
-
-create index INVITE_INVITE_UID on INVITE(INVITE_UID);
-create index INVITE_RESOURCE_ID on INVITE(RESOURCE_ID);
-create index INVITE_HOME_RESOURCE_ID on INVITE(HOME_RESOURCE_ID);
-
----------------------------
--- Sharing Notifications --
----------------------------
-
-create table NOTIFICATION_HOME (
-  RESOURCE_ID integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
-  OWNER_UID   varchar(255) not null unique                                 -- implicit index
-);
-
-create table NOTIFICATION (
-  RESOURCE_ID                   integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
-  NOTIFICATION_HOME_RESOURCE_ID integer      not null references NOTIFICATION_HOME,
-  NOTIFICATION_UID              varchar(255) not null,
-  XML_TYPE                      varchar(255) not null,
-  XML_DATA                      text         not null,
-  MD5                           char(32)     not null,
-  CREATED                       timestamp default timezone('UTC', CURRENT_TIMESTAMP),
-  MODIFIED                      timestamp default timezone('UTC', CURRENT_TIMESTAMP),
-
-  unique(NOTIFICATION_UID, NOTIFICATION_HOME_RESOURCE_ID) -- implicit index
-);
-
-create index NOTIFICATION_NOTIFICATION_HOME_RESOURCE_ID on
-  NOTIFICATION(NOTIFICATION_HOME_RESOURCE_ID);
-
--------------------
--- Calendar Bind --
--------------------
-
--- Joins CALENDAR_HOME and CALENDAR
-
-create table CALENDAR_BIND (
-  CALENDAR_HOME_RESOURCE_ID integer      not null references CALENDAR_HOME,
-  CALENDAR_RESOURCE_ID      integer      not null references CALENDAR on delete cascade,
-  
-  -- An invitation which hasn't been accepted yet will not yet have a resource
-  -- name, so this field may be null.
-  
-  CALENDAR_RESOURCE_NAME    varchar(255),
-  BIND_MODE                 integer      not null, -- enum CALENDAR_BIND_MODE
-  BIND_STATUS               integer      not null, -- enum CALENDAR_BIND_STATUS
-  SEEN_BY_OWNER             boolean      not null,
-  SEEN_BY_SHAREE            boolean      not null,
-  MESSAGE                   text,
-
-  primary key(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID), -- implicit index
-  unique(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_NAME)     -- implicit index
-);
-
-create index CALENDAR_BIND_RESOURCE_ID on CALENDAR_BIND(CALENDAR_RESOURCE_ID);
-
--- Enumeration of calendar bind modes
-
-create table CALENDAR_BIND_MODE (
-  ID          integer     primary key,
-  DESCRIPTION varchar(16) not null unique
-);
-
-insert into CALENDAR_BIND_MODE values (0, 'own'  );
-insert into CALENDAR_BIND_MODE values (1, 'read' );
-insert into CALENDAR_BIND_MODE values (2, 'write');
-insert into CALENDAR_BIND_MODE values (3, 'direct');
-
--- Enumeration of statuses
-
-create table CALENDAR_BIND_STATUS (
-  ID          integer     primary key,
-  DESCRIPTION varchar(16) not null unique
-);
-
-insert into CALENDAR_BIND_STATUS values (0, 'invited' );
-insert into CALENDAR_BIND_STATUS values (1, 'accepted');
-insert into CALENDAR_BIND_STATUS values (2, 'declined');
-insert into CALENDAR_BIND_STATUS values (3, 'invalid');
-
-
----------------------
--- Calendar Object --
----------------------
-
-create table CALENDAR_OBJECT (
-  RESOURCE_ID          integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
-  CALENDAR_RESOURCE_ID integer      not null references CALENDAR on delete cascade,
-  RESOURCE_NAME        varchar(255) not null,
-  ICALENDAR_TEXT       text         not null,
-  ICALENDAR_UID        varchar(255) not null,
-  ICALENDAR_TYPE       varchar(255) not null,
-  ATTACHMENTS_MODE     integer      default 0 not null, -- enum CALENDAR_OBJECT_ATTACHMENTS_MODE
-  DROPBOX_ID           varchar(255),
-  ORGANIZER            varchar(255),
-  ORGANIZER_OBJECT     integer      references CALENDAR_OBJECT,
-  RECURRANCE_MAX       date,        -- maximum date that recurrences have been expanded to.
-  ACCESS               integer      default 0 not null,
-  SCHEDULE_OBJECT      boolean      default false,
-  SCHEDULE_TAG         varchar(36)  default null,
-  SCHEDULE_ETAGS       text         default null,
-  PRIVATE_COMMENTS     boolean      default false not null,
-  MD5                  char(32)     not null,
-  CREATED              timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
-  MODIFIED             timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
-
-  unique(CALENDAR_RESOURCE_ID, RESOURCE_NAME) -- implicit index
-
-  -- since the 'inbox' is a 'calendar resource' for the purpose of storing
-  -- calendar objects, this constraint has to be selectively enforced by the
-  -- application layer.
-
-  -- unique(CALENDAR_RESOURCE_ID, ICALENDAR_UID)
-);
-
-create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_AND_ICALENDAR_UID on
-  CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, ICALENDAR_UID);
- 
-create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_RECURRANCE_MAX on
-  CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, RECURRANCE_MAX);
-
-create index CALENDAR_OBJECT_ORGANIZER_OBJECT on
-  CALENDAR_OBJECT(ORGANIZER_OBJECT);
-
-create index CALENDAR_OBJECT_DROPBOX_ID on
-  CALENDAR_OBJECT(DROPBOX_ID);
-
--- Enumeration of attachment modes
-
-create table CALENDAR_OBJECT_ATTACHMENTS_MODE (
-  ID          integer     primary key,
-  DESCRIPTION varchar(16) not null unique
-);
-
-insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (0, 'none' );
-insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (1, 'read' );
-insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (2, 'write');
-
-
--- Enumeration of calendar access types
-
-create table CALENDAR_ACCESS_TYPE (
-  ID          integer     primary key,
-  DESCRIPTION varchar(32) not null unique
-);
-
-insert into CALENDAR_ACCESS_TYPE values (0, ''             );
-insert into CALENDAR_ACCESS_TYPE values (1, 'public'       );
-insert into CALENDAR_ACCESS_TYPE values (2, 'private'      );
-insert into CALENDAR_ACCESS_TYPE values (3, 'confidential' );
-insert into CALENDAR_ACCESS_TYPE values (4, 'restricted'   );
-
------------------
--- Instance ID --
------------------
-
-create sequence INSTANCE_ID_SEQ;
-
-
-----------------
--- Time Range --
-----------------
-
-create table TIME_RANGE (
-  INSTANCE_ID                 integer        primary key default nextval('INSTANCE_ID_SEQ'), -- implicit index
-  CALENDAR_RESOURCE_ID        integer        not null references CALENDAR on delete cascade,
-  CALENDAR_OBJECT_RESOURCE_ID integer        not null references CALENDAR_OBJECT on delete cascade,
-  FLOATING                    boolean        not null,
-  START_DATE                  timestamp      not null,
-  END_DATE                    timestamp      not null,
-  FBTYPE                      integer        not null,
-  TRANSPARENT                 boolean        not null
-);
-
-create index TIME_RANGE_CALENDAR_RESOURCE_ID on
-  TIME_RANGE(CALENDAR_RESOURCE_ID);
-create index TIME_RANGE_CALENDAR_OBJECT_RESOURCE_ID on
-  TIME_RANGE(CALENDAR_OBJECT_RESOURCE_ID);
-
-
--- Enumeration of free/busy types
-
-create table FREE_BUSY_TYPE (
-  ID          integer     primary key,
-  DESCRIPTION varchar(16) not null unique
-);
-
-insert into FREE_BUSY_TYPE values (0, 'unknown'         );
-insert into FREE_BUSY_TYPE values (1, 'free'            );
-insert into FREE_BUSY_TYPE values (2, 'busy'            );
-insert into FREE_BUSY_TYPE values (3, 'busy-unavailable');
-insert into FREE_BUSY_TYPE values (4, 'busy-tentative'  );
-
-
-------------------
--- Transparency --
-------------------
-
-create table TRANSPARENCY (
-  TIME_RANGE_INSTANCE_ID      integer      not null references TIME_RANGE on delete cascade,
-  USER_ID                     varchar(255) not null,
-  TRANSPARENT                 boolean      not null
-);
-
-create index TRANSPARENCY_TIME_RANGE_INSTANCE_ID on
-  TRANSPARENCY(TIME_RANGE_INSTANCE_ID);
-
-----------------
--- Attachment --
-----------------
-
-create table ATTACHMENT (
-  CALENDAR_HOME_RESOURCE_ID   integer       not null references CALENDAR_HOME,
-  DROPBOX_ID                  varchar(255)  not null,
-  CONTENT_TYPE                varchar(255)  not null,
-  SIZE                        integer       not null,
-  MD5                         char(32)      not null,
-  CREATED                     timestamp default timezone('UTC', CURRENT_TIMESTAMP),
-  MODIFIED                    timestamp default timezone('UTC', CURRENT_TIMESTAMP),
-  PATH                        varchar(1024) not null,
-
-  primary key(DROPBOX_ID, PATH) --implicit index
-);
-
-create index ATTACHMENT_CALENDAR_HOME_RESOURCE_ID on
-  ATTACHMENT(CALENDAR_HOME_RESOURCE_ID);
-
------------------------
--- Resource Property --
------------------------
-
-create table RESOURCE_PROPERTY (
-  RESOURCE_ID integer      not null, -- foreign key: *.RESOURCE_ID
-  NAME        varchar(255) not null,
-  VALUE       text         not null, -- FIXME: xml?
-  VIEWER_UID  varchar(255),
-
-  primary key(RESOURCE_ID, NAME, VIEWER_UID) -- implicit index
-);
-
-
-----------------------
--- AddressBook Home --
-----------------------
-
-create table ADDRESSBOOK_HOME (
-  RESOURCE_ID      integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
-  OWNER_UID        varchar(255) not null unique                                 -- implicit index
-);
-
---------------------------------
--- AddressBook Home Meta-data --
---------------------------------
-
-create table ADDRESSBOOK_HOME_METADATA (
-  RESOURCE_ID      integer      primary key references ADDRESSBOOK_HOME on delete cascade, -- implicit index
-  QUOTA_USED_BYTES integer      default 0 not null
-);
-
------------------
--- AddressBook --
------------------
-
-create table ADDRESSBOOK (
-  RESOURCE_ID integer   primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
-  CREATED     timestamp default timezone('UTC', CURRENT_TIMESTAMP),
-  MODIFIED    timestamp default timezone('UTC', CURRENT_TIMESTAMP)
-);
-
-
-----------------------
--- AddressBook Bind --
-----------------------
-
--- Joins ADDRESSBOOK_HOME and ADDRESSBOOK
-
-create table ADDRESSBOOK_BIND (
-  ADDRESSBOOK_HOME_RESOURCE_ID integer      not null references ADDRESSBOOK_HOME,
-  ADDRESSBOOK_RESOURCE_ID      integer      not null references ADDRESSBOOK on delete cascade,
-
-  -- An invitation which hasn't been accepted yet will not yet have a resource
-  -- name, so this field may be null.
-
-  ADDRESSBOOK_RESOURCE_NAME    varchar(255),
-  BIND_MODE                    integer      not null, -- enum CALENDAR_BIND_MODE
-  BIND_STATUS                  integer      not null, -- enum CALENDAR_BIND_STATUS
-  SEEN_BY_OWNER                boolean      not null,
-  SEEN_BY_SHAREE               boolean      not null,
-  MESSAGE                      text,                  -- FIXME: xml?
-
-  primary key(ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_ID), -- implicit index
-  unique(ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_NAME)     -- implicit index
-);
-
-create index ADDRESSBOOK_BIND_RESOURCE_ID on
-  ADDRESSBOOK_BIND(ADDRESSBOOK_RESOURCE_ID);
-
-create table ADDRESSBOOK_OBJECT (
-  RESOURCE_ID             integer      primary key default nextval('RESOURCE_ID_SEQ'),    -- implicit index
-  ADDRESSBOOK_RESOURCE_ID integer      not null references ADDRESSBOOK on delete cascade,
-  RESOURCE_NAME           varchar(255) not null,
-  VCARD_TEXT              text         not null,
-  VCARD_UID               varchar(255) not null,
-  MD5                     char(32)     not null,
-  CREATED                 timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
-  MODIFIED                timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
-
-  unique(ADDRESSBOOK_RESOURCE_ID, RESOURCE_NAME), -- implicit index
-  unique(ADDRESSBOOK_RESOURCE_ID, VCARD_UID)      -- implicit index
-);
-
----------------
--- Revisions --
----------------
-
-create sequence REVISION_SEQ;
-
-
----------------
--- Revisions --
----------------
-
-create table CALENDAR_OBJECT_REVISIONS (
-  CALENDAR_HOME_RESOURCE_ID integer      not null references CALENDAR_HOME,
-  CALENDAR_RESOURCE_ID      integer      references CALENDAR,
-  CALENDAR_NAME             varchar(255) default null,
-  RESOURCE_NAME             varchar(255),
-  REVISION                  integer      default nextval('REVISION_SEQ') not null,
-  DELETED                   boolean      not null
-);
-
-create index CALENDAR_OBJECT_REVISIONS_HOME_RESOURCE_ID
-  on CALENDAR_OBJECT_REVISIONS(CALENDAR_HOME_RESOURCE_ID);
-
-create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME
-  on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, RESOURCE_NAME);
-
--------------------------------
--- AddressBook Object Revisions --
--------------------------------
-
-create table ADDRESSBOOK_OBJECT_REVISIONS (
-  ADDRESSBOOK_HOME_RESOURCE_ID integer      not null references ADDRESSBOOK_HOME,
-  ADDRESSBOOK_RESOURCE_ID      integer      references ADDRESSBOOK,
-  ADDRESSBOOK_NAME             varchar(255) default null,
-  RESOURCE_NAME                varchar(255),
-  REVISION                     integer      default nextval('REVISION_SEQ') not null,
-  DELETED                      boolean      not null
-);
-
-create index ADDRESSBOOK_OBJECT_REVISIONS_HOME_RESOURCE_ID
-  on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_HOME_RESOURCE_ID);
-
-create index ADDRESSBOOK_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME
-  on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_RESOURCE_ID, RESOURCE_NAME);
-
------------------------------------
--- Notification Object Revisions --
------------------------------------
-
-create table NOTIFICATION_OBJECT_REVISIONS (
-  NOTIFICATION_HOME_RESOURCE_ID integer      not null references NOTIFICATION_HOME on delete cascade,
-  RESOURCE_NAME                 varchar(255),
-  REVISION                      integer      default nextval('REVISION_SEQ') not null,
-  DELETED                       boolean      not null,
-
-  unique(NOTIFICATION_HOME_RESOURCE_ID, RESOURCE_NAME) -- implicit index
-);
-
-
---------------------
--- Schema Version --
---------------------
-
-create table CALENDARSERVER (
-  NAME                          varchar(255) primary key, -- implicit index
-  VALUE                         varchar(255)
-);
-
-insert into CALENDARSERVER values ('VERSION', '5');
-

Copied: CalendarServer/trunk/txdav/common/datastore/sql_schema/old/v5.sql (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/sql_schema/old/v5.sql)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/old/v5.sql	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/old/v5.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,448 @@
+-- -*- test-case-name: txdav.caldav.datastore.test.test_sql,txdav.carddav.datastore.test.test_sql -*-
+
+----
+-- Copyright (c) 2010-2011 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.
+----
+
+-----------------
+-- Resource ID --
+-----------------
+
+create sequence RESOURCE_ID_SEQ;
+
+
+-------------------
+-- Calendar Home --
+-------------------
+
+create table CALENDAR_HOME (
+  RESOURCE_ID      integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  OWNER_UID        varchar(255) not null unique                                 -- implicit index
+);
+
+----------------------------
+-- Calendar Home Metadata --
+----------------------------
+
+create table CALENDAR_HOME_METADATA (
+  RESOURCE_ID      integer      primary key references CALENDAR_HOME on delete cascade, -- implicit index
+  QUOTA_USED_BYTES integer      default 0 not null
+);
+
+--------------
+-- Calendar --
+--------------
+
+create table CALENDAR (
+  RESOURCE_ID integer   primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  CREATED     timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED    timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+------------------------
+-- Sharing Invitation --
+------------------------
+
+create table INVITE (
+    INVITE_UID         varchar(255) not null,
+    NAME               varchar(255) not null,
+    RECIPIENT_ADDRESS  varchar(255) not null,
+    HOME_RESOURCE_ID   integer      not null,
+    RESOURCE_ID        integer      not null
+    
+    -- Need primary key on (INVITE_UID, NAME, RECIPIENT_ADDRESS)?
+);
+
+create index INVITE_INVITE_UID on INVITE(INVITE_UID);
+create index INVITE_RESOURCE_ID on INVITE(RESOURCE_ID);
+create index INVITE_HOME_RESOURCE_ID on INVITE(HOME_RESOURCE_ID);
+
+---------------------------
+-- Sharing Notifications --
+---------------------------
+
+create table NOTIFICATION_HOME (
+  RESOURCE_ID integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  OWNER_UID   varchar(255) not null unique                                 -- implicit index
+);
+
+create table NOTIFICATION (
+  RESOURCE_ID                   integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  NOTIFICATION_HOME_RESOURCE_ID integer      not null references NOTIFICATION_HOME,
+  NOTIFICATION_UID              varchar(255) not null,
+  XML_TYPE                      varchar(255) not null,
+  XML_DATA                      text         not null,
+  MD5                           char(32)     not null,
+  CREATED                       timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED                      timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+
+  unique(NOTIFICATION_UID, NOTIFICATION_HOME_RESOURCE_ID) -- implicit index
+);
+
+create index NOTIFICATION_NOTIFICATION_HOME_RESOURCE_ID on
+  NOTIFICATION(NOTIFICATION_HOME_RESOURCE_ID);
+
+-------------------
+-- Calendar Bind --
+-------------------
+
+-- Joins CALENDAR_HOME and CALENDAR
+
+create table CALENDAR_BIND (
+  CALENDAR_HOME_RESOURCE_ID integer      not null references CALENDAR_HOME,
+  CALENDAR_RESOURCE_ID      integer      not null references CALENDAR on delete cascade,
+  
+  -- An invitation which hasn't been accepted yet will not yet have a resource
+  -- name, so this field may be null.
+  
+  CALENDAR_RESOURCE_NAME    varchar(255),
+  BIND_MODE                 integer      not null, -- enum CALENDAR_BIND_MODE
+  BIND_STATUS               integer      not null, -- enum CALENDAR_BIND_STATUS
+  SEEN_BY_OWNER             boolean      not null,
+  SEEN_BY_SHAREE            boolean      not null,
+  MESSAGE                   text,
+
+  primary key(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID), -- implicit index
+  unique(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_NAME)     -- implicit index
+);
+
+create index CALENDAR_BIND_RESOURCE_ID on CALENDAR_BIND(CALENDAR_RESOURCE_ID);
+
+-- Enumeration of calendar bind modes
+
+create table CALENDAR_BIND_MODE (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_BIND_MODE values (0, 'own'  );
+insert into CALENDAR_BIND_MODE values (1, 'read' );
+insert into CALENDAR_BIND_MODE values (2, 'write');
+insert into CALENDAR_BIND_MODE values (3, 'direct');
+
+-- Enumeration of statuses
+
+create table CALENDAR_BIND_STATUS (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_BIND_STATUS values (0, 'invited' );
+insert into CALENDAR_BIND_STATUS values (1, 'accepted');
+insert into CALENDAR_BIND_STATUS values (2, 'declined');
+insert into CALENDAR_BIND_STATUS values (3, 'invalid');
+
+
+---------------------
+-- Calendar Object --
+---------------------
+
+create table CALENDAR_OBJECT (
+  RESOURCE_ID          integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  CALENDAR_RESOURCE_ID integer      not null references CALENDAR on delete cascade,
+  RESOURCE_NAME        varchar(255) not null,
+  ICALENDAR_TEXT       text         not null,
+  ICALENDAR_UID        varchar(255) not null,
+  ICALENDAR_TYPE       varchar(255) not null,
+  ATTACHMENTS_MODE     integer      default 0 not null, -- enum CALENDAR_OBJECT_ATTACHMENTS_MODE
+  DROPBOX_ID           varchar(255),
+  ORGANIZER            varchar(255),
+  ORGANIZER_OBJECT     integer      references CALENDAR_OBJECT,
+  RECURRANCE_MAX       date,        -- maximum date that recurrences have been expanded to.
+  ACCESS               integer      default 0 not null,
+  SCHEDULE_OBJECT      boolean      default false,
+  SCHEDULE_TAG         varchar(36)  default null,
+  SCHEDULE_ETAGS       text         default null,
+  PRIVATE_COMMENTS     boolean      default false not null,
+  MD5                  char(32)     not null,
+  CREATED              timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED             timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+
+  unique(CALENDAR_RESOURCE_ID, RESOURCE_NAME) -- implicit index
+
+  -- since the 'inbox' is a 'calendar resource' for the purpose of storing
+  -- calendar objects, this constraint has to be selectively enforced by the
+  -- application layer.
+
+  -- unique(CALENDAR_RESOURCE_ID, ICALENDAR_UID)
+);
+
+create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_AND_ICALENDAR_UID on
+  CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, ICALENDAR_UID);
+ 
+create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_RECURRANCE_MAX on
+  CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, RECURRANCE_MAX);
+
+create index CALENDAR_OBJECT_ORGANIZER_OBJECT on
+  CALENDAR_OBJECT(ORGANIZER_OBJECT);
+
+create index CALENDAR_OBJECT_DROPBOX_ID on
+  CALENDAR_OBJECT(DROPBOX_ID);
+
+-- Enumeration of attachment modes
+
+create table CALENDAR_OBJECT_ATTACHMENTS_MODE (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (0, 'none' );
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (1, 'read' );
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (2, 'write');
+
+
+-- Enumeration of calendar access types
+
+create table CALENDAR_ACCESS_TYPE (
+  ID          integer     primary key,
+  DESCRIPTION varchar(32) not null unique
+);
+
+insert into CALENDAR_ACCESS_TYPE values (0, ''             );
+insert into CALENDAR_ACCESS_TYPE values (1, 'public'       );
+insert into CALENDAR_ACCESS_TYPE values (2, 'private'      );
+insert into CALENDAR_ACCESS_TYPE values (3, 'confidential' );
+insert into CALENDAR_ACCESS_TYPE values (4, 'restricted'   );
+
+-----------------
+-- Instance ID --
+-----------------
+
+create sequence INSTANCE_ID_SEQ;
+
+
+----------------
+-- Time Range --
+----------------
+
+create table TIME_RANGE (
+  INSTANCE_ID                 integer        primary key default nextval('INSTANCE_ID_SEQ'), -- implicit index
+  CALENDAR_RESOURCE_ID        integer        not null references CALENDAR on delete cascade,
+  CALENDAR_OBJECT_RESOURCE_ID integer        not null references CALENDAR_OBJECT on delete cascade,
+  FLOATING                    boolean        not null,
+  START_DATE                  timestamp      not null,
+  END_DATE                    timestamp      not null,
+  FBTYPE                      integer        not null,
+  TRANSPARENT                 boolean        not null
+);
+
+create index TIME_RANGE_CALENDAR_RESOURCE_ID on
+  TIME_RANGE(CALENDAR_RESOURCE_ID);
+create index TIME_RANGE_CALENDAR_OBJECT_RESOURCE_ID on
+  TIME_RANGE(CALENDAR_OBJECT_RESOURCE_ID);
+
+
+-- Enumeration of free/busy types
+
+create table FREE_BUSY_TYPE (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into FREE_BUSY_TYPE values (0, 'unknown'         );
+insert into FREE_BUSY_TYPE values (1, 'free'            );
+insert into FREE_BUSY_TYPE values (2, 'busy'            );
+insert into FREE_BUSY_TYPE values (3, 'busy-unavailable');
+insert into FREE_BUSY_TYPE values (4, 'busy-tentative'  );
+
+
+------------------
+-- Transparency --
+------------------
+
+create table TRANSPARENCY (
+  TIME_RANGE_INSTANCE_ID      integer      not null references TIME_RANGE on delete cascade,
+  USER_ID                     varchar(255) not null,
+  TRANSPARENT                 boolean      not null
+);
+
+create index TRANSPARENCY_TIME_RANGE_INSTANCE_ID on
+  TRANSPARENCY(TIME_RANGE_INSTANCE_ID);
+
+----------------
+-- Attachment --
+----------------
+
+create table ATTACHMENT (
+  CALENDAR_HOME_RESOURCE_ID   integer       not null references CALENDAR_HOME,
+  DROPBOX_ID                  varchar(255)  not null,
+  CONTENT_TYPE                varchar(255)  not null,
+  SIZE                        integer       not null,
+  MD5                         char(32)      not null,
+  CREATED                     timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED                    timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+  PATH                        varchar(1024) not null,
+
+  primary key(DROPBOX_ID, PATH) --implicit index
+);
+
+create index ATTACHMENT_CALENDAR_HOME_RESOURCE_ID on
+  ATTACHMENT(CALENDAR_HOME_RESOURCE_ID);
+
+-----------------------
+-- Resource Property --
+-----------------------
+
+create table RESOURCE_PROPERTY (
+  RESOURCE_ID integer      not null, -- foreign key: *.RESOURCE_ID
+  NAME        varchar(255) not null,
+  VALUE       text         not null, -- FIXME: xml?
+  VIEWER_UID  varchar(255),
+
+  primary key(RESOURCE_ID, NAME, VIEWER_UID) -- implicit index
+);
+
+
+----------------------
+-- AddressBook Home --
+----------------------
+
+create table ADDRESSBOOK_HOME (
+  RESOURCE_ID      integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  OWNER_UID        varchar(255) not null unique                                 -- implicit index
+);
+
+--------------------------------
+-- AddressBook Home Meta-data --
+--------------------------------
+
+create table ADDRESSBOOK_HOME_METADATA (
+  RESOURCE_ID      integer      primary key references ADDRESSBOOK_HOME on delete cascade, -- implicit index
+  QUOTA_USED_BYTES integer      default 0 not null
+);
+
+-----------------
+-- AddressBook --
+-----------------
+
+create table ADDRESSBOOK (
+  RESOURCE_ID integer   primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  CREATED     timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED    timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+----------------------
+-- AddressBook Bind --
+----------------------
+
+-- Joins ADDRESSBOOK_HOME and ADDRESSBOOK
+
+create table ADDRESSBOOK_BIND (
+  ADDRESSBOOK_HOME_RESOURCE_ID integer      not null references ADDRESSBOOK_HOME,
+  ADDRESSBOOK_RESOURCE_ID      integer      not null references ADDRESSBOOK on delete cascade,
+
+  -- An invitation which hasn't been accepted yet will not yet have a resource
+  -- name, so this field may be null.
+
+  ADDRESSBOOK_RESOURCE_NAME    varchar(255),
+  BIND_MODE                    integer      not null, -- enum CALENDAR_BIND_MODE
+  BIND_STATUS                  integer      not null, -- enum CALENDAR_BIND_STATUS
+  SEEN_BY_OWNER                boolean      not null,
+  SEEN_BY_SHAREE               boolean      not null,
+  MESSAGE                      text,                  -- FIXME: xml?
+
+  primary key(ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_ID), -- implicit index
+  unique(ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_NAME)     -- implicit index
+);
+
+create index ADDRESSBOOK_BIND_RESOURCE_ID on
+  ADDRESSBOOK_BIND(ADDRESSBOOK_RESOURCE_ID);
+
+create table ADDRESSBOOK_OBJECT (
+  RESOURCE_ID             integer      primary key default nextval('RESOURCE_ID_SEQ'),    -- implicit index
+  ADDRESSBOOK_RESOURCE_ID integer      not null references ADDRESSBOOK on delete cascade,
+  RESOURCE_NAME           varchar(255) not null,
+  VCARD_TEXT              text         not null,
+  VCARD_UID               varchar(255) not null,
+  MD5                     char(32)     not null,
+  CREATED                 timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED                timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+
+  unique(ADDRESSBOOK_RESOURCE_ID, RESOURCE_NAME), -- implicit index
+  unique(ADDRESSBOOK_RESOURCE_ID, VCARD_UID)      -- implicit index
+);
+
+---------------
+-- Revisions --
+---------------
+
+create sequence REVISION_SEQ;
+
+
+---------------
+-- Revisions --
+---------------
+
+create table CALENDAR_OBJECT_REVISIONS (
+  CALENDAR_HOME_RESOURCE_ID integer      not null references CALENDAR_HOME,
+  CALENDAR_RESOURCE_ID      integer      references CALENDAR,
+  CALENDAR_NAME             varchar(255) default null,
+  RESOURCE_NAME             varchar(255),
+  REVISION                  integer      default nextval('REVISION_SEQ') not null,
+  DELETED                   boolean      not null
+);
+
+create index CALENDAR_OBJECT_REVISIONS_HOME_RESOURCE_ID
+  on CALENDAR_OBJECT_REVISIONS(CALENDAR_HOME_RESOURCE_ID);
+
+create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME
+  on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, RESOURCE_NAME);
+
+-------------------------------
+-- AddressBook Object Revisions --
+-------------------------------
+
+create table ADDRESSBOOK_OBJECT_REVISIONS (
+  ADDRESSBOOK_HOME_RESOURCE_ID integer      not null references ADDRESSBOOK_HOME,
+  ADDRESSBOOK_RESOURCE_ID      integer      references ADDRESSBOOK,
+  ADDRESSBOOK_NAME             varchar(255) default null,
+  RESOURCE_NAME                varchar(255),
+  REVISION                     integer      default nextval('REVISION_SEQ') not null,
+  DELETED                      boolean      not null
+);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_HOME_RESOURCE_ID
+  on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_HOME_RESOURCE_ID);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME
+  on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_RESOURCE_ID, RESOURCE_NAME);
+
+-----------------------------------
+-- Notification Object Revisions --
+-----------------------------------
+
+create table NOTIFICATION_OBJECT_REVISIONS (
+  NOTIFICATION_HOME_RESOURCE_ID integer      not null references NOTIFICATION_HOME on delete cascade,
+  RESOURCE_NAME                 varchar(255),
+  REVISION                      integer      default nextval('REVISION_SEQ') not null,
+  DELETED                       boolean      not null,
+
+  unique(NOTIFICATION_HOME_RESOURCE_ID, RESOURCE_NAME) -- implicit index
+);
+
+
+--------------------
+-- Schema Version --
+--------------------
+
+create table CALENDARSERVER (
+  NAME                          varchar(255) primary key, -- implicit index
+  VALUE                         varchar(255)
+);
+
+insert into CALENDARSERVER values ('VERSION', '5');
+

Copied: CalendarServer/trunk/txdav/common/datastore/sql_schema/old/v6.sql (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/sql_schema/old/v6.sql)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/old/v6.sql	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/old/v6.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,464 @@
+-- -*- test-case-name: txdav.caldav.datastore.test.test_sql,txdav.carddav.datastore.test.test_sql -*-
+
+----
+-- Copyright (c) 2010-2011 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.
+----
+
+-----------------
+-- Resource ID --
+-----------------
+
+create sequence RESOURCE_ID_SEQ;
+
+
+-------------------
+-- Calendar Home --
+-------------------
+
+create table CALENDAR_HOME (
+  RESOURCE_ID      integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  OWNER_UID        varchar(255) not null unique                                 -- implicit index
+);
+
+----------------------------
+-- Calendar Home Metadata --
+----------------------------
+
+create table CALENDAR_HOME_METADATA (
+  RESOURCE_ID      integer      primary key references CALENDAR_HOME on delete cascade, -- implicit index
+  QUOTA_USED_BYTES integer      default 0 not null
+);
+
+--------------
+-- Calendar --
+--------------
+
+create table CALENDAR (
+  RESOURCE_ID integer   primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  CREATED     timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED    timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+------------------------
+-- Sharing Invitation --
+------------------------
+
+create table INVITE (
+    INVITE_UID         varchar(255) not null,
+    NAME               varchar(255) not null,
+    RECIPIENT_ADDRESS  varchar(255) not null,
+    HOME_RESOURCE_ID   integer      not null,
+    RESOURCE_ID        integer      not null
+    
+    -- Need primary key on (INVITE_UID, NAME, RECIPIENT_ADDRESS)?
+);
+
+create index INVITE_INVITE_UID on INVITE(INVITE_UID);
+create index INVITE_RESOURCE_ID on INVITE(RESOURCE_ID);
+create index INVITE_HOME_RESOURCE_ID on INVITE(HOME_RESOURCE_ID);
+
+---------------------------
+-- Sharing Notifications --
+---------------------------
+
+create table NOTIFICATION_HOME (
+  RESOURCE_ID integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  OWNER_UID   varchar(255) not null unique                                 -- implicit index
+);
+
+create table NOTIFICATION (
+  RESOURCE_ID                   integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  NOTIFICATION_HOME_RESOURCE_ID integer      not null references NOTIFICATION_HOME,
+  NOTIFICATION_UID              varchar(255) not null,
+  XML_TYPE                      varchar(255) not null,
+  XML_DATA                      text         not null,
+  MD5                           char(32)     not null,
+  CREATED                       timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED                      timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+
+  unique(NOTIFICATION_UID, NOTIFICATION_HOME_RESOURCE_ID) -- implicit index
+);
+
+create index NOTIFICATION_NOTIFICATION_HOME_RESOURCE_ID on
+  NOTIFICATION(NOTIFICATION_HOME_RESOURCE_ID);
+
+-------------------
+-- Calendar Bind --
+-------------------
+
+-- Joins CALENDAR_HOME and CALENDAR
+
+create table CALENDAR_BIND (
+  CALENDAR_HOME_RESOURCE_ID integer      not null references CALENDAR_HOME,
+  CALENDAR_RESOURCE_ID      integer      not null references CALENDAR on delete cascade,
+  
+  -- An invitation which hasn't been accepted yet will not yet have a resource
+  -- name, so this field may be null.
+  
+  CALENDAR_RESOURCE_NAME    varchar(255),
+  BIND_MODE                 integer      not null, -- enum CALENDAR_BIND_MODE
+  BIND_STATUS               integer      not null, -- enum CALENDAR_BIND_STATUS
+  SEEN_BY_OWNER             boolean      not null,
+  SEEN_BY_SHAREE            boolean      not null,
+  MESSAGE                   text,
+
+  primary key(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID), -- implicit index
+  unique(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_NAME)     -- implicit index
+);
+
+create index CALENDAR_BIND_RESOURCE_ID on CALENDAR_BIND(CALENDAR_RESOURCE_ID);
+
+-- Enumeration of calendar bind modes
+
+create table CALENDAR_BIND_MODE (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_BIND_MODE values (0, 'own'  );
+insert into CALENDAR_BIND_MODE values (1, 'read' );
+insert into CALENDAR_BIND_MODE values (2, 'write');
+insert into CALENDAR_BIND_MODE values (3, 'direct');
+
+-- Enumeration of statuses
+
+create table CALENDAR_BIND_STATUS (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_BIND_STATUS values (0, 'invited' );
+insert into CALENDAR_BIND_STATUS values (1, 'accepted');
+insert into CALENDAR_BIND_STATUS values (2, 'declined');
+insert into CALENDAR_BIND_STATUS values (3, 'invalid');
+
+
+---------------------
+-- Calendar Object --
+---------------------
+
+create table CALENDAR_OBJECT (
+  RESOURCE_ID          integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  CALENDAR_RESOURCE_ID integer      not null references CALENDAR on delete cascade,
+  RESOURCE_NAME        varchar(255) not null,
+  ICALENDAR_TEXT       text         not null,
+  ICALENDAR_UID        varchar(255) not null,
+  ICALENDAR_TYPE       varchar(255) not null,
+  ATTACHMENTS_MODE     integer      default 0 not null, -- enum CALENDAR_OBJECT_ATTACHMENTS_MODE
+  DROPBOX_ID           varchar(255),
+  ORGANIZER            varchar(255),
+  ORGANIZER_OBJECT     integer      references CALENDAR_OBJECT,
+  RECURRANCE_MAX       date,        -- maximum date that recurrences have been expanded to.
+  ACCESS               integer      default 0 not null,
+  SCHEDULE_OBJECT      boolean      default false,
+  SCHEDULE_TAG         varchar(36)  default null,
+  SCHEDULE_ETAGS       text         default null,
+  PRIVATE_COMMENTS     boolean      default false not null,
+  MD5                  char(32)     not null,
+  CREATED              timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED             timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+
+  unique(CALENDAR_RESOURCE_ID, RESOURCE_NAME) -- implicit index
+
+  -- since the 'inbox' is a 'calendar resource' for the purpose of storing
+  -- calendar objects, this constraint has to be selectively enforced by the
+  -- application layer.
+
+  -- unique(CALENDAR_RESOURCE_ID, ICALENDAR_UID)
+);
+
+create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_AND_ICALENDAR_UID on
+  CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, ICALENDAR_UID);
+ 
+create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_RECURRANCE_MAX on
+  CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, RECURRANCE_MAX);
+
+create index CALENDAR_OBJECT_ORGANIZER_OBJECT on
+  CALENDAR_OBJECT(ORGANIZER_OBJECT);
+
+create index CALENDAR_OBJECT_DROPBOX_ID on
+  CALENDAR_OBJECT(DROPBOX_ID);
+
+-- Enumeration of attachment modes
+
+create table CALENDAR_OBJECT_ATTACHMENTS_MODE (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (0, 'none' );
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (1, 'read' );
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (2, 'write');
+
+
+-- Enumeration of calendar access types
+
+create table CALENDAR_ACCESS_TYPE (
+  ID          integer     primary key,
+  DESCRIPTION varchar(32) not null unique
+);
+
+insert into CALENDAR_ACCESS_TYPE values (0, ''             );
+insert into CALENDAR_ACCESS_TYPE values (1, 'public'       );
+insert into CALENDAR_ACCESS_TYPE values (2, 'private'      );
+insert into CALENDAR_ACCESS_TYPE values (3, 'confidential' );
+insert into CALENDAR_ACCESS_TYPE values (4, 'restricted'   );
+
+-----------------
+-- Instance ID --
+-----------------
+
+create sequence INSTANCE_ID_SEQ;
+
+
+----------------
+-- Time Range --
+----------------
+
+create table TIME_RANGE (
+  INSTANCE_ID                 integer        primary key default nextval('INSTANCE_ID_SEQ'), -- implicit index
+  CALENDAR_RESOURCE_ID        integer        not null references CALENDAR on delete cascade,
+  CALENDAR_OBJECT_RESOURCE_ID integer        not null references CALENDAR_OBJECT on delete cascade,
+  FLOATING                    boolean        not null,
+  START_DATE                  timestamp      not null,
+  END_DATE                    timestamp      not null,
+  FBTYPE                      integer        not null,
+  TRANSPARENT                 boolean        not null
+);
+
+create index TIME_RANGE_CALENDAR_RESOURCE_ID on
+  TIME_RANGE(CALENDAR_RESOURCE_ID);
+create index TIME_RANGE_CALENDAR_OBJECT_RESOURCE_ID on
+  TIME_RANGE(CALENDAR_OBJECT_RESOURCE_ID);
+
+
+-- Enumeration of free/busy types
+
+create table FREE_BUSY_TYPE (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into FREE_BUSY_TYPE values (0, 'unknown'         );
+insert into FREE_BUSY_TYPE values (1, 'free'            );
+insert into FREE_BUSY_TYPE values (2, 'busy'            );
+insert into FREE_BUSY_TYPE values (3, 'busy-unavailable');
+insert into FREE_BUSY_TYPE values (4, 'busy-tentative'  );
+
+
+------------------
+-- Transparency --
+------------------
+
+create table TRANSPARENCY (
+  TIME_RANGE_INSTANCE_ID      integer      not null references TIME_RANGE on delete cascade,
+  USER_ID                     varchar(255) not null,
+  TRANSPARENT                 boolean      not null
+);
+
+create index TRANSPARENCY_TIME_RANGE_INSTANCE_ID on
+  TRANSPARENCY(TIME_RANGE_INSTANCE_ID);
+
+----------------
+-- Attachment --
+----------------
+
+create table ATTACHMENT (
+  CALENDAR_HOME_RESOURCE_ID   integer       not null references CALENDAR_HOME,
+  DROPBOX_ID                  varchar(255)  not null,
+  CONTENT_TYPE                varchar(255)  not null,
+  SIZE                        integer       not null,
+  MD5                         char(32)      not null,
+  CREATED                     timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED                    timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+  PATH                        varchar(1024) not null,
+
+  primary key(DROPBOX_ID, PATH) --implicit index
+);
+
+create index ATTACHMENT_CALENDAR_HOME_RESOURCE_ID on
+  ATTACHMENT(CALENDAR_HOME_RESOURCE_ID);
+
+-----------------------
+-- Resource Property --
+-----------------------
+
+create table RESOURCE_PROPERTY (
+  RESOURCE_ID integer      not null, -- foreign key: *.RESOURCE_ID
+  NAME        varchar(255) not null,
+  VALUE       text         not null, -- FIXME: xml?
+  VIEWER_UID  varchar(255),
+
+  primary key(RESOURCE_ID, NAME, VIEWER_UID) -- implicit index
+);
+
+
+----------------------
+-- AddressBook Home --
+----------------------
+
+create table ADDRESSBOOK_HOME (
+  RESOURCE_ID      integer      primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  OWNER_UID        varchar(255) not null unique                                 -- implicit index
+);
+
+--------------------------------
+-- AddressBook Home Meta-data --
+--------------------------------
+
+create table ADDRESSBOOK_HOME_METADATA (
+  RESOURCE_ID      integer      primary key references ADDRESSBOOK_HOME on delete cascade, -- implicit index
+  QUOTA_USED_BYTES integer      default 0 not null
+);
+
+-----------------
+-- AddressBook --
+-----------------
+
+create table ADDRESSBOOK (
+  RESOURCE_ID integer   primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+  CREATED     timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED    timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+----------------------
+-- AddressBook Bind --
+----------------------
+
+-- Joins ADDRESSBOOK_HOME and ADDRESSBOOK
+
+create table ADDRESSBOOK_BIND (
+  ADDRESSBOOK_HOME_RESOURCE_ID integer      not null references ADDRESSBOOK_HOME,
+  ADDRESSBOOK_RESOURCE_ID      integer      not null references ADDRESSBOOK on delete cascade,
+
+  -- An invitation which hasn't been accepted yet will not yet have a resource
+  -- name, so this field may be null.
+
+  ADDRESSBOOK_RESOURCE_NAME    varchar(255),
+  BIND_MODE                    integer      not null, -- enum CALENDAR_BIND_MODE
+  BIND_STATUS                  integer      not null, -- enum CALENDAR_BIND_STATUS
+  SEEN_BY_OWNER                boolean      not null,
+  SEEN_BY_SHAREE               boolean      not null,
+  MESSAGE                      text,                  -- FIXME: xml?
+
+  primary key(ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_ID), -- implicit index
+  unique(ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_NAME)     -- implicit index
+);
+
+create index ADDRESSBOOK_BIND_RESOURCE_ID on
+  ADDRESSBOOK_BIND(ADDRESSBOOK_RESOURCE_ID);
+
+create table ADDRESSBOOK_OBJECT (
+  RESOURCE_ID             integer      primary key default nextval('RESOURCE_ID_SEQ'),    -- implicit index
+  ADDRESSBOOK_RESOURCE_ID integer      not null references ADDRESSBOOK on delete cascade,
+  RESOURCE_NAME           varchar(255) not null,
+  VCARD_TEXT              text         not null,
+  VCARD_UID               varchar(255) not null,
+  MD5                     char(32)     not null,
+  CREATED                 timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+  MODIFIED                timestamp    default timezone('UTC', CURRENT_TIMESTAMP),
+
+  unique(ADDRESSBOOK_RESOURCE_ID, RESOURCE_NAME), -- implicit index
+  unique(ADDRESSBOOK_RESOURCE_ID, VCARD_UID)      -- implicit index
+);
+
+---------------
+-- Revisions --
+---------------
+
+create sequence REVISION_SEQ;
+
+
+---------------
+-- Revisions --
+---------------
+
+create table CALENDAR_OBJECT_REVISIONS (
+  CALENDAR_HOME_RESOURCE_ID integer      not null references CALENDAR_HOME,
+  CALENDAR_RESOURCE_ID      integer      references CALENDAR,
+  CALENDAR_NAME             varchar(255) default null,
+  RESOURCE_NAME             varchar(255),
+  REVISION                  integer      default nextval('REVISION_SEQ') not null,
+  DELETED                   boolean      not null
+);
+
+create index CALENDAR_OBJECT_REVISIONS_HOME_RESOURCE_ID
+  on CALENDAR_OBJECT_REVISIONS(CALENDAR_HOME_RESOURCE_ID);
+
+create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME
+  on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, RESOURCE_NAME);
+
+-------------------------------
+-- AddressBook Object Revisions --
+-------------------------------
+
+create table ADDRESSBOOK_OBJECT_REVISIONS (
+  ADDRESSBOOK_HOME_RESOURCE_ID integer      not null references ADDRESSBOOK_HOME,
+  ADDRESSBOOK_RESOURCE_ID      integer      references ADDRESSBOOK,
+  ADDRESSBOOK_NAME             varchar(255) default null,
+  RESOURCE_NAME                varchar(255),
+  REVISION                     integer      default nextval('REVISION_SEQ') not null,
+  DELETED                      boolean      not null
+);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_HOME_RESOURCE_ID
+  on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_HOME_RESOURCE_ID);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME
+  on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_RESOURCE_ID, RESOURCE_NAME);
+
+-----------------------------------
+-- Notification Object Revisions --
+-----------------------------------
+
+create table NOTIFICATION_OBJECT_REVISIONS (
+  NOTIFICATION_HOME_RESOURCE_ID integer      not null references NOTIFICATION_HOME on delete cascade,
+  RESOURCE_NAME                 varchar(255),
+  REVISION                      integer      default nextval('REVISION_SEQ') not null,
+  DELETED                       boolean      not null,
+
+  unique(NOTIFICATION_HOME_RESOURCE_ID, RESOURCE_NAME) -- implicit index
+);
+
+
+-------------------------------------------
+-- Apple Push Notification Subscriptions --
+-------------------------------------------
+
+create table APN_SUBSCRIPTIONS (
+  TOKEN                         varchar(255) not null,
+  RESOURCE_KEY                  varchar(255) not null,
+  MODIFIED                      integer not null,
+  SUBSCRIBER_GUID               varchar(255) not null,
+  unique(TOKEN, RESOURCE_KEY) -- implicit index
+);
+
+create index APN_SUBSCRIPTIONS_RESOURCE_KEY
+   on APN_SUBSCRIPTIONS(RESOURCE_KEY);
+
+
+--------------------
+-- Schema Version --
+--------------------
+
+create table CALENDARSERVER (
+  NAME                          varchar(255) primary key, -- implicit index
+  VALUE                         varchar(255)
+);
+
+insert into CALENDARSERVER values ('VERSION', '6');
+

Deleted: CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_5_to_6.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_5_to_6.sql	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_5_to_6.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,38 +0,0 @@
-----
--- Copyright (c) 2011 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.
-----
-
--------------------------------------------------
--- Upgrade database schema from VERSION 5 to 6 --
--------------------------------------------------
-
----------------------------------------------------------
--- New table for Apple Push Notification Subscriptions --
----------------------------------------------------------
-
-create table APN_SUBSCRIPTIONS (
-  TOKEN                         varchar(255) not null,
-  RESOURCE_KEY                  varchar(255) not null,
-  MODIFIED                      integer not null,
-  SUBSCRIBER_GUID               varchar(255) not null,
-  unique(TOKEN, RESOURCE_KEY) -- implicit index
-);
-
-create index APN_SUBSCRIPTIONS_RES_9610d78e
-  on APN_SUBSCRIPTIONS(RESOURCE_KEY);
-
--- Now update the version
-update CALENDARSERVER set VALUE = '6' where NAME = 'VERSION';
-

Copied: CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_5_to_6.sql (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_5_to_6.sql)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_5_to_6.sql	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_5_to_6.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,38 @@
+----
+-- Copyright (c) 2011 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.
+----
+
+-------------------------------------------------
+-- Upgrade database schema from VERSION 5 to 6 --
+-------------------------------------------------
+
+---------------------------------------------------------
+-- New table for Apple Push Notification Subscriptions --
+---------------------------------------------------------
+
+create table APN_SUBSCRIPTIONS (
+  TOKEN                         varchar(255) not null,
+  RESOURCE_KEY                  varchar(255) not null,
+  MODIFIED                      integer not null,
+  SUBSCRIBER_GUID               varchar(255) not null,
+  unique(TOKEN, RESOURCE_KEY) -- implicit index
+);
+
+create index APN_SUBSCRIPTIONS_RES_9610d78e
+  on APN_SUBSCRIPTIONS(RESOURCE_KEY);
+
+-- Now update the version
+update CALENDARSERVER set VALUE = '6' where NAME = 'VERSION';
+

Copied: CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_6_to_7.sql (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_6_to_7.sql)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_6_to_7.sql	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_6_to_7.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,38 @@
+----
+-- Copyright (c) 2011 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.
+----
+
+-------------------------------------------------
+-- Upgrade database schema from VERSION 5 to 6 --
+-------------------------------------------------
+
+-- Just need to add one column
+alter table CALENDAR_HOME
+ add ("DATAVERSION" integer default 1 null);
+ 
+-- Just need to modify one column
+alter table CALENDAR_OBJECT
+ add ("SUPPORTED_COMPONENTS" nvarchar2(255) default null);
+
+-- Just need to add one column
+alter table ADDRESSBOOK_HOME
+ add ("DATAVERSION" integer default 1 null);
+ 
+-- Now update the version
+update CALENDARSERVER set VALUE = '7' where NAME = 'VERSION';
+
+-- Also insert the initial data version which we will use in the data upgrade
+insert into CALENDARSERVER values ('CALENDAR-DATAVERSION', '1');
+insert into CALENDARSERVER values ('ADDRESSBOOK-DATAVERSION', '1');

Deleted: CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_5_to_6.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_5_to_6.sql	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_5_to_6.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,38 +0,0 @@
-----
--- Copyright (c) 2011 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.
-----
-
--------------------------------------------------
--- Upgrade database schema from VERSION 5 to 6 --
--------------------------------------------------
-
----------------------------------------------------------
--- New table for Apple Push Notification Subscriptions --
----------------------------------------------------------
-
-create table APN_SUBSCRIPTIONS (
-  TOKEN                         varchar(255) not null,
-  RESOURCE_KEY                  varchar(255) not null,
-  MODIFIED                      integer not null,
-  SUBSCRIBER_GUID               varchar(255) not null,
-  unique(TOKEN, RESOURCE_KEY) -- implicit index
-);
-
-create index APN_SUBSCRIPTIONS_RESOURCE_KEY
-  on APN_SUBSCRIPTIONS(RESOURCE_KEY);
-
--- Now update the version
-update CALENDARSERVER set VALUE = '6' where NAME = 'VERSION';
-

Copied: CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_5_to_6.sql (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_5_to_6.sql)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_5_to_6.sql	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_5_to_6.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,38 @@
+----
+-- Copyright (c) 2011 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.
+----
+
+-------------------------------------------------
+-- Upgrade database schema from VERSION 5 to 6 --
+-------------------------------------------------
+
+---------------------------------------------------------
+-- New table for Apple Push Notification Subscriptions --
+---------------------------------------------------------
+
+create table APN_SUBSCRIPTIONS (
+  TOKEN                         varchar(255) not null,
+  RESOURCE_KEY                  varchar(255) not null,
+  MODIFIED                      integer not null,
+  SUBSCRIBER_GUID               varchar(255) not null,
+  unique(TOKEN, RESOURCE_KEY) -- implicit index
+);
+
+create index APN_SUBSCRIPTIONS_RESOURCE_KEY
+  on APN_SUBSCRIPTIONS(RESOURCE_KEY);
+
+-- Now update the version
+update CALENDARSERVER set VALUE = '6' where NAME = 'VERSION';
+

Copied: CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_6_to_7.sql (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_6_to_7.sql)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_6_to_7.sql	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_6_to_7.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,38 @@
+----
+-- Copyright (c) 2011 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.
+----
+
+-------------------------------------------------
+-- Upgrade database schema from VERSION 5 to 6 --
+-------------------------------------------------
+
+-- Just need to add one column
+alter table CALENDAR_HOME
+ add column DATAVERSION integer default 1 null;
+ 
+-- Just need to add one column
+alter table CALENDAR
+ add column SUPPORTED_COMPONENTS varchar(255) default null;
+
+-- Just need to add one column
+alter table ADDRESSBOOK_HOME
+ add column DATAVERSION integer default 1 null;
+ 
+-- Now update the version
+update CALENDARSERVER set VALUE = '7' where NAME = 'VERSION';
+
+-- Also insert the initial data version which we will use in the data upgrade
+insert into CALENDARSERVER values ('CALENDAR-DATAVERSION', '1');
+insert into CALENDARSERVER values ('ADDRESSBOOK-DATAVERSION', '1');

Deleted: CalendarServer/trunk/txdav/common/datastore/test/test_util.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/test/test_util.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/txdav/common/datastore/test/test_util.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,361 +0,0 @@
-##
-# Copyright (c) 2010-2011 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.
-##
-from twext.enterprise.ienterprise import ORACLE_DIALECT, POSTGRES_DIALECT
-
-"""
-Tests for L{txdav.common.datastore.util}.
-"""
-
-from twext.python.filepath import CachingFilePath
-from twext.web2.http_headers import MimeType
-from twisted.application.service import Service, MultiService
-from twisted.internet.defer import inlineCallbacks, Deferred, returnValue
-from twisted.internet.protocol import Protocol
-from twisted.python.modules import getModule
-from twisted.trial.unittest import TestCase
-from txdav.caldav.datastore.test.common import CommonTests
-from txdav.carddav.datastore.test.common import CommonTests as ABCommonTests
-from txdav.common.datastore.file import CommonDataStore
-from txdav.common.datastore.test.util import theStoreBuilder, \
-    populateCalendarsFrom, StubNotifierFactory, resetCalendarMD5s,\
-    populateAddressBooksFrom, resetAddressBookMD5s
-from txdav.common.datastore.util import UpgradeToDatabaseService,\
-    UpgradeDatabaseSchemaService
-import re
-
-class HomeMigrationTests(TestCase):
-    """
-    Tests for L{UpgradeToDatabaseService}.
-    """
-
-    @inlineCallbacks
-    def setUp(self):
-        """
-        Set up two stores to migrate between.
-        """
-        # Add some files to the file store.
-
-        self.filesPath = CachingFilePath(self.mktemp())
-        self.filesPath.createDirectory()
-        fileStore = self.fileStore = CommonDataStore(
-            self.filesPath, StubNotifierFactory(), True, True
-        )
-        self.sqlStore = yield theStoreBuilder.buildStore(
-            self, StubNotifierFactory()
-        )
-        subStarted = self.subStarted = Deferred()
-        class StubService(Service, object):
-            def startService(self):
-                super(StubService, self).startService()
-                subStarted.callback(None)
-        self.stubService = StubService()
-        self.topService = MultiService()
-        self.upgrader = UpgradeToDatabaseService(
-            fileStore, self.sqlStore, self.stubService
-        )
-        self.upgrader.setServiceParent(self.topService)
-
-        requirements = CommonTests.requirements
-        yield populateCalendarsFrom(requirements, fileStore)
-        md5s = CommonTests.md5s
-        yield resetCalendarMD5s(md5s, fileStore)
-        self.filesPath.child("calendars").child(
-            "__uids__").child("ho").child("me").child("home1").child(
-            ".some-extra-data").setContent("some extra data")
-
-        requirements = ABCommonTests.requirements
-        yield populateAddressBooksFrom(requirements, fileStore)
-        md5s = ABCommonTests.md5s
-        yield resetAddressBookMD5s(md5s, fileStore)
-        self.filesPath.child("addressbooks").child(
-            "__uids__").child("ho").child("me").child("home1").child(
-            ".some-extra-data").setContent("some extra data")
-
-
-    @inlineCallbacks
-    def test_upgradeCalendarHomes(self):
-        """
-        L{UpgradeToDatabaseService.startService} will do the upgrade, then
-        start its dependent service by adding it to its service hierarchy.
-        """
-        self.topService.startService()
-        yield self.subStarted
-        self.assertEquals(self.stubService.running, True)
-        txn = self.sqlStore.newTransaction()
-        self.addCleanup(txn.commit)
-        for uid in CommonTests.requirements:
-            if CommonTests.requirements[uid] is not None:
-                self.assertNotIdentical(
-                    None, (yield txn.calendarHomeWithUID(uid))
-                )
-        # Successfully migrated calendar homes are deleted
-        self.assertFalse(self.filesPath.child("calendars").child(
-            "__uids__").child("ho").child("me").child("home1").exists())
-
-        # Want metadata preserved
-        home = (yield txn.calendarHomeWithUID("home1"))
-        calendar = (yield home.calendarWithName("calendar_1"))
-        for name, metadata, md5 in (
-            ("1.ics", CommonTests.metadata1, CommonTests.md5Values[0]),
-            ("2.ics", CommonTests.metadata2, CommonTests.md5Values[1]),
-            ("3.ics", CommonTests.metadata3, CommonTests.md5Values[2]),
-        ):
-            object = (yield calendar.calendarObjectWithName(name))
-            self.assertEquals(object.getMetadata(), metadata)
-            self.assertEquals(object.md5(), md5)
-
-
-    @inlineCallbacks
-    def test_upgradeExistingHome(self):
-        """
-        L{UpgradeToDatabaseService.startService} will skip migrating existing
-        homes.
-        """
-        startTxn = self.sqlStore.newTransaction("populate empty sample")
-        yield startTxn.calendarHomeWithUID("home1", create=True)
-        yield startTxn.commit()
-        self.topService.startService()
-        yield self.subStarted
-        vrfyTxn = self.sqlStore.newTransaction("verify sample still empty")
-        self.addCleanup(vrfyTxn.commit)
-        home = yield vrfyTxn.calendarHomeWithUID("home1")
-        # The default calendar is still there.
-        self.assertNotIdentical(None, (yield home.calendarWithName("calendar")))
-        # The migrated calendar isn't.
-        self.assertIdentical(None, (yield home.calendarWithName("calendar_1")))
-
-
-    @inlineCallbacks
-    def test_upgradeAttachments(self):
-        """
-        L{UpgradeToDatabaseService.startService} upgrades calendar attachments
-        as well.
-        """
-
-        txn = self.fileStore.newTransaction()
-        committed = []
-        def maybeCommit():
-            if not committed:
-                committed.append(True)
-                return txn.commit()
-        self.addCleanup(maybeCommit)
-
-        @inlineCallbacks
-        def getSampleObj():
-            home = (yield txn.calendarHomeWithUID("home1"))
-            calendar = (yield home.calendarWithName("calendar_1"))
-            object = (yield calendar.calendarObjectWithName("1.ics"))
-            returnValue(object)
-
-        inObject = yield getSampleObj()
-        someAttachmentName = "some-attachment"
-        someAttachmentType = MimeType.fromString("application/x-custom-type")
-        attachment = yield inObject.createAttachmentWithName(
-            someAttachmentName,
-        )
-        transport = attachment.store(someAttachmentType)
-        someAttachmentData = "Here is some data for your attachment, enjoy."
-        transport.write(someAttachmentData)
-        yield transport.loseConnection()
-        yield maybeCommit()
-        self.topService.startService()
-        yield self.subStarted
-        committed = []
-        txn = self.sqlStore.newTransaction()
-        outObject = yield getSampleObj()
-        outAttachment = yield outObject.attachmentWithName(someAttachmentName)
-        allDone = Deferred()
-        class SimpleProto(Protocol):
-            data = ''
-            def dataReceived(self, data):
-                self.data += data
-            def connectionLost(self, reason):
-                allDone.callback(self.data)
-        self.assertEquals(outAttachment.contentType(), someAttachmentType)
-        outAttachment.retrieve(SimpleProto())
-        allData = yield allDone
-        self.assertEquals(allData, someAttachmentData)
-
-
-    @inlineCallbacks
-    def test_upgradeAddressBookHomes(self):
-        """
-        L{UpgradeToDatabaseService.startService} will do the upgrade, then
-        start its dependent service by adding it to its service hierarchy.
-        """
-        self.topService.startService()
-        yield self.subStarted
-        self.assertEquals(self.stubService.running, True)
-        txn = self.sqlStore.newTransaction()
-        self.addCleanup(txn.commit)
-        for uid in ABCommonTests.requirements:
-            if ABCommonTests.requirements[uid] is not None:
-                self.assertNotIdentical(
-                    None, (yield txn.addressbookHomeWithUID(uid))
-                )
-        # Successfully migrated addressbook homes are deleted
-        self.assertFalse(self.filesPath.child("addressbooks").child(
-            "__uids__").child("ho").child("me").child("home1").exists())
-
-        # Want metadata preserved
-        home = (yield txn.addressbookHomeWithUID("home1"))
-        adbk = (yield home.addressbookWithName("addressbook_1"))
-        for name, md5 in (
-            ("1.vcf", ABCommonTests.md5Values[0]),
-            ("2.vcf", ABCommonTests.md5Values[1]),
-            ("3.vcf", ABCommonTests.md5Values[2]),
-        ):
-            object = (yield adbk.addressbookObjectWithName(name))
-            self.assertEquals(object.md5(), md5)
-
-class SchemaUpgradeTests(TestCase):
-    """
-    Tests for L{UpgradeDatabaseSchemaService}.
-    """
-
-    def _getSchemaVersion(self, fp):
-        schema = fp.getContent()
-        found = re.search("insert into CALENDARSERVER values \('VERSION', '(\d)+'\);", schema)
-        if found is None:
-            self.fail("Could not determine schema version for: %s" % (fp,))
-        return int(found.group(1))
-
-    def test_scanUpgradeFiles(self):
-        
-        upgrader = UpgradeDatabaseSchemaService(None, None)
-
-        upgrader.schemaLocation = getModule(__name__).filePath.sibling("fake_schema1")
-        files = upgrader.scanForUpgradeFiles("fake_dialect")
-        self.assertEqual(files, 
-            [(3, 4, upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_3_to_4.sql"))],
-        )
-
-        upgrader.schemaLocation = getModule(__name__).filePath.sibling("fake_schema2")
-        files = upgrader.scanForUpgradeFiles("fake_dialect")
-        self.assertEqual(files, 
-            [
-                (3, 4, upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_3_to_4.sql")),
-                (3, 5, upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_3_to_5.sql")),
-                (4, 5, upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_4_to_5.sql")),
-            ]
-        )
-
-    def test_determineUpgradeSequence(self):
-        
-        upgrader = UpgradeDatabaseSchemaService(None, None)
-
-        upgrader.schemaLocation = getModule(__name__).filePath.sibling("fake_schema1")
-        files = upgrader.scanForUpgradeFiles("fake_dialect")
-        upgrades = upgrader.determineUpgradeSequence(3, 4, files, "fake_dialect")
-        self.assertEqual(upgrades, 
-            [upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_3_to_4.sql")],
-        )
-        self.assertRaises(RuntimeError, upgrader.determineUpgradeSequence, 3, 5, files, "fake_dialect")
-
-        upgrader.schemaLocation = getModule(__name__).filePath.sibling("fake_schema2")
-        files = upgrader.scanForUpgradeFiles("fake_dialect")
-        upgrades = upgrader.determineUpgradeSequence(3, 5, files, "fake_dialect")
-        self.assertEqual(upgrades, 
-            [upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_3_to_5.sql")]
-        )
-        upgrades = upgrader.determineUpgradeSequence(4, 5, files, "fake_dialect")
-        self.assertEqual(upgrades, 
-            [upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_4_to_5.sql")]
-        )
-
-        upgrader.schemaLocation = getModule(__name__).filePath.sibling("fake_schema3")
-        files = upgrader.scanForUpgradeFiles("fake_dialect")
-        upgrades = upgrader.determineUpgradeSequence(3, 5, files, "fake_dialect")
-        self.assertEqual(upgrades, 
-            [
-                upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_3_to_4.sql"),
-                upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_4_to_5.sql"),
-            ]
-        )
-
-    def test_upgradeAvailability(self):
-        """
-        Make sure that each old schema has a valid upgrade path to the current one.
-        """
-        
-        for dialect in (POSTGRES_DIALECT, ORACLE_DIALECT,):
-            upgrader = UpgradeDatabaseSchemaService(None, None)
-            files = upgrader.scanForUpgradeFiles(dialect)
-
-            current_version = self._getSchemaVersion(upgrader.schemaLocation.child("current.sql"))
-            
-            for child in upgrader.schemaLocation.child("old").globChildren("*.sql"):
-                old_version = self._getSchemaVersion(child)
-                upgrades = upgrader.determineUpgradeSequence(old_version, current_version, files, dialect)
-                self.assertNotEqual(len(upgrades), 0)
-
-    @inlineCallbacks
-    def test_dbUpgrades(self):
-        """
-        This does a full DB test of all possible upgrade paths. For each old schema, it loads it into the DB
-        then runs the upgrade service. This ensures all the upgrade.sql files work correctly - at least for
-        postgres.
-        """
-
-        store = yield theStoreBuilder.buildStore(
-            self, StubNotifierFactory()
-        )
-
-        @inlineCallbacks
-        def _loadOldSchema(path):
-            """
-            Use the postgres schema mechanism to do tests under a separate "namespace"
-            in postgres that we can quickly wipe clean afterwards.
-            """
-            startTxn = store.newTransaction("test_dbUpgrades")        
-            yield startTxn.execSQL("create schema test_dbUpgrades;")
-            yield startTxn.execSQL("set search_path to test_dbUpgrades;")
-            yield startTxn.execSQL(path.getContent())
-            yield startTxn.commit()
-
-        @inlineCallbacks
-        def _loadVersion():
-            startTxn = store.newTransaction("test_dbUpgrades")        
-            new_version = yield startTxn.execSQL("select value from calendarserver where name = 'VERSION';")
-            yield startTxn.commit()
-            returnValue(int(new_version[0][0]))
-
-        @inlineCallbacks
-        def _unloadOldSchema():
-            startTxn = store.newTransaction("test_dbUpgrades")        
-            yield startTxn.execSQL("set search_path to public;")
-            yield startTxn.execSQL("drop schema test_dbUpgrades cascade;")
-            yield startTxn.commit()
-
-        @inlineCallbacks
-        def _cleanupOldSchema():
-            startTxn = store.newTransaction("test_dbUpgrades")        
-            yield startTxn.execSQL("set search_path to public;")
-            yield startTxn.execSQL("drop schema if exists test_dbUpgrades cascade;")
-            yield startTxn.commit()
-
-        self.addCleanup(_cleanupOldSchema)
-
-        test_upgrader = UpgradeDatabaseSchemaService(None, None)
-        expected_version = self._getSchemaVersion(test_upgrader.schemaLocation.child("current.sql"))
-        for child in test_upgrader.schemaLocation.child("old").globChildren("*.sql"):
-            upgrader = UpgradeDatabaseSchemaService(store, None)
-            yield _loadOldSchema(child)
-            yield upgrader.doUpgrade()
-            new_version = yield _loadVersion()
-            yield _unloadOldSchema()
-
-            self.assertEqual(new_version, expected_version)

Modified: CalendarServer/trunk/txdav/common/datastore/test/util.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/test/util.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/txdav/common/datastore/test/util.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -14,6 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 ##
+from twistedcaldav.config import config
 
 """
 Store test utility functions
@@ -101,6 +102,11 @@
             self.sharedService = PostgresService(
                 dbRoot, getReady, current_sql_schema, resetSchema=True,
                 databaseName="caldav",
+                options = [
+                    "-c log_lock_waits=TRUE",
+                    "-c log_statement=all",
+                    "-c log_line_prefix='%p.%x '",
+                ],
                 testMode=True
             )
             self.sharedService.startService()
@@ -262,6 +268,8 @@
             # explicitly listed.
             try:
                 yield home.removeCalendarWithName("calendar")
+                if config.RestrictCalendarsToOneComponentType:
+                    yield home.removeCalendarWithName("tasks")
                 yield home.removeCalendarWithName("inbox")
             except NoSuchHomeChildError:
                 pass
@@ -508,7 +516,6 @@
     # else in this module; nothing else in this module should ever touch global
     # configuration. -glyph
 
-    from twistedcaldav.config import config
     from twistedcaldav.memcacher import Memcacher
 
     aTest.patch(config.Memcached.Pools.Default, "ClientEnabled", False)

Deleted: CalendarServer/trunk/txdav/common/datastore/upgrade/__init__.py
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/__init__.py	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/__init__.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,16 +0,0 @@
-##
-# Copyright (c) 2011 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.
-##
-

Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/__init__.py (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/__init__.py)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/__init__.py	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/__init__.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,16 @@
+##
+# Copyright (c) 2011 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.
+##
+

Deleted: CalendarServer/trunk/txdav/common/datastore/upgrade/file/__init__.py
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/file/__init__.py	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/file/__init__.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,16 +0,0 @@
-##
-# Copyright (c) 2011 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.
-##
-

Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/file/__init__.py (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/file/__init__.py)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/file/__init__.py	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/file/__init__.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,16 @@
+##
+# Copyright (c) 2011 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.
+##
+

Deleted: CalendarServer/trunk/txdav/common/datastore/upgrade/migrate.py
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/migrate.py	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/migrate.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,196 +0,0 @@
-# -*- test-case-name: txdav.common.datastore.upgrade.test.test_migrate -*-
-##
-# Copyright (c) 2011 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.
-##
-
-"""
-Migrating from file store to sql store.
-"""
-
-import os
-import errno
-import xattr
-
-from twext.python.log import LoggingMixIn
-from twisted.application.service import Service
-from twisted.internet import reactor
-from twisted.internet.defer import inlineCallbacks
-from twisted.python.runtime import platform
-
-from txdav.caldav.datastore.util import migrateHome as migrateCalendarHome
-from txdav.carddav.datastore.util import migrateHome as migrateAddressbookHome
-from txdav.common.datastore.file import CommonDataStore as FileStore, TOPPATHS
-from txdav.base.propertystore.xattr import PropertyStore as XattrPropertyStore
-from txdav.base.propertystore.appledouble_xattr import (
-    PropertyStore as AppleDoubleStore)
-
-class UpgradeToDatabaseService(Service, LoggingMixIn, object):
-    """
-    Upgrade resources from a filesystem store to a database store.
-    """
-
-    @classmethod
-    def wrapService(cls, path, service, store, uid=None, gid=None):
-        """
-        Create an L{UpgradeToDatabaseService} if there are still file-based
-        calendar or addressbook homes remaining in the given path.
-
-        @param path: a path pointing at the document root, where the file-based
-            data-store is located.
-        @type path: L{CachingFilePath}
-
-        @param service: the service to wrap.  This service should be started
-            when the upgrade is complete.  (This is accomplished by returning
-            it directly when no upgrade needs to be done, and by adding it to
-            the service hierarchy when the upgrade completes; assuming that the
-            service parent of the resulting service will be set to a
-            L{MultiService} or similar.)
-
-        @param store: the SQL storage service.
-
-        @type service: L{IService}
-
-        @return: a service
-        @rtype: L{IService}
-        """
-        # TODO: TOPPATHS should be computed based on enabled flags in 'store',
-        # not hard coded.
-        for homeType in TOPPATHS:
-            if path.child(homeType).exists():
-                if platform.isMacOSX():
-                    appropriateStoreClass = XattrPropertyStore
-                else:
-                    attrs = xattr.xattr(path.path)
-                    try:
-                        attrs.get('user.should-not-be-set')
-                    except IOError, ioe:
-                        if ioe.errno == errno.ENODATA:
-                            # xattrs are supported and enabled on the filesystem
-                            # where the calendar data lives.  this takes some
-                            # doing (you have to edit fstab), so this means
-                            # we're trying to migrate some 2.x data from a
-                            # previous linux installation.
-                            appropriateStoreClass = XattrPropertyStore
-                        elif ioe.errno == errno.EOPNOTSUPP:
-                            # The operation wasn't supported.  This is what will
-                            # usually happen on a naively configured filesystem,
-                            # so this means we're most likely trying to migrate
-                            # some data from an untarred archive created on an
-                            # OS X installation using xattrs.
-                            appropriateStoreClass = AppleDoubleStore
-                        else:
-                            # No need to check for ENOENT and the like; we just
-                            # checked above to make sure the parent exists.
-                            # Other errors are not anticipated here, so fail
-                            # fast.
-                            raise
-
-                    appropriateStoreClass = AppleDoubleStore
-
-                self = cls(
-                    FileStore(path, None, True, True,
-                              propertyStoreClass=appropriateStoreClass),
-                    store, service, uid=uid, gid=gid,
-                )
-                return self
-        return service
-
-
-    def __init__(self, fileStore, sqlStore, service, uid=None, gid=None):
-        """
-        Initialize the service.
-        """
-        self.wrappedService = service
-        self.fileStore = fileStore
-        self.sqlStore = sqlStore
-        self.uid = uid
-        self.gid = gid
-
-
-    @inlineCallbacks
-    def doMigration(self):
-        """
-        Do the migration.  Called by C{startService}, but a different method
-        because C{startService} should return C{None}, not a L{Deferred}.
-
-        @return: a Deferred which fires when the migration is complete.
-        """
-        self.log_warn("Beginning filesystem -> database upgrade.")
-
-        self.sqlStore.setMigrating(True)
-
-        for homeType, migrateFunc, eachFunc, destFunc, _ignore_topPathName in [
-            ("calendar", migrateCalendarHome,
-                self.fileStore.eachCalendarHome,
-                lambda txn: txn.calendarHomeWithUID,
-                "calendars"),
-            ("addressbook", migrateAddressbookHome,
-                self.fileStore.eachAddressbookHome,
-                lambda txn: txn.addressbookHomeWithUID,
-                "addressbooks")
-            ]:
-            for fileTxn, fileHome in eachFunc():
-                uid = fileHome.uid()
-                self.log_warn("Migrating %s UID %r" % (homeType, uid))
-                sqlTxn = self.sqlStore.newTransaction()
-                homeGetter = destFunc(sqlTxn)
-                if (yield homeGetter(uid, create=False)) is not None:
-                    self.log_warn(
-                        "%s home %r already existed not migrating" % (
-                            homeType, uid))
-                    yield sqlTxn.abort()
-                    yield fileTxn.commit()
-                    continue
-                sqlHome = yield homeGetter(uid, create=True)
-                if sqlHome is None:
-                    raise RuntimeError("THIS SHOULD NOT BE POSSIBLE.")
-                yield migrateFunc(fileHome, sqlHome)
-                yield fileTxn.commit()
-                yield sqlTxn.commit()
-                # FIXME: need a public remove...HomeWithUID() for de-
-                # provisioning
-
-                # Remove file home after migration
-                fileHome._path.remove()
-        for homeType in TOPPATHS:
-            homesPath = self.fileStore._path.child(homeType)
-            if homesPath.isdir():
-                homesPath.remove()
-
-        # Set attachment directory ownership.  FIXME: is this still necessary
-        # since attachments started living outside the database directory
-        # created by initdb?  default permissions might be correct now.
-        sqlAttachmentsPath = self.sqlStore.attachmentsPath
-        if (sqlAttachmentsPath and sqlAttachmentsPath.exists() and
-            (self.uid or self.gid)):
-            uid = self.uid or -1
-            gid = self.gid or -1
-            for fp in sqlAttachmentsPath.walk():
-                os.chown(fp.path, uid, gid)
-
-        self.sqlStore.setMigrating(False) 
-        self.log_warn(
-            "Filesystem upgrade complete, launching database service."
-        )
-
-        # see http://twistedmatrix.com/trac/ticket/4649
-        reactor.callLater(0, self.wrappedService.setServiceParent, self.parent)
-
-
-    def startService(self):
-        """
-        Start the service.
-        """
-        self.doMigration()

Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/migrate.py (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/migrate.py)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/migrate.py	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/migrate.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,196 @@
+# -*- test-case-name: txdav.common.datastore.upgrade.test.test_migrate -*-
+##
+# Copyright (c) 2011 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.
+##
+
+"""
+Migrating from file store to sql store.
+"""
+
+import os
+import errno
+import xattr
+
+from twext.python.log import LoggingMixIn
+from twisted.application.service import Service
+from twisted.internet import reactor
+from twisted.internet.defer import inlineCallbacks
+from twisted.python.runtime import platform
+
+from txdav.caldav.datastore.util import migrateHome as migrateCalendarHome
+from txdav.carddav.datastore.util import migrateHome as migrateAddressbookHome
+from txdav.common.datastore.file import CommonDataStore as FileStore, TOPPATHS
+from txdav.base.propertystore.xattr import PropertyStore as XattrPropertyStore
+from txdav.base.propertystore.appledouble_xattr import (
+    PropertyStore as AppleDoubleStore)
+
+class UpgradeToDatabaseService(Service, LoggingMixIn, object):
+    """
+    Upgrade resources from a filesystem store to a database store.
+    """
+
+    @classmethod
+    def wrapService(cls, path, service, store, uid=None, gid=None):
+        """
+        Create an L{UpgradeToDatabaseService} if there are still file-based
+        calendar or addressbook homes remaining in the given path.
+
+        @param path: a path pointing at the document root, where the file-based
+            data-store is located.
+        @type path: L{CachingFilePath}
+
+        @param service: the service to wrap.  This service should be started
+            when the upgrade is complete.  (This is accomplished by returning
+            it directly when no upgrade needs to be done, and by adding it to
+            the service hierarchy when the upgrade completes; assuming that the
+            service parent of the resulting service will be set to a
+            L{MultiService} or similar.)
+
+        @param store: the SQL storage service.
+
+        @type service: L{IService}
+
+        @return: a service
+        @rtype: L{IService}
+        """
+        # TODO: TOPPATHS should be computed based on enabled flags in 'store',
+        # not hard coded.
+        for homeType in TOPPATHS:
+            if path.child(homeType).exists():
+                if platform.isMacOSX():
+                    appropriateStoreClass = XattrPropertyStore
+                else:
+                    attrs = xattr.xattr(path.path)
+                    try:
+                        attrs.get('user.should-not-be-set')
+                    except IOError, ioe:
+                        if ioe.errno == errno.ENODATA:
+                            # xattrs are supported and enabled on the filesystem
+                            # where the calendar data lives.  this takes some
+                            # doing (you have to edit fstab), so this means
+                            # we're trying to migrate some 2.x data from a
+                            # previous linux installation.
+                            appropriateStoreClass = XattrPropertyStore
+                        elif ioe.errno == errno.EOPNOTSUPP:
+                            # The operation wasn't supported.  This is what will
+                            # usually happen on a naively configured filesystem,
+                            # so this means we're most likely trying to migrate
+                            # some data from an untarred archive created on an
+                            # OS X installation using xattrs.
+                            appropriateStoreClass = AppleDoubleStore
+                        else:
+                            # No need to check for ENOENT and the like; we just
+                            # checked above to make sure the parent exists.
+                            # Other errors are not anticipated here, so fail
+                            # fast.
+                            raise
+
+                    appropriateStoreClass = AppleDoubleStore
+
+                self = cls(
+                    FileStore(path, None, True, True,
+                              propertyStoreClass=appropriateStoreClass),
+                    store, service, uid=uid, gid=gid,
+                )
+                return self
+        return service
+
+
+    def __init__(self, fileStore, sqlStore, service, uid=None, gid=None):
+        """
+        Initialize the service.
+        """
+        self.wrappedService = service
+        self.fileStore = fileStore
+        self.sqlStore = sqlStore
+        self.uid = uid
+        self.gid = gid
+
+
+    @inlineCallbacks
+    def doMigration(self):
+        """
+        Do the migration.  Called by C{startService}, but a different method
+        because C{startService} should return C{None}, not a L{Deferred}.
+
+        @return: a Deferred which fires when the migration is complete.
+        """
+        self.log_warn("Beginning filesystem -> database upgrade.")
+
+        self.sqlStore.setMigrating(True)
+
+        for homeType, migrateFunc, eachFunc, destFunc, _ignore_topPathName in [
+            ("calendar", migrateCalendarHome,
+                self.fileStore.eachCalendarHome,
+                lambda txn: txn.calendarHomeWithUID,
+                "calendars"),
+            ("addressbook", migrateAddressbookHome,
+                self.fileStore.eachAddressbookHome,
+                lambda txn: txn.addressbookHomeWithUID,
+                "addressbooks")
+            ]:
+            for fileTxn, fileHome in eachFunc():
+                uid = fileHome.uid()
+                self.log_warn("Migrating %s UID %r" % (homeType, uid))
+                sqlTxn = self.sqlStore.newTransaction()
+                homeGetter = destFunc(sqlTxn)
+                if (yield homeGetter(uid, create=False)) is not None:
+                    self.log_warn(
+                        "%s home %r already existed not migrating" % (
+                            homeType, uid))
+                    yield sqlTxn.abort()
+                    yield fileTxn.commit()
+                    continue
+                sqlHome = yield homeGetter(uid, create=True)
+                if sqlHome is None:
+                    raise RuntimeError("THIS SHOULD NOT BE POSSIBLE.")
+                yield migrateFunc(fileHome, sqlHome)
+                yield fileTxn.commit()
+                yield sqlTxn.commit()
+                # FIXME: need a public remove...HomeWithUID() for de-
+                # provisioning
+
+                # Remove file home after migration
+                fileHome._path.remove()
+        for homeType in TOPPATHS:
+            homesPath = self.fileStore._path.child(homeType)
+            if homesPath.isdir():
+                homesPath.remove()
+
+        # Set attachment directory ownership.  FIXME: is this still necessary
+        # since attachments started living outside the database directory
+        # created by initdb?  default permissions might be correct now.
+        sqlAttachmentsPath = self.sqlStore.attachmentsPath
+        if (sqlAttachmentsPath and sqlAttachmentsPath.exists() and
+            (self.uid or self.gid)):
+            uid = self.uid or -1
+            gid = self.gid or -1
+            for fp in sqlAttachmentsPath.walk():
+                os.chown(fp.path, uid, gid)
+
+        self.sqlStore.setMigrating(False) 
+        self.log_warn(
+            "Filesystem upgrade complete, launching database service."
+        )
+
+        # see http://twistedmatrix.com/trac/ticket/4649
+        reactor.callLater(0, self.wrappedService.setServiceParent, self.parent)
+
+
+    def startService(self):
+        """
+        Start the service.
+        """
+        self.doMigration()

Deleted: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/__init__.py
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/__init__.py	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/__init__.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,16 +0,0 @@
-##
-# Copyright (c) 2011 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.
-##
-

Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/__init__.py (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/__init__.py)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/__init__.py	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/__init__.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,16 @@
+##
+# Copyright (c) 2011 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.
+##
+

Deleted: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/__init__.py
===================================================================
Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/__init__.py (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/test/__init__.py)
===================================================================
Deleted: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema1/current.sql
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/test/fake_schema1/current.sql	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema1/current.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,28 +0,0 @@
-----
--- Copyright (c) 2011 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.
-----
-
---------------------
--- Schema Version --
---------------------
-
-create table CALENDARSERVER (
-  NAME                          varchar(255),
-  VALUE                         varchar(255),
-  unique(NAME)
-);
-
--- Current version of the schema
-insert into CALENDARSERVER values ('VERSION', '4');

Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema1/current.sql (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/test/fake_schema1/current.sql)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema1/current.sql	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema1/current.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,28 @@
+----
+-- Copyright (c) 2011 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.
+----
+
+--------------------
+-- Schema Version --
+--------------------
+
+create table CALENDARSERVER (
+  NAME                          varchar(255),
+  VALUE                         varchar(255),
+  unique(NAME)
+);
+
+-- Current version of the schema
+insert into CALENDARSERVER values ('VERSION', '4');

Deleted: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema1/upgrades/fake_dialect/upgrade_from_3_to_4.sql
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/test/fake_schema1/upgrades/fake_dialect/upgrade_from_3_to_4.sql	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema1/upgrades/fake_dialect/upgrade_from_3_to_4.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,24 +0,0 @@
-----
--- Copyright (c) 2011 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.
-----
-
--------------------------------------------------
--- Upgrade database schema from VERSION 3 to 4 --
--------------------------------------------------
-
-
--- Now update the version
-update CALENDARSERVER set VALUE = '4' where NAME = 'VERSION';
-

Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema1/upgrades/fake_dialect/upgrade_from_3_to_4.sql (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/test/fake_schema1/upgrades/fake_dialect/upgrade_from_3_to_4.sql)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema1/upgrades/fake_dialect/upgrade_from_3_to_4.sql	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema1/upgrades/fake_dialect/upgrade_from_3_to_4.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,24 @@
+----
+-- Copyright (c) 2011 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.
+----
+
+-------------------------------------------------
+-- Upgrade database schema from VERSION 3 to 4 --
+-------------------------------------------------
+
+
+-- Now update the version
+update CALENDARSERVER set VALUE = '4' where NAME = 'VERSION';
+

Deleted: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/current.sql
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/test/fake_schema2/current.sql	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/current.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,28 +0,0 @@
-----
--- Copyright (c) 2011 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.
-----
-
---------------------
--- Schema Version --
---------------------
-
-create table CALENDARSERVER (
-  NAME                          varchar(255),
-  VALUE                         varchar(255),
-  unique(NAME)
-);
-
--- Current version of the schema
-insert into CALENDARSERVER values ('VERSION', '5');

Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/current.sql (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/test/fake_schema2/current.sql)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/current.sql	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/current.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,28 @@
+----
+-- Copyright (c) 2011 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.
+----
+
+--------------------
+-- Schema Version --
+--------------------
+
+create table CALENDARSERVER (
+  NAME                          varchar(255),
+  VALUE                         varchar(255),
+  unique(NAME)
+);
+
+-- Current version of the schema
+insert into CALENDARSERVER values ('VERSION', '5');

Deleted: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_3_to_4.sql
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_3_to_4.sql	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_3_to_4.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,24 +0,0 @@
-----
--- Copyright (c) 2011 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.
-----
-
--------------------------------------------------
--- Upgrade database schema from VERSION 3 to 4 --
--------------------------------------------------
-
-
--- Now update the version
-update CALENDARSERVER set VALUE = '4' where NAME = 'VERSION';
-

Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_3_to_4.sql (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_3_to_4.sql)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_3_to_4.sql	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_3_to_4.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,24 @@
+----
+-- Copyright (c) 2011 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.
+----
+
+-------------------------------------------------
+-- Upgrade database schema from VERSION 3 to 4 --
+-------------------------------------------------
+
+
+-- Now update the version
+update CALENDARSERVER set VALUE = '4' where NAME = 'VERSION';
+

Deleted: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_3_to_5.sql
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_3_to_5.sql	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_3_to_5.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,24 +0,0 @@
-----
--- Copyright (c) 2011 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.
-----
-
--------------------------------------------------
--- Upgrade database schema from VERSION 3 to 5 --
--------------------------------------------------
-
-
--- Now update the version
-update CALENDARSERVER set VALUE = '5' where NAME = 'VERSION';
-

Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_3_to_5.sql (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_3_to_5.sql)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_3_to_5.sql	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_3_to_5.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,24 @@
+----
+-- Copyright (c) 2011 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.
+----
+
+-------------------------------------------------
+-- Upgrade database schema from VERSION 3 to 5 --
+-------------------------------------------------
+
+
+-- Now update the version
+update CALENDARSERVER set VALUE = '5' where NAME = 'VERSION';
+

Deleted: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_4_to_5.sql
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_4_to_5.sql	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_4_to_5.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,24 +0,0 @@
-----
--- Copyright (c) 2011 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.
-----
-
--------------------------------------------------
--- Upgrade database schema from VERSION 4 to 5 --
--------------------------------------------------
-
-
--- Now update the version
-update CALENDARSERVER set VALUE = '5' where NAME = 'VERSION';
-

Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_4_to_5.sql (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_4_to_5.sql)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_4_to_5.sql	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema2/upgrades/fake_dialect/upgrade_from_4_to_5.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,24 @@
+----
+-- Copyright (c) 2011 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.
+----
+
+-------------------------------------------------
+-- Upgrade database schema from VERSION 4 to 5 --
+-------------------------------------------------
+
+
+-- Now update the version
+update CALENDARSERVER set VALUE = '5' where NAME = 'VERSION';
+

Deleted: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/current.sql
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/test/fake_schema3/current.sql	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/current.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,28 +0,0 @@
-----
--- Copyright (c) 2011 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.
-----
-
---------------------
--- Schema Version --
---------------------
-
-create table CALENDARSERVER (
-  NAME                          varchar(255),
-  VALUE                         varchar(255),
-  unique(NAME)
-);
-
--- Current version of the schema
-insert into CALENDARSERVER values ('VERSION', '5');

Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/current.sql (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/test/fake_schema3/current.sql)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/current.sql	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/current.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,28 @@
+----
+-- Copyright (c) 2011 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.
+----
+
+--------------------
+-- Schema Version --
+--------------------
+
+create table CALENDARSERVER (
+  NAME                          varchar(255),
+  VALUE                         varchar(255),
+  unique(NAME)
+);
+
+-- Current version of the schema
+insert into CALENDARSERVER values ('VERSION', '5');

Deleted: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/upgrades/fake_dialect/upgrade_from_3_to_4.sql
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/test/fake_schema3/upgrades/fake_dialect/upgrade_from_3_to_4.sql	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/upgrades/fake_dialect/upgrade_from_3_to_4.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,24 +0,0 @@
-----
--- Copyright (c) 2011 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.
-----
-
--------------------------------------------------
--- Upgrade database schema from VERSION 3 to 4 --
--------------------------------------------------
-
-
--- Now update the version
-update CALENDARSERVER set VALUE = '4' where NAME = 'VERSION';
-

Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/upgrades/fake_dialect/upgrade_from_3_to_4.sql (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/test/fake_schema3/upgrades/fake_dialect/upgrade_from_3_to_4.sql)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/upgrades/fake_dialect/upgrade_from_3_to_4.sql	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/upgrades/fake_dialect/upgrade_from_3_to_4.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,24 @@
+----
+-- Copyright (c) 2011 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.
+----
+
+-------------------------------------------------
+-- Upgrade database schema from VERSION 3 to 4 --
+-------------------------------------------------
+
+
+-- Now update the version
+update CALENDARSERVER set VALUE = '4' where NAME = 'VERSION';
+

Deleted: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/upgrades/fake_dialect/upgrade_from_4_to_5.sql
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/test/fake_schema3/upgrades/fake_dialect/upgrade_from_4_to_5.sql	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/upgrades/fake_dialect/upgrade_from_4_to_5.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,24 +0,0 @@
-----
--- Copyright (c) 2011 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.
-----
-
--------------------------------------------------
--- Upgrade database schema from VERSION 4 to 5 --
--------------------------------------------------
-
-
--- Now update the version
-update CALENDARSERVER set VALUE = '5' where NAME = 'VERSION';
-

Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/upgrades/fake_dialect/upgrade_from_4_to_5.sql (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/test/fake_schema3/upgrades/fake_dialect/upgrade_from_4_to_5.sql)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/upgrades/fake_dialect/upgrade_from_4_to_5.sql	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/fake_schema3/upgrades/fake_dialect/upgrade_from_4_to_5.sql	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,24 @@
+----
+-- Copyright (c) 2011 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.
+----
+
+-------------------------------------------------
+-- Upgrade database schema from VERSION 4 to 5 --
+-------------------------------------------------
+
+
+-- Now update the version
+update CALENDARSERVER set VALUE = '5' where NAME = 'VERSION';
+

Deleted: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/test_upgrade.py
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/test/test_upgrade.py	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/test_upgrade.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,249 +0,0 @@
-##
-# Copyright (c) 2010-2011 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.
-##
-
-"""
-Tests for L{txdav.common.datastore.upgrade.sql.upgrade}.
-"""
-
-from twext.enterprise.ienterprise import ORACLE_DIALECT, POSTGRES_DIALECT
-from twisted.internet.defer import inlineCallbacks, returnValue
-from twisted.python.modules import getModule
-from twisted.trial.unittest import TestCase
-from txdav.common.datastore.test.util import theStoreBuilder, StubNotifierFactory
-from txdav.common.datastore.upgrade.sql.upgrade import UpgradeDatabaseSchemaService,\
-    UpgradeDatabaseDataService
-import re
-
-class SchemaUpgradeTests(TestCase):
-    """
-    Tests for L{UpgradeDatabaseSchemaService}.
-    """
-
-    def _getSchemaVersion(self, fp, versionKey):
-        schema = fp.getContent()
-        found = re.search("insert into CALENDARSERVER values \('%s', '(\d)+'\);" % (versionKey,), schema)
-        if found is None:
-            if versionKey == "VERSION":
-                self.fail("Could not determine schema version for: %s" % (fp,))
-            else:
-                return 1
-        return int(found.group(1))
-
-    def test_scanUpgradeFiles(self):
-        
-        upgrader = UpgradeDatabaseSchemaService(None, None)
-
-        upgrader.schemaLocation = getModule(__name__).filePath.sibling("fake_schema1")
-        files = upgrader.scanForUpgradeFiles("fake_dialect")
-        self.assertEqual(files, 
-            [(3, 4, upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_3_to_4.sql"))],
-        )
-
-        upgrader.schemaLocation = getModule(__name__).filePath.sibling("fake_schema2")
-        files = upgrader.scanForUpgradeFiles("fake_dialect")
-        self.assertEqual(files, 
-            [
-                (3, 4, upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_3_to_4.sql")),
-                (3, 5, upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_3_to_5.sql")),
-                (4, 5, upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_4_to_5.sql")),
-            ]
-        )
-
-    def test_determineUpgradeSequence(self):
-        
-        upgrader = UpgradeDatabaseSchemaService(None, None)
-
-        upgrader.schemaLocation = getModule(__name__).filePath.sibling("fake_schema1")
-        files = upgrader.scanForUpgradeFiles("fake_dialect")
-        upgrades = upgrader.determineUpgradeSequence(3, 4, files, "fake_dialect")
-        self.assertEqual(upgrades, 
-            [upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_3_to_4.sql")],
-        )
-        self.assertRaises(RuntimeError, upgrader.determineUpgradeSequence, 3, 5, files, "fake_dialect")
-
-        upgrader.schemaLocation = getModule(__name__).filePath.sibling("fake_schema2")
-        files = upgrader.scanForUpgradeFiles("fake_dialect")
-        upgrades = upgrader.determineUpgradeSequence(3, 5, files, "fake_dialect")
-        self.assertEqual(upgrades, 
-            [upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_3_to_5.sql")]
-        )
-        upgrades = upgrader.determineUpgradeSequence(4, 5, files, "fake_dialect")
-        self.assertEqual(upgrades, 
-            [upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_4_to_5.sql")]
-        )
-
-        upgrader.schemaLocation = getModule(__name__).filePath.sibling("fake_schema3")
-        files = upgrader.scanForUpgradeFiles("fake_dialect")
-        upgrades = upgrader.determineUpgradeSequence(3, 5, files, "fake_dialect")
-        self.assertEqual(upgrades, 
-            [
-                upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_3_to_4.sql"),
-                upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_4_to_5.sql"),
-            ]
-        )
-
-    def test_upgradeAvailability(self):
-        """
-        Make sure that each old schema has a valid upgrade path to the current one.
-        """
-        
-        for dialect in (POSTGRES_DIALECT, ORACLE_DIALECT,):
-            upgrader = UpgradeDatabaseSchemaService(None, None)
-            files = upgrader.scanForUpgradeFiles(dialect)
-
-            current_version = self._getSchemaVersion(upgrader.schemaLocation.child("current.sql"), "VERSION")
-            
-            for child in upgrader.schemaLocation.child("old").globChildren("*.sql"):
-                old_version = self._getSchemaVersion(child, "VERSION")
-                upgrades = upgrader.determineUpgradeSequence(old_version, current_version, files, dialect)
-                self.assertNotEqual(len(upgrades), 0)
-
-#    def test_upgradeDataAvailability(self):
-#        """
-#        Make sure that each upgrade file has a valid data upgrade file or None.
-#        """
-#        
-#        for dialect in (POSTGRES_DIALECT, ORACLE_DIALECT,):
-#            upgrader = UpgradeDatabaseSchemaService(None, None)
-#            files = upgrader.scanForUpgradeFiles(dialect)
-#            for _ignore_from, _ignore_to, fp in files:
-#                result = upgrader.getDataUpgrade(fp)
-#                if result is not None:
-#                    self.assertIsInstance(result, types.FunctionType)
-
-    @inlineCallbacks
-    def test_dbSchemaUpgrades(self):
-        """
-        This does a full DB test of all possible upgrade paths. For each old schema, it loads it into the DB
-        then runs the upgrade service. This ensures all the upgrade.sql files work correctly - at least for
-        postgres.
-        """
-
-        store = yield theStoreBuilder.buildStore(
-            self, StubNotifierFactory()
-        )
-
-        @inlineCallbacks
-        def _loadOldSchema(path):
-            """
-            Use the postgres schema mechanism to do tests under a separate "namespace"
-            in postgres that we can quickly wipe clean afterwards.
-            """
-            startTxn = store.newTransaction("test_dbUpgrades")        
-            yield startTxn.execSQL("create schema test_dbUpgrades;")
-            yield startTxn.execSQL("set search_path to test_dbUpgrades;")
-            yield startTxn.execSQL(path.getContent())
-            yield startTxn.commit()
-
-        @inlineCallbacks
-        def _loadVersion():
-            startTxn = store.newTransaction("test_dbUpgrades")        
-            new_version = yield startTxn.execSQL("select value from calendarserver where name = 'VERSION';")
-            yield startTxn.commit()
-            returnValue(int(new_version[0][0]))
-
-        @inlineCallbacks
-        def _unloadOldSchema():
-            startTxn = store.newTransaction("test_dbUpgrades")        
-            yield startTxn.execSQL("set search_path to public;")
-            yield startTxn.execSQL("drop schema test_dbUpgrades cascade;")
-            yield startTxn.commit()
-
-        @inlineCallbacks
-        def _cleanupOldSchema():
-            startTxn = store.newTransaction("test_dbUpgrades")        
-            yield startTxn.execSQL("set search_path to public;")
-            yield startTxn.execSQL("drop schema if exists test_dbUpgrades cascade;")
-            yield startTxn.commit()
-
-        self.addCleanup(_cleanupOldSchema)
-
-        test_upgrader = UpgradeDatabaseSchemaService(None, None)
-        expected_version = self._getSchemaVersion(test_upgrader.schemaLocation.child("current.sql"), "VERSION")
-        for child in test_upgrader.schemaLocation.child("old").globChildren("*.sql"):
-            upgrader = UpgradeDatabaseSchemaService(store, None)
-            yield _loadOldSchema(child)
-            yield upgrader.databaseUpgrade()
-            new_version = yield _loadVersion()
-            yield _unloadOldSchema()
-
-            self.assertEqual(new_version, expected_version)
-
-    @inlineCallbacks
-    def test_dbDataUpgrades(self):
-        """
-        This does a full DB test of all possible data upgrade paths. For each old schema, it loads it into the DB
-        then runs the data upgrade service. This ensures all the upgrade_XX.py files work correctly - at least for
-        postgres.
-        
-        TODO: this currently does not create any calendar data to test with. It simply runs the upgrade on an empty
-        store.
-        """
-
-        store = yield theStoreBuilder.buildStore(
-            self, StubNotifierFactory()
-        )
-
-        @inlineCallbacks
-        def _loadOldData(path, oldVersion):
-            """
-            Use the postgres schema mechanism to do tests under a separate "namespace"
-            in postgres that we can quickly wipe clean afterwards.
-            """
-            startTxn = store.newTransaction("test_dbUpgrades")        
-            yield startTxn.execSQL("create schema test_dbUpgrades;")
-            yield startTxn.execSQL("set search_path to test_dbUpgrades;")
-            yield startTxn.execSQL(path.getContent())
-            yield startTxn.execSQL("update CALENDARSERVER set VALUE = '%s' where NAME = 'CALENDAR-DATAVERSION';" % (oldVersion,))
-            yield startTxn.commit()
-
-        @inlineCallbacks
-        def _loadVersion():
-            startTxn = store.newTransaction("test_dbUpgrades")        
-            new_version = yield startTxn.execSQL("select value from calendarserver where name = 'CALENDAR-DATAVERSION';")
-            yield startTxn.commit()
-            returnValue(int(new_version[0][0]))
-
-        @inlineCallbacks
-        def _unloadOldData():
-            startTxn = store.newTransaction("test_dbUpgrades")        
-            yield startTxn.execSQL("set search_path to public;")
-            yield startTxn.execSQL("drop schema test_dbUpgrades cascade;")
-            yield startTxn.commit()
-
-        @inlineCallbacks
-        def _cleanupOldData():
-            startTxn = store.newTransaction("test_dbUpgrades")        
-            yield startTxn.execSQL("set search_path to public;")
-            yield startTxn.execSQL("drop schema if exists test_dbUpgrades cascade;")
-            yield startTxn.commit()
-
-        self.addCleanup(_cleanupOldData)
-
-        test_upgrader = UpgradeDatabaseSchemaService(None, None)
-        expected_version = self._getSchemaVersion(test_upgrader.schemaLocation.child("current.sql"), "CALENDAR-DATAVERSION")
-        versions = set()
-        for child in test_upgrader.schemaLocation.child("old").globChildren("*.sql"):
-            versions.add(self._getSchemaVersion(child, "CALENDAR-DATAVERSION"))
-
-        for oldVersion in sorted(versions):
-            upgrader = UpgradeDatabaseDataService(store, None)
-            yield _loadOldData(test_upgrader.schemaLocation.child("current.sql"), oldVersion)
-            yield upgrader.databaseUpgrade()
-            new_version = yield _loadVersion()
-            yield _unloadOldData()
-
-            self.assertEqual(new_version, expected_version)

Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/test_upgrade.py (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/test/test_upgrade.py)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/test_upgrade.py	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/test/test_upgrade.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,249 @@
+##
+# Copyright (c) 2010-2011 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.
+##
+
+"""
+Tests for L{txdav.common.datastore.upgrade.sql.upgrade}.
+"""
+
+from twext.enterprise.ienterprise import ORACLE_DIALECT, POSTGRES_DIALECT
+from twisted.internet.defer import inlineCallbacks, returnValue
+from twisted.python.modules import getModule
+from twisted.trial.unittest import TestCase
+from txdav.common.datastore.test.util import theStoreBuilder, StubNotifierFactory
+from txdav.common.datastore.upgrade.sql.upgrade import UpgradeDatabaseSchemaService,\
+    UpgradeDatabaseDataService
+import re
+
+class SchemaUpgradeTests(TestCase):
+    """
+    Tests for L{UpgradeDatabaseSchemaService}.
+    """
+
+    def _getSchemaVersion(self, fp, versionKey):
+        schema = fp.getContent()
+        found = re.search("insert into CALENDARSERVER values \('%s', '(\d)+'\);" % (versionKey,), schema)
+        if found is None:
+            if versionKey == "VERSION":
+                self.fail("Could not determine schema version for: %s" % (fp,))
+            else:
+                return 1
+        return int(found.group(1))
+
+    def test_scanUpgradeFiles(self):
+        
+        upgrader = UpgradeDatabaseSchemaService(None, None)
+
+        upgrader.schemaLocation = getModule(__name__).filePath.sibling("fake_schema1")
+        files = upgrader.scanForUpgradeFiles("fake_dialect")
+        self.assertEqual(files, 
+            [(3, 4, upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_3_to_4.sql"))],
+        )
+
+        upgrader.schemaLocation = getModule(__name__).filePath.sibling("fake_schema2")
+        files = upgrader.scanForUpgradeFiles("fake_dialect")
+        self.assertEqual(files, 
+            [
+                (3, 4, upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_3_to_4.sql")),
+                (3, 5, upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_3_to_5.sql")),
+                (4, 5, upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_4_to_5.sql")),
+            ]
+        )
+
+    def test_determineUpgradeSequence(self):
+        
+        upgrader = UpgradeDatabaseSchemaService(None, None)
+
+        upgrader.schemaLocation = getModule(__name__).filePath.sibling("fake_schema1")
+        files = upgrader.scanForUpgradeFiles("fake_dialect")
+        upgrades = upgrader.determineUpgradeSequence(3, 4, files, "fake_dialect")
+        self.assertEqual(upgrades, 
+            [upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_3_to_4.sql")],
+        )
+        self.assertRaises(RuntimeError, upgrader.determineUpgradeSequence, 3, 5, files, "fake_dialect")
+
+        upgrader.schemaLocation = getModule(__name__).filePath.sibling("fake_schema2")
+        files = upgrader.scanForUpgradeFiles("fake_dialect")
+        upgrades = upgrader.determineUpgradeSequence(3, 5, files, "fake_dialect")
+        self.assertEqual(upgrades, 
+            [upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_3_to_5.sql")]
+        )
+        upgrades = upgrader.determineUpgradeSequence(4, 5, files, "fake_dialect")
+        self.assertEqual(upgrades, 
+            [upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_4_to_5.sql")]
+        )
+
+        upgrader.schemaLocation = getModule(__name__).filePath.sibling("fake_schema3")
+        files = upgrader.scanForUpgradeFiles("fake_dialect")
+        upgrades = upgrader.determineUpgradeSequence(3, 5, files, "fake_dialect")
+        self.assertEqual(upgrades, 
+            [
+                upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_3_to_4.sql"),
+                upgrader.schemaLocation.child("upgrades").child("fake_dialect").child("upgrade_from_4_to_5.sql"),
+            ]
+        )
+
+    def test_upgradeAvailability(self):
+        """
+        Make sure that each old schema has a valid upgrade path to the current one.
+        """
+        
+        for dialect in (POSTGRES_DIALECT, ORACLE_DIALECT,):
+            upgrader = UpgradeDatabaseSchemaService(None, None)
+            files = upgrader.scanForUpgradeFiles(dialect)
+
+            current_version = self._getSchemaVersion(upgrader.schemaLocation.child("current.sql"), "VERSION")
+            
+            for child in upgrader.schemaLocation.child("old").globChildren("*.sql"):
+                old_version = self._getSchemaVersion(child, "VERSION")
+                upgrades = upgrader.determineUpgradeSequence(old_version, current_version, files, dialect)
+                self.assertNotEqual(len(upgrades), 0)
+
+#    def test_upgradeDataAvailability(self):
+#        """
+#        Make sure that each upgrade file has a valid data upgrade file or None.
+#        """
+#        
+#        for dialect in (POSTGRES_DIALECT, ORACLE_DIALECT,):
+#            upgrader = UpgradeDatabaseSchemaService(None, None)
+#            files = upgrader.scanForUpgradeFiles(dialect)
+#            for _ignore_from, _ignore_to, fp in files:
+#                result = upgrader.getDataUpgrade(fp)
+#                if result is not None:
+#                    self.assertIsInstance(result, types.FunctionType)
+
+    @inlineCallbacks
+    def test_dbSchemaUpgrades(self):
+        """
+        This does a full DB test of all possible upgrade paths. For each old schema, it loads it into the DB
+        then runs the upgrade service. This ensures all the upgrade.sql files work correctly - at least for
+        postgres.
+        """
+
+        store = yield theStoreBuilder.buildStore(
+            self, StubNotifierFactory()
+        )
+
+        @inlineCallbacks
+        def _loadOldSchema(path):
+            """
+            Use the postgres schema mechanism to do tests under a separate "namespace"
+            in postgres that we can quickly wipe clean afterwards.
+            """
+            startTxn = store.newTransaction("test_dbUpgrades")        
+            yield startTxn.execSQL("create schema test_dbUpgrades;")
+            yield startTxn.execSQL("set search_path to test_dbUpgrades;")
+            yield startTxn.execSQL(path.getContent())
+            yield startTxn.commit()
+
+        @inlineCallbacks
+        def _loadVersion():
+            startTxn = store.newTransaction("test_dbUpgrades")        
+            new_version = yield startTxn.execSQL("select value from calendarserver where name = 'VERSION';")
+            yield startTxn.commit()
+            returnValue(int(new_version[0][0]))
+
+        @inlineCallbacks
+        def _unloadOldSchema():
+            startTxn = store.newTransaction("test_dbUpgrades")        
+            yield startTxn.execSQL("set search_path to public;")
+            yield startTxn.execSQL("drop schema test_dbUpgrades cascade;")
+            yield startTxn.commit()
+
+        @inlineCallbacks
+        def _cleanupOldSchema():
+            startTxn = store.newTransaction("test_dbUpgrades")        
+            yield startTxn.execSQL("set search_path to public;")
+            yield startTxn.execSQL("drop schema if exists test_dbUpgrades cascade;")
+            yield startTxn.commit()
+
+        self.addCleanup(_cleanupOldSchema)
+
+        test_upgrader = UpgradeDatabaseSchemaService(None, None)
+        expected_version = self._getSchemaVersion(test_upgrader.schemaLocation.child("current.sql"), "VERSION")
+        for child in test_upgrader.schemaLocation.child("old").globChildren("*.sql"):
+            upgrader = UpgradeDatabaseSchemaService(store, None)
+            yield _loadOldSchema(child)
+            yield upgrader.databaseUpgrade()
+            new_version = yield _loadVersion()
+            yield _unloadOldSchema()
+
+            self.assertEqual(new_version, expected_version)
+
+    @inlineCallbacks
+    def test_dbDataUpgrades(self):
+        """
+        This does a full DB test of all possible data upgrade paths. For each old schema, it loads it into the DB
+        then runs the data upgrade service. This ensures all the upgrade_XX.py files work correctly - at least for
+        postgres.
+        
+        TODO: this currently does not create any calendar data to test with. It simply runs the upgrade on an empty
+        store.
+        """
+
+        store = yield theStoreBuilder.buildStore(
+            self, StubNotifierFactory()
+        )
+
+        @inlineCallbacks
+        def _loadOldData(path, oldVersion):
+            """
+            Use the postgres schema mechanism to do tests under a separate "namespace"
+            in postgres that we can quickly wipe clean afterwards.
+            """
+            startTxn = store.newTransaction("test_dbUpgrades")        
+            yield startTxn.execSQL("create schema test_dbUpgrades;")
+            yield startTxn.execSQL("set search_path to test_dbUpgrades;")
+            yield startTxn.execSQL(path.getContent())
+            yield startTxn.execSQL("update CALENDARSERVER set VALUE = '%s' where NAME = 'CALENDAR-DATAVERSION';" % (oldVersion,))
+            yield startTxn.commit()
+
+        @inlineCallbacks
+        def _loadVersion():
+            startTxn = store.newTransaction("test_dbUpgrades")        
+            new_version = yield startTxn.execSQL("select value from calendarserver where name = 'CALENDAR-DATAVERSION';")
+            yield startTxn.commit()
+            returnValue(int(new_version[0][0]))
+
+        @inlineCallbacks
+        def _unloadOldData():
+            startTxn = store.newTransaction("test_dbUpgrades")        
+            yield startTxn.execSQL("set search_path to public;")
+            yield startTxn.execSQL("drop schema test_dbUpgrades cascade;")
+            yield startTxn.commit()
+
+        @inlineCallbacks
+        def _cleanupOldData():
+            startTxn = store.newTransaction("test_dbUpgrades")        
+            yield startTxn.execSQL("set search_path to public;")
+            yield startTxn.execSQL("drop schema if exists test_dbUpgrades cascade;")
+            yield startTxn.commit()
+
+        self.addCleanup(_cleanupOldData)
+
+        test_upgrader = UpgradeDatabaseSchemaService(None, None)
+        expected_version = self._getSchemaVersion(test_upgrader.schemaLocation.child("current.sql"), "CALENDAR-DATAVERSION")
+        versions = set()
+        for child in test_upgrader.schemaLocation.child("old").globChildren("*.sql"):
+            versions.add(self._getSchemaVersion(child, "CALENDAR-DATAVERSION"))
+
+        for oldVersion in sorted(versions):
+            upgrader = UpgradeDatabaseDataService(store, None)
+            yield _loadOldData(test_upgrader.schemaLocation.child("current.sql"), oldVersion)
+            yield upgrader.databaseUpgrade()
+            new_version = yield _loadVersion()
+            yield _unloadOldData()
+
+            self.assertEqual(new_version, expected_version)

Deleted: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrade.py
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/upgrade.py	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrade.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,345 +0,0 @@
-# -*- test-case-name: txdav.common.datastore.upgrade.sql.test -*-
-##
-# Copyright (c) 2010-2011 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.
-##
-
-"""
-Utilities, mostly related to upgrading, common to calendar and addresbook
-data stores.
-"""
-
-import re
-
-from twext.python.log import LoggingMixIn
-
-from twisted.application.service import Service
-from twisted.internet import reactor
-from twisted.internet.defer import inlineCallbacks, returnValue
-from twisted.python.modules import getModule
-from twisted.python.reflect import namedObject
-
-class UpgradeDatabaseCoreService(Service, LoggingMixIn, object):
-    """
-    Base class for either schema or data upgrades on the database.
-
-    upgrade files in sql syntax that we can execute against the database to
-    accomplish the upgrade.
-
-    @ivar sqlStore: The store to operate on.
-
-    @type sqlStore: L{txdav.idav.IDataStore}
-
-    @ivar wrappedService: Wrapped L{IService} that will be started after this
-        L{UpgradeDatabaseSchemaService}'s work is done and the database schema
-        of C{sqlStore} is fully upgraded.  This may also be specified as
-        C{None}, in which case no service will be started.
-
-    @type wrappedService: L{IService} or C{NoneType}
-    """
-
-    @classmethod
-    def wrapService(cls, service, store, uid=None, gid=None):
-        """
-        Create an L{UpgradeDatabaseSchemaService} when starting the database
-        so we can check the schema version and do any upgrades.
-
-        @param service: the service to wrap.  This service should be started
-            when the upgrade is complete.  (This is accomplished by returning
-            it directly when no upgrade needs to be done, and by adding it to
-            the service hierarchy when the upgrade completes; assuming that the
-            service parent of the resulting service will be set to a
-            L{MultiService} or similar.)
-
-        @param store: the SQL storage service.
-
-        @type service: L{IService}
-
-        @type store: L{txdav.idav.IDataStore}
-
-        @return: a service
-        @rtype: L{IService}
-        """
-        return cls(store, service, uid=uid, gid=gid,)
-
-    def __init__(self, sqlStore, service, uid=None, gid=None):
-        """
-        Initialize the service.
-        """
-        self.wrappedService = service
-        self.sqlStore = sqlStore
-        self.uid = uid
-        self.gid = gid
-        self.schemaLocation = getModule(__name__).filePath.parent().parent().sibling("sql_schema")
-        self.pyLocation = getModule(__name__).filePath.parent()
-        
-        self.versionKey = None
-        self.versionDescriptor = ""
-        self.upgradeFileSuffix = ""
-        self.defaultKeyValue = None
-        
-    def startService(self):
-        """
-        Start the service.
-        """
-        self.databaseUpgrade()
-
-    @inlineCallbacks
-    def databaseUpgrade(self):
-        """
-        Do a database schema upgrade.
-        """
-        self.log_warn("Beginning database %s check." % (self.versionDescriptor,))
-        
-        # Retrieve information from schema and database
-        dialect, required_version, actual_version = yield self.getVersions()
-
-        if required_version == actual_version:
-            self.log_warn("%s version check complete: no upgrade needed." % (self.versionDescriptor.capitalize(),))
-        elif required_version < actual_version:
-            msg = "Actual %s version %s is more recent than the expected version %s. The service cannot be started" % (
-                self.versionDescriptor, actual_version, required_version,
-            )
-            self.log_error(msg)
-            raise RuntimeError(msg)
-        else:
-            yield self.upgradeVersion(actual_version, required_version, dialect)
-            
-        self.log_warn("Database %s check complete." % (self.versionDescriptor,))
-
-        # see http://twistedmatrix.com/trac/ticket/4649
-        if self.wrappedService is not None:
-            reactor.callLater(0, self.wrappedService.setServiceParent, self.parent)
-    
-    @inlineCallbacks
-    def getVersions(self):
-        """
-        Extract the expected version from the database schema and get the actual version in the current
-        database, along with the DB dialect.
-        """
-
-        # Retrieve the version number from the schema file
-        current_schema = self.schemaLocation.child("current.sql").getContent()
-        found = re.search("insert into CALENDARSERVER values \('%s', '(\d)+'\);" % (self.versionKey,), current_schema)
-        if found is None:
-            msg = "Schema is missing required database key %s insert statement: %s" % (self.versionKey, current_schema,)
-            self.log_error(msg)
-            raise RuntimeError(msg)
-        else:
-            required_version = int(found.group(1))
-            self.log_warn("Required database key %s: %s." % (self.versionKey, required_version,))
-        
-        # Get the schema version in the current database
-        sqlTxn = self.sqlStore.newTransaction()
-        dialect = sqlTxn.dialect
-        try:
-            actual_version = yield sqlTxn.calendarserverValue(self.versionKey)
-            actual_version = int(actual_version)
-            yield sqlTxn.commit()
-        except RuntimeError, ValueError:
-            self.log_error("Database key %s cannot be determined." % (self.versionKey,))
-            yield sqlTxn.abort()
-            if self.defaultKeyValue is None:
-                raise
-            else:
-                actual_version = self.defaultKeyValue
-
-        self.log_warn("Actual database key %s: %s." % (self.versionKey, actual_version,))
-
-        returnValue((dialect, required_version, actual_version,))
-
-    @inlineCallbacks
-    def upgradeVersion(self, fromVersion, toVersion, dialect):
-        """
-        Update the database from one version to another (the current one). Do this by
-        looking for upgrade_from_X_to_Y.sql files that cover the full range of upgrades.
-        """
-
-        self.log_warn("Starting %s upgrade from version %d to %d." % (self.versionDescriptor, fromVersion, toVersion,))
-        
-        # Scan for all possible upgrade files - returned sorted
-        files = self.scanForUpgradeFiles(dialect)
-        
-        # Determine upgrade sequence and run each upgrade
-        upgrades = self.determineUpgradeSequence(fromVersion, toVersion, files, dialect)
-
-        # Use one transaction for the entire set of upgrades
-        try:
-            for fp in upgrades:
-                yield self.applyUpgrade(fp)
-        except RuntimeError:
-            self.log_error("Database %s upgrade failed using: %s" % (self.versionDescriptor, fp.basename(),))
-            raise
-
-        self.log_warn("%s upgraded from version %d to %d." % (self.versionDescriptor.capitalize(), fromVersion, toVersion,))
-
-    def getPathToUpgrades(self, dialect):
-        """
-        Return the path where appropriate upgrade files can be found. 
-        """
-        raise NotImplementedError
-
-    def scanForUpgradeFiles(self, dialect):
-        """
-        Scan for upgrade files with the require name.
-        """
-        
-        fp = self.getPathToUpgrades(dialect)
-        upgrades = []
-        regex = re.compile("upgrade_from_(\d)+_to_(\d)+%s" % (self.upgradeFileSuffix,))
-        for child in fp.globChildren("upgrade_*%s" % (self.upgradeFileSuffix,)):
-            matched = regex.match(child.basename())
-            if matched is not None:
-                fromV = int(matched.group(1))
-                toV = int(matched.group(2))
-                upgrades.append((fromV, toV, child))
-        
-        upgrades.sort(key=lambda x:(x[0], x[1]))
-        return upgrades
-
-    def determineUpgradeSequence(self, fromVersion, toVersion, files, dialect):
-        """
-        Determine the upgrade_from_X_to_Y(.sql|.py) files that cover the full range of upgrades.
-        Note that X and Y may not be consecutive, e.g., we might have an upgrade from 3 to 4,
-        4 to 5, and 3 to 5 - the later because it is more efficient to jump over the intermediate
-        step. As a result we will always try and pick the upgrade file that gives the biggest
-        jump from one version to another at each step.
-        """
-
-        # Now find the path from the old version to the current one
-        filesByFromVersion = {}
-        for fromV, toV, fp in files:
-            if fromV not in filesByFromVersion or filesByFromVersion[fromV][1] < toV:
-                filesByFromVersion[fromV] = fromV, toV, fp
-        
-        upgrades = []
-        nextVersion = fromVersion
-        while nextVersion != toVersion:
-            if nextVersion not in filesByFromVersion:
-                msg = "Missing upgrade file from version %d with dialect %s" % (nextVersion, dialect,)
-                self.log_error(msg)
-                raise RuntimeError(msg)
-            else:
-                upgrades.append(filesByFromVersion[nextVersion][2])
-                nextVersion = filesByFromVersion[nextVersion][1]
-        
-        return upgrades
-
-    def applyUpgrade(self, fp):
-        """
-        Apply the supplied upgrade to the database. Always return an L{Deferred"
-        """
-        raise NotImplementedError
-        
-class UpgradeDatabaseSchemaService(UpgradeDatabaseCoreService):
-    """
-    Checks and upgrades the database schema. This assumes there are a bunch of
-    upgrade files in sql syntax that we can execute against the database to
-    accomplish the upgrade.
-
-    @ivar sqlStore: The store to operate on.
-
-    @type sqlStore: L{txdav.idav.IDataStore}
-
-    @ivar wrappedService: Wrapped L{IService} that will be started after this
-        L{UpgradeDatabaseSchemaService}'s work is done and the database schema
-        of C{sqlStore} is fully upgraded.  This may also be specified as
-        C{None}, in which case no service will be started.
-
-    @type wrappedService: L{IService} or C{NoneType}
-    """
-
-    def __init__(self, sqlStore, service, uid=None, gid=None):
-        """
-        Initialize the service.
-        
-        @param sqlStore: The store to operate on. Can be C{None} when doing unit tests.
-        @param service:  Wrapped service. Can be C{None} when doing unit tests.
-        """
-        super(UpgradeDatabaseSchemaService, self).__init__(sqlStore, service, uid, gid)
-        
-        self.versionKey = "VERSION"
-        self.versionDescriptor = "schema"
-        self.upgradeFileSuffix = ".sql"
-
-    def getPathToUpgrades(self, dialect):
-        return self.schemaLocation.child("upgrades").child(dialect)
-
-    @inlineCallbacks
-    def applyUpgrade(self, fp):
-        """
-        Apply the schema upgrade .sql file to the database.
-        """
-        self.log_warn("Applying schema upgrade: %s" % (fp.basename(),))
-        sqlTxn = self.sqlStore.newTransaction()
-        try:
-            sql = fp.getContent()
-            yield sqlTxn.execSQLBlock(sql)
-            yield sqlTxn.commit()
-        except RuntimeError:
-            yield sqlTxn.abort()
-            raise
-
-class UpgradeDatabaseDataService(UpgradeDatabaseCoreService):
-    """
-    Checks and upgrades the database data. This assumes there are a bunch of
-    upgrade python modules that we can execute against the database to
-    accomplish the upgrade.
-
-    @ivar sqlStore: The store to operate on.
-
-    @type sqlStore: L{txdav.idav.IDataStore}
-
-    @ivar wrappedService: Wrapped L{IService} that will be started after this
-        L{UpgradeDatabaseSchemaService}'s work is done and the database schema
-        of C{sqlStore} is fully upgraded.  This may also be specified as
-        C{None}, in which case no service will be started.
-
-    @type wrappedService: L{IService} or C{NoneType}
-    """
-
-    def __init__(self, sqlStore, service, uid=None, gid=None):
-        """
-        Initialize the service.
-        
-        @param sqlStore: The store to operate on. Can be C{None} when doing unit tests.
-        @param service:  Wrapped service. Can be C{None} when doing unit tests.
-        """
-        super(UpgradeDatabaseDataService, self).__init__(sqlStore, service, uid, gid)
-        
-        self.versionKey = "CALENDAR-DATAVERSION"
-        self.versionDescriptor = "data"
-        self.upgradeFileSuffix = ".py"
-
-    def getPathToUpgrades(self, dialect):
-        return self.pyLocation.child("upgrades")
-
-    @inlineCallbacks
-    def applyUpgrade(self, fp):
-        """
-        Apply the data upgrade .py files to the database.
-        """
-        
-        # Find the module function we need to execute
-        try:
-            module = getModule(__name__)
-            module = ".".join(module.name.split(".")[:-1]) + ".upgrades." + fp.basename()[:-3] + ".doUpgrade"
-            doUpgrade = namedObject(module)
-        except ImportError:
-            msg = "Failed data upgrade: %s" % (fp.basename()[:-4],)
-            self.log_error(msg)
-            raise RuntimeError(msg)
-
-        self.log_warn("Applying data upgrade: %s" % (module,))
-        yield doUpgrade(self.sqlStore)

Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrade.py (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/upgrade.py)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrade.py	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrade.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,345 @@
+# -*- test-case-name: txdav.common.datastore.upgrade.sql.test -*-
+##
+# Copyright (c) 2010-2011 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.
+##
+
+"""
+Utilities, mostly related to upgrading, common to calendar and addresbook
+data stores.
+"""
+
+import re
+
+from twext.python.log import LoggingMixIn
+
+from twisted.application.service import Service
+from twisted.internet import reactor
+from twisted.internet.defer import inlineCallbacks, returnValue
+from twisted.python.modules import getModule
+from twisted.python.reflect import namedObject
+
+class UpgradeDatabaseCoreService(Service, LoggingMixIn, object):
+    """
+    Base class for either schema or data upgrades on the database.
+
+    upgrade files in sql syntax that we can execute against the database to
+    accomplish the upgrade.
+
+    @ivar sqlStore: The store to operate on.
+
+    @type sqlStore: L{txdav.idav.IDataStore}
+
+    @ivar wrappedService: Wrapped L{IService} that will be started after this
+        L{UpgradeDatabaseSchemaService}'s work is done and the database schema
+        of C{sqlStore} is fully upgraded.  This may also be specified as
+        C{None}, in which case no service will be started.
+
+    @type wrappedService: L{IService} or C{NoneType}
+    """
+
+    @classmethod
+    def wrapService(cls, service, store, uid=None, gid=None):
+        """
+        Create an L{UpgradeDatabaseSchemaService} when starting the database
+        so we can check the schema version and do any upgrades.
+
+        @param service: the service to wrap.  This service should be started
+            when the upgrade is complete.  (This is accomplished by returning
+            it directly when no upgrade needs to be done, and by adding it to
+            the service hierarchy when the upgrade completes; assuming that the
+            service parent of the resulting service will be set to a
+            L{MultiService} or similar.)
+
+        @param store: the SQL storage service.
+
+        @type service: L{IService}
+
+        @type store: L{txdav.idav.IDataStore}
+
+        @return: a service
+        @rtype: L{IService}
+        """
+        return cls(store, service, uid=uid, gid=gid,)
+
+    def __init__(self, sqlStore, service, uid=None, gid=None):
+        """
+        Initialize the service.
+        """
+        self.wrappedService = service
+        self.sqlStore = sqlStore
+        self.uid = uid
+        self.gid = gid
+        self.schemaLocation = getModule(__name__).filePath.parent().parent().sibling("sql_schema")
+        self.pyLocation = getModule(__name__).filePath.parent()
+        
+        self.versionKey = None
+        self.versionDescriptor = ""
+        self.upgradeFileSuffix = ""
+        self.defaultKeyValue = None
+        
+    def startService(self):
+        """
+        Start the service.
+        """
+        self.databaseUpgrade()
+
+    @inlineCallbacks
+    def databaseUpgrade(self):
+        """
+        Do a database schema upgrade.
+        """
+        self.log_warn("Beginning database %s check." % (self.versionDescriptor,))
+        
+        # Retrieve information from schema and database
+        dialect, required_version, actual_version = yield self.getVersions()
+
+        if required_version == actual_version:
+            self.log_warn("%s version check complete: no upgrade needed." % (self.versionDescriptor.capitalize(),))
+        elif required_version < actual_version:
+            msg = "Actual %s version %s is more recent than the expected version %s. The service cannot be started" % (
+                self.versionDescriptor, actual_version, required_version,
+            )
+            self.log_error(msg)
+            raise RuntimeError(msg)
+        else:
+            yield self.upgradeVersion(actual_version, required_version, dialect)
+            
+        self.log_warn("Database %s check complete." % (self.versionDescriptor,))
+
+        # see http://twistedmatrix.com/trac/ticket/4649
+        if self.wrappedService is not None:
+            reactor.callLater(0, self.wrappedService.setServiceParent, self.parent)
+    
+    @inlineCallbacks
+    def getVersions(self):
+        """
+        Extract the expected version from the database schema and get the actual version in the current
+        database, along with the DB dialect.
+        """
+
+        # Retrieve the version number from the schema file
+        current_schema = self.schemaLocation.child("current.sql").getContent()
+        found = re.search("insert into CALENDARSERVER values \('%s', '(\d)+'\);" % (self.versionKey,), current_schema)
+        if found is None:
+            msg = "Schema is missing required database key %s insert statement: %s" % (self.versionKey, current_schema,)
+            self.log_error(msg)
+            raise RuntimeError(msg)
+        else:
+            required_version = int(found.group(1))
+            self.log_warn("Required database key %s: %s." % (self.versionKey, required_version,))
+        
+        # Get the schema version in the current database
+        sqlTxn = self.sqlStore.newTransaction()
+        dialect = sqlTxn.dialect
+        try:
+            actual_version = yield sqlTxn.calendarserverValue(self.versionKey)
+            actual_version = int(actual_version)
+            yield sqlTxn.commit()
+        except RuntimeError, ValueError:
+            self.log_error("Database key %s cannot be determined." % (self.versionKey,))
+            yield sqlTxn.abort()
+            if self.defaultKeyValue is None:
+                raise
+            else:
+                actual_version = self.defaultKeyValue
+
+        self.log_warn("Actual database key %s: %s." % (self.versionKey, actual_version,))
+
+        returnValue((dialect, required_version, actual_version,))
+
+    @inlineCallbacks
+    def upgradeVersion(self, fromVersion, toVersion, dialect):
+        """
+        Update the database from one version to another (the current one). Do this by
+        looking for upgrade_from_X_to_Y.sql files that cover the full range of upgrades.
+        """
+
+        self.log_warn("Starting %s upgrade from version %d to %d." % (self.versionDescriptor, fromVersion, toVersion,))
+        
+        # Scan for all possible upgrade files - returned sorted
+        files = self.scanForUpgradeFiles(dialect)
+        
+        # Determine upgrade sequence and run each upgrade
+        upgrades = self.determineUpgradeSequence(fromVersion, toVersion, files, dialect)
+
+        # Use one transaction for the entire set of upgrades
+        try:
+            for fp in upgrades:
+                yield self.applyUpgrade(fp)
+        except RuntimeError:
+            self.log_error("Database %s upgrade failed using: %s" % (self.versionDescriptor, fp.basename(),))
+            raise
+
+        self.log_warn("%s upgraded from version %d to %d." % (self.versionDescriptor.capitalize(), fromVersion, toVersion,))
+
+    def getPathToUpgrades(self, dialect):
+        """
+        Return the path where appropriate upgrade files can be found. 
+        """
+        raise NotImplementedError
+
+    def scanForUpgradeFiles(self, dialect):
+        """
+        Scan for upgrade files with the require name.
+        """
+        
+        fp = self.getPathToUpgrades(dialect)
+        upgrades = []
+        regex = re.compile("upgrade_from_(\d)+_to_(\d)+%s" % (self.upgradeFileSuffix,))
+        for child in fp.globChildren("upgrade_*%s" % (self.upgradeFileSuffix,)):
+            matched = regex.match(child.basename())
+            if matched is not None:
+                fromV = int(matched.group(1))
+                toV = int(matched.group(2))
+                upgrades.append((fromV, toV, child))
+        
+        upgrades.sort(key=lambda x:(x[0], x[1]))
+        return upgrades
+
+    def determineUpgradeSequence(self, fromVersion, toVersion, files, dialect):
+        """
+        Determine the upgrade_from_X_to_Y(.sql|.py) files that cover the full range of upgrades.
+        Note that X and Y may not be consecutive, e.g., we might have an upgrade from 3 to 4,
+        4 to 5, and 3 to 5 - the later because it is more efficient to jump over the intermediate
+        step. As a result we will always try and pick the upgrade file that gives the biggest
+        jump from one version to another at each step.
+        """
+
+        # Now find the path from the old version to the current one
+        filesByFromVersion = {}
+        for fromV, toV, fp in files:
+            if fromV not in filesByFromVersion or filesByFromVersion[fromV][1] < toV:
+                filesByFromVersion[fromV] = fromV, toV, fp
+        
+        upgrades = []
+        nextVersion = fromVersion
+        while nextVersion != toVersion:
+            if nextVersion not in filesByFromVersion:
+                msg = "Missing upgrade file from version %d with dialect %s" % (nextVersion, dialect,)
+                self.log_error(msg)
+                raise RuntimeError(msg)
+            else:
+                upgrades.append(filesByFromVersion[nextVersion][2])
+                nextVersion = filesByFromVersion[nextVersion][1]
+        
+        return upgrades
+
+    def applyUpgrade(self, fp):
+        """
+        Apply the supplied upgrade to the database. Always return an L{Deferred"
+        """
+        raise NotImplementedError
+        
+class UpgradeDatabaseSchemaService(UpgradeDatabaseCoreService):
+    """
+    Checks and upgrades the database schema. This assumes there are a bunch of
+    upgrade files in sql syntax that we can execute against the database to
+    accomplish the upgrade.
+
+    @ivar sqlStore: The store to operate on.
+
+    @type sqlStore: L{txdav.idav.IDataStore}
+
+    @ivar wrappedService: Wrapped L{IService} that will be started after this
+        L{UpgradeDatabaseSchemaService}'s work is done and the database schema
+        of C{sqlStore} is fully upgraded.  This may also be specified as
+        C{None}, in which case no service will be started.
+
+    @type wrappedService: L{IService} or C{NoneType}
+    """
+
+    def __init__(self, sqlStore, service, uid=None, gid=None):
+        """
+        Initialize the service.
+        
+        @param sqlStore: The store to operate on. Can be C{None} when doing unit tests.
+        @param service:  Wrapped service. Can be C{None} when doing unit tests.
+        """
+        super(UpgradeDatabaseSchemaService, self).__init__(sqlStore, service, uid, gid)
+        
+        self.versionKey = "VERSION"
+        self.versionDescriptor = "schema"
+        self.upgradeFileSuffix = ".sql"
+
+    def getPathToUpgrades(self, dialect):
+        return self.schemaLocation.child("upgrades").child(dialect)
+
+    @inlineCallbacks
+    def applyUpgrade(self, fp):
+        """
+        Apply the schema upgrade .sql file to the database.
+        """
+        self.log_warn("Applying schema upgrade: %s" % (fp.basename(),))
+        sqlTxn = self.sqlStore.newTransaction()
+        try:
+            sql = fp.getContent()
+            yield sqlTxn.execSQLBlock(sql)
+            yield sqlTxn.commit()
+        except RuntimeError:
+            yield sqlTxn.abort()
+            raise
+
+class UpgradeDatabaseDataService(UpgradeDatabaseCoreService):
+    """
+    Checks and upgrades the database data. This assumes there are a bunch of
+    upgrade python modules that we can execute against the database to
+    accomplish the upgrade.
+
+    @ivar sqlStore: The store to operate on.
+
+    @type sqlStore: L{txdav.idav.IDataStore}
+
+    @ivar wrappedService: Wrapped L{IService} that will be started after this
+        L{UpgradeDatabaseSchemaService}'s work is done and the database schema
+        of C{sqlStore} is fully upgraded.  This may also be specified as
+        C{None}, in which case no service will be started.
+
+    @type wrappedService: L{IService} or C{NoneType}
+    """
+
+    def __init__(self, sqlStore, service, uid=None, gid=None):
+        """
+        Initialize the service.
+        
+        @param sqlStore: The store to operate on. Can be C{None} when doing unit tests.
+        @param service:  Wrapped service. Can be C{None} when doing unit tests.
+        """
+        super(UpgradeDatabaseDataService, self).__init__(sqlStore, service, uid, gid)
+        
+        self.versionKey = "CALENDAR-DATAVERSION"
+        self.versionDescriptor = "data"
+        self.upgradeFileSuffix = ".py"
+
+    def getPathToUpgrades(self, dialect):
+        return self.pyLocation.child("upgrades")
+
+    @inlineCallbacks
+    def applyUpgrade(self, fp):
+        """
+        Apply the data upgrade .py files to the database.
+        """
+        
+        # Find the module function we need to execute
+        try:
+            module = getModule(__name__)
+            module = ".".join(module.name.split(".")[:-1]) + ".upgrades." + fp.basename()[:-3] + ".doUpgrade"
+            doUpgrade = namedObject(module)
+        except ImportError:
+            msg = "Failed data upgrade: %s" % (fp.basename()[:-4],)
+            self.log_error(msg)
+            raise RuntimeError(msg)
+
+        self.log_warn("Applying data upgrade: %s" % (module,))
+        yield doUpgrade(self.sqlStore)

Deleted: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/__init__.py
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/upgrades/__init__.py	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/__init__.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,16 +0,0 @@
-##
-# Copyright (c) 2011 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.
-##
-

Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/__init__.py (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/upgrades/__init__.py)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/__init__.py	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/__init__.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,16 @@
+##
+# Copyright (c) 2011 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.
+##
+

Deleted: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_1_to_2.py
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_1_to_2.py	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_1_to_2.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,85 +0,0 @@
-# -*- test-case-name: txdav.common.datastore.upgrade.sql.test -*-
-##
-# Copyright (c) 2011 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.
-##
-
-from twext.enterprise.dal.syntax import Update
-from twext.web2.dav.element.parser import WebDAVDocument
-from twisted.internet.defer import inlineCallbacks
-from twistedcaldav import caldavxml
-from txdav.common.datastore.sql_tables import schema
-from txdav.common.datastore.upgrade.sql.upgrades.util import rowsForProperty,\
-    removeProperty, updateDataVersion, doToEachCalendarHomeNotAtVersion
-
-"""
-Data upgrade from database version 1 to 2
-"""
-
-UPGRADE_TO_VERSION = 2
-
- at inlineCallbacks
-def doUpgrade(sqlStore):
-    """
-    Do the required upgrade steps.
-    """
-    yield moveSupportedComponentSetProperties(sqlStore)
-    yield splitCalendars(sqlStore)
-    
-    # Always bump the DB value
-    yield updateDataVersion(sqlStore, "CALENDAR-DATAVERSION", UPGRADE_TO_VERSION)
-
- at inlineCallbacks
-def moveSupportedComponentSetProperties(sqlStore):
-    """
-    Need to move all the CalDAV:supported-component-set properties in the RESOURCE_PROPERTY
-    table to the new CALENDAR table column, extracting the new format value from the XML property.
-    """
-
-    sqlTxn = sqlStore.newTransaction()
-    try:
-        rows = (yield rowsForProperty(sqlTxn, caldavxml.SupportedCalendarComponentSet))
-        for calendar_rid, value in rows:
-            prop = WebDAVDocument.fromString(value).root_element
-            supported_components = ",".join(sorted([comp.attributes["name"].upper() for comp in prop.children]))
-    
-            cal = schema.CALENDAR
-            yield Update(
-                {
-                    cal.SUPPORTED_COMPONENTS : supported_components
-                },
-                Where=(cal.RESOURCE_ID == calendar_rid)
-            ).on(sqlTxn)
-    
-        yield removeProperty(sqlTxn, caldavxml.SupportedCalendarComponentSet)
-        yield sqlTxn.commit()
-    except RuntimeError:
-        yield sqlTxn.abort()
-        raise
-
- at inlineCallbacks
-def splitCalendars(sqlStore):
-    """
-    Split all calendars by component type.
-    """
-
-    @inlineCallbacks
-    def doIt(home):
-        """
-        Split each regular calendar in the home.
-        """
-        yield home.splitCalendars()
-            
-    # Do this to each calendar home not already at version 2
-    yield doToEachCalendarHomeNotAtVersion(sqlStore, UPGRADE_TO_VERSION, doIt)

Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_1_to_2.py (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_1_to_2.py)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_1_to_2.py	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_1_to_2.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,85 @@
+# -*- test-case-name: txdav.common.datastore.upgrade.sql.test -*-
+##
+# Copyright (c) 2011 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.
+##
+
+from twext.enterprise.dal.syntax import Update
+from twext.web2.dav.element.parser import WebDAVDocument
+from twisted.internet.defer import inlineCallbacks
+from twistedcaldav import caldavxml
+from txdav.common.datastore.sql_tables import schema
+from txdav.common.datastore.upgrade.sql.upgrades.util import rowsForProperty,\
+    removeProperty, updateDataVersion, doToEachCalendarHomeNotAtVersion
+
+"""
+Data upgrade from database version 1 to 2
+"""
+
+UPGRADE_TO_VERSION = 2
+
+ at inlineCallbacks
+def doUpgrade(sqlStore):
+    """
+    Do the required upgrade steps.
+    """
+    yield moveSupportedComponentSetProperties(sqlStore)
+    yield splitCalendars(sqlStore)
+    
+    # Always bump the DB value
+    yield updateDataVersion(sqlStore, "CALENDAR-DATAVERSION", UPGRADE_TO_VERSION)
+
+ at inlineCallbacks
+def moveSupportedComponentSetProperties(sqlStore):
+    """
+    Need to move all the CalDAV:supported-component-set properties in the RESOURCE_PROPERTY
+    table to the new CALENDAR table column, extracting the new format value from the XML property.
+    """
+
+    sqlTxn = sqlStore.newTransaction()
+    try:
+        rows = (yield rowsForProperty(sqlTxn, caldavxml.SupportedCalendarComponentSet))
+        for calendar_rid, value in rows:
+            prop = WebDAVDocument.fromString(value).root_element
+            supported_components = ",".join(sorted([comp.attributes["name"].upper() for comp in prop.children]))
+    
+            cal = schema.CALENDAR
+            yield Update(
+                {
+                    cal.SUPPORTED_COMPONENTS : supported_components
+                },
+                Where=(cal.RESOURCE_ID == calendar_rid)
+            ).on(sqlTxn)
+    
+        yield removeProperty(sqlTxn, caldavxml.SupportedCalendarComponentSet)
+        yield sqlTxn.commit()
+    except RuntimeError:
+        yield sqlTxn.abort()
+        raise
+
+ at inlineCallbacks
+def splitCalendars(sqlStore):
+    """
+    Split all calendars by component type.
+    """
+
+    @inlineCallbacks
+    def doIt(home):
+        """
+        Split each regular calendar in the home.
+        """
+        yield home.splitCalendars()
+            
+    # Do this to each calendar home not already at version 2
+    yield doToEachCalendarHomeNotAtVersion(sqlStore, UPGRADE_TO_VERSION, doIt)

Deleted: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/util.py
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/upgrades/util.py	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/util.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,99 +0,0 @@
-##
-# Copyright (c) 2011 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.
-##
-
-from twext.enterprise.dal.syntax import Select, Delete, Update
-from twisted.internet.defer import inlineCallbacks, returnValue
-from txdav.base.propertystore.base import PropertyName
-from txdav.common.datastore.sql_tables import schema
-
- at inlineCallbacks
-def rowsForProperty(txn, propelement):
-    pname = PropertyName.fromElement(propelement)
-
-    rp = schema.RESOURCE_PROPERTY
-    rows = yield Select(
-        [rp.RESOURCE_ID, rp.VALUE,],
-        From=rp,
-        Where=rp.NAME == pname.toString(),
-    ).on(txn)
-    
-    returnValue(rows)
-
- at inlineCallbacks
-def removeProperty(txn, propelement):
-    pname = PropertyName.fromElement(propelement)
-
-    rp = schema.RESOURCE_PROPERTY
-    yield Delete(
-        From=rp,
-        Where=rp.NAME == pname.toString(),
-    ).on(txn)
-
- at inlineCallbacks
-def updateDataVersion(store, key, version):
-
-    txn = store.newTransaction("updateDataVersion")    
-    cs = schema.CALENDARSERVER
-    yield Update(
-        {cs.VALUE: version},
-        Where=cs.NAME == key,
-    ).on(txn)
-    yield txn.commit()
-
-def updateCalendarDataVersion(store, version):
-    return updateDataVersion(store, "CALENDAR-DATAVERSION", version)
-
-def updateAddressBookDataVersion(store, version):
-    return updateDataVersion(store, "ADDRESSBOOK-DATAVERSION", version)
-
- at inlineCallbacks
-def doToEachCalendarHomeNotAtVersion(store, version, doIt):
-    """
-    Do something to each calendar home whose version column indicates it is older
-    than the specified version. Do this in batches as there may be a lot of work to do.
-    """
-
-    while True:
-        
-        # Get the next home with an old version
-        txn = store.newTransaction("updateDataVersion")   
-        try: 
-            ch = schema.CALENDAR_HOME
-            rows = yield Select(
-                [ch.RESOURCE_ID, ch.OWNER_UID,],
-                From=ch,
-                Where=ch.DATAVERSION < version,
-                OrderBy=ch.OWNER_UID,
-                Limit=1,
-            ).on(txn)
-            
-            if len(rows) == 0:
-                yield txn.commit()
-                returnValue(None)
-            
-            # Apply to the home
-            resource_id, _ignore_owner_uid = rows[0]
-            home = yield txn.calendarHomeWithResourceID(resource_id)
-            yield doIt(home)
-    
-            # Update the home to the current version
-            yield Update(
-                {ch.DATAVERSION: version},
-                Where=ch.RESOURCE_ID == resource_id,
-            ).on(txn)
-            yield txn.commit()
-        except RuntimeError:
-            yield txn.abort()

Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/util.py (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/sql/upgrades/util.py)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/util.py	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/util.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,99 @@
+##
+# Copyright (c) 2011 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.
+##
+
+from twext.enterprise.dal.syntax import Select, Delete, Update
+from twisted.internet.defer import inlineCallbacks, returnValue
+from txdav.base.propertystore.base import PropertyName
+from txdav.common.datastore.sql_tables import schema
+
+ at inlineCallbacks
+def rowsForProperty(txn, propelement):
+    pname = PropertyName.fromElement(propelement)
+
+    rp = schema.RESOURCE_PROPERTY
+    rows = yield Select(
+        [rp.RESOURCE_ID, rp.VALUE,],
+        From=rp,
+        Where=rp.NAME == pname.toString(),
+    ).on(txn)
+    
+    returnValue(rows)
+
+ at inlineCallbacks
+def removeProperty(txn, propelement):
+    pname = PropertyName.fromElement(propelement)
+
+    rp = schema.RESOURCE_PROPERTY
+    yield Delete(
+        From=rp,
+        Where=rp.NAME == pname.toString(),
+    ).on(txn)
+
+ at inlineCallbacks
+def updateDataVersion(store, key, version):
+
+    txn = store.newTransaction("updateDataVersion")    
+    cs = schema.CALENDARSERVER
+    yield Update(
+        {cs.VALUE: version},
+        Where=cs.NAME == key,
+    ).on(txn)
+    yield txn.commit()
+
+def updateCalendarDataVersion(store, version):
+    return updateDataVersion(store, "CALENDAR-DATAVERSION", version)
+
+def updateAddressBookDataVersion(store, version):
+    return updateDataVersion(store, "ADDRESSBOOK-DATAVERSION", version)
+
+ at inlineCallbacks
+def doToEachCalendarHomeNotAtVersion(store, version, doIt):
+    """
+    Do something to each calendar home whose version column indicates it is older
+    than the specified version. Do this in batches as there may be a lot of work to do.
+    """
+
+    while True:
+        
+        # Get the next home with an old version
+        txn = store.newTransaction("updateDataVersion")   
+        try: 
+            ch = schema.CALENDAR_HOME
+            rows = yield Select(
+                [ch.RESOURCE_ID, ch.OWNER_UID,],
+                From=ch,
+                Where=ch.DATAVERSION < version,
+                OrderBy=ch.OWNER_UID,
+                Limit=1,
+            ).on(txn)
+            
+            if len(rows) == 0:
+                yield txn.commit()
+                returnValue(None)
+            
+            # Apply to the home
+            resource_id, _ignore_owner_uid = rows[0]
+            home = yield txn.calendarHomeWithResourceID(resource_id)
+            yield doIt(home)
+    
+            # Update the home to the current version
+            yield Update(
+                {ch.DATAVERSION: version},
+                Where=ch.RESOURCE_ID == resource_id,
+            ).on(txn)
+            yield txn.commit()
+        except RuntimeError:
+            yield txn.abort()

Deleted: CalendarServer/trunk/txdav/common/datastore/upgrade/test/__init__.py
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/test/__init__.py	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/test/__init__.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,16 +0,0 @@
-##
-# Copyright (c) 2011 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.
-##
-

Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/test/__init__.py (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/test/__init__.py)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/test/__init__.py	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/test/__init__.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,16 @@
+##
+# Copyright (c) 2011 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.
+##
+

Deleted: CalendarServer/trunk/txdav/common/datastore/upgrade/test/test_migrate.py
===================================================================
--- CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/test/test_migrate.py	2011-11-28 21:07:52 UTC (rev 8346)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/test/test_migrate.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,218 +0,0 @@
-##
-# Copyright (c) 2010-2011 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.
-##
-
-"""
-Tests for L{txdav.common.datastore.upgrade.migrate}.
-"""
-
-from twext.python.filepath import CachingFilePath
-from twext.web2.http_headers import MimeType
-from twisted.application.service import Service, MultiService
-from twisted.internet.defer import inlineCallbacks, Deferred, returnValue
-from twisted.internet.protocol import Protocol
-from twisted.trial.unittest import TestCase
-from txdav.caldav.datastore.test.common import CommonTests
-from txdav.carddav.datastore.test.common import CommonTests as ABCommonTests
-from txdav.common.datastore.file import CommonDataStore
-from txdav.common.datastore.test.util import theStoreBuilder, \
-    populateCalendarsFrom, StubNotifierFactory, resetCalendarMD5s,\
-    populateAddressBooksFrom, resetAddressBookMD5s
-from txdav.common.datastore.upgrade.migrate import UpgradeToDatabaseService
-
-class HomeMigrationTests(TestCase):
-    """
-    Tests for L{UpgradeToDatabaseService}.
-    """
-
-    @inlineCallbacks
-    def setUp(self):
-        """
-        Set up two stores to migrate between.
-        """
-        # Add some files to the file store.
-
-        self.filesPath = CachingFilePath(self.mktemp())
-        self.filesPath.createDirectory()
-        fileStore = self.fileStore = CommonDataStore(
-            self.filesPath, StubNotifierFactory(), True, True
-        )
-        self.sqlStore = yield theStoreBuilder.buildStore(
-            self, StubNotifierFactory()
-        )
-        subStarted = self.subStarted = Deferred()
-        class StubService(Service, object):
-            def startService(self):
-                super(StubService, self).startService()
-                subStarted.callback(None)
-        self.stubService = StubService()
-        self.topService = MultiService()
-        self.upgrader = UpgradeToDatabaseService(
-            fileStore, self.sqlStore, self.stubService
-        )
-        self.upgrader.setServiceParent(self.topService)
-
-        requirements = CommonTests.requirements
-        yield populateCalendarsFrom(requirements, fileStore)
-        md5s = CommonTests.md5s
-        yield resetCalendarMD5s(md5s, fileStore)
-        self.filesPath.child("calendars").child(
-            "__uids__").child("ho").child("me").child("home1").child(
-            ".some-extra-data").setContent("some extra data")
-
-        requirements = ABCommonTests.requirements
-        yield populateAddressBooksFrom(requirements, fileStore)
-        md5s = ABCommonTests.md5s
-        yield resetAddressBookMD5s(md5s, fileStore)
-        self.filesPath.child("addressbooks").child(
-            "__uids__").child("ho").child("me").child("home1").child(
-            ".some-extra-data").setContent("some extra data")
-
-
-    @inlineCallbacks
-    def test_upgradeCalendarHomes(self):
-        """
-        L{UpgradeToDatabaseService.startService} will do the upgrade, then
-        start its dependent service by adding it to its service hierarchy.
-        """
-        self.topService.startService()
-        yield self.subStarted
-        self.assertEquals(self.stubService.running, True)
-        txn = self.sqlStore.newTransaction()
-        self.addCleanup(txn.commit)
-        for uid in CommonTests.requirements:
-            if CommonTests.requirements[uid] is not None:
-                self.assertNotIdentical(
-                    None, (yield txn.calendarHomeWithUID(uid))
-                )
-        # Successfully migrated calendar homes are deleted
-        self.assertFalse(self.filesPath.child("calendars").child(
-            "__uids__").child("ho").child("me").child("home1").exists())
-
-        # Want metadata preserved
-        home = (yield txn.calendarHomeWithUID("home1"))
-        calendar = (yield home.calendarWithName("calendar_1"))
-        for name, metadata, md5 in (
-            ("1.ics", CommonTests.metadata1, CommonTests.md5Values[0]),
-            ("2.ics", CommonTests.metadata2, CommonTests.md5Values[1]),
-            ("3.ics", CommonTests.metadata3, CommonTests.md5Values[2]),
-        ):
-            object = (yield calendar.calendarObjectWithName(name))
-            self.assertEquals(object.getMetadata(), metadata)
-            self.assertEquals(object.md5(), md5)
-
-
-    @inlineCallbacks
-    def test_upgradeExistingHome(self):
-        """
-        L{UpgradeToDatabaseService.startService} will skip migrating existing
-        homes.
-        """
-        startTxn = self.sqlStore.newTransaction("populate empty sample")
-        yield startTxn.calendarHomeWithUID("home1", create=True)
-        yield startTxn.commit()
-        self.topService.startService()
-        yield self.subStarted
-        vrfyTxn = self.sqlStore.newTransaction("verify sample still empty")
-        self.addCleanup(vrfyTxn.commit)
-        home = yield vrfyTxn.calendarHomeWithUID("home1")
-        # The default calendar is still there.
-        self.assertNotIdentical(None, (yield home.calendarWithName("calendar")))
-        # The migrated calendar isn't.
-        self.assertIdentical(None, (yield home.calendarWithName("calendar_1")))
-
-
-    @inlineCallbacks
-    def test_upgradeAttachments(self):
-        """
-        L{UpgradeToDatabaseService.startService} upgrades calendar attachments
-        as well.
-        """
-
-        txn = self.fileStore.newTransaction()
-        committed = []
-        def maybeCommit():
-            if not committed:
-                committed.append(True)
-                return txn.commit()
-        self.addCleanup(maybeCommit)
-
-        @inlineCallbacks
-        def getSampleObj():
-            home = (yield txn.calendarHomeWithUID("home1"))
-            calendar = (yield home.calendarWithName("calendar_1"))
-            object = (yield calendar.calendarObjectWithName("1.ics"))
-            returnValue(object)
-
-        inObject = yield getSampleObj()
-        someAttachmentName = "some-attachment"
-        someAttachmentType = MimeType.fromString("application/x-custom-type")
-        attachment = yield inObject.createAttachmentWithName(
-            someAttachmentName,
-        )
-        transport = attachment.store(someAttachmentType)
-        someAttachmentData = "Here is some data for your attachment, enjoy."
-        transport.write(someAttachmentData)
-        yield transport.loseConnection()
-        yield maybeCommit()
-        self.topService.startService()
-        yield self.subStarted
-        committed = []
-        txn = self.sqlStore.newTransaction()
-        outObject = yield getSampleObj()
-        outAttachment = yield outObject.attachmentWithName(someAttachmentName)
-        allDone = Deferred()
-        class SimpleProto(Protocol):
-            data = ''
-            def dataReceived(self, data):
-                self.data += data
-            def connectionLost(self, reason):
-                allDone.callback(self.data)
-        self.assertEquals(outAttachment.contentType(), someAttachmentType)
-        outAttachment.retrieve(SimpleProto())
-        allData = yield allDone
-        self.assertEquals(allData, someAttachmentData)
-
-
-    @inlineCallbacks
-    def test_upgradeAddressBookHomes(self):
-        """
-        L{UpgradeToDatabaseService.startService} will do the upgrade, then
-        start its dependent service by adding it to its service hierarchy.
-        """
-        self.topService.startService()
-        yield self.subStarted
-        self.assertEquals(self.stubService.running, True)
-        txn = self.sqlStore.newTransaction()
-        self.addCleanup(txn.commit)
-        for uid in ABCommonTests.requirements:
-            if ABCommonTests.requirements[uid] is not None:
-                self.assertNotIdentical(
-                    None, (yield txn.addressbookHomeWithUID(uid))
-                )
-        # Successfully migrated addressbook homes are deleted
-        self.assertFalse(self.filesPath.child("addressbooks").child(
-            "__uids__").child("ho").child("me").child("home1").exists())
-
-        # Want metadata preserved
-        home = (yield txn.addressbookHomeWithUID("home1"))
-        adbk = (yield home.addressbookWithName("addressbook_1"))
-        for name, md5 in (
-            ("1.vcf", ABCommonTests.md5Values[0]),
-            ("2.vcf", ABCommonTests.md5Values[1]),
-            ("3.vcf", ABCommonTests.md5Values[2]),
-        ):
-            object = (yield adbk.addressbookObjectWithName(name))
-            self.assertEquals(object.md5(), md5)

Copied: CalendarServer/trunk/txdav/common/datastore/upgrade/test/test_migrate.py (from rev 8346, CalendarServer/branches/users/cdaboo/component-set-fixes/txdav/common/datastore/upgrade/test/test_migrate.py)
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/test/test_migrate.py	                        (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/test/test_migrate.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -0,0 +1,218 @@
+##
+# Copyright (c) 2010-2011 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.
+##
+
+"""
+Tests for L{txdav.common.datastore.upgrade.migrate}.
+"""
+
+from twext.python.filepath import CachingFilePath
+from twext.web2.http_headers import MimeType
+from twisted.application.service import Service, MultiService
+from twisted.internet.defer import inlineCallbacks, Deferred, returnValue
+from twisted.internet.protocol import Protocol
+from twisted.trial.unittest import TestCase
+from txdav.caldav.datastore.test.common import CommonTests
+from txdav.carddav.datastore.test.common import CommonTests as ABCommonTests
+from txdav.common.datastore.file import CommonDataStore
+from txdav.common.datastore.test.util import theStoreBuilder, \
+    populateCalendarsFrom, StubNotifierFactory, resetCalendarMD5s,\
+    populateAddressBooksFrom, resetAddressBookMD5s
+from txdav.common.datastore.upgrade.migrate import UpgradeToDatabaseService
+
+class HomeMigrationTests(TestCase):
+    """
+    Tests for L{UpgradeToDatabaseService}.
+    """
+
+    @inlineCallbacks
+    def setUp(self):
+        """
+        Set up two stores to migrate between.
+        """
+        # Add some files to the file store.
+
+        self.filesPath = CachingFilePath(self.mktemp())
+        self.filesPath.createDirectory()
+        fileStore = self.fileStore = CommonDataStore(
+            self.filesPath, StubNotifierFactory(), True, True
+        )
+        self.sqlStore = yield theStoreBuilder.buildStore(
+            self, StubNotifierFactory()
+        )
+        subStarted = self.subStarted = Deferred()
+        class StubService(Service, object):
+            def startService(self):
+                super(StubService, self).startService()
+                subStarted.callback(None)
+        self.stubService = StubService()
+        self.topService = MultiService()
+        self.upgrader = UpgradeToDatabaseService(
+            fileStore, self.sqlStore, self.stubService
+        )
+        self.upgrader.setServiceParent(self.topService)
+
+        requirements = CommonTests.requirements
+        yield populateCalendarsFrom(requirements, fileStore)
+        md5s = CommonTests.md5s
+        yield resetCalendarMD5s(md5s, fileStore)
+        self.filesPath.child("calendars").child(
+            "__uids__").child("ho").child("me").child("home1").child(
+            ".some-extra-data").setContent("some extra data")
+
+        requirements = ABCommonTests.requirements
+        yield populateAddressBooksFrom(requirements, fileStore)
+        md5s = ABCommonTests.md5s
+        yield resetAddressBookMD5s(md5s, fileStore)
+        self.filesPath.child("addressbooks").child(
+            "__uids__").child("ho").child("me").child("home1").child(
+            ".some-extra-data").setContent("some extra data")
+
+
+    @inlineCallbacks
+    def test_upgradeCalendarHomes(self):
+        """
+        L{UpgradeToDatabaseService.startService} will do the upgrade, then
+        start its dependent service by adding it to its service hierarchy.
+        """
+        self.topService.startService()
+        yield self.subStarted
+        self.assertEquals(self.stubService.running, True)
+        txn = self.sqlStore.newTransaction()
+        self.addCleanup(txn.commit)
+        for uid in CommonTests.requirements:
+            if CommonTests.requirements[uid] is not None:
+                self.assertNotIdentical(
+                    None, (yield txn.calendarHomeWithUID(uid))
+                )
+        # Successfully migrated calendar homes are deleted
+        self.assertFalse(self.filesPath.child("calendars").child(
+            "__uids__").child("ho").child("me").child("home1").exists())
+
+        # Want metadata preserved
+        home = (yield txn.calendarHomeWithUID("home1"))
+        calendar = (yield home.calendarWithName("calendar_1"))
+        for name, metadata, md5 in (
+            ("1.ics", CommonTests.metadata1, CommonTests.md5Values[0]),
+            ("2.ics", CommonTests.metadata2, CommonTests.md5Values[1]),
+            ("3.ics", CommonTests.metadata3, CommonTests.md5Values[2]),
+        ):
+            object = (yield calendar.calendarObjectWithName(name))
+            self.assertEquals(object.getMetadata(), metadata)
+            self.assertEquals(object.md5(), md5)
+
+
+    @inlineCallbacks
+    def test_upgradeExistingHome(self):
+        """
+        L{UpgradeToDatabaseService.startService} will skip migrating existing
+        homes.
+        """
+        startTxn = self.sqlStore.newTransaction("populate empty sample")
+        yield startTxn.calendarHomeWithUID("home1", create=True)
+        yield startTxn.commit()
+        self.topService.startService()
+        yield self.subStarted
+        vrfyTxn = self.sqlStore.newTransaction("verify sample still empty")
+        self.addCleanup(vrfyTxn.commit)
+        home = yield vrfyTxn.calendarHomeWithUID("home1")
+        # The default calendar is still there.
+        self.assertNotIdentical(None, (yield home.calendarWithName("calendar")))
+        # The migrated calendar isn't.
+        self.assertIdentical(None, (yield home.calendarWithName("calendar_1")))
+
+
+    @inlineCallbacks
+    def test_upgradeAttachments(self):
+        """
+        L{UpgradeToDatabaseService.startService} upgrades calendar attachments
+        as well.
+        """
+
+        txn = self.fileStore.newTransaction()
+        committed = []
+        def maybeCommit():
+            if not committed:
+                committed.append(True)
+                return txn.commit()
+        self.addCleanup(maybeCommit)
+
+        @inlineCallbacks
+        def getSampleObj():
+            home = (yield txn.calendarHomeWithUID("home1"))
+            calendar = (yield home.calendarWithName("calendar_1"))
+            object = (yield calendar.calendarObjectWithName("1.ics"))
+            returnValue(object)
+
+        inObject = yield getSampleObj()
+        someAttachmentName = "some-attachment"
+        someAttachmentType = MimeType.fromString("application/x-custom-type")
+        attachment = yield inObject.createAttachmentWithName(
+            someAttachmentName,
+        )
+        transport = attachment.store(someAttachmentType)
+        someAttachmentData = "Here is some data for your attachment, enjoy."
+        transport.write(someAttachmentData)
+        yield transport.loseConnection()
+        yield maybeCommit()
+        self.topService.startService()
+        yield self.subStarted
+        committed = []
+        txn = self.sqlStore.newTransaction()
+        outObject = yield getSampleObj()
+        outAttachment = yield outObject.attachmentWithName(someAttachmentName)
+        allDone = Deferred()
+        class SimpleProto(Protocol):
+            data = ''
+            def dataReceived(self, data):
+                self.data += data
+            def connectionLost(self, reason):
+                allDone.callback(self.data)
+        self.assertEquals(outAttachment.contentType(), someAttachmentType)
+        outAttachment.retrieve(SimpleProto())
+        allData = yield allDone
+        self.assertEquals(allData, someAttachmentData)
+
+
+    @inlineCallbacks
+    def test_upgradeAddressBookHomes(self):
+        """
+        L{UpgradeToDatabaseService.startService} will do the upgrade, then
+        start its dependent service by adding it to its service hierarchy.
+        """
+        self.topService.startService()
+        yield self.subStarted
+        self.assertEquals(self.stubService.running, True)
+        txn = self.sqlStore.newTransaction()
+        self.addCleanup(txn.commit)
+        for uid in ABCommonTests.requirements:
+            if ABCommonTests.requirements[uid] is not None:
+                self.assertNotIdentical(
+                    None, (yield txn.addressbookHomeWithUID(uid))
+                )
+        # Successfully migrated addressbook homes are deleted
+        self.assertFalse(self.filesPath.child("addressbooks").child(
+            "__uids__").child("ho").child("me").child("home1").exists())
+
+        # Want metadata preserved
+        home = (yield txn.addressbookHomeWithUID("home1"))
+        adbk = (yield home.addressbookWithName("addressbook_1"))
+        for name, md5 in (
+            ("1.vcf", ABCommonTests.md5Values[0]),
+            ("2.vcf", ABCommonTests.md5Values[1]),
+            ("3.vcf", ABCommonTests.md5Values[2]),
+        ):
+            object = (yield adbk.addressbookObjectWithName(name))
+            self.assertEquals(object.md5(), md5)

Deleted: CalendarServer/trunk/txdav/common/datastore/util.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/util.py	2011-11-29 03:25:36 UTC (rev 8348)
+++ CalendarServer/trunk/txdav/common/datastore/util.py	2011-11-29 03:27:44 UTC (rev 8349)
@@ -1,407 +0,0 @@
-# -*- test-case-name: txdav.common.datastore.test -*-
-##
-# Copyright (c) 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.
-##
-
-"""
-Utilities, mostly related to upgrading, common to calendar and addresbook
-data stores.
-"""
-
-import os
-import re
-import errno
-import xattr
-
-from twext.python.log import LoggingMixIn
-from twisted.application.service import Service
-from twisted.internet import reactor
-from twisted.internet.defer import inlineCallbacks
-from twisted.python.modules import getModule
-from twisted.python.runtime import platform
-
-from txdav.caldav.datastore.util import migrateHome as migrateCalendarHome
-from txdav.carddav.datastore.util import migrateHome as migrateAddressbookHome
-from txdav.common.datastore.file import CommonDataStore as FileStore, TOPPATHS
-from txdav.base.propertystore.xattr import PropertyStore as XattrPropertyStore
-from txdav.base.propertystore.appledouble_xattr import (
-    PropertyStore as AppleDoubleStore)
-
-
-class UpgradeToDatabaseService(Service, LoggingMixIn, object):
-    """
-    Upgrade resources from a filesystem store to a database store.
-    """
-
-    @classmethod
-    def wrapService(cls, path, service, store, uid=None, gid=None):
-        """
-        Create an L{UpgradeToDatabaseService} if there are still file-based
-        calendar or addressbook homes remaining in the given path.
-
-        @param path: a path pointing at the document root, where the file-based
-            data-store is located.
-        @type path: L{CachingFilePath}
-
-        @param service: the service to wrap.  This service should be started
-            when the upgrade is complete.  (This is accomplished by returning
-            it directly when no upgrade needs to be done, and by adding it to
-            the service hierarchy when the upgrade completes; assuming that the
-            service parent of the resulting service will be set to a
-            L{MultiService} or similar.)
-
-        @param store: the SQL storage service.
-
-        @type service: L{IService}
-
-        @return: a service
-        @rtype: L{IService}
-        """
-        # TODO: TOPPATHS should be computed based on enabled flags in 'store',
-        # not hard coded.
-        for homeType in TOPPATHS:
-            if path.child(homeType).exists():
-                if platform.isMacOSX():
-                    appropriateStoreClass = XattrPropertyStore
-                else:
-                    attrs = xattr.xattr(path.path)
-                    try:
-                        attrs.get('user.should-not-be-set')
-                    except IOError, ioe:
-                        if ioe.errno == errno.ENODATA:
-                            # xattrs are supported and enabled on the filesystem
-                            # where the calendar data lives.  this takes some
-                            # doing (you have to edit fstab), so this means
-                            # we're trying to migrate some 2.x data from a
-                            # previous linux installation.
-                            appropriateStoreClass = XattrPropertyStore
-                        elif ioe.errno == errno.EOPNOTSUPP:
-                            # The operation wasn't supported.  This is what will
-                            # usually happen on a naively configured filesystem,
-                            # so this means we're most likely trying to migrate
-                            # some data from an untarred archive created on an
-                            # OS X installation using xattrs.
-                            appropriateStoreClass = AppleDoubleStore
-                        else:
-                            # No need to check for ENOENT and the like; we just
-                            # checked above to make sure the parent exists.
-                            # Other errors are not anticipated here, so fail
-                            # fast.
-                            raise
-
-                    appropriateStoreClass = AppleDoubleStore
-
-                self = cls(
-                    FileStore(path, None, True, True,
-                              propertyStoreClass=appropriateStoreClass),
-                    store, service, uid=uid, gid=gid,
-                )
-                return self
-        return service
-
-
-    def __init__(self, fileStore, sqlStore, service, uid=None, gid=None):
-        """
-        Initialize the service.
-        """
-        self.wrappedService = service
-        self.fileStore = fileStore
-        self.sqlStore = sqlStore
-        self.uid = uid
-        self.gid = gid
-
-
-    @inlineCallbacks
-    def doMigration(self):
-        """
-        Do the migration.  Called by C{startService}, but a different method
-        because C{startService} should return C{None}, not a L{Deferred}.
-
-        @return: a Deferred which fires when the migration is complete.
-        """
-        self.sqlStore.setMigrating(True)
-
-        self.log_warn("Beginning filesystem -> database upgrade.")
-        for homeType, migrateFunc, eachFunc, destFunc, topPathName in [
-            ("calendar", migrateCalendarHome,
-                self.fileStore.eachCalendarHome,
-                lambda txn: txn.calendarHomeWithUID,
-                "calendars"),
-            ("addressbook", migrateAddressbookHome,
-                self.fileStore.eachAddressbookHome,
-                lambda txn: txn.addressbookHomeWithUID,
-                "addressbooks")
-            ]:
-            for fileTxn, fileHome in eachFunc():
-                uid = fileHome.uid()
-                self.log_warn("Migrating %s UID %r" % (homeType, uid))
-                sqlTxn = self.sqlStore.newTransaction()
-                homeGetter = destFunc(sqlTxn)
-                if (yield homeGetter(uid, create=False)) is not None:
-                    self.log_warn(
-                        "%s home %r already existed not migrating" % (
-                            homeType, uid))
-                    yield sqlTxn.abort()
-                    yield fileTxn.commit()
-                    continue
-                sqlHome = yield homeGetter(uid, create=True)
-                if sqlHome is None:
-                    raise RuntimeError("THIS SHOULD NOT BE POSSIBLE.")
-                yield migrateFunc(fileHome, sqlHome)
-                yield fileTxn.commit()
-                yield sqlTxn.commit()
-                # FIXME: need a public remove...HomeWithUID() for de-
-                # provisioning
-
-                # Remove file home after migration
-                fileHome._path.remove()
-        for homeType in TOPPATHS:
-            homesPath = self.fileStore._path.child(homeType)
-            if homesPath.isdir():
-                homesPath.remove()
-
-        # Set attachment directory ownership.  FIXME: is this still necessary
-        # since attachments started living outside the database directory
-        # created by initdb?  default permissions might be correct now.
-        sqlAttachmentsPath = self.sqlStore.attachmentsPath
-        if (sqlAttachmentsPath and sqlAttachmentsPath.exists() and
-            (self.uid or self.gid)):
-            uid = self.uid or -1
-            gid = self.gid or -1
-            for fp in sqlAttachmentsPath.walk():
-                os.chown(fp.path, uid, gid)
-
-        self.sqlStore.setMigrating(False)
-
-        self.log_warn(
-            "Filesystem upgrade complete, launching database service."
-        )
-        # see http://twistedmatrix.com/trac/ticket/4649
-        reactor.callLater(0, self.wrappedService.setServiceParent, self.parent)
-
-
-    def startService(self):
-        """
-        Start the service.
-        """
-        self.doMigration()
-
-
-
-class UpgradeDatabaseSchemaService(Service, LoggingMixIn, object):
-    """
-    Checks and upgrades the database schema. This assumes there are a bunch of
-    upgrade files in sql syntax that we can execute against the database to
-    accomplish the upgrade.
-
-    @ivar sqlStore: The store to operate on.
-
-    @type sqlStore: L{txdav.idav.IDataStore}
-
-    @ivar wrappedService: Wrapped L{IService} that will be started after this
-        L{UpgradeDatabaseSchemaService}'s work is done and the database schema
-        of C{sqlStore} is fully upgraded.  This may also be specified as
-        C{None}, in which case no service will be started.
-
-    @type wrappedService: L{IService} or C{NoneType}
-    """
-
-    @classmethod
-    def wrapService(cls, service, store, uid=None, gid=None):
-        """
-        Create an L{UpgradeDatabaseSchemaService} when starting the database
-        so we can check the schema version and do any upgrades.
-
-        @param service: the service to wrap.  This service should be started
-            when the upgrade is complete.  (This is accomplished by returning
-            it directly when no upgrade needs to be done, and by adding it to
-            the service hierarchy when the upgrade completes; assuming that the
-            service parent of the resulting service will be set to a
-            L{MultiService} or similar.)
-
-        @param store: the SQL storage service.
-
-        @type store: L{txdav.idav.IDataStore}
-
-        @type service: L{IService}
-
-        @return: a service
-        @rtype: L{IService}
-        """
-        return cls(store, service, uid=uid, gid=gid,)
-
-
-    def __init__(self, sqlStore, service, uid=None, gid=None):
-        """
-        Initialize the service.
-        """
-        self.wrappedService = service
-        self.sqlStore = sqlStore
-        self.uid = uid
-        self.gid = gid
-        self.schemaLocation = getModule(__name__).filePath.sibling("sql_schema")
-
-
-    @inlineCallbacks
-    def doUpgrade(self):
-        """
-        Do the schema check and upgrade if needed.  Called by C{startService},
-        but a different method because C{startService} should return C{None},
-        not a L{Deferred}.
-
-        @return: a Deferred which fires when the migration is complete.
-        """
-        self.log_warn("Beginning database schema check.")
-
-        # Retrieve the version number from the schema file
-        current_schema = self.schemaLocation.child("current.sql").getContent()
-        found = re.search(
-            "insert into CALENDARSERVER values \('VERSION', '(\d)+'\);",
-            current_schema)
-        if found is None:
-            msg = (
-                "Schema is missing required schema VERSION insert statement: %s"
-                % (current_schema,)
-            )
-            self.log_error(msg)
-            raise RuntimeError(msg)
-        else:
-            required_version = int(found.group(1))
-            self.log_warn("Required schema version: %s." % (required_version,))
-
-        # Get the schema version in the current database
-        sqlTxn = self.sqlStore.newTransaction()
-        dialect = sqlTxn.dialect
-        try:
-            actual_version = yield sqlTxn.schemaVersion()
-            yield sqlTxn.commit()
-        except RuntimeError:
-            self.log_error("Database schema version cannot be determined.")
-            yield sqlTxn.abort()
-            raise
-
-        self.log_warn("Actual schema version: %s." % (actual_version,))
-
-        if required_version == actual_version:
-            self.log_warn("Schema version check complete: no upgrade needed.")
-        elif required_version < actual_version:
-            msg = ("Actual schema version %s is more recent than the expected"
-                   " version %s. The service cannot be started" %
-                   (actual_version, required_version,))
-            self.log_error(msg)
-            raise RuntimeError(msg)
-        else:
-            yield self.upgradeVersion(actual_version, required_version, dialect)
-
-        self.log_warn(
-            "Database schema check complete, launching database service."
-        )
-        # see http://twistedmatrix.com/trac/ticket/4649
-        if self.wrappedService is not None:
-            reactor.callLater(0, self.wrappedService.setServiceParent,
-                              self.parent)
-
-
-    @inlineCallbacks
-    def upgradeVersion(self, fromVersion, toVersion, dialect):
-        """
-        Update the database from one version to another (the current one). Do this by
-        looking for upgrade_from_X_to_Y.sql files that cover the full range of upgrades.
-        """
-
-        self.log_warn("Starting schema upgrade from version %d to %d." % (fromVersion, toVersion,))
-        
-        # Scan for all possible upgrade files - returned sorted
-        files = self.scanForUpgradeFiles(dialect)
-        
-        # Determine upgrade sequence and run each upgrade
-        upgrades = self.determineUpgradeSequence(fromVersion, toVersion, files, dialect)
-
-        # Use one transaction for the entire set of upgrades
-        sqlTxn = self.sqlStore.newTransaction()
-        try:
-            for fp in upgrades:
-                yield self.applyUpgrade(sqlTxn, fp)
-            yield sqlTxn.commit()
-        except RuntimeError:
-            self.log_error("Database upgrade failed:" % (fp.basename(),))
-            yield sqlTxn.abort()
-            raise
-
-        self.log_warn("Schema upgraded from version %d to %d." % (fromVersion, toVersion,))
-
-    def scanForUpgradeFiles(self, dialect):
-        """
-        Scan the module path for upgrade files with the require name.
-        """
-        
-        fp = self.schemaLocation.child("upgrades").child(dialect)
-        upgrades = []
-        regex = re.compile("upgrade_from_(\d)+_to_(\d)+.sql")
-        for child in fp.globChildren("upgrade_*.sql"):
-            matched = regex.match(child.basename())
-            if matched is not None:
-                fromV = int(matched.group(1))
-                toV = int(matched.group(2))
-                upgrades.append((fromV, toV, child))
-        
-        upgrades.sort(key=lambda x:(x[0], x[1]))
-        return upgrades
-    
-    def determineUpgradeSequence(self, fromVersion, toVersion, files, dialect):
-        """
-        Determine the upgrade_from_X_to_Y.sql files that cover the full range of upgrades.
-        Note that X and Y may not be consecutive, e.g., we might have an upgrade from 3 to 4,
-        4 to 5, and 3 to 5 - the later because it is more efficient to jump over the intermediate
-        step. As a result we will always try and pick the upgrade file that gives the biggest
-        jump from one version to another at each step.
-        """
-
-        # Now find the path from the old version to the current one
-        filesByFromVersion = {}
-        for fromV, toV, fp in files:
-            if fromV not in filesByFromVersion or filesByFromVersion[fromV][1] < toV:
-                filesByFromVersion[fromV] = fromV, toV, fp
-        
-        upgrades = []
-        nextVersion = fromVersion
-        while nextVersion != toVersion:
-            if nextVersion not in filesByFromVersion:
-                msg = "Missing upgrade file from version %d with dialect %s" % (nextVersion, dialect,)
-                self.log_error(msg)
-                raise RuntimeError(msg)
-            else:
-                upgrades.append(filesByFromVersion[nextVersion][2])
-                nextVersion = filesByFromVersion[nextVersion][1]
-        
-        return upgrades
-
-    @inlineCallbacks
-    def applyUpgrade(self, sqlTxn, fp):
-        """
-        Apply the schema upgrade .sql file to the database.
-        """
-        self.log_warn("Applying schema upgrade: %s" % (fp.basename(),))
-        sql = fp.getContent()
-        yield sqlTxn.execSQLBlock(sql)
-        
-    def startService(self):
-        """
-        Start the service.
-        """
-        self.doUpgrade()
-
-
-
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20111128/32e87906/attachment-0001.html>


More information about the calendarserver-changes mailing list