Merge lp:~jelmer/brz/appveyor into lp:brz

Proposed by Jelmer Vernooij
Status: Merged
Merged at revision: 7311
Proposed branch: lp:~jelmer/brz/appveyor
Merge into: lp:brz
Diff against target: 1691 lines (+551/-192)
42 files modified
appveyor.yml (+92/-0)
breezy/_patiencediff_c.c (+41/-8)
breezy/builtins.py (+35/-26)
breezy/git/cache.py (+1/-3)
breezy/git/git-remote-bzr (+7/-2)
breezy/git/git_remote_helper.py (+1/-1)
breezy/git/memorytree.py (+4/-0)
breezy/git/object_store.py (+2/-2)
breezy/git/tests/test_blackbox.py (+9/-0)
breezy/git/tests/test_branch.py (+7/-1)
breezy/git/tests/test_git_remote_helper.py (+31/-2)
breezy/git/tests/test_object_store.py (+32/-2)
breezy/globbing.py (+3/-1)
breezy/ignores.py (+1/-1)
breezy/memorytree.py (+18/-4)
breezy/plugins/propose/launchpad.py (+1/-0)
breezy/python-compat.h (+4/-0)
breezy/tests/blackbox/test_bisect.py (+1/-0)
breezy/tests/blackbox/test_push.py (+20/-0)
breezy/tests/blackbox/test_remove.py (+2/-1)
breezy/tests/blackbox/test_uncommit.py (+14/-0)
breezy/tests/features.py (+14/-0)
breezy/tests/test_memorytree.py (+65/-70)
breezy/tests/test_script.py (+2/-2)
breezy/tests/test_urlutils.py (+3/-0)
breezy/transport/memory.py (+50/-32)
breezy/urlutils.py (+4/-1)
build.cmd (+21/-0)
byov.conf (+4/-2)
doc/developers/apport.txt (+1/-1)
doc/developers/configuration.txt (+0/-14)
doc/developers/contribution-quickstart.txt (+1/-1)
doc/developers/plugin-development.txt (+1/-1)
doc/en/admin-guide/hooks-plugins.txt (+4/-4)
doc/en/admin-guide/migration.txt (+1/-1)
doc/en/release-notes/brz-3.0.txt (+10/-0)
doc/en/user-guide/controlling_registration.txt (+3/-3)
doc/en/user-guide/git_limitations.txt (+18/-0)
doc/en/user-guide/index-plain.txt (+1/-0)
doc/en/user-guide/installing_breezy.txt (+1/-1)
doc/en/user-guide/plugins.txt (+2/-2)
setup.py (+19/-3)
To merge this branch: bzr merge lp:~jelmer/brz/appveyor
Reviewer Review Type Date Requested Status
Breezy developers Pending
Review via email: mp+363947@code.launchpad.net

Description of the change

Add appveyor configuration.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'appveyor.yml'
2--- appveyor.yml 1970-01-01 00:00:00 +0000
3+++ appveyor.yml 2019-03-06 06:08:28 +0000
4@@ -0,0 +1,92 @@
5+environment:
6+
7+ matrix:
8+
9+ - PYTHON: "C:\\Python27"
10+ PYTHON_VERSION: "2.7.x"
11+ PYTHON_ARCH: "32"
12+
13+ - PYTHON: "C:\\Python27-x64"
14+ PYTHON_VERSION: "2.7.x"
15+ PYTHON_ARCH: "64"
16+
17+ - PYTHON: "C:\\Python34"
18+ PYTHON_VERSION: "3.4.x"
19+ PYTHON_ARCH: "32"
20+
21+ - PYTHON: "C:\\Python34-x64"
22+ PYTHON_VERSION: "3.4.x"
23+ PYTHON_ARCH: "64"
24+ DISTUTILS_USE_SDK: "1"
25+
26+ - PYTHON: "C:\\Python35"
27+ PYTHON_VERSION: "3.5.x"
28+ PYTHON_ARCH: "32"
29+
30+ - PYTHON: "C:\\Python35-x64"
31+ PYTHON_VERSION: "3.5.x"
32+ PYTHON_ARCH: "64"
33+
34+ - PYTHON: "C:\\Python36"
35+ PYTHON_VERSION: "3.6.x"
36+ PYTHON_ARCH: "32"
37+
38+ - PYTHON: "C:\\Python36-x64"
39+ PYTHON_VERSION: "3.6.x"
40+ PYTHON_ARCH: "64"
41+
42+install:
43+ # If there is a newer build queued for the same PR, cancel this one.
44+ # The AppVeyor 'rollout builds' option is supposed to serve the same
45+ # purpose but it is problematic because it tends to cancel builds pushed
46+ # directly to master instead of just PR builds (or the converse).
47+ # credits: JuliaLang developers.
48+ - ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod `
49+ https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | `
50+ Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { `
51+ throw "There are newer queued builds for this pull request, failing early." }
52+ - ECHO "Filesystem root:"
53+ - ps: "ls \"C:/\""
54+
55+ - ECHO "Installed SDKs:"
56+ - ps: "ls \"C:/Program Files/Microsoft SDKs/Windows\""
57+
58+ # Install Python (from the official .msi of http://python.org) and pip when
59+ # not already installed.
60+ - ps: if (-not(Test-Path($env:PYTHON))) { & appveyor\install.ps1 }
61+
62+ # Prepend newly installed Python to the PATH of this build (this cannot be
63+ # done from inside the powershell script as it would require to restart
64+ # the parent CMD process).
65+ - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
66+
67+ # Check that we have the expected version and architecture for Python
68+ - "build.cmd %PYTHON%\\python.exe --version"
69+ - "build.cmd %PYTHON%\\python.exe -c \"import struct; print(struct.calcsize('P') * 8)\""
70+
71+ # Install setuptools/wheel so that we can e.g. use bdist_wheel
72+ - "pip install setuptools wheel"
73+ # Install cython so we can build C extensions
74+ - "pip install cython"
75+
76+ - "build.cmd %PYTHON%\\python.exe setup.py develop"
77+
78+ - "pip install launchpadlib"
79+
80+build_script:
81+ # Build the compiled extension
82+ - "build.cmd %PYTHON%\\python.exe setup.py build"
83+
84+test_script:
85+ - "build.cmd %PYTHON%\\python.exe setup.py test"
86+ - "build.cmd %PYTHON%\\pythonw.exe setup.py test"
87+
88+after_test:
89+ - "build.cmd %PYTHON%\\python.exe setup.py bdist_wheel"
90+ # http://stackoverflow.com/questions/43255455/unicode-character-causing-error-with-bdist-wininst-on-python-3-but-not-python-2
91+ # - "python setup.py bdist_wininst"
92+ - "build.cmd %PYTHON%\\python.exe setup.py bdist_msi"
93+ - ps: "ls dist"
94+
95+artifacts:
96+ - path: dist\*
97
98=== modified file 'breezy/_patiencediff_c.c'
99--- breezy/_patiencediff_c.c 2019-01-27 18:53:46 +0000
100+++ breezy/_patiencediff_c.c 2019-03-06 06:08:28 +0000
101@@ -1163,14 +1163,47 @@
102
103
104 static PyTypeObject PatienceSequenceMatcherType = {
105- PyObject_HEAD_INIT(NULL)
106- .tp_name = "PatienceSequenceMatcher",
107- .tp_basicsize = sizeof(PatienceSequenceMatcher),
108- .tp_dealloc = (destructor)PatienceSequenceMatcher_dealloc,
109- .tp_flags = Py_TPFLAGS_DEFAULT,
110- .tp_doc = PatienceSequenceMatcher_doc,
111- .tp_methods = PatienceSequenceMatcher_methods,
112- .tp_new = PatienceSequenceMatcher_new,
113+ PyVarObject_HEAD_INIT(NULL, 0)
114+ "PatienceSequenceMatcher", /* tp_name */
115+ sizeof(PatienceSequenceMatcher), /* tp_basicsize */
116+ sizeof(PyObject *), /* tp_itemsize */
117+ (destructor)PatienceSequenceMatcher_dealloc, /* tp_dealloc */
118+ 0, /* tp_print */
119+ 0, /* tp_getattr */
120+ 0, /* tp_setattr */
121+ 0, /* tp_compare */
122+ 0, /* tp_repr */
123+ 0, /* tp_as_number */
124+ 0, /* tp_as_sequence */
125+ 0, /* tp_as_mapping */
126+ 0, /* tp_hash */
127+ 0, /* tp_call */
128+ 0, /* tp_str */
129+ 0, /* tp_getattro */
130+ 0, /* tp_setattro */
131+ 0, /* tp_as_buffer */
132+ Py_TPFLAGS_DEFAULT, /* tp_flags */
133+ PatienceSequenceMatcher_doc, /* tp_doc */
134+ 0, /* tp_traverse */
135+ 0, /* tp_clear */
136+ 0, /* tp_richcompare */
137+ 0, /* tp_weaklistoffset */
138+ // without implementing tp_iter, Python will fall back to PySequence*
139+ // which seems to work ok, we may need something faster/lighter in the
140+ // future.
141+ 0, /* tp_iter */
142+ 0, /* tp_iternext */
143+ PatienceSequenceMatcher_methods, /* tp_methods */
144+ 0, /* tp_members */
145+ 0, /* tp_getset */
146+ 0, /* tp_base */
147+ 0, /* tp_dict */
148+ 0, /* tp_descr_get */
149+ 0, /* tp_descr_set */
150+ 0, /* tp_dictoffset */
151+ 0, /* tp_init */
152+ 0, /* tp_alloc */
153+ PatienceSequenceMatcher_new, /* tp_new */
154 };
155
156
157
158=== modified file 'breezy/builtins.py'
159--- breezy/builtins.py 2019-02-09 03:23:20 +0000
160+++ breezy/builtins.py 2019-03-06 06:08:28 +0000
161@@ -348,7 +348,7 @@
162 Not versioned and not matching an ignore pattern.
163
164 Additionally for directories, symlinks and files with a changed
165- executable bit, Bazaar indicates their type using a trailing
166+ executable bit, Breezy indicates their type using a trailing
167 character: '/', '@' or '*' respectively. These decorations can be
168 disabled using the '--no-classify' option.
169
170@@ -454,11 +454,11 @@
171
172 b = controldir.ControlDir.open_containing_tree_or_branch(directory)[1]
173
174- revisions = b.repository.revisions
175+ revisions = getattr(b.repository, "revisions", None)
176 if revisions is None:
177 raise errors.BzrCommandError(
178 gettext('Repository %r does not support '
179- 'access to raw revision texts'))
180+ 'access to raw revision texts') % b.repository)
181
182 with b.repository.lock_read():
183 # TODO: jam 20060112 should cat-revision always output utf-8?
184@@ -1344,6 +1344,7 @@
185 use_existing_dir=False, directory=None, stacked_on=None,
186 stacked=False, strict=None, no_tree=False,
187 overwrite_tags=False, lossy=False):
188+ from .location import location_to_url
189 from .push import _show_push_branch
190
191 if overwrite:
192@@ -1371,6 +1372,7 @@
193 more_warning='Uncommitted changes will not be pushed.')
194 # Get the stacked_on branch, if any
195 if stacked_on is not None:
196+ stacked_on = location_to_url(stacked_on, 'read')
197 stacked_on = urlutils.normalize_url(stacked_on)
198 elif stacked:
199 parent_url = br_from.get_parent()
200@@ -1728,7 +1730,7 @@
201 If the tree's branch is bound to a master branch, brz will also update
202 the branch from the master.
203
204- You cannot update just a single file or directory, because each Bazaar
205+ You cannot update just a single file or directory, because each Breezy
206 working tree has just a single basis revision. If you want to restore a
207 file that has been removed locally, use 'brz revert' instead of 'brz
208 update'. If you want to restore a file to its state in a previous
209@@ -1871,11 +1873,11 @@
210 class cmd_remove(Command):
211 __doc__ = """Remove files or directories.
212
213- This makes Bazaar stop tracking changes to the specified files. Bazaar will
214+ This makes Breezy stop tracking changes to the specified files. Breezy will
215 delete them if they can easily be recovered using revert otherwise they
216 will be backed up (adding an extension of the form .~#~). If no options or
217- parameters are given Bazaar will scan for files that are being tracked by
218- Bazaar but missing in your tree and stop tracking them for you.
219+ parameters are given Breezy will scan for files that are being tracked by
220+ Breezy but missing in your tree and stop tracking them for you.
221 """
222 takes_args = ['file*']
223 takes_options = ['verbose',
224@@ -3091,9 +3093,10 @@
225 using this command or directly by using an editor, be sure to commit
226 it.
227
228- Bazaar also supports a global ignore file ~/.bazaar/ignore. On Windows
229- the global ignore file can be found in the application data directory as
230- C:\\Documents and Settings\\<user>\\Application Data\\Bazaar\\2.0\\ignore.
231+ Breezy also supports a global ignore file ~/.config/breezy/ignore. On
232+ Windows the global ignore file can be found in the application data
233+ directory as
234+ C:\\Documents and Settings\\<user>\\Application Data\\Breezy\\3.0\\ignore.
235 Global ignores are not touched by this command. The global ignore file
236 can be edited directly using an editor.
237
238@@ -3732,7 +3735,7 @@
239 unreferenced ancestors
240 Texts that are ancestors of other texts, but
241 are not properly referenced by the revision ancestry. This is a
242- subtle problem that Bazaar can work around.
243+ subtle problem that Breezy can work around.
244
245 unique file texts
246 This is the total number of unique file contents
247@@ -3744,7 +3747,7 @@
248 entries are modified, but the file contents are not. It does not
249 indicate a problem.
250
251- If no restrictions are specified, all Bazaar data that is found at the given
252+ If no restrictions are specified, all data that is found at the given
253 location will be checked.
254
255 :Examples:
256@@ -3786,10 +3789,10 @@
257 __doc__ = """Upgrade a repository, branch or working tree to a newer format.
258
259 When the default format has changed after a major new release of
260- Bazaar, you may be informed during certain operations that you
261+ Bazaar/Breezy, you may be informed during certain operations that you
262 should upgrade. Upgrading to a newer format may improve performance
263 or make new features available. It may however limit interoperability
264- with older repositories or with older versions of Bazaar.
265+ with older repositories or with older versions of Bazaar or Breezy.
266
267 If you wish to upgrade to a particular format rather than the
268 current default, that can be specified using the --format option.
269@@ -3811,7 +3814,7 @@
270 If the conversion of a branch fails, remaining branches are still
271 tried.
272
273- For more information on upgrades, see the Bazaar Upgrade Guide,
274+ For more information on upgrades, see the Breezy Upgrade Guide,
275 https://www.breezy-vcs.org/doc/en/upgrade-guide/.
276 """
277
278@@ -4312,7 +4315,7 @@
279 through OTHER, excluding BASE but including OTHER, will be merged. If this
280 causes some revisions to be skipped, i.e. if the destination branch does
281 not already contain revision BASE, such a merge is commonly referred to as
282- a "cherrypick". Unlike a normal merge, Bazaar does not currently track
283+ a "cherrypick". Unlike a normal merge, Breezy does not currently track
284 cherrypicks. The changes look like a normal commit, and the history of the
285 changes from the other branch is not stored in the commit.
286
287@@ -5133,8 +5136,8 @@
288
289 --verbose shows the path where each plugin is located.
290
291- A plugin is an external component for Bazaar that extends the
292- revision control system, by adding or replacing code in Bazaar.
293+ A plugin is an external component for Breezy that extends the
294+ revision control system, by adding or replacing code in Breezy.
295 Plugins can do a variety of things, including overriding commands,
296 adding new commands, providing additional network transports and
297 customizing log output.
298@@ -5420,10 +5423,10 @@
299 else:
300 self.add_cleanup(b.lock_write().unlock)
301 return self._run(b, tree, dry_run, verbose, revision, force,
302- local, keep_tags)
303+ local, keep_tags, location)
304
305 def _run(self, b, tree, dry_run, verbose, revision, force, local,
306- keep_tags):
307+ keep_tags, location):
308 from .log import log_formatter, show_log
309 from .uncommit import uncommit
310
311@@ -5477,10 +5480,16 @@
312 last_rev_id, rev_id)
313 uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
314 revno=revno, local=local, keep_tags=keep_tags)
315- self.outf.write(
316- gettext('You can restore the old tip by running:\n'
317- ' brz pull . -r revid:%s\n')
318- % last_rev_id.decode('utf-8'))
319+ if location != '.':
320+ self.outf.write(
321+ gettext('You can restore the old tip by running:\n'
322+ ' brz pull -d %s %s -r revid:%s\n')
323+ % (location, location, last_rev_id.decode('utf-8')))
324+ else:
325+ self.outf.write(
326+ gettext('You can restore the old tip by running:\n'
327+ ' brz pull . -r revid:%s\n')
328+ % last_rev_id.decode('utf-8'))
329
330
331 class cmd_break_lock(Command):
332@@ -5498,7 +5507,7 @@
333 :Examples:
334 brz break-lock
335 brz break-lock brz+ssh://example.com/brz/foo
336- brz break-lock --conf ~/.bazaar
337+ brz break-lock --conf ~/.config/breezy
338 """
339
340 takes_args = ['location?']
341@@ -5789,7 +5798,7 @@
342 branch containing submit_branch in its ancestory without needing access to
343 the source branch.
344
345- If --no-bundle is specified, then Bazaar doesn't send the contents of the
346+ If --no-bundle is specified, then Breezy doesn't send the contents of the
347 revisions, but only a structured request to merge from the
348 public_location. In that case the public_branch is needed and it must be
349 up-to-date and accessible to the recipient. The public_branch is always
350
351=== modified file 'breezy/git/cache.py'
352--- breezy/git/cache.py 2018-11-12 01:41:38 +0000
353+++ breezy/git/cache.py 2019-03-06 06:08:28 +0000
354@@ -613,11 +613,9 @@
355
356 def open(self, transport):
357 try:
358- basepath = transport.local_abspath(".").encode(osutils._fs_enc)
359+ basepath = transport.local_abspath(".")
360 except bzr_errors.NotLocalUrl:
361 basepath = get_cache_dir()
362- if not isinstance(basepath, str):
363- raise TypeError(basepath)
364 try:
365 return TdbBzrGitCache(os.path.join(basepath, "idmap.tdb"))
366 except ImportError:
367
368=== modified file 'breezy/git/git-remote-bzr'
369--- breezy/git/git-remote-bzr 2018-03-26 22:28:24 +0000
370+++ breezy/git/git-remote-bzr 2019-03-06 06:08:28 +0000
371@@ -32,10 +32,12 @@
372 import breezy
373 breezy.initialize()
374
375+from breezy.sixish import PY3
376+
377 from breezy.plugin import load_plugins
378 load_plugins()
379
380-from breezy.plugins.git.git_remote_helper import (
381+from breezy.git.git_remote_helper import (
382 RemoteHelper,
383 open_local_dir,
384 open_remote_dir,
385@@ -46,4 +48,7 @@
386 (shortname, url) = args
387
388 helper = RemoteHelper(open_local_dir(), shortname, open_remote_dir(url))
389-helper.process(sys.stdin, sys.stdout)
390+if PY3:
391+ helper.process(sys.stdin.buffer, sys.stdout.buffer)
392+else:
393+ helper.process(sys.stdin, sys.stdout)
394
395=== modified file 'breezy/git/git_remote_helper.py'
396--- breezy/git/git_remote_helper.py 2018-11-11 14:23:06 +0000
397+++ breezy/git/git_remote_helper.py 2019-03-06 06:08:28 +0000
398@@ -186,7 +186,7 @@
399 self.batchcmd = None
400 else:
401 try:
402- self.commands[argv[0]](self, outf, argv)
403+ self.commands[argv[0].decode()](self, outf, argv)
404 except KeyError:
405 raise Exception("Unknown remote command %r" % argv)
406 outf.flush()
407
408=== modified file 'breezy/git/memorytree.py'
409--- breezy/git/memorytree.py 2018-11-18 00:25:19 +0000
410+++ breezy/git/memorytree.py 2019-03-06 06:08:28 +0000
411@@ -258,3 +258,7 @@
412 def kind(self, p):
413 stat_value = self._file_transport.stat(p)
414 return osutils.file_kind_from_stat_mode(stat_value.st_mode)
415+
416+ def get_symlink_target(self, path):
417+ with self.lock_read():
418+ return self._file_transport.readlink(path)
419
420=== modified file 'breezy/git/object_store.py'
421--- breezy/git/object_store.py 2019-01-01 21:23:40 +0000
422+++ breezy/git/object_store.py 2019-03-06 06:08:28 +0000
423@@ -359,7 +359,7 @@
424 continue
425
426 if tree.kind(path) != 'directory':
427- raise AssertionError
428+ continue
429
430 obj = Tree()
431 for value in tree.iter_child_entries(path):
432@@ -589,7 +589,7 @@
433 for (file_id, revision, expected_sha), chunks in stream:
434 blob = Blob()
435 blob.chunked = chunks
436- if blob.id != expected_sha and blob.data == "":
437+ if blob.id != expected_sha and blob.data == b"":
438 # Perhaps it's a symlink ?
439 tree = self.tree_cache.revision_tree(revision)
440 path = tree.id2path(file_id)
441
442=== modified file 'breezy/git/tests/test_blackbox.py'
443--- breezy/git/tests/test_blackbox.py 2019-02-14 04:20:37 +0000
444+++ breezy/git/tests/test_blackbox.py 2019-03-06 06:08:28 +0000
445@@ -78,6 +78,15 @@
446 self.assertEqual(output, '')
447 self.assertFileEqual("foo\n", ".gitignore")
448
449+ def test_cat_revision(self):
450+ self.simple_commit()
451+ output, error = self.run_bzr(['cat-revision', '-r-1'], retcode=3)
452+ self.assertContainsRe(
453+ error,
454+ 'brz: ERROR: Repository .* does not support access to raw '
455+ 'revision texts')
456+ self.assertEqual(output, '')
457+
458 def test_branch(self):
459 os.mkdir("gitbranch")
460 GitRepo.init(os.path.join(self.test_dir, "gitbranch"))
461
462=== modified file 'breezy/git/tests/test_branch.py'
463--- breezy/git/tests/test_branch.py 2019-01-19 17:13:53 +0000
464+++ breezy/git/tests/test_branch.py 2019-03-06 06:08:28 +0000
465@@ -112,6 +112,7 @@
466 reva = self.simple_commit_a()
467 self.build_tree(['b'])
468 r = GitRepo(".")
469+ self.addCleanup(r.close)
470 r.stage("b")
471 revb = r.do_commit(b"b", committer=b"Somebody <foo@example.com>")
472
473@@ -129,6 +130,7 @@
474 o.tag_timezone = 0
475 o.tag_time = 42
476 r = GitRepo(".")
477+ self.addCleanup(r.close)
478 r.object_store.add_object(o)
479 r[b'refs/tags/foo'] = o.id
480 thebranch = Branch.open('.')
481@@ -138,6 +140,7 @@
482 def test_tag(self):
483 reva = self.simple_commit_a()
484 r = GitRepo(".")
485+ self.addCleanup(r.close)
486 r.refs[b"refs/tags/foo"] = reva
487 thebranch = Branch.open('.')
488 self.assertEqual({"foo": default_mapping.revision_id_foreign_to_bzr(reva)},
489@@ -221,6 +224,7 @@
490 def test_sprouted_tags(self):
491 path, gitsha = self.make_onerev_branch()
492 r = GitRepo(path)
493+ self.addCleanup(r.close)
494 r.refs[b"refs/tags/lala"] = r.head()
495 oldrepo = Repository.open(path)
496 revid = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha)
497@@ -231,6 +235,7 @@
498 def test_sprouted_ghost_tags(self):
499 path, gitsha = self.make_onerev_branch()
500 r = GitRepo(path)
501+ self.addCleanup(r.close)
502 r.refs[b"refs/tags/lala"] = b"aa" * 20
503 oldrepo = Repository.open(path)
504 revid = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha)
505@@ -238,7 +243,7 @@
506 self.clone_git_branch, path, "f")
507 self.assertEqual({}, newbranch.tags.get_tag_dict())
508 # Dulwich raises a UserWarning for tags with invalid target
509- self.assertEqual(1, len(warnings))
510+ self.assertIn(('ref refs/tags/lala points at non-present sha ' + ("aa" * 20), ), [w.args for w in warnings])
511
512 def test_interbranch_pull(self):
513 path, (gitsha1, gitsha2) = self.make_tworev_branch()
514@@ -272,6 +277,7 @@
515 def test_interbranch_pull_with_tags(self):
516 path, (gitsha1, gitsha2) = self.make_tworev_branch()
517 gitrepo = GitRepo(path)
518+ self.addCleanup(gitrepo.close)
519 gitrepo.refs[b"refs/tags/sometag"] = gitsha2
520 oldrepo = Repository.open(path)
521 revid1 = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha1)
522
523=== modified file 'breezy/git/tests/test_git_remote_helper.py'
524--- breezy/git/tests/test_git_remote_helper.py 2018-11-21 03:39:28 +0000
525+++ breezy/git/tests/test_git_remote_helper.py 2019-03-06 06:08:28 +0000
526@@ -23,12 +23,15 @@
527
528 from io import BytesIO
529 import os
530+import subprocess
531+import sys
532
533 from dulwich.repo import Repo
534
535 from ...tests import (
536 TestCaseWithTransport,
537 )
538+from ...tests.features import PathFeature
539
540 from ..object_store import get_object_store
541 from ..git_remote_helper import (
542@@ -46,6 +49,11 @@
543 return object_store._lookup_revision_sha1(bzr_revid)
544
545
546+git_remote_bzr_path = os.path.abspath(
547+ os.path.join(os.path.dirname(__file__), '..', 'git-remote-bzr'))
548+git_remote_bzr_feature = PathFeature(git_remote_bzr_path)
549+
550+
551 class OpenLocalDirTests(TestCaseWithTransport):
552
553 def test_from_env_dir(self):
554@@ -86,8 +94,29 @@
555 self.assertEqual(out, b"\n")
556 r = Repo('local')
557 self.assertTrue(git_sha1 in r.object_store)
558- self.assertEqual({
559- }, r.get_refs())
560+ self.assertEqual({}, r.get_refs())
561+
562+
563+class ExecuteRemoteHelperTests(TestCaseWithTransport):
564+
565+ def test_run(self):
566+ self.requireFeature(git_remote_bzr_feature)
567+ local_dir = self.make_branch_and_tree('local', format='git').controldir
568+ local_path = local_dir.control_transport.local_abspath('.')
569+ remote_tree = self.make_branch_and_tree('remote')
570+ remote_dir = remote_tree.controldir
571+ shortname = 'bzr'
572+ env = dict(os.environ)
573+ env['GIT_DIR'] = local_path
574+ env['PYTHONPATH'] = ':'.join(sys.path)
575+ p = subprocess.Popen(
576+ [sys.executable, git_remote_bzr_path, local_path, remote_dir.user_url],
577+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,
578+ stderr=subprocess.PIPE, env=env)
579+ (out, err) = p.communicate(b'capabilities\n')
580+ lines = out.splitlines()
581+ self.assertIn(b'push', lines, "no 'push' in %r, error: %r" % (lines, err))
582+ self.assertEqual(b'', err)
583
584
585 class RemoteHelperTests(TestCaseWithTransport):
586
587=== modified file 'breezy/git/tests/test_object_store.py'
588--- breezy/git/tests/test_object_store.py 2018-11-11 04:08:32 +0000
589+++ breezy/git/tests/test_object_store.py 2019-03-06 06:08:28 +0000
590@@ -18,6 +18,9 @@
591
592 from __future__ import absolute_import
593
594+import os
595+import shutil
596+
597 from dulwich.objects import (
598 Blob,
599 Tree,
600@@ -41,6 +44,7 @@
601 TestCase,
602 TestCaseWithTransport,
603 )
604+from ...tests.features import SymlinkFeature
605
606 from ..cache import (
607 DictGitShaMap,
608@@ -144,11 +148,11 @@
609 def setUp(self):
610 super(BazaarObjectStoreTests, self).setUp()
611 self.branch = self.make_branch(".")
612- self.branch.lock_write()
613- self.addCleanup(self.branch.unlock)
614 self.store = BazaarObjectStore(self.branch.repository)
615
616 def test_get_blob(self):
617+ self.branch.lock_write()
618+ self.addCleanup(self.branch.unlock)
619 b = Blob()
620 b.data = b'a\nb\nc\nd\ne\n'
621 self.store.lock_read()
622@@ -167,7 +171,31 @@
623 self.store.lock_read()
624 self.assertEqual(b, self.store[b.id])
625
626+ def test_directory_converted_to_symlink(self):
627+ self.requireFeature(SymlinkFeature)
628+ b = Blob()
629+ b.data = b'trgt'
630+ self.store.lock_read()
631+ self.addCleanup(self.store.unlock)
632+ self.assertRaises(KeyError, self.store.__getitem__, b.id)
633+ tree = self.branch.controldir.create_workingtree()
634+ self.build_tree_contents([
635+ ('foo/', ),
636+ ('foo/bar', b'a\nb\nc\nd\ne\n')])
637+ tree.add(['foo', 'foo/bar'])
638+ revid1 = tree.commit('commit 1')
639+ shutil.rmtree('foo')
640+ os.symlink('trgt', 'foo')
641+ revid2 = tree.commit('commit 2')
642+ # read locks cache
643+ self.assertRaises(KeyError, self.store.__getitem__, b.id)
644+ self.store.unlock()
645+ self.store.lock_read()
646+ self.assertEqual(b, self.store[b.id])
647+
648 def test_get_raw(self):
649+ self.branch.lock_write()
650+ self.addCleanup(self.branch.unlock)
651 b = Blob()
652 b.data = b'a\nb\nc\nd\ne\n'
653 self.store.lock_read()
654@@ -187,6 +215,8 @@
655 self.assertEqual(b.as_raw_string(), self.store.get_raw(b.id)[1])
656
657 def test_contains(self):
658+ self.branch.lock_write()
659+ self.addCleanup(self.branch.unlock)
660 b = Blob()
661 b.data = b'a\nb\nc\nd\ne\n'
662 self.store.lock_read()
663
664=== modified file 'breezy/globbing.py'
665--- breezy/globbing.py 2018-11-18 19:48:57 +0000
666+++ breezy/globbing.py 2019-03-06 06:08:28 +0000
667@@ -248,7 +248,9 @@
668 # the combined pattern we sent to regex. Instead we indicate to
669 # the user that an ignore file needs fixing.
670 mutter('Invalid pattern found in regex: %s.', e.msg)
671- e.msg = "File ~/.bazaar/ignore or .bzrignore contains error(s)."
672+ e.msg = (
673+ "File ~/.config/breezy/ignore or "
674+ ".bzrignore contains error(s).")
675 bad_patterns = ''
676 for _, patterns in self._regex_patterns:
677 for p in patterns:
678
679=== modified file 'breezy/ignores.py'
680--- breezy/ignores.py 2018-11-12 01:41:38 +0000
681+++ breezy/ignores.py 2019-03-06 06:08:28 +0000
682@@ -33,7 +33,7 @@
683 )
684 """)
685
686-# ~/.bazaar/ignore will be filled out using
687+# ~/.config/breezy/ignore will be filled out using
688 # this ignore list, if it does not exist
689 # please keep these sorted (in C locale order) to aid merging
690 USER_DEFAULTS = [
691
692=== modified file 'breezy/memorytree.py'
693--- breezy/memorytree.py 2018-11-18 00:25:19 +0000
694+++ breezy/memorytree.py 2019-03-06 06:08:28 +0000
695@@ -22,6 +22,7 @@
696 from __future__ import absolute_import
697
698 import os
699+import stat
700
701 from . import (
702 errors,
703@@ -62,7 +63,15 @@
704 with self.lock_tree_write():
705 for f, file_id, kind in zip(files, ids, kinds):
706 if kind is None:
707- kind = 'file'
708+ st_mode = self._file_transport.stat(f).st_mode
709+ if stat.S_ISREG(st_mode):
710+ kind = 'file'
711+ elif stat.S_ISLNK(st_mode):
712+ kind = 'symlink'
713+ elif stat.S_ISDIR(st_mode):
714+ kind = 'directory'
715+ else:
716+ raise AssertionError('Unknown file kind')
717 if file_id is None:
718 self._inventory.add_path(f, kind=kind)
719 else:
720@@ -127,7 +136,7 @@
721 # memory tree does not support nested trees yet.
722 return kind, None, None, None
723 elif kind == 'symlink':
724- raise NotImplementedError('symlink support')
725+ return kind, None, None, self._inventory[id].symlink_target
726 else:
727 raise NotImplementedError('unknown kind')
728
729@@ -148,8 +157,7 @@
730 return self._inventory.get_entry_by_path(path).executable
731
732 def kind(self, path):
733- file_id = self.path2id(path)
734- return self._inventory[file_id].kind
735+ return self._inventory.get_entry_by_path(path).kind
736
737 def mkdir(self, path, file_id=None):
738 """See MutableTree.mkdir()."""
739@@ -227,6 +235,8 @@
740 continue
741 if entry.kind == 'directory':
742 self._file_transport.mkdir(path)
743+ elif entry.kind == 'symlink':
744+ self._file_transport.symlink(entry.symlink_target, path)
745 elif entry.kind == 'file':
746 self._file_transport.put_file(
747 path, self._basis_tree.get_file(path))
748@@ -302,6 +312,10 @@
749 else:
750 raise
751
752+ def get_symlink_target(self, path):
753+ with self.lock_read():
754+ return self._file_transport.readlink(path)
755+
756 def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
757 """See MutableTree.set_parent_trees()."""
758 if len(parents_list) == 0:
759
760=== modified file 'breezy/plugins/propose/launchpad.py'
761--- breezy/plugins/propose/launchpad.py 2019-02-10 18:37:58 +0000
762+++ breezy/plugins/propose/launchpad.py 2019-03-06 06:08:28 +0000
763@@ -140,6 +140,7 @@
764
765 def set_description(self, description):
766 self._mp.description = description
767+ self._mp.lp_save()
768
769 def close(self):
770 self._mp.setStatus(status='Rejected')
771
772=== modified file 'breezy/python-compat.h'
773--- breezy/python-compat.h 2018-08-21 00:53:34 +0000
774+++ breezy/python-compat.h 2019-03-06 06:08:28 +0000
775@@ -25,6 +25,10 @@
776 #ifndef _BZR_PYTHON_COMPAT_H
777 #define _BZR_PYTHON_COMPAT_H
778
779+#ifdef _MSC_VER
780+#define inline __inline
781+#endif
782+
783 #if PY_MAJOR_VERSION >= 3
784
785 #define PyInt_FromSsize_t PyLong_FromSsize_t
786
787=== modified file 'breezy/tests/blackbox/test_bisect.py'
788--- breezy/tests/blackbox/test_bisect.py 2018-11-11 04:08:32 +0000
789+++ breezy/tests/blackbox/test_bisect.py 2019-03-06 06:08:28 +0000
790@@ -28,6 +28,7 @@
791 from .. import (
792 KnownFailure,
793 TestCaseWithTransport,
794+ TestSkipped,
795 )
796 from ...bzr.bzrdir import BzrDir
797
798
799=== modified file 'breezy/tests/blackbox/test_push.py'
800--- breezy/tests/blackbox/test_push.py 2018-11-16 12:08:41 +0000
801+++ breezy/tests/blackbox/test_push.py 2019-03-06 06:08:28 +0000
802@@ -22,6 +22,7 @@
803 from breezy import (
804 branch,
805 controldir,
806+ directory_service,
807 errors,
808 osutils,
809 tests,
810@@ -498,6 +499,25 @@
811 self.assertPublished(branch_tree.last_revision(),
812 trunk_tree.branch.base)
813
814+ def test_push_new_branch_stacked_on(self):
815+ """Pushing a new branch with --stacked-on can use directory URLs."""
816+ trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
817+ class FooDirectory(object):
818+ def look_up(self, name, url, purpose=None):
819+ if url == 'foo:':
820+ return trunk_tree.branch.base
821+ return url
822+ directory_service.directories.register('foo:', FooDirectory, 'Foo directory')
823+ self.addCleanup(directory_service.directories.remove, 'foo:')
824+ # we publish branch_tree with a reference to the mainline.
825+ out, err = self.run_bzr(['push', '--stacked-on', 'foo:',
826+ self.get_url('published')], working_dir='branch')
827+ self.assertEqual('', out)
828+ self.assertEqual('Created new stacked branch referring to %s.\n' %
829+ trunk_tree.branch.base, err)
830+ self.assertPublished(branch_tree.last_revision(),
831+ trunk_tree.branch.base)
832+
833 def test_push_new_branch_stacked_uses_parent_when_no_public_url(self):
834 """When the parent has no public url the parent is used as-is."""
835 trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
836
837=== modified file 'breezy/tests/blackbox/test_remove.py'
838--- breezy/tests/blackbox/test_remove.py 2018-11-17 18:49:41 +0000
839+++ breezy/tests/blackbox/test_remove.py 2019-03-06 06:08:28 +0000
840@@ -23,6 +23,7 @@
841 features,
842 TestCaseWithTransport,
843 TestSkipped,
844+ TestNotApplicable,
845 )
846 from breezy.workingtree import WorkingTree
847 from breezy import osutils
848@@ -278,7 +279,7 @@
849 def test_remove_backslash(self):
850 # pad.lv/176263
851 if os.path.sep == '\\':
852- raise tests.TestNotApplicable(
853+ raise TestNotApplicable(
854 'unable to add filenames with backslashes where '
855 ' it is the path separator')
856 tree = self.make_branch_and_tree('.')
857
858=== modified file 'breezy/tests/blackbox/test_uncommit.py'
859--- breezy/tests/blackbox/test_uncommit.py 2018-11-18 19:48:57 +0000
860+++ breezy/tests/blackbox/test_uncommit.py 2019-03-06 06:08:28 +0000
861@@ -246,6 +246,20 @@
862 brz pull . -r revid:a2
863 """)
864
865+ def test_uncommit_shows_pull_with_location(self):
866+ wt = self.create_simple_tree()
867+
868+ script = ScriptRunner()
869+ script.run_script(self, """
870+$ brz uncommit --force tree
871+ 2 ...
872+ second commit
873+...
874+The above revision(s) will be removed.
875+You can restore the old tip by running:
876+ brz pull -d tree tree -r revid:a2
877+""")
878+
879 def test_uncommit_octopus_merge(self):
880 # Check that uncommit keeps the pending merges in the same order
881 # though it will also filter out ones in the ancestry
882
883=== modified file 'breezy/tests/features.py'
884--- breezy/tests/features.py 2019-01-19 01:44:20 +0000
885+++ breezy/tests/features.py 2019-03-06 06:08:28 +0000
886@@ -568,3 +568,17 @@
887
888
889 BackslashFilenameFeature = _BackslashFilenameFeature()
890+
891+
892+class PathFeature(Feature):
893+ """Feature testing whether a particular path exists."""
894+
895+ def __init__(self, path):
896+ super(PathFeature, self).__init__()
897+ self.path = path
898+
899+ def _probe(self):
900+ return os.path.exists(self.path)
901+
902+ def feature_name(self):
903+ return "%s exists" % self.path
904
905=== modified file 'breezy/tests/test_memorytree.py'
906--- breezy/tests/test_memorytree.py 2018-11-11 04:08:32 +0000
907+++ breezy/tests/test_memorytree.py 2019-03-06 06:08:28 +0000
908@@ -46,21 +46,17 @@
909 rev_id = tree.commit('first post')
910 tree.unlock()
911 tree = MemoryTree.create_on_branch(branch)
912- tree.lock_read()
913- self.assertEqual([rev_id], tree.get_parent_ids())
914- with tree.get_file('foo') as f:
915- self.assertEqual(b'contents of foo\n', f.read())
916- tree.unlock()
917+ with tree.lock_read():
918+ self.assertEqual([rev_id], tree.get_parent_ids())
919+ with tree.get_file('foo') as f:
920+ self.assertEqual(b'contents of foo\n', f.read())
921
922 def test_get_root_id(self):
923 branch = self.make_branch('branch')
924 tree = MemoryTree.create_on_branch(branch)
925- tree.lock_write()
926- try:
927+ with tree.lock_write():
928 tree.add([''])
929 self.assertIsNot(None, tree.get_root_id())
930- finally:
931- tree.unlock()
932
933 def test_lock_tree_write(self):
934 """Check we can lock_tree_write and unlock MemoryTrees."""
935@@ -73,9 +69,8 @@
936 """Check that we error when trying to upgrade a read lock to write."""
937 branch = self.make_branch('branch')
938 tree = MemoryTree.create_on_branch(branch)
939- tree.lock_read()
940- self.assertRaises(errors.ReadOnlyError, tree.lock_tree_write)
941- tree.unlock()
942+ with tree.lock_read():
943+ self.assertRaises(errors.ReadOnlyError, tree.lock_tree_write)
944
945 def test_lock_write(self):
946 """Check we can lock_write and unlock MemoryTrees."""
947@@ -88,58 +83,63 @@
948 """Check that we error when trying to upgrade a read lock to write."""
949 branch = self.make_branch('branch')
950 tree = MemoryTree.create_on_branch(branch)
951- tree.lock_read()
952- self.assertRaises(errors.ReadOnlyError, tree.lock_write)
953- tree.unlock()
954+ with tree.lock_read():
955+ self.assertRaises(errors.ReadOnlyError, tree.lock_write)
956
957 def test_add_with_kind(self):
958 branch = self.make_branch('branch')
959 tree = MemoryTree.create_on_branch(branch)
960- tree.lock_write()
961- tree.add(['', 'afile', 'adir'], None,
962- ['directory', 'file', 'directory'])
963- self.assertEqual('afile', tree.id2path(tree.path2id('afile')))
964- self.assertEqual('adir', tree.id2path(tree.path2id('adir')))
965- self.assertFalse(tree.has_filename('afile'))
966- self.assertFalse(tree.has_filename('adir'))
967- tree.unlock()
968+ with tree.lock_write():
969+ tree.add(['', 'afile', 'adir'], None,
970+ ['directory', 'file', 'directory'])
971+ self.assertEqual('afile', tree.id2path(tree.path2id('afile')))
972+ self.assertEqual('adir', tree.id2path(tree.path2id('adir')))
973+ self.assertFalse(tree.has_filename('afile'))
974+ self.assertFalse(tree.has_filename('adir'))
975
976 def test_put_new_file(self):
977 branch = self.make_branch('branch')
978 tree = MemoryTree.create_on_branch(branch)
979- tree.lock_write()
980- tree.add(['', 'foo'], ids=[b'root-id', b'foo-id'],
981- kinds=['directory', 'file'])
982- tree.put_file_bytes_non_atomic('foo', b'barshoom')
983- self.assertEqual(b'barshoom', tree.get_file('foo').read())
984- tree.unlock()
985+ with tree.lock_write():
986+ tree.add(['', 'foo'], ids=[b'root-id', b'foo-id'],
987+ kinds=['directory', 'file'])
988+ tree.put_file_bytes_non_atomic('foo', b'barshoom')
989+ with tree.get_file('foo') as f:
990+ self.assertEqual(b'barshoom', f.read())
991
992 def test_put_existing_file(self):
993 branch = self.make_branch('branch')
994 tree = MemoryTree.create_on_branch(branch)
995- tree.lock_write()
996- tree.add(['', 'foo'], ids=[b'root-id', b'foo-id'],
997- kinds=['directory', 'file'])
998- tree.put_file_bytes_non_atomic('foo', b'first-content')
999- tree.put_file_bytes_non_atomic('foo', b'barshoom')
1000- self.assertEqual(b'barshoom', tree.get_file('foo').read())
1001- tree.unlock()
1002+ with tree.lock_write():
1003+ tree.add(['', 'foo'], ids=[b'root-id', b'foo-id'],
1004+ kinds=['directory', 'file'])
1005+ tree.put_file_bytes_non_atomic('foo', b'first-content')
1006+ tree.put_file_bytes_non_atomic('foo', b'barshoom')
1007+ self.assertEqual(b'barshoom', tree.get_file('foo').read())
1008
1009 def test_add_in_subdir(self):
1010 branch = self.make_branch('branch')
1011 tree = MemoryTree.create_on_branch(branch)
1012- tree.lock_write()
1013- self.addCleanup(tree.unlock)
1014- tree.add([''], [b'root-id'], ['directory'])
1015- # Unfortunately, the only way to 'mkdir' is to call 'tree.mkdir', but
1016- # that *always* adds the directory as well. So if you want to create a
1017- # file in a subdirectory, you have to split out the 'mkdir()' calls
1018- # from the add and put_file_bytes_non_atomic calls. :(
1019- tree.mkdir('adir', b'dir-id')
1020- tree.add(['adir/afile'], [b'file-id'], ['file'])
1021- self.assertEqual('adir/afile', tree.id2path(b'file-id'))
1022- self.assertEqual('adir', tree.id2path(b'dir-id'))
1023- tree.put_file_bytes_non_atomic('adir/afile', b'barshoom')
1024+ with tree.lock_write():
1025+ tree.add([''], [b'root-id'], ['directory'])
1026+ # Unfortunately, the only way to 'mkdir' is to call 'tree.mkdir', but
1027+ # that *always* adds the directory as well. So if you want to create a
1028+ # file in a subdirectory, you have to split out the 'mkdir()' calls
1029+ # from the add and put_file_bytes_non_atomic calls. :(
1030+ tree.mkdir('adir', b'dir-id')
1031+ tree.add(['adir/afile'], [b'file-id'], ['file'])
1032+ self.assertEqual('adir/afile', tree.id2path(b'file-id'))
1033+ self.assertEqual('adir', tree.id2path(b'dir-id'))
1034+ tree.put_file_bytes_non_atomic('adir/afile', b'barshoom')
1035+
1036+ def test_add_symlink(self):
1037+ branch = self.make_branch('branch')
1038+ tree = MemoryTree.create_on_branch(branch)
1039+ with tree.lock_write():
1040+ tree._file_transport.symlink('bar', 'foo')
1041+ tree.add(['', 'foo'])
1042+ self.assertEqual('symlink', tree.kind('foo'))
1043+ self.assertEqual('bar', tree.get_symlink_target('foo'))
1044
1045 def test_commit_trivial(self):
1046 """Smoke test for commit on a MemoryTree.
1047@@ -149,40 +149,35 @@
1048 """
1049 branch = self.make_branch('branch')
1050 tree = MemoryTree.create_on_branch(branch)
1051- tree.lock_write()
1052- tree.add(['', 'foo'], ids=[b'root-id', b'foo-id'],
1053- kinds=['directory', 'file'])
1054- tree.put_file_bytes_non_atomic('foo', b'barshoom')
1055- revision_id = tree.commit('message baby')
1056- # the parents list for the tree should have changed.
1057- self.assertEqual([revision_id], tree.get_parent_ids())
1058- tree.unlock()
1059+ with tree.lock_write():
1060+ tree.add(['', 'foo'], ids=[b'root-id', b'foo-id'],
1061+ kinds=['directory', 'file'])
1062+ tree.put_file_bytes_non_atomic('foo', b'barshoom')
1063+ revision_id = tree.commit('message baby')
1064+ # the parents list for the tree should have changed.
1065+ self.assertEqual([revision_id], tree.get_parent_ids())
1066 # and we should have a revision that is accessible outside the tree lock
1067 revtree = tree.branch.repository.revision_tree(revision_id)
1068- revtree.lock_read()
1069- self.addCleanup(revtree.unlock)
1070- with revtree.get_file('foo') as f:
1071+ with revtree.lock_read(), revtree.get_file('foo') as f:
1072 self.assertEqual(b'barshoom', f.read())
1073
1074 def test_unversion(self):
1075 """Some test for unversion of a memory tree."""
1076 branch = self.make_branch('branch')
1077 tree = MemoryTree.create_on_branch(branch)
1078- tree.lock_write()
1079- tree.add(['', 'foo'], ids=[b'root-id', b'foo-id'],
1080- kinds=['directory', 'file'])
1081- tree.unversion(['foo'])
1082- self.assertFalse(tree.is_versioned('foo'))
1083- self.assertFalse(tree.has_id(b'foo-id'))
1084- tree.unlock()
1085+ with tree.lock_write():
1086+ tree.add(['', 'foo'], ids=[b'root-id', b'foo-id'],
1087+ kinds=['directory', 'file'])
1088+ tree.unversion(['foo'])
1089+ self.assertFalse(tree.is_versioned('foo'))
1090+ self.assertFalse(tree.has_id(b'foo-id'))
1091
1092 def test_last_revision(self):
1093 """There should be a last revision method we can call."""
1094 tree = self.make_branch_and_memory_tree('branch')
1095- tree.lock_write()
1096- tree.add('')
1097- rev_id = tree.commit('first post')
1098- tree.unlock()
1099+ with tree.lock_write():
1100+ tree.add('')
1101+ rev_id = tree.commit('first post')
1102 self.assertEqual(rev_id, tree.last_revision())
1103
1104 def test_rename_file(self):
1105
1106=== modified file 'breezy/tests/test_script.py'
1107--- breezy/tests/test_script.py 2018-11-20 21:24:08 +0000
1108+++ breezy/tests/test_script.py 2019-03-06 06:08:28 +0000
1109@@ -322,12 +322,12 @@
1110 def test_cat_input_to_file(self):
1111 retcode, out, err = self.run_command(['cat', '>file'],
1112 'content\n', None, None)
1113- self.assertFileEqual(b'content\n', 'file')
1114+ self.assertFileEqual('content\n', 'file')
1115 self.assertEqual(None, out)
1116 self.assertEqual(None, err)
1117 retcode, out, err = self.run_command(['cat', '>>file'],
1118 'more\n', None, None)
1119- self.assertFileEqual(b'content\nmore\n', 'file')
1120+ self.assertFileEqual('content\nmore\n', 'file')
1121 self.assertEqual(None, out)
1122 self.assertEqual(None, err)
1123
1124
1125=== modified file 'breezy/tests/test_urlutils.py'
1126--- breezy/tests/test_urlutils.py 2018-11-23 03:06:01 +0000
1127+++ breezy/tests/test_urlutils.py 2019-03-06 06:08:28 +0000
1128@@ -599,6 +599,9 @@
1129 self.assertEqual(("foo/base,key1=val1/other/elements",
1130 {"key2": "val2"}), split_segment_parameters(
1131 "foo/base,key1=val1/other/elements,key2=val2"))
1132+ self.assertRaises(
1133+ urlutils.InvalidURL, split_segment_parameters,
1134+ "foo/base,key1")
1135 # TODO: Check full URLs as well as relative references
1136
1137 def test_win32_strip_local_trailing_slash(self):
1138
1139=== modified file 'breezy/transport/memory.py'
1140--- breezy/transport/memory.py 2018-11-17 16:53:10 +0000
1141+++ breezy/transport/memory.py 2019-03-06 06:08:28 +0000
1142@@ -26,9 +26,10 @@
1143 from io import (
1144 BytesIO,
1145 )
1146+import itertools
1147 import os
1148 import errno
1149-from stat import S_IFREG, S_IFDIR, S_IFLNK
1150+from stat import S_IFREG, S_IFDIR, S_IFLNK, S_ISDIR
1151
1152 from .. import (
1153 transport,
1154@@ -50,20 +51,16 @@
1155
1156 class MemoryStat(object):
1157
1158- def __init__(self, size, kind, perms):
1159+ def __init__(self, size, kind, perms=None):
1160 self.st_size = size
1161- if kind == 'file':
1162+ if not S_ISDIR(kind):
1163 if perms is None:
1164 perms = 0o644
1165- self.st_mode = S_IFREG | perms
1166- elif kind == 'directory':
1167+ self.st_mode = kind | perms
1168+ else:
1169 if perms is None:
1170 perms = 0o755
1171- self.st_mode = S_IFDIR | perms
1172- elif kind == 'symlink':
1173- self.st_mode = S_IFLNK | 0o644
1174- else:
1175- raise AssertionError('unknown kind %r' % kind)
1176+ self.st_mode = kind | perms
1177
1178
1179 class MemoryTransport(transport.Transport):
1180@@ -111,7 +108,7 @@
1181
1182 def append_file(self, relpath, f, mode=None):
1183 """See Transport.append_file()."""
1184- _abspath = self._abspath(relpath)
1185+ _abspath = self._resolve_symlinks(relpath)
1186 self._check_parent(_abspath)
1187 orig_content, orig_mode = self._files.get(_abspath, (b"", None))
1188 if mode is None:
1189@@ -128,16 +125,20 @@
1190 def has(self, relpath):
1191 """See Transport.has()."""
1192 _abspath = self._abspath(relpath)
1193- return ((_abspath in self._files)
1194- or (_abspath in self._dirs)
1195- or (_abspath in self._symlinks))
1196+ for container in (self._files, self._dirs, self._symlinks):
1197+ if _abspath in container.keys():
1198+ return True
1199+ return False
1200
1201 def delete(self, relpath):
1202 """See Transport.delete()."""
1203 _abspath = self._abspath(relpath)
1204- if _abspath not in self._files:
1205+ if _abspath in self._files:
1206+ del self._files[_abspath]
1207+ elif _abspath in self._symlinks:
1208+ del self._symlinks[_abspath]
1209+ else:
1210 raise NoSuchFile(relpath)
1211- del self._files[_abspath]
1212
1213 def external_url(self):
1214 """See breezy.transport.Transport.external_url."""
1215@@ -147,7 +148,7 @@
1216
1217 def get(self, relpath):
1218 """See Transport.get()."""
1219- _abspath = self._abspath(relpath)
1220+ _abspath = self._resolve_symlinks(relpath)
1221 if _abspath not in self._files:
1222 if _abspath in self._dirs:
1223 return LateReadError(relpath)
1224@@ -157,15 +158,20 @@
1225
1226 def put_file(self, relpath, f, mode=None):
1227 """See Transport.put_file()."""
1228- _abspath = self._abspath(relpath)
1229+ _abspath = self._resolve_symlinks(relpath)
1230 self._check_parent(_abspath)
1231 raw_bytes = f.read()
1232 self._files[_abspath] = (raw_bytes, mode)
1233 return len(raw_bytes)
1234
1235+ def symlink(self, source, target):
1236+ _abspath = self._resolve_symlinks(target)
1237+ self._check_parent(_abspath)
1238+ self._symlinks[_abspath] = self._abspath(source)
1239+
1240 def mkdir(self, relpath, mode=None):
1241 """See Transport.mkdir()."""
1242- _abspath = self._abspath(relpath)
1243+ _abspath = self._resolve_symlinks(relpath)
1244 self._check_parent(_abspath)
1245 if _abspath in self._dirs:
1246 raise FileExists(relpath)
1247@@ -183,13 +189,13 @@
1248 return True
1249
1250 def iter_files_recursive(self):
1251- for file in self._files:
1252+ for file in itertools.chain(self._files, self._symlinks):
1253 if file.startswith(self._cwd):
1254 yield urlutils.escape(file[len(self._cwd):])
1255
1256 def list_dir(self, relpath):
1257 """See Transport.list_dir()."""
1258- _abspath = self._abspath(relpath)
1259+ _abspath = self._resolve_symlinks(relpath)
1260 if _abspath != '/' and _abspath not in self._dirs:
1261 raise NoSuchFile(relpath)
1262 result = []
1263@@ -197,7 +203,7 @@
1264 if not _abspath.endswith('/'):
1265 _abspath += '/'
1266
1267- for path_group in self._files, self._dirs:
1268+ for path_group in self._files, self._dirs, self._symlinks:
1269 for path in path_group:
1270 if path.startswith(_abspath):
1271 trailing = path[len(_abspath):]
1272@@ -207,8 +213,8 @@
1273
1274 def rename(self, rel_from, rel_to):
1275 """Rename a file or directory; fail if the destination exists"""
1276- abs_from = self._abspath(rel_from)
1277- abs_to = self._abspath(rel_to)
1278+ abs_from = self._resolve_symlinks(rel_from)
1279+ abs_to = self._resolve_symlinks(rel_to)
1280
1281 def replace(x):
1282 if x == abs_from:
1283@@ -233,21 +239,25 @@
1284 # fail differently depending on dict order. So work on copy, fail on
1285 # error on only replace dicts if all goes well.
1286 renamed_files = self._files.copy()
1287+ renamed_symlinks = self._symlinks.copy()
1288 renamed_dirs = self._dirs.copy()
1289 do_renames(renamed_files)
1290+ do_renames(renamed_symlinks)
1291 do_renames(renamed_dirs)
1292 # We may have been cloned so modify in place
1293 self._files.clear()
1294 self._files.update(renamed_files)
1295+ self._symlinks.clear()
1296+ self._symlinks.update(renamed_symlinks)
1297 self._dirs.clear()
1298 self._dirs.update(renamed_dirs)
1299
1300 def rmdir(self, relpath):
1301 """See Transport.rmdir."""
1302- _abspath = self._abspath(relpath)
1303+ _abspath = self._resolve_symlinks(relpath)
1304 if _abspath in self._files:
1305 self._translate_error(IOError(errno.ENOTDIR, relpath), relpath)
1306- for path in self._files:
1307+ for path in itertools.chain(self._files, self._symlinks):
1308 if path.startswith(_abspath + '/'):
1309 self._translate_error(IOError(errno.ENOTEMPTY, relpath),
1310 relpath)
1311@@ -262,13 +272,13 @@
1312 def stat(self, relpath):
1313 """See Transport.stat()."""
1314 _abspath = self._abspath(relpath)
1315- if _abspath in self._files:
1316- return MemoryStat(len(self._files[_abspath][0]), 'file',
1317+ if _abspath in self._files.keys():
1318+ return MemoryStat(len(self._files[_abspath][0]), S_IFREG,
1319 self._files[_abspath][1])
1320- elif _abspath in self._dirs:
1321- return MemoryStat(0, 'directory', self._dirs[_abspath])
1322- elif _abspath in self._symlinks:
1323- return MemoryStat(0, 'symlink', 0)
1324+ elif _abspath in self._dirs.keys():
1325+ return MemoryStat(0, S_IFDIR, self._dirs[_abspath])
1326+ elif _abspath in self._symlinks.keys():
1327+ return MemoryStat(0, S_IFLNK)
1328 else:
1329 raise NoSuchFile(_abspath)
1330
1331@@ -280,6 +290,12 @@
1332 """See Transport.lock_write()."""
1333 return _MemoryLock(self._abspath(relpath), self)
1334
1335+ def _resolve_symlinks(self, relpath):
1336+ path = self._abspath(relpath)
1337+ while path in self._symlinks.keys():
1338+ path = self._symlinks[path]
1339+ return path
1340+
1341 def _abspath(self, relpath):
1342 """Generate an internal absolute path."""
1343 relpath = urlutils.unescape(relpath)
1344@@ -336,6 +352,7 @@
1345 def start_server(self):
1346 self._dirs = {'/': None}
1347 self._files = {}
1348+ self._symlinks = {}
1349 self._locks = {}
1350 self._scheme = "memory+%s:///" % id(self)
1351
1352@@ -344,6 +361,7 @@
1353 result = memory.MemoryTransport(url)
1354 result._dirs = self._dirs
1355 result._files = self._files
1356+ result._symlinks = self._symlinks
1357 result._locks = self._locks
1358 return result
1359 self._memory_factory = memory_factory
1360
1361=== modified file 'breezy/urlutils.py'
1362--- breezy/urlutils.py 2018-11-16 23:19:12 +0000
1363+++ breezy/urlutils.py 2019-03-06 06:08:28 +0000
1364@@ -561,7 +561,10 @@
1365 (base_url, subsegments) = split_segment_parameters_raw(url)
1366 parameters = {}
1367 for subsegment in subsegments:
1368- (key, value) = subsegment.split("=", 1)
1369+ try:
1370+ (key, value) = subsegment.split("=", 1)
1371+ except ValueError:
1372+ raise InvalidURL(url, "missing = in subsegment")
1373 if not isinstance(key, str):
1374 raise TypeError(key)
1375 if not isinstance(value, str):
1376
1377=== added file 'build.cmd'
1378--- build.cmd 1970-01-01 00:00:00 +0000
1379+++ build.cmd 2019-03-06 06:08:28 +0000
1380@@ -0,0 +1,21 @@
1381+@echo off
1382+:: To build extensions for 64 bit Python 3, we need to configure environment
1383+:: variables to use the MSVC 2010 C++ compilers from GRMSDKX_EN_DVD.iso of:
1384+:: MS Windows SDK for Windows 7 and .NET Framework 4
1385+::
1386+:: More details at:
1387+:: https://github.com/cython/cython/wiki/CythonExtensionsOnWindows
1388+
1389+IF "%DISTUTILS_USE_SDK%"=="1" (
1390+ ECHO Configuring environment to build with MSVC on a 64bit architecture
1391+ ECHO Using Windows SDK 7.1
1392+ "C:\Program Files\Microsoft SDKs\Windows\v7.1\Setup\WindowsSdkVer.exe" -q -version:v7.1
1393+ CALL "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64 /release
1394+ SET MSSdk=1
1395+ REM Need the following to allow tox to see the SDK compiler
1396+ SET TOX_TESTENV_PASSENV=DISTUTILS_USE_SDK MSSdk INCLUDE LIB
1397+) ELSE (
1398+ ECHO Using default MSVC build environment
1399+)
1400+
1401+CALL %*
1402
1403=== modified file 'byov.conf'
1404--- byov.conf 2018-12-19 01:30:58 +0000
1405+++ byov.conf 2019-03-06 06:08:28 +0000
1406@@ -13,6 +13,8 @@
1407 sphinx_epytext.install3 = (pip3 install sphinx_epytext)
1408 flake8.install = (pip install flake8)
1409 flake8.install3 = (pip3 install flake8)
1410+cython.install = (pip install cython)
1411+cython.install3 = (pip3 install cython)
1412
1413 [brz]
1414 # FIXME: we're stuck on xenial
1415@@ -25,12 +27,12 @@
1416
1417 # FIXME: Arguably this should be vm.build_deps=brz but it requires either an
1418 # available package or at least a debian/ dir ? -- vila 2018-02-23
1419-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-pip, python3-pip, python-setuptools, python3-setuptools, python-flake8, python3-flake8, python-sphinx, python3-sphinx, python-launchpadlib, python3-launchpadlib
1420+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, python-pip, python3-pip, python-setuptools, python3-setuptools, python-flake8, python3-flake8, python-sphinx, python3-sphinx, python-launchpadlib, python3-launchpadlib
1421 subunit.build_deps = python-testscenarios, python3-testscenarios, python-testtools, python3-testtools
1422 vm.packages = {brz.build_deps}, {subunit.build_deps}, bzr, git, python-junitxml
1423 [brz-xenial]
1424 vm.release = xenial
1425-byoci.setup.command = ({dulwich.clone} && {dulwich.install} && {dulwich.install3} && {fastimport.clone} && {fastimport.install} && {fastimport.install3} && {subunit.clone} && {flake8.install} && {flake8.install3} && {sphinx_epytext.install} && {sphinx_epytext.install3})
1426+byoci.setup.command = ({dulwich.clone} && {dulwich.install} && {dulwich.install3} && {fastimport.clone} && {fastimport.install} && {fastimport.install3} && {subunit.clone} && {flake8.install} && {flake8.install3} && {sphinx_epytext.install} && {sphinx_epytext.install3} && {cython.install} && {cython.install3})
1427 # FIXME: bzr log -l2 should be by default -- vila 2018-03-09
1428 byoci.tests.command = bash -o pipefail -c "bzr log -l2 && PYTHONPATH=../subunit/python:$PYTHONPATH PATH=../subunit/filters:$PATH make check-ci | subunit2junitxml -o ../results.xml -f | subunit2pyunit"
1429 [brz-bionic]
1430
1431=== modified file 'doc/developers/apport.txt'
1432--- doc/developers/apport.txt 2009-12-02 20:34:07 +0000
1433+++ doc/developers/apport.txt 2019-03-06 06:08:28 +0000
1434@@ -41,7 +41,7 @@
1435
1436 #. An exception reaches the top-level handler.
1437
1438-#. We log it in apport-format to a file in ~/.bazaar/crash.
1439+#. We log it in apport-format to a file in ~/.config/breezy/crash.
1440
1441 #. We tell the user where that file is, and invite them to file a bug
1442 report.
1443
1444=== modified file 'doc/developers/configuration.txt'
1445--- doc/developers/configuration.txt 2017-07-30 16:59:50 +0000
1446+++ doc/developers/configuration.txt 2019-03-06 06:08:28 +0000
1447@@ -154,20 +154,6 @@
1448 though). The ``bzr-bookmarks`` plugin defines a ``BOOKMARKS`` section there
1449 for example.
1450
1451-pkgimport.conf
1452-==============
1453-
1454-The Ubuntu package importer defines a store and two stacks involving
1455-``pkgimport.conf``. A no-name section contains the options common to all
1456-packages and sections named after their corresponding package can also be
1457-defined.
1458-
1459-The ``ImporterStack`` uses ``locations.conf`` and the no-name section in
1460-``pkgimport.conf`` for the importer options.
1461-
1462-The ``PackageStack`` uses only ``pkgimport.conf`` and uses the section name
1463-after the package followed by the no-name section.
1464-
1465 location.conf
1466 =============
1467
1468
1469=== modified file 'doc/developers/contribution-quickstart.txt'
1470--- doc/developers/contribution-quickstart.txt 2019-01-01 21:38:07 +0000
1471+++ doc/developers/contribution-quickstart.txt 2019-03-06 06:08:28 +0000
1472@@ -46,7 +46,7 @@
1473 closely-related cluster of bugs per branch, to make reviews and merges
1474 flow more smoothly.
1475
1476-You probably want this configuration in ``~/.bazaar/locations.conf``::
1477+You probably want this configuration in ``~/.config/breezy/locations.conf``::
1478
1479 [/home/USER/brz]
1480 push_location = lp:~LAUNCHPAD_USER/brz/{branchname}
1481
1482=== modified file 'doc/developers/plugin-development.txt'
1483--- doc/developers/plugin-development.txt 2018-11-22 02:23:26 +0000
1484+++ doc/developers/plugin-development.txt 2019-03-06 06:08:28 +0000
1485@@ -31,7 +31,7 @@
1486 To ensure your plugin under development is available to Breezy, set
1487 the ``BRZ_PLUGIN_PATH`` environment variable to its parent directory.
1488 Alternatively, you may wish to develop your plugin within a directory
1489-under your personal plugins area (``~/.bazaar/plugins`` on GNU/Linux)
1490+under your personal plugins area (``~/.config/breezy/plugins`` on GNU/Linux)
1491 or put a symbolic link in that area pointing to your plugin under
1492 test. Finally you can use ``BRZ_PLUGINS_AT`` to point to a specific
1493 directory for a specific plugin (separated by your platform's value of
1494
1495=== modified file 'doc/en/admin-guide/hooks-plugins.txt'
1496--- doc/en/admin-guide/hooks-plugins.txt 2018-11-18 13:20:01 +0000
1497+++ doc/en/admin-guide/hooks-plugins.txt 2019-03-06 06:08:28 +0000
1498@@ -25,10 +25,10 @@
1499 http://doc.bazaar.canonical.com/plugins/en/. For purposes of installation,
1500 plugins are simply python packages. They can be installed alongside Bazaar in
1501 the ``bzrlib.plugins`` package using each plugin's ``setup.py``. They can
1502-also be installed in the plugin path which is the user's ``~/.bazaar/plugins``
1503-directory or can be specified with the ``BZR_PLUGIN_PATH`` environment
1504-variable. See ``bzr help configuration`` for more on specifying the location
1505-of plugins.
1506+also be installed in the plugin path which is the user's
1507+``~/.config/breezy/plugins`` directory or can be specified with the
1508+``BZR_PLUGIN_PATH`` environment variable. See ``bzr help configuration`` for
1509+more on specifying the location of plugins.
1510
1511
1512 Email Notification
1513
1514=== modified file 'doc/en/admin-guide/migration.txt'
1515--- doc/en/admin-guide/migration.txt 2018-11-18 13:20:01 +0000
1516+++ doc/en/admin-guide/migration.txt 2019-03-06 06:08:28 +0000
1517@@ -56,7 +56,7 @@
1518 This command has flexible ways to specify what paths within the Subversion
1519 repository contain branches and which contain tags. For example, the
1520 recommended layout for Subversion projects (called ``trunk`` by the svn
1521-plugin) could be specified in ``~/.bazaar/subversion.conf`` as
1522+plugin) could be specified in ``~/.config/breezy/subversion.conf`` as
1523
1524 ::
1525
1526
1527=== modified file 'doc/en/release-notes/brz-3.0.txt'
1528--- doc/en/release-notes/brz-3.0.txt 2019-03-02 22:31:28 +0000
1529+++ doc/en/release-notes/brz-3.0.txt 2019-03-06 06:08:28 +0000
1530@@ -85,6 +85,9 @@
1531 longer performed, since there are no longer
1532 any automated imports. (Jelmer Vernooij)
1533
1534+ * ``setuptools`` is now required to build and install Breezy.
1535+ (Jelmer Vernooij)
1536+
1537 New Features
1538 ************
1539
1540@@ -234,6 +237,13 @@
1541 * Don't report .git files as unknown files.
1542 (Jelmer Vernooij, Debian Bug #921240)
1543
1544+* Raise better error when path subsegments lack =.
1545+ (Jelmer Vernooij, #891483)
1546+
1547+* Display correct pull location argument in
1548+ output of ``brz uncommit``.
1549+ (Jelmer Vernooij, #386577)
1550+
1551 Documentation
1552 *************
1553
1554
1555=== modified file 'doc/en/user-guide/controlling_registration.txt'
1556--- doc/en/user-guide/controlling_registration.txt 2017-05-21 13:41:54 +0000
1557+++ doc/en/user-guide/controlling_registration.txt 2019-03-06 06:08:28 +0000
1558@@ -95,12 +95,12 @@
1559 There are some ignored files which are not project specific, but more user
1560 specific. Things like editor temporary files, or personal temporary files.
1561 Rather than add these ignores to every project, brz supports a global
1562-ignore file in ``~/.bazaar/ignore`` [#]_. It has the same syntax as the
1563+ignore file in ``~/.config/breezy/ignore`` [#]_. It has the same syntax as the
1564 per-project ignore file.
1565
1566 .. [#] On Windows, the users configuration files can be found in the
1567- application data directory. So instead of ``~/.bazaar/branch.conf``
1568+ application data directory. So instead of ``~/.config/breezy/branch.conf``
1569 the configuration file can be found as:
1570- ``C:\Documents and Settings\<username>\Application Data\Breezy\2.0\branch.conf``.
1571+ ``C:\Documents and Settings\<username>\Application Data\Breezy\3.0\branch.conf``.
1572 The same is true for ``locations.conf``, ``ignore``, and the
1573 ``plugins`` directory.
1574
1575=== added file 'doc/en/user-guide/git_limitations.txt'
1576--- doc/en/user-guide/git_limitations.txt 1970-01-01 00:00:00 +0000
1577+++ doc/en/user-guide/git_limitations.txt 2019-03-06 06:08:28 +0000
1578@@ -0,0 +1,18 @@
1579+Git Limitations
1580+===============
1581+
1582+Breezy's support for Git repositories currently has the following limitations:
1583+
1584+* No support for creating annotated tags. pad.lv/1758185
1585+* No support for gitattributes and the features that depend on it (lfs, eol, etc). pad.lv/1802797
1586+* Limited support for submodules. pad.lv/402814
1587+* No rename/copy inference. pad.lv/1760740
1588+* No support for creating shallow branches (pad.lv/1760151)
1589+* No good way to refer to git remotes from the command-line (pad.lv/1702283)
1590+* No mailmap support (pad.lv/544031)
1591+
1592+Functionality similar to git that's missing:
1593+
1594+* No rebase command. pad.lv/1708046
1595+* No --amend option for commit. pad.lv/507529
1596+* No clone/fetch commands. pad.lv/831939
1597
1598=== modified file 'doc/en/user-guide/index-plain.txt'
1599--- doc/en/user-guide/index-plain.txt 2018-11-24 15:56:05 +0000
1600+++ doc/en/user-guide/index-plain.txt 2019-03-06 06:08:28 +0000
1601@@ -114,6 +114,7 @@
1602 .. include:: setting_up_email.txt
1603 .. include:: http_smart_server.txt
1604 .. include:: writing_a_plugin.txt
1605+.. include:: git_limitations.txt
1606 .. include:: licence.txt
1607
1608 .. |--| unicode:: U+2014
1609
1610=== modified file 'doc/en/user-guide/installing_breezy.txt'
1611--- doc/en/user-guide/installing_breezy.txt 2018-11-18 13:43:04 +0000
1612+++ doc/en/user-guide/installing_breezy.txt 2019-03-06 06:08:28 +0000
1613@@ -90,7 +90,7 @@
1614 3. Put the created directory on your PATH.
1615
1616 Advanced users may also wish to build the optional C extensions for greater
1617-speed. This can be done using ``make`` and requires ``pyrex`` and a C compiler.
1618+speed. This can be done using ``make`` and requires ``cython`` and a C compiler.
1619 Please contact us on email or IRC if you need assistance with this.
1620
1621
1622
1623=== modified file 'doc/en/user-guide/plugins.txt'
1624--- doc/en/user-guide/plugins.txt 2017-05-21 13:41:54 +0000
1625+++ doc/en/user-guide/plugins.txt 2019-03-06 06:08:28 +0000
1626@@ -35,7 +35,7 @@
1627
1628 Installing a plugin is very easy! If not already created, create a
1629 ``plugins`` directory under your Breezy configuration directory,
1630-``~/.bazaar/`` on Unix and
1631+``~/.config/breezy/`` on Unix and
1632 ``C:\Documents and Settings\<username>\Application Data\Breezy\2.0\``
1633 on Windows. Within this directory (referred to as $BZR_HOME below),
1634 each plugin is placed in its own subdirectory.
1635@@ -45,7 +45,7 @@
1636 one can perform the following::
1637
1638 brz branch http://panoramicfeedback.com/opensource/brz/brztools
1639- ~/.bazaar/plugins/brztools
1640+ ~/.config/breezy/plugins/brztools
1641
1642 When installing plugins, the directories that you install them in must
1643 be valid python identifiers. This means that they can only contain
1644
1645=== modified file 'setup.py'
1646--- setup.py 2019-02-06 05:44:37 +0000
1647+++ setup.py 2019-03-06 06:08:28 +0000
1648@@ -16,6 +16,14 @@
1649 sys.stderr.write("[ERROR] Not a supported Python version. Need 2.7+\n")
1650 sys.exit(1)
1651
1652+
1653+try:
1654+ import setuptools
1655+except ImportError:
1656+ sys.stderr.write("[ERROR] Please install setuptools\n")
1657+ sys.exit(1)
1658+
1659+
1660 # NOTE: The directory containing setup.py, whether run by 'python setup.py' or
1661 # './setup.py' or the equivalent with another path, should always be at the
1662 # start of the path, so this should find the right one...
1663@@ -118,8 +126,7 @@
1664 BREEZY['packages'] = get_breezy_packages()
1665
1666
1667-from distutils import log
1668-from distutils.core import setup
1669+from setuptools import setup
1670 from distutils.version import LooseVersion
1671 from distutils.command.install_scripts import install_scripts
1672 from distutils.command.install_data import install_data
1673@@ -211,8 +218,17 @@
1674 print("")
1675 from distutils.command.build_ext import build_ext
1676 else:
1677- have_cython = True
1678+ minimum_cython_version = '0.29'
1679 cython_version_info = LooseVersion(cython_version)
1680+ if cython_version_info < LooseVersion(minimum_cython_version):
1681+ print("Version of Cython is too old. "
1682+ "Current is %s, need at least %s."
1683+ % (cython_version, minimum_cython_version))
1684+ print("If the .c files are available, they will be built,"
1685+ " but modifying the .pyx files will not rebuild them.")
1686+ have_cython = False
1687+ else:
1688+ have_cython = True
1689
1690
1691 class build_ext_if_possible(build_ext):

Subscribers

People subscribed via source and target branches