Merge lp:~jelmer/loggerhead/breezy-compat-1 into lp:loggerhead

Proposed by Jelmer Vernooij
Status: Merged
Merged at revision: 496
Proposed branch: lp:~jelmer/loggerhead/breezy-compat-1
Merge into: lp:loggerhead
Diff against target: 361 lines (+97/-53)
6 files modified
loggerhead/controllers/filediff_ui.py (+44/-22)
loggerhead/controllers/revision_ui.py (+6/-4)
loggerhead/controllers/view_ui.py (+9/-8)
loggerhead/history.py (+28/-12)
loggerhead/main.py (+4/-1)
loggerhead/tests/test_controllers.py (+6/-6)
To merge this branch: bzr merge lp:~jelmer/loggerhead/breezy-compat-1
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Loggerhead Reviewers Pending
Review via email: mp+377809@code.launchpad.net

Commit message

Fix compatibility with newer versions of Breezy.

Description of the change

Fix compatibility with newer versions of Breezy.

Newer versions of Breezy have removed file ids from most of the public API, to
accomodate formats that don't have file ids (like Git).

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'loggerhead/controllers/filediff_ui.py'
2--- loggerhead/controllers/filediff_ui.py 2018-10-20 16:06:44 +0000
3+++ loggerhead/controllers/filediff_ui.py 2020-01-19 20:20:41 +0000
4@@ -3,9 +3,19 @@
5 from breezy import (
6 diff,
7 errors,
8- osutils,
9 urlutils,
10 )
11+try:
12+ from breezy.tree import find_previous_path
13+except ImportError: # breezy < 3.1
14+ def find_previous_path(from_tree, to_tree, path):
15+ file_id = from_tree.path2id(path)
16+ if file_id is None:
17+ raise errors.NoSuchFile(path)
18+ try:
19+ return to_tree.id2path(file_id)
20+ except errors.NoSuchId:
21+ return None
22
23 from .. import util
24 from ..controllers import TemplatedBranchView
25@@ -14,6 +24,7 @@
26 def _process_diff(difftext):
27 chunks = []
28 chunk = None
29+
30 def decode_line(line):
31 return line.decode('utf-8', 'replace')
32 for line in difftext.splitlines():
33@@ -39,41 +50,52 @@
34 old_lineno += 1
35 new_lineno += 1
36 elif line.startswith(b'+'):
37- chunk.diff.append(util.Container(old_lineno=None,
38- new_lineno=new_lineno,
39- type='insert', line=decode_line(line[1:])))
40+ chunk.diff.append(util.Container(
41+ old_lineno=None,
42+ new_lineno=new_lineno,
43+ type='insert', line=decode_line(line[1:])))
44 new_lineno += 1
45 elif line.startswith(b'-'):
46- chunk.diff.append(util.Container(old_lineno=old_lineno,
47- new_lineno=None,
48- type='delete', line=decode_line(line[1:])))
49+ chunk.diff.append(util.Container(
50+ old_lineno=old_lineno,
51+ new_lineno=None,
52+ type='delete', line=decode_line(line[1:])))
53 old_lineno += 1
54 else:
55- chunk.diff.append(util.Container(old_lineno=None,
56- new_lineno=None,
57- type='unknown',
58- line=repr(line)))
59+ chunk.diff.append(util.Container(
60+ old_lineno=None,
61+ new_lineno=None,
62+ type='unknown',
63+ line=repr(line)))
64 if chunk is not None:
65 chunks.append(chunk)
66 return chunks
67
68
69-def diff_chunks_for_file(repository, file_id, compare_revid, revid,
70+def diff_chunks_for_file(repository, filename, compare_revid, revid,
71 context_lines=None):
72 if context_lines is None:
73 context_lines = 3
74 lines = {}
75- args = []
76- for r in (compare_revid, revid):
77- if r == b'null:':
78- lines[r] = []
79+ compare_tree = repository.revision_tree(compare_revid)
80+ tree = repository.revision_tree(revid)
81+ try:
82+ lines[revid] = tree.get_file_lines(filename)
83+ except errors.NoSuchFile:
84+ lines[revid] = []
85+ lines[compare_revid] = compare_tree.get_file_lines(filename)
86+ else:
87+ compare_filename = find_previous_path(tree, compare_tree, filename)
88+ if compare_filename is not None:
89+ lines[compare_revid] = compare_tree.get_file_lines(compare_filename)
90 else:
91- args.append((file_id, r, r))
92- for r, bytes_iter in repository.iter_files_bytes(args):
93- lines[r] = osutils.split_lines(b''.join(bytes_iter))
94+ lines[compare_revid] = []
95+
96 buffer = BytesIO()
97 try:
98- diff.internal_diff('', lines[compare_revid], '', lines[revid], buffer, context_lines=context_lines)
99+ diff.internal_diff(
100+ '', lines[compare_revid], '', lines[revid], buffer,
101+ context_lines=context_lines)
102 except errors.BinaryFile:
103 difftext = b''
104 else:
105@@ -90,7 +112,7 @@
106 def get_values(self, path, kwargs, headers):
107 revid = urlutils.unquote_to_bytes(self.args[0])
108 compare_revid = urlutils.unquote_to_bytes(self.args[1])
109- file_id = urlutils.unquote_to_bytes(self.args[2])
110+ filename = urlutils.unquote(self.args[2])
111
112 try:
113 context_lines = int(kwargs['context'])
114@@ -98,7 +120,7 @@
115 context_lines = None
116
117 chunks = diff_chunks_for_file(
118- self._history._branch.repository, file_id, compare_revid, revid,
119+ self._history._branch.repository, filename, compare_revid, revid,
120 context_lines=context_lines)
121
122 return {
123
124=== modified file 'loggerhead/controllers/revision_ui.py'
125--- loggerhead/controllers/revision_ui.py 2018-10-20 15:02:08 +0000
126+++ loggerhead/controllers/revision_ui.py 2020-01-19 20:20:41 +0000
127@@ -30,6 +30,7 @@
128
129 DEFAULT_LINE_COUNT_LIMIT = 3000
130
131+
132 def dq(p):
133 return urlutils.quote(urlutils.quote(p, safe=''))
134
135@@ -55,7 +56,7 @@
136 start_revid,
137 filter_file_id,
138 query)
139- except:
140+ except BaseException:
141 self.log.exception('Exception fetching changes')
142 raise HTTPServerError('Could not fetch changes')
143 # XXX: Some concern about namespace collisions. These are only stored
144@@ -114,12 +115,12 @@
145 if path in ('', '/'):
146 path = None
147
148-
149 file_changes = values['file_changes']
150 link_data = {}
151 path_to_id = {}
152 if path:
153- items = [x for x in file_changes.text_changes if x.filename == path]
154+ items = [x for x in file_changes.text_changes
155+ if x.filename == path]
156 if len(items) > 0:
157 item = items[0]
158 try:
159@@ -137,7 +138,8 @@
160 for i, item in enumerate(file_changes.text_changes):
161 item.index = i
162 link_data['diff-' + str(i)] = '%s/%s/%s' % (
163- dq(item.new_revision), dq(item.old_revision), dq(item.file_id))
164+ dq(item.new_revision), dq(item.old_revision),
165+ dq(item.filename))
166 path_to_id[item.filename] = 'diff-' + str(i)
167
168 # Directory Breadcrumbs
169
170=== modified file 'loggerhead/controllers/view_ui.py'
171--- loggerhead/controllers/view_ui.py 2019-09-18 16:49:18 +0000
172+++ loggerhead/controllers/view_ui.py 2020-01-19 20:20:41 +0000
173@@ -21,6 +21,7 @@
174
175 from breezy.errors import (
176 BinaryFile,
177+ NoSuchFile,
178 NoSuchId,
179 NoSuchRevision,
180 )
181@@ -34,7 +35,6 @@
182 HTTPBadRequest,
183 HTTPMovedPermanently,
184 HTTPNotFound,
185- HTTPServerError,
186 )
187
188 from ..controllers import TemplatedBranchView
189@@ -137,19 +137,20 @@
190 # Create breadcrumb trail for the path within the branch
191 branch_breadcrumbs = util.branch_breadcrumbs(path, tree, 'files')
192
193- if not tree.has_id(file_id):
194+ try:
195+ if tree.kind(path) == "directory":
196+ raise HTTPMovedPermanently(
197+ self._branch.context_url(['/files', revno_url, path]))
198+ except NoSuchFile:
199 raise HTTPNotFound()
200
201- if tree.kind(path) == "directory":
202- raise HTTPMovedPermanently(self._branch.context_url(['/files', revno_url, path]))
203-
204 # no navbar for revisions
205 navigation = util.Container()
206
207 return {
208- # In AnnotateUI, "annotated" is a dictionary mapping lines to changes.
209- # We exploit the fact that bool({}) is False when checking whether
210- # we're in "annotated" mode.
211+ # In AnnotateUI, "annotated" is a dictionary mapping lines to
212+ # changes. We exploit the fact that bool({}) is False when
213+ # checking whether we're in "annotated" mode.
214 'annotated': {},
215 'revno_url': revno_url,
216 'file_id': file_id,
217
218=== modified file 'loggerhead/history.py'
219--- loggerhead/history.py 2019-09-18 16:46:07 +0000
220+++ loggerhead/history.py 2020-01-19 20:20:41 +0000
221@@ -33,8 +33,8 @@
222 import re
223 import textwrap
224 import threading
225-import tarfile
226
227+from breezy import version_info as breezy_version
228 from breezy import tag
229 import breezy.branch
230 import breezy.delta
231@@ -111,6 +111,7 @@
232 def __len__(self):
233 return len(self.revid_list)
234
235+
236 class FileChangeReporter(object):
237
238 def __init__(self, old_tree, new_tree):
239@@ -122,25 +123,38 @@
240 self.old_tree = old_tree
241 self.new_tree = new_tree
242
243- def revid(self, tree, file_id):
244+ def revid(self, tree, path):
245+ if path is None:
246+ return breezy.revision.NULL_REVISION
247 try:
248- path = tree.id2path(file_id)
249- except breezy.errors.NoSuchId:
250- return b'null:'
251- else:
252 return tree.get_file_revision(path)
253-
254- def report(self, file_id, paths, versioned, renamed, modified,
255- exe_change, kind):
256+ except breezy.errors.NoSuchFile:
257+ return breezy.revision.NULL_REVISION
258+
259+ if breezy_version >= (3, 1):
260+ def report(self, paths, versioned, renamed, copied, modified,
261+ exe_change, kind):
262+ return self._report(
263+ paths, versioned, renamed, copied,
264+ modified, exe_change, kind)
265+ else:
266+ def report(self, file_id, paths, versioned, renamed, modified,
267+ exe_change, kind):
268+ return self._report(
269+ paths, versioned, renamed, None,
270+ modified, exe_change, kind)
271+
272+ def _report(self, paths, versioned, renamed, copied, modified,
273+ exe_change, kind):
274 if modified not in ('unchanged', 'kind changed'):
275 if versioned == 'removed':
276 filename = rich_filename(paths[0], kind[0])
277 else:
278 filename = rich_filename(paths[1], kind[1])
279 self.text_changes.append(util.Container(
280- filename=filename, file_id=file_id,
281- old_revision=self.revid(self.old_tree, file_id),
282- new_revision=self.revid(self.new_tree, file_id)))
283+ filename=filename,
284+ old_revision=self.revid(self.old_tree, paths[0]),
285+ new_revision=self.revid(self.new_tree, paths[1])))
286 if versioned == 'added':
287 self.added.append(util.Container(
288 filename=rich_filename(paths[1], kind), kind=kind[1]))
289@@ -157,10 +171,12 @@
290 filename=rich_filename(paths[1], kind),
291 text_modified=modified == 'modified', exe_change=exe_change))
292
293+
294 # The lru_cache is not thread-safe, so we need a lock around it for
295 # all threads.
296 rev_info_memory_cache_lock = threading.RLock()
297
298+
299 class RevInfoMemoryCache(object):
300 """A store that validates values against the revids they were stored with.
301
302
303=== modified file 'loggerhead/main.py'
304--- loggerhead/main.py 2018-10-20 17:34:46 +0000
305+++ loggerhead/main.py 2020-01-19 20:20:41 +0000
306@@ -22,7 +22,10 @@
307 import sys
308
309 from breezy.plugin import load_plugins
310-from breezy.transport import location_to_url
311+try:
312+ from breezy.location import location_to_url
313+except ImportError: # Breezy < 3.1
314+ from breezy.transport import location_to_url
315
316 from paste import httpserver
317 from paste.httpexceptions import HTTPExceptionHandler, HTTPInternalServerError
318
319=== modified file 'loggerhead/tests/test_controllers.py'
320--- loggerhead/tests/test_controllers.py 2018-10-20 16:06:44 +0000
321+++ loggerhead/tests/test_controllers.py 2020-01-19 20:20:41 +0000
322@@ -247,8 +247,8 @@
323 builder = self.make_branch_builder('branch')
324 builder.start_series()
325 rev1 = builder.build_snapshot(None, [
326- ('add', ('', b'root-id', 'directory', '')),
327- ('add', ('filename', b'f-id', 'file', b'content\n'))],
328+ ('add', ('', None, 'directory', '')),
329+ ('add', ('filename', None, 'file', b'content\n'))],
330 message="First commit.")
331 rev2 = builder.build_snapshot(None, [
332 ('modify', ('filename', b'new content\n'))])
333@@ -260,7 +260,7 @@
334 def test_get_values_smoke(self):
335 branch_app, (rev1, rev2) = self.make_branch_app_for_filediff_ui()
336 env = {'SCRIPT_NAME': '/',
337- 'PATH_INFO': '/+filediff/%s/%s/f-id' % (rev2.decode('utf-8'), rev1.decode('utf-8')),
338+ 'PATH_INFO': '/+filediff/%s/%s/filename' % (rev2.decode('utf-8'), rev1.decode('utf-8')),
339 'REQUEST_METHOD': 'GET',
340 'wsgi.url_scheme': 'http',
341 'SERVER_NAME': 'localhost',
342@@ -275,7 +275,7 @@
343 def test_json_render_smoke(self):
344 branch_app, (rev1, rev2) = self.make_branch_app_for_filediff_ui()
345 env = {'SCRIPT_NAME': '/',
346- 'PATH_INFO': '/+json/+filediff/%s/%s/f-id' % (rev2.decode('utf-8'), rev1.decode('utf-8')),
347+ 'PATH_INFO': '/+json/+filediff/%s/%s/filename' % (rev2.decode('utf-8'), rev1.decode('utf-8')),
348 'REQUEST_METHOD': 'GET',
349 'wsgi.url_scheme': 'http',
350 'SERVER_NAME': 'localhost',
351@@ -290,8 +290,8 @@
352 builder = self.make_branch_builder('branch')
353 builder.start_series()
354 revid = builder.build_snapshot(None, [
355- ('add', ('', b'root-id', 'directory', '')),
356- ('add', ('filename', b'f-id', 'file', b'content\n'))],
357+ ('add', ('', None, 'directory', '')),
358+ ('add', ('filename', None, 'file', b'content\n'))],
359 message="First commit.")
360 builder.finish_series()
361 branch = builder.get_branch()

Subscribers

People subscribed via source and target branches