Tristan Van Berkom pushed to branch tristan/cas-cleanup-improve at BuildStream / buildstream
Commits:
-
1f8e506d
by Tristan Van Berkom at 2019-01-18T17:43:25Z
-
008cdee5
by Tristan Van Berkom at 2019-01-18T17:43:25Z
2 changed files:
Changes:
... | ... | @@ -21,6 +21,7 @@ import hashlib |
21 | 21 |
import itertools
|
22 | 22 |
import os
|
23 | 23 |
import stat
|
24 |
+import errno
|
|
24 | 25 |
import tempfile
|
25 | 26 |
import uuid
|
26 | 27 |
import contextlib
|
... | ... | @@ -545,11 +546,7 @@ class CASCache(): |
545 | 546 |
def remove(self, ref, *, defer_prune=False):
|
546 | 547 |
|
547 | 548 |
# Remove cache ref
|
548 |
- refpath = self._refpath(ref)
|
|
549 |
- if not os.path.exists(refpath):
|
|
550 |
- raise CASCacheError("Could not find ref '{}'".format(ref))
|
|
551 |
- |
|
552 |
- os.unlink(refpath)
|
|
549 |
+ self._remove_ref(ref)
|
|
553 | 550 |
|
554 | 551 |
if not defer_prune:
|
555 | 552 |
pruned = self.prune()
|
... | ... | @@ -626,6 +623,55 @@ class CASCache(): |
626 | 623 |
def _refpath(self, ref):
|
627 | 624 |
return os.path.join(self.casdir, 'refs', 'heads', ref)
|
628 | 625 |
|
626 |
+ # _remove_ref()
|
|
627 |
+ #
|
|
628 |
+ # Removes a ref.
|
|
629 |
+ #
|
|
630 |
+ # This also takes care of pruning away directories which can
|
|
631 |
+ # be removed after having removed the given ref.
|
|
632 |
+ #
|
|
633 |
+ # Args:
|
|
634 |
+ # ref (str): The ref to remove
|
|
635 |
+ #
|
|
636 |
+ # Raises:
|
|
637 |
+ # (CASCacheError): If the ref didnt exist, or a system error
|
|
638 |
+ # occurred while removing it
|
|
639 |
+ #
|
|
640 |
+ def _remove_ref(self, ref):
|
|
641 |
+ |
|
642 |
+ # Remove the ref itself
|
|
643 |
+ refpath = self._refpath(ref)
|
|
644 |
+ try:
|
|
645 |
+ os.unlink(refpath)
|
|
646 |
+ except FileNotFoundError:
|
|
647 |
+ raise CASCacheError("Could not find ref '{}'".format(ref)) from e
|
|
648 |
+ |
|
649 |
+ basedir = os.path.join(self.casdir, 'refs', 'heads')
|
|
650 |
+ components = list(os.path.split(ref))
|
|
651 |
+ |
|
652 |
+ while components:
|
|
653 |
+ components.pop()
|
|
654 |
+ refdir = os.path.join(basedir, *components)
|
|
655 |
+ |
|
656 |
+ # Break out once we reach the base
|
|
657 |
+ if refdir == basedir:
|
|
658 |
+ break
|
|
659 |
+ |
|
660 |
+ try:
|
|
661 |
+ os.rmdir(refdir)
|
|
662 |
+ except FileNotFoundError:
|
|
663 |
+ # The parent directory did not exist, but it's
|
|
664 |
+ # parent directory might still be ready to prune
|
|
665 |
+ pass
|
|
666 |
+ except OSError as e:
|
|
667 |
+ if e.errno == errno.ENOTEMPTY:
|
|
668 |
+ # The parent directory was not empty, so we
|
|
669 |
+ # cannot prune directories beyond this point
|
|
670 |
+ break
|
|
671 |
+ |
|
672 |
+ # Something went wrong here
|
|
673 |
+ raise CASCacheError("System error while removing ref '{}': {}".format(ref, e)) from e
|
|
674 |
+ |
|
629 | 675 |
# _commit_directory():
|
630 | 676 |
#
|
631 | 677 |
# Adds local directory to content addressable store.
|
... | ... | @@ -382,6 +382,7 @@ def test_extract_expiry(cli, datafiles, tmpdir): |
382 | 382 |
res = cli.run(project=project, args=['checkout', 'target.bst', os.path.join(str(tmpdir), 'checkout')])
|
383 | 383 |
res.assert_success()
|
384 | 384 |
|
385 |
+ # Get a snapshot of the extracts in advance
|
|
385 | 386 |
extractdir = os.path.join(project, 'cache', 'artifacts', 'extract', 'test', 'target')
|
386 | 387 |
extracts = os.listdir(extractdir)
|
387 | 388 |
assert(len(extracts) == 1)
|
... | ... | @@ -395,3 +396,16 @@ def test_extract_expiry(cli, datafiles, tmpdir): |
395 | 396 |
|
396 | 397 |
# Now the extract should be removed.
|
397 | 398 |
assert not os.path.exists(extract)
|
399 |
+ |
|
400 |
+ # As an added bonus, let's ensure that no directories have been left behind
|
|
401 |
+ #
|
|
402 |
+ # Now we should have a directory for the cached target2.bst, which
|
|
403 |
+ # replaced target.bst in the cache, we should not have a directory
|
|
404 |
+ # for the target.bst
|
|
405 |
+ refsdir = os.path.join(project, 'cache', 'artifacts', 'cas', 'refs', 'heads')
|
|
406 |
+ refsdirtest = os.path.join(refsdir, 'test')
|
|
407 |
+ refsdirtarget = os.path.join(refsdirtest, 'target')
|
|
408 |
+ refsdirtarget2 = os.path.join(refsdirtest, 'target2')
|
|
409 |
+ |
|
410 |
+ assert os.path.isdir(refsdirtarget2)
|
|
411 |
+ assert not os.path.exists(refsdirtarget)
|