Skip to content

Commit

Permalink
clean temp folders in cache (#13581)
Browse files Browse the repository at this point in the history
* clean temp folders in cache

* wip
  • Loading branch information
memsharded authored Mar 31, 2023
1 parent 766d8d3 commit 5b242f7
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 21 deletions.
10 changes: 8 additions & 2 deletions conan/api/subapi/cache.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import shutil

from conan.internal.conan_app import ConanApp
from conan.internal.integrity_check import IntegrityChecker
from conans.errors import ConanException
Expand Down Expand Up @@ -47,17 +49,21 @@ def check_integrity(self, package_list):
checker = IntegrityChecker(app)
checker.check(package_list)

def clean(self, package_list, source=None, build=None, download=None):
def clean(self, package_list, source=True, build=True, download=True, temp=True):
"""
Remove non critical folders from the cache, like source, build and download (.tgz store)
folders.
:param package_list: the package lists that should be cleaned
:param source: boolean, remove the "source" folder if True
:param build: boolean, remove the "build" folder if True
:param download: boolena, remove the "download (.tgz)" folder if True
:param download: boolen, remove the "download (.tgz)" folder if True
:param temp: boolean, remove the temporary folders
:return:
"""

app = ConanApp(self.conan_api.cache_folder)
if temp:
shutil.rmtree(app.cache.temp_folder)
for ref, ref_bundle in package_list.refs():
ref_layout = app.cache.ref_layout(ref)
if source:
Expand Down
21 changes: 13 additions & 8 deletions conan/api/subapi/profiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,24 @@
class ProfilesAPI:

def __init__(self, conan_api):
self._cache = ClientCache(conan_api.cache_folder)
self._conan_api = conan_api

def get_default_host(self):
"""
:return: the path to the default "host" profile, either in the cache or as defined
by the user in configuration
"""
loader = ProfileLoader(self._cache)
cache = ClientCache(self._conan_api.cache_folder)
loader = ProfileLoader(cache)
return loader.get_default_host()

def get_default_build(self):
"""
:return: the path to the default "build" profile, either in the cache or as
defined by the user in configuration
"""
loader = ProfileLoader(self._cache)
cache = ClientCache(self._conan_api.cache_folder)
loader = ProfileLoader(cache)
return loader.get_default_build()

def get_profiles_from_args(self, args):
Expand All @@ -41,20 +43,22 @@ def get_profile(self, profiles, settings=None, options=None, conf=None, cwd=None
finally adding the individual settings, options (priority over the profiles)
"""
assert isinstance(profiles, list), "Please provide a list of profiles"
loader = ProfileLoader(self._cache)
cache = ClientCache(self._conan_api.cache_folder)
loader = ProfileLoader(cache)
profile = loader.from_cli_args(profiles, settings, options, conf, cwd)
profile.conf.validate()
self._cache.new_config.validate()
cache.new_config.validate()
# Apply the new_config to the profiles the global one, so recipes get it too
profile.conf.rebase_conf_definition(self._cache.new_config)
profile.conf.rebase_conf_definition(cache.new_config)
return profile

def get_path(self, profile, cwd=None, exists=True):
"""
:return: the resolved path of the given profile name, that could be in the cache,
or local, depending on the "cwd"
"""
loader = ProfileLoader(self._cache)
cache = ClientCache(self._conan_api.cache_folder)
loader = ProfileLoader(cache)
cwd = cwd or os.getcwd()
profile_path = loader.get_profile_path(profile, cwd, exists=exists)
return profile_path
Expand All @@ -68,7 +72,8 @@ def list(self):
paths_to_ignore = ['.DS_Store']

profiles = []
profiles_path = self._cache.profiles_path
cache = ClientCache(self._conan_api.cache_folder)
profiles_path = cache.profiles_path
if os.path.exists(profiles_path):
for current_directory, _, files in os.walk(profiles_path, followlinks=True):
files = filter(lambda file: os.path.relpath(
Expand Down
16 changes: 9 additions & 7 deletions conan/cli/commands/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,25 +58,27 @@ def cache_clean(conan_api: ConanAPI, parser, subparser, *args):
Remove non-critical folders from the cache, like source, build and/or download
(.tgz store) ones.
"""
subparser.add_argument("pattern", help="Selection pattern for references to clean")
subparser.add_argument("pattern", nargs="?", help="Selection pattern for references to clean")
subparser.add_argument("-s", "--source", action='store_true', default=False,
help="Clean source folders")
subparser.add_argument("-b", "--build", action='store_true', default=False,
help="Clean build folders")
subparser.add_argument("-d", "--download", action='store_true', default=False,
help="Clean download folders")
subparser.add_argument("-t", "--temp", action='store_true', default=False,
help="Clean temporary folders")
subparser.add_argument('-p', '--package-query', action=OnceArgument,
help="Remove only the packages matching a specific query, e.g., "
"os=Windows AND (arch=x86 OR compiler=gcc)")
args = parser.parse_args(*args)

if not args.source and not args.build and not args.download:
raise ConanException("Define at least one argument among [--source, --build, --download]")

ref_pattern = ListPattern(args.pattern, rrev="*", package_id="*", prev="*")
ref_pattern = ListPattern(args.pattern or "*", rrev="*", package_id="*", prev="*")
package_list = conan_api.list.select(ref_pattern, package_query=args.package_query)
conan_api.cache.clean(package_list, source=args.source, build=args.build,
download=args.download)
if args.build or args.source or args.download or args.temp:
conan_api.cache.clean(package_list, source=args.source, build=args.build,
download=args.download, temp=args.temp)
else:
conan_api.cache.clean(package_list)


@conan_subcommand(formatters={"text": cli_out_write})
Expand Down
7 changes: 7 additions & 0 deletions conans/client/cache/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ def __init__(self, cache_folder):
db_filename = os.path.join(self._store_folder, 'cache.sqlite3')
self._data_cache = DataCache(self._store_folder, db_filename)

@property
def temp_folder(self):
""" temporary folder where Conan puts exports and packages before the final revision
is computed"""
# TODO: Improve the path definitions, this is very hardcoded
return os.path.join(self.cache_folder, "p", "t")

def create_export_recipe_layout(self, ref: RecipeReference):
return self._data_cache.create_export_recipe_layout(ref)

Expand Down
21 changes: 17 additions & 4 deletions conans/test/integration/command_v2/test_cache_clean.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,25 @@ def test_cache_clean():
assert os.path.exists(ref_layout.download_export())
assert os.path.exists(pkg_layout.download_package())

c.run('cache clean "*" -d')
c.run('cache clean -d')
assert not os.path.exists(ref_layout.download_export())
assert not os.path.exists(pkg_layout.download_package())


def test_cache_clean_noargs_error():
def test_cache_clean_all():
c = TestClient()
c.run('cache clean "*"', assert_error=True)
assert "Define at least one argument among [--source, --build, --download]" in c.out
c.save({"pkg1/conanfile.py": GenConanfile("pkg", "0.1").with_package("error"),
"pkg2/conanfile.py": GenConanfile("pkg", "0.2")})
c.run("create pkg1", assert_error=True)
c.run("create pkg2")
pref = c.created_package_reference("pkg/0.2")
folder = os.path.join(c.cache_folder, "p", "t")
assert len(os.listdir(folder)) == 1
c.run('cache clean')
assert not os.path.exists(folder)
ref_layout = c.get_latest_ref_layout(pref.ref)
pkg_layout = c.get_latest_pkg_layout(pref)
assert not os.path.exists(ref_layout.source())
assert not os.path.exists(ref_layout.download_export())
assert not os.path.exists(pkg_layout.build())
assert not os.path.exists(pkg_layout.download_package())

0 comments on commit 5b242f7

Please sign in to comment.