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
=== added file 'appveyor.yml'
--- appveyor.yml 1970-01-01 00:00:00 +0000
+++ appveyor.yml 2019-03-06 06:08:28 +0000
@@ -0,0 +1,92 @@
1environment:
2
3 matrix:
4
5 - PYTHON: "C:\\Python27"
6 PYTHON_VERSION: "2.7.x"
7 PYTHON_ARCH: "32"
8
9 - PYTHON: "C:\\Python27-x64"
10 PYTHON_VERSION: "2.7.x"
11 PYTHON_ARCH: "64"
12
13 - PYTHON: "C:\\Python34"
14 PYTHON_VERSION: "3.4.x"
15 PYTHON_ARCH: "32"
16
17 - PYTHON: "C:\\Python34-x64"
18 PYTHON_VERSION: "3.4.x"
19 PYTHON_ARCH: "64"
20 DISTUTILS_USE_SDK: "1"
21
22 - PYTHON: "C:\\Python35"
23 PYTHON_VERSION: "3.5.x"
24 PYTHON_ARCH: "32"
25
26 - PYTHON: "C:\\Python35-x64"
27 PYTHON_VERSION: "3.5.x"
28 PYTHON_ARCH: "64"
29
30 - PYTHON: "C:\\Python36"
31 PYTHON_VERSION: "3.6.x"
32 PYTHON_ARCH: "32"
33
34 - PYTHON: "C:\\Python36-x64"
35 PYTHON_VERSION: "3.6.x"
36 PYTHON_ARCH: "64"
37
38install:
39 # If there is a newer build queued for the same PR, cancel this one.
40 # The AppVeyor 'rollout builds' option is supposed to serve the same
41 # purpose but it is problematic because it tends to cancel builds pushed
42 # directly to master instead of just PR builds (or the converse).
43 # credits: JuliaLang developers.
44 - ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod `
45 https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | `
46 Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { `
47 throw "There are newer queued builds for this pull request, failing early." }
48 - ECHO "Filesystem root:"
49 - ps: "ls \"C:/\""
50
51 - ECHO "Installed SDKs:"
52 - ps: "ls \"C:/Program Files/Microsoft SDKs/Windows\""
53
54 # Install Python (from the official .msi of http://python.org) and pip when
55 # not already installed.
56 - ps: if (-not(Test-Path($env:PYTHON))) { & appveyor\install.ps1 }
57
58 # Prepend newly installed Python to the PATH of this build (this cannot be
59 # done from inside the powershell script as it would require to restart
60 # the parent CMD process).
61 - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
62
63 # Check that we have the expected version and architecture for Python
64 - "build.cmd %PYTHON%\\python.exe --version"
65 - "build.cmd %PYTHON%\\python.exe -c \"import struct; print(struct.calcsize('P') * 8)\""
66
67 # Install setuptools/wheel so that we can e.g. use bdist_wheel
68 - "pip install setuptools wheel"
69 # Install cython so we can build C extensions
70 - "pip install cython"
71
72 - "build.cmd %PYTHON%\\python.exe setup.py develop"
73
74 - "pip install launchpadlib"
75
76build_script:
77 # Build the compiled extension
78 - "build.cmd %PYTHON%\\python.exe setup.py build"
79
80test_script:
81 - "build.cmd %PYTHON%\\python.exe setup.py test"
82 - "build.cmd %PYTHON%\\pythonw.exe setup.py test"
83
84after_test:
85 - "build.cmd %PYTHON%\\python.exe setup.py bdist_wheel"
86 # http://stackoverflow.com/questions/43255455/unicode-character-causing-error-with-bdist-wininst-on-python-3-but-not-python-2
87 # - "python setup.py bdist_wininst"
88 - "build.cmd %PYTHON%\\python.exe setup.py bdist_msi"
89 - ps: "ls dist"
90
91artifacts:
92 - path: dist\*
093
=== modified file 'breezy/_patiencediff_c.c'
--- breezy/_patiencediff_c.c 2019-01-27 18:53:46 +0000
+++ breezy/_patiencediff_c.c 2019-03-06 06:08:28 +0000
@@ -1163,14 +1163,47 @@
11631163
11641164
1165static PyTypeObject PatienceSequenceMatcherType = {1165static PyTypeObject PatienceSequenceMatcherType = {
1166 PyObject_HEAD_INIT(NULL)1166 PyVarObject_HEAD_INIT(NULL, 0)
1167 .tp_name = "PatienceSequenceMatcher",1167 "PatienceSequenceMatcher", /* tp_name */
1168 .tp_basicsize = sizeof(PatienceSequenceMatcher),1168 sizeof(PatienceSequenceMatcher), /* tp_basicsize */
1169 .tp_dealloc = (destructor)PatienceSequenceMatcher_dealloc,1169 sizeof(PyObject *), /* tp_itemsize */
1170 .tp_flags = Py_TPFLAGS_DEFAULT,1170 (destructor)PatienceSequenceMatcher_dealloc, /* tp_dealloc */
1171 .tp_doc = PatienceSequenceMatcher_doc,1171 0, /* tp_print */
1172 .tp_methods = PatienceSequenceMatcher_methods,1172 0, /* tp_getattr */
1173 .tp_new = PatienceSequenceMatcher_new,1173 0, /* tp_setattr */
1174 0, /* tp_compare */
1175 0, /* tp_repr */
1176 0, /* tp_as_number */
1177 0, /* tp_as_sequence */
1178 0, /* tp_as_mapping */
1179 0, /* tp_hash */
1180 0, /* tp_call */
1181 0, /* tp_str */
1182 0, /* tp_getattro */
1183 0, /* tp_setattro */
1184 0, /* tp_as_buffer */
1185 Py_TPFLAGS_DEFAULT, /* tp_flags */
1186 PatienceSequenceMatcher_doc, /* tp_doc */
1187 0, /* tp_traverse */
1188 0, /* tp_clear */
1189 0, /* tp_richcompare */
1190 0, /* tp_weaklistoffset */
1191 // without implementing tp_iter, Python will fall back to PySequence*
1192 // which seems to work ok, we may need something faster/lighter in the
1193 // future.
1194 0, /* tp_iter */
1195 0, /* tp_iternext */
1196 PatienceSequenceMatcher_methods, /* tp_methods */
1197 0, /* tp_members */
1198 0, /* tp_getset */
1199 0, /* tp_base */
1200 0, /* tp_dict */
1201 0, /* tp_descr_get */
1202 0, /* tp_descr_set */
1203 0, /* tp_dictoffset */
1204 0, /* tp_init */
1205 0, /* tp_alloc */
1206 PatienceSequenceMatcher_new, /* tp_new */
1174};1207};
11751208
11761209
11771210
=== modified file 'breezy/builtins.py'
--- breezy/builtins.py 2019-02-09 03:23:20 +0000
+++ breezy/builtins.py 2019-03-06 06:08:28 +0000
@@ -348,7 +348,7 @@
348 Not versioned and not matching an ignore pattern.348 Not versioned and not matching an ignore pattern.
349349
350 Additionally for directories, symlinks and files with a changed350 Additionally for directories, symlinks and files with a changed
351 executable bit, Bazaar indicates their type using a trailing351 executable bit, Breezy indicates their type using a trailing
352 character: '/', '@' or '*' respectively. These decorations can be352 character: '/', '@' or '*' respectively. These decorations can be
353 disabled using the '--no-classify' option.353 disabled using the '--no-classify' option.
354354
@@ -454,11 +454,11 @@
454454
455 b = controldir.ControlDir.open_containing_tree_or_branch(directory)[1]455 b = controldir.ControlDir.open_containing_tree_or_branch(directory)[1]
456456
457 revisions = b.repository.revisions457 revisions = getattr(b.repository, "revisions", None)
458 if revisions is None:458 if revisions is None:
459 raise errors.BzrCommandError(459 raise errors.BzrCommandError(
460 gettext('Repository %r does not support '460 gettext('Repository %r does not support '
461 'access to raw revision texts'))461 'access to raw revision texts') % b.repository)
462462
463 with b.repository.lock_read():463 with b.repository.lock_read():
464 # TODO: jam 20060112 should cat-revision always output utf-8?464 # TODO: jam 20060112 should cat-revision always output utf-8?
@@ -1344,6 +1344,7 @@
1344 use_existing_dir=False, directory=None, stacked_on=None,1344 use_existing_dir=False, directory=None, stacked_on=None,
1345 stacked=False, strict=None, no_tree=False,1345 stacked=False, strict=None, no_tree=False,
1346 overwrite_tags=False, lossy=False):1346 overwrite_tags=False, lossy=False):
1347 from .location import location_to_url
1347 from .push import _show_push_branch1348 from .push import _show_push_branch
13481349
1349 if overwrite:1350 if overwrite:
@@ -1371,6 +1372,7 @@
1371 more_warning='Uncommitted changes will not be pushed.')1372 more_warning='Uncommitted changes will not be pushed.')
1372 # Get the stacked_on branch, if any1373 # Get the stacked_on branch, if any
1373 if stacked_on is not None:1374 if stacked_on is not None:
1375 stacked_on = location_to_url(stacked_on, 'read')
1374 stacked_on = urlutils.normalize_url(stacked_on)1376 stacked_on = urlutils.normalize_url(stacked_on)
1375 elif stacked:1377 elif stacked:
1376 parent_url = br_from.get_parent()1378 parent_url = br_from.get_parent()
@@ -1728,7 +1730,7 @@
1728 If the tree's branch is bound to a master branch, brz will also update1730 If the tree's branch is bound to a master branch, brz will also update
1729 the branch from the master.1731 the branch from the master.
17301732
1731 You cannot update just a single file or directory, because each Bazaar1733 You cannot update just a single file or directory, because each Breezy
1732 working tree has just a single basis revision. If you want to restore a1734 working tree has just a single basis revision. If you want to restore a
1733 file that has been removed locally, use 'brz revert' instead of 'brz1735 file that has been removed locally, use 'brz revert' instead of 'brz
1734 update'. If you want to restore a file to its state in a previous1736 update'. If you want to restore a file to its state in a previous
@@ -1871,11 +1873,11 @@
1871class cmd_remove(Command):1873class cmd_remove(Command):
1872 __doc__ = """Remove files or directories.1874 __doc__ = """Remove files or directories.
18731875
1874 This makes Bazaar stop tracking changes to the specified files. Bazaar will1876 This makes Breezy stop tracking changes to the specified files. Breezy will
1875 delete them if they can easily be recovered using revert otherwise they1877 delete them if they can easily be recovered using revert otherwise they
1876 will be backed up (adding an extension of the form .~#~). If no options or1878 will be backed up (adding an extension of the form .~#~). If no options or
1877 parameters are given Bazaar will scan for files that are being tracked by1879 parameters are given Breezy will scan for files that are being tracked by
1878 Bazaar but missing in your tree and stop tracking them for you.1880 Breezy but missing in your tree and stop tracking them for you.
1879 """1881 """
1880 takes_args = ['file*']1882 takes_args = ['file*']
1881 takes_options = ['verbose',1883 takes_options = ['verbose',
@@ -3091,9 +3093,10 @@
3091 using this command or directly by using an editor, be sure to commit3093 using this command or directly by using an editor, be sure to commit
3092 it.3094 it.
30933095
3094 Bazaar also supports a global ignore file ~/.bazaar/ignore. On Windows3096 Breezy also supports a global ignore file ~/.config/breezy/ignore. On
3095 the global ignore file can be found in the application data directory as3097 Windows the global ignore file can be found in the application data
3096 C:\\Documents and Settings\\<user>\\Application Data\\Bazaar\\2.0\\ignore.3098 directory as
3099 C:\\Documents and Settings\\<user>\\Application Data\\Breezy\\3.0\\ignore.
3097 Global ignores are not touched by this command. The global ignore file3100 Global ignores are not touched by this command. The global ignore file
3098 can be edited directly using an editor.3101 can be edited directly using an editor.
30993102
@@ -3732,7 +3735,7 @@
3732 unreferenced ancestors3735 unreferenced ancestors
3733 Texts that are ancestors of other texts, but3736 Texts that are ancestors of other texts, but
3734 are not properly referenced by the revision ancestry. This is a3737 are not properly referenced by the revision ancestry. This is a
3735 subtle problem that Bazaar can work around.3738 subtle problem that Breezy can work around.
37363739
3737 unique file texts3740 unique file texts
3738 This is the total number of unique file contents3741 This is the total number of unique file contents
@@ -3744,7 +3747,7 @@
3744 entries are modified, but the file contents are not. It does not3747 entries are modified, but the file contents are not. It does not
3745 indicate a problem.3748 indicate a problem.
37463749
3747 If no restrictions are specified, all Bazaar data that is found at the given3750 If no restrictions are specified, all data that is found at the given
3748 location will be checked.3751 location will be checked.
37493752
3750 :Examples:3753 :Examples:
@@ -3786,10 +3789,10 @@
3786 __doc__ = """Upgrade a repository, branch or working tree to a newer format.3789 __doc__ = """Upgrade a repository, branch or working tree to a newer format.
37873790
3788 When the default format has changed after a major new release of3791 When the default format has changed after a major new release of
3789 Bazaar, you may be informed during certain operations that you3792 Bazaar/Breezy, you may be informed during certain operations that you
3790 should upgrade. Upgrading to a newer format may improve performance3793 should upgrade. Upgrading to a newer format may improve performance
3791 or make new features available. It may however limit interoperability3794 or make new features available. It may however limit interoperability
3792 with older repositories or with older versions of Bazaar.3795 with older repositories or with older versions of Bazaar or Breezy.
37933796
3794 If you wish to upgrade to a particular format rather than the3797 If you wish to upgrade to a particular format rather than the
3795 current default, that can be specified using the --format option.3798 current default, that can be specified using the --format option.
@@ -3811,7 +3814,7 @@
3811 If the conversion of a branch fails, remaining branches are still3814 If the conversion of a branch fails, remaining branches are still
3812 tried.3815 tried.
38133816
3814 For more information on upgrades, see the Bazaar Upgrade Guide,3817 For more information on upgrades, see the Breezy Upgrade Guide,
3815 https://www.breezy-vcs.org/doc/en/upgrade-guide/.3818 https://www.breezy-vcs.org/doc/en/upgrade-guide/.
3816 """3819 """
38173820
@@ -4312,7 +4315,7 @@
4312 through OTHER, excluding BASE but including OTHER, will be merged. If this4315 through OTHER, excluding BASE but including OTHER, will be merged. If this
4313 causes some revisions to be skipped, i.e. if the destination branch does4316 causes some revisions to be skipped, i.e. if the destination branch does
4314 not already contain revision BASE, such a merge is commonly referred to as4317 not already contain revision BASE, such a merge is commonly referred to as
4315 a "cherrypick". Unlike a normal merge, Bazaar does not currently track4318 a "cherrypick". Unlike a normal merge, Breezy does not currently track
4316 cherrypicks. The changes look like a normal commit, and the history of the4319 cherrypicks. The changes look like a normal commit, and the history of the
4317 changes from the other branch is not stored in the commit.4320 changes from the other branch is not stored in the commit.
43184321
@@ -5133,8 +5136,8 @@
51335136
5134 --verbose shows the path where each plugin is located.5137 --verbose shows the path where each plugin is located.
51355138
5136 A plugin is an external component for Bazaar that extends the5139 A plugin is an external component for Breezy that extends the
5137 revision control system, by adding or replacing code in Bazaar.5140 revision control system, by adding or replacing code in Breezy.
5138 Plugins can do a variety of things, including overriding commands,5141 Plugins can do a variety of things, including overriding commands,
5139 adding new commands, providing additional network transports and5142 adding new commands, providing additional network transports and
5140 customizing log output.5143 customizing log output.
@@ -5420,10 +5423,10 @@
5420 else:5423 else:
5421 self.add_cleanup(b.lock_write().unlock)5424 self.add_cleanup(b.lock_write().unlock)
5422 return self._run(b, tree, dry_run, verbose, revision, force,5425 return self._run(b, tree, dry_run, verbose, revision, force,
5423 local, keep_tags)5426 local, keep_tags, location)
54245427
5425 def _run(self, b, tree, dry_run, verbose, revision, force, local,5428 def _run(self, b, tree, dry_run, verbose, revision, force, local,
5426 keep_tags):5429 keep_tags, location):
5427 from .log import log_formatter, show_log5430 from .log import log_formatter, show_log
5428 from .uncommit import uncommit5431 from .uncommit import uncommit
54295432
@@ -5477,10 +5480,16 @@
5477 last_rev_id, rev_id)5480 last_rev_id, rev_id)
5478 uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,5481 uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
5479 revno=revno, local=local, keep_tags=keep_tags)5482 revno=revno, local=local, keep_tags=keep_tags)
5480 self.outf.write(5483 if location != '.':
5481 gettext('You can restore the old tip by running:\n'5484 self.outf.write(
5482 ' brz pull . -r revid:%s\n')5485 gettext('You can restore the old tip by running:\n'
5483 % last_rev_id.decode('utf-8'))5486 ' brz pull -d %s %s -r revid:%s\n')
5487 % (location, location, last_rev_id.decode('utf-8')))
5488 else:
5489 self.outf.write(
5490 gettext('You can restore the old tip by running:\n'
5491 ' brz pull . -r revid:%s\n')
5492 % last_rev_id.decode('utf-8'))
54845493
54855494
5486class cmd_break_lock(Command):5495class cmd_break_lock(Command):
@@ -5498,7 +5507,7 @@
5498 :Examples:5507 :Examples:
5499 brz break-lock5508 brz break-lock
5500 brz break-lock brz+ssh://example.com/brz/foo5509 brz break-lock brz+ssh://example.com/brz/foo
5501 brz break-lock --conf ~/.bazaar5510 brz break-lock --conf ~/.config/breezy
5502 """5511 """
55035512
5504 takes_args = ['location?']5513 takes_args = ['location?']
@@ -5789,7 +5798,7 @@
5789 branch containing submit_branch in its ancestory without needing access to5798 branch containing submit_branch in its ancestory without needing access to
5790 the source branch.5799 the source branch.
57915800
5792 If --no-bundle is specified, then Bazaar doesn't send the contents of the5801 If --no-bundle is specified, then Breezy doesn't send the contents of the
5793 revisions, but only a structured request to merge from the5802 revisions, but only a structured request to merge from the
5794 public_location. In that case the public_branch is needed and it must be5803 public_location. In that case the public_branch is needed and it must be
5795 up-to-date and accessible to the recipient. The public_branch is always5804 up-to-date and accessible to the recipient. The public_branch is always
57965805
=== modified file 'breezy/git/cache.py'
--- breezy/git/cache.py 2018-11-12 01:41:38 +0000
+++ breezy/git/cache.py 2019-03-06 06:08:28 +0000
@@ -613,11 +613,9 @@
613613
614 def open(self, transport):614 def open(self, transport):
615 try:615 try:
616 basepath = transport.local_abspath(".").encode(osutils._fs_enc)616 basepath = transport.local_abspath(".")
617 except bzr_errors.NotLocalUrl:617 except bzr_errors.NotLocalUrl:
618 basepath = get_cache_dir()618 basepath = get_cache_dir()
619 if not isinstance(basepath, str):
620 raise TypeError(basepath)
621 try:619 try:
622 return TdbBzrGitCache(os.path.join(basepath, "idmap.tdb"))620 return TdbBzrGitCache(os.path.join(basepath, "idmap.tdb"))
623 except ImportError:621 except ImportError:
624622
=== modified file 'breezy/git/git-remote-bzr'
--- breezy/git/git-remote-bzr 2018-03-26 22:28:24 +0000
+++ breezy/git/git-remote-bzr 2019-03-06 06:08:28 +0000
@@ -32,10 +32,12 @@
32import breezy32import breezy
33breezy.initialize()33breezy.initialize()
3434
35from breezy.sixish import PY3
36
35from breezy.plugin import load_plugins37from breezy.plugin import load_plugins
36load_plugins()38load_plugins()
3739
38from breezy.plugins.git.git_remote_helper import (40from breezy.git.git_remote_helper import (
39 RemoteHelper,41 RemoteHelper,
40 open_local_dir,42 open_local_dir,
41 open_remote_dir,43 open_remote_dir,
@@ -46,4 +48,7 @@
46(shortname, url) = args48(shortname, url) = args
4749
48helper = RemoteHelper(open_local_dir(), shortname, open_remote_dir(url))50helper = RemoteHelper(open_local_dir(), shortname, open_remote_dir(url))
49helper.process(sys.stdin, sys.stdout)51if PY3:
52 helper.process(sys.stdin.buffer, sys.stdout.buffer)
53else:
54 helper.process(sys.stdin, sys.stdout)
5055
=== modified file 'breezy/git/git_remote_helper.py'
--- breezy/git/git_remote_helper.py 2018-11-11 14:23:06 +0000
+++ breezy/git/git_remote_helper.py 2019-03-06 06:08:28 +0000
@@ -186,7 +186,7 @@
186 self.batchcmd = None186 self.batchcmd = None
187 else:187 else:
188 try:188 try:
189 self.commands[argv[0]](self, outf, argv)189 self.commands[argv[0].decode()](self, outf, argv)
190 except KeyError:190 except KeyError:
191 raise Exception("Unknown remote command %r" % argv)191 raise Exception("Unknown remote command %r" % argv)
192 outf.flush()192 outf.flush()
193193
=== modified file 'breezy/git/memorytree.py'
--- breezy/git/memorytree.py 2018-11-18 00:25:19 +0000
+++ breezy/git/memorytree.py 2019-03-06 06:08:28 +0000
@@ -258,3 +258,7 @@
258 def kind(self, p):258 def kind(self, p):
259 stat_value = self._file_transport.stat(p)259 stat_value = self._file_transport.stat(p)
260 return osutils.file_kind_from_stat_mode(stat_value.st_mode)260 return osutils.file_kind_from_stat_mode(stat_value.st_mode)
261
262 def get_symlink_target(self, path):
263 with self.lock_read():
264 return self._file_transport.readlink(path)
261265
=== modified file 'breezy/git/object_store.py'
--- breezy/git/object_store.py 2019-01-01 21:23:40 +0000
+++ breezy/git/object_store.py 2019-03-06 06:08:28 +0000
@@ -359,7 +359,7 @@
359 continue359 continue
360360
361 if tree.kind(path) != 'directory':361 if tree.kind(path) != 'directory':
362 raise AssertionError362 continue
363363
364 obj = Tree()364 obj = Tree()
365 for value in tree.iter_child_entries(path):365 for value in tree.iter_child_entries(path):
@@ -589,7 +589,7 @@
589 for (file_id, revision, expected_sha), chunks in stream:589 for (file_id, revision, expected_sha), chunks in stream:
590 blob = Blob()590 blob = Blob()
591 blob.chunked = chunks591 blob.chunked = chunks
592 if blob.id != expected_sha and blob.data == "":592 if blob.id != expected_sha and blob.data == b"":
593 # Perhaps it's a symlink ?593 # Perhaps it's a symlink ?
594 tree = self.tree_cache.revision_tree(revision)594 tree = self.tree_cache.revision_tree(revision)
595 path = tree.id2path(file_id)595 path = tree.id2path(file_id)
596596
=== modified file 'breezy/git/tests/test_blackbox.py'
--- breezy/git/tests/test_blackbox.py 2019-02-14 04:20:37 +0000
+++ breezy/git/tests/test_blackbox.py 2019-03-06 06:08:28 +0000
@@ -78,6 +78,15 @@
78 self.assertEqual(output, '')78 self.assertEqual(output, '')
79 self.assertFileEqual("foo\n", ".gitignore")79 self.assertFileEqual("foo\n", ".gitignore")
8080
81 def test_cat_revision(self):
82 self.simple_commit()
83 output, error = self.run_bzr(['cat-revision', '-r-1'], retcode=3)
84 self.assertContainsRe(
85 error,
86 'brz: ERROR: Repository .* does not support access to raw '
87 'revision texts')
88 self.assertEqual(output, '')
89
81 def test_branch(self):90 def test_branch(self):
82 os.mkdir("gitbranch")91 os.mkdir("gitbranch")
83 GitRepo.init(os.path.join(self.test_dir, "gitbranch"))92 GitRepo.init(os.path.join(self.test_dir, "gitbranch"))
8493
=== modified file 'breezy/git/tests/test_branch.py'
--- breezy/git/tests/test_branch.py 2019-01-19 17:13:53 +0000
+++ breezy/git/tests/test_branch.py 2019-03-06 06:08:28 +0000
@@ -112,6 +112,7 @@
112 reva = self.simple_commit_a()112 reva = self.simple_commit_a()
113 self.build_tree(['b'])113 self.build_tree(['b'])
114 r = GitRepo(".")114 r = GitRepo(".")
115 self.addCleanup(r.close)
115 r.stage("b")116 r.stage("b")
116 revb = r.do_commit(b"b", committer=b"Somebody <foo@example.com>")117 revb = r.do_commit(b"b", committer=b"Somebody <foo@example.com>")
117118
@@ -129,6 +130,7 @@
129 o.tag_timezone = 0130 o.tag_timezone = 0
130 o.tag_time = 42131 o.tag_time = 42
131 r = GitRepo(".")132 r = GitRepo(".")
133 self.addCleanup(r.close)
132 r.object_store.add_object(o)134 r.object_store.add_object(o)
133 r[b'refs/tags/foo'] = o.id135 r[b'refs/tags/foo'] = o.id
134 thebranch = Branch.open('.')136 thebranch = Branch.open('.')
@@ -138,6 +140,7 @@
138 def test_tag(self):140 def test_tag(self):
139 reva = self.simple_commit_a()141 reva = self.simple_commit_a()
140 r = GitRepo(".")142 r = GitRepo(".")
143 self.addCleanup(r.close)
141 r.refs[b"refs/tags/foo"] = reva144 r.refs[b"refs/tags/foo"] = reva
142 thebranch = Branch.open('.')145 thebranch = Branch.open('.')
143 self.assertEqual({"foo": default_mapping.revision_id_foreign_to_bzr(reva)},146 self.assertEqual({"foo": default_mapping.revision_id_foreign_to_bzr(reva)},
@@ -221,6 +224,7 @@
221 def test_sprouted_tags(self):224 def test_sprouted_tags(self):
222 path, gitsha = self.make_onerev_branch()225 path, gitsha = self.make_onerev_branch()
223 r = GitRepo(path)226 r = GitRepo(path)
227 self.addCleanup(r.close)
224 r.refs[b"refs/tags/lala"] = r.head()228 r.refs[b"refs/tags/lala"] = r.head()
225 oldrepo = Repository.open(path)229 oldrepo = Repository.open(path)
226 revid = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha)230 revid = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha)
@@ -231,6 +235,7 @@
231 def test_sprouted_ghost_tags(self):235 def test_sprouted_ghost_tags(self):
232 path, gitsha = self.make_onerev_branch()236 path, gitsha = self.make_onerev_branch()
233 r = GitRepo(path)237 r = GitRepo(path)
238 self.addCleanup(r.close)
234 r.refs[b"refs/tags/lala"] = b"aa" * 20239 r.refs[b"refs/tags/lala"] = b"aa" * 20
235 oldrepo = Repository.open(path)240 oldrepo = Repository.open(path)
236 revid = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha)241 revid = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha)
@@ -238,7 +243,7 @@
238 self.clone_git_branch, path, "f")243 self.clone_git_branch, path, "f")
239 self.assertEqual({}, newbranch.tags.get_tag_dict())244 self.assertEqual({}, newbranch.tags.get_tag_dict())
240 # Dulwich raises a UserWarning for tags with invalid target245 # Dulwich raises a UserWarning for tags with invalid target
241 self.assertEqual(1, len(warnings))246 self.assertIn(('ref refs/tags/lala points at non-present sha ' + ("aa" * 20), ), [w.args for w in warnings])
242247
243 def test_interbranch_pull(self):248 def test_interbranch_pull(self):
244 path, (gitsha1, gitsha2) = self.make_tworev_branch()249 path, (gitsha1, gitsha2) = self.make_tworev_branch()
@@ -272,6 +277,7 @@
272 def test_interbranch_pull_with_tags(self):277 def test_interbranch_pull_with_tags(self):
273 path, (gitsha1, gitsha2) = self.make_tworev_branch()278 path, (gitsha1, gitsha2) = self.make_tworev_branch()
274 gitrepo = GitRepo(path)279 gitrepo = GitRepo(path)
280 self.addCleanup(gitrepo.close)
275 gitrepo.refs[b"refs/tags/sometag"] = gitsha2281 gitrepo.refs[b"refs/tags/sometag"] = gitsha2
276 oldrepo = Repository.open(path)282 oldrepo = Repository.open(path)
277 revid1 = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha1)283 revid1 = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha1)
278284
=== modified file 'breezy/git/tests/test_git_remote_helper.py'
--- breezy/git/tests/test_git_remote_helper.py 2018-11-21 03:39:28 +0000
+++ breezy/git/tests/test_git_remote_helper.py 2019-03-06 06:08:28 +0000
@@ -23,12 +23,15 @@
2323
24from io import BytesIO24from io import BytesIO
25import os25import os
26import subprocess
27import sys
2628
27from dulwich.repo import Repo29from dulwich.repo import Repo
2830
29from ...tests import (31from ...tests import (
30 TestCaseWithTransport,32 TestCaseWithTransport,
31 )33 )
34from ...tests.features import PathFeature
3235
33from ..object_store import get_object_store36from ..object_store import get_object_store
34from ..git_remote_helper import (37from ..git_remote_helper import (
@@ -46,6 +49,11 @@
46 return object_store._lookup_revision_sha1(bzr_revid)49 return object_store._lookup_revision_sha1(bzr_revid)
4750
4851
52git_remote_bzr_path = os.path.abspath(
53 os.path.join(os.path.dirname(__file__), '..', 'git-remote-bzr'))
54git_remote_bzr_feature = PathFeature(git_remote_bzr_path)
55
56
49class OpenLocalDirTests(TestCaseWithTransport):57class OpenLocalDirTests(TestCaseWithTransport):
5058
51 def test_from_env_dir(self):59 def test_from_env_dir(self):
@@ -86,8 +94,29 @@
86 self.assertEqual(out, b"\n")94 self.assertEqual(out, b"\n")
87 r = Repo('local')95 r = Repo('local')
88 self.assertTrue(git_sha1 in r.object_store)96 self.assertTrue(git_sha1 in r.object_store)
89 self.assertEqual({97 self.assertEqual({}, r.get_refs())
90 }, r.get_refs())98
99
100class ExecuteRemoteHelperTests(TestCaseWithTransport):
101
102 def test_run(self):
103 self.requireFeature(git_remote_bzr_feature)
104 local_dir = self.make_branch_and_tree('local', format='git').controldir
105 local_path = local_dir.control_transport.local_abspath('.')
106 remote_tree = self.make_branch_and_tree('remote')
107 remote_dir = remote_tree.controldir
108 shortname = 'bzr'
109 env = dict(os.environ)
110 env['GIT_DIR'] = local_path
111 env['PYTHONPATH'] = ':'.join(sys.path)
112 p = subprocess.Popen(
113 [sys.executable, git_remote_bzr_path, local_path, remote_dir.user_url],
114 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
115 stderr=subprocess.PIPE, env=env)
116 (out, err) = p.communicate(b'capabilities\n')
117 lines = out.splitlines()
118 self.assertIn(b'push', lines, "no 'push' in %r, error: %r" % (lines, err))
119 self.assertEqual(b'', err)
91120
92121
93class RemoteHelperTests(TestCaseWithTransport):122class RemoteHelperTests(TestCaseWithTransport):
94123
=== modified file 'breezy/git/tests/test_object_store.py'
--- breezy/git/tests/test_object_store.py 2018-11-11 04:08:32 +0000
+++ breezy/git/tests/test_object_store.py 2019-03-06 06:08:28 +0000
@@ -18,6 +18,9 @@
1818
19from __future__ import absolute_import19from __future__ import absolute_import
2020
21import os
22import shutil
23
21from dulwich.objects import (24from dulwich.objects import (
22 Blob,25 Blob,
23 Tree,26 Tree,
@@ -41,6 +44,7 @@
41 TestCase,44 TestCase,
42 TestCaseWithTransport,45 TestCaseWithTransport,
43 )46 )
47from ...tests.features import SymlinkFeature
4448
45from ..cache import (49from ..cache import (
46 DictGitShaMap,50 DictGitShaMap,
@@ -144,11 +148,11 @@
144 def setUp(self):148 def setUp(self):
145 super(BazaarObjectStoreTests, self).setUp()149 super(BazaarObjectStoreTests, self).setUp()
146 self.branch = self.make_branch(".")150 self.branch = self.make_branch(".")
147 self.branch.lock_write()
148 self.addCleanup(self.branch.unlock)
149 self.store = BazaarObjectStore(self.branch.repository)151 self.store = BazaarObjectStore(self.branch.repository)
150152
151 def test_get_blob(self):153 def test_get_blob(self):
154 self.branch.lock_write()
155 self.addCleanup(self.branch.unlock)
152 b = Blob()156 b = Blob()
153 b.data = b'a\nb\nc\nd\ne\n'157 b.data = b'a\nb\nc\nd\ne\n'
154 self.store.lock_read()158 self.store.lock_read()
@@ -167,7 +171,31 @@
167 self.store.lock_read()171 self.store.lock_read()
168 self.assertEqual(b, self.store[b.id])172 self.assertEqual(b, self.store[b.id])
169173
174 def test_directory_converted_to_symlink(self):
175 self.requireFeature(SymlinkFeature)
176 b = Blob()
177 b.data = b'trgt'
178 self.store.lock_read()
179 self.addCleanup(self.store.unlock)
180 self.assertRaises(KeyError, self.store.__getitem__, b.id)
181 tree = self.branch.controldir.create_workingtree()
182 self.build_tree_contents([
183 ('foo/', ),
184 ('foo/bar', b'a\nb\nc\nd\ne\n')])
185 tree.add(['foo', 'foo/bar'])
186 revid1 = tree.commit('commit 1')
187 shutil.rmtree('foo')
188 os.symlink('trgt', 'foo')
189 revid2 = tree.commit('commit 2')
190 # read locks cache
191 self.assertRaises(KeyError, self.store.__getitem__, b.id)
192 self.store.unlock()
193 self.store.lock_read()
194 self.assertEqual(b, self.store[b.id])
195
170 def test_get_raw(self):196 def test_get_raw(self):
197 self.branch.lock_write()
198 self.addCleanup(self.branch.unlock)
171 b = Blob()199 b = Blob()
172 b.data = b'a\nb\nc\nd\ne\n'200 b.data = b'a\nb\nc\nd\ne\n'
173 self.store.lock_read()201 self.store.lock_read()
@@ -187,6 +215,8 @@
187 self.assertEqual(b.as_raw_string(), self.store.get_raw(b.id)[1])215 self.assertEqual(b.as_raw_string(), self.store.get_raw(b.id)[1])
188216
189 def test_contains(self):217 def test_contains(self):
218 self.branch.lock_write()
219 self.addCleanup(self.branch.unlock)
190 b = Blob()220 b = Blob()
191 b.data = b'a\nb\nc\nd\ne\n'221 b.data = b'a\nb\nc\nd\ne\n'
192 self.store.lock_read()222 self.store.lock_read()
193223
=== modified file 'breezy/globbing.py'
--- breezy/globbing.py 2018-11-18 19:48:57 +0000
+++ breezy/globbing.py 2019-03-06 06:08:28 +0000
@@ -248,7 +248,9 @@
248 # the combined pattern we sent to regex. Instead we indicate to248 # the combined pattern we sent to regex. Instead we indicate to
249 # the user that an ignore file needs fixing.249 # the user that an ignore file needs fixing.
250 mutter('Invalid pattern found in regex: %s.', e.msg)250 mutter('Invalid pattern found in regex: %s.', e.msg)
251 e.msg = "File ~/.bazaar/ignore or .bzrignore contains error(s)."251 e.msg = (
252 "File ~/.config/breezy/ignore or "
253 ".bzrignore contains error(s).")
252 bad_patterns = ''254 bad_patterns = ''
253 for _, patterns in self._regex_patterns:255 for _, patterns in self._regex_patterns:
254 for p in patterns:256 for p in patterns:
255257
=== modified file 'breezy/ignores.py'
--- breezy/ignores.py 2018-11-12 01:41:38 +0000
+++ breezy/ignores.py 2019-03-06 06:08:28 +0000
@@ -33,7 +33,7 @@
33 )33 )
34""")34""")
3535
36# ~/.bazaar/ignore will be filled out using36# ~/.config/breezy/ignore will be filled out using
37# this ignore list, if it does not exist37# this ignore list, if it does not exist
38# please keep these sorted (in C locale order) to aid merging38# please keep these sorted (in C locale order) to aid merging
39USER_DEFAULTS = [39USER_DEFAULTS = [
4040
=== modified file 'breezy/memorytree.py'
--- breezy/memorytree.py 2018-11-18 00:25:19 +0000
+++ breezy/memorytree.py 2019-03-06 06:08:28 +0000
@@ -22,6 +22,7 @@
22from __future__ import absolute_import22from __future__ import absolute_import
2323
24import os24import os
25import stat
2526
26from . import (27from . import (
27 errors,28 errors,
@@ -62,7 +63,15 @@
62 with self.lock_tree_write():63 with self.lock_tree_write():
63 for f, file_id, kind in zip(files, ids, kinds):64 for f, file_id, kind in zip(files, ids, kinds):
64 if kind is None:65 if kind is None:
65 kind = 'file'66 st_mode = self._file_transport.stat(f).st_mode
67 if stat.S_ISREG(st_mode):
68 kind = 'file'
69 elif stat.S_ISLNK(st_mode):
70 kind = 'symlink'
71 elif stat.S_ISDIR(st_mode):
72 kind = 'directory'
73 else:
74 raise AssertionError('Unknown file kind')
66 if file_id is None:75 if file_id is None:
67 self._inventory.add_path(f, kind=kind)76 self._inventory.add_path(f, kind=kind)
68 else:77 else:
@@ -127,7 +136,7 @@
127 # memory tree does not support nested trees yet.136 # memory tree does not support nested trees yet.
128 return kind, None, None, None137 return kind, None, None, None
129 elif kind == 'symlink':138 elif kind == 'symlink':
130 raise NotImplementedError('symlink support')139 return kind, None, None, self._inventory[id].symlink_target
131 else:140 else:
132 raise NotImplementedError('unknown kind')141 raise NotImplementedError('unknown kind')
133142
@@ -148,8 +157,7 @@
148 return self._inventory.get_entry_by_path(path).executable157 return self._inventory.get_entry_by_path(path).executable
149158
150 def kind(self, path):159 def kind(self, path):
151 file_id = self.path2id(path)160 return self._inventory.get_entry_by_path(path).kind
152 return self._inventory[file_id].kind
153161
154 def mkdir(self, path, file_id=None):162 def mkdir(self, path, file_id=None):
155 """See MutableTree.mkdir()."""163 """See MutableTree.mkdir()."""
@@ -227,6 +235,8 @@
227 continue235 continue
228 if entry.kind == 'directory':236 if entry.kind == 'directory':
229 self._file_transport.mkdir(path)237 self._file_transport.mkdir(path)
238 elif entry.kind == 'symlink':
239 self._file_transport.symlink(entry.symlink_target, path)
230 elif entry.kind == 'file':240 elif entry.kind == 'file':
231 self._file_transport.put_file(241 self._file_transport.put_file(
232 path, self._basis_tree.get_file(path))242 path, self._basis_tree.get_file(path))
@@ -302,6 +312,10 @@
302 else:312 else:
303 raise313 raise
304314
315 def get_symlink_target(self, path):
316 with self.lock_read():
317 return self._file_transport.readlink(path)
318
305 def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):319 def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
306 """See MutableTree.set_parent_trees()."""320 """See MutableTree.set_parent_trees()."""
307 if len(parents_list) == 0:321 if len(parents_list) == 0:
308322
=== modified file 'breezy/plugins/propose/launchpad.py'
--- breezy/plugins/propose/launchpad.py 2019-02-10 18:37:58 +0000
+++ breezy/plugins/propose/launchpad.py 2019-03-06 06:08:28 +0000
@@ -140,6 +140,7 @@
140140
141 def set_description(self, description):141 def set_description(self, description):
142 self._mp.description = description142 self._mp.description = description
143 self._mp.lp_save()
143144
144 def close(self):145 def close(self):
145 self._mp.setStatus(status='Rejected')146 self._mp.setStatus(status='Rejected')
146147
=== modified file 'breezy/python-compat.h'
--- breezy/python-compat.h 2018-08-21 00:53:34 +0000
+++ breezy/python-compat.h 2019-03-06 06:08:28 +0000
@@ -25,6 +25,10 @@
25#ifndef _BZR_PYTHON_COMPAT_H25#ifndef _BZR_PYTHON_COMPAT_H
26#define _BZR_PYTHON_COMPAT_H26#define _BZR_PYTHON_COMPAT_H
2727
28#ifdef _MSC_VER
29#define inline __inline
30#endif
31
28#if PY_MAJOR_VERSION >= 332#if PY_MAJOR_VERSION >= 3
2933
30#define PyInt_FromSsize_t PyLong_FromSsize_t34#define PyInt_FromSsize_t PyLong_FromSsize_t
3135
=== modified file 'breezy/tests/blackbox/test_bisect.py'
--- breezy/tests/blackbox/test_bisect.py 2018-11-11 04:08:32 +0000
+++ breezy/tests/blackbox/test_bisect.py 2019-03-06 06:08:28 +0000
@@ -28,6 +28,7 @@
28from .. import (28from .. import (
29 KnownFailure,29 KnownFailure,
30 TestCaseWithTransport,30 TestCaseWithTransport,
31 TestSkipped,
31 )32 )
32from ...bzr.bzrdir import BzrDir33from ...bzr.bzrdir import BzrDir
3334
3435
=== modified file 'breezy/tests/blackbox/test_push.py'
--- breezy/tests/blackbox/test_push.py 2018-11-16 12:08:41 +0000
+++ breezy/tests/blackbox/test_push.py 2019-03-06 06:08:28 +0000
@@ -22,6 +22,7 @@
22from breezy import (22from breezy import (
23 branch,23 branch,
24 controldir,24 controldir,
25 directory_service,
25 errors,26 errors,
26 osutils,27 osutils,
27 tests,28 tests,
@@ -498,6 +499,25 @@
498 self.assertPublished(branch_tree.last_revision(),499 self.assertPublished(branch_tree.last_revision(),
499 trunk_tree.branch.base)500 trunk_tree.branch.base)
500501
502 def test_push_new_branch_stacked_on(self):
503 """Pushing a new branch with --stacked-on can use directory URLs."""
504 trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
505 class FooDirectory(object):
506 def look_up(self, name, url, purpose=None):
507 if url == 'foo:':
508 return trunk_tree.branch.base
509 return url
510 directory_service.directories.register('foo:', FooDirectory, 'Foo directory')
511 self.addCleanup(directory_service.directories.remove, 'foo:')
512 # we publish branch_tree with a reference to the mainline.
513 out, err = self.run_bzr(['push', '--stacked-on', 'foo:',
514 self.get_url('published')], working_dir='branch')
515 self.assertEqual('', out)
516 self.assertEqual('Created new stacked branch referring to %s.\n' %
517 trunk_tree.branch.base, err)
518 self.assertPublished(branch_tree.last_revision(),
519 trunk_tree.branch.base)
520
501 def test_push_new_branch_stacked_uses_parent_when_no_public_url(self):521 def test_push_new_branch_stacked_uses_parent_when_no_public_url(self):
502 """When the parent has no public url the parent is used as-is."""522 """When the parent has no public url the parent is used as-is."""
503 trunk_tree, branch_tree = self.create_trunk_and_feature_branch()523 trunk_tree, branch_tree = self.create_trunk_and_feature_branch()
504524
=== modified file 'breezy/tests/blackbox/test_remove.py'
--- breezy/tests/blackbox/test_remove.py 2018-11-17 18:49:41 +0000
+++ breezy/tests/blackbox/test_remove.py 2019-03-06 06:08:28 +0000
@@ -23,6 +23,7 @@
23 features,23 features,
24 TestCaseWithTransport,24 TestCaseWithTransport,
25 TestSkipped,25 TestSkipped,
26 TestNotApplicable,
26 )27 )
27from breezy.workingtree import WorkingTree28from breezy.workingtree import WorkingTree
28from breezy import osutils29from breezy import osutils
@@ -278,7 +279,7 @@
278 def test_remove_backslash(self):279 def test_remove_backslash(self):
279 # pad.lv/176263280 # pad.lv/176263
280 if os.path.sep == '\\':281 if os.path.sep == '\\':
281 raise tests.TestNotApplicable(282 raise TestNotApplicable(
282 'unable to add filenames with backslashes where '283 'unable to add filenames with backslashes where '
283 ' it is the path separator')284 ' it is the path separator')
284 tree = self.make_branch_and_tree('.')285 tree = self.make_branch_and_tree('.')
285286
=== modified file 'breezy/tests/blackbox/test_uncommit.py'
--- breezy/tests/blackbox/test_uncommit.py 2018-11-18 19:48:57 +0000
+++ breezy/tests/blackbox/test_uncommit.py 2019-03-06 06:08:28 +0000
@@ -246,6 +246,20 @@
246 brz pull . -r revid:a2246 brz pull . -r revid:a2
247""")247""")
248248
249 def test_uncommit_shows_pull_with_location(self):
250 wt = self.create_simple_tree()
251
252 script = ScriptRunner()
253 script.run_script(self, """
254$ brz uncommit --force tree
255 2 ...
256 second commit
257...
258The above revision(s) will be removed.
259You can restore the old tip by running:
260 brz pull -d tree tree -r revid:a2
261""")
262
249 def test_uncommit_octopus_merge(self):263 def test_uncommit_octopus_merge(self):
250 # Check that uncommit keeps the pending merges in the same order264 # Check that uncommit keeps the pending merges in the same order
251 # though it will also filter out ones in the ancestry265 # though it will also filter out ones in the ancestry
252266
=== modified file 'breezy/tests/features.py'
--- breezy/tests/features.py 2019-01-19 01:44:20 +0000
+++ breezy/tests/features.py 2019-03-06 06:08:28 +0000
@@ -568,3 +568,17 @@
568568
569569
570BackslashFilenameFeature = _BackslashFilenameFeature()570BackslashFilenameFeature = _BackslashFilenameFeature()
571
572
573class PathFeature(Feature):
574 """Feature testing whether a particular path exists."""
575
576 def __init__(self, path):
577 super(PathFeature, self).__init__()
578 self.path = path
579
580 def _probe(self):
581 return os.path.exists(self.path)
582
583 def feature_name(self):
584 return "%s exists" % self.path
571585
=== modified file 'breezy/tests/test_memorytree.py'
--- breezy/tests/test_memorytree.py 2018-11-11 04:08:32 +0000
+++ breezy/tests/test_memorytree.py 2019-03-06 06:08:28 +0000
@@ -46,21 +46,17 @@
46 rev_id = tree.commit('first post')46 rev_id = tree.commit('first post')
47 tree.unlock()47 tree.unlock()
48 tree = MemoryTree.create_on_branch(branch)48 tree = MemoryTree.create_on_branch(branch)
49 tree.lock_read()49 with tree.lock_read():
50 self.assertEqual([rev_id], tree.get_parent_ids())50 self.assertEqual([rev_id], tree.get_parent_ids())
51 with tree.get_file('foo') as f:51 with tree.get_file('foo') as f:
52 self.assertEqual(b'contents of foo\n', f.read())52 self.assertEqual(b'contents of foo\n', f.read())
53 tree.unlock()
5453
55 def test_get_root_id(self):54 def test_get_root_id(self):
56 branch = self.make_branch('branch')55 branch = self.make_branch('branch')
57 tree = MemoryTree.create_on_branch(branch)56 tree = MemoryTree.create_on_branch(branch)
58 tree.lock_write()57 with tree.lock_write():
59 try:
60 tree.add([''])58 tree.add([''])
61 self.assertIsNot(None, tree.get_root_id())59 self.assertIsNot(None, tree.get_root_id())
62 finally:
63 tree.unlock()
6460
65 def test_lock_tree_write(self):61 def test_lock_tree_write(self):
66 """Check we can lock_tree_write and unlock MemoryTrees."""62 """Check we can lock_tree_write and unlock MemoryTrees."""
@@ -73,9 +69,8 @@
73 """Check that we error when trying to upgrade a read lock to write."""69 """Check that we error when trying to upgrade a read lock to write."""
74 branch = self.make_branch('branch')70 branch = self.make_branch('branch')
75 tree = MemoryTree.create_on_branch(branch)71 tree = MemoryTree.create_on_branch(branch)
76 tree.lock_read()72 with tree.lock_read():
77 self.assertRaises(errors.ReadOnlyError, tree.lock_tree_write)73 self.assertRaises(errors.ReadOnlyError, tree.lock_tree_write)
78 tree.unlock()
7974
80 def test_lock_write(self):75 def test_lock_write(self):
81 """Check we can lock_write and unlock MemoryTrees."""76 """Check we can lock_write and unlock MemoryTrees."""
@@ -88,58 +83,63 @@
88 """Check that we error when trying to upgrade a read lock to write."""83 """Check that we error when trying to upgrade a read lock to write."""
89 branch = self.make_branch('branch')84 branch = self.make_branch('branch')
90 tree = MemoryTree.create_on_branch(branch)85 tree = MemoryTree.create_on_branch(branch)
91 tree.lock_read()86 with tree.lock_read():
92 self.assertRaises(errors.ReadOnlyError, tree.lock_write)87 self.assertRaises(errors.ReadOnlyError, tree.lock_write)
93 tree.unlock()
9488
95 def test_add_with_kind(self):89 def test_add_with_kind(self):
96 branch = self.make_branch('branch')90 branch = self.make_branch('branch')
97 tree = MemoryTree.create_on_branch(branch)91 tree = MemoryTree.create_on_branch(branch)
98 tree.lock_write()92 with tree.lock_write():
99 tree.add(['', 'afile', 'adir'], None,93 tree.add(['', 'afile', 'adir'], None,
100 ['directory', 'file', 'directory'])94 ['directory', 'file', 'directory'])
101 self.assertEqual('afile', tree.id2path(tree.path2id('afile')))95 self.assertEqual('afile', tree.id2path(tree.path2id('afile')))
102 self.assertEqual('adir', tree.id2path(tree.path2id('adir')))96 self.assertEqual('adir', tree.id2path(tree.path2id('adir')))
103 self.assertFalse(tree.has_filename('afile'))97 self.assertFalse(tree.has_filename('afile'))
104 self.assertFalse(tree.has_filename('adir'))98 self.assertFalse(tree.has_filename('adir'))
105 tree.unlock()
10699
107 def test_put_new_file(self):100 def test_put_new_file(self):
108 branch = self.make_branch('branch')101 branch = self.make_branch('branch')
109 tree = MemoryTree.create_on_branch(branch)102 tree = MemoryTree.create_on_branch(branch)
110 tree.lock_write()103 with tree.lock_write():
111 tree.add(['', 'foo'], ids=[b'root-id', b'foo-id'],104 tree.add(['', 'foo'], ids=[b'root-id', b'foo-id'],
112 kinds=['directory', 'file'])105 kinds=['directory', 'file'])
113 tree.put_file_bytes_non_atomic('foo', b'barshoom')106 tree.put_file_bytes_non_atomic('foo', b'barshoom')
114 self.assertEqual(b'barshoom', tree.get_file('foo').read())107 with tree.get_file('foo') as f:
115 tree.unlock()108 self.assertEqual(b'barshoom', f.read())
116109
117 def test_put_existing_file(self):110 def test_put_existing_file(self):
118 branch = self.make_branch('branch')111 branch = self.make_branch('branch')
119 tree = MemoryTree.create_on_branch(branch)112 tree = MemoryTree.create_on_branch(branch)
120 tree.lock_write()113 with tree.lock_write():
121 tree.add(['', 'foo'], ids=[b'root-id', b'foo-id'],114 tree.add(['', 'foo'], ids=[b'root-id', b'foo-id'],
122 kinds=['directory', 'file'])115 kinds=['directory', 'file'])
123 tree.put_file_bytes_non_atomic('foo', b'first-content')116 tree.put_file_bytes_non_atomic('foo', b'first-content')
124 tree.put_file_bytes_non_atomic('foo', b'barshoom')117 tree.put_file_bytes_non_atomic('foo', b'barshoom')
125 self.assertEqual(b'barshoom', tree.get_file('foo').read())118 self.assertEqual(b'barshoom', tree.get_file('foo').read())
126 tree.unlock()
127119
128 def test_add_in_subdir(self):120 def test_add_in_subdir(self):
129 branch = self.make_branch('branch')121 branch = self.make_branch('branch')
130 tree = MemoryTree.create_on_branch(branch)122 tree = MemoryTree.create_on_branch(branch)
131 tree.lock_write()123 with tree.lock_write():
132 self.addCleanup(tree.unlock)124 tree.add([''], [b'root-id'], ['directory'])
133 tree.add([''], [b'root-id'], ['directory'])125 # Unfortunately, the only way to 'mkdir' is to call 'tree.mkdir', but
134 # Unfortunately, the only way to 'mkdir' is to call 'tree.mkdir', but126 # that *always* adds the directory as well. So if you want to create a
135 # that *always* adds the directory as well. So if you want to create a127 # file in a subdirectory, you have to split out the 'mkdir()' calls
136 # file in a subdirectory, you have to split out the 'mkdir()' calls128 # from the add and put_file_bytes_non_atomic calls. :(
137 # from the add and put_file_bytes_non_atomic calls. :(129 tree.mkdir('adir', b'dir-id')
138 tree.mkdir('adir', b'dir-id')130 tree.add(['adir/afile'], [b'file-id'], ['file'])
139 tree.add(['adir/afile'], [b'file-id'], ['file'])131 self.assertEqual('adir/afile', tree.id2path(b'file-id'))
140 self.assertEqual('adir/afile', tree.id2path(b'file-id'))132 self.assertEqual('adir', tree.id2path(b'dir-id'))
141 self.assertEqual('adir', tree.id2path(b'dir-id'))133 tree.put_file_bytes_non_atomic('adir/afile', b'barshoom')
142 tree.put_file_bytes_non_atomic('adir/afile', b'barshoom')134
135 def test_add_symlink(self):
136 branch = self.make_branch('branch')
137 tree = MemoryTree.create_on_branch(branch)
138 with tree.lock_write():
139 tree._file_transport.symlink('bar', 'foo')
140 tree.add(['', 'foo'])
141 self.assertEqual('symlink', tree.kind('foo'))
142 self.assertEqual('bar', tree.get_symlink_target('foo'))
143143
144 def test_commit_trivial(self):144 def test_commit_trivial(self):
145 """Smoke test for commit on a MemoryTree.145 """Smoke test for commit on a MemoryTree.
@@ -149,40 +149,35 @@
149 """149 """
150 branch = self.make_branch('branch')150 branch = self.make_branch('branch')
151 tree = MemoryTree.create_on_branch(branch)151 tree = MemoryTree.create_on_branch(branch)
152 tree.lock_write()152 with tree.lock_write():
153 tree.add(['', 'foo'], ids=[b'root-id', b'foo-id'],153 tree.add(['', 'foo'], ids=[b'root-id', b'foo-id'],
154 kinds=['directory', 'file'])154 kinds=['directory', 'file'])
155 tree.put_file_bytes_non_atomic('foo', b'barshoom')155 tree.put_file_bytes_non_atomic('foo', b'barshoom')
156 revision_id = tree.commit('message baby')156 revision_id = tree.commit('message baby')
157 # the parents list for the tree should have changed.157 # the parents list for the tree should have changed.
158 self.assertEqual([revision_id], tree.get_parent_ids())158 self.assertEqual([revision_id], tree.get_parent_ids())
159 tree.unlock()
160 # and we should have a revision that is accessible outside the tree lock159 # and we should have a revision that is accessible outside the tree lock
161 revtree = tree.branch.repository.revision_tree(revision_id)160 revtree = tree.branch.repository.revision_tree(revision_id)
162 revtree.lock_read()161 with revtree.lock_read(), revtree.get_file('foo') as f:
163 self.addCleanup(revtree.unlock)
164 with revtree.get_file('foo') as f:
165 self.assertEqual(b'barshoom', f.read())162 self.assertEqual(b'barshoom', f.read())
166163
167 def test_unversion(self):164 def test_unversion(self):
168 """Some test for unversion of a memory tree."""165 """Some test for unversion of a memory tree."""
169 branch = self.make_branch('branch')166 branch = self.make_branch('branch')
170 tree = MemoryTree.create_on_branch(branch)167 tree = MemoryTree.create_on_branch(branch)
171 tree.lock_write()168 with tree.lock_write():
172 tree.add(['', 'foo'], ids=[b'root-id', b'foo-id'],169 tree.add(['', 'foo'], ids=[b'root-id', b'foo-id'],
173 kinds=['directory', 'file'])170 kinds=['directory', 'file'])
174 tree.unversion(['foo'])171 tree.unversion(['foo'])
175 self.assertFalse(tree.is_versioned('foo'))172 self.assertFalse(tree.is_versioned('foo'))
176 self.assertFalse(tree.has_id(b'foo-id'))173 self.assertFalse(tree.has_id(b'foo-id'))
177 tree.unlock()
178174
179 def test_last_revision(self):175 def test_last_revision(self):
180 """There should be a last revision method we can call."""176 """There should be a last revision method we can call."""
181 tree = self.make_branch_and_memory_tree('branch')177 tree = self.make_branch_and_memory_tree('branch')
182 tree.lock_write()178 with tree.lock_write():
183 tree.add('')179 tree.add('')
184 rev_id = tree.commit('first post')180 rev_id = tree.commit('first post')
185 tree.unlock()
186 self.assertEqual(rev_id, tree.last_revision())181 self.assertEqual(rev_id, tree.last_revision())
187182
188 def test_rename_file(self):183 def test_rename_file(self):
189184
=== modified file 'breezy/tests/test_script.py'
--- breezy/tests/test_script.py 2018-11-20 21:24:08 +0000
+++ breezy/tests/test_script.py 2019-03-06 06:08:28 +0000
@@ -322,12 +322,12 @@
322 def test_cat_input_to_file(self):322 def test_cat_input_to_file(self):
323 retcode, out, err = self.run_command(['cat', '>file'],323 retcode, out, err = self.run_command(['cat', '>file'],
324 'content\n', None, None)324 'content\n', None, None)
325 self.assertFileEqual(b'content\n', 'file')325 self.assertFileEqual('content\n', 'file')
326 self.assertEqual(None, out)326 self.assertEqual(None, out)
327 self.assertEqual(None, err)327 self.assertEqual(None, err)
328 retcode, out, err = self.run_command(['cat', '>>file'],328 retcode, out, err = self.run_command(['cat', '>>file'],
329 'more\n', None, None)329 'more\n', None, None)
330 self.assertFileEqual(b'content\nmore\n', 'file')330 self.assertFileEqual('content\nmore\n', 'file')
331 self.assertEqual(None, out)331 self.assertEqual(None, out)
332 self.assertEqual(None, err)332 self.assertEqual(None, err)
333333
334334
=== modified file 'breezy/tests/test_urlutils.py'
--- breezy/tests/test_urlutils.py 2018-11-23 03:06:01 +0000
+++ breezy/tests/test_urlutils.py 2019-03-06 06:08:28 +0000
@@ -599,6 +599,9 @@
599 self.assertEqual(("foo/base,key1=val1/other/elements",599 self.assertEqual(("foo/base,key1=val1/other/elements",
600 {"key2": "val2"}), split_segment_parameters(600 {"key2": "val2"}), split_segment_parameters(
601 "foo/base,key1=val1/other/elements,key2=val2"))601 "foo/base,key1=val1/other/elements,key2=val2"))
602 self.assertRaises(
603 urlutils.InvalidURL, split_segment_parameters,
604 "foo/base,key1")
602 # TODO: Check full URLs as well as relative references605 # TODO: Check full URLs as well as relative references
603606
604 def test_win32_strip_local_trailing_slash(self):607 def test_win32_strip_local_trailing_slash(self):
605608
=== modified file 'breezy/transport/memory.py'
--- breezy/transport/memory.py 2018-11-17 16:53:10 +0000
+++ breezy/transport/memory.py 2019-03-06 06:08:28 +0000
@@ -26,9 +26,10 @@
26from io import (26from io import (
27 BytesIO,27 BytesIO,
28 )28 )
29import itertools
29import os30import os
30import errno31import errno
31from stat import S_IFREG, S_IFDIR, S_IFLNK32from stat import S_IFREG, S_IFDIR, S_IFLNK, S_ISDIR
3233
33from .. import (34from .. import (
34 transport,35 transport,
@@ -50,20 +51,16 @@
5051
51class MemoryStat(object):52class MemoryStat(object):
5253
53 def __init__(self, size, kind, perms):54 def __init__(self, size, kind, perms=None):
54 self.st_size = size55 self.st_size = size
55 if kind == 'file':56 if not S_ISDIR(kind):
56 if perms is None:57 if perms is None:
57 perms = 0o64458 perms = 0o644
58 self.st_mode = S_IFREG | perms59 self.st_mode = kind | perms
59 elif kind == 'directory':60 else:
60 if perms is None:61 if perms is None:
61 perms = 0o75562 perms = 0o755
62 self.st_mode = S_IFDIR | perms63 self.st_mode = kind | perms
63 elif kind == 'symlink':
64 self.st_mode = S_IFLNK | 0o644
65 else:
66 raise AssertionError('unknown kind %r' % kind)
6764
6865
69class MemoryTransport(transport.Transport):66class MemoryTransport(transport.Transport):
@@ -111,7 +108,7 @@
111108
112 def append_file(self, relpath, f, mode=None):109 def append_file(self, relpath, f, mode=None):
113 """See Transport.append_file()."""110 """See Transport.append_file()."""
114 _abspath = self._abspath(relpath)111 _abspath = self._resolve_symlinks(relpath)
115 self._check_parent(_abspath)112 self._check_parent(_abspath)
116 orig_content, orig_mode = self._files.get(_abspath, (b"", None))113 orig_content, orig_mode = self._files.get(_abspath, (b"", None))
117 if mode is None:114 if mode is None:
@@ -128,16 +125,20 @@
128 def has(self, relpath):125 def has(self, relpath):
129 """See Transport.has()."""126 """See Transport.has()."""
130 _abspath = self._abspath(relpath)127 _abspath = self._abspath(relpath)
131 return ((_abspath in self._files)128 for container in (self._files, self._dirs, self._symlinks):
132 or (_abspath in self._dirs)129 if _abspath in container.keys():
133 or (_abspath in self._symlinks))130 return True
131 return False
134132
135 def delete(self, relpath):133 def delete(self, relpath):
136 """See Transport.delete()."""134 """See Transport.delete()."""
137 _abspath = self._abspath(relpath)135 _abspath = self._abspath(relpath)
138 if _abspath not in self._files:136 if _abspath in self._files:
137 del self._files[_abspath]
138 elif _abspath in self._symlinks:
139 del self._symlinks[_abspath]
140 else:
139 raise NoSuchFile(relpath)141 raise NoSuchFile(relpath)
140 del self._files[_abspath]
141142
142 def external_url(self):143 def external_url(self):
143 """See breezy.transport.Transport.external_url."""144 """See breezy.transport.Transport.external_url."""
@@ -147,7 +148,7 @@
147148
148 def get(self, relpath):149 def get(self, relpath):
149 """See Transport.get()."""150 """See Transport.get()."""
150 _abspath = self._abspath(relpath)151 _abspath = self._resolve_symlinks(relpath)
151 if _abspath not in self._files:152 if _abspath not in self._files:
152 if _abspath in self._dirs:153 if _abspath in self._dirs:
153 return LateReadError(relpath)154 return LateReadError(relpath)
@@ -157,15 +158,20 @@
157158
158 def put_file(self, relpath, f, mode=None):159 def put_file(self, relpath, f, mode=None):
159 """See Transport.put_file()."""160 """See Transport.put_file()."""
160 _abspath = self._abspath(relpath)161 _abspath = self._resolve_symlinks(relpath)
161 self._check_parent(_abspath)162 self._check_parent(_abspath)
162 raw_bytes = f.read()163 raw_bytes = f.read()
163 self._files[_abspath] = (raw_bytes, mode)164 self._files[_abspath] = (raw_bytes, mode)
164 return len(raw_bytes)165 return len(raw_bytes)
165166
167 def symlink(self, source, target):
168 _abspath = self._resolve_symlinks(target)
169 self._check_parent(_abspath)
170 self._symlinks[_abspath] = self._abspath(source)
171
166 def mkdir(self, relpath, mode=None):172 def mkdir(self, relpath, mode=None):
167 """See Transport.mkdir()."""173 """See Transport.mkdir()."""
168 _abspath = self._abspath(relpath)174 _abspath = self._resolve_symlinks(relpath)
169 self._check_parent(_abspath)175 self._check_parent(_abspath)
170 if _abspath in self._dirs:176 if _abspath in self._dirs:
171 raise FileExists(relpath)177 raise FileExists(relpath)
@@ -183,13 +189,13 @@
183 return True189 return True
184190
185 def iter_files_recursive(self):191 def iter_files_recursive(self):
186 for file in self._files:192 for file in itertools.chain(self._files, self._symlinks):
187 if file.startswith(self._cwd):193 if file.startswith(self._cwd):
188 yield urlutils.escape(file[len(self._cwd):])194 yield urlutils.escape(file[len(self._cwd):])
189195
190 def list_dir(self, relpath):196 def list_dir(self, relpath):
191 """See Transport.list_dir()."""197 """See Transport.list_dir()."""
192 _abspath = self._abspath(relpath)198 _abspath = self._resolve_symlinks(relpath)
193 if _abspath != '/' and _abspath not in self._dirs:199 if _abspath != '/' and _abspath not in self._dirs:
194 raise NoSuchFile(relpath)200 raise NoSuchFile(relpath)
195 result = []201 result = []
@@ -197,7 +203,7 @@
197 if not _abspath.endswith('/'):203 if not _abspath.endswith('/'):
198 _abspath += '/'204 _abspath += '/'
199205
200 for path_group in self._files, self._dirs:206 for path_group in self._files, self._dirs, self._symlinks:
201 for path in path_group:207 for path in path_group:
202 if path.startswith(_abspath):208 if path.startswith(_abspath):
203 trailing = path[len(_abspath):]209 trailing = path[len(_abspath):]
@@ -207,8 +213,8 @@
207213
208 def rename(self, rel_from, rel_to):214 def rename(self, rel_from, rel_to):
209 """Rename a file or directory; fail if the destination exists"""215 """Rename a file or directory; fail if the destination exists"""
210 abs_from = self._abspath(rel_from)216 abs_from = self._resolve_symlinks(rel_from)
211 abs_to = self._abspath(rel_to)217 abs_to = self._resolve_symlinks(rel_to)
212218
213 def replace(x):219 def replace(x):
214 if x == abs_from:220 if x == abs_from:
@@ -233,21 +239,25 @@
233 # fail differently depending on dict order. So work on copy, fail on239 # fail differently depending on dict order. So work on copy, fail on
234 # error on only replace dicts if all goes well.240 # error on only replace dicts if all goes well.
235 renamed_files = self._files.copy()241 renamed_files = self._files.copy()
242 renamed_symlinks = self._symlinks.copy()
236 renamed_dirs = self._dirs.copy()243 renamed_dirs = self._dirs.copy()
237 do_renames(renamed_files)244 do_renames(renamed_files)
245 do_renames(renamed_symlinks)
238 do_renames(renamed_dirs)246 do_renames(renamed_dirs)
239 # We may have been cloned so modify in place247 # We may have been cloned so modify in place
240 self._files.clear()248 self._files.clear()
241 self._files.update(renamed_files)249 self._files.update(renamed_files)
250 self._symlinks.clear()
251 self._symlinks.update(renamed_symlinks)
242 self._dirs.clear()252 self._dirs.clear()
243 self._dirs.update(renamed_dirs)253 self._dirs.update(renamed_dirs)
244254
245 def rmdir(self, relpath):255 def rmdir(self, relpath):
246 """See Transport.rmdir."""256 """See Transport.rmdir."""
247 _abspath = self._abspath(relpath)257 _abspath = self._resolve_symlinks(relpath)
248 if _abspath in self._files:258 if _abspath in self._files:
249 self._translate_error(IOError(errno.ENOTDIR, relpath), relpath)259 self._translate_error(IOError(errno.ENOTDIR, relpath), relpath)
250 for path in self._files:260 for path in itertools.chain(self._files, self._symlinks):
251 if path.startswith(_abspath + '/'):261 if path.startswith(_abspath + '/'):
252 self._translate_error(IOError(errno.ENOTEMPTY, relpath),262 self._translate_error(IOError(errno.ENOTEMPTY, relpath),
253 relpath)263 relpath)
@@ -262,13 +272,13 @@
262 def stat(self, relpath):272 def stat(self, relpath):
263 """See Transport.stat()."""273 """See Transport.stat()."""
264 _abspath = self._abspath(relpath)274 _abspath = self._abspath(relpath)
265 if _abspath in self._files:275 if _abspath in self._files.keys():
266 return MemoryStat(len(self._files[_abspath][0]), 'file',276 return MemoryStat(len(self._files[_abspath][0]), S_IFREG,
267 self._files[_abspath][1])277 self._files[_abspath][1])
268 elif _abspath in self._dirs:278 elif _abspath in self._dirs.keys():
269 return MemoryStat(0, 'directory', self._dirs[_abspath])279 return MemoryStat(0, S_IFDIR, self._dirs[_abspath])
270 elif _abspath in self._symlinks:280 elif _abspath in self._symlinks.keys():
271 return MemoryStat(0, 'symlink', 0)281 return MemoryStat(0, S_IFLNK)
272 else:282 else:
273 raise NoSuchFile(_abspath)283 raise NoSuchFile(_abspath)
274284
@@ -280,6 +290,12 @@
280 """See Transport.lock_write()."""290 """See Transport.lock_write()."""
281 return _MemoryLock(self._abspath(relpath), self)291 return _MemoryLock(self._abspath(relpath), self)
282292
293 def _resolve_symlinks(self, relpath):
294 path = self._abspath(relpath)
295 while path in self._symlinks.keys():
296 path = self._symlinks[path]
297 return path
298
283 def _abspath(self, relpath):299 def _abspath(self, relpath):
284 """Generate an internal absolute path."""300 """Generate an internal absolute path."""
285 relpath = urlutils.unescape(relpath)301 relpath = urlutils.unescape(relpath)
@@ -336,6 +352,7 @@
336 def start_server(self):352 def start_server(self):
337 self._dirs = {'/': None}353 self._dirs = {'/': None}
338 self._files = {}354 self._files = {}
355 self._symlinks = {}
339 self._locks = {}356 self._locks = {}
340 self._scheme = "memory+%s:///" % id(self)357 self._scheme = "memory+%s:///" % id(self)
341358
@@ -344,6 +361,7 @@
344 result = memory.MemoryTransport(url)361 result = memory.MemoryTransport(url)
345 result._dirs = self._dirs362 result._dirs = self._dirs
346 result._files = self._files363 result._files = self._files
364 result._symlinks = self._symlinks
347 result._locks = self._locks365 result._locks = self._locks
348 return result366 return result
349 self._memory_factory = memory_factory367 self._memory_factory = memory_factory
350368
=== modified file 'breezy/urlutils.py'
--- breezy/urlutils.py 2018-11-16 23:19:12 +0000
+++ breezy/urlutils.py 2019-03-06 06:08:28 +0000
@@ -561,7 +561,10 @@
561 (base_url, subsegments) = split_segment_parameters_raw(url)561 (base_url, subsegments) = split_segment_parameters_raw(url)
562 parameters = {}562 parameters = {}
563 for subsegment in subsegments:563 for subsegment in subsegments:
564 (key, value) = subsegment.split("=", 1)564 try:
565 (key, value) = subsegment.split("=", 1)
566 except ValueError:
567 raise InvalidURL(url, "missing = in subsegment")
565 if not isinstance(key, str):568 if not isinstance(key, str):
566 raise TypeError(key)569 raise TypeError(key)
567 if not isinstance(value, str):570 if not isinstance(value, str):
568571
=== added file 'build.cmd'
--- build.cmd 1970-01-01 00:00:00 +0000
+++ build.cmd 2019-03-06 06:08:28 +0000
@@ -0,0 +1,21 @@
1@echo off
2:: To build extensions for 64 bit Python 3, we need to configure environment
3:: variables to use the MSVC 2010 C++ compilers from GRMSDKX_EN_DVD.iso of:
4:: MS Windows SDK for Windows 7 and .NET Framework 4
5::
6:: More details at:
7:: https://github.com/cython/cython/wiki/CythonExtensionsOnWindows
8
9IF "%DISTUTILS_USE_SDK%"=="1" (
10 ECHO Configuring environment to build with MSVC on a 64bit architecture
11 ECHO Using Windows SDK 7.1
12 "C:\Program Files\Microsoft SDKs\Windows\v7.1\Setup\WindowsSdkVer.exe" -q -version:v7.1
13 CALL "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64 /release
14 SET MSSdk=1
15 REM Need the following to allow tox to see the SDK compiler
16 SET TOX_TESTENV_PASSENV=DISTUTILS_USE_SDK MSSdk INCLUDE LIB
17) ELSE (
18 ECHO Using default MSVC build environment
19)
20
21CALL %*
022
=== modified file 'byov.conf'
--- byov.conf 2018-12-19 01:30:58 +0000
+++ byov.conf 2019-03-06 06:08:28 +0000
@@ -13,6 +13,8 @@
13sphinx_epytext.install3 = (pip3 install sphinx_epytext)13sphinx_epytext.install3 = (pip3 install sphinx_epytext)
14flake8.install = (pip install flake8)14flake8.install = (pip install flake8)
15flake8.install3 = (pip3 install flake8)15flake8.install3 = (pip3 install flake8)
16cython.install = (pip install cython)
17cython.install3 = (pip3 install cython)
1618
17[brz]19[brz]
18# FIXME: we're stuck on xenial20# FIXME: we're stuck on xenial
@@ -25,12 +27,12 @@
2527
26# FIXME: Arguably this should be vm.build_deps=brz but it requires either an28# FIXME: Arguably this should be vm.build_deps=brz but it requires either an
27# available package or at least a debian/ dir ? -- vila 2018-02-2329# available package or at least a debian/ dir ? -- vila 2018-02-23
28brz.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-launchpadlib30brz.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
29subunit.build_deps = python-testscenarios, python3-testscenarios, python-testtools, python3-testtools31subunit.build_deps = python-testscenarios, python3-testscenarios, python-testtools, python3-testtools
30vm.packages = {brz.build_deps}, {subunit.build_deps}, bzr, git, python-junitxml32vm.packages = {brz.build_deps}, {subunit.build_deps}, bzr, git, python-junitxml
31[brz-xenial]33[brz-xenial]
32vm.release = xenial34vm.release = xenial
33byoci.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})35byoci.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})
34# FIXME: bzr log -l2 should be by default -- vila 2018-03-0936# FIXME: bzr log -l2 should be by default -- vila 2018-03-09
35byoci.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"37byoci.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"
36[brz-bionic]38[brz-bionic]
3739
=== modified file 'doc/developers/apport.txt'
--- doc/developers/apport.txt 2009-12-02 20:34:07 +0000
+++ doc/developers/apport.txt 2019-03-06 06:08:28 +0000
@@ -41,7 +41,7 @@
4141
42#. An exception reaches the top-level handler.42#. An exception reaches the top-level handler.
4343
44#. We log it in apport-format to a file in ~/.bazaar/crash.44#. We log it in apport-format to a file in ~/.config/breezy/crash.
4545
46#. We tell the user where that file is, and invite them to file a bug46#. We tell the user where that file is, and invite them to file a bug
47 report.47 report.
4848
=== modified file 'doc/developers/configuration.txt'
--- doc/developers/configuration.txt 2017-07-30 16:59:50 +0000
+++ doc/developers/configuration.txt 2019-03-06 06:08:28 +0000
@@ -154,20 +154,6 @@
154though). The ``bzr-bookmarks`` plugin defines a ``BOOKMARKS`` section there154though). The ``bzr-bookmarks`` plugin defines a ``BOOKMARKS`` section there
155for example.155for example.
156156
157pkgimport.conf
158==============
159
160The Ubuntu package importer defines a store and two stacks involving
161``pkgimport.conf``. A no-name section contains the options common to all
162packages and sections named after their corresponding package can also be
163defined.
164
165The ``ImporterStack`` uses ``locations.conf`` and the no-name section in
166``pkgimport.conf`` for the importer options.
167
168The ``PackageStack`` uses only ``pkgimport.conf`` and uses the section name
169after the package followed by the no-name section.
170
171location.conf157location.conf
172=============158=============
173159
174160
=== modified file 'doc/developers/contribution-quickstart.txt'
--- doc/developers/contribution-quickstart.txt 2019-01-01 21:38:07 +0000
+++ doc/developers/contribution-quickstart.txt 2019-03-06 06:08:28 +0000
@@ -46,7 +46,7 @@
46closely-related cluster of bugs per branch, to make reviews and merges46closely-related cluster of bugs per branch, to make reviews and merges
47flow more smoothly.47flow more smoothly.
4848
49You probably want this configuration in ``~/.bazaar/locations.conf``::49You probably want this configuration in ``~/.config/breezy/locations.conf``::
5050
51 [/home/USER/brz]51 [/home/USER/brz]
52 push_location = lp:~LAUNCHPAD_USER/brz/{branchname}52 push_location = lp:~LAUNCHPAD_USER/brz/{branchname}
5353
=== modified file 'doc/developers/plugin-development.txt'
--- doc/developers/plugin-development.txt 2018-11-22 02:23:26 +0000
+++ doc/developers/plugin-development.txt 2019-03-06 06:08:28 +0000
@@ -31,7 +31,7 @@
31To ensure your plugin under development is available to Breezy, set31To ensure your plugin under development is available to Breezy, set
32the ``BRZ_PLUGIN_PATH`` environment variable to its parent directory.32the ``BRZ_PLUGIN_PATH`` environment variable to its parent directory.
33Alternatively, you may wish to develop your plugin within a directory33Alternatively, you may wish to develop your plugin within a directory
34under your personal plugins area (``~/.bazaar/plugins`` on GNU/Linux)34under your personal plugins area (``~/.config/breezy/plugins`` on GNU/Linux)
35or put a symbolic link in that area pointing to your plugin under35or put a symbolic link in that area pointing to your plugin under
36test. Finally you can use ``BRZ_PLUGINS_AT`` to point to a specific36test. Finally you can use ``BRZ_PLUGINS_AT`` to point to a specific
37directory for a specific plugin (separated by your platform's value of37directory for a specific plugin (separated by your platform's value of
3838
=== modified file 'doc/en/admin-guide/hooks-plugins.txt'
--- doc/en/admin-guide/hooks-plugins.txt 2018-11-18 13:20:01 +0000
+++ doc/en/admin-guide/hooks-plugins.txt 2019-03-06 06:08:28 +0000
@@ -25,10 +25,10 @@
25http://doc.bazaar.canonical.com/plugins/en/. For purposes of installation,25http://doc.bazaar.canonical.com/plugins/en/. For purposes of installation,
26plugins are simply python packages. They can be installed alongside Bazaar in26plugins are simply python packages. They can be installed alongside Bazaar in
27the ``bzrlib.plugins`` package using each plugin's ``setup.py``. They can27the ``bzrlib.plugins`` package using each plugin's ``setup.py``. They can
28also be installed in the plugin path which is the user's ``~/.bazaar/plugins``28also be installed in the plugin path which is the user's
29directory or can be specified with the ``BZR_PLUGIN_PATH`` environment29``~/.config/breezy/plugins`` directory or can be specified with the
30variable. See ``bzr help configuration`` for more on specifying the location30``BZR_PLUGIN_PATH`` environment variable. See ``bzr help configuration`` for
31of plugins.31more on specifying the location of plugins.
3232
3333
34Email Notification34Email Notification
3535
=== modified file 'doc/en/admin-guide/migration.txt'
--- doc/en/admin-guide/migration.txt 2018-11-18 13:20:01 +0000
+++ doc/en/admin-guide/migration.txt 2019-03-06 06:08:28 +0000
@@ -56,7 +56,7 @@
56This command has flexible ways to specify what paths within the Subversion56This command has flexible ways to specify what paths within the Subversion
57repository contain branches and which contain tags. For example, the57repository contain branches and which contain tags. For example, the
58recommended layout for Subversion projects (called ``trunk`` by the svn58recommended layout for Subversion projects (called ``trunk`` by the svn
59plugin) could be specified in ``~/.bazaar/subversion.conf`` as59plugin) could be specified in ``~/.config/breezy/subversion.conf`` as
6060
61::61::
6262
6363
=== modified file 'doc/en/release-notes/brz-3.0.txt'
--- doc/en/release-notes/brz-3.0.txt 2019-03-02 22:31:28 +0000
+++ doc/en/release-notes/brz-3.0.txt 2019-03-06 06:08:28 +0000
@@ -85,6 +85,9 @@
85 longer performed, since there are no longer85 longer performed, since there are no longer
86 any automated imports. (Jelmer Vernooij)86 any automated imports. (Jelmer Vernooij)
8787
88 * ``setuptools`` is now required to build and install Breezy.
89 (Jelmer Vernooij)
90
88New Features91New Features
89************92************
9093
@@ -234,6 +237,13 @@
234* Don't report .git files as unknown files.237* Don't report .git files as unknown files.
235 (Jelmer Vernooij, Debian Bug #921240)238 (Jelmer Vernooij, Debian Bug #921240)
236239
240* Raise better error when path subsegments lack =.
241 (Jelmer Vernooij, #891483)
242
243* Display correct pull location argument in
244 output of ``brz uncommit``.
245 (Jelmer Vernooij, #386577)
246
237Documentation247Documentation
238*************248*************
239249
240250
=== modified file 'doc/en/user-guide/controlling_registration.txt'
--- doc/en/user-guide/controlling_registration.txt 2017-05-21 13:41:54 +0000
+++ doc/en/user-guide/controlling_registration.txt 2019-03-06 06:08:28 +0000
@@ -95,12 +95,12 @@
95There are some ignored files which are not project specific, but more user95There are some ignored files which are not project specific, but more user
96specific. Things like editor temporary files, or personal temporary files.96specific. Things like editor temporary files, or personal temporary files.
97Rather than add these ignores to every project, brz supports a global97Rather than add these ignores to every project, brz supports a global
98ignore file in ``~/.bazaar/ignore`` [#]_. It has the same syntax as the98ignore file in ``~/.config/breezy/ignore`` [#]_. It has the same syntax as the
99per-project ignore file.99per-project ignore file.
100100
101.. [#] On Windows, the users configuration files can be found in the101.. [#] On Windows, the users configuration files can be found in the
102 application data directory. So instead of ``~/.bazaar/branch.conf``102 application data directory. So instead of ``~/.config/breezy/branch.conf``
103 the configuration file can be found as:103 the configuration file can be found as:
104 ``C:\Documents and Settings\<username>\Application Data\Breezy\2.0\branch.conf``.104 ``C:\Documents and Settings\<username>\Application Data\Breezy\3.0\branch.conf``.
105 The same is true for ``locations.conf``, ``ignore``, and the105 The same is true for ``locations.conf``, ``ignore``, and the
106 ``plugins`` directory.106 ``plugins`` directory.
107107
=== added file 'doc/en/user-guide/git_limitations.txt'
--- doc/en/user-guide/git_limitations.txt 1970-01-01 00:00:00 +0000
+++ doc/en/user-guide/git_limitations.txt 2019-03-06 06:08:28 +0000
@@ -0,0 +1,18 @@
1Git Limitations
2===============
3
4Breezy's support for Git repositories currently has the following limitations:
5
6* No support for creating annotated tags. pad.lv/1758185
7* No support for gitattributes and the features that depend on it (lfs, eol, etc). pad.lv/1802797
8* Limited support for submodules. pad.lv/402814
9* No rename/copy inference. pad.lv/1760740
10* No support for creating shallow branches (pad.lv/1760151)
11* No good way to refer to git remotes from the command-line (pad.lv/1702283)
12* No mailmap support (pad.lv/544031)
13
14Functionality similar to git that's missing:
15
16* No rebase command. pad.lv/1708046
17* No --amend option for commit. pad.lv/507529
18* No clone/fetch commands. pad.lv/831939
019
=== modified file 'doc/en/user-guide/index-plain.txt'
--- doc/en/user-guide/index-plain.txt 2018-11-24 15:56:05 +0000
+++ doc/en/user-guide/index-plain.txt 2019-03-06 06:08:28 +0000
@@ -114,6 +114,7 @@
114.. include:: setting_up_email.txt114.. include:: setting_up_email.txt
115.. include:: http_smart_server.txt115.. include:: http_smart_server.txt
116.. include:: writing_a_plugin.txt116.. include:: writing_a_plugin.txt
117.. include:: git_limitations.txt
117.. include:: licence.txt118.. include:: licence.txt
118119
119.. |--| unicode:: U+2014120.. |--| unicode:: U+2014
120121
=== modified file 'doc/en/user-guide/installing_breezy.txt'
--- doc/en/user-guide/installing_breezy.txt 2018-11-18 13:43:04 +0000
+++ doc/en/user-guide/installing_breezy.txt 2019-03-06 06:08:28 +0000
@@ -90,7 +90,7 @@
90 3. Put the created directory on your PATH.90 3. Put the created directory on your PATH.
9191
92Advanced users may also wish to build the optional C extensions for greater92Advanced users may also wish to build the optional C extensions for greater
93speed. This can be done using ``make`` and requires ``pyrex`` and a C compiler.93speed. This can be done using ``make`` and requires ``cython`` and a C compiler.
94Please contact us on email or IRC if you need assistance with this.94Please contact us on email or IRC if you need assistance with this.
9595
9696
9797
=== modified file 'doc/en/user-guide/plugins.txt'
--- doc/en/user-guide/plugins.txt 2017-05-21 13:41:54 +0000
+++ doc/en/user-guide/plugins.txt 2019-03-06 06:08:28 +0000
@@ -35,7 +35,7 @@
3535
36Installing a plugin is very easy! If not already created, create a36Installing a plugin is very easy! If not already created, create a
37``plugins`` directory under your Breezy configuration directory,37``plugins`` directory under your Breezy configuration directory,
38``~/.bazaar/`` on Unix and38``~/.config/breezy/`` on Unix and
39``C:\Documents and Settings\<username>\Application Data\Breezy\2.0\``39``C:\Documents and Settings\<username>\Application Data\Breezy\2.0\``
40on Windows. Within this directory (referred to as $BZR_HOME below),40on Windows. Within this directory (referred to as $BZR_HOME below),
41each plugin is placed in its own subdirectory.41each plugin is placed in its own subdirectory.
@@ -45,7 +45,7 @@
45one can perform the following::45one can perform the following::
4646
47 brz branch http://panoramicfeedback.com/opensource/brz/brztools47 brz branch http://panoramicfeedback.com/opensource/brz/brztools
48 ~/.bazaar/plugins/brztools48 ~/.config/breezy/plugins/brztools
4949
50When installing plugins, the directories that you install them in must50When installing plugins, the directories that you install them in must
51be valid python identifiers. This means that they can only contain51be valid python identifiers. This means that they can only contain
5252
=== modified file 'setup.py'
--- setup.py 2019-02-06 05:44:37 +0000
+++ setup.py 2019-03-06 06:08:28 +0000
@@ -16,6 +16,14 @@
16 sys.stderr.write("[ERROR] Not a supported Python version. Need 2.7+\n")16 sys.stderr.write("[ERROR] Not a supported Python version. Need 2.7+\n")
17 sys.exit(1)17 sys.exit(1)
1818
19
20try:
21 import setuptools
22except ImportError:
23 sys.stderr.write("[ERROR] Please install setuptools\n")
24 sys.exit(1)
25
26
19# NOTE: The directory containing setup.py, whether run by 'python setup.py' or27# NOTE: The directory containing setup.py, whether run by 'python setup.py' or
20# './setup.py' or the equivalent with another path, should always be at the28# './setup.py' or the equivalent with another path, should always be at the
21# start of the path, so this should find the right one...29# start of the path, so this should find the right one...
@@ -118,8 +126,7 @@
118BREEZY['packages'] = get_breezy_packages()126BREEZY['packages'] = get_breezy_packages()
119127
120128
121from distutils import log129from setuptools import setup
122from distutils.core import setup
123from distutils.version import LooseVersion130from distutils.version import LooseVersion
124from distutils.command.install_scripts import install_scripts131from distutils.command.install_scripts import install_scripts
125from distutils.command.install_data import install_data132from distutils.command.install_data import install_data
@@ -211,8 +218,17 @@
211 print("")218 print("")
212 from distutils.command.build_ext import build_ext219 from distutils.command.build_ext import build_ext
213else:220else:
214 have_cython = True221 minimum_cython_version = '0.29'
215 cython_version_info = LooseVersion(cython_version)222 cython_version_info = LooseVersion(cython_version)
223 if cython_version_info < LooseVersion(minimum_cython_version):
224 print("Version of Cython is too old. "
225 "Current is %s, need at least %s."
226 % (cython_version, minimum_cython_version))
227 print("If the .c files are available, they will be built,"
228 " but modifying the .pyx files will not rebuild them.")
229 have_cython = False
230 else:
231 have_cython = True
216232
217233
218class build_ext_if_possible(build_ext):234class build_ext_if_possible(build_ext):

Subscribers

People subscribed via source and target branches