diff --git a/README.md b/README.md index 37d3f85..99d161b 100644 --- a/README.md +++ b/README.md @@ -261,6 +261,13 @@ policies: regex_pattern: "\d" ``` +- `DeleteLeastRecentlyUsedFiles` - delete the least recently used files until the total kept size is greater than passed value + +```yaml +- rule: DeleteLeastRecentlyUsedFiles + keep_at_most_mb: 512 +``` + ## Keep - `KeepLatestNFiles` - Leaves the last (by creation time) files in the amount of N pieces. WITHOUT accounting @@ -562,4 +569,3 @@ In order to provide a new release of `artifactory-cleanup`, there are two steps 1. Bump the version in the [setup.py](setup.py) 2. Bump the version in the [__init__.py](./artifactory_cleanup/__init__.py) 3. Create a Git release tag (in format `1.0.1`) by creating a release on GitHub - diff --git a/artifactory_cleanup/rules/delete.py b/artifactory_cleanup/rules/delete.py index fa76994..37a6518 100644 --- a/artifactory_cleanup/rules/delete.py +++ b/artifactory_cleanup/rules/delete.py @@ -113,12 +113,36 @@ class DeleteByRegexpName(Rule): def __init__(self, regex_pattern): self.regex_pattern = rf"{regex_pattern}" - def aql_add_filter(self, filters): - print("Here's filters that we get\n", filters) - return filters - def filter(self, artifacts: ArtifactsList) -> ArtifactsList: for artifact in artifacts[:]: if re.match(self.regex_pattern, artifact["name"]) is None: artifacts.remove(artifact) - return artifacts \ No newline at end of file + return artifacts + + +class DeleteLeastRecentlyUsedFiles(Rule): + """ + Delete the least recently used files until the total kept size is greater than ``keep_at_most_mb`` megabytes. + Creation is interpreted as a first usage. + """ + + def __init__(self, keep_at_most_mb: int): + self.keepAtMostBytes = keep_at_most_mb * 1024 * 1024 + + def filter(self, artifacts: ArtifactsList) -> ArtifactsList: + # List will contain fresh files at the beginning + artifacts.sort(key=utils.sort_by_usage, reverse=True) + + keptSize = 0 + keptArtifacts = [] + for artifact in artifacts: + keptSize += artifact["size"] + if keptSize > self.keepAtMostBytes: + # No need to keep files if overflow occurs + break + + keptArtifacts.append(artifact) + + artifacts.keep(keptArtifacts) + + return artifacts diff --git a/artifactory_cleanup/rules/utils.py b/artifactory_cleanup/rules/utils.py index d87b1e7..373ff81 100644 --- a/artifactory_cleanup/rules/utils.py +++ b/artifactory_cleanup/rules/utils.py @@ -3,7 +3,7 @@ from treelib import Node, Tree -from artifactory_cleanup.rules.base import ArtifactsList +from artifactory_cleanup.rules.base import ArtifactDict, ArtifactsList def is_repository(data): @@ -188,3 +188,10 @@ def to_masks(masks: Union[str, List[str]]): return masks else: raise AttributeError("'masks' argument must by list of string OR string") + + +def sort_by_usage(artifact: ArtifactDict) -> str: + try: + return artifact["stats"]["downloaded"] + except: + return artifact["created"]