|
1 | 1 | #!/usr/bin/env python3 |
2 | 2 | """Filesystem related util functions.""" |
3 | | - |
| 3 | +from collections import namedtuple |
4 | 4 | from typing import Iterable, Callable |
5 | 5 | import itertools |
6 | 6 | import os |
|
18 | 18 | import dulwich.porcelain |
19 | 19 |
|
20 | 20 | HOME = Path.home() |
| 21 | +PosixPathPair = namedtuple("PosixPathPair", ["prefix", "base"]) |
21 | 22 |
|
22 | 23 |
|
23 | 24 | def copy_if_exists(src: str, dst: str | Path = HOME) -> bool: |
@@ -691,3 +692,28 @@ def filter( |
691 | 692 | if sub_pattern: |
692 | 693 | return _filter_sp(path, pattern=pattern, sub_pattern=sub_pattern) |
693 | 694 | return _filter_num(path, pattern=pattern, num_lines=num_lines) |
| 695 | + |
| 696 | + |
| 697 | +def trace_dir_upwards(path: str | pathlib.Path, name: str) -> PosixPathPair: |
| 698 | + """Find the parent directory with the specified name. |
| 699 | +
|
| 700 | + Args: |
| 701 | + path: A local path contains `/name/`. |
| 702 | + name: The base name (stem) of the parent directory. |
| 703 | +
|
| 704 | + Returns: |
| 705 | + A PosixPathPair which contains the parent directory |
| 706 | + and the relative path to this parent directory. |
| 707 | + """ |
| 708 | + def _trace_dir_upwards(path: pathlib.Path) -> pathlib.Path: |
| 709 | + while (stem := path.stem) != name: |
| 710 | + if not stem: |
| 711 | + raise ValueError(f"The path {path} does not contain /{name}/!") |
| 712 | + path = path.parent |
| 713 | + return path |
| 714 | + |
| 715 | + if isinstance(path, str): |
| 716 | + path = pathlib.Path(path) |
| 717 | + prefix = _trace_dir_upwards(path) |
| 718 | + return PosixPathPair(prefix, path.relative_to(prefix)) |
| 719 | + |
0 commit comments