Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

remove runN if symlink target is gone #4362

Merged
merged 7 commits into from
Aug 19, 2021
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
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ Remove obsolete Cylc 7 `[scheduling]spawn to max active cycle points` config.
safer by preventing cleaning of dirs that contain more than one workflow
run dir (use `--force` to override this safeguard).

[#4362](https://github.com/cylc/cylc-flow/pull/4362) -
When using `cylc clean` on a sequential run directory, remove the `runN` symlink
if it points to the removed directory.

-------------------------------------------------------------------------------
## __cylc-8.0b2 (<span actions:bind='release-date'>Released 2021-07-28</span>)__

Expand Down
9 changes: 9 additions & 0 deletions cylc/flow/workflow_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,15 @@ def clean(reg: str, run_dir: Path, rm_dirs: Optional[Set[str]] = None) -> None:
# Remove empty parents of symlink target up to <symlink_dir>/cylc-run/
remove_empty_parents(target, Path(reg, symlink))

# Remove `runN` symlink if it's now broken
runN = run_dir.parent / WorkflowFiles.RUN_N
if (
runN.is_symlink() and
not run_dir.exists() and
os.readlink(str(runN)) == run_dir.name
):
runN.unlink()


def get_symlink_dirs(reg: str, run_dir: Union[Path, str]) -> Dict[str, Path]:
"""Return the standard symlink dirs and their targets if they exist in
Expand Down
31 changes: 31 additions & 0 deletions tests/unit/test_workflow_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import os
from pathlib import Path
import pytest
import re
import shutil
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Type, Union
from unittest import mock
Expand All @@ -40,6 +41,7 @@
_remote_clean_cmd,
check_flow_file,
check_nested_run_dirs,
clean,
get_rsync_rund_cmd,
get_symlink_dirs,
is_installed,
Expand Down Expand Up @@ -1523,3 +1525,32 @@ def test_get_rsync_rund_cmd(tmp_run_dir: Callable):
'--exclude=log', '--exclude=work', '--exclude=share',
'--exclude=_cylc-install', '--exclude=.service',
'blah/', f'{cylc_run_dir}/']


@pytest.mark.parametrize(
'expect, dirs',
[
(['run1'], ['run1', 'run2']),
(['run1', 'run11'], ['run1', 'run11', 'run2']),
(['run1200'], ['run1200', 'run1201']),
(['foo'], ['foo', 'bar']),
]
)
def test_delete_runN(tmp_path, expect, dirs):
"""It deletes the runN symlink.
"""
for dir_ in dirs:
(tmp_path / dir_).mkdir()
if re.findall('run\d*', dirs[-1]):
(Path(tmp_path / 'runN')).symlink_to(dirs[-1])
clean(str(tmp_path.name) + '/' + dirs[-1], tmp_path / dirs[-1])
assert sorted([i.stem for i in tmp_path.glob('*')]) == sorted(expect)


def test_delete_runN_skipif_cleanedrun_not_runN(tmp_path):
"""It doesn't delete the symlink dir to be cleaned is not runN"""
for folder in ['run1', 'run2']:
(tmp_path / folder).mkdir()
(tmp_path / 'runN').symlink_to(tmp_path / 'run2')
clean(str(tmp_path.name) + '/' + 'run1', tmp_path / 'run1')
assert sorted([i.stem for i in tmp_path.glob('*')]) == ['run2', 'runN']