Source code for runway.cfngin.hooks.staticsite.utils

"""Utility functions for website build/upload."""
from __future__ import annotations

import hashlib
import logging
import os
from pathlib import Path
from typing import TYPE_CHECKING, Dict, Iterable, List, Optional, Union, cast

import igittigitt

from ....utils import FileHash, change_dir

if TYPE_CHECKING:
    from _typeshed import StrPath

LOGGER = logging.getLogger(__name__)


[docs]def calculate_hash_of_files(files: Iterable[StrPath], root: Path) -> str: """Return a hash of all of the given files at the given root. Args: files: file names to include in the hash calculation, relative to ``root``. root: base directory to analyze files in. Returns: A hash of the hashes of the given files. """ file_hash = FileHash(hashlib.md5()) file_hash.add_files(sorted(str(f) for f in files), relative_to=root) return file_hash.hexdigest
[docs]def get_hash_of_files( root_path: Path, directories: Optional[List[Dict[str, Union[List[str], str]]]] = None, ) -> str: """Generate md5 hash of files. Args: root_path: Base directory where all paths will be relative to. This should already be resolve to an absolute path. directories: List of mappings that describe the paths to hash and files to exclude. """ directories = directories or [{"path": "./"}] files_to_hash: List[StrPath] = [] for i in directories: gitignore = get_ignorer( root_path / cast(str, i["path"]), cast(Optional[List[str]], i.get("exclusions")), ) with change_dir(root_path): for root, dirs, files in os.walk(cast(str, i["path"]), topdown=True): sub_root = Path(root).resolve() if root != "./" and gitignore.match(sub_root): dirs[:] = [] # type: ignore files[:] = [] # type: ignore else: for filename in files: filepath = sub_root / filename if not gitignore.match(filepath): files_to_hash.append(filepath) return calculate_hash_of_files(files_to_hash, root_path)
[docs]def get_ignorer( path: Path, additional_exclusions: Optional[List[str]] = None ) -> igittigitt.IgnoreParser: """Create gitignore filter from directory ``.gitignore`` file. Args: path: Top-level directory that the gitignore filter will be created for. This directory and it's subdirectories will be searched for ``.gitignore`` files to use. additional_exclusions: Additional gitignore patterns to add. """ additional_exclusions = additional_exclusions or [] gitignore = igittigitt.IgnoreParser() gitignore.parse_rule_files(path) for rule in additional_exclusions: gitignore.add_rule(rule, path) return gitignore