Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 24 additions & 9 deletions examples/extensions/commands/ci_test_example.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import os
import warnings
import json

from test.examples_tools import run, tmp_dir

from conan import conan_version

non_deterministic_conanfile = """\
from datetime import datetime
Expand Down Expand Up @@ -54,11 +56,24 @@ def install_clean_command():
f.write(non_deterministic_conanfile.format(name="clean_other", comment="# Changing RREV"))
run("conan create .") # different RREV (this is the latest one)

# 3. Run "conan clean" command: Cleaning all the non-latest RREVs (and its packages) and PREVs
output = run("conan clean --force")
assert "Removed package revision: clean_hello/1.0#" in output # removing earlier PREV from clean_hello
assert "Removed recipe revision: clean_other/1.0#" in output # removing earlier RREV from clean_other
# Now, it should have removed nothing
output = run("conan clean --force")
assert "Removed recipe revision: clean_other/1.0#" not in output
assert "Removed package revision: clean_hello/1.0#" not in output
if conan_version >= "2.21.0-dev":
output = run("conan list '*/*#*:*#*' --format=json ")
all_packages = json.loads("\n".join(output.splitlines()[1:]))
output = run("conan list '*/*#latest:*#latest' --format=json")
latest_packages = json.loads("\n".join(output.splitlines()[1:]))
if all_packages == latest_packages:
warnings.warn("Skipping 'conan clean' test because there are no old revisions to clean.")
# 3. Run "conan clean" command: Cleaning all the non-latest RREVs (and its packages) and PREVs
output = run("conan clean --force")
assert "Removed package revision: clean_hello/1.0#" in output # removing earlier PREV from clean_hello
assert "Removed recipe revision: clean_other/1.0#" in output # removing earlier RREV from clean_other
# Now, it should have removed nothing
output = run("conan clean --force")
assert "Removed recipe revision: clean_other/1.0#" not in output
assert "Removed package revision: clean_hello/1.0#" not in output
# Make sure latest revisions are still there
output = run("conan list '*/*#*:*#*' --format=json")
listed_after = json.loads("\n".join(output.splitlines()[1:]))
assert latest_packages == listed_after
else:
warnings.warn("Skipping 'conan clean' test because it requires Conan 2.21 due new API list.")
45 changes: 25 additions & 20 deletions examples/extensions/commands/clean/cmd_clean.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from conan.api.conan_api import ConanAPI
from conan.api.model import PackagesList, ListPattern
from conan.api.input import UserInput
from conan.api.output import ConanOutput, Color
from conan.cli.command import OnceArgument, conan_command
Expand Down Expand Up @@ -27,26 +28,30 @@ def confirmation(message):
remote = conan_api.remotes.get(args.remote) if args.remote else None
output_remote = remote or "Local cache"

# Getting all the recipes
recipes = conan_api.search.recipes("*/*", remote=remote)
if recipes and not confirmation("Do you want to remove all the recipes revisions and their packages ones, "
# List all recipes revisions and all their packages revisions as well
pkg_list = conan_api.list.select(ListPattern("*/*#*:*#*", rrev=None, prev=None), remote=remote)
if pkg_list and not confirmation("Do you want to remove all the recipes revisions and their packages ones, "
"except the latest package revision from the latest recipe one?"):
out.writeln("Aborted")
return
for recipe in recipes:
out.writeln(f"{str(recipe)}", fg=recipe_color)
all_rrevs = conan_api.list.recipe_revisions(recipe, remote=remote)
latest_rrev = all_rrevs[0] if all_rrevs else None
for rrev in all_rrevs:
if rrev != latest_rrev:
conan_api.remove.recipe(rrev, remote=remote)
out.writeln(f"Removed recipe revision: {rrev.repr_notime()} "
f"and all its package revisions [{output_remote}]", fg=removed_color)

# Split the package list into based on their recipe reference
for sub_pkg_list in pkg_list.split():
latest = max(sub_pkg_list.items(), key=lambda item: item[0])[0]
out.writeln(f"Keeping recipe revision: {latest.repr_notime()} "
f"and its latest package revisions [{output_remote}]", fg=recipe_color)
for rref, packages in sub_pkg_list.items():
# For the latest recipe revision, keep the latest package revision only
if latest == rref:
# Get the latest package timestamp for each package_id
latest_pref_list = [max([p for p in packages if p.package_id == pkg_id], key=lambda p: p.timestamp)
for pkg_id in {p.package_id for p in packages}]
for pref in packages:
if pref not in latest_pref_list:
conan_api.remove.package(pref, remote=remote)
out.writeln(f"Removed package revision: {pref.repr_notime()} [{output_remote}]", fg=removed_color)
else:
packages = conan_api.list.packages_configurations(rrev, remote=remote)
for package_ref in packages:
all_prevs = conan_api.list.package_revisions(package_ref, remote=remote)
latest_prev = all_prevs[0] if all_prevs else None
for prev in all_prevs:
if prev != latest_prev:
conan_api.remove.package(prev, remote=remote)
out.writeln(f"Removed package revision: {prev.repr_notime()} [{output_remote}]", fg=removed_color)
# Otherwise, remove all outdated recipe revisions and their packages
conan_api.remove.recipe(rref, remote=remote)
out.writeln(f"Removed recipe revision: {rref.repr_notime()} "
f"and all its package revisions [{output_remote}]", fg=removed_color)