... |
... |
@@ -40,6 +40,8 @@ from ._filebaseddirectory import FileBasedDirectory |
40
|
40
|
from ..utils import FileListResult, safe_copy, list_relative_paths, _relative_symlink_target
|
41
|
41
|
from .._artifactcache.cascache import CASCache
|
42
|
42
|
|
|
43
|
+import copy # Temporary
|
|
44
|
+import operator
|
43
|
45
|
|
44
|
46
|
class IndexEntry():
|
45
|
47
|
""" Used in our index of names to objects to store the 'modified' flag
|
... |
... |
@@ -84,7 +86,9 @@ class CasBasedDirectory(Directory): |
84
|
86
|
if ref:
|
85
|
87
|
with open(self.cas_cache.objpath(ref), 'rb') as f:
|
86
|
88
|
self.pb2_directory.ParseFromString(f.read())
|
87
|
|
-
|
|
89
|
+ print("Opening ref {} and parsed into directory containing: {} {} {}.".format(ref.hash, [d.name for d in self.pb2_directory.directories],
|
|
90
|
+ [d.name for d in self.pb2_directory.symlinks],
|
|
91
|
+ [d.name for d in self.pb2_directory.files]))
|
88
|
92
|
self.ref = ref
|
89
|
93
|
self.index = OrderedDict()
|
90
|
94
|
self.parent = parent
|
... |
... |
@@ -161,13 +165,13 @@ class CasBasedDirectory(Directory): |
161
|
165
|
existing_item = self._find_pb2_entry(name)
|
162
|
166
|
if isinstance(existing_item, remote_execution_pb2.FileNode):
|
163
|
167
|
# Directory imported over file with same name
|
164
|
|
- self.remove_item(name)
|
|
168
|
+ self.delete_entry(name)
|
165
|
169
|
elif isinstance(existing_item, remote_execution_pb2.SymlinkNode):
|
166
|
170
|
# Directory imported over symlink with same source name
|
167
|
171
|
if self.symlink_target_is_directory(existing_item):
|
168
|
172
|
return self._resolve_symlink_or_directory(name) # That's fine; any files in the source directory should end up at the target of the symlink.
|
169
|
173
|
else:
|
170
|
|
- self.remove_item(name) # Symlinks to files get replaced
|
|
174
|
+ self.delete_entry(name) # Symlinks to files get replaced
|
171
|
175
|
return self.descend(name, create=True) # Creates the directory if it doesn't already exist.
|
172
|
176
|
|
173
|
177
|
|
... |
... |
@@ -223,11 +227,27 @@ class CasBasedDirectory(Directory): |
223
|
227
|
symlinknode.target = os.readlink(os.path.join(basename, filename))
|
224
|
228
|
self.index[filename] = IndexEntry(symlinknode, modified=(existing_link is not None))
|
225
|
229
|
|
|
230
|
+ def _add_new_link_direct(self, name, target):
|
|
231
|
+ existing_link = self._find_pb2_entry(name)
|
|
232
|
+ if existing_link:
|
|
233
|
+ symlinknode = existing_link
|
|
234
|
+ else:
|
|
235
|
+ symlinknode = self.pb2_directory.symlinks.add()
|
|
236
|
+ assert(isinstance(symlinknode, remote_execution_pb2.SymlinkNode))
|
|
237
|
+ symlinknode.name = name
|
|
238
|
+ # A symlink node has no digest.
|
|
239
|
+ symlinknode.target = target
|
|
240
|
+ self.index[name] = IndexEntry(symlinknode, modified=(existing_link is not None))
|
|
241
|
+
|
|
242
|
+
|
226
|
243
|
def delete_entry(self, name):
|
227
|
244
|
for collection in [self.pb2_directory.files, self.pb2_directory.symlinks, self.pb2_directory.directories]:
|
228
|
|
- if name in collection:
|
229
|
|
- collection.remove(name)
|
|
245
|
+ for thing in collection:
|
|
246
|
+ if thing.name == name:
|
|
247
|
+ print("Removing {} from PB2".format(name))
|
|
248
|
+ collection.remove(thing)
|
230
|
249
|
if name in self.index:
|
|
250
|
+ print("Removing {} from index".format(name))
|
231
|
251
|
del self.index[name]
|
232
|
252
|
|
233
|
253
|
def descend(self, subdirectory_spec, create=False):
|
... |
... |
@@ -268,9 +288,12 @@ class CasBasedDirectory(Directory): |
268
|
288
|
return entry.descend(subdirectory_spec[1:], create)
|
269
|
289
|
else:
|
270
|
290
|
# May be a symlink
|
|
291
|
+ target = self._resolve(subdirectory_spec[0])
|
|
292
|
+ if isinstance(target, CasBasedDirectory):
|
|
293
|
+ return target
|
271
|
294
|
error = "Cannot descend into {}, which is a '{}' in the directory {}"
|
272
|
295
|
raise VirtualDirectoryError(error.format(subdirectory_spec[0],
|
273
|
|
- type(entry).__name__,
|
|
296
|
+ type(self.index[subdirectory_spec[0]].pb_object).__name__,
|
274
|
297
|
self))
|
275
|
298
|
else:
|
276
|
299
|
if create:
|
... |
... |
@@ -308,6 +331,7 @@ class CasBasedDirectory(Directory): |
308
|
331
|
return self.index[name].buildstream_object
|
309
|
332
|
# OK then, it's a symlink
|
310
|
333
|
symlink = self._find_pb2_entry(name)
|
|
334
|
+ assert isinstance(symlink, remote_execution_pb2.SymlinkNode)
|
311
|
335
|
absolute = symlink.target.startswith(CasBasedDirectory._pb2_absolute_path_prefix)
|
312
|
336
|
if absolute:
|
313
|
337
|
root = self.find_root()
|
... |
... |
@@ -324,6 +348,16 @@ class CasBasedDirectory(Directory): |
324
|
348
|
directory = directory.descend(c, create=True)
|
325
|
349
|
return directory
|
326
|
350
|
|
|
351
|
+ def _is_followable(self, name):
|
|
352
|
+ """ Returns true if this is a directory or symlink to a valid directory. """
|
|
353
|
+ if name not in self.index:
|
|
354
|
+ return False
|
|
355
|
+ if isinstance(self.index[name].buildstream_object, Directory):
|
|
356
|
+ return True
|
|
357
|
+ target = self._resolve(name)
|
|
358
|
+ print("Is {} followable? Resolved to {}".format(name, target))
|
|
359
|
+ return isinstance(target, CasBasedDirectory) or target is None
|
|
360
|
+
|
327
|
361
|
def _resolve_symlink(self, node):
|
328
|
362
|
"""Same as _resolve_symlink_or_directory but takes a SymlinkNode.
|
329
|
363
|
"""
|
... |
... |
@@ -348,8 +382,13 @@ class CasBasedDirectory(Directory): |
348
|
382
|
|
349
|
383
|
|
350
|
384
|
def _resolve(self, name, absolute_symlinks_resolve=True):
|
351
|
|
- """ Resolves any name to an object. If the name points to a symlink in this
|
352
|
|
- directory, it returns the thing it points to, recursively. Returns a CasBasedDirectory, FileNode or None. Never creates a directory or otherwise alters the directory. """
|
|
385
|
+ """ Resolves any name to an object. If the name points to a symlink in
|
|
386
|
+ this directory, it returns the thing it points to,
|
|
387
|
+ recursively. Returns a CasBasedDirectory, FileNode or
|
|
388
|
+ None. Never creates a directory or otherwise alters the
|
|
389
|
+ directory.
|
|
390
|
+
|
|
391
|
+ """
|
353
|
392
|
# First check if it's a normal object and return that
|
354
|
393
|
|
355
|
394
|
if name not in self.index:
|
... |
... |
@@ -408,7 +447,7 @@ class CasBasedDirectory(Directory): |
408
|
447
|
else:
|
409
|
448
|
return f
|
410
|
449
|
else:
|
411
|
|
- print(" resolving {}: nonexistent!".format(c))
|
|
450
|
+ print(" resolving {}: Broken symlink".format(c))
|
412
|
451
|
return None
|
413
|
452
|
|
414
|
453
|
# Shouldn't get here.
|
... |
... |
@@ -426,17 +465,21 @@ class CasBasedDirectory(Directory): |
426
|
465
|
return True
|
427
|
466
|
if (isinstance(existing_entry,
|
428
|
467
|
(remote_execution_pb2.FileNode, remote_execution_pb2.SymlinkNode))):
|
|
468
|
+ self.delete_entry(name)
|
|
469
|
+ print("Processing overwrite of file/symlink {}: Added to overwritten list and deleted".format(name))
|
429
|
470
|
fileListResult.overwritten.append(relative_pathname)
|
430
|
471
|
return True
|
431
|
472
|
elif isinstance(existing_entry, remote_execution_pb2.DirectoryNode):
|
432
|
473
|
# If 'name' maps to a DirectoryNode, then there must be an entry in index
|
433
|
474
|
# pointing to another Directory.
|
434
|
475
|
if self.index[name].buildstream_object.is_empty():
|
|
476
|
+ print("Processing overwrite of directory: Removing original")
|
435
|
477
|
self.delete_entry(name)
|
436
|
478
|
fileListResult.overwritten.append(relative_pathname)
|
437
|
479
|
return True
|
438
|
480
|
else:
|
439
|
481
|
# We can't overwrite a non-empty directory, so we just ignore it.
|
|
482
|
+ print("Processing overwrite of non-empty directory: Ignoring overwrite")
|
440
|
483
|
fileListResult.ignored.append(relative_pathname)
|
441
|
484
|
return False
|
442
|
485
|
assert False, ("Entry '{}' is not a recognised file/link/directory and not None; it is {}"
|
... |
... |
@@ -447,7 +490,13 @@ class CasBasedDirectory(Directory): |
447
|
490
|
""" _import_directory_recursively and _import_files_from_directory will be called alternately
|
448
|
491
|
as a directory tree is descended. """
|
449
|
492
|
if directory_name in self.index:
|
450
|
|
- subdir = self._resolve_symlink_or_directory(directory_name)
|
|
493
|
+ if self._is_followable(directory_name):
|
|
494
|
+ subdir = self._resolve_symlink_or_directory(directory_name)
|
|
495
|
+ else:
|
|
496
|
+ print("Overwriting unfollowable thing {}".format(directory_name))
|
|
497
|
+ self.delete_entry(directory_name)
|
|
498
|
+ subdir = self._add_directory(directory_name)
|
|
499
|
+ # TODO: Add this to the list of overwritten things.
|
451
|
500
|
else:
|
452
|
501
|
subdir = self._add_directory(directory_name)
|
453
|
502
|
new_path_prefix = os.path.join(path_prefix, directory_name)
|
... |
... |
@@ -459,7 +508,10 @@ class CasBasedDirectory(Directory): |
459
|
508
|
def _import_files_from_directory(self, source_directory, files, path_prefix=""):
|
460
|
509
|
""" Imports files from a traditional directory """
|
461
|
510
|
result = FileListResult()
|
462
|
|
- for entry in sorted(files):
|
|
511
|
+ for entry in files:
|
|
512
|
+ print("Importing {} from file system".format(entry))
|
|
513
|
+ print("...Order of elements was {}".format(", ".join(self.index.keys())))
|
|
514
|
+
|
463
|
515
|
split_path = entry.split(os.path.sep)
|
464
|
516
|
# The actual file on the FS we're importing
|
465
|
517
|
import_file = os.path.join(source_directory, entry)
|
... |
... |
@@ -484,6 +536,8 @@ class CasBasedDirectory(Directory): |
484
|
536
|
if self._check_replacement(entry, path_prefix, result):
|
485
|
537
|
self._add_new_file(source_directory, entry)
|
486
|
538
|
result.files_written.append(relative_pathname)
|
|
539
|
+ print("...Order of elements is now {}".format(", ".join(self.index.keys())))
|
|
540
|
+
|
487
|
541
|
return result
|
488
|
542
|
|
489
|
543
|
|
... |
... |
@@ -540,6 +594,17 @@ class CasBasedDirectory(Directory): |
540
|
594
|
x = self._resolve_symlink(symlink_node)
|
541
|
595
|
return isinstance(x, CasBasedDirectory)
|
542
|
596
|
|
|
597
|
+ def _verify_unique(self):
|
|
598
|
+ # Verifies that there are no duplicate names in this directory or subdirectories.
|
|
599
|
+ names = []
|
|
600
|
+ for entrylist in [self.pb2_directory.files, self.pb2_directory.directories, self.pb2_directory.symlinks]:
|
|
601
|
+ for e in entrylist:
|
|
602
|
+ if e.name in names:
|
|
603
|
+ raise VirtualDirectoryError("Duplicate entry for name {} found".format(e.name))
|
|
604
|
+ names.append(e.name)
|
|
605
|
+ for d in self.pb2_directory.directories:
|
|
606
|
+ self.index[d.name].buildstream_object._verify_unique()
|
|
607
|
+
|
543
|
608
|
def _partial_import_cas_into_cas(self, source_directory, files, path_prefix="", file_list_required=True):
|
544
|
609
|
""" Import only the files and symlinks listed in 'files' from source_directory to this one.
|
545
|
610
|
Args:
|
... |
... |
@@ -548,11 +613,11 @@ class CasBasedDirectory(Directory): |
548
|
613
|
path_prefix (str): Prefix used to add entries to the file list result.
|
549
|
614
|
file_list_required: Whether to update the file list while processing.
|
550
|
615
|
"""
|
551
|
|
- print("Beginning partial import of {} into {}".format(source_directory, self))
|
|
616
|
+ print("Beginning partial import of {} into {}. Files are: >{}<".format(source_directory, self, ", ".join(files)))
|
552
|
617
|
result = FileListResult()
|
553
|
618
|
processed_directories = set()
|
554
|
619
|
for f in files:
|
555
|
|
- if f == ".": continue
|
|
620
|
+ #if f == ".": continue
|
556
|
621
|
fullname = os.path.join(path_prefix, f)
|
557
|
622
|
components = f.split(os.path.sep)
|
558
|
623
|
if len(components)>1:
|
... |
... |
@@ -562,6 +627,12 @@ class CasBasedDirectory(Directory): |
562
|
627
|
if dirname not in processed_directories:
|
563
|
628
|
# Now strip off the first directory name and import files recursively.
|
564
|
629
|
subcomponents = CasBasedDirectory.files_in_subdir(files, dirname)
|
|
630
|
+ # We will fail at this point if there is a file or symlink to file called 'dirname'.
|
|
631
|
+ if dirname in self.index:
|
|
632
|
+ x = self._resolve(dirname)
|
|
633
|
+ if isinstance(x, remote_execution_pb2.FileNode):
|
|
634
|
+ self.delete_entry(dirname)
|
|
635
|
+ result.overwritten.append(f)
|
565
|
636
|
self.create_directory(dirname)
|
566
|
637
|
print("Creating destination in {}: {}".format(self, dirname))
|
567
|
638
|
dest_subdir = self._resolve_symlink_or_directory(dirname)
|
... |
... |
@@ -576,17 +647,24 @@ class CasBasedDirectory(Directory): |
576
|
647
|
self.create_directory(f)
|
577
|
648
|
else:
|
578
|
649
|
# We're importing a file or symlink - replace anything with the same name.
|
579
|
|
- self._check_replacement(f, path_prefix, result)
|
580
|
|
- item = source_directory.index[f].pb_object
|
581
|
|
- if isinstance(item, remote_execution_pb2.FileNode):
|
582
|
|
- filenode = self.pb2_directory.files.add(digest=item.digest, name=f,
|
583
|
|
- is_executable=item.is_executable)
|
584
|
|
- self.index[f] = IndexEntry(filenode, modified=(fullname in result.overwritten))
|
585
|
|
- else:
|
586
|
|
- assert(isinstance(item, remote_execution_pb2.SymlinkNode))
|
587
|
|
- symlinknode = self.pb2_directory.symlinks.add(name=f, target=item.target)
|
588
|
|
- # A symlink node has no digest.
|
589
|
|
- self.index[f] = IndexEntry(symlinknode, modified=(fullname in result.overwritten))
|
|
650
|
+ print("Import of file/symlink {} into this directory. Removing anything existing...".format(f))
|
|
651
|
+ print(" ... ordering of nodes in this dir was: {}".format(self.index.keys()))
|
|
652
|
+ print(" ... symlinks were {}".format([x.name for x in self.pb2_directory.symlinks]))
|
|
653
|
+ importable = self._check_replacement(f, path_prefix, result)
|
|
654
|
+ if importable:
|
|
655
|
+ print(" ... after replacement of '{}', symlinks are now {}".format(f, [x.name for x in self.pb2_directory.symlinks]))
|
|
656
|
+ item = source_directory.index[f].pb_object
|
|
657
|
+ if isinstance(item, remote_execution_pb2.FileNode):
|
|
658
|
+ print(" ... importing file")
|
|
659
|
+ filenode = self.pb2_directory.files.add(digest=item.digest, name=f,
|
|
660
|
+ is_executable=item.is_executable)
|
|
661
|
+ self.index[f] = IndexEntry(filenode, modified=(fullname in result.overwritten))
|
|
662
|
+ else:
|
|
663
|
+ print(" ... importing symlink")
|
|
664
|
+ assert(isinstance(item, remote_execution_pb2.SymlinkNode))
|
|
665
|
+ self._add_new_link_direct(name=f, target=item.target)
|
|
666
|
+ print(" ... symlinks are now {}".format([x.name for x in self.pb2_directory.symlinks]))
|
|
667
|
+ print(" ... ordering of nodes in this dir is now: {}".format(self.index.keys()))
|
590
|
668
|
return result
|
591
|
669
|
|
592
|
670
|
def transfer_node_contents(destination, source):
|
... |
... |
@@ -632,11 +710,69 @@ class CasBasedDirectory(Directory): |
632
|
710
|
"""
|
633
|
711
|
if files is None:
|
634
|
712
|
#return self._full_import_cas_into_cas(source_directory, can_hardlink=True)
|
635
|
|
- files = source_directory.list_relative_paths()
|
|
713
|
+ files = list(source_directory.list_relative_paths())
|
636
|
714
|
print("Extracted all files from source directory '{}': {}".format(source_directory, files))
|
637
|
|
- return self._partial_import_cas_into_cas(source_directory, files)
|
638
|
|
-
|
|
715
|
+ return self._partial_import_cas_into_cas(source_directory, list(files))
|
|
716
|
+
|
|
717
|
+ def _describe(self, thing):
|
|
718
|
+ # Describes protocol buffer objects
|
|
719
|
+ if isinstance(thing, remote_execution_pb2.DirectoryNode):
|
|
720
|
+ return "directory called {}".format(thing.name)
|
|
721
|
+ elif isinstance(thing, remote_execution_pb2.SymlinkNode):
|
|
722
|
+ return "symlink called {} pointing to {}".format(thing.name, thing.target)
|
|
723
|
+ elif isinstance(thing, remote_execution_pb2.FileNode):
|
|
724
|
+ return "file called {}".format(thing.name)
|
|
725
|
+ else:
|
|
726
|
+ return "strange thing"
|
|
727
|
+
|
|
728
|
+
|
|
729
|
+ def showdiff(self, other):
|
|
730
|
+ print("Diffing {} and {}:".format(self, other))
|
|
731
|
+
|
|
732
|
+ def compare_list(l1, l2):
|
|
733
|
+ item2 = None
|
|
734
|
+ index = 0
|
|
735
|
+ print("Comparing lists: {} vs {}".format([d.name for d in l1], [d.name for d in l2]))
|
|
736
|
+ for item1 in l1:
|
|
737
|
+ if index>=len(l2):
|
|
738
|
+ print("l2 is short: no item to correspond to '{}' in l1.".format(item1.name))
|
|
739
|
+ return False
|
|
740
|
+ item2 = l2[index]
|
|
741
|
+ if item1.name != item2.name:
|
|
742
|
+ print("Items do not match: {}, a {} in l1, vs {}, a {} in l2".format(item1.name, self._describe(item1), item2.name, self._describe(item2)))
|
|
743
|
+ return False
|
|
744
|
+ index += 1
|
|
745
|
+ if index != len(l2):
|
|
746
|
+ print("l2 is long: Has extra items {}".format(l2[index:]))
|
|
747
|
+ return False
|
|
748
|
+ return True
|
639
|
749
|
|
|
750
|
+ def compare_pb2_directories(d1, d2):
|
|
751
|
+ result = (compare_list(d1.directories, d2.directories)
|
|
752
|
+ and compare_list(d1.symlinks, d2.symlinks)
|
|
753
|
+ and compare_list(d1.files, d2.files))
|
|
754
|
+ return result
|
|
755
|
+
|
|
756
|
+ if not compare_pb2_directories(self.pb2_directory, other.pb2_directory):
|
|
757
|
+ return False
|
|
758
|
+
|
|
759
|
+ for d in self.pb2_directory.directories:
|
|
760
|
+ self.index[d.name].buildstream_object.showdiff(other.index[d.name].buildstream_object)
|
|
761
|
+ print("No differences found in {}".format(self))
|
|
762
|
+
|
|
763
|
+ def show_files_recursive(self):
|
|
764
|
+ elems = []
|
|
765
|
+ for (k,v) in self.index.items():
|
|
766
|
+ if type(v.pb_object) == remote_execution_pb2.DirectoryNode:
|
|
767
|
+ elems.append("{}=[{}]".format(k, v.buildstream_object.show_files_recursive()))
|
|
768
|
+ elif type(v.pb_object) == remote_execution_pb2.SymlinkNode:
|
|
769
|
+ elems.append("{}(s)".format(k))
|
|
770
|
+ elif type(v.pb_object) == remote_execution_pb2.FileNode:
|
|
771
|
+ elems.append("{}(f)".format(k))
|
|
772
|
+ else:
|
|
773
|
+ elems.append("{}(?)".format(k))
|
|
774
|
+ return " ".join(elems)
|
|
775
|
+
|
640
|
776
|
def import_files(self, external_pathspec, *, files=None,
|
641
|
777
|
report_written=True, update_utimes=False,
|
642
|
778
|
can_link=False):
|
... |
... |
@@ -659,12 +795,30 @@ class CasBasedDirectory(Directory): |
659
|
795
|
can_link (bool): Ignored, since hard links do not have any meaning within CAS.
|
660
|
796
|
"""
|
661
|
797
|
|
|
798
|
+ print("Directory before import: {}".format(self.show_files_recursive()))
|
|
799
|
+
|
|
800
|
+ # Sync self
|
|
801
|
+ self._recalculate_recursing_down()
|
|
802
|
+ if self.parent:
|
|
803
|
+ self.parent._recalculate_recursing_up(self)
|
|
804
|
+
|
|
805
|
+ # Duplicate the current directory
|
|
806
|
+
|
|
807
|
+
|
|
808
|
+ print("Original CAS before CAS-based import: {}".format(self.show_files_recursive()))
|
|
809
|
+ print("Original CAS hash: {}".format(self.ref.hash))
|
662
|
810
|
duplicate_cas = None
|
|
811
|
+ self._verify_unique()
|
663
|
812
|
if isinstance(external_pathspec, CasBasedDirectory):
|
|
813
|
+ duplicate_cas = CasBasedDirectory(self.context, ref=copy.copy(self.ref))
|
|
814
|
+ duplicate_cas._verify_unique()
|
|
815
|
+ print("-"*80 + "Performing direct CAS-to-CAS import")
|
|
816
|
+ print("Duplicated CAS before file-based import: {}".format(duplicate_cas.show_files_recursive()))
|
|
817
|
+ print("Duplicate CAS hash: {}".format(duplicate_cas.ref.hash))
|
664
|
818
|
result = self._import_cas_into_cas(external_pathspec, files=files)
|
665
|
|
-
|
666
|
|
- # Duplicate the current directory and do an import that way.
|
667
|
|
- duplicate_cas = CasBasedDirectory(self.context, ref=self.ref)
|
|
819
|
+ self._verify_unique()
|
|
820
|
+ print("Result of cas-to-cas import: {}".format(self.show_files_recursive()))
|
|
821
|
+ print("-"*80 + "Performing round-trip import via file system")
|
668
|
822
|
with tempfile.TemporaryDirectory(prefix="roundtrip") as tmpdir:
|
669
|
823
|
external_pathspec.export_files(tmpdir)
|
670
|
824
|
if files is None:
|
... |
... |
@@ -672,8 +826,12 @@ class CasBasedDirectory(Directory): |
672
|
826
|
duplicate_cas._import_files_from_directory(tmpdir, files=files)
|
673
|
827
|
duplicate_cas._recalculate_recursing_down()
|
674
|
828
|
if duplicate_cas.parent:
|
675
|
|
- duplicate_cas.parent._recalculate_recursing_up(self)
|
|
829
|
+ duplicate_cas.parent._recalculate_recursing_up(duplicate_cas)
|
|
830
|
+ print("Result of direct import: {}".format(duplicate_cas.show_files_recursive()))
|
|
831
|
+
|
|
832
|
+
|
676
|
833
|
else:
|
|
834
|
+ print("-"*80 + "Performing initial import")
|
677
|
835
|
if isinstance(external_pathspec, FileBasedDirectory):
|
678
|
836
|
source_directory = external_pathspec.get_underlying_directory()
|
679
|
837
|
else:
|
... |
... |
@@ -697,6 +855,7 @@ class CasBasedDirectory(Directory): |
697
|
855
|
self.parent._recalculate_recursing_up(self)
|
698
|
856
|
if duplicate_cas:
|
699
|
857
|
if duplicate_cas.ref.hash != self.ref.hash:
|
|
858
|
+ self.showdiff(duplicate_cas)
|
700
|
859
|
raise VirtualDirectoryError("Mismatch between file-imported result {} and cas-to-cas imported result {}.".format(duplicate_cas.ref.hash,self.ref.hash))
|
701
|
860
|
|
702
|
861
|
return result
|
... |
... |
@@ -757,6 +916,7 @@ class CasBasedDirectory(Directory): |
757
|
916
|
for entry in self.pb2_directory.symlinks:
|
758
|
917
|
src_name = os.path.join(to_directory, entry.name)
|
759
|
918
|
target_name = entry.target
|
|
919
|
+ print("Exporting symlink named {}".format(src_name))
|
760
|
920
|
try:
|
761
|
921
|
os.symlink(target_name, src_name)
|
762
|
922
|
except FileExistsError as e:
|
... |
... |
@@ -857,6 +1017,7 @@ class CasBasedDirectory(Directory): |
857
|
1017
|
for (k, v) in sorted(directory_list):
|
858
|
1018
|
print("Yielding from subdirectory name {}".format(k))
|
859
|
1019
|
yield from v.buildstream_object.list_relative_paths(relpath=os.path.join(relpath, k))
|
|
1020
|
+ print("List_relative_paths on {} complete".format(relpath))
|
860
|
1021
|
|
861
|
1022
|
def recalculate_hash(self):
|
862
|
1023
|
""" Recalcuates the hash for this directory and store the results in
|