Merge lp:~jelmer/brz/inter-memorygittree into lp:brz

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/inter-memorygittree
Merge into: lp:brz
Diff against target: 277 lines (+110/-89)
4 files modified
breezy/plugins/git/memorytree.py (+16/-0)
breezy/plugins/git/tests/test_workingtree.py (+3/-1)
breezy/plugins/git/tree.py (+88/-1)
breezy/plugins/git/workingtree.py (+3/-87)
To merge this branch: bzr merge lp:~jelmer/brz/inter-memorygittree
Reviewer Review Type Date Requested Status
Jelmer Vernooij Approve
Review via email: mp+346426@code.launchpad.net

Commit message

Make InterIndexGitTree suitable for use with MemoryGitTree.

Description of the change

Make InterIndexGitTree suitable for use with MemoryGitTree.

To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) wrote :

Rubberstamp! Proposer approves of own proposal.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'breezy/plugins/git/memorytree.py'
2--- breezy/plugins/git/memorytree.py 2018-03-26 22:28:24 +0000
3+++ breezy/plugins/git/memorytree.py 2018-05-21 21:08:24 +0000
4@@ -23,7 +23,11 @@
5 import posixpath
6 import stat
7
8+from dulwich.index import (
9+ index_entry_from_stat,
10+ )
11 from dulwich.objects import (
12+ Blob,
13 Tree,
14 )
15
16@@ -171,6 +175,18 @@
17 (mem_stat.st_mode, 0, 0, 0, 0, 0, mem_stat.st_size, 0, 0, 0))
18 return stat_val
19
20+ def _live_entry(self, path):
21+ stat_val = self._lstat(path)
22+ if stat.S_ISDIR(stat_val.st_mode):
23+ return None
24+ elif stat.S_ISLNK(stat_val.st_mode):
25+ blob = Blob.from_string(self._file_transport.readlink(path))
26+ elif stat.S_ISREG(stat_val.st_mode):
27+ blob = Blob.from_string(self._file_transport.get_bytes(path))
28+ else:
29+ raise AssertionError('unknown type %d' % stat_val.st_mode)
30+ return index_entry_from_stat(stat_val, blob.id, 0)
31+
32 def get_file_with_stat(self, path, file_id=None):
33 return (self.get_file(path, file_id), self._lstat(path))
34
35
36=== modified file 'breezy/plugins/git/tests/test_workingtree.py'
37--- breezy/plugins/git/tests/test_workingtree.py 2018-05-13 22:54:28 +0000
38+++ breezy/plugins/git/tests/test_workingtree.py 2018-05-21 21:08:24 +0000
39@@ -29,9 +29,11 @@
40 )
41
42 from .... import conflicts as _mod_conflicts
43+from ..tree import (
44+ changes_between_git_tree_and_working_copy,
45+ )
46 from ..workingtree import (
47 FLAG_STAGEMASK,
48- changes_between_git_tree_and_working_copy,
49 )
50 from ....tests import TestCaseWithTransport
51
52
53=== modified file 'breezy/plugins/git/tree.py'
54--- breezy/plugins/git/tree.py 2018-05-15 01:20:00 +0000
55+++ breezy/plugins/git/tree.py 2018-05-21 21:08:24 +0000
56@@ -24,6 +24,9 @@
57 import os
58
59 from dulwich.index import (
60+ blob_from_path_and_stat,
61+ cleanup_mode,
62+ commit_tree,
63 index_entry_from_stat,
64 )
65 from dulwich.object_store import (
66@@ -1184,7 +1187,8 @@
67 else:
68 todo = [(p, i) for (p, i) in self._recurse_index_entries() if p.startswith(from_path+'/')]
69 for child_path, child_value in todo:
70- (child_to_index, child_to_index_path) = self._lookup_index(posixpath.join(to_path, posixpath.relpath(child_path, from_path)))
71+ (child_to_index, child_to_index_path) = self._lookup_index(
72+ posixpath.join(to_path, posixpath.relpath(child_path, from_path)))
73 child_to_index[child_to_index_path] = child_value
74 # TODO(jelmer): Mark individual index as dirty
75 self._index_dirty = True
76@@ -1252,3 +1256,86 @@
77 return 'directory'
78 else:
79 return kind
80+
81+ def _live_entry(self, relpath):
82+ raise NotImplementedError(self._live_entry)
83+
84+
85+class InterIndexGitTree(InterGitTrees):
86+ """InterTree that works between a Git revision tree and an index."""
87+
88+ def __init__(self, source, target):
89+ super(InterIndexGitTree, self).__init__(source, target)
90+ self._index = target.index
91+
92+ @classmethod
93+ def is_compatible(cls, source, target):
94+ return (isinstance(source, GitRevisionTree) and
95+ isinstance(target, MutableGitIndexTree))
96+
97+ def _iter_git_changes(self, want_unchanged=False, specific_files=None,
98+ require_versioned=False, extra_trees=None,
99+ want_unversioned=False):
100+ trees = [self.source]
101+ if extra_trees is not None:
102+ trees.extend(extra_trees)
103+ if specific_files is not None:
104+ specific_files = self.target.find_related_paths_across_trees(
105+ specific_files, trees,
106+ require_versioned=require_versioned)
107+ # TODO(jelmer): Restrict to specific_files, for performance reasons.
108+ with self.lock_read():
109+ return changes_between_git_tree_and_working_copy(
110+ self.source.store, self.source.tree,
111+ self.target, want_unchanged=want_unchanged,
112+ want_unversioned=want_unversioned)
113+
114+
115+_mod_tree.InterTree.register_optimiser(InterIndexGitTree)
116+
117+
118+def changes_between_git_tree_and_working_copy(store, from_tree_sha, target,
119+ want_unchanged=False, want_unversioned=False):
120+ """Determine the changes between a git tree and a working tree with index.
121+
122+ """
123+ extras = set()
124+ blobs = {}
125+ # Report dirified directories to commit_tree first, so that they can be
126+ # replaced with non-empty directories if they have contents.
127+ dirified = []
128+ for path, index_entry in target._recurse_index_entries():
129+ try:
130+ live_entry = target._live_entry(path)
131+ except EnvironmentError as e:
132+ if e.errno == errno.ENOENT:
133+ # Entry was removed; keep it listed, but mark it as gone.
134+ blobs[path] = (ZERO_SHA, 0)
135+ elif e.errno == errno.EISDIR:
136+ # Entry was turned into a directory
137+ dirified.append((path, Tree().id, stat.S_IFDIR))
138+ store.add_object(Tree())
139+ else:
140+ raise
141+ else:
142+ blobs[path] = (live_entry.sha, cleanup_mode(live_entry.mode))
143+ if want_unversioned:
144+ for e in target.extras():
145+ st = target._lstat(e)
146+ try:
147+ np, accessible = osutils.normalized_filename(e)
148+ except UnicodeDecodeError:
149+ raise errors.BadFilenameEncoding(
150+ e, osutils._fs_enc)
151+ if stat.S_ISDIR(st.st_mode):
152+ blob = Tree()
153+ else:
154+ blob = blob_from_path_and_stat(target.abspath(e).encode(osutils._fs_enc), st)
155+ store.add_object(blob)
156+ np = np.encode('utf-8')
157+ blobs[np] = (blob.id, cleanup_mode(st.st_mode))
158+ extras.add(np)
159+ to_tree_sha = commit_tree(store, dirified + [(p, s, m) for (p, (s, m)) in blobs.items()])
160+ return store.tree_changes(
161+ from_tree_sha, to_tree_sha, include_trees=True,
162+ want_unchanged=want_unchanged, change_type_same=True), extras
163
164=== modified file 'breezy/plugins/git/workingtree.py'
165--- breezy/plugins/git/workingtree.py 2018-05-13 22:54:28 +0000
166+++ breezy/plugins/git/workingtree.py 2018-05-21 21:08:24 +0000
167@@ -31,12 +31,9 @@
168 SHA1Writer,
169 build_index_from_tree,
170 changes_from_tree,
171- cleanup_mode,
172- commit_tree,
173 index_entry_from_path,
174 index_entry_from_stat,
175 iter_fresh_entries,
176- blob_from_path_and_stat,
177 FLAG_STAGEMASK,
178 read_submodule_head,
179 validate_path,
180@@ -734,6 +731,9 @@
181 def _lstat(self, path):
182 return os.lstat(self.abspath(path))
183
184+ def _live_entry(self, path):
185+ return index_entry_from_path(self.abspath(path.decode('utf-8')).encode(osutils._fs_enc))
186+
187 def is_executable(self, path, file_id=None):
188 with self.lock_read():
189 if getattr(self, "_supports_executable", osutils.supports_executable)():
190@@ -1339,87 +1339,3 @@
191 for hook in MutableTree.hooks['post_build_tree']:
192 hook(wt)
193 return wt
194-
195-
196-class InterIndexGitTree(InterGitTrees):
197- """InterTree that works between a Git revision tree and an index."""
198-
199- def __init__(self, source, target):
200- super(InterIndexGitTree, self).__init__(source, target)
201- self._index = target.index
202-
203- @classmethod
204- def is_compatible(cls, source, target):
205- from .repository import GitRevisionTree
206- return (isinstance(source, GitRevisionTree) and
207- isinstance(target, GitWorkingTree))
208-
209- def _iter_git_changes(self, want_unchanged=False, specific_files=None,
210- require_versioned=False, extra_trees=None,
211- want_unversioned=False):
212- trees = [self.source]
213- if extra_trees is not None:
214- trees.extend(extra_trees)
215- if specific_files is not None:
216- specific_files = self.target.find_related_paths_across_trees(
217- specific_files, trees,
218- require_versioned=require_versioned)
219- # TODO(jelmer): Restrict to specific_files, for performance reasons.
220- with self.lock_read():
221- return changes_between_git_tree_and_working_copy(
222- self.source.store, self.source.tree,
223- self.target, want_unchanged=want_unchanged,
224- want_unversioned=want_unversioned)
225-
226-
227-tree.InterTree.register_optimiser(InterIndexGitTree)
228-
229-
230-def changes_between_git_tree_and_working_copy(store, from_tree_sha, target,
231- want_unchanged=False, want_unversioned=False):
232- """Determine the changes between a git tree and a working tree with index.
233-
234- """
235- extras = set()
236- blobs = {}
237- # Report dirified directories to commit_tree first, so that they can be
238- # replaced with non-empty directories if they have contents.
239- dirified = []
240- target_root_path = target.abspath('.').encode(sys.getfilesystemencoding())
241- for path, index_entry in target._recurse_index_entries():
242- try:
243- live_entry = index_entry_from_path(
244- target.abspath(path.decode('utf-8')).encode(osutils._fs_enc))
245- except EnvironmentError as e:
246- if e.errno == errno.ENOENT:
247- # Entry was removed; keep it listed, but mark it as gone.
248- blobs[path] = (ZERO_SHA, 0)
249- elif e.errno == errno.EISDIR:
250- # Entry was turned into a directory
251- dirified.append((path, Tree().id, stat.S_IFDIR))
252- store.add_object(Tree())
253- else:
254- raise
255- else:
256- blobs[path] = (live_entry.sha, cleanup_mode(live_entry.mode))
257- if want_unversioned:
258- for e in target.extras():
259- ap = target.abspath(e)
260- st = os.lstat(ap)
261- try:
262- np, accessible = osutils.normalized_filename(e)
263- except UnicodeDecodeError:
264- raise errors.BadFilenameEncoding(
265- e, osutils._fs_enc)
266- if stat.S_ISDIR(st.st_mode):
267- blob = Tree()
268- else:
269- blob = blob_from_path_and_stat(ap.encode('utf-8'), st)
270- store.add_object(blob)
271- np = np.encode('utf-8')
272- blobs[np] = (blob.id, cleanup_mode(st.st_mode))
273- extras.add(np)
274- to_tree_sha = commit_tree(store, dirified + [(p, s, m) for (p, (s, m)) in blobs.items()])
275- return store.tree_changes(
276- from_tree_sha, to_tree_sha, include_trees=True,
277- want_unchanged=want_unchanged, change_type_same=True), extras

Subscribers

People subscribed via source and target branches