2 # Copyright (C) 2005 Edgewall Software
3 # Copyright (C) 2005 Christopher Lenz <cmlenz@gmx.de>
5 # This software is licensed as described in the file
6 # LICENSE_FOR_PYTHON_BINDINGS, which you should have received as part
7 # of this distribution. The terms are also available at
8 # < http://subversion.tigris.org/license-for-python-bindings.html >.
9 # If newer versions of this license are posted there, you may use a
10 # newer version instead, at your option.
12 # Author: Christopher Lenz <cmlenz@gmx.de>
14 from __future__
import generators
16 class Repository(object):
18 Base class for a repository provided by a version control system.
21 def __init__(self
, authz
):
22 self
.authz
= authz
or Authorizer()
26 Close the connection to the repository.
28 raise NotImplementedError
30 def get_changeset(self
, rev
):
32 Retrieve a Changeset object that describes the changes made in
35 raise NotImplementedError
37 def has_node(self
, path
, rev
):
39 Tell if there's a node at the specified (path,rev) combination.
41 raise NotImplementedError
43 def get_node(self
, path
, rev
=None):
45 Retrieve a Node (directory or file) from the repository at the
46 given path. If the rev parameter is specified, the version of the
47 node at that revision is returned, otherwise the latest version
48 of the node is returned.
50 raise NotImplementedError
52 def get_oldest_rev(self
):
54 Return the oldest revision stored in the repository.
56 raise NotImplementedError
57 oldest_rev
= property(lambda x
: x
.get_oldest_rev())
59 def get_youngest_rev(self
):
61 Return the youngest revision in the repository.
63 raise NotImplementedError
64 youngest_rev
= property(lambda x
: x
.get_youngest_rev())
66 def previous_rev(self
, rev
):
68 Return the revision immediately preceding the specified revision.
70 raise NotImplementedError
72 def next_rev(self
, rev
):
74 Return the revision immediately following the specified revision.
76 raise NotImplementedError
78 def rev_older_than(self
, rev1
, rev2
):
80 Return True if rev1 is older than rev2, i.e. if rev1 comes before rev2
81 in the revision sequence.
83 raise NotImplementedError
85 def get_path_history(self
, path
, rev
=None, limit
=None):
87 Retrieve all the revisions containing this path (no newer than 'rev').
88 The result format should be the same as the one of Node.get_history()
90 raise NotImplementedError
92 def normalize_path(self
, path
):
94 Return a canonical representation of path in the repos.
96 return NotImplementedError
98 def normalize_rev(self
, rev
):
100 Return a canonical representation of a revision in the repos.
101 'None' is a valid revision value and represents the youngest revision.
103 return NotImplementedError
105 def get_deltas(self
, old_path
, old_rev
, new_path
, new_rev
, ignore_ancestry
=1):
107 Generator that yields change tuples (old_node, new_node, kind, change)
108 for each node change between the two arbitrary (path,rev) pairs.
110 The old_node is assumed to be None when the change is an ADD,
111 the new_node is assumed to be None when the change is a DELETE.
113 raise NotImplementedError
118 Represents a directory or file in the repository.
124 def __init__(self
, path
, rev
, kind
):
125 assert kind
in (Node
.DIRECTORY
, Node
.FILE
), "Unknown node kind %s" % kind
126 self
.path
= str(path
)
130 def get_content(self
):
132 Return a stream for reading the content of the node. This method
133 will return None for directories. The returned object should provide
134 a read([len]) function.
136 raise NotImplementedError
138 def get_entries(self
):
140 Generator that yields the immediate child entries of a directory, in no
141 particular order. If the node is a file, this method returns None.
143 raise NotImplementedError
145 def get_history(self
, limit
=None):
147 Generator that yields (path, rev, chg) tuples, one for each revision in which
148 the node was changed. This generator will follow copies and moves of a
149 node (if the underlying version control system supports that), which
150 will be indicated by the first element of the tuple (i.e. the path)
152 Starts with an entry for the current revision.
154 raise NotImplementedError
156 def get_previous(self
):
158 Return the (path, rev, chg) tuple corresponding to the previous
159 revision for that node.
162 for p
in self
.get_history(2):
168 def get_properties(self
):
170 Returns a dictionary containing the properties (meta-data) of the node.
171 The set of properties depends on the version control system.
173 raise NotImplementedError
175 def get_content_length(self
):
176 raise NotImplementedError
177 content_length
= property(lambda x
: x
.get_content_length())
179 def get_content_type(self
):
180 raise NotImplementedError
181 content_type
= property(lambda x
: x
.get_content_type())
184 return self
.path
.split('/')[-1]
185 name
= property(lambda x
: x
.get_name())
187 def get_last_modified(self
):
188 raise NotImplementedError
189 last_modified
= property(lambda x
: x
.get_last_modified())
191 isdir
= property(lambda x
: x
.kind
== Node
.DIRECTORY
)
192 isfile
= property(lambda x
: x
.kind
== Node
.FILE
)
195 class Changeset(object):
197 Represents a set of changes of a repository.
206 def __init__(self
, rev
, message
, author
, date
):
208 self
.message
= message
212 def get_changes(self
):
214 Generator that produces a (path, kind, change, base_rev, base_path)
215 tuple for every change in the changeset, where change can be one of
216 Changeset.ADD, Changeset.COPY, Changeset.DELETE, Changeset.EDIT or
217 Changeset.MOVE, and kind is one of Node.FILE or Node.DIRECTORY.
219 raise NotImplementedError
222 class PermissionDenied(Exception):
224 Exception raised by an authorizer if the user has insufficient permissions
225 to view a specific part of the repository.
230 class Authorizer(object):
232 Base class for authorizers that are responsible to granting or denying
233 access to view certain parts of a repository.
236 def assert_permission(self
, path
):
237 if not self
.has_permission(path
):
238 raise PermissionDenied
, \
239 'Insufficient permissions to access %s' % path
241 def has_permission(self
, path
):
244 def has_permission_for_changeset(self
, rev
):