def test_remove_dir_symlinks(target, expected_err, tmp_path): """Test that remove_dir() can delete symlinks, including the target.""" target_path = tmp_path.joinpath('x/y') target_path.mkdir(parents=True) tmp_path.joinpath('a').mkdir() symlink_path = tmp_path.joinpath('a/b') if target == 'dir': # Add a file into the the target dir to check it removes that ok target_path.joinpath('meow').touch() symlink_path.symlink_to(target_path) elif target == 'file': target_path = target_path.joinpath('meow') target_path.touch() symlink_path.symlink_to(target_path) elif target is None: symlink_path.symlink_to(target_path) # Break symlink target_path.rmdir() if expected_err: with pytest.raises(expected_err): remove_dir(symlink_path) else: remove_dir(symlink_path) for path in [symlink_path, target_path]: assert path.exists() is False assert path.is_symlink() is False
def test_remove_dir_relative(tmp_path): """Test that you cannot use remove_dir() on a relative path. When removing a path, we want to be absolute-ly sure where it is! """ # cd to temp dir in case we accidentally succeed in deleting the path os.chdir(tmp_path) with pytest.raises(ValueError) as cm: remove_dir('foo/bar') assert 'Path must be absolute' in str(cm.value)
def clean(reg): """Remove a stopped workflow from the local filesystem only. Deletes the workflow run directory and any symlink dirs. Note: if the run dir has already been manually deleted, it will not be possible to clean the symlink dirs. Args: reg (str): Workflow name. """ run_dir = Path(get_workflow_run_dir(reg)) try: _clean_check(reg, run_dir) except FileNotFoundError as exc: LOG.info(str(exc)) return # Note: 'share/cycle' must come first, and '' must come last for possible_symlink in ( SuiteFiles.SHARE_CYCLE_DIR, SuiteFiles.SHARE_DIR, SuiteFiles.LOG_DIR, SuiteFiles.WORK_DIR, ''): name = Path(possible_symlink) path = Path(run_dir, possible_symlink) if path.is_symlink(): # Ensure symlink is pointing to expected directory. If not, # something is wrong and we should abort target = path.resolve() if target.exists() and not target.is_dir(): raise WorkflowFilesError( f'Invalid Cylc symlink directory {path} -> {target}\n' f'Target is not a directory') expected_end = str(Path('cylc-run', reg, name)) if not str(target).endswith(expected_end): raise WorkflowFilesError( f'Invalid Cylc symlink directory {path} -> {target}\n' f'Expected target to end with "{expected_end}"') # Remove <symlink_dir>/cylc-run/<reg> target_cylc_run_dir = str(target).rsplit(str(reg), 1)[0] target_reg_dir = Path(target_cylc_run_dir, reg) if target_reg_dir.is_dir(): remove_dir(target_reg_dir) # Remove empty parents _remove_empty_reg_parents(reg, target_reg_dir) remove_dir(run_dir) _remove_empty_reg_parents(reg, run_dir)
def test_remove_dir(filetype, expected_err, tmp_path): """Test that remove_dir() can delete nested dirs and handle bad paths.""" test_path = tmp_path.joinpath('foo/bar') if filetype == 'dir': # Test removal of sub directories too sub_dir = test_path.joinpath('baz') sub_dir.mkdir(parents=True) sub_dir_file = sub_dir.joinpath('meow') sub_dir_file.touch() elif filetype == 'file': test_path = tmp_path.joinpath('meow') test_path.touch() if expected_err: with pytest.raises(expected_err): remove_dir(test_path) else: remove_dir(test_path) assert test_path.exists() is False assert test_path.is_symlink() is False