##// END OF EJS Templates
first implementation of #34 changeset raw diff based on udiff from python
marcink -
r466:183cee11 default
parent child Browse files
Show More
@@ -0,0 +1,8 b''
1 # HG changeset patch
2 # User ${c.changeset.author}
3 # Date ${"%d %d" % c.changeset._ctx.date()}
4 # Node ID ${c.changeset._hex}
5 # ${c.parent_tmpl}
6 ${c.changeset.message}
7
8 ${c.diffs|n} No newline at end of file
@@ -1,164 +1,167 b''
1 """Routes configuration
1 """Routes configuration
2
2
3 The more specific and detailed routes should be defined first so they
3 The more specific and detailed routes should be defined first so they
4 may take precedent over the more generic routes. For more information
4 may take precedent over the more generic routes. For more information
5 refer to the routes manual at http://routes.groovie.org/docs/
5 refer to the routes manual at http://routes.groovie.org/docs/
6 """
6 """
7 from __future__ import with_statement
7 from __future__ import with_statement
8 from routes import Mapper
8 from routes import Mapper
9 from pylons_app.lib.utils import check_repo_fast as cr
9 from pylons_app.lib.utils import check_repo_fast as cr
10
10
11 def make_map(config):
11 def make_map(config):
12 """Create, configure and return the routes Mapper"""
12 """Create, configure and return the routes Mapper"""
13 map = Mapper(directory=config['pylons.paths']['controllers'],
13 map = Mapper(directory=config['pylons.paths']['controllers'],
14 always_scan=config['debug'])
14 always_scan=config['debug'])
15 map.minimization = False
15 map.minimization = False
16 map.explicit = False
16 map.explicit = False
17
17
18 # The ErrorController route (handles 404/500 error pages); it should
18 # The ErrorController route (handles 404/500 error pages); it should
19 # likely stay at the top, ensuring it can always be resolved
19 # likely stay at the top, ensuring it can always be resolved
20 map.connect('/error/{action}', controller='error')
20 map.connect('/error/{action}', controller='error')
21 map.connect('/error/{action}/{id}', controller='error')
21 map.connect('/error/{action}/{id}', controller='error')
22
22
23 # CUSTOM ROUTES HERE
23 # CUSTOM ROUTES HERE
24 map.connect('hg_home', '/', controller='hg', action='index')
24 map.connect('hg_home', '/', controller='hg', action='index')
25
25
26 def check_repo(environ, match_dict):
26 def check_repo(environ, match_dict):
27 """
27 """
28 check for valid repository for proper 404 handling
28 check for valid repository for proper 404 handling
29 @param environ:
29 @param environ:
30 @param match_dict:
30 @param match_dict:
31 """
31 """
32 repo_name = match_dict.get('repo_name')
32 repo_name = match_dict.get('repo_name')
33 return not cr(repo_name, config['base_path'])
33 return not cr(repo_name, config['base_path'])
34
34
35 #REST REPO MAP
35 #REST REPO MAP
36 with map.submapper(path_prefix='/_admin', controller='admin/repos') as m:
36 with map.submapper(path_prefix='/_admin', controller='admin/repos') as m:
37 m.connect("repos", "/repos",
37 m.connect("repos", "/repos",
38 action="create", conditions=dict(method=["POST"]))
38 action="create", conditions=dict(method=["POST"]))
39 m.connect("repos", "/repos",
39 m.connect("repos", "/repos",
40 action="index", conditions=dict(method=["GET"]))
40 action="index", conditions=dict(method=["GET"]))
41 m.connect("formatted_repos", "/repos.{format}",
41 m.connect("formatted_repos", "/repos.{format}",
42 action="index",
42 action="index",
43 conditions=dict(method=["GET"]))
43 conditions=dict(method=["GET"]))
44 m.connect("new_repo", "/repos/new",
44 m.connect("new_repo", "/repos/new",
45 action="new", conditions=dict(method=["GET"]))
45 action="new", conditions=dict(method=["GET"]))
46 m.connect("formatted_new_repo", "/repos/new.{format}",
46 m.connect("formatted_new_repo", "/repos/new.{format}",
47 action="new", conditions=dict(method=["GET"]))
47 action="new", conditions=dict(method=["GET"]))
48 m.connect("/repos/{repo_name:.*}",
48 m.connect("/repos/{repo_name:.*}",
49 action="update", conditions=dict(method=["PUT"],
49 action="update", conditions=dict(method=["PUT"],
50 function=check_repo))
50 function=check_repo))
51 m.connect("/repos/{repo_name:.*}",
51 m.connect("/repos/{repo_name:.*}",
52 action="delete", conditions=dict(method=["DELETE"],
52 action="delete", conditions=dict(method=["DELETE"],
53 function=check_repo))
53 function=check_repo))
54 m.connect("edit_repo", "/repos/{repo_name:.*}/edit",
54 m.connect("edit_repo", "/repos/{repo_name:.*}/edit",
55 action="edit", conditions=dict(method=["GET"],
55 action="edit", conditions=dict(method=["GET"],
56 function=check_repo))
56 function=check_repo))
57 m.connect("formatted_edit_repo", "/repos/{repo_name:.*}.{format}/edit",
57 m.connect("formatted_edit_repo", "/repos/{repo_name:.*}.{format}/edit",
58 action="edit", conditions=dict(method=["GET"],
58 action="edit", conditions=dict(method=["GET"],
59 function=check_repo))
59 function=check_repo))
60 m.connect("repo", "/repos/{repo_name:.*}",
60 m.connect("repo", "/repos/{repo_name:.*}",
61 action="show", conditions=dict(method=["GET"],
61 action="show", conditions=dict(method=["GET"],
62 function=check_repo))
62 function=check_repo))
63 m.connect("formatted_repo", "/repos/{repo_name:.*}.{format}",
63 m.connect("formatted_repo", "/repos/{repo_name:.*}.{format}",
64 action="show", conditions=dict(method=["GET"],
64 action="show", conditions=dict(method=["GET"],
65 function=check_repo))
65 function=check_repo))
66 #ajax delete repo perm user
66 #ajax delete repo perm user
67 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
67 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
68 action="delete_perm_user", conditions=dict(method=["DELETE"],
68 action="delete_perm_user", conditions=dict(method=["DELETE"],
69 function=check_repo))
69 function=check_repo))
70
70
71 map.resource('user', 'users', controller='admin/users', path_prefix='/_admin')
71 map.resource('user', 'users', controller='admin/users', path_prefix='/_admin')
72 map.resource('permission', 'permissions', controller='admin/permissions', path_prefix='/_admin')
72 map.resource('permission', 'permissions', controller='admin/permissions', path_prefix='/_admin')
73
73
74 #REST SETTINGS MAP
74 #REST SETTINGS MAP
75 with map.submapper(path_prefix='/_admin', controller='admin/settings') as m:
75 with map.submapper(path_prefix='/_admin', controller='admin/settings') as m:
76 m.connect("admin_settings", "/settings",
76 m.connect("admin_settings", "/settings",
77 action="create", conditions=dict(method=["POST"]))
77 action="create", conditions=dict(method=["POST"]))
78 m.connect("admin_settings", "/settings",
78 m.connect("admin_settings", "/settings",
79 action="index", conditions=dict(method=["GET"]))
79 action="index", conditions=dict(method=["GET"]))
80 m.connect("formatted_admin_settings", "/settings.{format}",
80 m.connect("formatted_admin_settings", "/settings.{format}",
81 action="index", conditions=dict(method=["GET"]))
81 action="index", conditions=dict(method=["GET"]))
82 m.connect("admin_new_setting", "/settings/new",
82 m.connect("admin_new_setting", "/settings/new",
83 action="new", conditions=dict(method=["GET"]))
83 action="new", conditions=dict(method=["GET"]))
84 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
84 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
85 action="new", conditions=dict(method=["GET"]))
85 action="new", conditions=dict(method=["GET"]))
86 m.connect("/settings/{setting_id}",
86 m.connect("/settings/{setting_id}",
87 action="update", conditions=dict(method=["PUT"]))
87 action="update", conditions=dict(method=["PUT"]))
88 m.connect("/settings/{setting_id}",
88 m.connect("/settings/{setting_id}",
89 action="delete", conditions=dict(method=["DELETE"]))
89 action="delete", conditions=dict(method=["DELETE"]))
90 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
90 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
91 action="edit", conditions=dict(method=["GET"]))
91 action="edit", conditions=dict(method=["GET"]))
92 m.connect("formatted_admin_edit_setting", "/settings/{setting_id}.{format}/edit",
92 m.connect("formatted_admin_edit_setting", "/settings/{setting_id}.{format}/edit",
93 action="edit", conditions=dict(method=["GET"]))
93 action="edit", conditions=dict(method=["GET"]))
94 m.connect("admin_setting", "/settings/{setting_id}",
94 m.connect("admin_setting", "/settings/{setting_id}",
95 action="show", conditions=dict(method=["GET"]))
95 action="show", conditions=dict(method=["GET"]))
96 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
96 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
97 action="show", conditions=dict(method=["GET"]))
97 action="show", conditions=dict(method=["GET"]))
98 m.connect("admin_settings_my_account", "/my_account",
98 m.connect("admin_settings_my_account", "/my_account",
99 action="my_account", conditions=dict(method=["GET"]))
99 action="my_account", conditions=dict(method=["GET"]))
100 m.connect("admin_settings_my_account_update", "/my_account_update",
100 m.connect("admin_settings_my_account_update", "/my_account_update",
101 action="my_account_update", conditions=dict(method=["PUT"]))
101 action="my_account_update", conditions=dict(method=["PUT"]))
102 m.connect("admin_settings_create_repository", "/create_repository",
102 m.connect("admin_settings_create_repository", "/create_repository",
103 action="create_repository", conditions=dict(method=["GET"]))
103 action="create_repository", conditions=dict(method=["GET"]))
104
104
105 #ADMIN
105 #ADMIN
106 with map.submapper(path_prefix='/_admin', controller='admin/admin') as m:
106 with map.submapper(path_prefix='/_admin', controller='admin/admin') as m:
107 m.connect('admin_home', '', action='index')#main page
107 m.connect('admin_home', '', action='index')#main page
108 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
108 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
109 action='add_repo')
109 action='add_repo')
110 #SEARCH
110 #SEARCH
111 map.connect('search', '/_admin/search', controller='search')
111 map.connect('search', '/_admin/search', controller='search')
112
112
113 #LOGIN/LOGOUT
113 #LOGIN/LOGOUT
114 map.connect('login_home', '/_admin/login', controller='login')
114 map.connect('login_home', '/_admin/login', controller='login')
115 map.connect('logout_home', '/_admin/logout', controller='login', action='logout')
115 map.connect('logout_home', '/_admin/logout', controller='login', action='logout')
116 map.connect('register', '/_admin/register', controller='login', action='register')
116 map.connect('register', '/_admin/register', controller='login', action='register')
117
117
118 #FEEDS
118 #FEEDS
119 map.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
119 map.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
120 controller='feed', action='rss',
120 controller='feed', action='rss',
121 conditions=dict(function=check_repo))
121 conditions=dict(function=check_repo))
122 map.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
122 map.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
123 controller='feed', action='atom',
123 controller='feed', action='atom',
124 conditions=dict(function=check_repo))
124 conditions=dict(function=check_repo))
125
125
126
126
127 #OTHERS
127 #OTHERS
128 map.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
128 map.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
129 controller='changeset', revision='tip',
129 controller='changeset', revision='tip',
130 conditions=dict(function=check_repo))
130 conditions=dict(function=check_repo))
131 map.connect('raw_changeset_home', '/{repo_name:.*}/raw-changeset/{revision}',
132 controller='changeset',action='raw_changeset', revision='tip',
133 conditions=dict(function=check_repo))
131 map.connect('summary_home', '/{repo_name:.*}/summary',
134 map.connect('summary_home', '/{repo_name:.*}/summary',
132 controller='summary', conditions=dict(function=check_repo))
135 controller='summary', conditions=dict(function=check_repo))
133 map.connect('shortlog_home', '/{repo_name:.*}/shortlog',
136 map.connect('shortlog_home', '/{repo_name:.*}/shortlog',
134 controller='shortlog', conditions=dict(function=check_repo))
137 controller='shortlog', conditions=dict(function=check_repo))
135 map.connect('branches_home', '/{repo_name:.*}/branches',
138 map.connect('branches_home', '/{repo_name:.*}/branches',
136 controller='branches', conditions=dict(function=check_repo))
139 controller='branches', conditions=dict(function=check_repo))
137 map.connect('tags_home', '/{repo_name:.*}/tags',
140 map.connect('tags_home', '/{repo_name:.*}/tags',
138 controller='tags', conditions=dict(function=check_repo))
141 controller='tags', conditions=dict(function=check_repo))
139 map.connect('changelog_home', '/{repo_name:.*}/changelog',
142 map.connect('changelog_home', '/{repo_name:.*}/changelog',
140 controller='changelog', conditions=dict(function=check_repo))
143 controller='changelog', conditions=dict(function=check_repo))
141 map.connect('files_home', '/{repo_name:.*}/files/{revision}/{f_path:.*}',
144 map.connect('files_home', '/{repo_name:.*}/files/{revision}/{f_path:.*}',
142 controller='files', revision='tip', f_path='',
145 controller='files', revision='tip', f_path='',
143 conditions=dict(function=check_repo))
146 conditions=dict(function=check_repo))
144 map.connect('files_diff_home', '/{repo_name:.*}/diff/{f_path:.*}',
147 map.connect('files_diff_home', '/{repo_name:.*}/diff/{f_path:.*}',
145 controller='files', action='diff', revision='tip', f_path='',
148 controller='files', action='diff', revision='tip', f_path='',
146 conditions=dict(function=check_repo))
149 conditions=dict(function=check_repo))
147 map.connect('files_raw_home', '/{repo_name:.*}/rawfile/{revision}/{f_path:.*}',
150 map.connect('files_raw_home', '/{repo_name:.*}/rawfile/{revision}/{f_path:.*}',
148 controller='files', action='rawfile', revision='tip', f_path='',
151 controller='files', action='rawfile', revision='tip', f_path='',
149 conditions=dict(function=check_repo))
152 conditions=dict(function=check_repo))
150 map.connect('files_annotate_home', '/{repo_name:.*}/annotate/{revision}/{f_path:.*}',
153 map.connect('files_annotate_home', '/{repo_name:.*}/annotate/{revision}/{f_path:.*}',
151 controller='files', action='annotate', revision='tip', f_path='',
154 controller='files', action='annotate', revision='tip', f_path='',
152 conditions=dict(function=check_repo))
155 conditions=dict(function=check_repo))
153 map.connect('files_archive_home', '/{repo_name:.*}/archive/{revision}/{fileformat}',
156 map.connect('files_archive_home', '/{repo_name:.*}/archive/{revision}/{fileformat}',
154 controller='files', action='archivefile', revision='tip',
157 controller='files', action='archivefile', revision='tip',
155 conditions=dict(function=check_repo))
158 conditions=dict(function=check_repo))
156 map.connect('repo_settings_update', '/{repo_name:.*}/settings',
159 map.connect('repo_settings_update', '/{repo_name:.*}/settings',
157 controller='settings', action="update",
160 controller='settings', action="update",
158 conditions=dict(method=["PUT"], function=check_repo))
161 conditions=dict(method=["PUT"], function=check_repo))
159 map.connect('repo_settings_home', '/{repo_name:.*}/settings',
162 map.connect('repo_settings_home', '/{repo_name:.*}/settings',
160 controller='settings', action='index',
163 controller='settings', action='index',
161 conditions=dict(function=check_repo))
164 conditions=dict(function=check_repo))
162
165
163
166
164 return map
167 return map
@@ -1,97 +1,136 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # changeset controller for pylons
3 # changeset controller for pylons
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5
6 # This program is free software; you can redistribute it and/or
5 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
6 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
7 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
8 # of the License or (at your opinion) any later version of the license.
10 #
9 #
11 # This program is distributed in the hope that it will be useful,
10 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
13 # GNU General Public License for more details.
15 #
14 #
16 # You should have received a copy of the GNU General Public License
15 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
16 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
18 # MA 02110-1301, USA.
20 """
19 """
21 Created on April 25, 2010
20 Created on April 25, 2010
22 changeset controller for pylons
21 changeset controller for pylons
23 @author: marcink
22 @author: marcink
24 """
23 """
25 from pylons import tmpl_context as c, url, request
24 from pylons import tmpl_context as c, url, request, response
26 from pylons.controllers.util import redirect
25 from pylons.controllers.util import redirect
27 from pylons_app.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
26 from pylons_app.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
28 from pylons_app.lib.base import BaseController, render
27 from pylons_app.lib.base import BaseController, render
29 from pylons_app.model.hg_model import HgModel
28 from pylons_app.model.hg_model import HgModel
30 from vcs.exceptions import RepositoryError
29 from vcs.exceptions import RepositoryError
31 from vcs.nodes import FileNode
30 from vcs.nodes import FileNode
32 from vcs.utils import diffs as differ
31 from vcs.utils import diffs as differ
33 import logging
32 import logging
34 import traceback
33 import traceback
35
34
36 log = logging.getLogger(__name__)
35 log = logging.getLogger(__name__)
37
36
38 class ChangesetController(BaseController):
37 class ChangesetController(BaseController):
39
38
40 @LoginRequired()
39 @LoginRequired()
41 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
40 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
42 'repository.admin')
41 'repository.admin')
43 def __before__(self):
42 def __before__(self):
44 super(ChangesetController, self).__before__()
43 super(ChangesetController, self).__before__()
45
44
46 def index(self, revision):
45 def index(self, revision):
47 hg_model = HgModel()
46 hg_model = HgModel()
48 try:
47 try:
49 c.changeset = hg_model.get_repo(c.repo_name).get_changeset(revision)
48 c.changeset = hg_model.get_repo(c.repo_name).get_changeset(revision)
50 except RepositoryError:
49 except RepositoryError:
51 log.error(traceback.format_exc())
50 log.error(traceback.format_exc())
52 return redirect(url('hg_home'))
51 return redirect(url('hg_home'))
53 else:
52 else:
54 try:
53 try:
55 c.changeset_old = c.changeset.parents[0]
54 c.changeset_old = c.changeset.parents[0]
56 except IndexError:
55 except IndexError:
57 c.changeset_old = None
56 c.changeset_old = None
58 c.changes = []
57 c.changes = []
59
58
60 for node in c.changeset.added:
59 for node in c.changeset.added:
61 filenode_old = FileNode(node.path, '')
60 filenode_old = FileNode(node.path, '')
62 if filenode_old.is_binary or node.is_binary:
61 if filenode_old.is_binary or node.is_binary:
63 diff = 'binary file'
62 diff = 'binary file'
64 else:
63 else:
65 f_udiff = differ.get_udiff(filenode_old, node)
64 f_udiff = differ.get_udiff(filenode_old, node)
66 diff = differ.DiffProcessor(f_udiff).as_html()
65 diff = differ.DiffProcessor(f_udiff).as_html()
67 try:
66
68 diff = unicode(diff)
69 except:
70 log.warning('Decoding failed of %s', filenode_old)
71 log.warning('Decoding failed of %s', node)
72 diff = 'unsupported type'
73 cs1 = None
67 cs1 = None
74 cs2 = node.last_changeset.raw_id
68 cs2 = node.last_changeset.raw_id
75 c.changes.append(('added', node, diff, cs1, cs2))
69 c.changes.append(('added', node, diff, cs1, cs2))
76
70
77 for node in c.changeset.changed:
71 for node in c.changeset.changed:
78 filenode_old = c.changeset_old.get_node(node.path)
72 filenode_old = c.changeset_old.get_node(node.path)
79 if filenode_old.is_binary or node.is_binary:
73 if filenode_old.is_binary or node.is_binary:
80 diff = 'binary file'
74 diff = 'binary file'
81 else:
75 else:
82 f_udiff = differ.get_udiff(filenode_old, node)
76 f_udiff = differ.get_udiff(filenode_old, node)
83 diff = differ.DiffProcessor(f_udiff).as_html()
77 diff = differ.DiffProcessor(f_udiff).as_html()
84 try:
78
85 diff = unicode(diff)
86 except:
87 log.warning('Decoding failed of %s', filenode_old)
88 log.warning('Decoding failed of %s', node)
89 diff = 'unsupported type'
90 cs1 = filenode_old.last_changeset.raw_id
79 cs1 = filenode_old.last_changeset.raw_id
91 cs2 = node.last_changeset.raw_id
80 cs2 = node.last_changeset.raw_id
92 c.changes.append(('changed', node, diff, cs1, cs2))
81 c.changes.append(('changed', node, diff, cs1, cs2))
93
82
94 for node in c.changeset.removed:
83 for node in c.changeset.removed:
95 c.changes.append(('removed', node, None, None, None))
84 c.changes.append(('removed', node, None, None, None))
96
85
97 return render('changeset/changeset.html')
86 return render('changeset/changeset.html')
87
88 def raw_changeset(self,revision):
89
90 hg_model = HgModel()
91 try:
92 c.changeset = hg_model.get_repo(c.repo_name).get_changeset(revision)
93 except RepositoryError:
94 log.error(traceback.format_exc())
95 return redirect(url('hg_home'))
96 else:
97 try:
98 c.changeset_old = c.changeset.parents[0]
99 except IndexError:
100 c.changeset_old = None
101 c.changes = []
102
103 for node in c.changeset.added:
104 filenode_old = FileNode(node.path, '')
105 if filenode_old.is_binary or node.is_binary:
106 diff = 'binary file'
107 else:
108 f_udiff = differ.get_udiff(filenode_old, node)
109 diff = differ.DiffProcessor(f_udiff).raw_diff()
110
111 cs1 = None
112 cs2 = node.last_changeset.raw_id
113 c.changes.append(('added', node, diff, cs1, cs2))
114
115 for node in c.changeset.changed:
116 filenode_old = c.changeset_old.get_node(node.path)
117 if filenode_old.is_binary or node.is_binary:
118 diff = 'binary file'
119 else:
120 f_udiff = differ.get_udiff(filenode_old, node)
121 diff = differ.DiffProcessor(f_udiff).raw_diff()
122
123 cs1 = filenode_old.last_changeset.raw_id
124 cs2 = node.last_changeset.raw_id
125 c.changes.append(('changed', node, diff, cs1, cs2))
126
127 response.content_type = 'text/plain'
128
129 parent = True if len(c.changeset.parents) > 0 else False
130 c.parent_tmpl = 'Parent %s' % c.changeset.parents[0]._hex if parent else ''
131
132 c.diffs = ''
133 for x in c.changes:
134 c.diffs += x[2]
135
136 return render('changeset/raw_changeset.html')
General Comments 0
You need to be logged in to leave comments. Login now