Module continuous_delivery_scripts.utils.filesystem_helpers

Helpers with regards to actions on the filesystem.

Functions

def cd(new_dir: str) ‑> Generator
Expand source code
@contextmanager
def cd(new_dir: str) -> Generator:
    """Context manager allowing an operation to be performed inside given directory.

    Args:
         new_dir: the directory to move into

    """
    prev_dir = os.getcwd()
    os.chdir(os.path.expanduser(new_dir))
    try:
        yield
    finally:
        os.chdir(prev_dir)

Context manager allowing an operation to be performed inside given directory.

Args
-----=
new_dir
the directory to move into
def find_file_in_tree(file_name: str,
starting_point: str = '/home/runner/work/continuous-delivery-scripts/continuous-delivery-scripts',
top: bool = False) ‑> str
Expand source code
def find_file_in_tree(file_name: str, starting_point: str = os.getcwd(), top: bool = False) -> str:
    """Finds a file in directory tree.

    Args:
        file_name: name of the file to look for.
        starting_point: path from where to start the search
        top: search up the directory tree to root if True; down the tree otherwise.

    Returns:
            path of the file of interest.
    """
    if not file_name:
        raise ValueError("Undefined file name")

    iterator = _get_directory_walk_method(top)
    for directory in iterator(starting_point):
        file_path = os.path.join(directory, file_name)
        if os.path.exists(file_path):
            break
    else:
        raise FileNotFoundError(
            f'File [{file_name}] not found anywhere in directories {"above" if top else "under"} {starting_point}'
        )
    return file_path

Finds a file in directory tree.

Args
-----=
file_name
name of the file to look for.
starting_point
path from where to start the search
top
search up the directory tree to root if True; down the tree otherwise.

Returns -----= path of the file of interest.

def list_all_files(root_path: pathlib.Path,
should_exclude_path: Callable[[pathlib.Path], bool] | None = None) ‑> Iterator[pathlib.Path]
Expand source code
def list_all_files(root_path: Path, should_exclude_path: Optional[Callable[[Path], bool]] = None) -> Iterator[Path]:
    """Lists all the files in a directory."""
    for root, dirs, files in os.walk(str(root_path)):
        yield from _browse_files(files, root, should_exclude_path)
        if should_exclude_path:
            _exclude_browsing_paths(dirs, root, should_exclude_path)

Lists all the files in a directory.

def match_pattern(path: pathlib.Path, pattern: str) ‑> bool
Expand source code
def match_pattern(path: Path, pattern: str) -> bool:
    """Checks whether a path matches a `Unix`-like pattern e.g. `**/*.txt`."""
    enhanced_path = EnhancedPath(str(path))
    return any([enhanced_path.match(pattern), enhanced_path.globmatch(pattern, flags=GLOBSTAR)])

Checks whether a path matches a Unix-like pattern e.g. **/*.txt.

def scan_file_for_pattern(file_path: pathlib.Path, pattern: Pattern) ‑> Match | None
Expand source code
def scan_file_for_pattern(file_path: Path, pattern: Pattern) -> Optional[Match]:
    """Looks for a specific pattern in a file."""
    if not file_path.exists():
        return None
    with open(str(file_path), "r", encoding="utf8") as f:
        text = f.read()
        return pattern.search(text)

Looks for a specific pattern in a file.

def should_exclude_path(path: pathlib.Path, excludes: List[str]) ‑> bool
Expand source code
def should_exclude_path(path: Path, excludes: List[str]) -> bool:
    """Determines if a file should be excluded i.e. its filename follows a pattern defined in excludes list."""
    return any([match_pattern(path, p) for p in excludes])

Determines if a file should be excluded i.e. its filename follows a pattern defined in excludes list.

def walk_up_tree_to_root(starting_point: str) ‑> Iterator[str]
Expand source code
def walk_up_tree_to_root(starting_point: str) -> Iterator[str]:
    """Iterates from path to root.

    Args:
        starting_point: path from where to start.

    Returns:
        Iterator walking up the directory tree up to the root.
    """
    if not os.path.exists(starting_point):
        raise FileNotFoundError(starting_point)

    current_dir = os.path.realpath(starting_point if os.path.isdir(starting_point) else os.path.dirname(starting_point))

    previous_dir = None
    while previous_dir != current_dir:
        yield current_dir
        previous_dir = current_dir
        current_dir = os.path.dirname(current_dir)

Iterates from path to root.

Args
-----=
starting_point
path from where to start.

Returns -----= Iterator walking up the directory tree up to the root.

Classes

class TemporaryDirectory
Expand source code
class TemporaryDirectory:
    """Creates and returns a temporary directory.

    This is the same as tempfile.TemporaryDirectory in most cases.
    However, on CI the temporary folder may not be accessible.
    Moreover, on Windows TemporaryDirectory will fail cleaning up
    (https://bugs.python.org/issue22107) and hence, a workaround had to be
    implemented.

    """

    def __init__(self) -> None:
        """Constructor."""
        self._tmp_dir_context_manager = tempfile.TemporaryDirectory()
        self._tmp_dir_path = Path(self._tmp_dir_context_manager.name).resolve()

    @property
    def path(self) -> Path:
        """Path to the folder."""
        return self._tmp_dir_path

    def __str__(self) -> str:
        """String representation."""
        return str(self._tmp_dir_path)

    def __enter__(self) -> Path:
        """Context manager entry point."""
        return self.path

    def __exit__(self, exc: Any, value: Any, tb: Any) -> None:
        """Context manager exit point."""
        self.cleanup()

    def _default_cleanup(self) -> None:
        try:
            self._tmp_dir_context_manager.cleanup()
        except FileNotFoundError as e:
            logger.warning(f"Failed cleaning up {self.path}. Reason: {str(e)}")

    def _windows_cleanup(self) -> None:
        if self.path.exists():
            shutil.rmtree(str(self.path), ignore_errors=True)

    def cleanup(self) -> None:
        """Deletes the temporary directory."""
        if platform.system() == "Windows":
            self._windows_cleanup()
        else:
            self._default_cleanup()

Creates and returns a temporary directory.

This is the same as tempfile.TemporaryDirectory in most cases. However, on CI the temporary folder may not be accessible. Moreover, on Windows TemporaryDirectory will fail cleaning up (https://bugs.python.org/issue22107) and hence, a workaround had to be implemented.

Constructor.

Instance variables

prop path : pathlib.Path
Expand source code
@property
def path(self) -> Path:
    """Path to the folder."""
    return self._tmp_dir_path

Path to the folder.

Methods

def cleanup(self) ‑> None
Expand source code
def cleanup(self) -> None:
    """Deletes the temporary directory."""
    if platform.system() == "Windows":
        self._windows_cleanup()
    else:
        self._default_cleanup()

Deletes the temporary directory.