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
=== modified file 'breezy/plugins/git/memorytree.py'
--- breezy/plugins/git/memorytree.py 2018-03-26 22:28:24 +0000
+++ breezy/plugins/git/memorytree.py 2018-05-21 21:08:24 +0000
@@ -23,7 +23,11 @@
23import posixpath23import posixpath
24import stat24import stat
2525
26from dulwich.index import (
27 index_entry_from_stat,
28 )
26from dulwich.objects import (29from dulwich.objects import (
30 Blob,
27 Tree,31 Tree,
28 )32 )
2933
@@ -171,6 +175,18 @@
171 (mem_stat.st_mode, 0, 0, 0, 0, 0, mem_stat.st_size, 0, 0, 0))175 (mem_stat.st_mode, 0, 0, 0, 0, 0, mem_stat.st_size, 0, 0, 0))
172 return stat_val176 return stat_val
173177
178 def _live_entry(self, path):
179 stat_val = self._lstat(path)
180 if stat.S_ISDIR(stat_val.st_mode):
181 return None
182 elif stat.S_ISLNK(stat_val.st_mode):
183 blob = Blob.from_string(self._file_transport.readlink(path))
184 elif stat.S_ISREG(stat_val.st_mode):
185 blob = Blob.from_string(self._file_transport.get_bytes(path))
186 else:
187 raise AssertionError('unknown type %d' % stat_val.st_mode)
188 return index_entry_from_stat(stat_val, blob.id, 0)
189
174 def get_file_with_stat(self, path, file_id=None):190 def get_file_with_stat(self, path, file_id=None):
175 return (self.get_file(path, file_id), self._lstat(path))191 return (self.get_file(path, file_id), self._lstat(path))
176192
177193
=== modified file 'breezy/plugins/git/tests/test_workingtree.py'
--- breezy/plugins/git/tests/test_workingtree.py 2018-05-13 22:54:28 +0000
+++ breezy/plugins/git/tests/test_workingtree.py 2018-05-21 21:08:24 +0000
@@ -29,9 +29,11 @@
29 )29 )
3030
31from .... import conflicts as _mod_conflicts31from .... import conflicts as _mod_conflicts
32from ..tree import (
33 changes_between_git_tree_and_working_copy,
34 )
32from ..workingtree import (35from ..workingtree import (
33 FLAG_STAGEMASK,36 FLAG_STAGEMASK,
34 changes_between_git_tree_and_working_copy,
35 )37 )
36from ....tests import TestCaseWithTransport38from ....tests import TestCaseWithTransport
3739
3840
=== modified file 'breezy/plugins/git/tree.py'
--- breezy/plugins/git/tree.py 2018-05-15 01:20:00 +0000
+++ breezy/plugins/git/tree.py 2018-05-21 21:08:24 +0000
@@ -24,6 +24,9 @@
24import os24import os
2525
26from dulwich.index import (26from dulwich.index import (
27 blob_from_path_and_stat,
28 cleanup_mode,
29 commit_tree,
27 index_entry_from_stat,30 index_entry_from_stat,
28 )31 )
29from dulwich.object_store import (32from dulwich.object_store import (
@@ -1184,7 +1187,8 @@
1184 else:1187 else:
1185 todo = [(p, i) for (p, i) in self._recurse_index_entries() if p.startswith(from_path+'/')]1188 todo = [(p, i) for (p, i) in self._recurse_index_entries() if p.startswith(from_path+'/')]
1186 for child_path, child_value in todo:1189 for child_path, child_value in todo:
1187 (child_to_index, child_to_index_path) = self._lookup_index(posixpath.join(to_path, posixpath.relpath(child_path, from_path)))1190 (child_to_index, child_to_index_path) = self._lookup_index(
1191 posixpath.join(to_path, posixpath.relpath(child_path, from_path)))
1188 child_to_index[child_to_index_path] = child_value1192 child_to_index[child_to_index_path] = child_value
1189 # TODO(jelmer): Mark individual index as dirty1193 # TODO(jelmer): Mark individual index as dirty
1190 self._index_dirty = True1194 self._index_dirty = True
@@ -1252,3 +1256,86 @@
1252 return 'directory'1256 return 'directory'
1253 else:1257 else:
1254 return kind1258 return kind
1259
1260 def _live_entry(self, relpath):
1261 raise NotImplementedError(self._live_entry)
1262
1263
1264class InterIndexGitTree(InterGitTrees):
1265 """InterTree that works between a Git revision tree and an index."""
1266
1267 def __init__(self, source, target):
1268 super(InterIndexGitTree, self).__init__(source, target)
1269 self._index = target.index
1270
1271 @classmethod
1272 def is_compatible(cls, source, target):
1273 return (isinstance(source, GitRevisionTree) and
1274 isinstance(target, MutableGitIndexTree))
1275
1276 def _iter_git_changes(self, want_unchanged=False, specific_files=None,
1277 require_versioned=False, extra_trees=None,
1278 want_unversioned=False):
1279 trees = [self.source]
1280 if extra_trees is not None:
1281 trees.extend(extra_trees)
1282 if specific_files is not None:
1283 specific_files = self.target.find_related_paths_across_trees(
1284 specific_files, trees,
1285 require_versioned=require_versioned)
1286 # TODO(jelmer): Restrict to specific_files, for performance reasons.
1287 with self.lock_read():
1288 return changes_between_git_tree_and_working_copy(
1289 self.source.store, self.source.tree,
1290 self.target, want_unchanged=want_unchanged,
1291 want_unversioned=want_unversioned)
1292
1293
1294_mod_tree.InterTree.register_optimiser(InterIndexGitTree)
1295
1296
1297def changes_between_git_tree_and_working_copy(store, from_tree_sha, target,
1298 want_unchanged=False, want_unversioned=False):
1299 """Determine the changes between a git tree and a working tree with index.
1300
1301 """
1302 extras = set()
1303 blobs = {}
1304 # Report dirified directories to commit_tree first, so that they can be
1305 # replaced with non-empty directories if they have contents.
1306 dirified = []
1307 for path, index_entry in target._recurse_index_entries():
1308 try:
1309 live_entry = target._live_entry(path)
1310 except EnvironmentError as e:
1311 if e.errno == errno.ENOENT:
1312 # Entry was removed; keep it listed, but mark it as gone.
1313 blobs[path] = (ZERO_SHA, 0)
1314 elif e.errno == errno.EISDIR:
1315 # Entry was turned into a directory
1316 dirified.append((path, Tree().id, stat.S_IFDIR))
1317 store.add_object(Tree())
1318 else:
1319 raise
1320 else:
1321 blobs[path] = (live_entry.sha, cleanup_mode(live_entry.mode))
1322 if want_unversioned:
1323 for e in target.extras():
1324 st = target._lstat(e)
1325 try:
1326 np, accessible = osutils.normalized_filename(e)
1327 except UnicodeDecodeError:
1328 raise errors.BadFilenameEncoding(
1329 e, osutils._fs_enc)
1330 if stat.S_ISDIR(st.st_mode):
1331 blob = Tree()
1332 else:
1333 blob = blob_from_path_and_stat(target.abspath(e).encode(osutils._fs_enc), st)
1334 store.add_object(blob)
1335 np = np.encode('utf-8')
1336 blobs[np] = (blob.id, cleanup_mode(st.st_mode))
1337 extras.add(np)
1338 to_tree_sha = commit_tree(store, dirified + [(p, s, m) for (p, (s, m)) in blobs.items()])
1339 return store.tree_changes(
1340 from_tree_sha, to_tree_sha, include_trees=True,
1341 want_unchanged=want_unchanged, change_type_same=True), extras
12551342
=== modified file 'breezy/plugins/git/workingtree.py'
--- breezy/plugins/git/workingtree.py 2018-05-13 22:54:28 +0000
+++ breezy/plugins/git/workingtree.py 2018-05-21 21:08:24 +0000
@@ -31,12 +31,9 @@
31 SHA1Writer,31 SHA1Writer,
32 build_index_from_tree,32 build_index_from_tree,
33 changes_from_tree,33 changes_from_tree,
34 cleanup_mode,
35 commit_tree,
36 index_entry_from_path,34 index_entry_from_path,
37 index_entry_from_stat,35 index_entry_from_stat,
38 iter_fresh_entries,36 iter_fresh_entries,
39 blob_from_path_and_stat,
40 FLAG_STAGEMASK,37 FLAG_STAGEMASK,
41 read_submodule_head,38 read_submodule_head,
42 validate_path,39 validate_path,
@@ -734,6 +731,9 @@
734 def _lstat(self, path):731 def _lstat(self, path):
735 return os.lstat(self.abspath(path))732 return os.lstat(self.abspath(path))
736733
734 def _live_entry(self, path):
735 return index_entry_from_path(self.abspath(path.decode('utf-8')).encode(osutils._fs_enc))
736
737 def is_executable(self, path, file_id=None):737 def is_executable(self, path, file_id=None):
738 with self.lock_read():738 with self.lock_read():
739 if getattr(self, "_supports_executable", osutils.supports_executable)():739 if getattr(self, "_supports_executable", osutils.supports_executable)():
@@ -1339,87 +1339,3 @@
1339 for hook in MutableTree.hooks['post_build_tree']:1339 for hook in MutableTree.hooks['post_build_tree']:
1340 hook(wt)1340 hook(wt)
1341 return wt1341 return wt
1342
1343
1344class InterIndexGitTree(InterGitTrees):
1345 """InterTree that works between a Git revision tree and an index."""
1346
1347 def __init__(self, source, target):
1348 super(InterIndexGitTree, self).__init__(source, target)
1349 self._index = target.index
1350
1351 @classmethod
1352 def is_compatible(cls, source, target):
1353 from .repository import GitRevisionTree
1354 return (isinstance(source, GitRevisionTree) and
1355 isinstance(target, GitWorkingTree))
1356
1357 def _iter_git_changes(self, want_unchanged=False, specific_files=None,
1358 require_versioned=False, extra_trees=None,
1359 want_unversioned=False):
1360 trees = [self.source]
1361 if extra_trees is not None:
1362 trees.extend(extra_trees)
1363 if specific_files is not None:
1364 specific_files = self.target.find_related_paths_across_trees(
1365 specific_files, trees,
1366 require_versioned=require_versioned)
1367 # TODO(jelmer): Restrict to specific_files, for performance reasons.
1368 with self.lock_read():
1369 return changes_between_git_tree_and_working_copy(
1370 self.source.store, self.source.tree,
1371 self.target, want_unchanged=want_unchanged,
1372 want_unversioned=want_unversioned)
1373
1374
1375tree.InterTree.register_optimiser(InterIndexGitTree)
1376
1377
1378def changes_between_git_tree_and_working_copy(store, from_tree_sha, target,
1379 want_unchanged=False, want_unversioned=False):
1380 """Determine the changes between a git tree and a working tree with index.
1381
1382 """
1383 extras = set()
1384 blobs = {}
1385 # Report dirified directories to commit_tree first, so that they can be
1386 # replaced with non-empty directories if they have contents.
1387 dirified = []
1388 target_root_path = target.abspath('.').encode(sys.getfilesystemencoding())
1389 for path, index_entry in target._recurse_index_entries():
1390 try:
1391 live_entry = index_entry_from_path(
1392 target.abspath(path.decode('utf-8')).encode(osutils._fs_enc))
1393 except EnvironmentError as e:
1394 if e.errno == errno.ENOENT:
1395 # Entry was removed; keep it listed, but mark it as gone.
1396 blobs[path] = (ZERO_SHA, 0)
1397 elif e.errno == errno.EISDIR:
1398 # Entry was turned into a directory
1399 dirified.append((path, Tree().id, stat.S_IFDIR))
1400 store.add_object(Tree())
1401 else:
1402 raise
1403 else:
1404 blobs[path] = (live_entry.sha, cleanup_mode(live_entry.mode))
1405 if want_unversioned:
1406 for e in target.extras():
1407 ap = target.abspath(e)
1408 st = os.lstat(ap)
1409 try:
1410 np, accessible = osutils.normalized_filename(e)
1411 except UnicodeDecodeError:
1412 raise errors.BadFilenameEncoding(
1413 e, osutils._fs_enc)
1414 if stat.S_ISDIR(st.st_mode):
1415 blob = Tree()
1416 else:
1417 blob = blob_from_path_and_stat(ap.encode('utf-8'), st)
1418 store.add_object(blob)
1419 np = np.encode('utf-8')
1420 blobs[np] = (blob.id, cleanup_mode(st.st_mode))
1421 extras.add(np)
1422 to_tree_sha = commit_tree(store, dirified + [(p, s, m) for (p, (s, m)) in blobs.items()])
1423 return store.tree_changes(
1424 from_tree_sha, to_tree_sha, include_trees=True,
1425 want_unchanged=want_unchanged, change_type_same=True), extras

Subscribers

People subscribed via source and target branches