Пример #1
0
def move(
    sources: ListOfPathsOrStrs,
    destination: PathOrStr = None,
    excludes: ListOfPathsOrStrs = None,
    merge: Callable[[str, str, Path], str] = None,
    required: bool = False,
) -> bool:
    """
    copy file(s) at source to current directory, preserving file mode.

    Args:
        sources (ListOfPathsOrStrs): Glob pattern(s) to copy
        destination (PathOrStr): Destination folder for copied files
        excludes (ListOfPathsOrStrs): Glob pattern(s) of files to skip
        merge (Callable[[str, str, Path], str]): Callback function for merging files
            if there is an existing file.
        required (bool): If required and no source files are copied, throws a MissingSourceError

    Returns:
        True if any files were copied, False otherwise.
    """
    copied = False

    for source in _expand_paths(sources):
        if destination is None:
            canonical_destination = _tracked_paths.relativize(source)
        else:
            canonical_destination = Path(destination)

        if excludes:
            excludes = [
                _tracked_paths.relativize(e)
                for e in _expand_paths(excludes, source)
            ]
        else:
            excludes = []
        if source.is_dir():
            copied = copied or _copy_dir_to_existing_dir(
                source, canonical_destination, excludes=excludes, merge=merge)
        elif source not in excludes:
            # copy individual file
            if merge is not None and canonical_destination.is_file():
                _merge_file(source, canonical_destination, merge)
            else:
                shutil.copy2(source, canonical_destination)
            copied = True

    if not copied:
        if required:
            raise MissingSourceError(
                f"No files in sources {sources} were copied. Does the source "
                f"contain files?")
        else:
            logger.warning(
                f"No files in sources {sources} were copied. Does the source "
                f"contain files?")

    return copied
Пример #2
0
def _copy_dir_to_existing_dir(
    source: Path,
    destination: Path,
    excludes: ListOfPathsOrStrs = None,
    merge: Callable[[str, str, Path], str] = None,
) -> bool:
    """
    copies files over existing files to an existing directory
    this function does not copy empty directories.

    Returns: True if any files were copied, False otherwise.
    """
    copied = False

    if not excludes:
        excludes = []
    for root, _, files in os.walk(source):
        for name in files:
            rel_path = str(Path(root).relative_to(source))
            dest_dir = destination / rel_path
            dest_path = dest_dir / name
            exclude = [
                e
                for e in excludes
                if (
                    Path(e) == _tracked_paths.relativize(root)
                    or Path(e) == _tracked_paths.relativize(Path(root) / name)
                )
            ]
            if not exclude:
                os.makedirs(str(dest_dir), exist_ok=True)
                source_path = Path(os.path.join(root, name))
                if merge is not None and dest_path.is_file():
                    try:
                        _merge_file(source_path, dest_path, merge)
                    except Exception:
                        logger.exception(
                            "_merge_file failed for %s, fall back to copy", source_path,
                        )
                        shutil.copy2(str(source_path), str(dest_path))
                else:
                    shutil.copy2(str(source_path), str(dest_path))
                copied = True

    return copied
Пример #3
0
def test_deep_paths():
    parent = FIXTURES / "parent"
    deep_path = FIXTURES / "parent" / "child" / "grandchild"
    deep_item = deep_path / "thing.txt"

    _tracked_paths.add(parent)
    _tracked_paths.add(deep_path)

    assert _tracked_paths.relativize(deep_item) == Path("thing.txt")
Пример #4
0
def move(
    sources: ListOfPathsOrStrs,
    destination: PathOrStr = None,
    excludes: ListOfPathsOrStrs = None,
    merge: Callable[[str, str, Path], str] = None,
) -> bool:
    """
    copy file(s) at source to current directory.

    Returns: True if any files were copied, False otherwise.
    """
    copied = False

    for source in _expand_paths(sources):
        if destination is None:
            canonical_destination = _tracked_paths.relativize(source)
        else:
            canonical_destination = Path(destination)

        if excludes:
            excludes = [
                _tracked_paths.relativize(e) for e in _expand_paths(excludes, source)
            ]
        else:
            excludes = []
        if source.is_dir():
            copied = copied or _copy_dir_to_existing_dir(
                source, canonical_destination, excludes=excludes, merge=merge
            )
        elif source not in excludes:
            # copy individual file
            if merge is not None and canonical_destination.is_file():
                _merge_file(source, canonical_destination, merge)
            else:
                shutil.copy2(source, canonical_destination)
            copied = True

    if not copied:
        log.warning(
            f"No files in sources {sources} were copied. Does the source "
            f"contain files?"
        )

    return copied