mirror of
https://git.srhtnin.garden/sarah/SaraSort.git
synced 2026-10-15 02:53:17 +02:00
Directory configs outside their directories (SaraSortd 7.2)
SaraSort finds configs and history files where SaraSortd 7.2 keeps them (DirConfDir, [DirConfs]), and Settings > SaraSortd moves the existing ones between "inside each directory" and one folder. Imports keep [DirConfs] entries with moved directories, and Warnings flag a config folder inside an input or a SaraSortd older than 7.2. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
edc2832a0f
commit
28252e3101
5 files changed
+177
-20
No files matched your search
+12
-7
@@ -308,12 +308,17 @@ class ConfigPage(ft.Row):
|
|||||||
self._OpenCurrent()
|
self._OpenCurrent()
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def _KindOf(self, ConfPath: Path) -> str:
|
def _EntryOf(self, ConfPath: Path) -> tuple[str, str]:
|
||||||
|
"""(Kind, directory) of a config in the list. The directory is what
|
||||||
|
the list shows, since a config can live outside its directory."""
|
||||||
for _, Items in self._Entries():
|
for _, Items in self._Entries():
|
||||||
for _, ItemPath, Kind in Items:
|
for Label, ItemPath, Kind in Items:
|
||||||
if ItemPath == ConfPath:
|
if ItemPath == ConfPath:
|
||||||
return Kind
|
return Kind, Label
|
||||||
return "Global"
|
return "Global", ""
|
||||||
|
|
||||||
|
def _KindOf(self, ConfPath: Path) -> str:
|
||||||
|
return self._EntryOf(ConfPath)[0]
|
||||||
|
|
||||||
def _OpenCurrent(self) -> None:
|
def _OpenCurrent(self) -> None:
|
||||||
ConfPath = self.Current
|
ConfPath = self.Current
|
||||||
@@ -329,12 +334,12 @@ class ConfigPage(ft.Row):
|
|||||||
self.Mode = "Raw"
|
self.Mode = "Raw"
|
||||||
self.App.Notify(f"{ConfPath.name} isn't valid TOML ({Error}); showing it raw.", "warning")
|
self.App.Notify(f"{ConfPath.name} isn't valid TOML ({Error}); showing it raw.", "warning")
|
||||||
|
|
||||||
Kind = self._KindOf(ConfPath)
|
Kind, DirPath = self._EntryOf(ConfPath)
|
||||||
TheSetup = self.TheSetup
|
TheSetup = self.TheSetup
|
||||||
OutputStyle = Kind in ("Out", "OutTemplate") or (
|
OutputStyle = Kind in ("Out", "OutTemplate") or (
|
||||||
Kind == "In" and TheSetup.SharedConfName() and ConfPath.parent.as_posix() in TheSetup.Outputs
|
Kind == "In" and DirPath in TheSetup.Outputs and TheSetup.SharesConf(DirPath)
|
||||||
)
|
)
|
||||||
OutputPath = ConfPath.parent.as_posix() if Kind in ("In", "Out") else "/Output"
|
OutputPath = DirPath if Kind in ("In", "Out") else "/Output"
|
||||||
|
|
||||||
FormButton = ChipButton("Form", lambda e: self._SetMode("Form"))
|
FormButton = ChipButton("Form", lambda e: self._SetMode("Form"))
|
||||||
RawButton = ChipButton("Raw", lambda e: self._SetMode("Raw"))
|
RawButton = ChipButton("Raw", lambda e: self._SetMode("Raw"))
|
||||||
|
|||||||
@@ -36,7 +36,11 @@ own settings, and where SaraSortd lives. The SaraSortd tab also exports and impo
|
|||||||
configs as one file: GlobalConf.toml, both templates and every directory's own config, comments included.
|
configs as one file: GlobalConf.toml, both templates and every directory's own config, comments included.
|
||||||
Importing backs the current configs up to `~/.config/SaraSuite/SaraSort/Backups/` first. If directories it
|
Importing backs the current configs up to `~/.config/SaraSuite/SaraSort/Backups/` first. If directories it
|
||||||
uses don't exist, you can cancel, give any of them a new path (the configs and arrows follow), or have them
|
uses don't exist, you can cancel, give any of them a new path (the configs and arrows follow), or have them
|
||||||
made. Run as an AppImage, the header also has an "Add to app menu"
|
made. The same tab sets where SaraSortd keeps directory configs (7.2): inside each directory, or all
|
||||||
|
in one folder like SaraTag's Lexicons (`DirConfDir`, e.g. `Pictures_CatsConfig.toml`), and moves the
|
||||||
|
existing configs and history files there so no rules are lost. Single directories can also get their own
|
||||||
|
file through `[DirConfs]` in GlobalConf.toml, which SaraSort reads and edits like any other config.
|
||||||
|
Run as an AppImage, the header also has an "Add to app menu"
|
||||||
button, like SaraSuite's.
|
button, like SaraSuite's.
|
||||||
|
|
||||||
After a change to `GlobalConf.toml` (new inputs or outputs) SaraSort restarts SaraSortd, since SaraSortd
|
After a change to `GlobalConf.toml` (new inputs or outputs) SaraSort restarts SaraSortd, since SaraSortd
|
||||||
|
|||||||
+51
@@ -112,6 +112,49 @@ def ShowSettingsDialog(TheApp: App, OnSaved: Callable[[], None]) -> None:
|
|||||||
|
|
||||||
SortdFileField = ft.TextField(value=str(Home / "SaraSortd-Configs.toml"), label="SaraSortd export file path")
|
SortdFileField = ft.TextField(value=str(Home / "SaraSortd-Configs.toml"), label="SaraSortd export file path")
|
||||||
|
|
||||||
|
# Where directory configs live (SaraSortd 7.2's DirConfDir), like SaraTag's Lexicons folder.
|
||||||
|
try:
|
||||||
|
CurrentSetup = Setup(Config)
|
||||||
|
CurrentFolder = str(CurrentSetup.Dirs.get("DirConfDir", "") or "")
|
||||||
|
except SortdError:
|
||||||
|
CurrentSetup, CurrentFolder = None, ""
|
||||||
|
LocationPicker = ft.RadioGroup(
|
||||||
|
ft.Row([
|
||||||
|
ft.Radio(value="Inside", label="Inside each directory"),
|
||||||
|
ft.Radio(value="Folder", label="In one folder"),
|
||||||
|
]),
|
||||||
|
value="Folder" if CurrentFolder else "Inside",
|
||||||
|
disabled=CurrentSetup is None,
|
||||||
|
)
|
||||||
|
FolderRow, FolderField = DirField(TheApp, "Config folder (relative paths count from GlobalConf.toml's folder)",
|
||||||
|
CurrentFolder or "Dirs")
|
||||||
|
FolderRow.visible = bool(CurrentFolder)
|
||||||
|
|
||||||
|
def OnLocationChanged(e) -> None:
|
||||||
|
FolderRow.visible = LocationPicker.value == "Folder"
|
||||||
|
FolderRow.update()
|
||||||
|
|
||||||
|
LocationPicker.on_change = OnLocationChanged
|
||||||
|
|
||||||
|
def OnMoveConfs(e) -> None:
|
||||||
|
NewFolder = (FolderField.value or "").strip() if LocationPicker.value == "Folder" else ""
|
||||||
|
if LocationPicker.value == "Folder" and not NewFolder:
|
||||||
|
TheApp.Notify("Pick a folder for the configs.", "warning")
|
||||||
|
return
|
||||||
|
if NewFolder == CurrentFolder:
|
||||||
|
TheApp.Notify("The configs are already there.", "info")
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
Moved = Setup(Config).MoveDirConfs(NewFolder)
|
||||||
|
except (OSError, SortdError) as Error:
|
||||||
|
TheApp.Notify(f"Couldn't move the configs: {Error}", "error")
|
||||||
|
return
|
||||||
|
Page.pop_dialog()
|
||||||
|
OnSaved()
|
||||||
|
TheApp.AfterGlobalChange()
|
||||||
|
TheApp.Notify(f"Moved {Moved} file{'s' if Moved != 1 else ''}; directory configs now live "
|
||||||
|
f"{'in ' + NewFolder if NewFolder else 'inside each directory'}.", "success")
|
||||||
|
|
||||||
def OnSortdExport(e) -> None:
|
def OnSortdExport(e) -> None:
|
||||||
PathText = (SortdFileField.value or "").strip()
|
PathText = (SortdFileField.value or "").strip()
|
||||||
if not PathText:
|
if not PathText:
|
||||||
@@ -206,6 +249,14 @@ def ShowSettingsDialog(TheApp: App, OnSaved: Callable[[], None]) -> None:
|
|||||||
RefreshField,
|
RefreshField,
|
||||||
LogLinesField,
|
LogLinesField,
|
||||||
ft.Divider(height=1, color=Palette.Surface1),
|
ft.Divider(height=1, color=Palette.Surface1),
|
||||||
|
_Note("Where SaraSortd keeps each directory's config (and history file). In one folder, the "
|
||||||
|
"directories stay clean; each config is named after its directory, e.g. "
|
||||||
|
"Pictures_CatsConfig.toml. Needs SaraSortd 7.2. Moving takes the existing configs along."),
|
||||||
|
LocationPicker,
|
||||||
|
FolderRow,
|
||||||
|
ft.OutlinedButton(content="Move configs", style=ChipButtonStyle(), on_click=OnMoveConfs,
|
||||||
|
disabled=CurrentSetup is None),
|
||||||
|
ft.Divider(height=1, color=Palette.Surface1),
|
||||||
_Note("Export/import all of SaraSortd's configs as one file: GlobalConf.toml, both templates "
|
_Note("Export/import all of SaraSortd's configs as one file: GlobalConf.toml, both templates "
|
||||||
"and every input/output directory's own config. Importing replaces the current ones "
|
"and every input/output directory's own config. Importing replaces the current ones "
|
||||||
"(they're backed up first)."),
|
"(they're backed up first)."),
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import datetime
|
|||||||
import fnmatch
|
import fnmatch
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import shutil
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
@@ -38,6 +39,7 @@ def ReadToml(FilePath: Path) -> tomlkit.TOMLDocument:
|
|||||||
|
|
||||||
|
|
||||||
def WriteToml(FilePath: Path, Document: tomlkit.TOMLDocument) -> None:
|
def WriteToml(FilePath: Path, Document: tomlkit.TOMLDocument) -> None:
|
||||||
|
FilePath.parent.mkdir(parents=True, exist_ok=True) # configs can live outside their directory
|
||||||
FilePath.write_text(tomlkit.dumps(Document), encoding="utf-8")
|
FilePath.write_text(tomlkit.dumps(Document), encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
@@ -212,14 +214,97 @@ class Setup:
|
|||||||
return f"{Call[0]}RootDir{Call[1]}{PathText[len(Root):]}"
|
return f"{Call[0]}RootDir{Call[1]}{PathText[len(Root):]}"
|
||||||
return PathText
|
return PathText
|
||||||
|
|
||||||
|
def ConfFolder(self, PathText: str) -> Path:
|
||||||
|
"""SaraSortd's ConfFolder: relative paths count from GlobalConf.toml's folder."""
|
||||||
|
Parsed = self.Parse(str(PathText))
|
||||||
|
if os.path.isabs(Parsed):
|
||||||
|
return Path(os.path.normpath(Parsed))
|
||||||
|
return Path(os.path.normpath(self.GlobalPath.parent / Parsed))
|
||||||
|
|
||||||
|
def FlatName(self, DirPath: str) -> str:
|
||||||
|
"""SaraSortd's FlatName: "%RootDir%/Pictures/Cats" -> "Pictures_Cats"."""
|
||||||
|
Root = self.Parse(str(self.Dirs.get("RootDir", ""))).rstrip("/")
|
||||||
|
DirPath = DirPath.rstrip("/")
|
||||||
|
if Root and DirPath.startswith(Root + "/"):
|
||||||
|
Relative = DirPath[len(Root) + 1:]
|
||||||
|
else:
|
||||||
|
Relative = DirPath.strip("/") or os.path.basename(DirPath)
|
||||||
|
return Relative.replace("/", "_")
|
||||||
|
|
||||||
|
def CentralConf(self, DirPath: str, Kind: str) -> Optional[Path]:
|
||||||
|
"""SaraSortd 7.2: a config named in [DirConfs], or one in DirConfDir.
|
||||||
|
None when the config lives inside the directory."""
|
||||||
|
for Key, Value in (self.Data.get("DirConfs") or {}).items():
|
||||||
|
if self.Parse(str(Key)).rstrip("/") == DirPath.rstrip("/"):
|
||||||
|
if isinstance(Value, dict):
|
||||||
|
Value = Value.get(Kind)
|
||||||
|
if Value:
|
||||||
|
return self.ConfFolder(str(Value))
|
||||||
|
Folder = self.Dirs.get("DirConfDir")
|
||||||
|
if Folder:
|
||||||
|
Name = self.Parse(str(self.Names.get(NameKeys[Kind], ".@Config")), Parent=self.FlatName(DirPath)).lstrip(".")
|
||||||
|
return self.ConfFolder(str(Folder)) / f"{Name}.toml"
|
||||||
|
return None
|
||||||
|
|
||||||
def ConfFile(self, DirPath: str, Kind: str) -> Path:
|
def ConfFile(self, DirPath: str, Kind: str) -> Path:
|
||||||
"""A directory's own config, e.g. ~/Sorting/Output/.OutputConfig.toml."""
|
"""A directory's own config: inside it (e.g. ~/Sorting/Output/.OutputConfig.toml),
|
||||||
|
or wherever DirConfDir / [DirConfs] put it."""
|
||||||
|
Central = self.CentralConf(DirPath, Kind)
|
||||||
|
if Central:
|
||||||
|
return Central
|
||||||
Name = self.Parse(str(self.Names.get(NameKeys[Kind], ".@Config")), Parent=os.path.basename(DirPath))
|
Name = self.Parse(str(self.Names.get(NameKeys[Kind], ".@Config")), Parent=os.path.basename(DirPath))
|
||||||
return Path(DirPath) / f"{Name}.toml"
|
return Path(DirPath) / f"{Name}.toml"
|
||||||
|
|
||||||
def SharedConfName(self) -> bool:
|
def HistoryFile(self, DirPath: str) -> Optional[Path]:
|
||||||
"""Input and output configs use the same file name (both default to .@Config)."""
|
"""SaraSortd's HistoryPath: next to a config kept outside the directory, or inside it."""
|
||||||
return self.Names.get("InDirConfName") == self.Names.get("OutDirConfName")
|
HistoryName = self.Names.get("FileHistoryName")
|
||||||
|
if not HistoryName:
|
||||||
|
return None
|
||||||
|
Central = self.CentralConf(DirPath, "In") or self.CentralConf(DirPath, "Out")
|
||||||
|
if Central:
|
||||||
|
return Central.parent / f"{self.Parse(str(HistoryName), Parent=self.FlatName(DirPath)).lstrip('.')}.toml"
|
||||||
|
return Path(DirPath) / f"{self.Parse(str(HistoryName), Parent=os.path.basename(DirPath))}.toml"
|
||||||
|
|
||||||
|
def SharesConf(self, DirPath: str) -> bool:
|
||||||
|
"""Its input and output config are one file (the default .@Config names do that)."""
|
||||||
|
return self.ConfFile(DirPath, "In") == self.ConfFile(DirPath, "Out")
|
||||||
|
|
||||||
|
def CentralFolder(self) -> Optional[Path]:
|
||||||
|
Folder = self.Dirs.get("DirConfDir")
|
||||||
|
return self.ConfFolder(str(Folder)) if Folder else None
|
||||||
|
|
||||||
|
def MoveDirConfs(self, NewFolder: str) -> int:
|
||||||
|
"""Sets DirConfDir ("" = inside each directory) and moves every existing
|
||||||
|
directory config and history file to match, so no rules are lost.
|
||||||
|
Directories named in [DirConfs] stay where they are. Returns how many
|
||||||
|
files moved. Raises SortdError (before moving anything) when a file is
|
||||||
|
already where one would go."""
|
||||||
|
NewDoc = tomlkit.parse(tomlkit.dumps(self.Global))
|
||||||
|
NewDoc.setdefault("DirectoryPaths", tomlkit.table())["DirConfDir"] = NewFolder
|
||||||
|
After = Setup(self.Config, NewDoc)
|
||||||
|
Folder = After.CentralFolder()
|
||||||
|
for InputPath in self.Inputs:
|
||||||
|
if Folder and (Folder == Path(InputPath) or str(Folder).startswith(InputPath.rstrip("/") + "/")):
|
||||||
|
raise SortdError(f"{Folder} is inside the input {InputPath}; SaraSortd would sort its own configs away.")
|
||||||
|
Plan: dict[Path, Path] = {}
|
||||||
|
for DirPath in dict.fromkeys(self.Inputs + self.Outputs):
|
||||||
|
Kinds = (["In"] if DirPath in self.Inputs else []) + (["Out"] if DirPath in self.Outputs else [])
|
||||||
|
Pairs = [(self.ConfFile(DirPath, Kind), After.ConfFile(DirPath, Kind)) for Kind in Kinds]
|
||||||
|
Pairs.append((self.HistoryFile(DirPath), After.HistoryFile(DirPath)))
|
||||||
|
for Old, New in Pairs:
|
||||||
|
if Old and New and Old != New and Old.exists():
|
||||||
|
Plan[Old] = New
|
||||||
|
Taken = [New for New in Plan.values() if New.exists()]
|
||||||
|
if Taken:
|
||||||
|
raise SortdError(f"Not moved: {', '.join(str(New) for New in Taken)} already exist(s).")
|
||||||
|
for Old, New in Plan.items():
|
||||||
|
New.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
shutil.move(str(Old), str(New))
|
||||||
|
WriteToml(self.GlobalPath, NewDoc)
|
||||||
|
self.Global = NewDoc
|
||||||
|
self.Data = NewDoc.unwrap()
|
||||||
|
self.Dirs = self.Data.get("DirectoryPaths", {})
|
||||||
|
return len(Plan)
|
||||||
|
|
||||||
def TemplatePath(self, Kind: str) -> Path:
|
def TemplatePath(self, Kind: str) -> Path:
|
||||||
return self.ConfDir / TemplateNames[Kind]
|
return self.ConfDir / TemplateNames[Kind]
|
||||||
@@ -364,7 +449,7 @@ class Setup:
|
|||||||
else:
|
else:
|
||||||
Document = self._NewDirConf(DirPath, Kind)
|
Document = self._NewDirConf(DirPath, Kind)
|
||||||
IsNew = True
|
IsNew = True
|
||||||
if self.SharedConfName() and DirPath in self.Inputs and DirPath in self.Outputs:
|
if DirPath in self.Inputs and DirPath in self.Outputs and self.SharesConf(DirPath):
|
||||||
# One file for both roles: make sure it has the keys both read.
|
# One file for both roles: make sure it has the keys both read.
|
||||||
Other = "In" if Kind == "Out" else "Out"
|
Other = "In" if Kind == "Out" else "Out"
|
||||||
OtherTemplate = ReadToml(self.TemplatePath(Other))
|
OtherTemplate = ReadToml(self.TemplatePath(Other))
|
||||||
@@ -469,7 +554,7 @@ class Setup:
|
|||||||
# When the input is also an output and both use one config file, its
|
# When the input is also an output and both use one config file, its
|
||||||
# [[Files]] are output rules too: an input-only entry (no NewFileName)
|
# [[Files]] are output rules too: an input-only entry (no NewFileName)
|
||||||
# would crash SaraSortd, so leave them alone.
|
# would crash SaraSortd, so leave them alone.
|
||||||
SharedFile = self.SharedConfName() and InputPath in self.Outputs
|
SharedFile = InputPath in self.Outputs and self.SharesConf(InputPath)
|
||||||
if "*" not in InPatterns and not SharedFile:
|
if "*" not in InPatterns and not SharedFile:
|
||||||
for Pattern in Patterns:
|
for Pattern in Patterns:
|
||||||
if Pattern not in InPatterns:
|
if Pattern not in InPatterns:
|
||||||
@@ -613,12 +698,8 @@ class Setup:
|
|||||||
WriteToml(ConfPath, Document)
|
WriteToml(ConfPath, Document)
|
||||||
|
|
||||||
GlobalChanged = self.RemoveDir(PathText)
|
GlobalChanged = self.RemoveDir(PathText)
|
||||||
Parent = os.path.basename(PathText)
|
Leftovers = {self.ConfFile(PathText, "In"), self.ConfFile(PathText, "Out"), self.HistoryFile(PathText)}
|
||||||
Leftovers = {self.ConfFile(PathText, "In"), self.ConfFile(PathText, "Out")}
|
for FilePath in filter(None, Leftovers):
|
||||||
HistoryName = self.Names.get("FileHistoryName")
|
|
||||||
if HistoryName:
|
|
||||||
Leftovers.add(Path(PathText) / f"{self.Parse(str(HistoryName), Parent=Parent)}.toml")
|
|
||||||
for FilePath in Leftovers:
|
|
||||||
FilePath.unlink(missing_ok=True)
|
FilePath.unlink(missing_ok=True)
|
||||||
return GlobalChanged
|
return GlobalChanged
|
||||||
|
|
||||||
@@ -777,6 +858,15 @@ class Setup:
|
|||||||
Found.append(("Warning", f"{CatchAll} takes every file from {InputPath} first, so {FoundEdge.Output} never gets any ({', '.join(FoundEdge.Patterns)})."))
|
Found.append(("Warning", f"{CatchAll} takes every file from {InputPath} first, so {FoundEdge.Output} never gets any ({', '.join(FoundEdge.Patterns)})."))
|
||||||
elif "*" in FoundEdge.Patterns:
|
elif "*" in FoundEdge.Patterns:
|
||||||
CatchAll = FoundEdge.Output
|
CatchAll = FoundEdge.Output
|
||||||
|
Central = self.CentralFolder()
|
||||||
|
if (Central or self.Data.get("DirConfs")) and Daemon and not VersionAtLeast(Daemon, (7, 2)):
|
||||||
|
Found.append(("Error", f"Directory configs are kept outside their directories (DirConfDir / [DirConfs]), "
|
||||||
|
f"which SaraSortd {Daemon} doesn't know about. Update SaraSortd to 7.2."))
|
||||||
|
if Central:
|
||||||
|
for InputPath in Inputs:
|
||||||
|
if Central == Path(InputPath) or str(Central).startswith(InputPath.rstrip("/") + "/"):
|
||||||
|
Found.append(("Error", f"DirConfDir ({Central}) is inside the input {InputPath}, so SaraSortd "
|
||||||
|
"would sort its own configs away."))
|
||||||
if UsesOwnInputs and Daemon and not VersionAtLeast(Daemon, (7, 1)):
|
if UsesOwnInputs and Daemon and not VersionAtLeast(Daemon, (7, 1)):
|
||||||
Found.append(("Error", f"Some [[Files]] entries have their own ValidInputDirs, which SaraSortd {Daemon} ignores. Update SaraSortd to 7.1."))
|
Found.append(("Error", f"Some [[Files]] entries have their own ValidInputDirs, which SaraSortd {Daemon} ignores. Update SaraSortd to 7.1."))
|
||||||
|
|
||||||
|
|||||||
@@ -172,6 +172,13 @@ def ApplyBundle(Config: AppConfig, TheBundle: Bundle, Remap: dict[str, str]) ->
|
|||||||
Paths = GlobalDoc.get("DirectoryPaths", {})
|
Paths = GlobalDoc.get("DirectoryPaths", {})
|
||||||
for Key in ("InputDir", "OutputDir"):
|
for Key in ("InputDir", "OutputDir"):
|
||||||
_RemapList(TheSetup, Paths.get(Key), Remap)
|
_RemapList(TheSetup, Paths.get(Key), Remap)
|
||||||
|
# A moved directory keeps its own config file from [DirConfs] (SaraSortd 7.2).
|
||||||
|
DirConfs = GlobalDoc.get("DirConfs")
|
||||||
|
for Key in list(DirConfs.keys()) if DirConfs is not None else []:
|
||||||
|
Resolved = TheSetup.Parse(str(Key)).rstrip("/")
|
||||||
|
if Resolved in Remap:
|
||||||
|
DirConfs[TheSetup.Shorthand(Remap[Resolved])] = DirConfs[Key]
|
||||||
|
del DirConfs[Key]
|
||||||
|
|
||||||
ConfDir = Path(Config.SortdConfigDir).expanduser()
|
ConfDir = Path(Config.SortdConfigDir).expanduser()
|
||||||
ConfDir.mkdir(parents=True, exist_ok=True)
|
ConfDir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|||||||
Reference in new issue
Block a user