|
50 | 50 | import stat
|
51 | 51 | import sys
|
52 | 52 | import tempfile
|
53 |
| -from collections import deque |
54 |
| -from typing import IO, Any, Callable, ContextManager, Iterable, Iterator, List, Optional, TypeVar, Union |
| 53 | +from collections import defaultdict, deque |
| 54 | +from typing import Dict, IO, Any, Callable, ContextManager, Iterable, Iterator, List, Optional, TypeVar, Union |
55 | 55 |
|
56 | 56 | # this package
|
57 | 57 | from domdf_python_tools.compat import nullcontext
|
|
78 | 78 | "matchglob",
|
79 | 79 | "unwanted_dirs",
|
80 | 80 | "TemporaryPathPlus",
|
| 81 | + "sort_paths", |
81 | 82 | ]
|
82 | 83 |
|
83 | 84 | newline_default = object()
|
@@ -1005,3 +1006,33 @@ def cleanup(self) -> None:
|
1005 | 1006 |
|
1006 | 1007 | def __enter__(self) -> PathPlus:
|
1007 | 1008 | return self.name
|
| 1009 | + |
| 1010 | + |
| 1011 | +def sort_paths(*paths: PathLike) -> List[PathPlus]: |
| 1012 | + """ |
| 1013 | + Sort the ``paths`` by directory, then by file. |
| 1014 | +
|
| 1015 | + :param paths: |
| 1016 | +
|
| 1017 | + .. versionadded:: 2.6.0 |
| 1018 | + """ |
| 1019 | + |
| 1020 | + directories: Dict[str, List[PathPlus]] = defaultdict(list) |
| 1021 | + local_contents: List[PathPlus] = [] |
| 1022 | + files: List[PathPlus] = [] |
| 1023 | + |
| 1024 | + for obj in [PathPlus(path) for path in paths]: |
| 1025 | + if len(obj.parts) > 1: |
| 1026 | + key = obj.parts[0] |
| 1027 | + directories[key].append(obj) |
| 1028 | + else: |
| 1029 | + local_contents.append(obj) |
| 1030 | + |
| 1031 | + # sort directories |
| 1032 | + directories = {directory: directories[directory] for directory in sorted(directories.keys())} |
| 1033 | + |
| 1034 | + for directory, contents in directories.items(): |
| 1035 | + contents = [path.relative_to(directory) for path in contents] |
| 1036 | + files.extend(PathPlus(directory) / path for path in sort_paths(*contents)) |
| 1037 | + |
| 1038 | + return files + sorted(local_contents) |
0 commit comments