1"""
2
3davcmd.py
4---------
5
6containts commands like copy, move, delete for normal
7resources and collections
8
9"""
10
11from string import split,replace,joinfields
12import urlparse
13
14from utils import create_treelist, is_prefix
15from errors import *
16
17def deltree(dc,uri,exclude={}):
18    """ delete a tree of resources
19
20    dc  -- dataclass to use
21    uri -- root uri to delete
22    exclude -- an optional list of uri:error_code pairs which should not
23           be deleted.
24
25    returns dict of uri:error_code tuples from which
26    another method can create a multistatus xml element.
27
28    Also note that we only know Depth=infinity thus we don't have
29    to test for it.
30
31    """
32
33    tlist=create_treelist(dc,uri)
34    result={}
35
36    for i in range(len(tlist),0,-1):
37        problem_uris=result.keys()
38        element=tlist[i-1]
39
40        # test here, if an element is a prefix of an uri which
41        # generated an error before.
42        # note that we walk here from childs to parents, thus
43        # we cannot delete a parent if a child made a problem.
44        # (see example in 8.6.2.1)
45        ok=1
46        for p in problem_uris:
47            if is_prefix(element,p):
48                ok=None
49                break
50
51            if not ok: continue
52
53        # here we test for the exclude list which is the other way round!
54        for p in exclude.keys():
55            if is_prefix(p,element):
56                ok=None
57                break
58
59            if not ok: continue
60
61        # now delete stuff
62        try:
63            delone(dc,element)
64        except DAV_Error, (ec,dd):
65            result[element]=ec
66
67    return result
68
69def delone(dc,uri):
70    """ delete a single object """
71    if dc.is_collection(uri):
72        return dc.rmcol(uri)   # should be empty
73    else:
74        return dc.rm(uri)
75
76###
77### COPY
78###
79
80# helper function
81
82def copy(dc,src,dst):
83    """ only copy the element
84
85    This is just a helper method factored out from copy and
86    copytree. It will not handle the overwrite or depth header.
87
88    """
89
90    # destination should have been deleted before
91    if dc.exists(dst):
92        raise DAV_Error, 412
93
94    # source should exist also
95    if not dc.exists(src):
96        raise DAV_NotFound
97
98    if dc.is_collection(src):
99        dc.copycol(src, dst) # an exception will be passed thru
100    else:
101        dc.copy(src, dst)  # an exception will be passed thru
102
103# the main functions
104
105def copyone(dc,src,dst,overwrite=None):
106    """ copy one resource to a new destination """
107
108    if overwrite and dc.exists(dst):
109        delres = deltree(dc, dst)
110    else:
111        delres={}
112
113    # if we cannot delete everything, then do not copy!
114    if delres:
115        return delres
116
117    try:
118        copy(dc, src, dst)    # pass thru exceptions
119    except DAV_Error, (ec, dd):
120        return ec
121
122def copytree(dc,src,dst,overwrite=None):
123    """ copy a tree of resources to another location
124
125    dc  -- dataclass to use
126    src -- src uri from where to copy
127    dst -- dst uri
128    overwrite -- if 1 then delete dst uri before
129
130    returns dict of uri:error_code tuples from which
131    another method can create a multistatus xml element.
132
133    """
134
135    # first delete the destination resource
136    if overwrite and dc.exists(dst):
137        delres=deltree(dc,dst)
138    else:
139        delres={}
140
141    # if we cannot delete everything, then do not copy!
142    if delres:
143        return delres
144
145    # get the tree we have to copy
146    tlist = create_treelist(dc,src)
147    result = {}
148
149    # prepare destination URIs (get the prefix)
150    dpath = urlparse.urlparse(dst)[2]
151
152    for element in tlist:
153        problem_uris = result.keys()
154
155        # now URIs get longer and longer thus we have
156        # to test if we had a parent URI which we were not
157        # able to copy in problem_uris which is the prefix
158        # of the actual element. If it is, then we cannot
159        # copy this as well but do not generate another error.
160        ok=1
161        for p in problem_uris:
162            if is_prefix(p,element):
163                ok=None
164                break
165
166        if not ok: continue
167
168        # now create the destination URI which corresponds to
169        # the actual source URI. -> actual_dst
170        # ("subtract" the base src from the URI and prepend the
171        # dst prefix to it.)
172        esrc=replace(element,src,"")
173        actual_dst=dpath+esrc
174
175        # now copy stuff
176        try:
177            copy(dc,element,actual_dst)
178        except DAV_Error, (ec,dd):
179            result[element]=ec
180
181    return result
182
183
184###
185### MOVE
186###
187
188
189def moveone(dc,src,dst,overwrite=None):
190    """ move a single resource
191
192    This is done by first copying it and then deleting
193    the original.
194    """
195
196    # first copy it
197    copyone(dc, src, dst, overwrite)
198
199    # then delete it
200    dc.rm(src)
201
202def movetree(dc,src,dst,overwrite=None):
203    """ move a collection
204
205    This is done by first copying it and then deleting
206    the original.
207
208    PROBLEM: if something did not copy then we have a problem
209    when deleting as the original might get deleted!
210    """
211
212    # first copy it
213    res = copytree(dc,src,dst,overwrite)
214
215    # then delete it
216    res = deltree(dc,src,exclude=res)
217
218    return res
219
220