1"""
2
3"""
4
5# Imports:
6from __future__ import annotations
7
8# ##-- stdlib imports
9import datetime
10import enum
11import functools as ftz
12import itertools as itz
13import logging as logmod
14import shutil
15from functools import partial
16from uuid import UUID, uuid1
17
18# ##-- end stdlib imports
19
20# ##-- 3rd party imports
21from jgdv import Proto
22from jgdv.structs.dkey import DKey, DKeyed
23from jgdv.structs.locator._interface import LocationMeta_e
24
25# ##-- end 3rd party imports
26
27# ##-- 1st party imports
28import doot
29import doot.errors
30
31# ##-- end 1st party imports
32
33# ##-| Local
34from . import ActionSpec, DootTask, TaskSpec
35
36# # End of Imports.
37
38# ##-- types
39# isort: off
40import abc
41import collections.abc
42from typing import TYPE_CHECKING, cast, assert_type, assert_never
43from typing import Generic, NewType
44# Protocols:
45from typing import Protocol, runtime_checkable
46# Typing Decorators:
47from typing import no_type_check, final, override, overload
48
49if TYPE_CHECKING:
50 import pathlib as pl
51 from .interface import TaskSpec_i, ActionSpec_i
52 from jgdv.structs.locator._interface import Location_p
53 from jgdv import Maybe
54 from typing import Final
55 from typing import ClassVar, Any, LiteralString
56 from typing import Never, Self, Literal
57 from typing import TypeGuard
58 from collections.abc import Iterable, Iterator, Callable, Generator
59 from collections.abc import Sequence, Mapping, MutableMapping, Hashable
60
61##--|
62from ._interface import Task_p
63
64# isort: on
65# ##-- end types
66
67##-- logging
68logging = logmod.getLogger(__name__)
69##-- end logging
70
71make_missing : Final[bool] = doot.config.on_fail(False).settings.commands.run.location_check.make_missing() # noqa: FBT003
72strict : Final[bool] = doot.config.on_fail(True).settings.commands.run.location_check.strict() # noqa: FBT003
73##--|
[docs]
74@Proto(Task_p)
75class CheckLocsTask(DootTask):
76 """ A Task for registered directories exist.
77 Will build missing if doot.config.startup.location_check.make_missing is true
78 """
79 task_name = "_locations::check"
80
81 def __init__(self, spec:TaskSpec_i=None):
82 actions : list[ActionSpec_i]
83 locations : list[Location_p]
84 match [DKey(x, implicit=True) for x in doot.locs]:
85 case []:
86 actions = []
87 case [*_]:
88 locations = [DKey(x, implicit=True) for x in doot.locs] # type: ignore[misc]
89 actions = [ActionSpec.build({"args": locations, "fun":self.checklocs })]
90
91 spec = {
92 "name" : CheckLocsTask.task_name,
93 "actions" : actions,
94 "priority" : 100,
95 }
96 super().__init__(TaskSpec(**spec))
97
[docs]
98 @DKeyed.args # type: ignore[attr-defined]
99 def checklocs(self, spec:ActionSpec_i, state:dict, args:list) -> None: # noqa: ARG002
100 path : pl.Path
101 ##--|
102 errors = []
103 for loc in args:
104 try:
105 if doot.locs.metacheck(loc, LocationMeta_e.file, LocationMeta_e.remote):
106 continue
107
108 path = doot.locs.Current[loc]
109 match path.exists():
110 case True:
111 logging.debug("Location Exists : %s", path)
112 case False if make_missing:
113 doot.report.wf.act(info="Check", msg=f"Making Missing Location: {path}")
114 path.mkdir(parents=True)
115 case False if strict:
116 errors.append(path)
117 case False:
118 doot.report.wf.act(info="Check", msg=f"Location Missing: {path}")
119 except PermissionError:
120 if strict:
121 errors.append(path)
122 doot.report.wf.act("Check", f"Location Permision Error: {loc}")
123 doot.report.wf.fail()
124 else:
125 if strict and bool(errors):
126 raise doot.errors.ConfigError("Missing Location(s)", errors)