annotate examples/trac/trac/versioncontrol/svn_fs.py @ 39:93b4dcbafd7b trunk

Copy Trac to main branch.
author cmlenz
date Mon, 03 Jul 2006 18:53:27 +0000
parents
children
rev   line source
39
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
1 # -*- coding: utf-8 -*-
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
2 #
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
3 # Copyright (C) 2005-2006 Edgewall Software
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
4 # Copyright (C) 2005 Christopher Lenz <cmlenz@gmx.de>
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
5 # Copyright (C) 2005-2006 Christian Boos <cboos@neuf.fr>
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
6 # All rights reserved.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
7 #
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
8 # This software is licensed as described in the file COPYING, which
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
9 # you should have received as part of this distribution. The terms
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
10 # are also available at http://trac.edgewall.com/license.html.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
11 #
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
12 # This software consists of voluntary contributions made by many
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
13 # individuals. For the exact contribution history, see the revision
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
14 # history and logs, available at http://projects.edgewall.com/trac/.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
15 #
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
16 # Author: Christopher Lenz <cmlenz@gmx.de>
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
17 # Christian Boos <cboos@neuf.fr>
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
18
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
19 """
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
20 Note about Unicode:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
21 All paths (or strings) manipulated by the Subversion bindings are
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
22 assumed to be UTF-8 encoded.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
23
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
24 All paths manipulated by Trac are `unicode` objects.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
25
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
26 Therefore:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
27 * before being handed out to SVN, the Trac paths have to be encoded to UTF-8,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
28 using `_to_svn()`
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
29 * before being handed out to Trac, a SVN path has to be decoded from UTF-8,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
30 using `_from_svn()`
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
31
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
32 Warning: `SubversionNode.get_content` returns an object from which one
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
33 can read a stream of bytes.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
34 NO guarantees can be given about what that stream of bytes
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
35 represents.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
36 It might be some text, encoded in some way or another.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
37 SVN properties __might__ give some hints about the content,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
38 but they actually only reflect the beliefs of whomever set
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
39 those properties...
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
40 """
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
41
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
42 import os.path
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
43 import time
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
44 import weakref
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
45 import posixpath
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
46
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
47 from trac.core import *
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
48 from trac.versioncontrol import Changeset, Node, Repository, \
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
49 IRepositoryConnector, \
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
50 NoSuchChangeset, NoSuchNode
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
51 from trac.versioncontrol.cache import CachedRepository
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
52 from trac.versioncontrol.svn_authz import SubversionAuthorizer
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
53 from trac.util.text import to_unicode
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
54
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
55 try:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
56 from svn import fs, repos, core, delta
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
57 has_subversion = True
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
58 except ImportError:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
59 has_subversion = False
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
60 class dummy_svn(object):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
61 svn_node_dir = 1
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
62 svn_node_file = 2
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
63 def apr_pool_destroy(): pass
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
64 def apr_terminate(): pass
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
65 def apr_pool_clear(): pass
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
66 Editor = object
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
67 delta = core = dummy_svn()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
68
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
69
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
70 _kindmap = {core.svn_node_dir: Node.DIRECTORY,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
71 core.svn_node_file: Node.FILE}
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
72
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
73
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
74 application_pool = None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
75
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
76 def _get_history(svn_path, authz, fs_ptr, pool, start, end, limit=None):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
77 """`svn_path` is assumed to be a UTF-8 encoded string.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
78 Returned history paths will be `unicode` objects though."""
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
79 history = []
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
80 if hasattr(repos, 'svn_repos_history2'):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
81 # For Subversion >= 1.1
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
82 def authz_cb(root, path, pool):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
83 if limit and len(history) >= limit:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
84 return 0
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
85 return authz.has_permission(_from_svn(path)) and 1 or 0
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
86 def history2_cb(path, rev, pool):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
87 history.append((_from_svn(path), rev))
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
88 repos.svn_repos_history2(fs_ptr, svn_path, history2_cb, authz_cb,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
89 start, end, 1, pool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
90 else:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
91 # For Subversion 1.0.x
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
92 def history_cb(path, rev, pool):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
93 path = _from_svn(path)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
94 if authz.has_permission(path):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
95 history.append((path, rev))
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
96 repos.svn_repos_history(fs_ptr, svn_path, history_cb,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
97 start, end, 1, pool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
98 for item in history:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
99 yield item
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
100
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
101 def _to_svn(*args):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
102 """Expect a list of `unicode` path components.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
103 Returns an UTF-8 encoded string suitable for the Subversion python bindings.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
104 """
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
105 return '/'.join([path.strip('/') for path in args]).encode('utf-8')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
106
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
107 def _from_svn(path):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
108 """Expect an UTF-8 encoded string and transform it to an `unicode` object"""
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
109 return path and path.decode('utf-8')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
110
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
111 def _normalize_path(path):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
112 """Remove leading "/", except for the root."""
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
113 return path and path.strip('/') or '/'
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
114
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
115 def _path_within_scope(scope, fullpath):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
116 """Remove the leading scope from repository paths.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
117
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
118 Return `None` if the path is not is scope.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
119 """
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
120 if fullpath is not None:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
121 fullpath = fullpath.lstrip('/')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
122 if scope == '/':
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
123 return _normalize_path(fullpath)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
124 scope = scope.strip('/')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
125 if (fullpath + '/').startswith(scope + '/'):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
126 return fullpath[len(scope) + 1:] or '/'
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
127
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
128 def _is_path_within_scope(scope, fullpath):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
129 """Check whether the given `fullpath` is within the given `scope`"""
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
130 if scope == '/':
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
131 return fullpath is not None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
132 fullpath = fullpath and fullpath.lstrip('/') or ''
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
133 scope = scope.strip('/')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
134 return (fullpath + '/').startswith(scope + '/')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
135
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
136
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
137 def _mark_weakpool_invalid(weakpool):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
138 if weakpool():
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
139 weakpool()._mark_invalid()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
140
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
141
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
142 class Pool(object):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
143 """A Pythonic memory pool object"""
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
144
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
145 # Protect svn.core methods from GC
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
146 apr_pool_destroy = staticmethod(core.apr_pool_destroy)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
147 apr_terminate = staticmethod(core.apr_terminate)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
148 apr_pool_clear = staticmethod(core.apr_pool_clear)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
149
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
150 def __init__(self, parent_pool=None):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
151 """Create a new memory pool"""
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
152
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
153 global application_pool
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
154 self._parent_pool = parent_pool or application_pool
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
155
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
156 # Create pool
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
157 if self._parent_pool:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
158 self._pool = core.svn_pool_create(self._parent_pool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
159 else:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
160 # If we are an application-level pool,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
161 # then initialize APR and set this pool
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
162 # to be the application-level pool
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
163 core.apr_initialize()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
164 application_pool = self
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
165
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
166 self._pool = core.svn_pool_create(None)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
167 self._mark_valid()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
168
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
169 def __call__(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
170 return self._pool
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
171
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
172 def valid(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
173 """Check whether this memory pool and its parents
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
174 are still valid"""
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
175 return hasattr(self,"_is_valid")
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
176
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
177 def assert_valid(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
178 """Assert that this memory_pool is still valid."""
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
179 assert self.valid();
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
180
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
181 def clear(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
182 """Clear embedded memory pool. Invalidate all subpools."""
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
183 self.apr_pool_clear(self._pool)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
184 self._mark_valid()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
185
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
186 def destroy(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
187 """Destroy embedded memory pool. If you do not destroy
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
188 the memory pool manually, Python will destroy it
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
189 automatically."""
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
190
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
191 global application_pool
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
192
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
193 self.assert_valid()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
194
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
195 # Destroy pool
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
196 self.apr_pool_destroy(self._pool)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
197
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
198 # Clear application pool and terminate APR if necessary
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
199 if not self._parent_pool:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
200 application_pool = None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
201 self.apr_terminate()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
202
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
203 self._mark_invalid()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
204
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
205 def __del__(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
206 """Automatically destroy memory pools, if necessary"""
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
207 if self.valid():
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
208 self.destroy()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
209
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
210 def _mark_valid(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
211 """Mark pool as valid"""
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
212 if self._parent_pool:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
213 # Refer to self using a weakreference so that we don't
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
214 # create a reference cycle
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
215 weakself = weakref.ref(self)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
216
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
217 # Set up callbacks to mark pool as invalid when parents
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
218 # are destroyed
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
219 self._weakref = weakref.ref(self._parent_pool._is_valid,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
220 lambda x: \
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
221 _mark_weakpool_invalid(weakself));
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
222
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
223 # mark pool as valid
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
224 self._is_valid = lambda: 1
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
225
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
226 def _mark_invalid(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
227 """Mark pool as invalid"""
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
228 if self.valid():
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
229 # Mark invalid
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
230 del self._is_valid
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
231
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
232 # Free up memory
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
233 del self._parent_pool
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
234 if hasattr(self, "_weakref"):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
235 del self._weakref
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
236
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
237
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
238 # Initialize application-level pool
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
239 if has_subversion:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
240 Pool()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
241
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
242
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
243 class SubversionConnector(Component):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
244
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
245 implements(IRepositoryConnector)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
246
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
247 def get_supported_types(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
248 global has_subversion
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
249 if has_subversion:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
250 yield ("svnfs", 4)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
251 yield ("svn", 2)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
252
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
253 def get_repository(self, type, dir, authname):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
254 """Return a `SubversionRepository`.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
255
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
256 The repository is generally wrapped in a `CachedRepository`,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
257 unless `direct-svn-fs` is the specified type.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
258 """
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
259 authz = None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
260 if authname:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
261 authz = SubversionAuthorizer(self.env, authname)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
262 repos = SubversionRepository(dir, authz, self.log)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
263 return CachedRepository(self.env.get_db_cnx(), repos, authz, self.log)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
264
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
265
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
266 class SubversionRepository(Repository):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
267 """
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
268 Repository implementation based on the svn.fs API.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
269 """
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
270
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
271 def __init__(self, path, authz, log):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
272 self.path = path # might be needed by __del__()/close()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
273 self.log = log
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
274 if core.SVN_VER_MAJOR < 1:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
275 raise TracError("Subversion >= 1.0 required: Found %d.%d.%d" % \
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
276 (core.SVN_VER_MAJOR,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
277 core.SVN_VER_MINOR,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
278 core.SVN_VER_MICRO))
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
279 self.pool = Pool()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
280
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
281 # Remove any trailing slash or else subversion might abort
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
282 if isinstance(path, unicode):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
283 path = path.encode('utf-8')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
284 path = os.path.normpath(path).replace('\\', '/')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
285 self.path = repos.svn_repos_find_root_path(path, self.pool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
286 if self.path is None:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
287 raise TracError("%s does not appear to be a Subversion repository." \
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
288 % path)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
289
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
290 self.repos = repos.svn_repos_open(self.path, self.pool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
291 self.fs_ptr = repos.svn_repos_fs(self.repos)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
292
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
293 uuid = fs.get_uuid(self.fs_ptr, self.pool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
294 name = 'svn:%s:%s' % (uuid, path)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
295
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
296 Repository.__init__(self, name, authz, log)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
297
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
298 if self.path != path:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
299 self.scope = path[len(self.path):]
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
300 if not self.scope[-1] == '/':
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
301 self.scope += '/'
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
302 else:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
303 self.scope = '/'
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
304 assert self.scope[0] == '/'
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
305
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
306 self.log.debug("Opening subversion file-system at %s with scope %s" \
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
307 % (self.path, self.scope))
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
308 self.youngest = None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
309 self.oldest = None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
310
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
311 def __del__(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
312 self.close()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
313
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
314 def has_node(self, path, rev, pool=None):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
315 if not pool:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
316 pool = self.pool
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
317 rev_root = fs.revision_root(self.fs_ptr, rev, pool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
318 node_type = fs.check_path(rev_root, _to_svn(self.scope, path), pool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
319 return node_type in _kindmap
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
320
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
321 def normalize_path(self, path):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
322 return _normalize_path(path)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
323
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
324 def normalize_rev(self, rev):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
325 try:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
326 rev = int(rev)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
327 except (ValueError, TypeError):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
328 rev = None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
329 if rev is None:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
330 rev = self.youngest_rev
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
331 elif rev > self.youngest_rev:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
332 raise NoSuchChangeset(rev)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
333 return rev
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
334
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
335 def close(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
336 self.log.debug("Closing subversion file-system at %s" % self.path)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
337 self.repos = None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
338 self.fs_ptr = None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
339 self.pool = None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
340
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
341 def get_changeset(self, rev):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
342 return SubversionChangeset(int(rev), self.authz, self.scope,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
343 self.fs_ptr, self.pool)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
344
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
345 def get_node(self, path, rev=None):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
346 path = path or ''
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
347 self.authz.assert_permission(posixpath.join(self.scope, path))
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
348 if path and path[-1] == '/':
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
349 path = path[:-1]
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
350
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
351 rev = self.normalize_rev(rev)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
352
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
353 return SubversionNode(path, rev, self.authz, self.scope, self.fs_ptr,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
354 self.pool)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
355
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
356 def _history(self, path, start, end, limit=None, pool=None):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
357 return _get_history(_to_svn(self.scope, path), self.authz, self.fs_ptr,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
358 pool or self.pool, start, end, limit)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
359
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
360 def _previous_rev(self, rev, path='', pool=None):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
361 if rev > 1: # don't use oldest here, as it's too expensive
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
362 try:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
363 for _, prev in self._history(path, 0, rev-1, limit=1,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
364 pool=pool):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
365 return prev
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
366 except (SystemError, # "null arg to internal routine" in 1.2.x
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
367 core.SubversionException): # in 1.3.x
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
368 pass
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
369 return None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
370
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
371
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
372 def get_oldest_rev(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
373 if self.oldest is None:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
374 self.oldest = 1
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
375 if self.scope != '/':
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
376 self.oldest = self.next_rev(0, find_initial_rev=True)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
377 return self.oldest
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
378
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
379 def get_youngest_rev(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
380 if not self.youngest:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
381 self.youngest = fs.youngest_rev(self.fs_ptr, self.pool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
382 if self.scope != '/':
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
383 for path, rev in self._history('', 0, self.youngest, limit=1):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
384 self.youngest = rev
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
385 return self.youngest
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
386
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
387 def previous_rev(self, rev, path=''):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
388 rev = self.normalize_rev(rev)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
389 return self._previous_rev(rev, path)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
390
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
391 def next_rev(self, rev, path='', find_initial_rev=False):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
392 rev = self.normalize_rev(rev)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
393 next = rev + 1
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
394 youngest = self.youngest_rev
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
395 subpool = Pool(self.pool)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
396 while next <= youngest:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
397 subpool.clear()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
398 try:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
399 for _, next in self._history(path, rev+1, next, limit=1,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
400 pool=subpool):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
401 return next
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
402 except (SystemError, # "null arg to internal routine" in 1.2.x
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
403 core.SubversionException): # in 1.3.x
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
404 if not find_initial_rev:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
405 return next # a 'delete' event is also interesting...
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
406 next += 1
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
407 return None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
408
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
409 def rev_older_than(self, rev1, rev2):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
410 return self.normalize_rev(rev1) < self.normalize_rev(rev2)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
411
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
412 def get_youngest_rev_in_cache(self, db):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
413 """Get the latest stored revision by sorting the revision strings
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
414 numerically
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
415 """
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
416 cursor = db.cursor()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
417 cursor.execute("SELECT rev FROM revision "
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
418 "ORDER BY -LENGTH(rev), rev DESC LIMIT 1")
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
419 row = cursor.fetchone()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
420 return row and row[0] or None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
421
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
422 def get_path_history(self, path, rev=None, limit=None):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
423 path = self.normalize_path(path)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
424 rev = self.normalize_rev(rev)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
425 expect_deletion = False
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
426 subpool = Pool(self.pool)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
427 while rev:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
428 subpool.clear()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
429 if self.has_node(path, rev, subpool):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
430 if expect_deletion:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
431 # it was missing, now it's there again:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
432 # rev+1 must be a delete
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
433 yield path, rev+1, Changeset.DELETE
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
434 newer = None # 'newer' is the previously seen history tuple
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
435 older = None # 'older' is the currently examined history tuple
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
436 for p, r in _get_history(_to_svn(self.scope, path), self.authz,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
437 self.fs_ptr, subpool, 0, rev, limit):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
438 older = (_path_within_scope(self.scope, p), r,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
439 Changeset.ADD)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
440 rev = self._previous_rev(r, pool=subpool)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
441 if newer:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
442 if older[0] == path:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
443 # still on the path: 'newer' was an edit
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
444 yield newer[0], newer[1], Changeset.EDIT
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
445 else:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
446 # the path changed: 'newer' was a copy
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
447 rev = self._previous_rev(newer[1], pool=subpool)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
448 # restart before the copy op
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
449 yield newer[0], newer[1], Changeset.COPY
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
450 older = (older[0], older[1], 'unknown')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
451 break
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
452 newer = older
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
453 if older:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
454 # either a real ADD or the source of a COPY
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
455 yield older
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
456 else:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
457 expect_deletion = True
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
458 rev = self._previous_rev(rev, pool=subpool)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
459
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
460 def get_changes(self, old_path, old_rev, new_path, new_rev,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
461 ignore_ancestry=0):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
462 old_node = new_node = None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
463 old_rev = self.normalize_rev(old_rev)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
464 new_rev = self.normalize_rev(new_rev)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
465 if self.has_node(old_path, old_rev):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
466 old_node = self.get_node(old_path, old_rev)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
467 else:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
468 raise NoSuchNode(old_path, old_rev, 'The Base for Diff is invalid')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
469 if self.has_node(new_path, new_rev):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
470 new_node = self.get_node(new_path, new_rev)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
471 else:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
472 raise NoSuchNode(new_path, new_rev, 'The Target for Diff is invalid')
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
473 if new_node.kind != old_node.kind:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
474 raise TracError('Diff mismatch: Base is a %s (%s in revision %s) '
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
475 'and Target is a %s (%s in revision %s).' \
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
476 % (old_node.kind, old_path, old_rev,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
477 new_node.kind, new_path, new_rev))
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
478 subpool = Pool(self.pool)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
479 if new_node.isdir:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
480 editor = DiffChangeEditor()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
481 e_ptr, e_baton = delta.make_editor(editor, subpool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
482 old_root = fs.revision_root(self.fs_ptr, old_rev, subpool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
483 new_root = fs.revision_root(self.fs_ptr, new_rev, subpool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
484 def authz_cb(root, path, pool): return 1
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
485 text_deltas = 0 # as this is anyway re-done in Diff.py...
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
486 entry_props = 0 # "... typically used only for working copy updates"
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
487 repos.svn_repos_dir_delta(old_root,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
488 _to_svn(self.scope, old_path), '',
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
489 new_root,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
490 _to_svn(self.scope + new_path),
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
491 e_ptr, e_baton, authz_cb,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
492 text_deltas,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
493 1, # directory
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
494 entry_props,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
495 ignore_ancestry,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
496 subpool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
497 for path, kind, change in editor.deltas:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
498 path = _from_svn(path)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
499 old_node = new_node = None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
500 if change != Changeset.ADD:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
501 old_node = self.get_node(posixpath.join(old_path, path),
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
502 old_rev)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
503 if change != Changeset.DELETE:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
504 new_node = self.get_node(posixpath.join(new_path, path),
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
505 new_rev)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
506 else:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
507 kind = _kindmap[fs.check_path(old_root,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
508 _to_svn(self.scope,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
509 old_node.path),
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
510 subpool())]
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
511 yield (old_node, new_node, kind, change)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
512 else:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
513 old_root = fs.revision_root(self.fs_ptr, old_rev, subpool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
514 new_root = fs.revision_root(self.fs_ptr, new_rev, subpool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
515 if fs.contents_changed(old_root, _to_svn(self.scope, old_path),
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
516 new_root, _to_svn(self.scope, new_path),
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
517 subpool()):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
518 yield (old_node, new_node, Node.FILE, Changeset.EDIT)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
519
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
520
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
521 class SubversionNode(Node):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
522
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
523 def __init__(self, path, rev, authz, scope, fs_ptr, pool=None):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
524 self.authz = authz
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
525 self.scope = scope
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
526 self._scoped_svn_path = _to_svn(scope, path)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
527 self.fs_ptr = fs_ptr
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
528 self.pool = Pool(pool)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
529 self._requested_rev = rev
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
530
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
531 self.root = fs.revision_root(fs_ptr, rev, self.pool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
532 node_type = fs.check_path(self.root, self._scoped_svn_path,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
533 self.pool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
534 if not node_type in _kindmap:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
535 raise NoSuchNode(path, rev)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
536 cr = fs.node_created_rev(self.root, self._scoped_svn_path, self.pool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
537 cp = fs.node_created_path(self.root, self._scoped_svn_path, self.pool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
538 # Note: `cp` differs from `path` if the last change was a copy,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
539 # In that case, `path` doesn't even exist at `cr`.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
540 # The only guarantees are:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
541 # * this node exists at (path,rev)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
542 # * the node existed at (created_path,created_rev)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
543 # Also, `cp` might well be out of the scope of the repository,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
544 # in this case, we _don't_ use the ''create'' information.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
545 if _is_path_within_scope(self.scope, cp):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
546 self.created_rev = cr
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
547 self.created_path = _path_within_scope(self.scope, _from_svn(cp))
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
548 else:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
549 self.created_rev, self.created_path = rev, path
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
550 self.rev = self.created_rev
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
551 # TODO: check node id
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
552 Node.__init__(self, path, self.rev, _kindmap[node_type])
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
553
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
554 def get_content(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
555 if self.isdir:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
556 return None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
557 s = core.Stream(fs.file_contents(self.root, self._scoped_svn_path,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
558 self.pool()))
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
559 # Make sure the stream object references the pool to make sure the pool
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
560 # is not destroyed before the stream object.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
561 s._pool = self.pool
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
562 return s
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
563
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
564 def get_entries(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
565 if self.isfile:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
566 return
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
567 pool = Pool(self.pool)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
568 entries = fs.dir_entries(self.root, self._scoped_svn_path, pool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
569 for item in entries.keys():
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
570 path = posixpath.join(self.path, _from_svn(item))
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
571 if not self.authz.has_permission(path):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
572 continue
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
573 yield SubversionNode(path, self._requested_rev, self.authz,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
574 self.scope, self.fs_ptr, self.pool)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
575
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
576 def get_history(self,limit=None):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
577 newer = None # 'newer' is the previously seen history tuple
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
578 older = None # 'older' is the currently examined history tuple
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
579 pool = Pool(self.pool)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
580 for path, rev in _get_history(self._scoped_svn_path, self.authz,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
581 self.fs_ptr, pool,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
582 0, self._requested_rev, limit):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
583 path = _path_within_scope(self.scope, path)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
584 if rev > 0 and path:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
585 older = (path, rev, Changeset.ADD)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
586 if newer:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
587 change = newer[0] == older[0] and Changeset.EDIT or \
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
588 Changeset.COPY
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
589 newer = (newer[0], newer[1], change)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
590 yield newer
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
591 newer = older
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
592 if newer:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
593 yield newer
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
594
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
595 # def get_previous(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
596 # # FIXME: redo it with fs.node_history
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
597
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
598 def get_properties(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
599 props = fs.node_proplist(self.root, self._scoped_svn_path, self.pool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
600 for name, value in props.items():
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
601 # Note that property values can be arbitrary binary values
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
602 # so we can't assume they are UTF-8 strings...
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
603 props[_from_svn(name)] = to_unicode(value)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
604 return props
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
605
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
606 def get_content_length(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
607 if self.isdir:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
608 return None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
609 return fs.file_length(self.root, self._scoped_svn_path, self.pool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
610
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
611 def get_content_type(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
612 if self.isdir:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
613 return None
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
614 return self._get_prop(core.SVN_PROP_MIME_TYPE)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
615
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
616 def get_last_modified(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
617 date = fs.revision_prop(self.fs_ptr, self.created_rev,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
618 core.SVN_PROP_REVISION_DATE, self.pool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
619 return core.svn_time_from_cstring(date, self.pool()) / 1000000
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
620
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
621 def _get_prop(self, name):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
622 return fs.node_prop(self.root, self._scoped_svn_path, name, self.pool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
623
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
624
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
625 class SubversionChangeset(Changeset):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
626
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
627 def __init__(self, rev, authz, scope, fs_ptr, pool=None):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
628 self.rev = rev
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
629 self.authz = authz
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
630 self.scope = scope
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
631 self.fs_ptr = fs_ptr
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
632 self.pool = Pool(pool)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
633 message = self._get_prop(core.SVN_PROP_REVISION_LOG)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
634 author = self._get_prop(core.SVN_PROP_REVISION_AUTHOR)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
635 date = self._get_prop(core.SVN_PROP_REVISION_DATE)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
636 date = core.svn_time_from_cstring(date, self.pool()) / 1000000
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
637 Changeset.__init__(self, rev, message, author, date)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
638
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
639 def get_changes(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
640 pool = Pool(self.pool)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
641 tmp = Pool(pool)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
642 root = fs.revision_root(self.fs_ptr, self.rev, pool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
643 editor = repos.RevisionChangeCollector(self.fs_ptr, self.rev, pool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
644 e_ptr, e_baton = delta.make_editor(editor, pool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
645 repos.svn_repos_replay(root, e_ptr, e_baton, pool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
646
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
647 idx = 0
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
648 copies, deletions = {}, {}
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
649 changes = []
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
650 revroots = {}
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
651 for path, change in editor.changes.items():
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
652 #assert path == change.path or change.base_path
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
653
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
654 # Filtering on `path`
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
655 if not (_is_path_within_scope(self.scope, path) and \
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
656 self.authz.has_permission(path)):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
657 continue
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
658
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
659 path = change.path
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
660 base_path = change.base_path
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
661 base_rev = change.base_rev
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
662
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
663 # Ensure `base_path` is within the scope
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
664 if not (_is_path_within_scope(self.scope, base_path) and \
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
665 self.authz.has_permission(base_path)):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
666 base_path, base_rev = None, -1
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
667
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
668 # Determine the action
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
669 if not path: # deletion
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
670 if base_path:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
671 action = Changeset.DELETE
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
672 deletions[base_path] = idx
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
673 elif self.scope: # root property change
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
674 action = Changeset.EDIT
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
675 else: # deletion outside of scope, ignore
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
676 continue
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
677 elif change.added or not base_path: # add or copy
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
678 action = Changeset.ADD
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
679 if base_path and base_rev:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
680 action = Changeset.COPY
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
681 copies[base_path] = idx
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
682 else:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
683 action = Changeset.EDIT
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
684 # identify the most interesting base_path/base_rev
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
685 # in terms of last changed information (see r2562)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
686 if revroots.has_key(base_rev):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
687 b_root = revroots[base_rev]
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
688 else:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
689 b_root = fs.revision_root(self.fs_ptr, base_rev, pool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
690 revroots[base_rev] = b_root
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
691 tmp.clear()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
692 cbase_path = fs.node_created_path(b_root, base_path, tmp())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
693 cbase_rev = fs.node_created_rev(b_root, base_path, tmp())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
694 # give up if the created path is outside the scope
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
695 if _is_path_within_scope(self.scope, cbase_path):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
696 base_path, base_rev = cbase_path, cbase_rev
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
697
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
698 kind = _kindmap[change.item_kind]
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
699 path = _path_within_scope(self.scope, _from_svn(path or base_path))
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
700 base_path = _path_within_scope(self.scope, _from_svn(base_path))
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
701 changes.append([path, kind, action, base_path, base_rev])
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
702 idx += 1
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
703
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
704 moves = []
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
705 for k,v in copies.items():
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
706 if k in deletions:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
707 changes[v][2] = Changeset.MOVE
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
708 moves.append(deletions[k])
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
709 offset = 0
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
710 moves.sort()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
711 for i in moves:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
712 del changes[i - offset]
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
713 offset += 1
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
714
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
715 changes.sort()
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
716 for change in changes:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
717 yield tuple(change)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
718
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
719 def _get_prop(self, name):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
720 return fs.revision_prop(self.fs_ptr, self.rev, name, self.pool())
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
721
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
722
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
723 #
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
724 # Delta editor for diffs between arbitrary nodes
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
725 #
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
726 # Note 1: the 'copyfrom_path' and 'copyfrom_rev' information is not used
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
727 # because 'repos.svn_repos_dir_delta' *doesn't* provide it.
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
728 #
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
729 # Note 2: the 'dir_baton' is the path of the parent directory
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
730 #
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
731
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
732 class DiffChangeEditor(delta.Editor):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
733
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
734 def __init__(self):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
735 self.deltas = []
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
736
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
737 # -- svn.delta.Editor callbacks
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
738
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
739 def open_root(self, base_revision, dir_pool):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
740 return ('/', Changeset.EDIT)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
741
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
742 def add_directory(self, path, dir_baton, copyfrom_path, copyfrom_rev,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
743 dir_pool):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
744 self.deltas.append((path, Node.DIRECTORY, Changeset.ADD))
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
745 return (path, Changeset.ADD)
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
746
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
747 def open_directory(self, path, dir_baton, base_revision, dir_pool):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
748 return (path, dir_baton[1])
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
749
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
750 def change_dir_prop(self, dir_baton, name, value, pool):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
751 path, change = dir_baton
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
752 if change != Changeset.ADD:
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
753 self.deltas.append((path, Node.DIRECTORY, change))
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
754
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
755 def delete_entry(self, path, revision, dir_baton, pool):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
756 self.deltas.append((path, None, Changeset.DELETE))
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
757
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
758 def add_file(self, path, dir_baton, copyfrom_path, copyfrom_revision,
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
759 dir_pool):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
760 self.deltas.append((path, Node.FILE, Changeset.ADD))
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
761
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
762 def open_file(self, path, dir_baton, dummy_rev, file_pool):
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
763 self.deltas.append((path, Node.FILE, Changeset.EDIT))
93b4dcbafd7b Copy Trac to main branch.
cmlenz
parents:
diff changeset
764
Copyright (C) 2012-2017 Edgewall Software