Show More
@@ -25,6 +25,7 b' news' | |||||
25 | - #374 LDAP config is discarded when LDAP can't be activated |
|
25 | - #374 LDAP config is discarded when LDAP can't be activated | |
26 | - limited push/pull operations are now logged for git in the journal |
|
26 | - limited push/pull operations are now logged for git in the journal | |
27 | - bumped mercurial to 2.2.X series |
|
27 | - bumped mercurial to 2.2.X series | |
|
28 | - added support for displaying submodules in file-browser | |||
28 |
|
29 | |||
29 | fixes |
|
30 | fixes | |
30 | +++++ |
|
31 | +++++ | |
@@ -34,6 +35,8 b' fixes' | |||||
34 | - #418 cast to unicode fixes in notification objects |
|
35 | - #418 cast to unicode fixes in notification objects | |
35 | - #426 fixed mention extracting regex |
|
36 | - #426 fixed mention extracting regex | |
36 | - fixed remote-pulling for git remotes remopositories |
|
37 | - fixed remote-pulling for git remotes remopositories | |
|
38 | - fixed #434: Error when accessing files or changesets of a git repository | |||
|
39 | with submodules | |||
37 |
|
40 | |||
38 | 1.3.4 (**2012-03-28**) |
|
41 | 1.3.4 (**2012-03-28**) | |
39 | ---------------------- |
|
42 | ---------------------- |
@@ -27,8 +27,8 b" sys.path.insert(0, os.path.abspath('..')" | |||||
27 |
|
27 | |||
28 | # Add any Sphinx extension module names here, as strings. They can be extensions |
|
28 | # Add any Sphinx extension module names here, as strings. They can be extensions | |
29 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. |
|
29 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. | |
30 |
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', |
|
30 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', | |
31 |
'sphinx.ext.intersphinx', 'sphinx.ext.todo', |
|
31 | 'sphinx.ext.intersphinx', 'sphinx.ext.todo', | |
32 | 'sphinx.ext.viewcode'] |
|
32 | 'sphinx.ext.viewcode'] | |
33 |
|
33 | |||
34 | # Add any paths that contain templates here, relative to this directory. |
|
34 | # Add any paths that contain templates here, relative to this directory. |
@@ -5,7 +5,7 b' formencode==1.2.4' | |||||
5 | SQLAlchemy==0.7.6 |
|
5 | SQLAlchemy==0.7.6 | |
6 | Mako==0.7.0 |
|
6 | Mako==0.7.0 | |
7 | pygments>=1.4 |
|
7 | pygments>=1.4 | |
8 |
whoosh>=2. |
|
8 | whoosh>=2.4.0,<2.5 | |
9 | celery>=2.2.5,<2.3 |
|
9 | celery>=2.2.5,<2.3 | |
10 | babel |
|
10 | babel | |
11 | python-dateutil>=1.5.0,<2.0.0 |
|
11 | python-dateutil>=1.5.0,<2.0.0 | |
@@ -14,4 +14,4 b' webob==1.0.8' | |||||
14 | markdown==2.1.1 |
|
14 | markdown==2.1.1 | |
15 | docutils==0.8.1 |
|
15 | docutils==0.8.1 | |
16 | py-bcrypt |
|
16 | py-bcrypt | |
17 | mercurial>=2.2,<2.3 No newline at end of file |
|
17 | mercurial>=2.2.1,<2.3 No newline at end of file |
@@ -54,7 +54,7 b' requirements = [' | |||||
54 | "SQLAlchemy==0.7.6", |
|
54 | "SQLAlchemy==0.7.6", | |
55 | "Mako==0.7.0", |
|
55 | "Mako==0.7.0", | |
56 | "pygments>=1.4", |
|
56 | "pygments>=1.4", | |
57 |
"whoosh>=2. |
|
57 | "whoosh>=2.4.0,<2.5", | |
58 | "celery>=2.2.5,<2.3", |
|
58 | "celery>=2.2.5,<2.3", | |
59 | "babel", |
|
59 | "babel", | |
60 | "python-dateutil>=1.5.0,<2.0.0", |
|
60 | "python-dateutil>=1.5.0,<2.0.0", | |
@@ -69,10 +69,10 b' if __py_version__ < (2, 6):' | |||||
69 | requirements.append("pysqlite") |
|
69 | requirements.append("pysqlite") | |
70 |
|
70 | |||
71 | if __platform__ in PLATFORM_WIN: |
|
71 | if __platform__ in PLATFORM_WIN: | |
72 | requirements.append("mercurial>=2.2,<2.3") |
|
72 | requirements.append("mercurial>=2.2.1,<2.3") | |
73 | else: |
|
73 | else: | |
74 | requirements.append("py-bcrypt") |
|
74 | requirements.append("py-bcrypt") | |
75 | requirements.append("mercurial>=2.2,<2.3") |
|
75 | requirements.append("mercurial>=2.2.1,<2.3") | |
76 |
|
76 | |||
77 |
|
77 | |||
78 | def get_version(): |
|
78 | def get_version(): |
@@ -126,12 +126,7 b' class ChangelogController(BaseRepoContro' | |||||
126 |
|
126 | |||
127 | elif repo.alias == 'hg': |
|
127 | elif repo.alias == 'hg': | |
128 | dag = graphmod.dagwalker(repo._repo, revs) |
|
128 | dag = graphmod.dagwalker(repo._repo, revs) | |
129 | try: |
|
129 | c.dag = graphmod.colored(dag, repo._repo) | |
130 | c.dag = graphmod.colored(dag) |
|
|||
131 | except: |
|
|||
132 | #HG 2.2+ |
|
|||
133 | c.dag = graphmod.colored(dag, repo._repo) |
|
|||
134 |
|
||||
135 | for (id, type, ctx, vtx, edges) in c.dag: |
|
130 | for (id, type, ctx, vtx, edges) in c.dag: | |
136 | if type != graphmod.CHANGESET: |
|
131 | if type != graphmod.CHANGESET: | |
137 | continue |
|
132 | continue |
@@ -33,8 +33,8 b' from itertools import tee, imap' | |||||
33 | from pylons.i18n.translation import _ |
|
33 | from pylons.i18n.translation import _ | |
34 |
|
34 | |||
35 | from rhodecode.lib.vcs.exceptions import VCSError |
|
35 | from rhodecode.lib.vcs.exceptions import VCSError | |
36 | from rhodecode.lib.vcs.nodes import FileNode |
|
36 | from rhodecode.lib.vcs.nodes import FileNode, SubModuleNode | |
37 |
|
37 | from rhodecode.lib.helpers import escape | ||
38 | from rhodecode.lib.utils import EmptyChangeset |
|
38 | from rhodecode.lib.utils import EmptyChangeset | |
39 |
|
39 | |||
40 |
|
40 | |||
@@ -79,9 +79,13 b' def wrapped_diff(filenode_old, filenode_' | |||||
79 | 'diff menu to display this diff')) |
|
79 | 'diff menu to display this diff')) | |
80 | stats = (0, 0) |
|
80 | stats = (0, 0) | |
81 | size = 0 |
|
81 | size = 0 | |
82 |
|
||||
83 | if not diff: |
|
82 | if not diff: | |
84 | diff = wrap_to_table(_('No changes detected')) |
|
83 | submodules = filter(lambda o: isinstance(o, SubModuleNode), | |
|
84 | [filenode_new, filenode_old]) | |||
|
85 | if submodules: | |||
|
86 | diff = wrap_to_table(escape('Submodule %r' % submodules[0])) | |||
|
87 | else: | |||
|
88 | diff = wrap_to_table(_('No changes detected')) | |||
85 |
|
89 | |||
86 | cs1 = filenode_old.changeset.raw_id |
|
90 | cs1 = filenode_old.changeset.raw_id | |
87 | cs2 = filenode_new.changeset.raw_id |
|
91 | cs2 = filenode_new.changeset.raw_id | |
@@ -97,6 +101,10 b' def get_gitdiff(filenode_old, filenode_n' | |||||
97 | """ |
|
101 | """ | |
98 | # make sure we pass in default context |
|
102 | # make sure we pass in default context | |
99 | context = context or 3 |
|
103 | context = context or 3 | |
|
104 | submodules = filter(lambda o: isinstance(o, SubModuleNode), | |||
|
105 | [filenode_new, filenode_old]) | |||
|
106 | if submodules: | |||
|
107 | return '' | |||
100 |
|
108 | |||
101 | for filenode in (filenode_old, filenode_new): |
|
109 | for filenode in (filenode_old, filenode_new): | |
102 | if not isinstance(filenode, FileNode): |
|
110 | if not isinstance(filenode, FileNode): | |
@@ -109,7 +117,6 b' def get_gitdiff(filenode_old, filenode_n' | |||||
109 |
|
117 | |||
110 | vcs_gitdiff = repo.get_diff(old_raw_id, new_raw_id, filenode_new.path, |
|
118 | vcs_gitdiff = repo.get_diff(old_raw_id, new_raw_id, filenode_new.path, | |
111 | ignore_whitespace, context) |
|
119 | ignore_whitespace, context) | |
112 |
|
||||
113 | return vcs_gitdiff |
|
120 | return vcs_gitdiff | |
114 |
|
121 | |||
115 |
|
122 |
@@ -111,7 +111,7 b' def log_push_action(ui, repo, **kwargs):' | |||||
111 | Maps user last push action to new changeset id, from mercurial |
|
111 | Maps user last push action to new changeset id, from mercurial | |
112 |
|
112 | |||
113 | :param ui: |
|
113 | :param ui: | |
114 | :param repo: |
|
114 | :param repo: repo object containing the `ui` object | |
115 | """ |
|
115 | """ | |
116 |
|
116 | |||
117 | extras = dict(repo.ui.configitems('rhodecode_extras')) |
|
117 | extras = dict(repo.ui.configitems('rhodecode_extras')) |
@@ -201,7 +201,7 b' class SimpleGit(BaseVCSController):' | |||||
201 | # invalidate cache on push |
|
201 | # invalidate cache on push | |
202 | if action == 'push': |
|
202 | if action == 'push': | |
203 | self._invalidate_cache(repo_name) |
|
203 | self._invalidate_cache(repo_name) | |
204 | self._handle_githooks(action, baseui, environ) |
|
204 | self._handle_githooks(repo_name, action, baseui, environ) | |
205 |
|
205 | |||
206 | log.info('%s action on GIT repo "%s"' % (action, repo_name)) |
|
206 | log.info('%s action on GIT repo "%s"' % (action, repo_name)) | |
207 | app = self.__make_app(repo_name, repo_path) |
|
207 | app = self.__make_app(repo_name, repo_path) | |
@@ -264,7 +264,7 b' class SimpleGit(BaseVCSController):' | |||||
264 | op = getattr(self, '_git_stored_op', 'pull') |
|
264 | op = getattr(self, '_git_stored_op', 'pull') | |
265 | return op |
|
265 | return op | |
266 |
|
266 | |||
267 | def _handle_githooks(self, action, baseui, environ): |
|
267 | def _handle_githooks(self, repo_name, action, baseui, environ): | |
268 | from rhodecode.lib.hooks import log_pull_action, log_push_action |
|
268 | from rhodecode.lib.hooks import log_pull_action, log_push_action | |
269 | service = environ['QUERY_STRING'].split('=') |
|
269 | service = environ['QUERY_STRING'].split('=') | |
270 | if len(service) < 2: |
|
270 | if len(service) < 2: | |
@@ -279,9 +279,9 b' class SimpleGit(BaseVCSController):' | |||||
279 | pull_hook = 'preoutgoing.pull_logger' |
|
279 | pull_hook = 'preoutgoing.pull_logger' | |
280 | _hooks = dict(baseui.configitems('hooks')) or {} |
|
280 | _hooks = dict(baseui.configitems('hooks')) or {} | |
281 | if action == 'push' and _hooks.get(push_hook): |
|
281 | if action == 'push' and _hooks.get(push_hook): | |
282 | log_push_action(ui=baseui, repo=repo._repo) |
|
282 | log_push_action(ui=baseui, repo=_repo._repo) | |
283 | elif action == 'pull' and _hooks.get(pull_hook): |
|
283 | elif action == 'pull' and _hooks.get(pull_hook): | |
284 | log_pull_action(ui=baseui, repo=repo._repo) |
|
284 | log_pull_action(ui=baseui, repo=_repo._repo) | |
285 |
|
285 | |||
286 | def __inject_extras(self, repo_path, baseui, extras={}): |
|
286 | def __inject_extras(self, repo_path, baseui, extras={}): | |
287 | """ |
|
287 | """ |
@@ -909,3 +909,48 b' class BaseInMemoryChangeset(object):' | |||||
909 | :raises ``CommitError``: if any error occurs while committing |
|
909 | :raises ``CommitError``: if any error occurs while committing | |
910 | """ |
|
910 | """ | |
911 | raise NotImplementedError |
|
911 | raise NotImplementedError | |
|
912 | ||||
|
913 | ||||
|
914 | class EmptyChangeset(BaseChangeset): | |||
|
915 | """ | |||
|
916 | An dummy empty changeset. It's possible to pass hash when creating | |||
|
917 | an EmptyChangeset | |||
|
918 | """ | |||
|
919 | ||||
|
920 | def __init__(self, cs='0' * 40, repo=None, requested_revision=None, | |||
|
921 | alias=None): | |||
|
922 | self._empty_cs = cs | |||
|
923 | self.revision = -1 | |||
|
924 | self.message = '' | |||
|
925 | self.author = '' | |||
|
926 | self.date = '' | |||
|
927 | self.repository = repo | |||
|
928 | self.requested_revision = requested_revision | |||
|
929 | self.alias = alias | |||
|
930 | ||||
|
931 | @LazyProperty | |||
|
932 | def raw_id(self): | |||
|
933 | """ | |||
|
934 | Returns raw string identifying this changeset, useful for web | |||
|
935 | representation. | |||
|
936 | """ | |||
|
937 | ||||
|
938 | return self._empty_cs | |||
|
939 | ||||
|
940 | @LazyProperty | |||
|
941 | def branch(self): | |||
|
942 | from rhodecode.lib.vcs.backends import get_backend | |||
|
943 | return get_backend(self.alias).DEFAULT_BRANCH_NAME | |||
|
944 | ||||
|
945 | @LazyProperty | |||
|
946 | def short_id(self): | |||
|
947 | return self.raw_id[:12] | |||
|
948 | ||||
|
949 | def get_file_changeset(self, path): | |||
|
950 | return self | |||
|
951 | ||||
|
952 | def get_file_content(self, path): | |||
|
953 | return u'' | |||
|
954 | ||||
|
955 | def get_file_size(self, path): | |||
|
956 | return 0 |
@@ -10,7 +10,8 b' from rhodecode.lib.vcs.exceptions import' | |||||
10 | from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError |
|
10 | from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError | |
11 | from rhodecode.lib.vcs.exceptions import ImproperArchiveTypeError |
|
11 | from rhodecode.lib.vcs.exceptions import ImproperArchiveTypeError | |
12 | from rhodecode.lib.vcs.backends.base import BaseChangeset |
|
12 | from rhodecode.lib.vcs.backends.base import BaseChangeset | |
13 |
from rhodecode.lib.vcs.nodes import FileNode, DirNode, NodeKind, RootNode, |
|
13 | from rhodecode.lib.vcs.nodes import FileNode, DirNode, NodeKind, RootNode, \ | |
|
14 | RemovedFileNode, SubModuleNode | |||
14 | from rhodecode.lib.vcs.utils import safe_unicode |
|
15 | from rhodecode.lib.vcs.utils import safe_unicode | |
15 | from rhodecode.lib.vcs.utils import date_fromtimestamp |
|
16 | from rhodecode.lib.vcs.utils import date_fromtimestamp | |
16 | from rhodecode.lib.vcs.utils.lazy import LazyProperty |
|
17 | from rhodecode.lib.vcs.utils.lazy import LazyProperty | |
@@ -329,7 +330,13 b' class GitChangeset(BaseChangeset):' | |||||
329 | tree = self.repository._repo[id] |
|
330 | tree = self.repository._repo[id] | |
330 | dirnodes = [] |
|
331 | dirnodes = [] | |
331 | filenodes = [] |
|
332 | filenodes = [] | |
|
333 | als = self.repository.alias | |||
332 | for name, stat, id in tree.iteritems(): |
|
334 | for name, stat, id in tree.iteritems(): | |
|
335 | if objects.S_ISGITLINK(stat): | |||
|
336 | dirnodes.append(SubModuleNode(name, url=None, changeset=id, | |||
|
337 | alias=als)) | |||
|
338 | continue | |||
|
339 | ||||
333 | obj = self.repository._repo.get_object(id) |
|
340 | obj = self.repository._repo.get_object(id) | |
334 | if path != '': |
|
341 | if path != '': | |
335 | obj_path = '/'.join((path, name)) |
|
342 | obj_path = '/'.join((path, name)) | |
@@ -357,24 +364,31 b' class GitChangeset(BaseChangeset):' | |||||
357 | path = self._fix_path(path) |
|
364 | path = self._fix_path(path) | |
358 | if not path in self.nodes: |
|
365 | if not path in self.nodes: | |
359 | try: |
|
366 | try: | |
360 | id = self._get_id_for_path(path) |
|
367 | id_ = self._get_id_for_path(path) | |
361 | except ChangesetError: |
|
368 | except ChangesetError: | |
362 | raise NodeDoesNotExistError("Cannot find one of parents' " |
|
369 | raise NodeDoesNotExistError("Cannot find one of parents' " | |
363 | "directories for a given path: %s" % path) |
|
370 | "directories for a given path: %s" % path) | |
364 | obj = self.repository._repo.get_object(id) |
|
371 | ||
365 | if isinstance(obj, objects.Tree): |
|
372 | als = self.repository.alias | |
366 | if path == '': |
|
373 | _GL = lambda m: m and objects.S_ISGITLINK(m) | |
367 | node = RootNode(changeset=self) |
|
374 | if _GL(self._stat_modes.get(path)): | |
|
375 | node = SubModuleNode(path, url=None, changeset=id_, alias=als) | |||
|
376 | else: | |||
|
377 | obj = self.repository._repo.get_object(id_) | |||
|
378 | ||||
|
379 | if isinstance(obj, objects.Tree): | |||
|
380 | if path == '': | |||
|
381 | node = RootNode(changeset=self) | |||
|
382 | else: | |||
|
383 | node = DirNode(path, changeset=self) | |||
|
384 | node._tree = obj | |||
|
385 | elif isinstance(obj, objects.Blob): | |||
|
386 | node = FileNode(path, changeset=self) | |||
|
387 | node._blob = obj | |||
368 | else: |
|
388 | else: | |
369 | node = DirNode(path, changeset=self) |
|
389 | raise NodeDoesNotExistError("There is no file nor directory " | |
370 | node._tree = obj |
|
390 | "at the given path %r at revision %r" | |
371 | elif isinstance(obj, objects.Blob): |
|
391 | % (path, self.short_id)) | |
372 | node = FileNode(path, changeset=self) |
|
|||
373 | node._blob = obj |
|
|||
374 | else: |
|
|||
375 | raise NodeDoesNotExistError("There is no file nor directory " |
|
|||
376 | "at the given path %r at revision %r" |
|
|||
377 | % (path, self.short_id)) |
|
|||
378 | # cache node |
|
392 | # cache node | |
379 | self.nodes[path] = node |
|
393 | self.nodes[path] = node | |
380 | return self.nodes[path] |
|
394 | return self.nodes[path] | |
@@ -416,7 +430,6 b' class GitChangeset(BaseChangeset):' | |||||
416 | line)) |
|
430 | line)) | |
417 | _path = splitted[1].strip() |
|
431 | _path = splitted[1].strip() | |
418 | paths.add(_path) |
|
432 | paths.add(_path) | |
419 |
|
||||
420 | return sorted(paths) |
|
433 | return sorted(paths) | |
421 |
|
434 | |||
422 | @LazyProperty |
|
435 | @LazyProperty |
@@ -52,7 +52,7 b' class GitRepository(BaseRepository):' | |||||
52 | if baseui is None: |
|
52 | if baseui is None: | |
53 | from mercurial.ui import ui |
|
53 | from mercurial.ui import ui | |
54 | baseui = ui() |
|
54 | baseui = ui() | |
55 |
# patch the instance of GitRepo with an "FAKE" ui object to add |
|
55 | # patch the instance of GitRepo with an "FAKE" ui object to add | |
56 | # compatibility layer with Mercurial |
|
56 | # compatibility layer with Mercurial | |
57 | setattr(self._repo, 'ui', baseui) |
|
57 | setattr(self._repo, 'ui', baseui) | |
58 |
|
58 | |||
@@ -411,7 +411,7 b' class GitRepository(BaseRepository):' | |||||
411 | yield self.get_changeset(rev) |
|
411 | yield self.get_changeset(rev) | |
412 |
|
412 | |||
413 | def get_diff(self, rev1, rev2, path=None, ignore_whitespace=False, |
|
413 | def get_diff(self, rev1, rev2, path=None, ignore_whitespace=False, | |
414 | context=3): |
|
414 | context=3): | |
415 | """ |
|
415 | """ | |
416 | Returns (git like) *diff*, as plain text. Shows changes introduced by |
|
416 | Returns (git like) *diff*, as plain text. Shows changes introduced by | |
417 | ``rev2`` since ``rev1``. |
|
417 | ``rev2`` since ``rev1``. |
@@ -5,8 +5,9 b' from rhodecode.lib.vcs.backends.base imp' | |||||
5 | from rhodecode.lib.vcs.conf import settings |
|
5 | from rhodecode.lib.vcs.conf import settings | |
6 | from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError, \ |
|
6 | from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError, \ | |
7 | ChangesetError, ImproperArchiveTypeError, NodeDoesNotExistError, VCSError |
|
7 | ChangesetError, ImproperArchiveTypeError, NodeDoesNotExistError, VCSError | |
8 |
from rhodecode.lib.vcs.nodes import AddedFileNodesGenerator, |
|
8 | from rhodecode.lib.vcs.nodes import AddedFileNodesGenerator, \ | |
9 | DirNode, FileNode, NodeKind, RemovedFileNodesGenerator, RootNode |
|
9 | ChangedFileNodesGenerator, DirNode, FileNode, NodeKind, \ | |
|
10 | RemovedFileNodesGenerator, RootNode, SubModuleNode | |||
10 |
|
11 | |||
11 | from rhodecode.lib.vcs.utils import safe_str, safe_unicode, date_fromtimestamp |
|
12 | from rhodecode.lib.vcs.utils import safe_str, safe_unicode, date_fromtimestamp | |
12 | from rhodecode.lib.vcs.utils.lazy import LazyProperty |
|
13 | from rhodecode.lib.vcs.utils.lazy import LazyProperty | |
@@ -159,6 +160,13 b' class MercurialChangeset(BaseChangeset):' | |||||
159 | " %r" % (self.revision, path)) |
|
160 | " %r" % (self.revision, path)) | |
160 | return self._ctx.filectx(path) |
|
161 | return self._ctx.filectx(path) | |
161 |
|
162 | |||
|
163 | def _extract_submodules(self): | |||
|
164 | """ | |||
|
165 | returns a dictionary with submodule information from substate file | |||
|
166 | of hg repository | |||
|
167 | """ | |||
|
168 | return self._ctx.substate | |||
|
169 | ||||
162 | def get_file_mode(self, path): |
|
170 | def get_file_mode(self, path): | |
163 | """ |
|
171 | """ | |
164 | Returns stat mode of the file at the given ``path``. |
|
172 | Returns stat mode of the file at the given ``path``. | |
@@ -271,17 +279,27 b' class MercurialChangeset(BaseChangeset):' | |||||
271 | raise ChangesetError("Directory does not exist for revision %r at " |
|
279 | raise ChangesetError("Directory does not exist for revision %r at " | |
272 | " %r" % (self.revision, path)) |
|
280 | " %r" % (self.revision, path)) | |
273 | path = self._fix_path(path) |
|
281 | path = self._fix_path(path) | |
|
282 | ||||
274 | filenodes = [FileNode(f, changeset=self) for f in self._file_paths |
|
283 | filenodes = [FileNode(f, changeset=self) for f in self._file_paths | |
275 | if os.path.dirname(f) == path] |
|
284 | if os.path.dirname(f) == path] | |
276 | dirs = path == '' and '' or [d for d in self._dir_paths |
|
285 | dirs = path == '' and '' or [d for d in self._dir_paths | |
277 | if d and posixpath.dirname(d) == path] |
|
286 | if d and posixpath.dirname(d) == path] | |
278 | dirnodes = [DirNode(d, changeset=self) for d in dirs |
|
287 | dirnodes = [DirNode(d, changeset=self) for d in dirs | |
279 | if os.path.dirname(d) == path] |
|
288 | if os.path.dirname(d) == path] | |
|
289 | ||||
|
290 | als = self.repository.alias | |||
|
291 | for k, vals in self._extract_submodules().iteritems(): | |||
|
292 | #vals = url,rev,type | |||
|
293 | loc = vals[0] | |||
|
294 | cs = vals[1] | |||
|
295 | dirnodes.append(SubModuleNode(k, url=loc, changeset=cs, | |||
|
296 | alias=als)) | |||
280 | nodes = dirnodes + filenodes |
|
297 | nodes = dirnodes + filenodes | |
281 | # cache nodes |
|
298 | # cache nodes | |
282 | for node in nodes: |
|
299 | for node in nodes: | |
283 | self.nodes[node.path] = node |
|
300 | self.nodes[node.path] = node | |
284 | nodes.sort() |
|
301 | nodes.sort() | |
|
302 | ||||
285 | return nodes |
|
303 | return nodes | |
286 |
|
304 | |||
287 | def get_node(self, path): |
|
305 | def get_node(self, path): |
@@ -8,19 +8,22 b'' | |||||
8 | :created_on: Apr 8, 2010 |
|
8 | :created_on: Apr 8, 2010 | |
9 | :copyright: (c) 2010-2011 by Marcin Kuzminski, Lukasz Balcerzak. |
|
9 | :copyright: (c) 2010-2011 by Marcin Kuzminski, Lukasz Balcerzak. | |
10 | """ |
|
10 | """ | |
|
11 | import os | |||
11 | import stat |
|
12 | import stat | |
12 | import posixpath |
|
13 | import posixpath | |
13 | import mimetypes |
|
14 | import mimetypes | |
14 |
|
15 | |||
|
16 | from pygments import lexers | |||
|
17 | ||||
15 | from rhodecode.lib.vcs.utils.lazy import LazyProperty |
|
18 | from rhodecode.lib.vcs.utils.lazy import LazyProperty | |
16 | from rhodecode.lib.vcs.utils import safe_unicode |
|
19 | from rhodecode.lib.vcs.utils import safe_unicode, safe_str | |
17 | from rhodecode.lib.vcs.exceptions import NodeError |
|
20 | from rhodecode.lib.vcs.exceptions import NodeError | |
18 | from rhodecode.lib.vcs.exceptions import RemovedFileNodeError |
|
21 | from rhodecode.lib.vcs.exceptions import RemovedFileNodeError | |
19 |
|
22 | from rhodecode.lib.vcs.backends.base import EmptyChangeset | ||
20 | from pygments import lexers |
|
|||
21 |
|
23 | |||
22 |
|
24 | |||
23 | class NodeKind: |
|
25 | class NodeKind: | |
|
26 | SUBMODULE = -1 | |||
24 | DIR = 1 |
|
27 | DIR = 1 | |
25 | FILE = 2 |
|
28 | FILE = 2 | |
26 |
|
29 | |||
@@ -209,6 +212,13 b' class Node(object):' | |||||
209 | """ |
|
212 | """ | |
210 | return self.kind == NodeKind.DIR and self.path == '' |
|
213 | return self.kind == NodeKind.DIR and self.path == '' | |
211 |
|
214 | |||
|
215 | def is_submodule(self): | |||
|
216 | """ | |||
|
217 | Returns ``True`` if node's kind is ``NodeKind.SUBMODULE``, ``False`` | |||
|
218 | otherwise. | |||
|
219 | """ | |||
|
220 | return self.kind == NodeKind.SUBMODULE | |||
|
221 | ||||
212 | @LazyProperty |
|
222 | @LazyProperty | |
213 | def added(self): |
|
223 | def added(self): | |
214 | return self.state is NodeState.ADDED |
|
224 | return self.state is NodeState.ADDED | |
@@ -561,3 +571,41 b' class RootNode(DirNode):' | |||||
561 |
|
571 | |||
562 | def __repr__(self): |
|
572 | def __repr__(self): | |
563 | return '<%s>' % self.__class__.__name__ |
|
573 | return '<%s>' % self.__class__.__name__ | |
|
574 | ||||
|
575 | ||||
|
576 | class SubModuleNode(Node): | |||
|
577 | """ | |||
|
578 | represents a SubModule of Git or SubRepo of Mercurial | |||
|
579 | """ | |||
|
580 | is_binary = False | |||
|
581 | size = 0 | |||
|
582 | ||||
|
583 | def __init__(self, name, url=None, changeset=None, alias=None): | |||
|
584 | self.path = name | |||
|
585 | self.kind = NodeKind.SUBMODULE | |||
|
586 | self.alias = alias | |||
|
587 | # we have to use emptyChangeset here since this can point to svn/git/hg | |||
|
588 | # submodules we cannot get from repository | |||
|
589 | self.changeset = EmptyChangeset(str(changeset), alias=alias) | |||
|
590 | self.url = url or self._extract_submodule_url() | |||
|
591 | ||||
|
592 | def __repr__(self): | |||
|
593 | return '<%s %r @ %s>' % (self.__class__.__name__, self.path, | |||
|
594 | self.changeset.short_id) | |||
|
595 | ||||
|
596 | def _extract_submodule_url(self): | |||
|
597 | if self.alias == 'git': | |||
|
598 | #TODO: find a way to parse gits submodule file and extract the | |||
|
599 | # linking URL | |||
|
600 | return self.path | |||
|
601 | if self.alias == 'hg': | |||
|
602 | return self.path | |||
|
603 | ||||
|
604 | @LazyProperty | |||
|
605 | def name(self): | |||
|
606 | """ | |||
|
607 | Returns name of the node so if its path | |||
|
608 | then only last part is returned. | |||
|
609 | """ | |||
|
610 | org = safe_unicode(self.path.rstrip('/').split('/')[-1]) | |||
|
611 | return u'%s @ %s' % (org, self.changeset.short_id) |
@@ -2729,6 +2729,14 b' table.code-browser .browser-dir {' | |||||
2729 | text-align: left; |
|
2729 | text-align: left; | |
2730 | } |
|
2730 | } | |
2731 |
|
2731 | |||
|
2732 | table.code-browser .submodule-dir { | |||
|
2733 | background: url("../images/icons/disconnect.png") no-repeat scroll 3px; | |||
|
2734 | height: 16px; | |||
|
2735 | padding-left: 20px; | |||
|
2736 | text-align: left; | |||
|
2737 | } | |||
|
2738 | ||||
|
2739 | ||||
2732 | .box .search { |
|
2740 | .box .search { | |
2733 | clear: both; |
|
2741 | clear: both; | |
2734 | overflow: hidden; |
|
2742 | overflow: hidden; |
@@ -81,8 +81,11 b'' | |||||
81 | %if len(c.changeset.parents)>1: |
|
81 | %if len(c.changeset.parents)>1: | |
82 | <span class="merge">${_('merge')}</span> |
|
82 | <span class="merge">${_('merge')}</span> | |
83 | %endif |
|
83 | %endif | |
84 | <span class="branchtag" title="${'%s %s' % (_('branch'),c.changeset.branch)}"> |
|
84 | %if c.changeset.branch: | |
85 | ${h.link_to(c.changeset.branch,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}</span> |
|
85 | <span class="branchtag" title="${'%s %s' % (_('branch'),c.changeset.branch)}"> | |
|
86 | ${h.link_to(c.changeset.branch,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id))} | |||
|
87 | </span> | |||
|
88 | %endif | |||
86 | %for tag in c.changeset.tags: |
|
89 | %for tag in c.changeset.tags: | |
87 | <span class="tagtag" title="${'%s %s' % (_('tag'),tag)}"> |
|
90 | <span class="tagtag" title="${'%s %s' % (_('tag'),tag)}"> | |
88 | ${h.link_to(tag,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}</span> |
|
91 | ${h.link_to(tag,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id))}</span> |
@@ -70,7 +70,11 b'' | |||||
70 | %for cnt,node in enumerate(c.file): |
|
70 | %for cnt,node in enumerate(c.file): | |
71 | <tr class="parity${cnt%2}"> |
|
71 | <tr class="parity${cnt%2}"> | |
72 | <td> |
|
72 | <td> | |
73 | ${h.link_to(node.name,h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=h.safe_unicode(node.path)),class_=file_class(node)+" ypjax-link")} |
|
73 | %if node.is_submodule(): | |
|
74 | ${h.link_to(node.name,node.url or '#',class_="submodule-dir ypjax-link")} | |||
|
75 | %else: | |||
|
76 | ${h.link_to(node.name, h.url('files_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=h.safe_unicode(node.path)),class_=file_class(node)+" ypjax-link")} | |||
|
77 | %endif: | |||
74 | </td> |
|
78 | </td> | |
75 | <td> |
|
79 | <td> | |
76 | %if node.is_file(): |
|
80 | %if node.is_file(): |
@@ -119,7 +119,7 b'' | |||||
119 | </div> |
|
119 | </div> | |
120 | </div> |
|
120 | </div> | |
121 | <script> |
|
121 | <script> | |
122 | YUD.get('repo_count').innerHTML = ${cnt}; |
|
122 | YUD.get('repo_count').innerHTML = ${cnt+1}; | |
123 | var func = function(node){ |
|
123 | var func = function(node){ | |
124 | return node.parentNode.parentNode.parentNode.parentNode; |
|
124 | return node.parentNode.parentNode.parentNode.parentNode; | |
125 | } |
|
125 | } |
@@ -15,7 +15,7 b'' | |||||
15 | <div><pre><a href="${h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id)}">r${cs.revision}:${h.short_id(cs.raw_id)}</a></pre></div> |
|
15 | <div><pre><a href="${h.url('files_home',repo_name=c.repo_name,revision=cs.raw_id)}">r${cs.revision}:${h.short_id(cs.raw_id)}</a></pre></div> | |
16 | </td> |
|
16 | </td> | |
17 | <td> |
|
17 | <td> | |
18 | ${h.link_to(h.truncate(cs.message,50), |
|
18 | ${h.link_to(h.truncate(cs.message,50) or _('No commit message'), | |
19 | h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id), |
|
19 | h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id), | |
20 | title=cs.message)} |
|
20 | title=cs.message)} | |
21 | </td> |
|
21 | </td> | |
@@ -25,9 +25,11 b'' | |||||
25 | <td title="${cs.author}">${h.person(cs.author)}</td> |
|
25 | <td title="${cs.author}">${h.person(cs.author)}</td> | |
26 | <td> |
|
26 | <td> | |
27 | <span class="logtags"> |
|
27 | <span class="logtags"> | |
|
28 | %if cs.branch: | |||
28 | <span class="branchtag"> |
|
29 | <span class="branchtag"> | |
29 | ${cs.branch} |
|
30 | ${cs.branch} | |
30 | </span> |
|
31 | </span> | |
|
32 | %endif | |||
31 | </span> |
|
33 | </span> | |
32 | </td> |
|
34 | </td> | |
33 | <td> |
|
35 | <td> |
General Comments 0
You need to be logged in to leave comments.
Login now