##// END OF EJS Templates
svn: don't raise duplicate exception. The function already does that.
marcink -
r1926:f9d07533 default
parent child Browse files
Show More
@@ -1,236 +1,236 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2014-2017 RhodeCode GmbH
3 # Copyright (C) 2014-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 SVN commit module
22 SVN commit module
23 """
23 """
24
24
25
25
26 import dateutil.parser
26 import dateutil.parser
27 from zope.cachedescriptors.property import Lazy as LazyProperty
27 from zope.cachedescriptors.property import Lazy as LazyProperty
28
28
29 from rhodecode.lib.utils import safe_str, safe_unicode
29 from rhodecode.lib.utils import safe_str, safe_unicode
30 from rhodecode.lib.vcs import nodes, path as vcspath
30 from rhodecode.lib.vcs import nodes, path as vcspath
31 from rhodecode.lib.vcs.backends import base
31 from rhodecode.lib.vcs.backends import base
32 from rhodecode.lib.vcs.exceptions import CommitError, NodeDoesNotExistError
32 from rhodecode.lib.vcs.exceptions import CommitError, NodeDoesNotExistError
33
33
34
34
35 _SVN_PROP_TRUE = '*'
35 _SVN_PROP_TRUE = '*'
36
36
37
37
38 class SubversionCommit(base.BaseCommit):
38 class SubversionCommit(base.BaseCommit):
39 """
39 """
40 Subversion specific implementation of commits
40 Subversion specific implementation of commits
41
41
42 .. attribute:: branch
42 .. attribute:: branch
43
43
44 The Subversion backend does not support to assign branches to
44 The Subversion backend does not support to assign branches to
45 specific commits. This attribute has always the value `None`.
45 specific commits. This attribute has always the value `None`.
46
46
47 """
47 """
48
48
49 def __init__(self, repository, commit_id):
49 def __init__(self, repository, commit_id):
50 self.repository = repository
50 self.repository = repository
51 self.idx = self.repository._get_commit_idx(commit_id)
51 self.idx = self.repository._get_commit_idx(commit_id)
52 self._svn_rev = self.idx + 1
52 self._svn_rev = self.idx + 1
53 self._remote = repository._remote
53 self._remote = repository._remote
54 # TODO: handling of raw_id should be a method on repository itself,
54 # TODO: handling of raw_id should be a method on repository itself,
55 # which knows how to translate commit index and commit id
55 # which knows how to translate commit index and commit id
56 self.raw_id = commit_id
56 self.raw_id = commit_id
57 self.short_id = commit_id
57 self.short_id = commit_id
58 self.id = 'r%s' % (commit_id, )
58 self.id = 'r%s' % (commit_id, )
59
59
60 # TODO: Implement the following placeholder attributes
60 # TODO: Implement the following placeholder attributes
61 self.nodes = {}
61 self.nodes = {}
62 self.tags = []
62 self.tags = []
63
63
64 @property
64 @property
65 def author(self):
65 def author(self):
66 return safe_unicode(self._properties.get('svn:author'))
66 return safe_unicode(self._properties.get('svn:author'))
67
67
68 @property
68 @property
69 def date(self):
69 def date(self):
70 return _date_from_svn_properties(self._properties)
70 return _date_from_svn_properties(self._properties)
71
71
72 @property
72 @property
73 def message(self):
73 def message(self):
74 return safe_unicode(self._properties.get('svn:log'))
74 return safe_unicode(self._properties.get('svn:log'))
75
75
76 @LazyProperty
76 @LazyProperty
77 def _properties(self):
77 def _properties(self):
78 return self._remote.revision_properties(self._svn_rev)
78 return self._remote.revision_properties(self._svn_rev)
79
79
80 @LazyProperty
80 @LazyProperty
81 def parents(self):
81 def parents(self):
82 parent_idx = self.idx - 1
82 parent_idx = self.idx - 1
83 if parent_idx >= 0:
83 if parent_idx >= 0:
84 parent = self.repository.get_commit(commit_idx=parent_idx)
84 parent = self.repository.get_commit(commit_idx=parent_idx)
85 return [parent]
85 return [parent]
86 return []
86 return []
87
87
88 @LazyProperty
88 @LazyProperty
89 def children(self):
89 def children(self):
90 child_idx = self.idx + 1
90 child_idx = self.idx + 1
91 if child_idx < len(self.repository.commit_ids):
91 if child_idx < len(self.repository.commit_ids):
92 child = self.repository.get_commit(commit_idx=child_idx)
92 child = self.repository.get_commit(commit_idx=child_idx)
93 return [child]
93 return [child]
94 return []
94 return []
95
95
96 def get_file_mode(self, path):
96 def get_file_mode(self, path):
97 # Note: Subversion flags files which are executable with a special
97 # Note: Subversion flags files which are executable with a special
98 # property `svn:executable` which is set to the value ``"*"``.
98 # property `svn:executable` which is set to the value ``"*"``.
99 if self._get_file_property(path, 'svn:executable') == _SVN_PROP_TRUE:
99 if self._get_file_property(path, 'svn:executable') == _SVN_PROP_TRUE:
100 return base.FILEMODE_EXECUTABLE
100 return base.FILEMODE_EXECUTABLE
101 else:
101 else:
102 return base.FILEMODE_DEFAULT
102 return base.FILEMODE_DEFAULT
103
103
104 def is_link(self, path):
104 def is_link(self, path):
105 # Note: Subversion has a flag for special files, the content of the
105 # Note: Subversion has a flag for special files, the content of the
106 # file contains the type of that file.
106 # file contains the type of that file.
107 if self._get_file_property(path, 'svn:special') == _SVN_PROP_TRUE:
107 if self._get_file_property(path, 'svn:special') == _SVN_PROP_TRUE:
108 return self.get_file_content(path).startswith('link')
108 return self.get_file_content(path).startswith('link')
109 return False
109 return False
110
110
111 def _get_file_property(self, path, name):
111 def _get_file_property(self, path, name):
112 file_properties = self._remote.node_properties(
112 file_properties = self._remote.node_properties(
113 safe_str(path), self._svn_rev)
113 safe_str(path), self._svn_rev)
114 return file_properties.get(name)
114 return file_properties.get(name)
115
115
116 def get_file_content(self, path):
116 def get_file_content(self, path):
117 path = self._fix_path(path)
117 path = self._fix_path(path)
118 return self._remote.get_file_content(safe_str(path), self._svn_rev)
118 return self._remote.get_file_content(safe_str(path), self._svn_rev)
119
119
120 def get_file_size(self, path):
120 def get_file_size(self, path):
121 path = self._fix_path(path)
121 path = self._fix_path(path)
122 return self._remote.get_file_size(safe_str(path), self._svn_rev)
122 return self._remote.get_file_size(safe_str(path), self._svn_rev)
123
123
124 def get_file_history(self, path, limit=None, pre_load=None):
124 def get_file_history(self, path, limit=None, pre_load=None):
125 path = safe_str(self._fix_path(path))
125 path = safe_str(self._fix_path(path))
126 history = self._remote.node_history(path, self._svn_rev, limit)
126 history = self._remote.node_history(path, self._svn_rev, limit)
127 return [
127 return [
128 self.repository.get_commit(commit_id=str(svn_rev))
128 self.repository.get_commit(commit_id=str(svn_rev))
129 for svn_rev in history]
129 for svn_rev in history]
130
130
131 def get_file_annotate(self, path, pre_load=None):
131 def get_file_annotate(self, path, pre_load=None):
132 result = self._remote.file_annotate(safe_str(path), self._svn_rev)
132 result = self._remote.file_annotate(safe_str(path), self._svn_rev)
133
133
134 for zero_based_line_no, svn_rev, content in result:
134 for zero_based_line_no, svn_rev, content in result:
135 commit_id = str(svn_rev)
135 commit_id = str(svn_rev)
136 line_no = zero_based_line_no + 1
136 line_no = zero_based_line_no + 1
137 yield (
137 yield (
138 line_no,
138 line_no,
139 commit_id,
139 commit_id,
140 lambda: self.repository.get_commit(commit_id=commit_id),
140 lambda: self.repository.get_commit(commit_id=commit_id),
141 content)
141 content)
142
142
143 def get_node(self, path, pre_load=None):
143 def get_node(self, path, pre_load=None):
144 path = self._fix_path(path)
144 path = self._fix_path(path)
145 if path not in self.nodes:
145 if path not in self.nodes:
146
146
147 if path == '':
147 if path == '':
148 node = nodes.RootNode(commit=self)
148 node = nodes.RootNode(commit=self)
149 else:
149 else:
150 node_type = self._remote.get_node_type(
150 node_type = self._remote.get_node_type(
151 safe_str(path), self._svn_rev)
151 safe_str(path), self._svn_rev)
152 if node_type == 'dir':
152 if node_type == 'dir':
153 node = nodes.DirNode(path, commit=self)
153 node = nodes.DirNode(path, commit=self)
154 elif node_type == 'file':
154 elif node_type == 'file':
155 node = nodes.FileNode(path, commit=self, pre_load=pre_load)
155 node = nodes.FileNode(path, commit=self, pre_load=pre_load)
156 else:
156 else:
157 raise NodeDoesNotExistError(self.no_node_at_path(path))
157 raise self.no_node_at_path(path)
158
158
159 self.nodes[path] = node
159 self.nodes[path] = node
160 return self.nodes[path]
160 return self.nodes[path]
161
161
162 def get_nodes(self, path):
162 def get_nodes(self, path):
163 if self._get_kind(path) != nodes.NodeKind.DIR:
163 if self._get_kind(path) != nodes.NodeKind.DIR:
164 raise CommitError(
164 raise CommitError(
165 "Directory does not exist for commit %s at "
165 "Directory does not exist for commit %s at "
166 " '%s'" % (self.raw_id, path))
166 " '%s'" % (self.raw_id, path))
167 path = self._fix_path(path)
167 path = self._fix_path(path)
168
168
169 path_nodes = []
169 path_nodes = []
170 for name, kind in self._remote.get_nodes(
170 for name, kind in self._remote.get_nodes(
171 safe_str(path), revision=self._svn_rev):
171 safe_str(path), revision=self._svn_rev):
172 node_path = vcspath.join(path, name)
172 node_path = vcspath.join(path, name)
173 if kind == 'dir':
173 if kind == 'dir':
174 node = nodes.DirNode(node_path, commit=self)
174 node = nodes.DirNode(node_path, commit=self)
175 elif kind == 'file':
175 elif kind == 'file':
176 node = nodes.FileNode(node_path, commit=self)
176 node = nodes.FileNode(node_path, commit=self)
177 else:
177 else:
178 raise ValueError("Node kind %s not supported." % (kind, ))
178 raise ValueError("Node kind %s not supported." % (kind, ))
179 self.nodes[node_path] = node
179 self.nodes[node_path] = node
180 path_nodes.append(node)
180 path_nodes.append(node)
181
181
182 return path_nodes
182 return path_nodes
183
183
184 def _get_kind(self, path):
184 def _get_kind(self, path):
185 path = self._fix_path(path)
185 path = self._fix_path(path)
186 kind = self._remote.get_node_type(path, self._svn_rev)
186 kind = self._remote.get_node_type(path, self._svn_rev)
187 if kind == 'file':
187 if kind == 'file':
188 return nodes.NodeKind.FILE
188 return nodes.NodeKind.FILE
189 elif kind == 'dir':
189 elif kind == 'dir':
190 return nodes.NodeKind.DIR
190 return nodes.NodeKind.DIR
191 else:
191 else:
192 raise CommitError(
192 raise CommitError(
193 "Node does not exist at the given path '%s'" % (path, ))
193 "Node does not exist at the given path '%s'" % (path, ))
194
194
195 @LazyProperty
195 @LazyProperty
196 def _changes_cache(self):
196 def _changes_cache(self):
197 return self._remote.revision_changes(self._svn_rev)
197 return self._remote.revision_changes(self._svn_rev)
198
198
199 @LazyProperty
199 @LazyProperty
200 def affected_files(self):
200 def affected_files(self):
201 changed_files = set()
201 changed_files = set()
202 for files in self._changes_cache.itervalues():
202 for files in self._changes_cache.itervalues():
203 changed_files.update(files)
203 changed_files.update(files)
204 return list(changed_files)
204 return list(changed_files)
205
205
206 @LazyProperty
206 @LazyProperty
207 def id(self):
207 def id(self):
208 return self.raw_id
208 return self.raw_id
209
209
210 @property
210 @property
211 def added(self):
211 def added(self):
212 return nodes.AddedFileNodesGenerator(
212 return nodes.AddedFileNodesGenerator(
213 self._changes_cache['added'], self)
213 self._changes_cache['added'], self)
214
214
215 @property
215 @property
216 def changed(self):
216 def changed(self):
217 return nodes.ChangedFileNodesGenerator(
217 return nodes.ChangedFileNodesGenerator(
218 self._changes_cache['changed'], self)
218 self._changes_cache['changed'], self)
219
219
220 @property
220 @property
221 def removed(self):
221 def removed(self):
222 return nodes.RemovedFileNodesGenerator(
222 return nodes.RemovedFileNodesGenerator(
223 self._changes_cache['removed'], self)
223 self._changes_cache['removed'], self)
224
224
225
225
226 def _date_from_svn_properties(properties):
226 def _date_from_svn_properties(properties):
227 """
227 """
228 Parses the date out of given svn properties.
228 Parses the date out of given svn properties.
229
229
230 :return: :class:`datetime.datetime` instance. The object is naive.
230 :return: :class:`datetime.datetime` instance. The object is naive.
231 """
231 """
232
232
233 aware_date = dateutil.parser.parse(properties.get('svn:date'))
233 aware_date = dateutil.parser.parse(properties.get('svn:date'))
234 # final_date = aware_date.astimezone(dateutil.tz.tzlocal())
234 # final_date = aware_date.astimezone(dateutil.tz.tzlocal())
235 final_date = aware_date
235 final_date = aware_date
236 return final_date.replace(tzinfo=None)
236 return final_date.replace(tzinfo=None)
General Comments 0
You need to be logged in to leave comments. Login now