Merge lp:~jelmer/brz/3.2-merge-3.1 into lp:brz/3.2

Proposed by Jelmer Vernooij
Status: Merged
Approved by: Jelmer Vernooij
Approved revision: no longer in the source branch.
Merge reported by: The Breezy Bot
Merged at revision: not available
Proposed branch: lp:~jelmer/brz/3.2-merge-3.1
Merge into: lp:brz/3.2
Diff against target: 314 lines (+146/-15)
7 files modified
breezy/config.py (+2/-0)
breezy/git/branch.py (+2/-2)
breezy/git/dir.py (+8/-2)
breezy/git/transportgit.py (+110/-7)
breezy/memorybranch.py (+18/-2)
breezy/plugins/github/hoster.py (+4/-0)
setup.py (+2/-2)
To merge this branch: bzr merge lp:~jelmer/brz/3.2-merge-3.1
Reviewer Review Type Date Requested Status
Jelmer Vernooij Approve
Review via email: mp+402123@code.launchpad.net

This proposal supersedes a proposal from 2021-05-02.

Commit message

Merge lp:brz/3.1.

Description of the change

Merge lp:brz/3.1.

To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) : Posted in a previous version of this proposal
review: Approve
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote : Posted in a previous version of this proposal
Revision history for this message
Jelmer Vernooij (jelmer) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'breezy/config.py'
2--- breezy/config.py 2020-06-23 01:02:30 +0000
3+++ breezy/config.py 2021-05-02 18:08:32 +0000
4@@ -1250,6 +1250,8 @@
5
6 def _get_location_config(self):
7 if self._location_config is None:
8+ if self.branch.base is None:
9+ self.branch.base = 'memory://'
10 self._location_config = LocationConfig(self.branch.base)
11 return self._location_config
12
13
14=== modified file 'breezy/git/branch.py'
15--- breezy/git/branch.py 2021-04-03 12:58:34 +0000
16+++ breezy/git/branch.py 2021-05-02 18:08:32 +0000
17@@ -456,10 +456,10 @@
18 except ValueError:
19 self.name = None
20 if self.ref is not None:
21- params = {"ref": urlutils.escape(self.ref)}
22+ params = {"ref": urlutils.escape(self.ref, safe='')}
23 else:
24 if self.name != "":
25- params = {"branch": urlutils.escape(self.name)}
26+ params = {"branch": urlutils.escape(self.name, safe='')}
27 for k, v in params.items():
28 self._user_transport.set_segment_parameter(k, v)
29 self._control_transport.set_segment_parameter(k, v)
30
31=== modified file 'breezy/git/dir.py'
32--- breezy/git/dir.py 2021-04-03 12:58:34 +0000
33+++ breezy/git/dir.py 2021-05-02 18:08:32 +0000
34@@ -161,7 +161,8 @@
35 result = ControlDir.open_from_transport(target_transport)
36 except brz_errors.NotBranchError:
37 result = cloning_format.initialize_on_transport(target_transport)
38- source_branch = self.open_branch()
39+ if source_branch is None:
40+ source_branch = self.open_branch()
41 source_repository = self.find_repository()
42 try:
43 result_repo = result.find_repository()
44@@ -637,7 +638,12 @@
45 if not nascent_ok and ref not in self._git.refs:
46 raise brz_errors.NotBranchError(
47 self.root_transport.base, controldir=self)
48- ref_chain, unused_sha = self._git.refs.follow(ref)
49+ try:
50+ ref_chain, unused_sha = self._git.refs.follow(ref)
51+ except KeyError as e:
52+ raise brz_errors.NotBranchError(
53+ self.root_transport.base, controldir=self,
54+ detail='intermediate ref %s missing' % e.args[0])
55 if ref_chain[-1] == b'HEAD':
56 controldir = self
57 else:
58
59=== modified file 'breezy/git/transportgit.py'
60--- breezy/git/transportgit.py 2020-05-06 02:13:25 +0000
61+++ breezy/git/transportgit.py 2021-05-02 18:08:32 +0000
62@@ -20,6 +20,7 @@
63
64 import os
65 import sys
66+import posixpath
67
68 from dulwich.errors import (
69 NoIndexPresent,
70@@ -39,11 +40,16 @@
71 from dulwich.pack import (
72 MemoryPackIndex,
73 PackData,
74+ PackIndexer,
75 Pack,
76+ PackStreamCopier,
77 iter_sha1,
78 load_pack_index_file,
79 write_pack_objects,
80 write_pack_index_v2,
81+ write_pack_header,
82+ compute_file_sha,
83+ write_pack_object,
84 )
85 from dulwich.repo import (
86 BaseRepo,
87@@ -96,12 +102,7 @@
88 return "%s(%r)" % (self.__class__.__name__, self.transport)
89
90 def _ensure_dir_exists(self, path):
91- for n in range(path.count("/")):
92- dirname = "/".join(path.split("/")[:n + 1])
93- try:
94- self.transport.mkdir(dirname)
95- except FileExists:
96- pass
97+ self.transport.clone(posixpath.dirname(path)).create_prefix()
98
99 def subkeys(self, base):
100 """Refs present in this container under a base.
101@@ -267,6 +268,7 @@
102 :param new_ref: The new sha the refname will refer to.
103 :return: True if the set was successful, False otherwise.
104 """
105+ self._check_refname(name)
106 try:
107 realnames, _ = self.follow(name)
108 realname = realnames[-1]
109@@ -640,7 +642,12 @@
110 try:
111 size = self.pack_transport.stat(pack_name).st_size
112 except TransportNotPossible:
113- f = self.pack_transport.get(pack_name)
114+ try:
115+ f = self.pack_transport.get(pack_name)
116+ except NoSuchFile:
117+ warning('Unable to read pack file %s',
118+ self.pack_transport.abspath(pack_name))
119+ continue
120 # TODO(jelmer): Don't read entire file into memory?
121 f = BytesIO(f.read())
122 pd = PackData(pack_name, f)
123@@ -817,3 +824,99 @@
124 except FileExists:
125 pass
126 return cls(transport)
127+
128+ def _get_pack_basepath(self, entries):
129+ suffix = iter_sha1(entry[0] for entry in entries)
130+ # TODO: Handle self.pack_dir being bytes
131+ suffix = suffix.decode('ascii')
132+ return self.pack_transport.local_abspath("pack-" + suffix)
133+
134+ def _complete_thin_pack(self, f, path, copier, indexer):
135+ """Move a specific file containing a pack into the pack directory.
136+
137+ Note: The file should be on the same file system as the
138+ packs directory.
139+
140+ Args:
141+ f: Open file object for the pack.
142+ path: Path to the pack file.
143+ copier: A PackStreamCopier to use for writing pack data.
144+ indexer: A PackIndexer for indexing the pack.
145+ """
146+ entries = list(indexer)
147+
148+ # Update the header with the new number of objects.
149+ f.seek(0)
150+ write_pack_header(f, len(entries) + len(indexer.ext_refs()))
151+
152+ # Must flush before reading (http://bugs.python.org/issue3207)
153+ f.flush()
154+
155+ # Rescan the rest of the pack, computing the SHA with the new header.
156+ new_sha = compute_file_sha(f, end_ofs=-20)
157+
158+ # Must reposition before writing (http://bugs.python.org/issue3207)
159+ f.seek(0, os.SEEK_CUR)
160+
161+ # Complete the pack.
162+ for ext_sha in indexer.ext_refs():
163+ type_num, data = self.get_raw(ext_sha)
164+ offset = f.tell()
165+ crc32 = write_pack_object(
166+ f, type_num, data, sha=new_sha,
167+ compression_level=self.pack_compression_level)
168+ entries.append((ext_sha, offset, crc32))
169+ pack_sha = new_sha.digest()
170+ f.write(pack_sha)
171+ f.close()
172+
173+ # Move the pack in.
174+ entries.sort()
175+ pack_base_name = self._get_pack_basepath(entries)
176+ target_pack = pack_base_name + '.pack'
177+ if sys.platform == 'win32':
178+ # Windows might have the target pack file lingering. Attempt
179+ # removal, silently passing if the target does not exist.
180+ try:
181+ os.remove(target_pack)
182+ except FileNotFoundError:
183+ pass
184+ os.rename(path, target_pack)
185+
186+ # Write the index.
187+ index_file = GitFile(pack_base_name + '.idx', 'wb')
188+ try:
189+ write_pack_index_v2(index_file, entries, pack_sha)
190+ index_file.close()
191+ finally:
192+ index_file.abort()
193+
194+ # Add the pack to the store and return it.
195+ final_pack = Pack(pack_base_name)
196+ final_pack.check_length_and_checksum()
197+ self._add_cached_pack(pack_base_name, final_pack)
198+ return final_pack
199+
200+ def add_thin_pack(self, read_all, read_some):
201+ """Add a new thin pack to this object store.
202+
203+ Thin packs are packs that contain deltas with parents that exist
204+ outside the pack. They should never be placed in the object store
205+ directly, and always indexed and completed as they are copied.
206+
207+ Args:
208+ read_all: Read function that blocks until the number of
209+ requested bytes are read.
210+ read_some: Read function that returns at least one byte, but may
211+ not return the number of bytes requested.
212+ Returns: A Pack object pointing at the now-completed thin pack in the
213+ objects/pack directory.
214+ """
215+ import tempfile
216+ fd, path = tempfile.mkstemp(dir=self.pack_transport.local_abspath('.'), prefix='tmp_pack_')
217+ with os.fdopen(fd, 'w+b') as f:
218+ indexer = PackIndexer(f, resolve_ext_ref=self.get_raw)
219+ copier = PackStreamCopier(read_all, read_some, f,
220+ delta_iter=indexer)
221+ copier.verify()
222+ return self._complete_thin_pack(f, path, copier, indexer)
223
224=== modified file 'breezy/memorybranch.py'
225--- breezy/memorybranch.py 2020-07-28 01:15:49 +0000
226+++ breezy/memorybranch.py 2021-05-02 18:08:32 +0000
227@@ -20,7 +20,7 @@
228 from __future__ import absolute_import
229
230 from . import config as _mod_config, errors, osutils
231-from .branch import Branch
232+from .branch import Branch, BranchWriteLockResult
233 from .lock import LogicalLockResult, _RelockDebugMixin
234 from .revision import NULL_REVISION
235 from .tag import DisabledTags, MemoryTags
236@@ -42,6 +42,9 @@
237 self._partial_revision_id_to_revno_cache = {}
238 self.base = 'memory://' + osutils.rand_chars(10)
239
240+ def __repr__(self):
241+ return "<MemoryBranch()>"
242+
243 def get_config(self):
244 return _mod_config.Config()
245
246@@ -49,6 +52,9 @@
247 self.repository.lock_read()
248 return LogicalLockResult(self.unlock)
249
250+ def is_locked(self):
251+ return self.repository.is_locked()
252+
253 def lock_write(self, token=None):
254 self.repository.lock_write()
255 return BranchWriteLockResult(self.unlock, None)
256@@ -62,7 +68,6 @@
257 def _gen_revision_history(self):
258 """Generate the revision history from last revision
259 """
260- last_revno, last_revision = self.last_revision_info()
261 with self.lock_read():
262 self._extend_partial_history()
263 return list(reversed(self._partial_revision_history_cache))
264@@ -87,3 +92,14 @@
265 distance_from_last:
266 self._extend_partial_history(distance_from_last)
267 return self._partial_revision_history_cache[distance_from_last]
268+
269+ def get_config_stack(self):
270+ """Get a breezy.config.BranchStack for this Branch.
271+
272+ This can then be used to get and set configuration options for the
273+ branch.
274+
275+ :return: A breezy.config.BranchStack.
276+ """
277+ gstore = _mod_config.GlobalStore()
278+ return _mod_config.Stack([_mod_config.NameMatcher(gstore, 'DEFAULT').get_sections])
279
280=== modified file 'breezy/plugins/github/hoster.py'
281--- breezy/plugins/github/hoster.py 2021-04-03 12:58:34 +0000
282+++ breezy/plugins/github/hoster.py 2021-05-02 18:08:32 +0000
283@@ -333,6 +333,8 @@
284 'POST', path, body=json.dumps(data).encode('utf-8'))
285 if response.status == 403:
286 raise PermissionDenied(path, response.text)
287+ if response.status == 422:
288+ raise ValidationFailed(json.loads(response.text))
289 if response.status != 201:
290 raise UnexpectedHttpStatus(path, response.status)
291 return json.loads(response.text)
292@@ -659,5 +661,7 @@
293 maintainer_can_modify=allow_collaboration,
294 )
295 except ValidationFailed:
296+ # TODO(jelmer): Check the actual error message rather than assuming
297+ # a merge proposal exists?
298 raise MergeProposalExists(self.source_branch.user_url)
299 return GitHubMergeProposal(self.gh, pull_request)
300
301=== modified file 'setup.py'
302--- setup.py 2021-02-19 02:53:40 +0000
303+++ setup.py 2021-05-02 18:08:32 +0000
304@@ -72,8 +72,8 @@
305 ],
306 'extras_require': {
307 'cext': ['cython>=0.29'],
308- 'fastimport': ['fastimport'],
309- 'git': [],
310+ 'fastimport': ['fastimport<0.9.8;python_version<"3.0"', 'fastimport;python_version>="3.5"'],
311+ 'git': ['dulwich'],
312 'launchpad': ['launchpadlib>=1.6.3'],
313 'workspace': ['pyinotify'],
314 'doc': ['setuptools<45;python_version<"3.0"', 'sphinx==1.8.5;python_version<"3.0"', 'sphinx_epytext'],

Subscribers

People subscribed via source and target branches