[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