Merge lp:~brz/loggerhead/breezy into lp:loggerhead

Proposed by Jelmer Vernooij
Status: Merged
Merged at revision: 494
Proposed branch: lp:~brz/loggerhead/breezy
Merge into: lp:loggerhead
Diff against target: 4166 lines (+984/-812)
66 files modified
.bzrignore (+2/-0)
.testr.conf (+4/-0)
.travis.yml (+28/-0)
MANIFEST.in (+1/-1)
Makefile (+1/-1)
NEWS (+7/-1)
README.rst (+6/-5)
__init__.py (+79/-85)
byov.conf (+23/-0)
docs/index.rst (+22/-21)
docs/loggerhead-serve.rst (+5/-5)
info.py (+0/-15)
loggerhead-serve.1 (+3/-3)
loggerhead.wsgi (+12/-7)
loggerhead/__init__.py (+2/-11)
loggerhead/apps/__init__.py (+1/-1)
loggerhead/apps/branch.py (+48/-40)
loggerhead/apps/error.py (+1/-1)
loggerhead/apps/transport.py (+11/-20)
loggerhead/changecache.py (+15/-4)
loggerhead/config.py (+2/-2)
loggerhead/controllers/__init__.py (+21/-11)
loggerhead/controllers/annotate_ui.py (+12/-7)
loggerhead/controllers/atom_ui.py (+2/-2)
loggerhead/controllers/changelog_ui.py (+8/-6)
loggerhead/controllers/diff_ui.py (+5/-5)
loggerhead/controllers/directory_ui.py (+14/-12)
loggerhead/controllers/download_ui.py (+9/-8)
loggerhead/controllers/error_ui.py (+4/-4)
loggerhead/controllers/filediff_ui.py (+32/-27)
loggerhead/controllers/inventory_ui.py (+43/-30)
loggerhead/controllers/revision_ui.py (+8/-7)
loggerhead/controllers/revlog_ui.py (+5/-3)
loggerhead/controllers/search_ui.py (+3/-3)
loggerhead/controllers/view_ui.py (+40/-32)
loggerhead/daemon.py (+2/-2)
loggerhead/exporter.py (+0/-60)
loggerhead/highlight.py (+3/-3)
loggerhead/history.py (+70/-56)
loggerhead/load_test.py (+11/-7)
loggerhead/lsprof.py (+5/-2)
loggerhead/main.py (+24/-18)
loggerhead/middleware/profile.py (+1/-1)
loggerhead/search.py (+3/-3)
loggerhead/static/css/global.css (+2/-2)
loggerhead/static/css/view.css (+1/-2)
loggerhead/templatefunctions.py (+20/-17)
loggerhead/templates/directory.pt (+23/-13)
loggerhead/templates/inventory.pt (+26/-13)
loggerhead/templates/macros.pt (+1/-1)
loggerhead/tests/__init__.py (+8/-4)
loggerhead/tests/fixtures.py (+1/-1)
loggerhead/tests/test_controllers.py (+98/-57)
loggerhead/tests/test_corners.py (+7/-5)
loggerhead/tests/test_history.py (+70/-69)
loggerhead/tests/test_http_head.py (+14/-14)
loggerhead/tests/test_load_test.py (+10/-7)
loggerhead/tests/test_revision_ui.py (+3/-2)
loggerhead/tests/test_simple.py (+27/-23)
loggerhead/tests/test_templating.py (+1/-1)
loggerhead/tests/test_util.py (+2/-2)
loggerhead/util.py (+43/-26)
loggerhead/wholehistory.py (+9/-5)
loggerhead/zptsupport.py (+9/-6)
loggerheadd (+3/-3)
setup.py (+8/-7)
To merge this branch: bzr merge lp:~brz/loggerhead/breezy
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Review via email: mp+348498@code.launchpad.net

Commit message

Switch loggerhead over to using the Breezy rather than Bazaar APIs.

Description of the change

Switch loggerhead over to using the Breezy rather than Bazaar APIs.

To post a comment you must log in.
lp:~brz/loggerhead/breezy updated
506. By Jelmer Vernooij

Add travis config.

507. By Jelmer Vernooij

Install simpletal from homepage.

508. By Jelmer Vernooij

s/Bazaar/Breezy.

509. By Jelmer Vernooij

s/Bazaar/Breezy/.

510. By Jelmer Vernooij

s/bazaar.conf/breezy.conf.

511. By Jelmer Vernooij

Fix local path serving in serve-branches.

512. By Jelmer Vernooij

Use bool_from_string.

513. By Jelmer Vernooij

Serving .bzr/ on remote branches (or readonly+ branches) works fine.

514. By Jelmer Vernooij

Determine public URL for branching from request URL.

515. By Jelmer Vernooij

Some fixes for working with git trees.

516. By Jelmer Vernooij

Fix remaining tests.

517. By Jelmer Vernooij

Use more standard breezy infrastructure.

518. By Jelmer Vernooij

Merge support for more columns.

519. By Jelmer Vernooij

Remove python path hackery.

520. By Jelmer Vernooij

Use setuptools.

521. By Jelmer Vernooij

Some python3 porting work.

522. By Jelmer Vernooij

Avoid using cStringIO.

523. By Jelmer Vernooij

Fix some more import errors.

524. By Jelmer Vernooij

Use bleach rather than simpleTAL's HTMLStructureCleaner.

525. By Jelmer Vernooij

More python3 porting work.

526. By Jelmer Vernooij

Set install_requires. I can't find an entry in pip for SimpleTAL. :(

527. By Jelmer Vernooij

Fix relative import.

528. By Jelmer Vernooij

More python3 porting work.

529. By Jelmer Vernooij

More python 3 work; down to 16 failing tests.

530. By Jelmer Vernooij

More python3 porting.

531. By Jelmer Vernooij

Fix some more tests on Python 3.

532. By Jelmer Vernooij

More python 3 fixes.

533. By Jelmer Vernooij

Finish python 3 port.

534. By Jelmer Vernooij

Run tests on python 3.

535. By Jelmer Vernooij

Add NEWS, drop info.py.

536. By Jelmer Vernooij

Rename serve-branches to loggerhead-serve.

537. By Jelmer Vernooij

Add dependency on bleach.

538. By Jelmer Vernooij

Fix loading when loggerhead is installed separately.

539. By Jelmer Vernooij

Don't unnecessarily encode paths.

540. By Jelmer Vernooij

Fix use of urllib.unquote.

541. By Jelmer Vernooij

Avoid use of file_ids.

542. By Jelmer Vernooij

Merge trunk.

543. By Jelmer Vernooij

Drop python 3.4 support on travis.

544. By Jelmer Vernooij

Don't install loggerhead.wsgi - it's not an executable.

545. By Jelmer Vernooij

Try local loggerhead first, then fall back to system one.

546. By Jelmer Vernooij

Add byov.conf.

547. By Vincent Ladeuil

Don't depend on python3-simpletal, which is not available in Ubuntu yet.

548. By Jelmer Vernooij

Install simpletal from the webz.

549. By Jelmer Vernooij

Add missing dependency on six in byov.conf.

550. By Jelmer Vernooij

Add dependency on fixtures.

551. By Jelmer Vernooij

Fix compatibility with newer versions of breezy.

Revision history for this message
Colin Watson (cjwatson) wrote :

Sorry for the long delay here; it took me a long time to get a suitable Breezy-using Launchpad branch set up so that I could test the integration.

As well as the minor comments here, https://code.launchpad.net/~cjwatson/loggerhead/more-no-file-ids/+merge/372951 is needed.

review: Approve
lp:~brz/loggerhead/breezy updated
552. By Jelmer Vernooij

Merge breezy changes.

553. By Jelmer Vernooij

Review comments.

Revision history for this message
Jelmer Vernooij (jelmer) wrote :

Can you please land? I don't have access to lp:loggerhead

Revision history for this message
Colin Watson (cjwatson) wrote :

Landed. Thanks!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2011-07-10 22:53:59 +0000
3+++ .bzrignore 2019-09-18 16:50:15 +0000
4@@ -10,3 +10,5 @@
5 tags
6 .project
7 .pydevproject
8+.testrepository
9+MANIFEST
10
11=== added file '.testr.conf'
12--- .testr.conf 1970-01-01 00:00:00 +0000
13+++ .testr.conf 2019-09-18 16:50:15 +0000
14@@ -0,0 +1,4 @@
15+[DEFAULT]
16+test_command=BRZ_PLUGINS_AT=loggerhead@`pwd` BRZ_PLUGIN_PATH=-site:-user ${BRZ:-brz} selftest -s bp.loggerhead. --subunit2 $IDOPTION $LISTOPT
17+test_id_option=--load-list $IDFILE
18+test_list_option=--list
19
20=== added file '.travis.yml'
21--- .travis.yml 1970-01-01 00:00:00 +0000
22+++ .travis.yml 2019-09-18 16:50:15 +0000
23@@ -0,0 +1,28 @@
24+language: python
25+addons:
26+ apt:
27+ update: true
28+sudo: false
29+cache: pip
30+git:
31+ depth: false
32+
33+matrix:
34+ include:
35+ - python: 2.7
36+ env: TAL_VERSION=4.3
37+ - python: 3.5
38+ env: TAL_VERSION=5.2
39+ - python: 3.6
40+ env: TAL_VERSION=5.2
41+
42+script:
43+ - python -m coverage run -p -m unittest loggerhead.tests.test_suite
44+
45+install:
46+ - sudo apt install python-all subunit python-testtools adduser libjs-yui3-min
47+ - travis_retry pip install -U setuptools
48+ - travis_retry pip install -U pip coverage codecov flake8 testtools configobj cython testscenarios six docutils python-subunit dulwich bzr+lp:brz pygments simplejson paste http://www.owlfish.com/software/simpleTAL/downloads/SimpleTAL-$TAL_VERSION.tar.gz bleach
49+
50+after_success:
51+ - codecov
52
53=== renamed file 'HACKING' => 'HACKING.rst'
54=== modified file 'MANIFEST.in'
55--- MANIFEST.in 2012-02-08 00:25:23 +0000
56+++ MANIFEST.in 2019-09-18 16:50:15 +0000
57@@ -3,7 +3,7 @@
58 include NEWS
59 include README.txt
60 include apache-loggerhead.conf
61-include bazaar.conf
62+include breezy.conf
63 include loggerhead.conf.example
64 include loggerheadd
65 include Makefile
66
67=== modified file 'Makefile'
68--- Makefile 2011-03-14 08:47:03 +0000
69+++ Makefile 2019-09-18 16:50:15 +0000
70@@ -8,4 +8,4 @@
71 rm -rf dist/
72
73 check:
74- BZR_PLUGINS_AT=loggerhead@$$(pwd) bzr selftest -s bp.loggerhead
75+ BRZ_PLUGINS_AT=loggerhead@$$(pwd) brz selftest -s bp.loggerhead
76
77=== modified file 'NEWS'
78--- NEWS 2019-06-20 16:18:17 +0000
79+++ NEWS 2019-09-18 16:50:15 +0000
80@@ -1,9 +1,15 @@
81 What's changed in loggerhead?
82 =============================
83
84-NEXT
85+1.20.0
86 ----
87
88+ - Port to Breezy (https://www.breezy-vcs.org/). (Jelmer Vernooij)
89+
90+ - Port to Python 3. (Jelmer Vernooij)
91+
92+ - Serve-branches has been renamed to 'loggerhead-serve'. (Jelmer Vernooij)
93+
94 - Fixed weird icon in file lists (e.g. revision summaries) when a file or
95 directory with a blank name was listed. (Cruz Bishop, #387337).
96
97
98=== renamed file 'README' => 'README.rst'
99--- README 2010-04-23 01:30:29 +0000
100+++ README.rst 2019-09-18 16:50:15 +0000
101@@ -4,8 +4,7 @@
102 Overview
103 --------
104
105-Loggerhead is a web viewer for Bazaar branches. Its lets users do
106-stuff like:
107+Loggerhead is a web viewer for Breezy. Its lets users do stuff like:
108
109 * navigate through branch history
110 * view the files in a given revision
111@@ -23,6 +22,8 @@
112 Licensing
113 ---------
114
115-This software is (C) Copyright Canonical Limited 2006-10 under the
116-GPL Version 2 or later. Please see the file COPYING.txt for the
117-licence details.
118+This software is licensed under the GPL Version 2 or later.
119+Please see the file COPYING.txt for the licence details.
120+
121+ (C) Copyright Canonical Limited 2006-10
122+ (C) Copyright Breezy Developers 2018
123
124=== modified file '__init__.py'
125--- __init__.py 2012-02-08 01:50:02 +0000
126+++ __init__.py 2019-09-18 16:50:15 +0000
127@@ -18,8 +18,8 @@
128 # This file allows loggerhead to be treated as a plugin for bzr.
129 #
130 # XXX: Because loggerhead already contains a loggerhead directory, much of the
131-# code is going to appear loaded at bzrlib.plugins.loggerhead.loggerhead.
132-# This seems like the easiest thing, because bzrlib wants the top-level plugin
133+# code is going to appear loaded at breezy.plugins.loggerhead.loggerhead.
134+# This seems like the easiest thing, because breezy wants the top-level plugin
135 # directory to be the module, but when it's used as a library people expect
136 # the source directory to contain a directory called loggerhead. -- mbp
137 # 20090123
138@@ -32,91 +32,85 @@
139
140 import sys
141
142-from info import (
143- bzr_plugin_version as version_info,
144- bzr_compatible_versions,
145- )
146-
147-if __name__ == 'bzrlib.plugins.loggerhead':
148- import bzrlib
149- from bzrlib.api import require_any_api
150- from bzrlib import commands
151-
152- require_any_api(bzrlib, bzr_compatible_versions)
153-
154- from bzrlib.transport import transport_server_registry
155-
156- DEFAULT_HOST = '0.0.0.0'
157- DEFAULT_PORT = 8080
158- HELP = ('Loggerhead, a web-based code viewer and server. (default port: %d)' %
159- (DEFAULT_PORT,))
160-
161- def _ensure_loggerhead_path():
162- """Ensure that you can 'import loggerhead' and get the root."""
163- # loggerhead internal code will try to 'import loggerhead', so
164- # let's put it on the path if we can't find it in the existing path
165- try:
166- import loggerhead.apps.transport
167- except ImportError:
168- import os.path, sys
169- sys.path.append(os.path.dirname(__file__))
170-
171- def serve_http(transport, host=None, port=None, inet=None):
172- # TODO: if we supported inet to pass requests in and respond to them,
173- # then it would be easier to test the full stack, but it probably
174- # means routing around paste.httpserver.serve which probably
175- # isn't testing the full stack
176- from paste.httpexceptions import HTTPExceptionHandler
177- from paste.httpserver import serve
178-
179- _ensure_loggerhead_path()
180-
181+version_info = (1, 20, 0) # Keep in sync with loggerhead/__init__.py
182+
183+import breezy
184+from breezy import commands
185+
186+from breezy.transport import transport_server_registry
187+
188+DEFAULT_HOST = '0.0.0.0'
189+DEFAULT_PORT = 8080
190+HELP = ('Loggerhead, a web-based code viewer and server. (default port: %d)' %
191+ (DEFAULT_PORT,))
192+
193+
194+def serve_http(transport, host=None, port=None, inet=None, client_timeout=None):
195+ # TODO: if we supported inet to pass requests in and respond to them,
196+ # then it would be easier to test the full stack, but it probably
197+ # means routing around paste.httpserver.serve which probably
198+ # isn't testing the full stack
199+ from paste.httpexceptions import HTTPExceptionHandler
200+ from paste.httpserver import serve
201+
202+ try:
203+ from .loggerhead.apps.http_head import HeadMiddleware
204+ from .loggerhead.apps.transport import BranchesFromTransportRoot
205+ from .loggerhead.config import LoggerheadConfig
206+ from .loggerhead.main import setup_logging
207+ except ImportError:
208 from loggerhead.apps.http_head import HeadMiddleware
209 from loggerhead.apps.transport import BranchesFromTransportRoot
210 from loggerhead.config import LoggerheadConfig
211 from loggerhead.main import setup_logging
212
213- if host is None:
214- host = DEFAULT_HOST
215- if port is None:
216- port = DEFAULT_PORT
217- argv = ['--host', host, '--port', str(port), '--', transport.base]
218- if not transport.is_readonly():
219- argv.insert(0, '--allow-writes')
220- config = LoggerheadConfig(argv)
221- setup_logging(config, init_logging=False, log_file=sys.stderr)
222- app = BranchesFromTransportRoot(transport.base, config)
223- # Bug #758618, HeadMiddleware seems to break HTTPExceptionHandler from
224- # actually sending appropriate return codes to the client. Since nobody
225- # desperately needs HeadMiddleware right now, just ignoring it.
226- # app = HeadMiddleware(app)
227- app = HTTPExceptionHandler(app)
228- serve(app, host=host, port=port)
229-
230- transport_server_registry.register('http', serve_http, help=HELP)
231-
232- class cmd_load_test_loggerhead(commands.Command):
233- """Run a load test against a live loggerhead instance.
234-
235- Pass in the name of a script file to run. See loggerhead/load_test.py
236- for a description of the file format.
237- """
238-
239- takes_args = ["filename"]
240-
241- def run(self, filename):
242- from bzrlib.plugins.loggerhead.loggerhead import load_test
243- script = load_test.run_script(filename)
244- for thread_id in sorted(script._threads):
245- worker = script._threads[thread_id][0]
246- for url, success, time in worker.stats:
247- self.outf.write(' %5.3fs %s %s\n'
248- % (time, str(success)[0], url))
249-
250- commands.register_command(cmd_load_test_loggerhead)
251-
252- def load_tests(standard_tests, module, loader):
253- _ensure_loggerhead_path()
254- standard_tests.addTests(loader.loadTestsFromModuleNames(
255- ['bzrlib.plugins.loggerhead.loggerhead.tests']))
256- return standard_tests
257+ if host is None:
258+ host = DEFAULT_HOST
259+ if port is None:
260+ port = DEFAULT_PORT
261+ argv = ['--host', host, '--port', str(port), '--', transport.base]
262+ if not transport.is_readonly():
263+ argv.insert(0, '--allow-writes')
264+ config = LoggerheadConfig(argv)
265+ setup_logging(config, init_logging=False, log_file=sys.stderr)
266+ app = BranchesFromTransportRoot(transport.base, config)
267+ # Bug #758618, HeadMiddleware seems to break HTTPExceptionHandler from
268+ # actually sending appropriate return codes to the client. Since nobody
269+ # desperately needs HeadMiddleware right now, just ignoring it.
270+ # app = HeadMiddleware(app)
271+ app = HTTPExceptionHandler(app)
272+ serve(app, host=host, port=port)
273+
274+transport_server_registry.register('http', serve_http, help=HELP)
275+
276+class cmd_load_test_loggerhead(commands.Command):
277+ """Run a load test against a live loggerhead instance.
278+
279+ Pass in the name of a script file to run. See loggerhead/load_test.py
280+ for a description of the file format.
281+ """
282+
283+ hidden = True
284+ takes_args = ["filename"]
285+
286+ def run(self, filename):
287+ try:
288+ from .loggerhead.loggerhead import load_test
289+ except ImportError:
290+ from loggerhead.loggerhead import load_test
291+ script = load_test.run_script(filename)
292+ for thread_id in sorted(script._threads):
293+ worker = script._threads[thread_id][0]
294+ for url, success, time in worker.stats:
295+ self.outf.write(' %5.3fs %s %s\n'
296+ % (time, str(success)[0], url))
297+
298+commands.register_command(cmd_load_test_loggerhead)
299+
300+def load_tests(loader, basic_tests, pattern):
301+ try:
302+ from .loggerhead.tests import test_suite
303+ except ImportError:
304+ from loggerhead.tests import test_suite
305+ basic_tests.addTest(test_suite())
306+ return basic_tests
307
308=== renamed file 'bazaar.conf' => 'breezy.conf'
309=== added file 'byov.conf'
310--- byov.conf 1970-01-01 00:00:00 +0000
311+++ byov.conf 2019-09-18 16:50:15 +0000
312@@ -0,0 +1,23 @@
313+# Use lxd containers by default
314+vm.class = lxd
315+# Start with an up to date system by default
316+vm.update = True
317+# External sources dependencies, packages are not recent enough
318+dulwich.clone = (git clone git://jelmer.uk/dulwich ../dulwich.git)
319+dulwich.install = (cd ../dulwich.git && ./setup.py install --user)
320+dulwich3.install = (cd ../dulwich.git && python3 ./setup.py install --user)
321+simpletal3.install = pip3 install http://www.owlfish.com/software/simpleTAL/downloads/SimpleTAL-5.2.tar.gz
322+
323+[loggerhead]
324+vm.release = xenial
325+brz.build_deps = gcc, debhelper, python, python-all-dev, python3-all-dev, python-configobj, python3-configobj, python-docutils, python3-docutils, python-paramiko, python3-paramiko, python-subunit, python3-subunit, python-testtools, python3-testtools, subunit, cython, cython3, python-fastimport, python-dulwich, python-six, python3-six
326+loggerhead.build_deps = python-setuptools, python3-setuptools, libjs-yui3-min, python-docutils, python3-docutils, python-pygments, python3-pygments, python-simplejson, python3-simplejson, python-paste, python3-paste, python-pastedeploy, python3-pastedeploy, python-simpletal, python-bleach, python3-bleach
327+loggerhead.test_deps = python3-fixtures, python-fixtures
328+vm.packages = {brz.build_deps}, {loggerhead.build_deps}, {loggerhead.test_deps}, bzr, python-junitxml, python3-pip
329+brz.branch = (bzr branch lp:brz ../brz-trunk)
330+brz.make = (cd ../brz-trunk && make)
331+byoci.setup.command = ({dulwich.clone} && {dulwich.install} && {brz.branch} && {brz.make})
332+byoci.tests.command = bash -o pipefail -c "bzr log -l2 && (BRZ_PLUGINS_AT=loggerhead@`pwd` BRZ_PLUGIN_PATH=-site:-user python2 ../brz-trunk/brz selftest -v --parallel=fork --subunit2 | subunit2junitxml -o ../results.xml -f | subunit2pyunit)"
333+[loggerhead-py3]
334+byoci.setup.command = ({dulwich.clone} && {dulwich3.install} && {brz.branch} && {brz.make} && {simpletal3.install})
335+byoci.tests.command = bash -o pipefail -c "bzr log -l2 && (BRZ_PLUGINS_AT=loggerhead@`pwd` BRZ_PLUGIN_PATH=-site:-user python3 ../brz-trunk/brz selftest -v --parallel=fork --subunit2 | subunit2junitxml -o ../results.xml -f | subunit2pyunit)"
336
337=== modified file 'docs/index.rst'
338--- docs/index.rst 2012-02-02 04:58:46 +0000
339+++ docs/index.rst 2019-09-18 16:50:15 +0000
340@@ -1,7 +1,7 @@
341 Loggerhead: A web viewer for ``bzr`` branches
342 ==============================================
343
344-Loggerhead is a web viewer for projects in Bazaar. It can be used to navigate
345+Loggerhead is a web viewer for projects in Breezy. It can be used to navigate
346 a branch history, annotate files, view patches, perform searches, etc.
347 Loggerhead is heavily based on `bazaar-webserve
348 <https://launchpad.net/bzr-webserve>`_, which was, in turn, loosely
349@@ -53,12 +53,12 @@
350 ----------------------------------------
351
352 After installing all the dependencies, you should be able to run
353-:command:`serve-branches` with the branch you want to serve on the
354+:command:`loggerhead-serve` with the branch you want to serve on the
355 command line:
356
357 .. code-block:: sh
358
359- ./serve-branches ~/path/to/branch
360+ ./loggerhead-serve ~/path/to/branch
361
362 By default, the script listens on port 8080, so head to
363 http://localhost:8080/ in your browser to see the branch.
364@@ -70,7 +70,7 @@
365 Loggerhead will notice and refresh, and Bazaar uses its own branch
366 locking to prevent corruption.
367
368-See :doc:`serve-branches` for all command line options.
369+See :doc:`loggerhead-serve` for all command line options.
370
371 Running Loggerhead as a Daemon
372 ------------------------------
373@@ -84,7 +84,7 @@
374 $ sudo cp ./loggerheadd /etc/init.d
375
376 2) Edit the file to configure where your Loggerhead is installed, and which
377- serve-branches options you would like.
378+ loggerhead-serve options you would like.
379
380 .. code-block:: sh
381
382@@ -101,16 +101,16 @@
383 $ sudo chkconfig --add loggerheadd
384
385
386-Using Loggerhead as a Bazaar Plugin
387-------------------------------------
388+Using Loggerhead as a Breezy Plugin
389+-----------------------------------
390
391-This branch contains experimental support for using Loggerhead as a Bazaar
392+This branch contains experimental support for using Loggerhead as a Breezy
393 plugin. To use it, place the top-level Loggerhead directory (the one
394-containing COPYING.txt) at ``~/.bazaar/plugins/loggerhead``. E.g.:
395+containing COPYING.txt) at ``~/.config/breezy/plugins/loggerhead``. E.g.:
396
397 .. code-block:: sh
398
399- $ bzr branch lp:loggerhead ~/.bazaar/plugins/loggerhead
400+ $ bzr branch lp:loggerhead ~/.config/breezy/plugins/loggerhead
401 $ cd ~/myproject
402 $ bzr serve --http
403
404@@ -118,7 +118,7 @@
405 Using a Config File
406 -------------------
407
408-To hide branches from being displayed, add to ``~/.bazaar/locations.conf``,
409+To hide branches from being displayed, add to ``~/.config/breezy/locations.conf``,
410 under the branch's section:
411
412 .. code-block:: ini
413@@ -132,7 +132,7 @@
414 Serving Loggerhead behind Apache
415 --------------------------------
416
417-If you want to view Bazaar branches from your existing Apache
418+If you want to view Breezy branches from your existing Apache
419 installation, you'll need to configure Apache to proxy certain
420 requests to Loggerhead. Adding lines like this to your Apache
421 configuration is one way to do this:
422@@ -144,7 +144,7 @@
423 ProxyPassReverse http://127.0.0.1:8080/branches/
424 </Location>
425
426-If Paste Deploy is installed, the :command:`serve-branches` script can be
427+If Paste Deploy is installed, the :command:`loggerhead-serve` script can be
428 run behind a proxy at the root of a site, but if you're running it at
429 some path into the site, you'll need to specify it using
430 ``--prefix=/some_path``.
431@@ -154,8 +154,8 @@
432
433 A second method for using Loggerhead with apache is to have apache itself
434 execute Loggerhead via mod_wsgi. You need to add configuration for apache and
435-for bazaar to make this work. Example config files are in the Loggerhead doc
436-directory as apache-loggerhead.conf and bazaar.conf. You can copy them into
437+for breezy to make this work. Example config files are in the Loggerhead doc
438+directory as apache-loggerhead.conf and breezy.conf. You can copy them into
439 place and use them as a starting point following these directions:
440
441 1) Install mod_wsgi. On Ubuntu and other Debian derived distros::
442@@ -166,19 +166,20 @@
443
444 su -c yum install mod_wsgi
445
446-2) Copy the bazaar.conf file where apache will find it (May be done for you if
447+2) Copy the breezy.conf file where apache will find it (May be done for you if
448 you installed Loggerhead from a distribution package)::
449
450 # install -d -o apache -g apache -m 0755 /etc/loggerhead
451- # cp -p /usr/share/doc/loggerhead*/bazaar.conf /etc/loggerhead/
452- # ln -s /etc/loggerhead /var/www/.bazaar
453+ # cp -p /usr/share/doc/loggerhead*/breezy.conf /etc/loggerhead/
454+ # mkdir -p /var/www/.config
455+ # ln -s /etc/loggerhead /var/www/.config/breezy
456
457 3) Create the cache directory (May be done for you if you installed Loggerhead
458 from a distribution package)::
459
460 # install -d -o apache -g apache -m 0700 /var/cache/loggerhead/
461
462-4) Edit /etc/loggerhead/bazaar.conf. You need to set http_root_dir to the filesystem
463+4) Edit /etc/loggerhead/breezy.conf. You need to set http_root_dir to the filesystem
464 path that you will find your bzr branches under. Note that normal
465 directories under that path will also be visible in Loggerhead.
466
467@@ -188,7 +189,7 @@
468
469 6) Edit /etc/httpd/conf.d/loggerhead.conf to point to the url you desire to
470 serve Loggerhead on. This should match with the setting for
471- http_user_prefix in bazaar.conf
472+ http_user_prefix in breezy.conf
473
474 7) Restart apache and you should be able to start browsing
475
476@@ -220,7 +221,7 @@
477 .. toctree::
478 :maxdepth: 2
479
480- serve-branches
481+ loggerhead-serve
482
483
484 Support
485
486=== renamed file 'docs/serve-branches.rst' => 'docs/loggerhead-serve.rst'
487--- docs/serve-branches.rst 2010-03-25 10:32:47 +0000
488+++ docs/loggerhead-serve.rst 2019-09-18 16:50:15 +0000
489@@ -1,17 +1,17 @@
490-:command:`serve-branches`
491+:command:`loggerhead-serve`
492 =========================
493
494-The :command:`serve-branches` script runs a standalone Loggerhead server in
495+The :command:`loggerhead-serve` script runs a standalone Loggerhead server in
496 the foreground.
497
498-.. program:: serve-branches
499+.. program:: loggerhead-serve
500
501 Usage
502 -----
503
504 .. code-block:: sh
505
506- serve-branches [OPTIONS] <target directory>
507+ loggerhead-serve [OPTIONS] <target directory>
508
509 Options
510 -------
511@@ -76,7 +76,7 @@
512
513 .. cmdoption:: --allow-writes
514
515- Allow writing to the Bazaar server.
516+ Allow writing to the Breezy server.
517
518 Setting this option keeps Loggerhead from adding a 'readonly+' prefix
519 to the base URL of the branch. The only effect of suppressing this prefix
520
521=== removed file 'info.py'
522--- info.py 2011-11-23 08:33:12 +0000
523+++ info.py 1970-01-01 00:00:00 +0000
524@@ -1,15 +0,0 @@
525-#!/usr/bin/env python
526-# API Info for loggerhead
527-
528-bzr_plugin_name = "loggerhead"
529-
530-bzr_plugin_version = (1, 18, 1) # Keep in sync with loggerhead/__init__.py
531-
532-bzr_compatible_versions = [
533- (1, 17, 0), (1, 18, 0), (2, 0, 0), (2, 1, 0), (2, 2, 0), (2, 3, 0),
534- (2, 4, 0), (2, 5, 0),
535- ]
536-
537-bzr_minimum_version = bzr_compatible_versions[0]
538-
539-bzr_maximum_version = bzr_compatible_versions[-1]
540
541=== renamed file 'serve-branches' => 'loggerhead-serve'
542=== renamed file 'serve-branches.1' => 'loggerhead-serve.1'
543--- serve-branches.1 2008-09-10 23:12:59 +0000
544+++ loggerhead-serve.1 2019-09-18 16:50:15 +0000
545@@ -2,14 +2,14 @@
546 .SH NAME
547 loggerhead \- run a loggerhead server
548 .SH SYNOPSIS
549-.B serve-branches
550+.B loggerhead-serve
551 [\fIoptions\fR] \fI<path>\fR
552 .SH DESCRIPTION
553-Loggerhead is a web viewer for projects in bazaar. It can be used to navigate
554+Loggerhead is a web viewer for projects in Breezy. It can be used to navigate
555 a branch history, annotate files, view patches, perform searches, etc. It's
556 heavily based on bazaar-webserve, which is itself based on hgweb for Mercurial.
557 .PP
558-The serve-branches command runs a standalone loggerhead server in the foreground.
559+The loggerhead-serve command runs a standalone loggerhead server in the foreground.
560 .SH OPTIONS
561 .TP
562 \fB\-h\fR, \fB\-\-help\fR
563
564=== modified file 'loggerhead.wsgi'
565--- loggerhead.wsgi 2012-02-08 01:50:02 +0000
566+++ loggerhead.wsgi 2019-09-18 16:50:15 +0000
567@@ -23,9 +23,10 @@
568 from loggerhead.apps.transport import BranchesFromTransportRoot
569 from loggerhead.apps.error import ErrorHandlerApp
570 from loggerhead.config import LoggerheadConfig
571-from bzrlib import config as bzrconfig
572+from breezy import config as bzrconfig
573+from breezy.sixish import PY3
574 from paste.deploy.config import PrefixMiddleware
575-from bzrlib.plugin import load_plugins
576+from breezy.plugin import load_plugins
577
578 class NotConfiguredError(Exception):
579 pass
580@@ -36,14 +37,18 @@
581 prefix = config.get_option('user_prefix') or ''
582 # Note we could use LoggerheadConfig here if it didn't fail when a
583 # config option is not also a commandline option
584-root_dir = bzrconfig.GlobalConfig().get_user_option('http_root_dir')
585-if not root_dir:
586- raise NotConfiguredError('You must have a ~/.bazaar/bazaar.conf file for'
587+root_dir = os.getenv('LOGGERHEAD_ROOT_DIR')
588+if not root_dir:
589+ root_dir = bzrconfig.GlobalConfig().get_user_option('http_root_dir')
590+if not root_dir:
591+ raise NotConfiguredError('You must set LOGGERHEAD_ROOT_DIR or have '
592+ 'a ~/.config/breezy/breezy.conf file for'
593 ' %(user)s with http_root_dir set to the base directory you want'
594 ' to serve bazaar repositories from' %
595 {'user': pwd.getpwuid(os.geteuid()).pw_name})
596-prefix = prefix.encode('utf-8', 'ignore')
597-root_dir = root_dir.encode('utf-8', 'ignore')
598+if not PY3:
599+ prefix = prefix.encode('utf-8', 'ignore')
600+ root_dir = root_dir.encode('utf-8', 'ignore')
601 app = BranchesFromTransportRoot(root_dir, config)
602 app = PrefixMiddleware(app, prefix=prefix)
603 app = HTTPExceptionHandler(app)
604
605=== modified file 'loggerhead/__init__.py'
606--- loggerhead/__init__.py 2012-09-11 20:49:32 +0000
607+++ loggerhead/__init__.py 2019-09-18 16:50:15 +0000
608@@ -22,9 +22,9 @@
609
610 import pkg_resources
611
612-__version__ = '1.18.2' # Keep in sync with ../info.py.
613+__version__ = '1.20.0' # Keep in sync with ../__init__.py.
614 __revision__ = None
615-required_bzrlib = (1, 17)
616+required_breezy = (3, 0)
617
618 pkg_resources.get_distribution('Paste>=1.6')
619 try:
620@@ -32,12 +32,3 @@
621 except pkg_resources.DistributionNotFound:
622 # No paste.deploy is OK, but an old paste.deploy is bad.
623 pass
624-
625-try:
626- from bzrlib.branch import Branch
627- branch = Branch.open('./');
628-
629- __revision__ = branch.revno()
630-
631-except:
632- pass
633
634=== modified file 'loggerhead/apps/__init__.py'
635--- loggerhead/apps/__init__.py 2010-04-30 21:30:18 +0000
636+++ loggerhead/apps/__init__.py 2019-09-18 16:50:15 +0000
637@@ -4,7 +4,7 @@
638
639 from paste import urlparser, fileapp
640
641-from loggerhead.util import convert_file_errors
642+from ..util import convert_file_errors
643
644 static = os.path.join(
645 os.path.dirname(os.path.dirname(__file__)), 'static')
646
647=== modified file 'loggerhead/apps/branch.py'
648--- loggerhead/apps/branch.py 2012-02-08 01:50:02 +0000
649+++ loggerhead/apps/branch.py 2019-09-18 16:50:15 +0000
650@@ -17,31 +17,33 @@
651 """The WSGI application for serving a Bazaar branch."""
652
653 import logging
654-import urllib
655 import sys
656+import wsgiref.util
657
658-import bzrlib.branch
659-import bzrlib.errors
660-from bzrlib.hooks import Hooks
661-import bzrlib.lru_cache
662+import breezy.branch
663+import breezy.errors
664+from breezy.hooks import Hooks
665+import breezy.lru_cache
666+from breezy.sixish import viewitems
667+from breezy import urlutils
668
669 from paste import request
670 from paste import httpexceptions
671
672-from loggerhead.apps import static_app
673-from loggerhead.controllers.annotate_ui import AnnotateUI
674-from loggerhead.controllers.view_ui import ViewUI
675-from loggerhead.controllers.atom_ui import AtomUI
676-from loggerhead.controllers.changelog_ui import ChangeLogUI
677-from loggerhead.controllers.diff_ui import DiffUI
678-from loggerhead.controllers.download_ui import DownloadUI, DownloadTarballUI
679-from loggerhead.controllers.filediff_ui import FileDiffUI
680-from loggerhead.controllers.inventory_ui import InventoryUI
681-from loggerhead.controllers.revision_ui import RevisionUI
682-from loggerhead.controllers.revlog_ui import RevLogUI
683-from loggerhead.controllers.search_ui import SearchUI
684-from loggerhead.history import History
685-from loggerhead import util
686+from ..apps import static_app
687+from ..controllers.annotate_ui import AnnotateUI
688+from ..controllers.view_ui import ViewUI
689+from ..controllers.atom_ui import AtomUI
690+from ..controllers.changelog_ui import ChangeLogUI
691+from ..controllers.diff_ui import DiffUI
692+from ..controllers.download_ui import DownloadUI, DownloadTarballUI
693+from ..controllers.filediff_ui import FileDiffUI
694+from ..controllers.inventory_ui import InventoryUI
695+from ..controllers.revision_ui import RevisionUI
696+from ..controllers.revlog_ui import RevLogUI
697+from ..controllers.search_ui import SearchUI
698+from ..history import History
699+from .. import util
700
701
702 _DEFAULT = object()
703@@ -63,7 +65,7 @@
704 self.branch_link = branch_link # Currently only used in Launchpad
705 self.log = logging.getLogger('loggerhead.%s' % (friendly_name,))
706 if graph_cache is None:
707- graph_cache = bzrlib.lru_cache.LRUCache(10)
708+ graph_cache = breezy.lru_cache.LRUCache(10)
709 self.graph_cache = graph_cache
710 self.is_root = is_root
711 self.served_url = served_url
712@@ -84,7 +86,7 @@
713 # Only import the cache if we're going to use it.
714 # This makes sqlite optional
715 try:
716- from loggerhead.changecache import RevInfoDiskCache
717+ from ..changecache import RevInfoDiskCache
718 except ImportError:
719 self.log.debug("Couldn't load python-sqlite,"
720 " continuing without using a cache")
721@@ -92,18 +94,32 @@
722 revinfo_disk_cache = RevInfoDiskCache(cache_path)
723 return History(
724 self.branch, self.graph_cache,
725- revinfo_disk_cache=revinfo_disk_cache, cache_key=self.friendly_name)
726+ revinfo_disk_cache=revinfo_disk_cache,
727+ cache_key=(self.friendly_name.encode('utf-8') if self.friendly_name else None))
728+
729+ # Before the addition of this method, clicking to sort by date from
730+ # within a branch caused a jump up to the top of that branch.
731+ def sort_url(self, *args, **kw):
732+ if isinstance(args[0], list):
733+ args = args[0]
734+ qs = []
735+ for k, v in viewitems(kw):
736+ if v is not None:
737+ qs.append('%s=%s' % (k, urlutils.quote(v)))
738+ qs = '&'.join(qs)
739+ path_info = self._path_info.strip('/').split('?')[0]
740+ path_info += '?' + qs
741+ return self._url_base + '/' + path_info
742
743 def url(self, *args, **kw):
744 if isinstance(args[0], list):
745 args = args[0]
746 qs = []
747- for k, v in kw.iteritems():
748+ for k, v in viewitems(kw):
749 if v is not None:
750- qs.append('%s=%s' % (k, urllib.quote(v)))
751+ qs.append('%s=%s' % (k, urlutils.quote(v)))
752 qs = '&'.join(qs)
753- path_info = urllib.quote(
754- unicode('/'.join(args)).encode('utf-8'), safe='/~:')
755+ path_info = urlutils.quote('/'.join(args), safe='/~:')
756 if qs:
757 path_info += '?' + qs
758 return self._url_base + path_info
759@@ -147,14 +163,15 @@
760 return change.date
761
762 def public_branch_url(self):
763- return self.branch.get_config().get_user_option('public_branch')
764+ return self.branch.get_public_branch()
765
766 def lookup_app(self, environ):
767 # Check again if the branch is blocked from being served, this is
768 # mostly for tests. It's already checked in apps/transport.py
769- if self.branch.get_config().get_user_option('http_serve') == 'False':
770+ if not self.branch.get_config().get_user_option_as_bool('http_serve', default=True):
771 raise httpexceptions.HTTPNotFound()
772 self._url_base = environ['SCRIPT_NAME']
773+ self._path_info = environ['PATH_INFO']
774 self._static_url_base = environ.get('loggerhead.static.url')
775 if self._static_url_base is None:
776 self._static_url_base = self._url_base
777@@ -164,13 +181,7 @@
778 if public_branch is not None:
779 self.served_url = public_branch
780 else:
781- # Loggerhead only supports serving .bzr/ on local branches, so
782- # we shouldn't suggest something that won't work.
783- try:
784- util.local_path_from_url(self.branch.base)
785- self.served_url = self.url([])
786- except bzrlib.errors.InvalidURL:
787- self.served_url = None
788+ self.served_url = wsgiref.util.application_uri(environ)
789 for hook in self.hooks['controller']:
790 controller = hook(self, environ)
791 if controller is not None:
792@@ -190,8 +201,7 @@
793 raise httpexceptions.HTTPNotFound()
794
795 def app(self, environ, start_response):
796- self.branch.lock_read()
797- try:
798+ with self.branch.lock_read():
799 try:
800 c = self.lookup_app(environ)
801 return c(environ, start_response)
802@@ -199,8 +209,6 @@
803 environ['exc_info'] = sys.exc_info()
804 environ['branch'] = self
805 raise
806- finally:
807- self.branch.unlock()
808
809
810 class BranchWSGIAppHooks(Hooks):
811@@ -210,7 +218,7 @@
812 def __init__(self):
813 """Create the default hooks.
814 """
815- Hooks.__init__(self, "bzrlib.plugins.loggerhead.apps.branch",
816+ Hooks.__init__(self, "breezy.plugins.loggerhead.apps.branch",
817 "BranchWSGIApp.hooks")
818 self.add_hook('controller',
819 "Invoked when looking for the controller to use for a "
820
821=== modified file 'loggerhead/apps/error.py'
822--- loggerhead/apps/error.py 2012-02-08 01:50:02 +0000
823+++ loggerhead/apps/error.py 2019-09-18 16:50:15 +0000
824@@ -15,7 +15,7 @@
825 # Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
826 #
827
828-from loggerhead.controllers.error_ui import ErrorUI
829+from ..controllers.error_ui import ErrorUI
830
831
832 class ErrorHandlerApp(object):
833
834=== modified file 'loggerhead/apps/transport.py'
835--- loggerhead/apps/transport.py 2012-02-08 01:50:02 +0000
836+++ loggerhead/apps/transport.py 2019-09-18 16:50:15 +0000
837@@ -18,28 +18,22 @@
838
839 import threading
840
841-from bzrlib import branch, errors, lru_cache, urlutils
842-from bzrlib.config import LocationConfig
843-from bzrlib.smart import request
844-from bzrlib.transport import get_transport
845-from bzrlib.transport.http import wsgi
846+from breezy import branch, errors, lru_cache, urlutils
847+from breezy.config import LocationConfig
848+from breezy.bzr.smart import request
849+import breezy.ui
850+from breezy.transport import get_transport
851+from breezy.transport.http import wsgi
852
853 from paste.request import path_info_pop
854 from paste import httpexceptions
855 from paste import urlparser
856
857-from loggerhead import util
858-from loggerhead.apps.branch import BranchWSGIApp
859-from loggerhead.apps import favicon_app, robots_app, static_app
860-from loggerhead.controllers.directory_ui import DirectoryUI
861+from .. import util
862+from ..apps.branch import BranchWSGIApp
863+from ..apps import favicon_app, robots_app, static_app
864+from ..controllers.directory_ui import DirectoryUI
865
866-# TODO: Use bzrlib.ui.bool_from_string(), added in bzr 1.18
867-_bools = {
868- 'yes': True, 'no': False,
869- 'on': True, 'off': False,
870- '1': True, '0': False,
871- 'true': True, 'false': False,
872- }
873
874 class BranchesFromTransportServer(object):
875
876@@ -103,10 +97,7 @@
877 return urlparser.make_static(None, path)
878
879 def check_serveable(self, config):
880- value = config.get_user_option('http_serve')
881- if value is None:
882- return
883- elif not _bools.get(value.lower(), True):
884+ if not config.get_user_option_as_bool('http_serve', default=True):
885 raise httpexceptions.HTTPNotFound()
886
887 def __call__(self, environ, start_response):
888
889=== modified file 'loggerhead/changecache.py'
890--- loggerhead/changecache.py 2012-02-08 01:50:02 +0000
891+++ loggerhead/changecache.py 2019-09-18 16:50:15 +0000
892@@ -26,7 +26,10 @@
893 cached a change, it's good forever.
894 """
895
896-import cPickle
897+try:
898+ import cPickle as pickle
899+except ImportError: # Python >= 3
900+ import pickle
901 import marshal
902 import os
903 import tempfile
904@@ -73,10 +76,10 @@
905 con.close()
906
907 def _serialize(self, obj):
908- return dbapi2.Binary(cPickle.dumps(obj, protocol=2))
909+ return dbapi2.Binary(pickle.dumps(obj, protocol=2))
910
911 def _unserialize(self, data):
912- return cPickle.loads(str(data))
913+ return pickle.loads(str(data))
914
915 def get(self, revid):
916 self.cursor.execute(
917@@ -115,6 +118,10 @@
918 self.cursor = self.connection.cursor()
919
920 def get(self, key, revid):
921+ if not isinstance(key, bytes):
922+ raise TypeError(key)
923+ if not isinstance(revid, bytes):
924+ raise TypeError(revid)
925 self.cursor.execute(
926 "select revid, data from data where key = ?", (dbapi2.Binary(key),))
927 row = self.cursor.fetchone()
928@@ -126,13 +133,17 @@
929 return marshal.loads(zlib.decompress(row[1]))
930
931 def set(self, key, revid, data):
932+ if not isinstance(key, bytes):
933+ raise TypeError(key)
934+ if not isinstance(revid, bytes):
935+ raise TypeError(revid)
936 try:
937 self.cursor.execute(
938 'delete from data where key = ?', (dbapi2.Binary(key), ))
939 blob = zlib.compress(marshal.dumps(data))
940 self.cursor.execute(
941 "insert into data (key, revid, data) values (?, ?, ?)",
942- map(dbapi2.Binary, [key, revid, blob]))
943+ list(map(dbapi2.Binary, [key, revid, blob])))
944 self.connection.commit()
945 except dbapi2.IntegrityError:
946 # If another thread or process attempted to set the same key, we
947
948=== modified file 'loggerhead/config.py'
949--- loggerhead/config.py 2011-07-07 19:09:11 +0000
950+++ loggerhead/config.py 2019-09-18 16:50:15 +0000
951@@ -17,7 +17,7 @@
952 import sys
953 import tempfile
954
955-from bzrlib import config
956+from breezy import config
957
958 _temporary_sql_dir = None
959
960@@ -120,7 +120,7 @@
961
962 def get_option(self, option):
963 """Get the value for the config option, either
964- from ~/.bazaar/bazaar.conf or from the command line.
965+ from ~/.config/breezy/breezy.conf or from the command line.
966 All loggerhead-specific settings start with 'http_'
967 """
968 global_config = config.GlobalConfig().get_user_option('http_'+option)
969
970=== modified file 'loggerhead/controllers/__init__.py'
971--- loggerhead/controllers/__init__.py 2012-02-08 01:50:02 +0000
972+++ loggerhead/controllers/__init__.py 2019-09-18 16:50:15 +0000
973@@ -17,16 +17,19 @@
974 # along with this program; if not, write to the Free Software
975 # Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
976
977-import bzrlib.errors
978+import breezy.errors
979 import simplejson
980 import time
981
982+from breezy import osutils
983+
984 from paste.httpexceptions import HTTPNotFound, HTTPSeeOther
985 from paste.request import path_info_pop, parse_querystring
986
987-from loggerhead import util
988-from loggerhead.templatefunctions import templatefunctions
989-from loggerhead.zptsupport import load_template
990+from .. import templates
991+from .. import util
992+from ..templatefunctions import templatefunctions
993+from ..zptsupport import load_template
994
995
996 class BufferingWriter(object):
997@@ -39,7 +42,7 @@
998 self.buf_limit = buf_limit
999
1000 def flush(self):
1001- self.writefunc(''.join(self.buf))
1002+ self.writefunc(b''.join(self.buf))
1003 self.buf = []
1004 self.buflen = 0
1005
1006@@ -53,7 +56,7 @@
1007
1008 class TemplatedBranchView(object):
1009
1010- template_path = None
1011+ template_name = None
1012 supports_json = False
1013
1014 def __init__(self, branch, history_callable):
1015@@ -81,7 +84,10 @@
1016
1017 path = None
1018 if len(args) > 1:
1019- path = unicode('/'.join(args[1:]), 'utf-8')
1020+ path = '/'.join(args[1:])
1021+ if isinstance(path, bytes):
1022+ # Python 2
1023+ path = path.decode('utf-8')
1024 self.args = args
1025 self.kwargs = kwargs
1026 return path
1027@@ -109,7 +115,7 @@
1028 headers['Content-Type'] = 'application/json'
1029 elif 'Content-Type' not in headers:
1030 headers['Content-Type'] = 'text/html'
1031- writer = start_response("200 OK", headers.items())
1032+ writer = start_response("200 OK", list(headers.items()))
1033 if environ.get('REQUEST_METHOD') == 'HEAD':
1034 # No content for a HEAD request
1035 return []
1036@@ -117,10 +123,11 @@
1037 w = BufferingWriter(writer, 8192)
1038 if environ.get('loggerhead.as_json'):
1039 w.write(simplejson.dumps(values,
1040- default=util.convert_to_json_ready))
1041+ default=util.convert_to_json_ready).encode('utf-8'))
1042 else:
1043 self.add_template_values(values)
1044- template = load_template(self.template_path)
1045+ template = load_template(
1046+ '%s.%s' % (templates.__name__, self.template_name))
1047 template.expand_into(w, **values)
1048 w.flush()
1049 self.log.info(
1050@@ -135,8 +142,11 @@
1051 if len(self.args) > 0 and self.args != ['']:
1052 try:
1053 revid = h.fix_revid(self.args[0])
1054- except bzrlib.errors.NoSuchRevision:
1055+ except breezy.errors.NoSuchRevision:
1056 raise HTTPNotFound;
1057+ assert isinstance(revid, bytes)
1058 else:
1059 revid = h.last_revid
1060+ if revid is not None and not isinstance(revid, bytes):
1061+ raise TypeError(revid)
1062 return revid
1063
1064=== modified file 'loggerhead/controllers/annotate_ui.py'
1065--- loggerhead/controllers/annotate_ui.py 2012-02-08 01:50:02 +0000
1066+++ loggerhead/controllers/annotate_ui.py 2019-09-18 16:50:15 +0000
1067@@ -18,17 +18,22 @@
1068
1069 import itertools
1070
1071-from loggerhead.controllers.view_ui import ViewUI
1072-from loggerhead import util
1073+from ..controllers.view_ui import ViewUI
1074+from .. import util
1075
1076 class AnnotateUI(ViewUI):
1077
1078 def annotate_file(self, info):
1079 file_id = info['file_id']
1080 revid = info['change'].revid
1081-
1082+ if not isinstance(file_id, bytes):
1083+ raise TypeError(file_id)
1084+ if not isinstance(revid, bytes):
1085+ raise TypeError(revid)
1086+ path = self._history.get_path(revid, file_id)
1087+
1088 tree = self.tree_for(file_id, revid)
1089-
1090+
1091 change_cache = {}
1092 last_line_revid = None
1093 last_lineno = None
1094@@ -37,7 +42,7 @@
1095 revisions = {}
1096
1097 lineno = 0
1098- for (line_revid, text), lineno in zip(tree.annotate_iter(file_id), itertools.count(1)):
1099+ for (line_revid, text), lineno in zip(tree.annotate_iter(path, file_id), itertools.count(1)):
1100 if line_revid != last_line_revid:
1101 last_line_revid = line_revid
1102
1103@@ -70,9 +75,9 @@
1104 revisions[last_lineno].revspan = lineno - last_lineno + 1
1105
1106 return revisions
1107-
1108+
1109 def get_values(self, path, kwargs, headers):
1110 values = super(AnnotateUI, self).get_values(path, kwargs, headers)
1111 values['annotated'] = self.annotate_file(values)
1112-
1113+
1114 return values
1115
1116=== modified file 'loggerhead/controllers/atom_ui.py'
1117--- loggerhead/controllers/atom_ui.py 2012-02-08 01:50:02 +0000
1118+++ loggerhead/controllers/atom_ui.py 2019-09-18 16:50:15 +0000
1119@@ -17,12 +17,12 @@
1120 # Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
1121 #
1122
1123-from loggerhead.controllers import TemplatedBranchView
1124+from ..controllers import TemplatedBranchView
1125
1126
1127 class AtomUI (TemplatedBranchView):
1128
1129- template_path = 'loggerhead.templates.atom'
1130+ template_name = 'atom'
1131
1132 def get_values(self, path, kwargs, headers):
1133 history = self._history
1134
1135=== modified file 'loggerhead/controllers/changelog_ui.py'
1136--- loggerhead/controllers/changelog_ui.py 2012-02-08 01:50:02 +0000
1137+++ loggerhead/controllers/changelog_ui.py 2019-09-18 16:50:15 +0000
1138@@ -18,24 +18,26 @@
1139 # Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
1140 #
1141
1142-import urllib
1143-
1144 import simplejson
1145
1146 from paste.httpexceptions import HTTPServerError
1147
1148-from loggerhead import util
1149-from loggerhead.controllers import TemplatedBranchView
1150+from breezy import osutils, urlutils
1151+
1152+from .. import util
1153+from ..controllers import TemplatedBranchView
1154
1155
1156 class ChangeLogUI(TemplatedBranchView):
1157
1158- template_path = 'loggerhead.templates.changelog'
1159+ template_name = 'changelog'
1160
1161 def get_values(self, path, kwargs, headers):
1162 history = self._history
1163 revid = self.get_revid()
1164 filter_file_id = kwargs.get('filter_file_id', None)
1165+ if filter_file_id is not None:
1166+ filter_file_id = urlutils.unquote_to_bytes(osutils.safe_utf8(filter_file_id))
1167 query = kwargs.get('q', None)
1168 start_revid = history.fix_revid(kwargs.get('start_revid', None))
1169 orig_start_revid = start_revid
1170@@ -67,7 +69,7 @@
1171 data = {}
1172 for i, c in enumerate(changes):
1173 c.index = i
1174- data[str(i)] = urllib.quote(urllib.quote(c.revid, safe=''))
1175+ data[str(i)] = urlutils.quote(urlutils.quote_from_bytes(c.revid, safe=''))
1176 except:
1177 self.log.exception('Exception fetching changes')
1178 raise HTTPServerError('Could not fetch changes')
1179
1180=== modified file 'loggerhead/controllers/diff_ui.py'
1181--- loggerhead/controllers/diff_ui.py 2012-07-31 20:25:42 +0000
1182+++ loggerhead/controllers/diff_ui.py 2019-09-18 16:50:15 +0000
1183@@ -16,15 +16,15 @@
1184 # Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
1185 #
1186
1187-from cStringIO import StringIO
1188+from io import BytesIO
1189 import time
1190
1191 from paste.request import path_info_pop, parse_querystring
1192
1193-from bzrlib.diff import show_diff_trees
1194-from bzrlib.revision import NULL_REVISION
1195+from breezy.diff import show_diff_trees
1196+from breezy.revision import NULL_REVISION
1197
1198-from loggerhead.controllers import TemplatedBranchView
1199+from ..controllers import TemplatedBranchView
1200
1201
1202 class DiffUI(TemplatedBranchView):
1203@@ -71,7 +71,7 @@
1204 revtree1 = repo.revision_tree(revid_to)
1205 revtree2 = repo.revision_tree(revid_from)
1206
1207- diff_content_stream = StringIO()
1208+ diff_content_stream = BytesIO()
1209 show_diff_trees(revtree1, revtree2, diff_content_stream,
1210 old_label='', new_label='', context=numlines)
1211
1212
1213=== modified file 'loggerhead/controllers/directory_ui.py'
1214--- loggerhead/controllers/directory_ui.py 2012-02-08 01:50:02 +0000
1215+++ loggerhead/controllers/directory_ui.py 2019-09-18 16:50:15 +0000
1216@@ -20,33 +20,33 @@
1217 import logging
1218 import stat
1219
1220-from bzrlib import branch, errors
1221+from breezy import branch, errors, urlutils
1222
1223-from loggerhead import util
1224-from loggerhead.controllers import TemplatedBranchView
1225+from .. import util
1226+from ..controllers import TemplatedBranchView
1227
1228
1229 class DirEntry(object):
1230
1231 def __init__(self, dirname, parity, branch):
1232- self.dirname = dirname
1233+ self.dirname = urlutils.unquote(dirname)
1234 self.parity = parity
1235 self.branch = branch
1236 if branch is not None:
1237 # If a branch is empty, bzr raises an exception when trying this
1238 try:
1239- self.last_change = datetime.datetime.utcfromtimestamp(
1240- branch.repository.get_revision(
1241- branch.last_revision()).timestamp)
1242- except:
1243- self.last_change = None
1244+ self.last_revision = branch.repository.get_revision(branch.last_revision())
1245+ self.last_change_time = datetime.datetime.utcfromtimestamp(self.last_revision.timestamp)
1246+ except errors.NoSuchRevision:
1247+ self.last_revision = None
1248+ self.last_change_time = None
1249
1250
1251 class DirectoryUI(TemplatedBranchView):
1252 """
1253 """
1254
1255- template_path = 'loggerhead.templates.directory'
1256+ template_name = 'directory'
1257
1258 def __init__(self, static_url_base, transport, name):
1259
1260@@ -72,15 +72,17 @@
1261 for d in listing:
1262 try:
1263 b = branch.Branch.open_from_transport(self.transport.clone(d))
1264- if b.get_config().get_user_option('http_serve') == 'False':
1265- continue
1266 except:
1267+ # TODO(jelmer): don't catch all exceptions here
1268 try:
1269 if not stat.S_ISDIR(self.transport.stat(d).st_mode):
1270 continue
1271 except errors.NoSuchFile:
1272 continue
1273 b = None
1274+ else:
1275+ if not b.get_config().get_user_option_as_bool('http_serve', default=True):
1276+ continue
1277 dirs.append(DirEntry(d, parity, b))
1278 parity = 1 - parity
1279 # Create breadcrumb trail
1280
1281=== modified file 'loggerhead/controllers/download_ui.py'
1282--- loggerhead/controllers/download_ui.py 2012-03-22 14:09:52 +0000
1283+++ loggerhead/controllers/download_ui.py 2019-09-18 16:50:15 +0000
1284@@ -21,15 +21,15 @@
1285 import mimetypes
1286 import urllib
1287
1288-from bzrlib.errors import (
1289+from breezy.errors import (
1290 NoSuchId,
1291 NoSuchRevision,
1292 )
1293+from breezy import osutils, urlutils
1294 from paste import httpexceptions
1295 from paste.request import path_info_pop
1296
1297-from loggerhead.controllers import TemplatedBranchView
1298-from loggerhead.exporter import export_archive
1299+from ..controllers import TemplatedBranchView
1300
1301 log = logging.getLogger("loggerhead.controllers")
1302
1303@@ -38,7 +38,7 @@
1304
1305 def encode_filename(self, filename):
1306
1307- return urllib.quote(filename.encode('utf-8'))
1308+ return urlutils.escape(filename)
1309
1310 def get_args(self, environ):
1311 args = []
1312@@ -57,7 +57,7 @@
1313 raise httpexceptions.HTTPMovedPermanently(
1314 self._branch.absolute_url('/changes'))
1315 revid = h.fix_revid(args[0])
1316- file_id = args[1]
1317+ file_id = urlutils.unquote_to_bytes(osutils.safe_utf8(args[1]))
1318 try:
1319 path, filename, content = h.get_file(file_id, revid)
1320 except (NoSuchId, NoSuchRevision):
1321@@ -102,12 +102,13 @@
1322 # TODO: Perhaps set the tarball suggested mtime to the revision
1323 # mtime.
1324 root = self._branch.friendly_name or 'branch'
1325- encoded_filename = self.encode_filename(
1326- root + version_part + '.' + archive_format)
1327+ filename = root + version_part + '.' + archive_format
1328+ encoded_filename = self.encode_filename(filename)
1329 headers = [
1330 ('Content-Type', 'application/octet-stream'),
1331 ('Content-Disposition',
1332 "attachment; filename*=utf-8''%s" % (encoded_filename,)),
1333 ]
1334 start_response('200 OK', headers)
1335- return export_archive(history, root, revid, archive_format)
1336+ tree = history._branch.repository.revision_tree(revid)
1337+ return tree.archive(root=root, format=archive_format, name=filename)
1338
1339=== modified file 'loggerhead/controllers/error_ui.py'
1340--- loggerhead/controllers/error_ui.py 2012-02-08 01:50:02 +0000
1341+++ loggerhead/controllers/error_ui.py 2019-09-18 16:50:15 +0000
1342@@ -16,16 +16,16 @@
1343 # Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
1344 #
1345
1346-from StringIO import StringIO
1347+from io import StringIO
1348 import traceback
1349
1350-from loggerhead.controllers import TemplatedBranchView
1351-from loggerhead import util
1352+from ..controllers import TemplatedBranchView
1353+from .. import util
1354
1355
1356 class ErrorUI(TemplatedBranchView):
1357
1358- template_path = 'loggerhead.templates.error'
1359+ template_name = 'error'
1360
1361 def __init__(self, branch, exc_info):
1362 super(ErrorUI, self).__init__(branch, lambda: None)
1363
1364=== modified file 'loggerhead/controllers/filediff_ui.py'
1365--- loggerhead/controllers/filediff_ui.py 2015-03-19 14:48:47 +0000
1366+++ loggerhead/controllers/filediff_ui.py 2019-09-18 16:50:15 +0000
1367@@ -1,47 +1,52 @@
1368-from StringIO import StringIO
1369-import urllib
1370-
1371-from bzrlib import diff
1372-from bzrlib import errors
1373-from bzrlib import osutils
1374-
1375-from loggerhead import util
1376-from loggerhead.controllers import TemplatedBranchView
1377+from io import BytesIO
1378+
1379+from breezy import (
1380+ diff,
1381+ errors,
1382+ osutils,
1383+ urlutils,
1384+ )
1385+
1386+from .. import util
1387+from ..controllers import TemplatedBranchView
1388+
1389
1390 def _process_diff(difftext):
1391 chunks = []
1392 chunk = None
1393+ def decode_line(line):
1394+ return line.decode('utf-8', 'replace')
1395 for line in difftext.splitlines():
1396 if len(line) == 0:
1397 continue
1398- if line.startswith('+++ ') or line.startswith('--- '):
1399+ if line.startswith(b'+++ ') or line.startswith(b'--- '):
1400 continue
1401- if line.startswith('@@ '):
1402+ if line.startswith(b'@@ '):
1403 # new chunk
1404 if chunk is not None:
1405 chunks.append(chunk)
1406 chunk = util.Container()
1407 chunk.diff = []
1408- split_lines = line.split(' ')[1:3]
1409- lines = [int(x.split(',')[0][1:]) for x in split_lines]
1410+ split_lines = line.split(b' ')[1:3]
1411+ lines = [int(x.split(b',')[0][1:]) for x in split_lines]
1412 old_lineno = lines[0]
1413 new_lineno = lines[1]
1414- elif line.startswith(' '):
1415+ elif line.startswith(b' '):
1416 chunk.diff.append(util.Container(old_lineno=old_lineno,
1417 new_lineno=new_lineno,
1418 type='context',
1419- line=line[1:]))
1420+ line=decode_line(line[1:])))
1421 old_lineno += 1
1422 new_lineno += 1
1423- elif line.startswith('+'):
1424+ elif line.startswith(b'+'):
1425 chunk.diff.append(util.Container(old_lineno=None,
1426 new_lineno=new_lineno,
1427- type='insert', line=line[1:]))
1428+ type='insert', line=decode_line(line[1:])))
1429 new_lineno += 1
1430- elif line.startswith('-'):
1431+ elif line.startswith(b'-'):
1432 chunk.diff.append(util.Container(old_lineno=old_lineno,
1433 new_lineno=None,
1434- type='delete', line=line[1:]))
1435+ type='delete', line=decode_line(line[1:])))
1436 old_lineno += 1
1437 else:
1438 chunk.diff.append(util.Container(old_lineno=None,
1439@@ -60,17 +65,17 @@
1440 lines = {}
1441 args = []
1442 for r in (compare_revid, revid):
1443- if r == 'null:':
1444+ if r == b'null:':
1445 lines[r] = []
1446 else:
1447 args.append((file_id, r, r))
1448 for r, bytes_iter in repository.iter_files_bytes(args):
1449- lines[r] = osutils.split_lines(''.join(bytes_iter))
1450- buffer = StringIO()
1451+ lines[r] = osutils.split_lines(b''.join(bytes_iter))
1452+ buffer = BytesIO()
1453 try:
1454 diff.internal_diff('', lines[compare_revid], '', lines[revid], buffer, context_lines=context_lines)
1455 except errors.BinaryFile:
1456- difftext = ''
1457+ difftext = b''
1458 else:
1459 difftext = buffer.getvalue()
1460
1461@@ -79,13 +84,13 @@
1462
1463 class FileDiffUI(TemplatedBranchView):
1464
1465- template_path = 'loggerhead.templates.filediff'
1466+ template_name = 'filediff'
1467 supports_json = True
1468
1469 def get_values(self, path, kwargs, headers):
1470- revid = urllib.unquote(self.args[0])
1471- compare_revid = urllib.unquote(self.args[1])
1472- file_id = urllib.unquote(self.args[2])
1473+ revid = urlutils.unquote_to_bytes(self.args[0])
1474+ compare_revid = urlutils.unquote_to_bytes(self.args[1])
1475+ file_id = urlutils.unquote_to_bytes(self.args[2])
1476
1477 try:
1478 context_lines = int(kwargs['context'])
1479
1480=== modified file 'loggerhead/controllers/inventory_ui.py'
1481--- loggerhead/controllers/inventory_ui.py 2013-03-27 05:29:14 +0000
1482+++ loggerhead/controllers/inventory_ui.py 2019-09-18 16:50:15 +0000
1483@@ -24,60 +24,68 @@
1484
1485 from paste.httpexceptions import HTTPNotFound, HTTPMovedPermanently
1486
1487-from bzrlib import errors
1488-from bzrlib.revision import is_null as is_null_rev
1489+from breezy import (
1490+ errors,
1491+ osutils,
1492+ urlutils,
1493+ )
1494+from breezy.revision import is_null as is_null_rev
1495
1496-from loggerhead import util
1497-from loggerhead.controllers import TemplatedBranchView
1498+from .. import util
1499+from ..controllers import TemplatedBranchView
1500
1501
1502
1503 def dirname(path):
1504 if path is not None:
1505 path = path.rstrip('/')
1506- path = urllib.quote(posixpath.dirname(path).encode('utf-8'))
1507+ path = urlutils.escape(posixpath.dirname(path))
1508 return path
1509
1510
1511 class InventoryUI(TemplatedBranchView):
1512
1513- template_path = 'loggerhead.templates.inventory'
1514+ template_name = 'inventory'
1515 supports_json = True
1516
1517- def get_filelist(self, inv, path, sort_type, revno_url):
1518+ def get_filelist(self, tree, path, sort_type, revno_url):
1519 """
1520 return the list of all files (and their attributes) within a given
1521 path subtree.
1522
1523- @param inv: The inventory.
1524- @param path: The path of a directory within the inventory.
1525+ @param tree: The tree
1526+ @param path: The path of a directory within the tree.
1527 @param sort_type: How to sort the results... XXX.
1528 """
1529- file_id = inv.path2id(path)
1530- dir_ie = inv[file_id]
1531 file_list = []
1532
1533- if dir_ie.kind != 'directory':
1534+ if tree.kind(path) != 'directory':
1535 raise HTTPMovedPermanently(self._branch.context_url(['/view', revno_url, path]))
1536
1537 revid_set = set()
1538
1539- for filename, entry in dir_ie.children.iteritems():
1540- revid_set.add(entry.revision)
1541+ child_entries = []
1542+
1543+ for entry in tree.iter_child_entries(path):
1544+ child_path = osutils.pathjoin(path, entry.name)
1545+ child_revision = tree.get_file_revision(child_path)
1546+ revid_set.add(child_revision)
1547+ child_entries.append((child_path, entry, child_revision))
1548
1549 change_dict = {}
1550 for change in self._history.get_changes(list(revid_set)):
1551 change_dict[change.revid] = change
1552
1553- for filename, entry in dir_ie.children.iteritems():
1554- pathname = filename
1555+ for child_path, entry, child_revision in child_entries:
1556+ pathname = entry.name
1557+ contents_changed_rev = None
1558 if entry.kind == 'directory':
1559 pathname += '/'
1560- if path == '':
1561- absolutepath = pathname
1562+ size = None
1563 else:
1564- absolutepath = path + '/' + pathname
1565- revid = entry.revision
1566+ size = entry.text_size
1567+
1568+ file_timestamp = change_dict[child_revision].timestamp
1569
1570 # TODO: For the JSON rendering, this inlines the "change" aka
1571 # revision information attached to each file. Consider either
1572@@ -85,21 +93,26 @@
1573 # including the revision id and having a separate request to get
1574 # back the revision info.
1575 file = util.Container(
1576- filename=filename, executable=entry.executable,
1577- kind=entry.kind, absolutepath=absolutepath,
1578- file_id=entry.file_id, size=entry.text_size, revid=revid,
1579- change=change_dict[revid])
1580+ filename=entry.name, executable=entry.executable,
1581+ kind=entry.kind, absolutepath=child_path,
1582+ file_id=entry.file_id, size=size, revid=child_revision,
1583+ change=change_dict[child_revision], contents_changed_rev=contents_changed_rev)
1584 file_list.append(file)
1585
1586 if sort_type == 'filename':
1587 file_list.sort(key=lambda x: x.filename.lower()) # case-insensitive
1588 elif sort_type == 'size':
1589- file_list.sort(key=lambda x: x.size)
1590+ def size_key(x):
1591+ if x.size is None:
1592+ return -1
1593+ return x.size
1594+ file_list.sort(key=size_key)
1595 elif sort_type == 'date':
1596- file_list.sort(key=lambda x: x.change.date)
1597+ file_list.sort(key=lambda x: x.change.date, reverse=True)
1598
1599- # Always sort directories first.
1600- file_list.sort(key=lambda x: x.kind != 'directory')
1601+ if sort_type != 'date':
1602+ # Don't always sort directories first.
1603+ file_list.sort(key=lambda x: x.kind != 'directory')
1604
1605 return file_list
1606
1607@@ -137,14 +150,14 @@
1608 updir = dirname(path)
1609
1610 if not is_null_rev(revid):
1611- change = history.get_changes([ revid ])[0]
1612+ change = history.get_changes([revid])[0]
1613 # If we're looking at the tip, use head: in the URL instead
1614 if revid == branch.last_revision():
1615 revno_url = 'head:'
1616 else:
1617 revno_url = history.get_revno(revid)
1618 history.add_branch_nicks(change)
1619- filelist = self.get_filelist(rev_tree.inventory, path, sort_type, revno_url)
1620+ filelist = self.get_filelist(rev_tree, path, sort_type, revno_url)
1621
1622 else:
1623 start_revid = None
1624
1625=== modified file 'loggerhead/controllers/revision_ui.py'
1626--- loggerhead/controllers/revision_ui.py 2015-03-19 14:48:47 +0000
1627+++ loggerhead/controllers/revision_ui.py 2019-09-18 16:50:15 +0000
1628@@ -18,24 +18,25 @@
1629 #
1630
1631 import simplejson
1632-import urllib
1633
1634 from paste.httpexceptions import HTTPServerError
1635
1636-from loggerhead import util
1637-from loggerhead.controllers import TemplatedBranchView
1638-from loggerhead.controllers.filediff_ui import diff_chunks_for_file
1639+from breezy import urlutils
1640+
1641+from .. import util
1642+from ..controllers import TemplatedBranchView
1643+from ..controllers.filediff_ui import diff_chunks_for_file
1644
1645
1646 DEFAULT_LINE_COUNT_LIMIT = 3000
1647
1648 def dq(p):
1649- return urllib.quote(urllib.quote(p, safe=''))
1650+ return urlutils.quote(urlutils.quote(p, safe=''))
1651
1652
1653 class RevisionUI(TemplatedBranchView):
1654
1655- template_path = 'loggerhead.templates.revision'
1656+ template_name = 'revision'
1657 supports_json = True
1658
1659 def get_values(self, path, kwargs, headers):
1660@@ -88,7 +89,7 @@
1661 merged_in = None
1662
1663 return {
1664- 'revid': revid,
1665+ 'revid': revid.decode('utf-8'),
1666 'change': change,
1667 'file_changes': file_changes,
1668 'merged_in': merged_in,
1669
1670=== modified file 'loggerhead/controllers/revlog_ui.py'
1671--- loggerhead/controllers/revlog_ui.py 2011-06-27 15:05:06 +0000
1672+++ loggerhead/controllers/revlog_ui.py 2019-09-18 16:50:15 +0000
1673@@ -1,17 +1,19 @@
1674 import urllib
1675
1676-from loggerhead.controllers import TemplatedBranchView
1677+from breezy import osutils, urlutils
1678+
1679+from ..controllers import TemplatedBranchView
1680
1681
1682 class RevLogUI(TemplatedBranchView):
1683
1684- template_path = 'loggerhead.templates.revlog'
1685+ template_name = 'revlog'
1686 supports_json = True
1687
1688 def get_values(self, path, kwargs, headers):
1689 history = self._history
1690
1691- revid = urllib.unquote(self.args[0])
1692+ revid = urlutils.unquote_to_bytes(osutils.safe_utf8(self.args[0]))
1693
1694 change = history.get_changes([revid])[0]
1695 file_changes = history.get_file_changes(change)
1696
1697=== modified file 'loggerhead/controllers/search_ui.py'
1698--- loggerhead/controllers/search_ui.py 2012-02-08 01:50:02 +0000
1699+++ loggerhead/controllers/search_ui.py 2019-09-18 16:50:15 +0000
1700@@ -16,8 +16,8 @@
1701 # Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
1702 #
1703
1704-from loggerhead.controllers import TemplatedBranchView
1705-from loggerhead import search
1706+from ..controllers import TemplatedBranchView
1707+from .. import search
1708
1709
1710 class SearchUI(TemplatedBranchView):
1711@@ -26,7 +26,7 @@
1712 Class to output progressive search result terms.
1713 """
1714
1715- template_path = 'loggerhead.templates.search'
1716+ template_name = 'search'
1717
1718 def get_values(self, path, kwargs, response):
1719 """
1720
1721=== modified file 'loggerhead/controllers/view_ui.py'
1722--- loggerhead/controllers/view_ui.py 2012-03-22 14:09:52 +0000
1723+++ loggerhead/controllers/view_ui.py 2019-09-18 16:50:15 +0000
1724@@ -19,13 +19,16 @@
1725
1726 import os
1727
1728-from bzrlib.errors import (
1729+from breezy.errors import (
1730 BinaryFile,
1731 NoSuchId,
1732 NoSuchRevision,
1733 )
1734-import bzrlib.textfile
1735-import bzrlib.osutils
1736+from breezy import (
1737+ osutils,
1738+ urlutils,
1739+ )
1740+import breezy.textfile
1741
1742 from paste.httpexceptions import (
1743 HTTPBadRequest,
1744@@ -34,38 +37,47 @@
1745 HTTPServerError,
1746 )
1747
1748-from loggerhead.controllers import TemplatedBranchView
1749+from ..controllers import TemplatedBranchView
1750 try:
1751- from loggerhead.highlight import highlight
1752+ from ..highlight import highlight
1753 except ImportError:
1754 highlight = None
1755-from loggerhead import util
1756+from .. import util
1757
1758
1759 class ViewUI(TemplatedBranchView):
1760
1761- template_path = 'loggerhead.templates.view'
1762-
1763+ template_name = 'view'
1764+
1765 def tree_for(self, file_id, revid):
1766- file_revid = self._history.get_inventory(revid)[file_id].revision
1767+ if not isinstance(file_id, bytes):
1768+ raise TypeError(file_id)
1769+ if not isinstance(revid, bytes):
1770+ raise TypeError(revid)
1771+ rev_tree = self._history.revision_tree(revid)
1772+ file_revid = rev_tree.get_file_revision(rev_tree.id2path(file_id))
1773 return self._history._branch.repository.revision_tree(file_revid)
1774
1775 def text_lines(self, file_id, revid):
1776- file_name = os.path.basename(self._history.get_path(revid, file_id))
1777-
1778+ path = self._history.get_path(revid, file_id)
1779+ file_name = os.path.basename(path)
1780+
1781 tree = self.tree_for(file_id, revid)
1782- file_text = tree.get_file_text(file_id)
1783+ file_text = tree.get_file_text(path)
1784+
1785 encoding = 'utf-8'
1786 try:
1787- file_text = file_text.decode(encoding)
1788+ file_text.decode(encoding)
1789 except UnicodeDecodeError:
1790 encoding = 'iso-8859-15'
1791- file_text = file_text.decode(encoding)
1792-
1793- file_lines = bzrlib.osutils.split_lines(file_text)
1794- # This can throw bzrlib.errors.BinaryFile (which our caller catches).
1795- bzrlib.textfile.check_text_lines(file_lines)
1796-
1797+ file_text.decode(encoding)
1798+
1799+ file_lines = osutils.split_lines(file_text)
1800+ # This can throw breezy.errors.BinaryFile (which our caller catches).
1801+ breezy.textfile.check_text_lines(file_lines)
1802+
1803+ file_text = file_text.decode(encoding)
1804+
1805 if highlight is not None:
1806 hl_lines = highlight(file_name, file_text, encoding)
1807 # highlight strips off extra newlines at the end of the file.
1808@@ -73,8 +85,8 @@
1809 hl_lines.extend([u''] * extra_lines)
1810 else:
1811 hl_lines = map(util.html_escape, file_lines)
1812-
1813- return hl_lines;
1814+
1815+ return hl_lines
1816
1817 def file_contents(self, file_id, revid):
1818 try:
1819@@ -89,8 +101,9 @@
1820 history = self._history
1821 branch = history._branch
1822 revid = self.get_revid()
1823- revid = history.fix_revid(revid)
1824 file_id = kwargs.get('file_id', None)
1825+ if file_id is not None:
1826+ file_id = urlutils.unquote_to_bytes(osutils.safe_utf8(file_id))
1827 if (file_id is None) and (path is None):
1828 raise HTTPBadRequest('No file_id or filename '
1829 'provided to view')
1830@@ -119,20 +132,15 @@
1831 self._branch.is_root,
1832 'files'))
1833
1834+ tree = history.revision_tree(revid)
1835+
1836 # Create breadcrumb trail for the path within the branch
1837- try:
1838- inv = history.get_inventory(revid)
1839- except:
1840- self.log.exception('Exception fetching changes')
1841- raise HTTPServerError('Could not fetch changes')
1842- branch_breadcrumbs = util.branch_breadcrumbs(path, inv, 'files')
1843+ branch_breadcrumbs = util.branch_breadcrumbs(path, tree, 'files')
1844
1845- try:
1846- file = inv[file_id]
1847- except NoSuchId:
1848+ if not tree.has_id(file_id):
1849 raise HTTPNotFound()
1850
1851- if file.kind == "directory":
1852+ if tree.kind(path) == "directory":
1853 raise HTTPMovedPermanently(self._branch.context_url(['/files', revno_url, path]))
1854
1855 # no navbar for revisions
1856
1857=== modified file 'loggerhead/daemon.py'
1858--- loggerhead/daemon.py 2009-05-13 14:03:48 +0000
1859+++ loggerhead/daemon.py 2019-09-18 16:50:15 +0000
1860@@ -16,7 +16,7 @@
1861
1862 try:
1863 pid = os.fork()
1864- except OSError, e:
1865+ except OSError as e:
1866 raise Exception("%s [%d]" % (e.strerror, e.errno))
1867
1868 if pid == 0: # The first child.
1869@@ -24,7 +24,7 @@
1870
1871 try:
1872 pid = os.fork() # Fork a second child.
1873- except OSError, e:
1874+ except OSError as e:
1875 raise Exception("%s [%d]" % (e.strerror, e.errno))
1876
1877 if pid == 0: # The second child.
1878
1879=== removed file 'loggerhead/exporter.py'
1880--- loggerhead/exporter.py 2011-11-24 07:46:41 +0000
1881+++ loggerhead/exporter.py 1970-01-01 00:00:00 +0000
1882@@ -1,60 +0,0 @@
1883-# Copyright (C) 2011 Canonical Ltd
1884-#
1885-# This program is free software; you can redistribute it and/or modify
1886-# it under the terms of the GNU General Public License as published by
1887-# the Free Software Foundation; either version 2 of the License, or
1888-# (at your option) any later version.
1889-#
1890-# This program is distributed in the hope that it will be useful,
1891-# but WITHOUT ANY WARRANTY; without even the implied warranty of
1892-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1893-# GNU General Public License for more details.
1894-#
1895-"""Exports an archive from a bazaar branch"""
1896-
1897-from bzrlib.export import get_export_generator
1898-
1899-
1900-class ExporterFileObject(object):
1901- """Shim that accumulates temporarily written out data.
1902-
1903- There are python tarfile classes that want to write to a file like object.
1904- We want to stream data. But wsgi assumes it can pull data from the
1905- handler, rather than having bytes pushed.
1906-
1907- So this class holds the data temporarily, until it is pulled. It
1908- should never buffer everything because as soon as a chunk is produced,
1909- wsgi will be given the chance to take it.
1910- """
1911-
1912- def __init__(self):
1913- self._buffer = []
1914-
1915- def write(self, s):
1916- self._buffer.append(s)
1917-
1918- def get_buffer(self):
1919- try:
1920- return ''.join(self._buffer)
1921- finally:
1922- self._buffer = []
1923-
1924- def close(self):
1925- pass
1926-
1927-
1928-def export_archive(history, root, revid, archive_format):
1929- """Export tree contents to an archive
1930-
1931- :param history: Instance of history to export
1932- :param root: Root location inside the archive.
1933- :param revid: Revision to export
1934- :param archive_format: Format of the archive, eg 'tar.gz'.
1935- """
1936- fileobj = ExporterFileObject()
1937- tree = history._branch.repository.revision_tree(revid)
1938- for _ in get_export_generator(tree=tree, root=root, fileobj=fileobj,
1939- format=archive_format):
1940- yield fileobj.get_buffer()
1941- # Might have additonal contents written
1942- yield fileobj.get_buffer()
1943
1944=== modified file 'loggerhead/highlight.py'
1945--- loggerhead/highlight.py 2012-02-08 01:50:02 +0000
1946+++ loggerhead/highlight.py 2019-09-18 16:50:15 +0000
1947@@ -16,7 +16,7 @@
1948 # Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
1949 #
1950
1951-import bzrlib.osutils
1952+import breezy.osutils
1953 import cgi
1954
1955 from pygments import highlight as _highlight_func
1956@@ -37,7 +37,7 @@
1957 """
1958
1959 if len(text) > MAX_HIGHLIGHT_SIZE:
1960- return map(cgi.escape, bzrlib.osutils.split_lines(text))
1961+ return map(cgi.escape, breezy.osutils.split_lines(text))
1962
1963 formatter = HtmlFormatter(style=style, nowrap=True, classprefix='pyg-')
1964
1965@@ -50,6 +50,6 @@
1966 lexer = TextLexer(encoding=encoding)
1967
1968 hl_lines = _highlight_func(text, lexer, formatter)
1969- hl_lines = bzrlib.osutils.split_lines(hl_lines)
1970+ hl_lines = breezy.osutils.split_lines(hl_lines)
1971
1972 return hl_lines
1973
1974=== modified file 'loggerhead/history.py'
1975--- loggerhead/history.py 2016-03-30 06:18:39 +0000
1976+++ loggerhead/history.py 2019-09-18 16:50:15 +0000
1977@@ -35,23 +35,28 @@
1978 import threading
1979 import tarfile
1980
1981-from bzrlib import tag
1982-import bzrlib.branch
1983-import bzrlib.delta
1984-import bzrlib.errors
1985-import bzrlib.foreign
1986-import bzrlib.revision
1987+from breezy import tag
1988+import breezy.branch
1989+import breezy.delta
1990+import breezy.errors
1991+import breezy.foreign
1992+import breezy.osutils
1993+import breezy.revision
1994+from breezy.sixish import (
1995+ text_type,
1996+ viewvalues,
1997+ )
1998
1999-from loggerhead import search
2000-from loggerhead import util
2001-from loggerhead.wholehistory import compute_whole_history_data
2002+from . import search
2003+from . import util
2004+from .wholehistory import compute_whole_history_data
2005
2006
2007 def is_branch(folder):
2008 try:
2009- bzrlib.branch.Branch.open(folder)
2010+ breezy.branch.Branch.open(folder)
2011 return True
2012- except:
2013+ except breezy.errors.NotBranchError:
2014 return False
2015
2016
2017@@ -108,20 +113,22 @@
2018
2019 class FileChangeReporter(object):
2020
2021- def __init__(self, old_inv, new_inv):
2022+ def __init__(self, old_tree, new_tree):
2023 self.added = []
2024 self.modified = []
2025 self.renamed = []
2026 self.removed = []
2027 self.text_changes = []
2028- self.old_inv = old_inv
2029- self.new_inv = new_inv
2030+ self.old_tree = old_tree
2031+ self.new_tree = new_tree
2032
2033- def revid(self, inv, file_id):
2034+ def revid(self, tree, file_id):
2035 try:
2036- return inv[file_id].revision
2037- except bzrlib.errors.NoSuchId:
2038- return 'null:'
2039+ path = tree.id2path(file_id)
2040+ except breezy.errors.NoSuchId:
2041+ return b'null:'
2042+ else:
2043+ return tree.get_file_revision(path)
2044
2045 def report(self, file_id, paths, versioned, renamed, modified,
2046 exe_change, kind):
2047@@ -132,8 +139,8 @@
2048 filename = rich_filename(paths[1], kind[1])
2049 self.text_changes.append(util.Container(
2050 filename=filename, file_id=file_id,
2051- old_revision=self.revid(self.old_inv, file_id),
2052- new_revision=self.revid(self.new_inv, file_id)))
2053+ old_revision=self.revid(self.old_tree, file_id),
2054+ new_revision=self.revid(self.new_tree, file_id)))
2055 if versioned == 'added':
2056 self.added.append(util.Container(
2057 filename=rich_filename(paths[1], kind), kind=kind[1]))
2058@@ -299,7 +306,7 @@
2059
2060 @property
2061 def has_revisions(self):
2062- return not bzrlib.revision.is_null(self.last_revid)
2063+ return not breezy.revision.is_null(self.last_revid)
2064
2065 def get_config(self):
2066 return self._branch.get_config()
2067@@ -320,7 +327,7 @@
2068 if revid_list is None:
2069 # Just yield the mainline, starting at start_revid
2070 revid = start_revid
2071- is_null = bzrlib.revision.is_null
2072+ is_null = breezy.revision.is_null
2073 while not is_null(revid):
2074 yield revid
2075 parents = self._rev_info[self._rev_indices[revid]][2]
2076@@ -341,7 +348,7 @@
2077 i += 1
2078 return r
2079 while revid_set:
2080- if bzrlib.revision.is_null(revid):
2081+ if breezy.revision.is_null(revid):
2082 return
2083 rev_introduced = introduced_revisions(revid)
2084 matching = rev_introduced.intersection(revid_set)
2085@@ -360,11 +367,11 @@
2086 possible_keys = [(file_id, revid) for revid in self._rev_indices]
2087 get_parent_map = self._branch.repository.texts.get_parent_map
2088 # We chunk the requests as this works better with GraphIndex.
2089- # See _filter_revisions_touching_file_id in bzrlib/log.py
2090+ # See _filter_revisions_touching_file_id in breezy/log.py
2091 # for more information.
2092 revids = []
2093 chunk_size = 1000
2094- for start in xrange(0, len(possible_keys), chunk_size):
2095+ for start in range(0, len(possible_keys), chunk_size):
2096 next_keys = possible_keys[start:start + chunk_size]
2097 revids += [k[1] for k in get_parent_map(next_keys)]
2098 del possible_keys, next_keys
2099@@ -405,8 +412,6 @@
2100 # ignore the passed-in revid_list
2101 revid = self.fix_revid(query)
2102 if revid is not None:
2103- if isinstance(revid, unicode):
2104- revid = revid.encode('utf-8')
2105 changes = self.get_changes([revid])
2106 if (changes is not None) and (len(changes) > 0):
2107 return [revid]
2108@@ -448,13 +453,17 @@
2109 # if a "revid" is actually a dotted revno, convert it to a revid
2110 if revid is None:
2111 return revid
2112+ if not isinstance(revid, (str, text_type)):
2113+ raise TypeError(revid)
2114 if revid == 'head:':
2115 return self.last_revid
2116 try:
2117 if self.revno_re.match(revid):
2118 revid = self._revno_revid[revid]
2119 except KeyError:
2120- raise bzrlib.errors.NoSuchRevision(self._branch_nick, revid)
2121+ raise breezy.errors.NoSuchRevision(self._branch_nick, revid)
2122+ if not isinstance(revid, bytes):
2123+ revid = revid.encode('utf-8')
2124 return revid
2125
2126 def get_file_view(self, revid, file_id):
2127@@ -564,16 +573,13 @@
2128 # search index.
2129 return None, None, []
2130
2131- def get_inventory(self, revid):
2132- if revid not in self._inventory_cache:
2133- self._inventory_cache[revid] = (
2134- self._branch.repository.get_inventory(revid))
2135- return self._inventory_cache[revid]
2136+ def revision_tree(self, revid):
2137+ return self._branch.repository.revision_tree(revid)
2138
2139 def get_path(self, revid, file_id):
2140 if (file_id is None) or (file_id == ''):
2141 return ''
2142- path = self.get_inventory(revid).id2path(file_id)
2143+ path = self.revision_tree(revid).id2path(file_id)
2144 if (len(path) > 0) and not path.startswith('/'):
2145 path = '/' + path
2146 return path
2147@@ -581,7 +587,7 @@
2148 def get_file_id(self, revid, path):
2149 if (len(path) > 0) and not path.startswith('/'):
2150 path = '/' + path
2151- return self.get_inventory(revid).path2id(path)
2152+ return self.revision_tree(revid).path2id(path)
2153
2154 def get_merge_point_list(self, revid):
2155 """
2156@@ -618,7 +624,7 @@
2157 else:
2158 d[revnos] = (revnolast, revid)
2159
2160- return [revid for (_, revid) in d.itervalues()]
2161+ return [revid for (_, revid) in viewvalues(d)]
2162
2163 def add_branch_nicks(self, change):
2164 """
2165@@ -631,7 +637,7 @@
2166 for p in change.merge_points:
2167 fetch_set.add(p.revid)
2168 p_changes = self.get_changes(list(fetch_set))
2169- p_change_dict = dict([(c.revid, c) for c in p_changes])
2170+ p_change_dict = {c.revid: c for c in p_changes}
2171 for p in change.parents:
2172 if p.revid in p_change_dict:
2173 p.branch_nick = p_change_dict[p.revid].branch_nick
2174@@ -648,6 +654,9 @@
2175
2176 Revisions not present and NULL_REVISION will be ignored.
2177 """
2178+ for revid in revid_list:
2179+ if not isinstance(revid, bytes):
2180+ raise TypeError(revid_list)
2181 changes = self.get_changes_uncached(revid_list)
2182 if len(changes) == 0:
2183 return changes
2184@@ -674,8 +683,8 @@
2185
2186 def get_changes_uncached(self, revid_list):
2187 # FIXME: deprecated method in getting a null revision
2188- revid_list = filter(lambda revid: not bzrlib.revision.is_null(revid),
2189- revid_list)
2190+ revid_list = list(filter(lambda revid: not breezy.revision.is_null(revid),
2191+ revid_list))
2192 parent_map = self._branch.repository.get_graph().get_parent_map(
2193 revid_list)
2194 # We need to return the answer in the same order as the input,
2195@@ -688,7 +697,7 @@
2196
2197 def _change_from_revision(self, revision):
2198 """
2199- Given a bzrlib Revision, return a processed "change" for use in
2200+ Given a breezy Revision, return a processed "change" for use in
2201 templates.
2202 """
2203 message, short_message = clean_message(revision.message)
2204@@ -712,6 +721,7 @@
2205 'revid': revision.revision_id,
2206 'date': datetime.datetime.fromtimestamp(revision.timestamp),
2207 'utc_date': datetime.datetime.utcfromtimestamp(revision.timestamp),
2208+ 'timestamp': revision.timestamp,
2209 'committer': revision.committer,
2210 'authors': revision.get_apparent_authors(),
2211 'branch_nick': revision.properties.get('branch-nick', None),
2212@@ -722,15 +732,15 @@
2213 'bugs': [bug.split()[0] for bug in revision.properties.get('bugs', '').splitlines()],
2214 'tags': revtags,
2215 }
2216- if isinstance(revision, bzrlib.foreign.ForeignRevision):
2217+ if isinstance(revision, breezy.foreign.ForeignRevision):
2218 foreign_revid, mapping = (
2219 revision.foreign_revid, revision.mapping)
2220- elif ":" in revision.revision_id:
2221+ elif b":" in revision.revision_id:
2222 try:
2223 foreign_revid, mapping = \
2224- bzrlib.foreign.foreign_vcs_registry.parse_revision_id(
2225+ breezy.foreign.foreign_vcs_registry.parse_revision_id(
2226 revision.revision_id)
2227- except bzrlib.errors.InvalidRevisionId:
2228+ except breezy.errors.InvalidRevisionId:
2229 foreign_revid = None
2230 mapping = None
2231 else:
2232@@ -744,7 +754,7 @@
2233 if entry.parents:
2234 old_revid = entry.parents[0].revid
2235 else:
2236- old_revid = bzrlib.revision.NULL_REVISION
2237+ old_revid = breezy.revision.NULL_REVISION
2238 return self.file_changes_for_revision_ids(old_revid, entry.revid)
2239
2240 def add_changes(self, entry):
2241@@ -753,13 +763,17 @@
2242
2243 def get_file(self, file_id, revid):
2244 """Returns (path, filename, file contents)"""
2245- inv = self.get_inventory(revid)
2246- inv_entry = inv[file_id]
2247- rev_tree = self._branch.repository.revision_tree(inv_entry.revision)
2248- path = inv.id2path(file_id)
2249- if not path.startswith('/'):
2250+ if not isinstance(file_id, bytes):
2251+ raise TypeError(file_id)
2252+ if not isinstance(revid, bytes):
2253+ raise TypeError(revid)
2254+ rev_tree = self._branch.repository.revision_tree(revid)
2255+ path = rev_tree.id2path(file_id)
2256+ display_path = path
2257+ if not display_path.startswith('/'):
2258 path = '/' + path
2259- return path, inv_entry.name, rev_tree.get_file_text(file_id)
2260+ return (display_path, breezy.osutils.basename(path),
2261+ rev_tree.get_file_text(path))
2262
2263 def file_changes_for_revision_ids(self, old_revid, new_revid):
2264 """
2265@@ -775,17 +789,17 @@
2266 text_changes: list((filename, file_id)),
2267 """
2268 repo = self._branch.repository
2269- if (bzrlib.revision.is_null(old_revid) or
2270- bzrlib.revision.is_null(new_revid) or
2271- old_revid == new_revid):
2272+ if (breezy.revision.is_null(old_revid) or
2273+ breezy.revision.is_null(new_revid) or
2274+ old_revid == new_revid):
2275 old_tree, new_tree = map(
2276 repo.revision_tree, [old_revid, new_revid])
2277 else:
2278 old_tree, new_tree = repo.revision_trees([old_revid, new_revid])
2279
2280- reporter = FileChangeReporter(old_tree.inventory, new_tree.inventory)
2281+ reporter = FileChangeReporter(old_tree, new_tree)
2282
2283- bzrlib.delta.report_changes(new_tree.iter_changes(old_tree), reporter)
2284+ breezy.delta.report_changes(new_tree.iter_changes(old_tree), reporter)
2285
2286 return util.Container(
2287 added=sorted(reporter.added, key=lambda x: x.filename),
2288
2289=== modified file 'loggerhead/load_test.py'
2290--- loggerhead/load_test.py 2012-02-08 01:50:02 +0000
2291+++ loggerhead/load_test.py 2019-09-18 16:50:15 +0000
2292@@ -65,17 +65,21 @@
2293
2294 import threading
2295 import time
2296-import Queue
2297+try:
2298+ from queue import Queue, Empty
2299+except ImportError: # Python < 3
2300+ from Queue import Queue, Empty
2301
2302 import simplejson
2303
2304-from bzrlib import (
2305+from breezy import (
2306 errors,
2307 transport,
2308 urlutils,
2309 )
2310+from breezy.sixish import viewvalues
2311
2312-# This code will be doing multi-threaded requests against bzrlib.transport
2313+# This code will be doing multi-threaded requests against breezy.transport
2314 # code. We want to make sure to load everything ahead of time, so we don't get
2315 # lazy-import failures
2316 _ = transport.get_transport('http://example.com')
2317@@ -96,7 +100,7 @@
2318
2319 def __init__(self, identifier, blocking_time=1.0, _queue_size=1):
2320 self.identifier = identifier
2321- self.queue = Queue.Queue(_queue_size)
2322+ self.queue = Queue(_queue_size)
2323 self.start_time = self.end_time = None
2324 self.stats = []
2325 self.blocking_time = blocking_time
2326@@ -118,7 +122,7 @@
2327 while not stop_event.isSet():
2328 try:
2329 self.step_next()
2330- except Queue.Empty:
2331+ except Empty:
2332 pass
2333
2334 def process(self, url):
2335@@ -189,7 +193,7 @@
2336
2337 def finish_queues(self):
2338 """Wait for all queues of all children to finish."""
2339- for h, t in self._threads.itervalues():
2340+ for h, t in viewvalues(self._threads):
2341 h.queue.join()
2342
2343 def stop_and_join(self):
2344@@ -198,7 +202,7 @@
2345 This will stop even if workers still have work items.
2346 """
2347 self.stop_event.set()
2348- for h, t in self._threads.itervalues():
2349+ for h, t in viewvalues(self._threads):
2350 # Signal the queue that it should stop blocking, we don't have to
2351 # wait for the queue to empty, because we may see stop_event before
2352 # we see the <noop>
2353
2354=== modified file 'loggerhead/lsprof.py'
2355--- loggerhead/lsprof.py 2009-07-07 23:52:24 +0000
2356+++ loggerhead/lsprof.py 2019-09-18 16:50:15 +0000
2357@@ -6,7 +6,10 @@
2358 # instead of just the Stats object
2359
2360 import sys
2361-import thread
2362+try:
2363+ from threading import get_ident
2364+except ImportError: # python < 3
2365+ from thread import get_ident
2366 import threading
2367 from _lsprof import Profiler, profiler_entry
2368
2369@@ -19,7 +22,7 @@
2370 # we lose the first profile point for a new thread in order to trampoline
2371 # a new Profile object into place
2372 global _g_threadmap
2373- thr = thread.get_ident()
2374+ thr = get_ident()
2375 _g_threadmap[thr] = p = Profiler()
2376 # this overrides our sys.setprofile hook:
2377 p.enable(subcalls=True, builtins=True)
2378
2379=== modified file 'loggerhead/main.py'
2380--- loggerhead/main.py 2012-02-08 01:50:02 +0000
2381+++ loggerhead/main.py 2019-09-18 16:50:15 +0000
2382@@ -21,25 +21,26 @@
2383 import os
2384 import sys
2385
2386-from bzrlib.plugin import load_plugins
2387+from breezy.plugin import load_plugins
2388+from breezy.transport import location_to_url
2389
2390 from paste import httpserver
2391 from paste.httpexceptions import HTTPExceptionHandler, HTTPInternalServerError
2392 from paste.translogger import TransLogger
2393
2394-from loggerhead import __version__
2395-from loggerhead.apps.transport import (
2396+from . import __version__
2397+from .apps.transport import (
2398 BranchesFromTransportRoot, UserBranchesFromTransportRoot)
2399-from loggerhead.config import LoggerheadConfig
2400-from loggerhead.util import Reloader
2401-from loggerhead.apps.error import ErrorHandlerApp
2402-
2403-
2404-def get_config_and_path(args):
2405+from .config import LoggerheadConfig
2406+from .util import Reloader
2407+from .apps.error import ErrorHandlerApp
2408+
2409+
2410+def get_config_and_base(args):
2411 config = LoggerheadConfig(args)
2412
2413 if config.get_option('show_version'):
2414- print "loggerhead %s" % (__version__,)
2415+ print("loggerhead %s" % (__version__,))
2416 sys.exit(0)
2417
2418 if config.arg_count > 1:
2419@@ -50,6 +51,8 @@
2420 else:
2421 base = '.'
2422
2423+ base = location_to_url(base)
2424+
2425 if not config.get_option('allow_writes'):
2426 base = 'readonly+' + base
2427
2428@@ -70,9 +73,9 @@
2429 else:
2430 if config.get_option('log_folder'):
2431 logfile_path = os.path.join(
2432- config.get_option('log_folder'), 'serve-branches.log')
2433+ config.get_option('log_folder'), 'loggerhead-serve.log')
2434 else:
2435- logfile_path = 'serve-branches.log'
2436+ logfile_path = 'loggerhead-serve.log'
2437 handler = logging.FileHandler(logfile_path, 'a')
2438 formatter = logging.Formatter('%(asctime)s %(levelname)-8s %(name)s:'
2439 ' %(message)s')
2440@@ -92,9 +95,9 @@
2441 return logger
2442
2443
2444-def make_app_for_config_and_path(config, base):
2445+def make_app_for_config_and_base(config, base):
2446 if config.get_option('trunk_dir') and not config.get_option('user_dirs'):
2447- print "--trunk-dir is only valid with --user-dirs"
2448+ print("--trunk-dir is only valid with --user-dirs")
2449 sys.exit(1)
2450
2451 if config.get_option('reload'):
2452@@ -105,7 +108,7 @@
2453
2454 if config.get_option('user_dirs'):
2455 if not config.get_option('trunk_dir'):
2456- print "You didn't specify a directory for the trunk directories."
2457+ print("You didn't specify a directory for the trunk directories.")
2458 sys.exit(1)
2459 app = UserBranchesFromTransportRoot(base, config)
2460 else:
2461@@ -141,6 +144,9 @@
2462 raise exc
2463 return app(environ, start_response)
2464 return wrapped
2465+ logging.warning(
2466+ 'PasteDeploy not available; unable to support '
2467+ 'access through a reverse proxy.')
2468 app = check_not_proxied(app)
2469 else:
2470 app = PrefixMiddleware(app, prefix=prefix)
2471@@ -155,9 +161,9 @@
2472 def main(args):
2473 load_plugins()
2474
2475- config, path = get_config_and_path(args)
2476+ config, base = get_config_and_base(args)
2477
2478- app = make_app_for_config_and_path(config, path)
2479+ app = make_app_for_config_and_base(config, base)
2480
2481 if not config.get_option('user_port'):
2482 port = '8080'
2483@@ -184,6 +190,6 @@
2484 elif protocol == 'ajp':
2485 from flup.server.ajp import WSGIServer
2486 else:
2487- print 'Unknown protocol: %s.' % (protocol)
2488+ print('Unknown protocol: %s.' % (protocol))
2489 sys.exit(1)
2490 WSGIServer(app, bindAddress=(host, int(port))).run()
2491
2492=== modified file 'loggerhead/middleware/profile.py'
2493--- loggerhead/middleware/profile.py 2009-10-17 08:47:38 +0000
2494+++ loggerhead/middleware/profile.py 2019-09-18 16:50:15 +0000
2495@@ -2,7 +2,7 @@
2496
2497 import threading
2498
2499-from bzrlib.lsprof import profile
2500+from breezy.lsprof import profile
2501
2502
2503 class LSProfMiddleware(object):
2504
2505=== modified file 'loggerhead/search.py'
2506--- loggerhead/search.py 2012-02-08 01:50:02 +0000
2507+++ loggerhead/search.py 2019-09-18 16:50:15 +0000
2508@@ -24,9 +24,9 @@
2509 if _mod_index is not None:
2510 return
2511 try:
2512- from bzrlib.plugins.search import errors
2513- from bzrlib.plugins.search import index as _mod_index
2514- from bzrlib.plugins.search.index import FileTextHit, RevisionHit
2515+ from breezy.plugins.search import errors
2516+ from breezy.plugins.search import index as _mod_index
2517+ from breezy.plugins.search.index import FileTextHit, RevisionHit
2518 except ImportError:
2519 _mod_index = None
2520
2521
2522=== modified file 'loggerhead/static/css/global.css'
2523--- loggerhead/static/css/global.css 2015-03-17 11:38:32 +0000
2524+++ loggerhead/static/css/global.css 2019-09-18 16:50:15 +0000
2525@@ -230,11 +230,11 @@
2526 }
2527 th.datecell,
2528 td.date {
2529- width: 180px;
2530+ width: 100px;
2531 }
2532 th.timedate,
2533 td.timedate2 {
2534- width: 80px;
2535+ width: 60px;
2536 }
2537 th.downloadcell,
2538 td.downr {
2539
2540=== modified file 'loggerhead/static/css/view.css'
2541--- loggerhead/static/css/view.css 2019-06-20 16:18:17 +0000
2542+++ loggerhead/static/css/view.css 2019-09-18 16:50:15 +0000
2543@@ -5,8 +5,7 @@
2544 }
2545 .viewRev {
2546 border-right: none;
2547- white-space: nowrap;
2548- width: 1px;
2549+ width: 20%;
2550 padding: .3em .6em;
2551 }
2552 .viewComm,
2553
2554=== modified file 'loggerhead/templatefunctions.py'
2555--- loggerhead/templatefunctions.py 2012-05-02 22:23:34 +0000
2556+++ loggerhead/templatefunctions.py 2019-09-18 16:50:15 +0000
2557@@ -15,15 +15,18 @@
2558 #
2559
2560 import os
2561-import urllib
2562
2563 import pkg_resources
2564
2565-import bzrlib
2566+import breezy
2567+from breezy import urlutils
2568
2569-import loggerhead
2570-from loggerhead.zptsupport import zpt
2571-from loggerhead.util import html_format
2572+from . import (
2573+ __version__,
2574+ __revision__,
2575+ )
2576+from .zptsupport import zpt
2577+from .util import html_format
2578
2579
2580 templatefunctions = {}
2581@@ -52,18 +55,18 @@
2582 if currently_showing and filename == currently_showing:
2583 return html_format(
2584 '<b><a href="#%s">%s</a></b>',
2585- urllib.quote(filename.encode('utf-8')), filename)
2586+ urlutils.quote(filename), filename)
2587 else:
2588 return revision_link(
2589 url, entry.revno, filename,
2590- '#' + urllib.quote(filename.encode('utf-8')))
2591+ '#' + urlutils.quote(filename))
2592 else:
2593 def file_link(filename):
2594 return html_format(
2595 '<a href="%s%s" title="View changes to %s in revision %s">'
2596 '%s</a>',
2597 url(['/revision', entry.revno]),
2598- '#' + urllib.quote(filename.encode('utf-8')),
2599+ '#' + urlutils.quote(filename),
2600 filename, entry.revno, filename)
2601 return _pt('revisionfilechanges').expand(
2602 entry=entry, file_changes=file_changes, file_link=file_link, **templatefunctions)
2603@@ -71,7 +74,7 @@
2604
2605 @templatefunc
2606 def revisioninfo(url, branch, entry, file_changes=None, currently_showing=None, merged_in=None):
2607- from loggerhead import util
2608+ from . import util
2609 return _pt('revisioninfo').expand(
2610 url=url, change=entry, branch=branch, util=util,
2611 file_changes=file_changes, currently_showing=currently_showing,
2612@@ -142,11 +145,11 @@
2613
2614 @templatefunc
2615 def loggerhead_version():
2616- return loggerhead.__version__
2617-
2618+ return __version__
2619+
2620 @templatefunc
2621 def loggerhead_revision():
2622- return loggerhead.__revision__
2623+ return __revision__
2624
2625 _cached_generator_string = None
2626
2627@@ -159,13 +162,13 @@
2628 # TODO: Errors -- e.g. from a missing/invalid __version__ attribute, or
2629 # ValueError accessing Distribution.version -- should be non-fatal.
2630
2631- versions.append(('Loggerhead', loggerhead.__version__))
2632+ versions.append(('Loggerhead', __version__))
2633
2634 import sys
2635- python_version = bzrlib._format_version_tuple(sys.version_info)
2636+ python_version = breezy._format_version_tuple(sys.version_info)
2637 versions.append(('Python', python_version))
2638
2639- versions.append(('Bazaar', bzrlib.__version__))
2640+ versions.append(('Breezy', breezy.__version__))
2641
2642 Paste = pkg_resources.get_distribution('Paste')
2643 versions.append(('Paste', Paste.version))
2644@@ -188,11 +191,11 @@
2645 versions.append(('Pygments', pygments.__version__))
2646
2647 try:
2648- from bzrlib.plugins import search
2649+ from breezy.plugins import search
2650 except ImportError:
2651 pass
2652 else:
2653- bzr_search_version = bzrlib._format_version_tuple(
2654+ bzr_search_version = breezy._format_version_tuple(
2655 search.version_info)
2656 versions.append(('bzr-search', bzr_search_version))
2657
2658
2659=== modified file 'loggerhead/templates/directory.pt'
2660--- loggerhead/templates/directory.pt 2011-02-17 19:51:25 +0000
2661+++ loggerhead/templates/directory.pt 2019-09-18 16:50:15 +0000
2662@@ -2,6 +2,11 @@
2663 <html xmlns="http://www.w3.org/1999/xhtml" >
2664 <head>
2665 <title tal:content="string:Browsing ${name}"></title>
2666+ <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
2667+ <meta name="generator"
2668+ tal:attributes="content generator_string" />
2669+
2670+
2671 <link rel="stylesheet"
2672 tal:attributes="href python:static_url('/static/css/global.css')" />
2673 <link rel="shortcut icon"
2674@@ -17,16 +22,16 @@
2675 <div >
2676 <table id="logentries">
2677 <tr class="logheader">
2678- <th class="summarycell" colspan="2">Filename</th>
2679- <th class="datecell">Latest Rev</th>
2680+ <th class="datecell">Filename</th>
2681+ <th class="timedate">Latest Rev</th>
2682 <th class="datecell">Last Changed</th>
2683+ <th class="datecell">Committer</th>
2684+ <th class="summarycell">Comment</th>
2685 </tr>
2686
2687 <tr class="blueRow0" tal:condition="python:name != '/'">
2688- <td class="icocell">
2689+ <td class="summcell" colspan="5">
2690 <a href="../"><img tal:attributes="src python:static_url('/static/images/ico_folder_up.gif')" /></a>
2691- </td>
2692- <td class="summcell" colspan="3">
2693 <a href="../">..</a>
2694 </td>
2695 </tr>
2696@@ -34,37 +39,42 @@
2697
2698 <tal:branch-row tal:condition="dir/branch">
2699 <tr tal:attributes="class string:blueRow${dir/parity}">
2700- <td class="icocell">
2701+ <td class="date">
2702 <a tal:attributes="href string:${dir/dirname}/files">
2703 <img tal:attributes="src python:static_url('/static/images/ico_branch.gif')" alt="Branch" />
2704 </a>
2705- </td>
2706- <td class="autcell">
2707 <a tal:attributes="href string:${dir/dirname}/files" tal:content="dir/dirname" /></td>
2708 <td class="date">
2709 <a tal:attributes="href string:${dir/dirname}/revision/${dir/branch/revno};
2710 title string:Show revision ${dir/branch/revno}"
2711 tal:content="dir/branch/revno"></a>
2712 </td>
2713- <td class="date" tal:content="python:util.date_time(dir.last_change)"></td>
2714+ <td class="date" tal:content="python:util._approximatedate(dir.last_change_time)"></td>
2715+ <td class="date" tal:content="python:util.hide_email(dir.last_revision.committer) if dir.last_revision is not None else 'Nobody'"></td>
2716+ <td class="autcell" tal:content="python:dir.last_revision.message[:50] if dir.last_revision is not None else ''"></td>
2717 </tr>
2718+
2719 </tal:branch-row>
2720 <tal:non-branch-row tal:condition="not:dir/branch">
2721 <tr tal:attributes="class string:blueRow${dir/parity}">
2722- <td class="icocell">
2723+ <td class="date">
2724 <a tal:attributes="href string:${dir/dirname}/">
2725 <img tal:attributes="src python:static_url('/static/images/ico_folder.gif')" alt="Folder" />
2726 </a>
2727- </td>
2728- <td class="autcell">
2729 <a tal:attributes="href string:${dir/dirname}/" tal:content="dir/dirname" /></td>
2730 <td class="date"></td>
2731- <td class="date" tal:content="dir/last_change"></td>
2732+ <td class="date" colspan="4" tal:content="dir/last_change"></td>
2733 </tr>
2734 </tal:non-branch-row>
2735 </tal:block>
2736 </table>
2737 </div>
2738+
2739+ <p id="footer" class="fl">
2740+ Loggerhead is a web-based interface for <a href="https://www.breezy-vcs.org/">Breezy</a>
2741+ <br />
2742+ Version: <tal:version content="loggerhead_version" /><span tal:condition="loggerhead_revision">, Revision: <tal:revision content="loggerhead_revision" /></span>
2743+ </p>
2744 </div>
2745 </body>
2746 </html>
2747
2748=== modified file 'loggerhead/templates/inventory.pt'
2749--- loggerhead/templates/inventory.pt 2012-02-02 07:42:24 +0000
2750+++ loggerhead/templates/inventory.pt 2019-09-18 16:50:15 +0000
2751@@ -30,7 +30,7 @@
2752 <tal:no-link condition="not: branch/branch_link">
2753 <span metal:use-macro="breadcrumbs/directory"></span>
2754 </tal:no-link>
2755- <span>: <span metal:use-macro="breadcrumbs/branch" /> (revision <tal:revno content="change/revno"></tal:revno>)</span>
2756+ <span>: <span metal:use-macro="breadcrumbs/branch" /> (Revision <tal:revno content="change/revno"></tal:revno>)</span>
2757 </div>
2758 </tal:block>
2759
2760@@ -54,10 +54,12 @@
2761
2762 <table id="logentries">
2763 <tr class="logheader">
2764- <th class="summarycell"><a tal:attributes="href python:url(['/files', revid], sort='filename')">Filename</a></th>
2765- <th class="datecell">Latest Rev</th>
2766- <th class="datecell"><a tal:attributes="href python:url(['/files', revid], sort='date')">Last Changed</a></th>
2767- <th class="timedate"><a tal:attributes="href python:url(['/files', revid], sort='size')">Size</a></th>
2768+ <th class="datecell"><a tal:attributes="href python:branch.sort_url(['/files', revid], sort='filename')">Filename</a></th>
2769+ <th class="timedate">Latest Rev</th>
2770+ <th class="datecell"><a tal:attributes="href python:branch.sort_url(['/files', revid], sort='date')">Last Changed</a></th>
2771+ <th class="datecell">Committer</th>
2772+ <th class="summarycell">Comment</th>
2773+ <th class="timedate"><a tal:attributes="href python:branch.sort_url(['/files', revid], sort='size')">Size</a></th>
2774 <th class="expandcell"></th>
2775 <th class="expandcell"></th>
2776 </tr>
2777@@ -68,11 +70,15 @@
2778 <img tal:attributes="src python:branch.static_url('/static/images/ico_folder_up.gif')" />..</a>
2779 </td>
2780 </tr>
2781+ <tr class="blueRow0" tal:condition="python:updir is None">
2782+ <td class="summcell" colspan="6">
2783+ <a tal:attributes="href python:'/'.join(branch.friendly_name.split('/')[:-1])"><img tal:attributes="src python:static_url('/static/images/ico_folder_up.gif')" />..</a></td>
2784+ </tr>
2785
2786 <!-- Show this if it's a directory -->
2787 <tal:block repeat="file filelist">
2788 <tr tal:attributes="class string:blueRow${repeat/file/even}" tal:condition="python:file.kind=='directory'">
2789- <td class="autcell"><a tal:attributes="href python:url(['/files', revno_url, file.absolutepath])">
2790+ <td class="date"><a tal:attributes="href python:url(['/files', revno_url, file.absolutepath])">
2791 <img tal:attributes="src python:branch.static_url('/static/images/ico_folder.gif');
2792 title string:Go to ${file/filename}" />
2793 </a>
2794@@ -84,8 +90,10 @@
2795 title string:Show revision ${file/change/revno}"
2796 tal:content="file/change/revno"></a>
2797 </td>
2798- <td class="date" tal:content="python:util.date_time(file.change.utc_date)"></td>
2799- <td class="timedate2"></td>
2800+ <td class="date" tal:content="python:util._approximatedate(file.change.utc_date)"></td>
2801+ <td class="date" tal:content="python:util.hide_email(file.change.committer)"></td>
2802+ <td class="autcell" tal:content="python:file.change.comment[:50]"></td>
2803+ <td class="timedate2"></td><!-- not showing sizes of folders -->
2804 <td class="expcell"><a tal:attributes="href python:url(['/changes'], start_revid=start_revid, filter_file_id=file.file_id);
2805 title string:Show revision ${file/change/revno}">
2806 <img tal:attributes="src python:branch.static_url('/static/images/ico_planilla.gif')" alt="Diff" />
2807@@ -96,7 +104,7 @@
2808
2809 <!-- Show this if it's a symlink -->
2810 <tr tal:attributes="class string:blueRow${repeat/file/even}" tal:condition="python:file.kind=='symlink'">
2811- <td class="autcell"><a tal:attributes="href python:url(['/view', change.revno, file.absolutepath])">
2812+ <td class="date"><a tal:attributes="href python:url(['/view', change.revno, file.absolutepath])">
2813 <img tal:attributes="src python:branch.static_url('/static/images/ico_file_flecha.gif')" alt="Symlink" />
2814 </a>
2815
2816@@ -107,7 +115,9 @@
2817 title string:Show revision ${file/change/revno}"
2818 tal:content="file/change/revno"></a>
2819 </td>
2820- <td class="date" tal:content="python:util.date_time(file.change.utc_date)"></td>
2821+ <td class="date" tal:content="python:util._approximatedate(file.change.utc_date)"></td>
2822+ <td class="date" tal:content="python:util.hide_email(file.change.committer)"></td>
2823+ <td class="autcell" tal:content="python:file.change.comment[:50]"></td>
2824 <td class="timedate2">.</td>
2825 <td class="expcell"><a tal:attributes="href python:url(['/changes'], start_revid=start_revid, filter_file_id=file.file_id);
2826 title string:Show revision ${file/change/revno}">
2827@@ -120,7 +130,7 @@
2828
2829 <!-- Show this if it's a regular file -->
2830 <tr tal:attributes="class string:blueRow${repeat/file/even}" tal:condition="python:file.kind=='file'">
2831- <td class="autcell"><a tal:attributes="href python:url(['/view', revno_url, file.absolutepath])">
2832+ <td class="date"><a tal:attributes="href python:url(['/view', revno_url, file.absolutepath])">
2833 <img tal:attributes="src python:branch.static_url('/static/images/ico_file.gif');
2834 title string:View ${file/filename}"
2835 tal:condition="python:file.executable is False" />
2836@@ -136,7 +146,10 @@
2837 title string:Show revision ${file/change/revno}"
2838 tal:content="file/change/revno"></a>
2839 </td>
2840- <td class="date" tal:content="python:util.date_time(file.change.utc_date)"></td>
2841+ <td class="date" tal:content="python:util._approximatedate(file.change.utc_date)"></td>
2842+ <td class="date" tal:content="python:util.hide_email(file.change.committer)"></td>
2843+ <td class="autcell" tal:content="python:file.change.comment[:50]"></td>
2844+
2845 <td class="timedate2" tal:content="python:util.human_size(file.size)"></td>
2846 <td class="expcell"><a tal:attributes="href python:url(['/view', revno_url, file.absolutepath]);
2847 title string:View ${file/filename}">
2848@@ -144,7 +157,7 @@
2849 </a>
2850 </td>
2851 <td class="expcell">
2852- <a tal:attributes="href python:url(['/download', file.revid, file.file_id, file.filename]);
2853+ <a tal:attributes="href python:url(['/download', file.revid.decode('utf-8'), file.file_id.decode('utf-8'), file.filename]);
2854 title string:Download ${file/filename} at revision ${file/change/revno}">
2855 <img tal:attributes="src python:branch.static_url('/static/images/ico_file_download.gif')" alt="Download File" />
2856 </a>
2857
2858=== modified file 'loggerhead/templates/macros.pt'
2859--- loggerhead/templates/macros.pt 2012-05-03 21:39:50 +0000
2860+++ loggerhead/templates/macros.pt 2019-09-18 16:50:15 +0000
2861@@ -60,7 +60,7 @@
2862 <div metal:define-slot="content"></div>
2863
2864 <p id="footer" class="fl">
2865- Loggerhead is a web-based interface for <a href="http://bazaar-vcs.org/">Bazaar</a> branches
2866+ Loggerhead is a web-based interface for <a href="https://www.breezy-vcs.org/">Breezy</a>
2867 <br />
2868 Version: <tal:version content="loggerhead_version" /><span tal:condition="loggerhead_revision">, Revision: <tal:revision content="loggerhead_revision" /></span>
2869 </p>
2870
2871=== modified file 'loggerhead/tests/__init__.py'
2872--- loggerhead/tests/__init__.py 2011-09-08 00:33:28 +0000
2873+++ loggerhead/tests/__init__.py 2019-09-18 16:50:15 +0000
2874@@ -15,8 +15,13 @@
2875 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2876
2877
2878-def load_tests(standard_tests, module, loader):
2879- standard_tests.addTests(loader.loadTestsFromModuleNames([
2880+from __future__ import absolute_import
2881+
2882+
2883+def test_suite():
2884+ import unittest
2885+ loader = unittest.TestLoader()
2886+ return loader.loadTestsFromNames([
2887 (__name__ + '.' + x) for x in [
2888 'test_controllers',
2889 'test_corners',
2890@@ -27,5 +32,4 @@
2891 'test_revision_ui',
2892 'test_templating',
2893 'test_util',
2894- ]]))
2895- return standard_tests
2896+ ]])
2897
2898=== modified file 'loggerhead/tests/fixtures.py'
2899--- loggerhead/tests/fixtures.py 2011-11-25 02:28:56 +0000
2900+++ loggerhead/tests/fixtures.py 2019-09-18 16:50:15 +0000
2901@@ -37,7 +37,7 @@
2902 self.testcase.build_tree_contents(
2903 (filename, self.filecontents) for filename in filenames)
2904 for filename in filenames:
2905- self.tree.add(filename, '%s-id' % filename)
2906+ self.tree.add(filename, ('%s-id' % filename).encode('utf-8'))
2907 self.fileid = self.tree.path2id('myfilename')
2908 self.msg = 'a very exciting commit message <'
2909 self.revid = self.tree.commit(message=self.msg)
2910
2911=== modified file 'loggerhead/tests/test_controllers.py'
2912--- loggerhead/tests/test_controllers.py 2016-09-04 15:13:21 +0000
2913+++ loggerhead/tests/test_controllers.py 2019-09-18 16:50:15 +0000
2914@@ -14,6 +14,8 @@
2915 # along with this program; if not, write to the Free Software
2916 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2917
2918+from __future__ import absolute_import
2919+
2920 import tarfile
2921 import tempfile
2922
2923@@ -27,10 +29,10 @@
2924 Mismatch,
2925 )
2926
2927-from loggerhead.apps.branch import BranchWSGIApp
2928-from loggerhead.controllers.annotate_ui import AnnotateUI
2929-from loggerhead.controllers.inventory_ui import InventoryUI
2930-from loggerhead.tests.test_simple import (
2931+from ..apps.branch import BranchWSGIApp
2932+from ..controllers.annotate_ui import AnnotateUI
2933+from ..controllers.inventory_ui import InventoryUI
2934+from .test_simple import (
2935 BasicTests,
2936 consume_app,
2937 TestWithSimpleTree,
2938@@ -55,8 +57,8 @@
2939 def test_get_filelist(self):
2940 bzrbranch, inv_ui = self.make_bzrbranch_and_inventory_ui_for_tree_shape(
2941 ['filename'])
2942- inv = bzrbranch.repository.get_inventory(bzrbranch.last_revision())
2943- self.assertEqual(1, len(inv_ui.get_filelist(inv, '', 'filename', 'head')))
2944+ revtree = bzrbranch.repository.revision_tree(bzrbranch.last_revision())
2945+ self.assertEqual(1, len(inv_ui.get_filelist(revtree, '', 'filename', 'head')))
2946
2947 def test_smoke(self):
2948 bzrbranch, inv_ui = self.make_bzrbranch_and_inventory_ui_for_tree_shape(
2949@@ -65,23 +67,29 @@
2950 {'SCRIPT_NAME': '/files', 'PATH_INFO': ''})
2951 self.assertEqual(('200 OK', [('Content-Type', 'text/html')], None),
2952 start)
2953- self.assertContainsRe(content, 'filename')
2954+ self.assertContainsRe(content, b'filename')
2955
2956 def test_no_content_for_HEAD(self):
2957 bzrbranch, inv_ui = self.make_bzrbranch_and_inventory_ui_for_tree_shape(
2958 ['filename'])
2959 start, content = consume_app(inv_ui,
2960 {'SCRIPT_NAME': '/files', 'PATH_INFO': '',
2961- 'REQUEST_METHOD': 'HEAD'})
2962+ 'REQUEST_METHOD': 'HEAD',
2963+ 'wsgi.url_scheme': 'http',
2964+ 'SERVER_NAME': 'localhost',
2965+ 'SERVER_PORT': '80'})
2966 self.assertEqual(('200 OK', [('Content-Type', 'text/html')], None),
2967 start)
2968- self.assertEqual('', content)
2969+ self.assertEqual(b'', content)
2970
2971 def test_get_values_smoke(self):
2972 branch = self.make_bzrbranch_for_tree_shape(['a-file'])
2973 branch_app = self.make_branch_app(branch)
2974 env = {'SCRIPT_NAME': '', 'PATH_INFO': '/files',
2975- 'REQUEST_METHOD': 'GET'}
2976+ 'REQUEST_METHOD': 'GET',
2977+ 'wsgi.url_scheme': 'http',
2978+ 'SERVER_NAME': 'localhost',
2979+ 'SERVER_PORT': '80'}
2980 inv_ui = branch_app.lookup_app(env)
2981 inv_ui.parse_args(env)
2982 values = inv_ui.get_values('', {}, {})
2983@@ -91,7 +99,10 @@
2984 branch = self.make_bzrbranch_for_tree_shape(['a-file'])
2985 branch_app = self.make_branch_app(branch)
2986 env = {'SCRIPT_NAME': '', 'PATH_INFO': '/+json/files',
2987- 'REQUEST_METHOD': 'GET'}
2988+ 'REQUEST_METHOD': 'GET',
2989+ 'wsgi.url_scheme': 'http',
2990+ 'SERVER_NAME': 'localhost',
2991+ 'SERVER_PORT': '80'}
2992 inv_ui = branch_app.lookup_app(env)
2993 self.assertOkJsonResponse(inv_ui, env)
2994
2995@@ -102,10 +113,10 @@
2996 tree = self.make_branch_and_tree('.')
2997 self.build_tree_contents(shape1)
2998 tree.smart_add([])
2999- tree.commit('msg 1', rev_id='rev-1')
3000+ tree.commit('msg 1', rev_id=b'rev-1')
3001 self.build_tree_contents(shape2)
3002 tree.smart_add([])
3003- tree.commit('msg 2', rev_id='rev-2')
3004+ tree.commit('msg 2', rev_id=b'rev-2')
3005 branch = tree.branch
3006 self.addCleanup(branch.lock_read().unlock)
3007 return self.make_branch_app(branch)
3008@@ -113,18 +124,24 @@
3009 def test_get_values(self):
3010 branch_app = self.make_branch_app_for_revision_ui([], [])
3011 env = {'SCRIPT_NAME': '', 'PATH_INFO': '/revision/2',
3012- 'REQUEST_METHOD': 'GET'}
3013+ 'REQUEST_METHOD': 'GET',
3014+ 'wsgi.url_scheme': 'http',
3015+ 'SERVER_NAME': 'localhost',
3016+ 'SERVER_PORT': '80'}
3017 rev_ui = branch_app.lookup_app(env)
3018 rev_ui.parse_args(env)
3019 self.assertIsInstance(rev_ui.get_values('', {}, []), dict)
3020
3021 def test_add_template_values(self):
3022 branch_app = self.make_branch_app_for_revision_ui(
3023- [('file', 'content\n')], [('file', 'new content\n')])
3024+ [('file', b'content\n')], [('file', b'new content\n')])
3025 env = {'SCRIPT_NAME': '/',
3026 'PATH_INFO': '/revision/1/non-existent-file',
3027 'QUERY_STRING':'start_revid=1',
3028- 'REQUEST_METHOD': 'GET'}
3029+ 'REQUEST_METHOD': 'GET',
3030+ 'wsgi.url_scheme': 'http',
3031+ 'SERVER_NAME': 'localhost',
3032+ 'SERVER_PORT': '80'}
3033 revision_ui = branch_app.lookup_app(env)
3034 path = revision_ui.parse_args(env)
3035 values = revision_ui.get_values(path, revision_ui.kwargs, {})
3036@@ -133,11 +150,14 @@
3037
3038 def test_get_values_smoke(self):
3039 branch_app = self.make_branch_app_for_revision_ui(
3040- [('file', 'content\n'), ('other-file', 'other\n')],
3041- [('file', 'new content\n')])
3042+ [('file', b'content\n'), ('other-file', b'other\n')],
3043+ [('file', b'new content\n')])
3044 env = {'SCRIPT_NAME': '/',
3045 'PATH_INFO': '/revision/head:',
3046- 'REQUEST_METHOD': 'GET'}
3047+ 'REQUEST_METHOD': 'GET',
3048+ 'wsgi.url_scheme': 'http',
3049+ 'SERVER_NAME': 'localhost',
3050+ 'SERVER_PORT': '80'}
3051 revision_ui = branch_app.lookup_app(env)
3052 revision_ui.parse_args(env)
3053 values = revision_ui.get_values('', {}, {})
3054@@ -149,10 +169,13 @@
3055
3056 def test_json_render_smoke(self):
3057 branch_app = self.make_branch_app_for_revision_ui(
3058- [('file', 'content\n'), ('other-file', 'other\n')],
3059- [('file', 'new content\n')])
3060+ [('file', b'content\n'), ('other-file', b'other\n')],
3061+ [('file', b'new content\n')])
3062 env = {'SCRIPT_NAME': '', 'PATH_INFO': '/+json/revision/head:',
3063- 'REQUEST_METHOD': 'GET'}
3064+ 'REQUEST_METHOD': 'GET',
3065+ 'wsgi.url_scheme': 'http',
3066+ 'SERVER_NAME': 'localhost',
3067+ 'SERVER_PORT': '80'}
3068 revision_ui = branch_app.lookup_app(env)
3069 self.assertOkJsonResponse(revision_ui, env)
3070
3071@@ -172,8 +195,8 @@
3072 return AnnotateUI(branch_app, branch_app.get_history)
3073
3074 def test_annotate_file(self):
3075- history = [('rev1', 'old\nold\n', '.'), ('rev2', 'new\nold\n', '.')]
3076- ann_ui = self.make_annotate_ui_for_file_history('file_id', history)
3077+ history = [(b'rev1', b'old\nold\n', '.'), (b'rev2', b'new\nold\n', '.')]
3078+ ann_ui = self.make_annotate_ui_for_file_history(b'file_id', history)
3079 # A lot of this state is set up by __call__, but we'll do it directly
3080 # here.
3081 ann_ui.args = ['rev2']
3082@@ -186,8 +209,8 @@
3083
3084 def test_annotate_empty_comment(self):
3085 # Testing empty comment handling without breaking
3086- history = [('rev1', 'old\nold\n', '.'), ('rev2', 'new\nold\n', '')]
3087- ann_ui = self.make_annotate_ui_for_file_history('file_id', history)
3088+ history = [(b'rev1', b'old\nold\n', '.'), (b'rev2', b'new\nold\n', '')]
3089+ ann_ui = self.make_annotate_ui_for_file_history(b'file_id', history)
3090 ann_ui.args = ['rev2']
3091 ann_ui.get_values(
3092 'filename', kwargs={'file_id': 'file_id'}, headers={})
3093@@ -195,8 +218,8 @@
3094 def test_annotate_file_zero_sized(self):
3095 # Test against a zero-sized file without breaking. No annotation
3096 # must be present.
3097- history = [('rev1', '', '.')]
3098- ann_ui = self.make_annotate_ui_for_file_history('file_id', history)
3099+ history = [(b'rev1', b'', '.')]
3100+ ann_ui = self.make_annotate_ui_for_file_history(b'file_id', history)
3101 ann_ui.args = ['rev1']
3102 annotate_info = ann_ui.get_values('filename',
3103 kwargs={'file_id': 'file_id'}, headers={})
3104@@ -204,15 +227,15 @@
3105 self.assertEqual(0, len(annotated))
3106
3107 def test_annotate_nonexistent_file(self):
3108- history = [('rev1', '', '.')]
3109- ann_ui = self.make_annotate_ui_for_file_history('file_id', history)
3110+ history = [(b'rev1', b'', '.')]
3111+ ann_ui = self.make_annotate_ui_for_file_history(b'file_id', history)
3112 ann_ui.args = ['rev1']
3113 self.assertRaises(
3114 HTTPNotFound, ann_ui.get_values, 'not-filename', {}, {})
3115
3116 def test_annotate_nonexistent_rev(self):
3117- history = [('rev1', '', '.')]
3118- ann_ui = self.make_annotate_ui_for_file_history('file_id', history)
3119+ history = [(b'rev1', b'', '.')]
3120+ ann_ui = self.make_annotate_ui_for_file_history(b'file_id', history)
3121 ann_ui.args = ['norev']
3122 self.assertRaises(
3123 HTTPNotFound, ann_ui.get_values, 'not-filename', {}, {})
3124@@ -223,22 +246,25 @@
3125 def make_branch_app_for_filediff_ui(self):
3126 builder = self.make_branch_builder('branch')
3127 builder.start_series()
3128- builder.build_snapshot('rev-1-id', None, [
3129- ('add', ('', 'root-id', 'directory', '')),
3130- ('add', ('filename', 'f-id', 'file', 'content\n'))],
3131+ rev1 = builder.build_snapshot(None, [
3132+ ('add', ('', b'root-id', 'directory', '')),
3133+ ('add', ('filename', b'f-id', 'file', b'content\n'))],
3134 message="First commit.")
3135- builder.build_snapshot('rev-2-id', None, [
3136- ('modify', ('f-id', 'new content\n'))])
3137+ rev2 = builder.build_snapshot(None, [
3138+ ('modify', ('filename', b'new content\n'))])
3139 builder.finish_series()
3140 branch = builder.get_branch()
3141 self.addCleanup(branch.lock_read().unlock)
3142- return self.make_branch_app(branch)
3143+ return self.make_branch_app(branch), (rev1, rev2)
3144
3145 def test_get_values_smoke(self):
3146- branch_app = self.make_branch_app_for_filediff_ui()
3147+ branch_app, (rev1, rev2) = self.make_branch_app_for_filediff_ui()
3148 env = {'SCRIPT_NAME': '/',
3149- 'PATH_INFO': '/+filediff/rev-2-id/rev-1-id/f-id',
3150- 'REQUEST_METHOD': 'GET'}
3151+ 'PATH_INFO': '/+filediff/%s/%s/f-id' % (rev2.decode('utf-8'), rev1.decode('utf-8')),
3152+ 'REQUEST_METHOD': 'GET',
3153+ 'wsgi.url_scheme': 'http',
3154+ 'SERVER_NAME': 'localhost',
3155+ 'SERVER_PORT': '80'}
3156 filediff_ui = branch_app.lookup_app(env)
3157 filediff_ui.parse_args(env)
3158 values = filediff_ui.get_values('', {}, {})
3159@@ -247,10 +273,13 @@
3160 self.assertEqual('new content', chunks[0].diff[1].line)
3161
3162 def test_json_render_smoke(self):
3163- branch_app = self.make_branch_app_for_filediff_ui()
3164+ branch_app, (rev1, rev2) = self.make_branch_app_for_filediff_ui()
3165 env = {'SCRIPT_NAME': '/',
3166- 'PATH_INFO': '/+json/+filediff/rev-2-id/rev-1-id/f-id',
3167- 'REQUEST_METHOD': 'GET'}
3168+ 'PATH_INFO': '/+json/+filediff/%s/%s/f-id' % (rev2.decode('utf-8'), rev1.decode('utf-8')),
3169+ 'REQUEST_METHOD': 'GET',
3170+ 'wsgi.url_scheme': 'http',
3171+ 'SERVER_NAME': 'localhost',
3172+ 'SERVER_PORT': '80'}
3173 filediff_ui = branch_app.lookup_app(env)
3174 self.assertOkJsonResponse(filediff_ui, env)
3175
3176@@ -260,20 +289,23 @@
3177 def make_branch_app_for_revlog_ui(self):
3178 builder = self.make_branch_builder('branch')
3179 builder.start_series()
3180- builder.build_snapshot('rev-id', None, [
3181- ('add', ('', 'root-id', 'directory', '')),
3182- ('add', ('filename', 'f-id', 'file', 'content\n'))],
3183+ revid = builder.build_snapshot(None, [
3184+ ('add', ('', b'root-id', 'directory', '')),
3185+ ('add', ('filename', b'f-id', 'file', b'content\n'))],
3186 message="First commit.")
3187 builder.finish_series()
3188 branch = builder.get_branch()
3189 self.addCleanup(branch.lock_read().unlock)
3190- return self.make_branch_app(branch)
3191+ return self.make_branch_app(branch), revid
3192
3193 def test_get_values_smoke(self):
3194- branch_app = self.make_branch_app_for_revlog_ui()
3195+ branch_app, revid = self.make_branch_app_for_revlog_ui()
3196 env = {'SCRIPT_NAME': '/',
3197- 'PATH_INFO': '/+revlog/rev-id',
3198- 'REQUEST_METHOD': 'GET'}
3199+ 'PATH_INFO': '/+revlog/%s' % revid.decode('utf-8'),
3200+ 'REQUEST_METHOD': 'GET',
3201+ 'wsgi.url_scheme': 'http',
3202+ 'SERVER_NAME': 'localhost',
3203+ 'SERVER_PORT': '80'}
3204 revlog_ui = branch_app.lookup_app(env)
3205 revlog_ui.parse_args(env)
3206 values = revlog_ui.get_values('', {}, {})
3207@@ -281,9 +313,12 @@
3208 self.assertEqual(values['entry'].comment, "First commit.")
3209
3210 def test_json_render_smoke(self):
3211- branch_app = self.make_branch_app_for_revlog_ui()
3212- env = {'SCRIPT_NAME': '', 'PATH_INFO': '/+json/+revlog/rev-id',
3213- 'REQUEST_METHOD': 'GET'}
3214+ branch_app, revid = self.make_branch_app_for_revlog_ui()
3215+ env = {'SCRIPT_NAME': '', 'PATH_INFO': '/+json/+revlog/%s' % revid.decode('utf-8'),
3216+ 'REQUEST_METHOD': 'GET',
3217+ 'wsgi.url_scheme': 'http',
3218+ 'SERVER_NAME': 'localhost',
3219+ 'SERVER_PORT': '80'}
3220 revlog_ui = branch_app.lookup_app(env)
3221 self.assertOkJsonResponse(revlog_ui, env)
3222
3223@@ -295,7 +330,10 @@
3224 # A hook that returns None doesn't influence the searching for
3225 # a controller.
3226 env = {'SCRIPT_NAME': '', 'PATH_INFO': '/custom',
3227- 'REQUEST_METHOD': 'GET'}
3228+ 'REQUEST_METHOD': 'GET',
3229+ 'wsgi.url_scheme': 'http',
3230+ 'SERVER_NAME': 'localhost',
3231+ 'SERVER_PORT': '80'}
3232 myhook = lambda app, environ: None
3233 branch = self.make_branch('.')
3234 self.addCleanup(branch.lock_read().unlock)
3235@@ -308,7 +346,10 @@
3236 def test_working_hook(self):
3237 # A hook can provide an app to use for a particular request.
3238 env = {'SCRIPT_NAME': '', 'PATH_INFO': '/custom',
3239- 'REQUEST_METHOD': 'GET'}
3240+ 'REQUEST_METHOD': 'GET',
3241+ 'wsgi.url_scheme': 'http',
3242+ 'SERVER_NAME': 'localhost',
3243+ 'SERVER_PORT': '80'}
3244 myhook = lambda app, environ: "I am hooked"
3245 branch = self.make_branch('.')
3246 self.addCleanup(branch.lock_read().unlock)
3247@@ -348,7 +389,7 @@
3248 app = self.setUpLoggerhead()
3249 response = app.get('/download/1/myfilename-id/myfilename')
3250 self.assertEqual(
3251- 'some\nmultiline\ndata\nwith<htmlspecialchars\n', response.body)
3252+ b'some\nmultiline\ndata\nwith<htmlspecialchars\n', response.body)
3253 self.assertThat(
3254 response,
3255 MatchesDownloadHeaders('myfilename', 'application/octet-stream'))
3256
3257=== modified file 'loggerhead/tests/test_corners.py'
3258--- loggerhead/tests/test_corners.py 2009-04-02 20:32:12 +0000
3259+++ loggerhead/tests/test_corners.py 2019-09-18 16:50:15 +0000
3260@@ -1,6 +1,8 @@
3261+from __future__ import absolute_import
3262+
3263 import os
3264
3265-from loggerhead.tests.test_simple import BasicTests
3266+from .test_simple import BasicTests
3267
3268
3269 class TestCornerCases(BasicTests):
3270@@ -26,19 +28,19 @@
3271 self.addFileAndCommit('myfilename', msg)
3272
3273 # Make a commit that changes the execute bit of 'myfilename'.
3274- os.chmod('myfilename', 0755)
3275+ os.chmod('myfilename', 0o755)
3276 newrevid = self.tree.commit(message='make something executable')
3277
3278 # Check that it didn't break things.
3279 app = self.setUpLoggerhead()
3280- res = app.get('/revision/'+newrevid)
3281- res.mustcontain('executable')
3282+ res = app.get('/revision/'+newrevid.decode('utf-8'))
3283+ res.mustcontain(b'executable')
3284
3285 def test_revision_escapes_commit_message(self):
3286 """XXX."""
3287 self.createBranch()
3288
3289- msg = '<b>hi</b>'
3290+ msg = b'<b>hi</b>'
3291 self.addFileAndCommit('myfilename', msg)
3292 app = self.setUpLoggerhead()
3293 res = app.get('/revision/1')
3294
3295=== modified file 'loggerhead/tests/test_history.py'
3296--- loggerhead/tests/test_history.py 2011-03-25 13:09:10 +0000
3297+++ loggerhead/tests/test_history.py 2019-09-18 16:50:15 +0000
3298@@ -17,16 +17,16 @@
3299
3300 """Direct tests of the loggerhead/history.py module"""
3301
3302-from bzrlib.foreign import (
3303+from breezy.foreign import (
3304 ForeignRevision,
3305 ForeignVcs,
3306 VcsMapping,
3307 )
3308
3309 from datetime import datetime
3310-from bzrlib import tag, tests
3311+from breezy import tag, tests
3312
3313-from loggerhead import history as _mod_history
3314+from .. import history as _mod_history
3315
3316
3317 class TestCaseWithExamples(tests.TestCaseWithMemoryTransport):
3318@@ -40,26 +40,27 @@
3319 # rev-1
3320 builder = self.make_branch_builder('branch')
3321 builder.start_series()
3322- builder.build_snapshot('rev-1', None, [
3323- ('add', ('', 'root-id', 'directory', None))])
3324- builder.build_snapshot('rev-2', ['rev-1'], [])
3325- builder.build_snapshot('rev-3', ['rev-2'], [])
3326+ rev1 = builder.build_snapshot(None, [
3327+ ('add', ('', b'root-id', 'directory', None))])
3328+ rev2 = builder.build_snapshot([rev1], [])
3329+ rev3 = builder.build_snapshot([rev2], [])
3330 builder.finish_series()
3331 b = builder.get_branch()
3332 self.addCleanup(b.lock_read().unlock)
3333- return _mod_history.History(b, {})
3334+ return _mod_history.History(b, {}), [rev1, rev2, rev3]
3335
3336 def make_long_linear_ancestry(self):
3337 builder = self.make_branch_builder('branch')
3338+ revs = []
3339 builder.start_series()
3340- builder.build_snapshot('A', None, [
3341- ('add', ('', 'root-id', 'directory', None))])
3342+ revs.append(builder.build_snapshot(None, [
3343+ ('add', ('', b'root-id', 'directory', None))]))
3344 for r in "BCDEFGHIJKLMNOPQRSTUVWXYZ":
3345- builder.build_snapshot(r, None, [])
3346+ revs.append(builder.build_snapshot(None, []))
3347 builder.finish_series()
3348 b = builder.get_branch()
3349 self.addCleanup(b.lock_read().unlock)
3350- return _mod_history.History(b, {})
3351+ return _mod_history.History(b, {}), revs
3352
3353 def make_merged_ancestry(self):
3354 # Time goes up
3355@@ -70,14 +71,14 @@
3356 # rev-1
3357 builder = self.make_branch_builder('branch')
3358 builder.start_series()
3359- builder.build_snapshot('rev-1', None, [
3360- ('add', ('', 'root-id', 'directory', None))])
3361- builder.build_snapshot('rev-2', ['rev-1'], [])
3362- builder.build_snapshot('rev-3', ['rev-1', 'rev-2'], [])
3363+ rev1 = builder.build_snapshot(None, [
3364+ ('add', ('', b'root-id', 'directory', None))])
3365+ rev2 = builder.build_snapshot([rev1], [])
3366+ rev3 = builder.build_snapshot([rev1, rev2], [])
3367 builder.finish_series()
3368 b = builder.get_branch()
3369 self.addCleanup(b.lock_read().unlock)
3370- return _mod_history.History(b, {})
3371+ return _mod_history.History(b, {}), [rev1, rev2, rev3]
3372
3373 def make_deep_merged_ancestry(self):
3374 # Time goes up
3375@@ -92,17 +93,18 @@
3376 # A
3377 builder = self.make_branch_builder('branch')
3378 builder.start_series()
3379- builder.build_snapshot('A', None, [
3380- ('add', ('', 'root-id', 'directory', None))])
3381- builder.build_snapshot('B', ['A'], [])
3382- builder.build_snapshot('C', ['A'], [])
3383- builder.build_snapshot('D', ['C'], [])
3384- builder.build_snapshot('E', ['C', 'D'], [])
3385- builder.build_snapshot('F', ['B', 'E'], [])
3386+ rev_a = builder.build_snapshot(None, [
3387+ ('add', ('', b'root-id', 'directory', None))])
3388+ rev_b = builder.build_snapshot([rev_a], [])
3389+ rev_c = builder.build_snapshot([rev_a], [])
3390+ rev_d = builder.build_snapshot([rev_c], [])
3391+ rev_e = builder.build_snapshot([rev_c, rev_d], [])
3392+ rev_f = builder.build_snapshot([rev_b, rev_e], [])
3393 builder.finish_series()
3394 b = builder.get_branch()
3395 self.addCleanup(b.lock_read().unlock)
3396- return _mod_history.History(b, {})
3397+ return (_mod_history.History(b, {}),
3398+ [rev_a, rev_b, rev_c, rev_d, rev_e, rev_f])
3399
3400 def assertRevidsFrom(self, expected, history, search_revs, tip_rev):
3401 self.assertEqual(expected,
3402@@ -136,59 +138,58 @@
3403 class TestHistoryGetRevidsFrom(TestCaseWithExamples):
3404
3405 def test_get_revids_from_simple_mainline(self):
3406- history = self.make_linear_ancestry()
3407- self.assertRevidsFrom(['rev-3', 'rev-2', 'rev-1'],
3408- history, None, 'rev-3')
3409+ history, revs = self.make_linear_ancestry()
3410+ self.assertRevidsFrom(list(reversed(revs)), history, None, revs[2])
3411
3412 def test_get_revids_from_merged_mainline(self):
3413- history = self.make_merged_ancestry()
3414- self.assertRevidsFrom(['rev-3', 'rev-1'],
3415- history, None, 'rev-3')
3416+ history, revs = self.make_merged_ancestry()
3417+ self.assertRevidsFrom([revs[2], revs[0]],
3418+ history, None, revs[2])
3419
3420 def test_get_revids_given_one_rev(self):
3421- history = self.make_merged_ancestry()
3422+ history, revs = self.make_merged_ancestry()
3423 # rev-3 was the first mainline revision to see rev-2.
3424- self.assertRevidsFrom(['rev-3'], history, ['rev-2'], 'rev-3')
3425+ self.assertRevidsFrom([revs[2]], history, [revs[1]], revs[2])
3426
3427 def test_get_revids_deep_ancestry(self):
3428- history = self.make_deep_merged_ancestry()
3429- self.assertRevidsFrom(['F'], history, ['F'], 'F')
3430- self.assertRevidsFrom(['F'], history, ['E'], 'F')
3431- self.assertRevidsFrom(['F'], history, ['D'], 'F')
3432- self.assertRevidsFrom(['F'], history, ['C'], 'F')
3433- self.assertRevidsFrom(['B'], history, ['B'], 'F')
3434- self.assertRevidsFrom(['A'], history, ['A'], 'F')
3435+ history, revs = self.make_deep_merged_ancestry()
3436+ self.assertRevidsFrom([revs[-1]], history, [revs[-1]], revs[-1])
3437+ self.assertRevidsFrom([revs[-1]], history, [revs[-2]], revs[-1])
3438+ self.assertRevidsFrom([revs[-1]], history, [revs[-3]], revs[-1])
3439+ self.assertRevidsFrom([revs[-1]], history, [revs[-4]], revs[-1])
3440+ self.assertRevidsFrom([revs[1]], history, [revs[-5]], revs[-1])
3441+ self.assertRevidsFrom([revs[0]], history, [revs[-6]], revs[-1])
3442
3443 def test_get_revids_doesnt_over_produce_simple_mainline(self):
3444 # get_revids_from shouldn't walk the whole ancestry just to get the
3445 # answers for the first few revisions.
3446- history = self.make_long_linear_ancestry()
3447+ history, revs = self.make_long_linear_ancestry()
3448 accessed = track_rev_info_accesses(history)
3449- result = history.get_revids_from(None, 'Z')
3450- self.assertEqual(set(), accessed)
3451- self.assertEqual('Z', result.next())
3452- # We already know 'Z' because we passed it in.
3453- self.assertEqual(set(), accessed)
3454- self.assertEqual('Y', result.next())
3455- self.assertEqual(set([history._rev_indices['Z']]), accessed)
3456+ result = history.get_revids_from(None, revs[-1])
3457+ self.assertEqual(set(), accessed)
3458+ self.assertEqual(revs[-1], next(result))
3459+ # We already know revs[-1] because we passed it in.
3460+ self.assertEqual(set(), accessed)
3461+ self.assertEqual(revs[-2], next(result))
3462+ self.assertEqual(set([history._rev_indices[revs[-1]]]), accessed)
3463
3464 def test_get_revids_doesnt_over_produce_for_merges(self):
3465 # get_revids_from shouldn't walk the whole ancestry just to get the
3466 # answers for the first few revisions.
3467- history = self.make_long_linear_ancestry()
3468+ history, revs = self.make_long_linear_ancestry()
3469 accessed = track_rev_info_accesses(history)
3470- result = history.get_revids_from(['X', 'V'], 'Z')
3471+ result = history.get_revids_from([revs[-3], revs[-5]], revs[-1])
3472 self.assertEqual(set(), accessed)
3473- self.assertEqual('X', result.next())
3474+ self.assertEqual(revs[-3], next(result))
3475 # We access 'W' because we are checking that W wasn't merged into X.
3476 # The important bit is that we aren't getting the whole ancestry.
3477- self.assertEqual(set([history._rev_indices[x] for x in 'ZYXW']),
3478- accessed)
3479- self.assertEqual('V', result.next())
3480- self.assertEqual(set([history._rev_indices[x] for x in 'ZYXWVU']),
3481- accessed)
3482- self.assertRaises(StopIteration, result.next)
3483- self.assertEqual(set([history._rev_indices[x] for x in 'ZYXWVU']),
3484+ self.assertEqual(set([history._rev_indices[x] for x in list(reversed(revs))[:4]]),
3485+ accessed)
3486+ self.assertEqual(revs[-5], next(result))
3487+ self.assertEqual(set([history._rev_indices[x] for x in list(reversed(revs))[:6]]),
3488+ accessed)
3489+ self.assertRaises(StopIteration, next, result)
3490+ self.assertEqual(set([history._rev_indices[x] for x in list(reversed(revs))[:6]]),
3491 accessed)
3492
3493
3494@@ -291,32 +292,32 @@
3495 def test_get_view_limited_history(self):
3496 # get_view should only load enough history to serve the result, not all
3497 # history.
3498- history = self.make_long_linear_ancestry()
3499+ history, revs = self.make_long_linear_ancestry()
3500 accessed = track_rev_info_accesses(history)
3501- revid, start_revid, revid_list = history.get_view('Z', 'Z', None,
3502+ revid, start_revid, revid_list = history.get_view(revs[-1], revs[-1], None,
3503 extra_rev_count=5)
3504- self.assertEqual(['Z', 'Y', 'X', 'W', 'V', 'U'], revid_list)
3505- self.assertEqual('Z', revid)
3506- self.assertEqual('Z', start_revid)
3507- self.assertEqual(set([history._rev_indices[x] for x in 'ZYXWVU']),
3508+ self.assertEqual(list(reversed(revs))[:6], revid_list)
3509+ self.assertEqual(revs[-1], revid)
3510+ self.assertEqual(revs[-1], start_revid)
3511+ self.assertEqual(set([history._rev_indices[x] for x in list(reversed(revs))[:6]]),
3512 accessed)
3513
3514
3515 class TestHistoryGetChangedUncached(TestCaseWithExamples):
3516
3517 def test_native(self):
3518- history = self.make_linear_ancestry()
3519- changes = history.get_changes_uncached(['rev-1', 'rev-2'])
3520+ history, revs = self.make_linear_ancestry()
3521+ changes = history.get_changes_uncached([revs[0], revs[1]])
3522 self.assertEquals(2, len(changes))
3523- self.assertEquals('rev-1', changes[0].revid)
3524- self.assertEquals('rev-2', changes[1].revid)
3525+ self.assertEquals(revs[0], changes[0].revid)
3526+ self.assertEquals(revs[1], changes[1].revid)
3527 self.assertIs(None, getattr(changes[0], 'foreign_vcs', None))
3528 self.assertIs(None, getattr(changes[0], 'foreign_revid', None))
3529
3530 def test_foreign(self):
3531 # Test with a mocked foreign revision, as it's not possible
3532 # to rely on any foreign plugins being installed.
3533- history = self.make_linear_ancestry()
3534+ history, revs = self.make_linear_ancestry()
3535 foreign_vcs = ForeignVcs(None, "vcs")
3536 foreign_vcs.show_foreign_revid = repr
3537 foreign_rev = ForeignRevision(("uuid", 1234), VcsMapping(foreign_vcs),
3538
3539=== modified file 'loggerhead/tests/test_http_head.py'
3540--- loggerhead/tests/test_http_head.py 2011-02-10 02:33:15 +0000
3541+++ loggerhead/tests/test_http_head.py 2019-09-18 16:50:15 +0000
3542@@ -16,17 +16,17 @@
3543
3544 """Tests for the HeadMiddleware app."""
3545
3546-from cStringIO import StringIO
3547-
3548-from bzrlib import tests
3549-
3550-from loggerhead.apps import http_head
3551-
3552-
3553-content = ["<html>",
3554- "<head><title>Listed</title></head>",
3555- "<body>Content</body>",
3556- "</html>",
3557+from io import BytesIO
3558+
3559+from breezy import tests
3560+
3561+from ..apps import http_head
3562+
3563+
3564+content = [b"<html>",
3565+ b"<head><title>Listed</title></head>",
3566+ b"<body>Content</body>",
3567+ b"</html>",
3568 ]
3569 headers = {'X-Ignored-Header': 'Value'}
3570
3571@@ -51,7 +51,7 @@
3572 class TestHeadMiddleware(tests.TestCase):
3573
3574 def _trap_start_response(self, status, response_headers, exc_info=None):
3575- self._write_buffer = StringIO()
3576+ self._write_buffer = BytesIO()
3577 self._start_response_passed = (status, response_headers, exc_info)
3578 return self._write_buffer.write
3579
3580@@ -64,13 +64,13 @@
3581 app = http_head.HeadMiddleware(app)
3582 self._consume_app(app, 'GET')
3583 self.assertEqual(('200 OK', headers, None), self._start_response_passed)
3584- self.assertEqualDiff(''.join(content), self._write_buffer.getvalue())
3585+ self.assertEqualDiff(b''.join(content), self._write_buffer.getvalue())
3586
3587 def _verify_head_no_body(self, app):
3588 app = http_head.HeadMiddleware(app)
3589 self._consume_app(app, 'HEAD')
3590 self.assertEqual(('200 OK', headers, None), self._start_response_passed)
3591- self.assertEqualDiff('', self._write_buffer.getvalue())
3592+ self.assertEqualDiff(b'', self._write_buffer.getvalue())
3593
3594 def test_get_passthrough_yielding(self):
3595 self._verify_get_passthrough(yielding_app)
3596
3597=== modified file 'loggerhead/tests/test_load_test.py'
3598--- loggerhead/tests/test_load_test.py 2011-04-14 14:10:04 +0000
3599+++ loggerhead/tests/test_load_test.py 2019-09-18 16:50:15 +0000
3600@@ -15,12 +15,15 @@
3601 import socket
3602 import time
3603 import threading
3604-import Queue
3605-
3606-from bzrlib import tests
3607-from bzrlib.tests import http_server
3608-
3609-from loggerhead import load_test
3610+try:
3611+ from queue import Empty
3612+except ImportError: # Python < 3
3613+ from Queue import Empty
3614+
3615+from breezy import tests
3616+from breezy.tests import http_server
3617+
3618+from .. import load_test
3619
3620
3621 empty_script = """{
3622@@ -90,7 +93,7 @@
3623 def test_step_next_will_timeout(self):
3624 # We don't want step_next to block forever
3625 rt = NoopRequestWorker('id', blocking_time=0.001)
3626- self.assertRaises(Queue.Empty, rt.step_next)
3627+ self.assertRaises(Empty, rt.step_next)
3628
3629 def test_run_stops_for_stop_event(self):
3630 rt = NoopRequestWorker('id', blocking_time=0.001, _queue_size=2)
3631
3632=== modified file 'loggerhead/tests/test_revision_ui.py'
3633--- loggerhead/tests/test_revision_ui.py 2011-03-16 12:37:17 +0000
3634+++ loggerhead/tests/test_revision_ui.py 2019-09-18 16:50:15 +0000
3635@@ -15,8 +15,9 @@
3636 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3637 #
3638
3639+from __future__ import absolute_import
3640
3641-from loggerhead.tests.test_simple import BasicTests
3642+from .test_simple import BasicTests
3643
3644
3645 class TestRevisionUI(BasicTests):
3646@@ -43,4 +44,4 @@
3647 # and the Authors are connected. However, that requires asserting the
3648 # exact HTML connections, which I wanted to avoid.
3649 res.mustcontain('Committer', 'Joe Example')
3650- self.assertFalse('Author(s)' in res.body)
3651+ self.assertFalse(b'Author(s)' in res.body)
3652
3653=== modified file 'loggerhead/tests/test_simple.py'
3654--- loggerhead/tests/test_simple.py 2011-11-25 02:28:56 +0000
3655+++ loggerhead/tests/test_simple.py 2019-09-18 16:50:15 +0000
3656@@ -15,25 +15,27 @@
3657 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3658 #
3659
3660+from __future__ import absolute_import
3661+
3662 import cgi
3663 import logging
3664 import re
3665 import simplejson
3666-from cStringIO import StringIO
3667+from io import BytesIO
3668
3669-from bzrlib.tests import TestCaseWithTransport
3670+from breezy.tests import TestCaseWithTransport
3671 try:
3672- from bzrlib.util.configobj.configobj import ConfigObj
3673+ from breezy.util.configobj.configobj import ConfigObj
3674 except ImportError:
3675 from configobj import ConfigObj
3676-from bzrlib import config
3677+from breezy import config
3678
3679-from loggerhead.apps.branch import BranchWSGIApp
3680-from loggerhead.apps.http_head import HeadMiddleware
3681+from ..apps.branch import BranchWSGIApp
3682+from ..apps.http_head import HeadMiddleware
3683 from paste.fixture import TestApp
3684 from paste.httpexceptions import HTTPExceptionHandler, HTTPMovedPermanently
3685
3686-from loggerhead.tests.fixtures import (
3687+from .fixtures import (
3688 SampleBranch,
3689 )
3690
3691@@ -105,12 +107,6 @@
3692 self.failUnless("To get this branch, use:" in res)
3693 self.failUnless("lp:loggerhead" in res)
3694
3695- def test_no_empty_download_location(self):
3696- """With no served_url, no instructions how to get it"""
3697- app = self.setUpLoggerhead()
3698- res = app.get('/changes')
3699- self.failIf("To get this branch, use:" in res)
3700-
3701 def test_changes_search(self):
3702 app = self.setUpLoggerhead()
3703 res = app.get('/changes', params={'q': 'foo'})
3704@@ -127,10 +123,10 @@
3705 # '<span class='pyg-n'>with</span><span class='pyg-o'>&lt;</span>'
3706 # '<span class='pyg-n'>htmlspecialchars</span>
3707 # So we pre-filter the body, to make sure remove spans of that type.
3708- body_no_span = re.sub(r'<span class="pyg-.">', '', res.body)
3709- body_no_span = body_no_span.replace('</span>', '')
3710+ body_no_span = re.sub(b'<span class="pyg-.">', b'', res.body)
3711+ body_no_span = body_no_span.replace(b'</span>', b'')
3712 for line in self.filecontents.splitlines():
3713- escaped = cgi.escape(line)
3714+ escaped = cgi.escape(line).encode('utf-8')
3715 self.assertTrue(escaped in body_no_span,
3716 "did not find %r in %r" % (escaped, body_no_span))
3717
3718@@ -144,7 +140,7 @@
3719 res.mustcontain('myfilename')
3720 res = app.get('/files/1/')
3721 res.mustcontain('myfilename')
3722- res = app.get('/files/1/?file_id=' + self.tree.path2id(''))
3723+ res = app.get('/files/1/?file_id=' + self.tree.path2id('').decode('utf-8'))
3724 res.mustcontain('myfilename')
3725
3726 def test_inventory_bad_rev_404(self):
3727@@ -192,10 +188,18 @@
3728 def setUp(self):
3729 BasicTests.setUp(self)
3730 self.createBranch()
3731- locations = config.locations_config_filename()
3732- config.ensure_config_dir_exists()
3733- open(locations, 'wb').write('[%s]\nhttp_serve = False'
3734- % (self.tree.branch.base,))
3735+ try:
3736+ locations = config.locations_config_filename()
3737+ except AttributeError:
3738+ from breezy import bedding
3739+ locations = bedding.locations_config_path()
3740+ ensure_config_dir_exists = bedding.ensure_config_dir_exists
3741+ else:
3742+ ensure_config_dir_exists = config.ensure_config_dir_exists
3743+ ensure_config_dir_exists()
3744+ with open(locations, 'w') as f:
3745+ f.write('[%s]\nhttp_serve = False' % (
3746+ self.tree.branch.base,))
3747
3748 def test_no_access(self):
3749 app = self.setUpLoggerhead()
3750@@ -252,11 +256,11 @@
3751 app = self.setUpLoggerhead()
3752 res = app.get('/changes', extra_environ={'REQUEST_METHOD': 'HEAD'})
3753 self.assertEqual('text/html', res.header('Content-Type'))
3754- self.assertEqualDiff('', res.body)
3755+ self.assertEqualDiff(b'', res.body)
3756
3757
3758 def consume_app(app, env):
3759- body = StringIO()
3760+ body = BytesIO()
3761 start = []
3762 def start_response(status, headers, exc_info=None):
3763 start.append((status, headers, exc_info))
3764
3765=== modified file 'loggerhead/tests/test_templating.py'
3766--- loggerhead/tests/test_templating.py 2008-10-24 02:26:05 +0000
3767+++ loggerhead/tests/test_templating.py 2019-09-18 16:50:15 +0000
3768@@ -1,4 +1,4 @@
3769-from loggerhead.zptsupport import load_template
3770+from ..zptsupport import load_template
3771
3772 RENDERED = u"<html>\n<head>\n<title>%s</title>\n</head>\n\
3773 <body>\n<div>Hello, %s</div>\n</body>\n</html>"
3774
3775=== modified file 'loggerhead/tests/test_util.py'
3776--- loggerhead/tests/test_util.py 2011-09-08 00:33:28 +0000
3777+++ loggerhead/tests/test_util.py 2019-09-18 16:50:15 +0000
3778@@ -14,9 +14,9 @@
3779 # along with this program; if not, write to the Free Software
3780 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3781
3782-from bzrlib import tests
3783+from breezy import tests
3784
3785-from loggerhead.util import html_escape, html_format
3786+from ..util import html_escape, html_format
3787
3788
3789 class TestHTMLEscaping(tests.TestCase):
3790
3791=== modified file 'loggerhead/util.py'
3792--- loggerhead/util.py 2012-04-28 00:57:06 +0000
3793+++ loggerhead/util.py 2019-09-18 16:50:15 +0000
3794@@ -19,6 +19,8 @@
3795 # Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
3796 #
3797
3798+from __future__ import print_function
3799+
3800 import base64
3801 import datetime
3802 import logging
3803@@ -30,14 +32,19 @@
3804 import os
3805 import subprocess
3806
3807+from breezy.sixish import (
3808+ text_type,
3809+ viewitems,
3810+ )
3811+
3812 try:
3813 from xml.etree import ElementTree as ET
3814 except ImportError:
3815 from elementtree import ElementTree as ET
3816
3817-from bzrlib import urlutils
3818+from breezy import urlutils
3819
3820-from simpletal.simpleTALUtils import HTMLStructureCleaner
3821+import bleach
3822
3823 log = logging.getLogger("loggerhead.controllers")
3824
3825@@ -73,20 +80,27 @@
3826
3827
3828 def _approximatedate(date):
3829- delta = datetime.datetime.now() - date
3830- if abs(delta) > datetime.timedelta(1, 0, 0):
3831- # far in the past or future, display the date
3832- return date_day(date)
3833+ if date is None:
3834+ return 'Never'
3835+ delta = datetime.datetime.utcnow() - date
3836 future = delta < datetime.timedelta(0, 0, 0)
3837 delta = abs(delta)
3838+ years = delta.days // 365
3839+ months = delta.days // 30 # This is approximate.
3840 days = delta.days
3841- hours = delta.seconds / 3600
3842+ hours = delta.seconds // 3600
3843 minutes = (delta.seconds - (3600*hours)) / 60
3844 seconds = delta.seconds % 60
3845 result = ''
3846 if future:
3847 result += 'in '
3848- if days != 0:
3849+ if years != 0:
3850+ amount = years
3851+ unit = 'year'
3852+ elif months != 0:
3853+ amount = months
3854+ unit = 'month'
3855+ elif days != 0:
3856 amount = days
3857 unit = 'day'
3858 elif hours != 0:
3859@@ -100,10 +114,10 @@
3860 unit = 'second'
3861 if amount != 1:
3862 unit += 's'
3863- result += '%s %s' % (amount, unit)
3864+ result += '%s %s' % (int(amount), unit)
3865 if not future:
3866 result += ' ago'
3867- return result
3868+ return result
3869
3870
3871 def _wrap_with_date_time_title(date, formatted_date):
3872@@ -126,14 +140,14 @@
3873 def __init__(self, _dict=None, **kw):
3874 self._properties = {}
3875 if _dict is not None:
3876- for key, value in _dict.iteritems():
3877+ for key, value in viewitems(_dict):
3878 setattr(self, key, value)
3879- for key, value in kw.iteritems():
3880+ for key, value in viewitems(kw):
3881 setattr(self, key, value)
3882
3883 def __repr__(self):
3884 out = '{ '
3885- for key, value in self.__dict__.iteritems():
3886+ for key, value in viewitems(self.__dict__):
3887 if key.startswith('_') or (getattr(self.__dict__[key],
3888 '__call__', None) is not None):
3889 continue
3890@@ -262,21 +276,24 @@
3891 return s
3892 elif not s.strip():
3893 return '&nbsp;'
3894- else:
3895+ elif isinstance(s, bytes):
3896 try:
3897 s = s.decode('utf-8')
3898 except UnicodeDecodeError:
3899 s = s.decode('iso-8859-15')
3900 return s
3901+ elif isinstance(s, text_type):
3902+ return s
3903+ else:
3904+ return repr(s)
3905
3906-HSC = HTMLStructureCleaner()
3907
3908 def fixed_width(s):
3909 """
3910 expand tabs and turn spaces into "non-breaking spaces", so browsers won't
3911 chop up the string.
3912 """
3913- if not isinstance(s, unicode):
3914+ if not isinstance(s, text_type):
3915 # this kinda sucks. file contents are just binary data, and no
3916 # encoding metadata is stored, so we need to guess. this is probably
3917 # okay for most code, but for people using things like KOI-8, this
3918@@ -289,7 +306,7 @@
3919
3920 s = html_escape(s).expandtabs().replace(' ', NONBREAKING_SPACE)
3921
3922- return HSC.clean(s).replace('\n', '<br/>')
3923+ return bleach.clean(s).replace('\n', '<br/>')
3924
3925
3926 def fake_permissions(kind, executable):
3927@@ -456,7 +473,7 @@
3928 return breadcrumbs
3929
3930
3931-def branch_breadcrumbs(path, inv, view):
3932+def branch_breadcrumbs(path, tree, view):
3933 """
3934 Generate breadcrumb information from the branch path given
3935
3936@@ -464,7 +481,7 @@
3937
3938 Arguments:
3939 path -- The path to convert into breadcrumbs
3940- inv -- Inventory to get file information from
3941+ tree -- Tree to get file information from
3942 view -- The type of view we are showing (files, changes etc)
3943 """
3944 dir_parts = path.strip('/').split('/')
3945@@ -497,7 +514,7 @@
3946 def lsprof(f):
3947
3948 def _f(*a, **kw):
3949- from loggerhead.lsprof import profile
3950+ from .loggerhead.lsprof import profile
3951 import cPickle
3952 z = time.time()
3953 ret, stats = profile(f, *a, **kw)
3954@@ -548,7 +565,7 @@
3955
3956
3957 def set_context(map):
3958- t_context.map = dict((k, v) for (k, v) in map.iteritems() if k in _valid)
3959+ t_context.map = dict((k, v) for (k, v) in viewitems(map) if k in _valid)
3960
3961
3962 def get_context(**overrides):
3963@@ -567,7 +584,7 @@
3964 map['remember'] = t_context.map.get('remember', None)
3965 else:
3966 map.update(t_context.map)
3967- overrides = dict((k, v) for (k, v) in overrides.iteritems() if k in _valid)
3968+ overrides = dict((k, v) for (k, v) in viewitems(overrides) if k in _valid)
3969 map.update(overrides)
3970 return map
3971
3972@@ -605,7 +622,7 @@
3973 @classmethod
3974 def restart_with_reloader(cls):
3975 """Based on restart_with_monitor from paste.script.serve."""
3976- print 'Starting subprocess with file monitor'
3977+ print('Starting subprocess with file monitor')
3978 while True:
3979 args = [sys.executable] + sys.argv
3980 new_environ = os.environ.copy()
3981@@ -618,7 +635,7 @@
3982 exit_code = proc.wait()
3983 proc = None
3984 except KeyboardInterrupt:
3985- print '^C caught in monitor process'
3986+ print('^C caught in monitor process')
3987 return 1
3988 finally:
3989 if (proc is not None
3990@@ -633,7 +650,7 @@
3991 # a monitor, any exit code will restart
3992 if exit_code != 3:
3993 return exit_code
3994- print '-'*20, 'Restarting', '-'*20
3995+ print('-'*20, 'Restarting', '-'*20)
3996
3997
3998 def convert_file_errors(application):
3999@@ -641,7 +658,7 @@
4000 def new_application(environ, start_response):
4001 try:
4002 return application(environ, start_response)
4003- except (IOError, OSError), e:
4004+ except (IOError, OSError) as e:
4005 import errno
4006 from paste import httpexceptions
4007 if e.errno == errno.ENOENT:
4008
4009=== modified file 'loggerhead/wholehistory.py'
4010--- loggerhead/wholehistory.py 2012-02-08 01:50:02 +0000
4011+++ loggerhead/wholehistory.py 2019-09-18 16:50:15 +0000
4012@@ -20,19 +20,23 @@
4013 import logging
4014 import time
4015
4016-from bzrlib.revision import is_null, NULL_REVISION
4017-from bzrlib.tsort import merge_sort
4018+from breezy.revision import is_null, NULL_REVISION
4019+from breezy.sixish import (
4020+ viewitems,
4021+ viewkeys,
4022+ )
4023+from breezy.tsort import merge_sort
4024
4025
4026 def _strip_NULL_ghosts(revision_graph):
4027 """
4028- Copied over from bzrlib meant as a temporary workaround for
4029+ Copied over from breezy meant as a temporary workaround for
4030 deprecated methods.
4031 """
4032 # Filter ghosts, and null:
4033 if NULL_REVISION in revision_graph:
4034 del revision_graph[NULL_REVISION]
4035- for key, parents in revision_graph.iteritems():
4036+ for key, parents in viewitems(revision_graph):
4037 revision_graph[key] = tuple(parent for parent in parents if parent
4038 in revision_graph)
4039 return revision_graph
4040@@ -72,7 +76,7 @@
4041 _rev_indices[revid] = len(_rev_info)
4042 _rev_info.append([(seq, revid, merge_depth, revno_str, end_of_merge), (), parents])
4043
4044- for revid in _revision_graph.iterkeys():
4045+ for revid in viewkeys(_revision_graph):
4046 if _rev_info[_rev_indices[revid]][0][2] == 0:
4047 continue
4048 for parent in _revision_graph[revid]:
4049
4050=== modified file 'loggerhead/zptsupport.py'
4051--- loggerhead/zptsupport.py 2012-02-08 01:50:02 +0000
4052+++ loggerhead/zptsupport.py 2019-09-18 16:50:15 +0000
4053@@ -19,7 +19,9 @@
4054 import os
4055 import pkg_resources
4056 import re
4057-import StringIO
4058+from io import StringIO
4059+
4060+from breezy.sixish import viewitems
4061
4062 from simpletal import simpleTAL, simpleTALES
4063
4064@@ -30,7 +32,8 @@
4065 tinstance = _zpt_cache.get(tfile)
4066 stat = os.stat(tfile)
4067 if tinstance is None or tinstance.stat != stat:
4068- text = open(tfile).read()
4069+ with open(tfile) as tf:
4070+ text = tf.read()
4071 text = re.sub(r'\s*\n\s*', '\n', text)
4072 text = re.sub(r'[ \t]+', ' ', text)
4073 tinstance = _zpt_cache[tfile] = TemplateWrapper(
4074@@ -47,17 +50,17 @@
4075
4076 def expand(self, **info):
4077 context = simpleTALES.Context(allowPythonPath=1)
4078- for k, v in info.iteritems():
4079+ for k, v in viewitems(info):
4080 context.addGlobal(k, v)
4081- s = StringIO.StringIO()
4082+ s = StringIO()
4083 self.template.expandInline(context, s)
4084 return s.getvalue()
4085
4086 def expand_into(self, f, **info):
4087 context = simpleTALES.Context(allowPythonPath=1)
4088- for k, v in info.iteritems():
4089+ for k, v in viewitems(info):
4090 context.addGlobal(k, v)
4091- self.template.expand(context, f, 'utf-8')
4092+ self.template.expand(context, f, outputEncoding='utf-8')
4093
4094 @property
4095 def macros(self):
4096
4097=== modified file 'loggerheadd'
4098--- loggerheadd 2009-04-30 10:39:05 +0000
4099+++ loggerheadd 2019-09-18 16:50:15 +0000
4100@@ -22,8 +22,8 @@
4101 SUDO="sudo -H -u $LHUSER"
4102 fi
4103
4104-# If serve-branches is not in your path, you will need to specify the full path:
4105-SERVE_BRANCHES_CMD=serve-branches
4106+# If loggerhead-serve is not in your path, you will need to specify the full path:
4107+SERVE_BRANCHES_CMD=loggerhead-serve
4108
4109 LOG_FOLDER=/var/log/loggerhead
4110 LOG_FILE=$LOG_FOLDER/loggerheadd.log
4111@@ -33,7 +33,7 @@
4112 #please specify the base directory to serve:
4113 BZRROOT=/bzrroot
4114
4115-# You can add additional options to serve-branches here:
4116+# You can add additional options to loggerhead-serve here:
4117 START_CMD="$SERVE_BRANCHES_CMD --prefix=$URL_PREFIX --log-folder=$LOG_FOLDER --port=$PORT $BZRROOT"
4118
4119
4120
4121=== modified file 'setup.py'
4122--- setup.py 2015-03-17 11:23:13 +0000
4123+++ setup.py 2019-09-18 16:50:15 +0000
4124@@ -18,7 +18,7 @@
4125
4126 """Loggerhead is a web viewer for projects in bazaar"""
4127
4128-from distutils.core import setup
4129+from setuptools import setup
4130
4131 import loggerhead
4132
4133@@ -31,16 +31,15 @@
4134 maintainer = "Michael Hudson",
4135 maintainer_email = "michael.hudson@canonical.com",
4136 scripts = [
4137- "serve-branches",
4138- "loggerhead.wsgi",
4139+ "loggerhead-serve",
4140 ],
4141 packages = ["loggerhead",
4142 "loggerhead/apps",
4143 "loggerhead/controllers",
4144 "loggerhead/middleware",
4145 "loggerhead/templates",
4146- "bzrlib.plugins.loggerhead"],
4147- package_dir={'bzrlib.plugins.loggerhead':'.'},
4148+ "breezy.plugins.loggerhead"],
4149+ package_dir={'breezy.plugins.loggerhead':'.'},
4150 package_data = {"loggerhead": ["templates/*.pt",
4151 "static/css/*.css",
4152 "static/javascript/*.js",
4153@@ -68,9 +67,11 @@
4154 "static/javascript/yui/build/yui-base/*",
4155 "static/images/*"]},
4156 data_files = [
4157- ('share/man/man1', ['serve-branches.1']),
4158+ ('share/man/man1', ['loggerhead-serve.1']),
4159 ('share/doc/loggerhead', ['apache-loggerhead.conf',
4160 'loggerheadd',
4161- 'bazaar.conf']),
4162+ 'breezy.conf']),
4163 ],
4164+ install_requires=['simplejson', 'paste', 'bleach'],
4165+ testsuite='loggerhead.tests.test_suite',
4166 )

Subscribers

People subscribed via source and target branches