codekingpro/portable-devtools
115k
1import functools2import pathlib3from typing import Protocol, Union, runtime_checkable4 5####6# from jaraco.path 3.7.17 8 9class Symlink(str):10 """11 A string indicating the target of a symlink.12 """13 14 15FilesSpec = dict[str, Union[str, bytes, Symlink, 'FilesSpec']]16 17 18@runtime_checkable19class TreeMaker(Protocol):20 def __truediv__(self, *args, **kwargs): ... # pragma: no cover21 22 def mkdir(self, **kwargs): ... # pragma: no cover23 24 def write_text(self, content, **kwargs): ... # pragma: no cover25 26 def write_bytes(self, content): ... # pragma: no cover27 28 def symlink_to(self, target): ... # pragma: no cover29 30 31def _ensure_tree_maker(obj: str | TreeMaker) -> TreeMaker:32 return obj if isinstance(obj, TreeMaker) else pathlib.Path(obj) # type: ignore[return-value]33 34 35def build(36 spec: FilesSpec,37 prefix: str | TreeMaker = pathlib.Path(), # type: ignore[assignment]38):39 """40 Build a set of files/directories, as described by the spec.41 42 Each key represents a pathname, and the value represents43 the content. Content may be a nested directory.44 45 >>> spec = {46 ... 'README.txt': "A README file",47 ... "foo": {48 ... "__init__.py": "",49 ... "bar": {50 ... "__init__.py": "",51 ... },52 ... "baz.py": "# Some code",53 ... "bar.py": Symlink("baz.py"),54 ... },55 ... "bing": Symlink("foo"),56 ... }57 >>> target = getfixture('tmp_path')58 >>> build(spec, target)59 >>> target.joinpath('foo/baz.py').read_text(encoding='utf-8')60 '# Some code'61 >>> target.joinpath('bing/bar.py').read_text(encoding='utf-8')62 '# Some code'63 """64 for name, contents in spec.items():65 create(contents, _ensure_tree_maker(prefix) / name)66 67 68@functools.singledispatch69def create(content: str | bytes | FilesSpec, path):70 path.mkdir(exist_ok=True)71 build(content, prefix=path) # type: ignore[arg-type]72 73 74@create.register75def _(content: bytes, path):76 path.write_bytes(content)77 78 79@create.register80def _(content: str, path):81 path.write_text(content, encoding='utf-8')82 83 84@create.register85def _(content: Symlink, path):86 path.symlink_to(content)87 88 89# end from jaraco.path90####91 