diff options
Diffstat (limited to 'src/webdav/VersionHandler.py')
-rw-r--r-- | src/webdav/VersionHandler.py | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/src/webdav/VersionHandler.py b/src/webdav/VersionHandler.py new file mode 100644 index 0000000..a1962c6 --- /dev/null +++ b/src/webdav/VersionHandler.py @@ -0,0 +1,198 @@ +# pylint: disable-msg=W0612,W0142 +# +# Copyright 2008 German Aerospace Center (DLR) +# +# 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. + + +""" +The WebDAV client module forwards Delta-V related method invocations to +the following VersionHandler class. +""" + +__version__ = '$Revision$'[11:-2] + + +import types + +from webdav import Constants +from davlib import XML_CONTENT_TYPE, XML_DOC_HEADER + + +class VersionHandler(object): + """ + Implements a client interface for WebDAV Delta-V methods + For the Delta-V see RFC 3253 at http://www.ietf.org/rfc/rfc3253.txt + """ + + # restrict instance variables + __slots__ = ('path', 'connection') + + + def __init__(self, connection, path): + """ + Construct a VersionHandler with a URL path and a WebDAV connection. + This constructor must not be called outside class ResourceStorer. + + @param connection: L{webdav.Connection} instance + @param path: resource's path part of URL + """ + #assert isinstance(connection, Connection), \ + # "Class of connection is %s." % connection.__class__.__name__ + self.connection = connection + self.path = path + + + def activateVersionControl(self): + """ + Turns version control on for this resource. + The resource becomes a version controlled resource (VCR) + """ + response = self.connection._request(Constants.METHOD_VERSION_CONTROL, self.path, None, {}) + # set auto-versioning to DAV:locked-checkout + ## parse response body in case of an error + + def uncheckout(self, lockToken=None): + """ + Undos a previous check-out operation on this VCR. + The VCR is reverted to the state before the checkout/lock operation. + Beware: Property or content changes will be lost ! + A (optional) lock has to be removed seperatedly. + + @param lockToken: returned by a preceeding lock() method invocation or None + """ + headers = {} + if lockToken: + headers = lockToken.toHeader() + response = self.connection._request(Constants.METHOD_UNCHECKOUT, self.path, None, headers) + ## parse response body in case of an error + + def listAllVersions(self): + """ + List version history. + + @return: List of versions for this VCR. Each version entry is a tuple adhering + to the format (URL-path, name, creator, tuple of successor URL-paths). + If there are no branches then there is at most one successor within the tuple. + """ + # implementation is similar to the propfind method + headers = {} + headers['Content-Type'] = XML_CONTENT_TYPE + body = _createReportVersionTreeBody() + response = self.connection._request(Constants.METHOD_REPORT, self.path, body, headers) + # response is multi-status + result = [] + for path, properties in response.msr.items(): + # parse the successor-set value from XML into alist + result.append( (path, str(properties[Constants.PROP_VERSION_NAME]), \ + str(properties[Constants.PROP_CREATOR]), \ + _extractSuccessorList(properties[Constants.PROP_SUCCESSOR_SET])) ) + ## TODO: sort for path and produce list + result.sort() + return result + + # warning: not tested yet + def readVersionProperties(self): + """ + Provide version related information on this VCR. + This include a reference to the latest version resource, + check-out state information and a comment. + + @return: map of version properties with values. + """ + versionProperties = (Constants.PROP_CHECKEDIN, Constants.PROP_CHECKEDOUT, Constants.PROP_COMMENT) + return self.connection.readProperties(*versionProperties) + + + def revertToVersion(self, oldVersion): + """ + Revert this VCR to the given version. + Beware: All versions succeeding the given version are made unavailable. + + @param oldVersion: URL-path of a previous version of this VCR. + """ + ## send an update request + assert isinstance(oldVersion, types.StringType) or isinstance(oldVersion, types.UnicodeType) + response = self.connection._request(Constants.METHOD_UPDATE, self.path, + _createUpdateBody(oldVersion), {}) + return response + + + # the following is not needed when using auto-versioning + + # warning: not tested yet + def checkout(self): + """ + Marks resource as checked-out + This is usually followed by a GET (download) operation. + """ + response = self.connection._request(Constants.METHOD_CHECKOUT, self.path, None, {}) + ## parse response body in case of an error + + # warning: not tested yet + def checkin(self): + """ + Creates a new version from the VCR's content. + This opeartion is usually preceeded by one or more write operations. + """ + response = self.connection._request(Constants.METHOD_CHECKIN, self.path, None, {}) + versionUrl = response.getheader('Location') + return versionUrl + ## parse response body in case of an error + + + + +# Helper functions +def _createReportVersionTreeBody(): + """ + TBD + + @return: ... + @rtype: string + """ + versions = 'D:' + Constants.TAG_VERSION_TREE + prop = 'D:' + Constants.TAG_PROP + nameList = [Constants.PROP_SUCCESSOR_SET, Constants.PROP_VERSION_NAME, Constants.PROP_CREATOR] + return XML_DOC_HEADER + \ + '<%s xmlns:D="DAV:"><%s>' % (versions, prop) + \ + reduce(lambda xml, name: xml + "<D:%s/>" % name[1], [''] + nameList) + \ + '</%s></%s>' % (prop, versions) + +def _createUpdateBody(path): + """ + TBD + + @return: ... + @rtype: string + """ + update = 'D:' + Constants.TAG_UPDATE + version = 'D:' + Constants.TAG_VERSION + href = 'D:' + Constants.TAG_HREF + #PROP = 'D:' + TAG_PROP + return XML_DOC_HEADER + \ + '<%s xmlns:D="DAV:"><%s><%s>' % (update, version, href) + \ + path + \ + '</%s></%s></%s>' % (href, version, update) + +def _extractSuccessorList(element): + """ + TBD + + @return: ... + @rtype: tuple of strings + """ + result = [] + for href in element.children: + result.append(href.textof()) + return tuple(result) |