Skip to content

Commit

Permalink
Implement the --keep option for tmt clean (#3183) (#3183)
Browse files Browse the repository at this point in the history
  • Loading branch information
skycastlelily authored Dec 5, 2024
1 parent ebf02ad commit 2df13a9
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 15 deletions.
6 changes: 3 additions & 3 deletions docs/releases.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ tmt-1.40.0
Add the ``--workdir-root`` option for the ``tmt clean`` command so
that users can specify the directory they want to clean.

Add the ``--keep`` option for the ``tmt clean guests`` command.
Users can now choose to keep the selected number of latest guests
and clean the rest to release the resources.
Add the ``--keep`` option for the ``tmt clean guests`` and ``tmt clean``
commands. Users can now choose to keep the selected number of latest guests,
and maybe also runs, clean the rest to release the resources.


tmt-1.39.0
Expand Down
20 changes: 16 additions & 4 deletions tests/clean/basic/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ rlJournalStart
rlPhaseEnd

rlPhaseStartTest "Create a couple of runs"
for id in {001..004}; do
for id in {001..005}; do
rlRun "tmt --feeling-safe run --id clean-$id"
rlAssertExists "$root/clean-$id"
done
Expand All @@ -20,23 +20,35 @@ rlJournalStart
rlAssertExists "$root/clean-001"
rlAssertExists "$root/clean-002"
rlAssertExists "$root/clean-003"
rlAssertNotExists "$root/clean-004"
rlAssertExists "$root/clean-004"
rlAssertNotExists "$root/clean-005"
rlPhaseEnd

rlPhaseStartTest "Remove selected (full path)"
rlRun "tmt clean -v --id $root/clean-001"
rlAssertNotExists "$root/clean-001"
rlAssertExists "$root/clean-002"
rlAssertExists "$root/clean-003"
rlAssertNotExists "$root/clean-004"
rlAssertExists "$root/clean-004"
rlAssertNotExists "$root/clean-005"
rlPhaseEnd

rlPhaseStartTest "Remove selected (name)"
rlRun "tmt clean -v --id clean-002"
rlAssertNotExists "$root/clean-001"
rlAssertNotExists "$root/clean-002"
rlAssertExists "$root/clean-003"
rlAssertNotExists "$root/clean-004"
rlAssertExists "$root/clean-004"
rlAssertNotExists "$root/clean-005"
rlPhaseEnd

rlPhaseStartTest "Skip latest guests and runs"
rlRun "tmt clean -v --keep 1"
rlAssertNotExists "$root/clean-001"
rlAssertNotExists "$root/clean-002"
rlAssertNotExists "$root/clean-003"
rlAssertExists "$root/clean-004"
rlAssertNotExists "$root/clean-005"
rlPhaseEnd

rlPhaseStartTest "Create a couple of runs in non-default root workdir"
Expand Down
6 changes: 2 additions & 4 deletions tmt/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3997,7 +3997,7 @@ def _stop_running_guests(self, run: Run) -> bool:
self.cli_invocation.options['quiet'] = quiet
return successful

def guests(self, run_ids: tuple[str, ...]) -> bool:
def guests(self, run_ids: tuple[str, ...], keep: Optional[int]) -> bool:
""" Clean guests of runs """
self.info('guests', color='blue')
self.verbose('workdir root', self.workdir_root)
Expand All @@ -4009,7 +4009,6 @@ def guests(self, run_ids: tuple[str, ...]) -> bool:
successful = True
assert self._cli_context_object is not None # narrow type
all_workdirs = list(tmt.utils.generate_runs(self.workdir_root, run_ids))
keep = self.opt('keep')
if keep is not None:
# Sort by modify time of the workdirs to keep the newest guests
all_workdirs.sort(
Expand Down Expand Up @@ -4038,7 +4037,7 @@ def _clean_workdir(self, path: Path) -> bool:
return False
return True

def runs(self, id_: tuple[str, ...]) -> bool:
def runs(self, id_: tuple[str, ...], keep: Optional[int]) -> bool:
""" Clean workdirs of runs """
self.info('runs', color='blue')
self.verbose('workdir root', self.workdir_root)
Expand All @@ -4050,7 +4049,6 @@ def runs(self, id_: tuple[str, ...]) -> bool:
assert last_run.workdir is not None # narrow type
return self._clean_workdir(last_run.workdir)
all_workdirs = list(tmt.utils.generate_runs(self.workdir_root, id_))
keep = self.opt('keep')
if keep is not None:
# Sort by modify time of the workdirs and keep the newest workdirs
all_workdirs.sort(
Expand Down
14 changes: 10 additions & 4 deletions tmt/cli/_root.py
Original file line number Diff line number Diff line change
Expand Up @@ -1636,6 +1636,9 @@ def _construct_trying_provision_options(params: Any) -> dict[str, Any]:
@option(
'-i', '--id', 'id_', metavar="ID", multiple=True,
help='Identifier (name or directory path) of the run to be cleaned.')
@option(
'-k', '--keep', type=int, default=None,
help='The number of latest workdirs to keep, clean the rest.')
@option(
'-s', '--skip', choices=CLEAN_RESOURCES,
help='The resources which should be kept on the disk.', multiple=True)
Expand All @@ -1645,6 +1648,7 @@ def _construct_trying_provision_options(params: Any) -> dict[str, Any]:
def clean(context: Context,
last: bool,
id_: tuple[str, ...],
keep: Optional[int],
skip: list[str],
_workdir_root: Optional[str],
**kwargs: Any) -> None:
Expand Down Expand Up @@ -1691,9 +1695,9 @@ def clean(context: Context,
cli_invocation=CliInvocation.from_context(context),
workdir_root=workdir_root)
if workdir_root.exists():
if 'guests' not in skip and not clean_obj.guests(id_):
if 'guests' not in skip and not clean_obj.guests(id_, keep):
exit_code = 1
if 'runs' not in skip and not clean_obj.runs(id_):
if 'runs' not in skip and not clean_obj.runs(id_, keep):
exit_code = 1
else:
clean_obj.warn(
Expand Down Expand Up @@ -1774,7 +1778,8 @@ def clean_runs(
workdir_root=effective_workdir_root(workdir_root))
context.obj.clean_partials["runs"].append(
lambda: clean_obj.runs(
(context.parent and context.parent.params.get('id_', [])) or id_))
(context.parent and context.parent.params.get('id_', [])) or id_,
(context.parent and context.parent.params.get('keep', [])) or keep))


@clean.command(name='guests')
Expand Down Expand Up @@ -1822,7 +1827,8 @@ def clean_guests(
workdir_root=effective_workdir_root(workdir_root))
context.obj.clean_partials["guests"].append(
lambda: clean_obj.guests(
(context.parent and context.parent.params.get('id_', [])) or id_))
(context.parent and context.parent.params.get('id_', [])) or id_,
(context.parent and context.parent.params.get('keep', [])) or keep))


# ignore[arg-type]: click code expects click.Context, but we use our own type for better type
Expand Down

0 comments on commit 2df13a9

Please sign in to comment.