* subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c
[svn.git] / subversion / bindings / swig / python / svn / repos.py
blob56e9103215d37dda7a7e94d0f3643903cd9044a7
2 # repos.py: public Python interface for repos components
4 # Subversion is a tool for revision control.
5 # See http://subversion.tigris.org for more information.
7 ######################################################################
9 # Copyright (c) 2000-2004 CollabNet. All rights reserved.
11 # This software is licensed as described in the file COPYING, which
12 # you should have received as part of this distribution. The terms
13 # are also available at http://subversion.tigris.org/license-1.html.
14 # If newer versions of this license are posted there, you may use a
15 # newer version instead, at your option.
17 ######################################################################
19 from libsvn.repos import *
20 from svn.core import _unprefix_names, Pool
21 _unprefix_names(locals(), 'svn_repos_')
22 _unprefix_names(locals(), 'SVN_REPOS_')
23 del _unprefix_names
26 # Names that are not to be exported
27 import svn.core as _svncore, svn.fs as _svnfs, svn.delta as _svndelta
29 # Available change actions
30 CHANGE_ACTION_MODIFY = 0
31 CHANGE_ACTION_ADD = 1
32 CHANGE_ACTION_DELETE = 2
33 CHANGE_ACTION_REPLACE = 3
36 class ChangedPath:
37 __slots__ = [ 'item_kind', 'prop_changes', 'text_changed',
38 'base_path', 'base_rev', 'path', 'added', 'action',
40 def __init__(self,
41 item_kind, prop_changes, text_changed, base_path, base_rev,
42 path, added, action=None):
43 self.item_kind = item_kind
44 self.prop_changes = prop_changes
45 self.text_changed = text_changed
46 self.base_path = base_path
47 self.base_rev = base_rev
48 self.path = path
49 if action not in [None, CHANGE_ACTION_MODIFY, CHANGE_ACTION_ADD,
50 CHANGE_ACTION_DELETE, CHANGE_ACTION_REPLACE]:
51 raise Exception, "unsupported change type"
52 self.action = action
54 ### it would be nice to avoid this flag. however, without it, it would
55 ### be quite difficult to distinguish between a change to the previous
56 ### revision (which has a base_path/base_rev) and a copy from some
57 ### other path/rev. a change in path is obviously add-with-history,
58 ### but the same path could be a change to the previous rev or a restore
59 ### of an older version. when it is "change to previous", I'm not sure
60 ### if the rev is always repos.rev - 1, or whether it represents the
61 ### created or time-of-checkout rev. so... we use a flag (for now)
62 ### Note: This flag is also set for replaced paths unlike self.action
63 ### which is either set to CHANGE_ACTION_ADD or CHANGE_ACTION_REPLACE
64 self.added = added
67 class ChangeCollector(_svndelta.Editor):
68 """Available Since: 1.2.0
69 """
71 # BATON FORMAT: [path, base_path, base_rev]
73 def __init__(self, fs_ptr, root, pool=None, notify_cb=None):
74 self.fs_ptr = fs_ptr
75 self.changes = { } # path -> ChangedPathEntry()
76 self.roots = { } # revision -> svn_svnfs_root_t
77 self.notify_cb = notify_cb
78 self.props = { }
79 self.fs_root = root
81 # Figger out the base revision and root properties.
82 if _svnfs.is_revision_root(self.fs_root):
83 rev = _svnfs.revision_root_revision(self.fs_root)
84 self.base_rev = rev - 1
85 self.props = _svnfs.revision_proplist(self.fs_ptr, rev)
86 else:
87 txn_name = _svnfs.txn_root_name(self.fs_root)
88 txn_t = _svnfs.open_txn(self.fs_ptr, txn_name)
89 self.base_rev = _svnfs.txn_base_revision(txn_t)
90 self.props = _svnfs.txn_proplist(txn_t)
92 def get_root_props(self):
93 return self.props
95 def get_changes(self):
96 return self.changes
98 def _send_change(self, path):
99 if self.notify_cb:
100 change = self.changes.get(path)
101 if change:
102 self.notify_cb(change)
104 def _make_base_path(self, parent_path, path):
105 idx = path.rfind('/')
106 if parent_path:
107 parent_path = parent_path + '/'
108 if idx == -1:
109 return parent_path + path
110 return parent_path + path[idx+1:]
112 def _get_root(self, rev):
113 try:
114 return self.roots[rev]
115 except KeyError:
116 pass
117 root = self.roots[rev] = _svnfs.revision_root(self.fs_ptr, rev)
118 return root
120 def open_root(self, base_revision, dir_pool=None):
121 return ('', '', self.base_rev) # dir_baton
123 def delete_entry(self, path, revision, parent_baton, pool=None):
124 base_path = self._make_base_path(parent_baton[1], path)
125 if _svnfs.is_dir(self._get_root(parent_baton[2]), base_path):
126 item_type = _svncore.svn_node_dir
127 else:
128 item_type = _svncore.svn_node_file
129 self.changes[path] = ChangedPath(item_type,
130 False,
131 False,
132 base_path,
133 parent_baton[2], # base_rev
134 None, # (new) path
135 False, # added
136 CHANGE_ACTION_DELETE,
138 self._send_change(path)
140 def add_directory(self, path, parent_baton,
141 copyfrom_path, copyfrom_revision, dir_pool=None):
142 action = self.changes.has_key(path) and CHANGE_ACTION_REPLACE \
143 or CHANGE_ACTION_ADD
144 self.changes[path] = ChangedPath(_svncore.svn_node_dir,
145 False,
146 False,
147 copyfrom_path, # base_path
148 copyfrom_revision, # base_rev
149 path, # path
150 True, # added
151 action,
153 if copyfrom_path and (copyfrom_revision != -1):
154 base_path = copyfrom_path
155 else:
156 base_path = path
157 base_rev = copyfrom_revision
158 return (path, base_path, base_rev) # dir_baton
160 def open_directory(self, path, parent_baton, base_revision, dir_pool=None):
161 base_path = self._make_base_path(parent_baton[1], path)
162 return (path, base_path, parent_baton[2]) # dir_baton
164 def change_dir_prop(self, dir_baton, name, value, pool=None):
165 dir_path = dir_baton[0]
166 if self.changes.has_key(dir_path):
167 self.changes[dir_path].prop_changes = True
168 else:
169 # can't be added or deleted, so this must be CHANGED
170 self.changes[dir_path] = ChangedPath(_svncore.svn_node_dir,
171 True,
172 False,
173 dir_baton[1], # base_path
174 dir_baton[2], # base_rev
175 dir_path, # path
176 False, # added
177 CHANGE_ACTION_MODIFY,
180 def add_file(self, path, parent_baton,
181 copyfrom_path, copyfrom_revision, file_pool=None):
182 action = self.changes.has_key(path) and CHANGE_ACTION_REPLACE \
183 or CHANGE_ACTION_ADD
184 self.changes[path] = ChangedPath(_svncore.svn_node_file,
185 False,
186 False,
187 copyfrom_path, # base_path
188 copyfrom_revision, # base_rev
189 path, # path
190 True, # added
191 action,
193 if copyfrom_path and (copyfrom_revision != -1):
194 base_path = copyfrom_path
195 else:
196 base_path = path
197 base_rev = copyfrom_revision
198 return (path, base_path, base_rev) # file_baton
200 def open_file(self, path, parent_baton, base_revision, file_pool=None):
201 base_path = self._make_base_path(parent_baton[1], path)
202 return (path, base_path, parent_baton[2]) # file_baton
204 def apply_textdelta(self, file_baton, base_checksum):
205 file_path = file_baton[0]
206 if self.changes.has_key(file_path):
207 self.changes[file_path].text_changed = True
208 else:
209 # an add would have inserted a change record already, and it can't
210 # be a delete with a text delta, so this must be a normal change.
211 self.changes[file_path] = ChangedPath(_svncore.svn_node_file,
212 False,
213 True,
214 file_baton[1], # base_path
215 file_baton[2], # base_rev
216 file_path, # path
217 False, # added
218 CHANGE_ACTION_MODIFY,
221 # no handler
222 return None
224 def change_file_prop(self, file_baton, name, value, pool=None):
225 file_path = file_baton[0]
226 if self.changes.has_key(file_path):
227 self.changes[file_path].prop_changes = True
228 else:
229 # an add would have inserted a change record already, and it can't
230 # be a delete with a prop change, so this must be a normal change.
231 self.changes[file_path] = ChangedPath(_svncore.svn_node_file,
232 True,
233 False,
234 file_baton[1], # base_path
235 file_baton[2], # base_rev
236 file_path, # path
237 False, # added
238 CHANGE_ACTION_MODIFY,
240 def close_directory(self, dir_baton):
241 self._send_change(dir_baton[0])
243 def close_file(self, file_baton, text_checksum):
244 self._send_change(file_baton[0])
247 class RevisionChangeCollector(ChangeCollector):
248 """Deprecated: Use ChangeCollector.
249 This is a compatibility wrapper providing the interface of the
250 Subversion 1.1.x and earlier bindings.
252 Important difference: base_path members have a leading '/' character in
253 this interface."""
255 def __init__(self, fs_ptr, root, pool=None, notify_cb=None):
256 root = _svnfs.revision_root(fs_ptr, root)
257 ChangeCollector.__init__(self, fs_ptr, root, pool, notify_cb)
259 def _make_base_path(self, parent_path, path):
260 idx = path.rfind('/')
261 if idx == -1:
262 return parent_path + '/' + path
263 return parent_path + path[idx:]
266 # enable True/False in older vsns of Python
267 try:
268 True
269 except NameError:
270 True = 1
271 False = 0