machineconfig 7.38__py3-none-any.whl → 7.39__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of machineconfig might be problematic. Click here for more details.
- machineconfig/profile/create_links.py +2 -1
- machineconfig/profile/create_links_export.py +37 -8
- machineconfig/profile/create_shell_profile.py +64 -124
- machineconfig/scripts/linux/wrap_mcfg +1 -1
- machineconfig/scripts/python/croshell.py +4 -4
- machineconfig/scripts/python/define.py +1 -1
- machineconfig/scripts/python/env_manager/path_manager_tui.py +1 -1
- machineconfig/scripts/python/helpers_devops/cli_config.py +27 -32
- machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +12 -9
- machineconfig/scripts/python/helpers_devops/cli_repos.py +11 -10
- machineconfig/scripts/python/helpers_devops/cli_self.py +5 -7
- machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py +34 -15
- machineconfig/scripts/python/helpers_repos/count_lines_frontend.py +1 -1
- machineconfig/scripts/python/machineconfig.py +7 -0
- machineconfig/scripts/python/terminal.py +20 -3
- machineconfig/scripts/windows/mounts/mount_ssh.ps1 +1 -1
- machineconfig/scripts/windows/wrap_mcfg.ps1 +5 -0
- machineconfig/settings/shells/nushell/config.nu +1 -31
- machineconfig/settings/shells/nushell/init.nu +100 -34
- machineconfig/settings/shells/wt/settings.json +10 -2
- machineconfig/setup_linux/web_shortcuts/interactive.sh +10 -10
- machineconfig/setup_windows/web_shortcuts/interactive.ps1 +10 -10
- machineconfig/utils/code.py +1 -1
- machineconfig/utils/links.py +3 -2
- machineconfig/utils/ssh.py +1 -1
- {machineconfig-7.38.dist-info → machineconfig-7.39.dist-info}/METADATA +1 -1
- {machineconfig-7.38.dist-info → machineconfig-7.39.dist-info}/RECORD +30 -31
- machineconfig/scripts/python/helpers_repos/secure_repo.py +0 -15
- {machineconfig-7.38.dist-info → machineconfig-7.39.dist-info}/WHEEL +0 -0
- {machineconfig-7.38.dist-info → machineconfig-7.39.dist-info}/entry_points.txt +0 -0
- {machineconfig-7.38.dist-info → machineconfig-7.39.dist-info}/top_level.txt +0 -0
|
@@ -13,6 +13,7 @@ from rich.table import Table
|
|
|
13
13
|
|
|
14
14
|
from machineconfig.utils.path_extended import PathExtended
|
|
15
15
|
from machineconfig.utils.links import symlink_map, copy_map
|
|
16
|
+
from machineconfig.profile.create_links_export import ON_CONFLICT_STRICT
|
|
16
17
|
from machineconfig.utils.source_of_truth import LIBRARY_ROOT, CONFIG_ROOT
|
|
17
18
|
|
|
18
19
|
import platform
|
|
@@ -79,7 +80,7 @@ def read_mapper() -> MapperFileData:
|
|
|
79
80
|
|
|
80
81
|
|
|
81
82
|
def apply_mapper(mapper_data: dict[str, list[ConfigMapper]],
|
|
82
|
-
on_conflict:
|
|
83
|
+
on_conflict: ON_CONFLICT_STRICT,
|
|
83
84
|
method: Literal["symlink", "copy"]
|
|
84
85
|
):
|
|
85
86
|
operation_records: list[OperationRecord] = []
|
|
@@ -1,10 +1,26 @@
|
|
|
1
1
|
|
|
2
2
|
import typer
|
|
3
|
-
from typing import Optional, Literal, Annotated
|
|
3
|
+
from typing import Optional, Literal, Annotated, TypeAlias
|
|
4
4
|
|
|
5
|
+
ON_CONFLICT_LOOSE: TypeAlias = Literal[
|
|
6
|
+
"throw-error", "t",
|
|
7
|
+
"overwrite-self-managed", "os",
|
|
8
|
+
"backup-self-managed", "bs",
|
|
9
|
+
"overwrite-default-path", "od",
|
|
10
|
+
"backup-default-path", "bd"
|
|
11
|
+
]
|
|
12
|
+
ON_CONFLICT_STRICT: TypeAlias = Literal["throw-error", "overwrite-self-managed", "backup-self-managed", "overwrite-default-path", "backup-default-path"]
|
|
13
|
+
ON_CONFLICT_MAPPER: dict[str, ON_CONFLICT_STRICT] = {
|
|
14
|
+
"t": "throw-error",
|
|
15
|
+
"os": "overwrite-self-managed",
|
|
16
|
+
"bs": "backup-self-managed",
|
|
17
|
+
"od": "overwrite-default-path",
|
|
18
|
+
"bd": "backup-default-path"
|
|
19
|
+
}
|
|
5
20
|
|
|
6
|
-
|
|
7
|
-
|
|
21
|
+
|
|
22
|
+
def main_public_from_parser(method: Annotated[Literal["symlink", "s", "copy", "c"], typer.Option(..., help="Method to use for setting up the config file.")],
|
|
23
|
+
on_conflict: Annotated[ON_CONFLICT_LOOSE, typer.Option(..., help="Action to take on conflict")],
|
|
8
24
|
which: Annotated[Optional[str], typer.Option(..., help="Specific items to process")] = None,
|
|
9
25
|
interactive: Annotated[bool, typer.Option(..., help="Run in interactive mode")] = False):
|
|
10
26
|
"""Terminology:
|
|
@@ -28,15 +44,21 @@ def main_public_from_parser(method: Annotated[Literal["symlink", "copy"], typer.
|
|
|
28
44
|
from machineconfig.profile.create_links import apply_mapper
|
|
29
45
|
from machineconfig.profile.create_helper import copy_assets_to_machine
|
|
30
46
|
copy_assets_to_machine(which="settings") # config files live here and will be linked to.
|
|
31
|
-
|
|
47
|
+
method_map: dict[str, Literal["symlink", "copy"]] = {
|
|
48
|
+
"s": "symlink",
|
|
49
|
+
"symlink": "symlink",
|
|
50
|
+
"c": "copy",
|
|
51
|
+
"copy": "copy",
|
|
52
|
+
}
|
|
53
|
+
method = method_map[method]
|
|
54
|
+
apply_mapper(mapper_data=items_objections, on_conflict=ON_CONFLICT_MAPPER[on_conflict], method=method)
|
|
32
55
|
|
|
33
56
|
|
|
34
|
-
def main_private_from_parser(method: Annotated[Literal["symlink", "copy"], typer.Option(..., help="Method to use for linking files")],
|
|
35
|
-
on_conflict: Annotated[
|
|
57
|
+
def main_private_from_parser(method: Annotated[Literal["symlink", "s", "copy", "c"], typer.Option(..., help="Method to use for linking files")],
|
|
58
|
+
on_conflict: Annotated[ON_CONFLICT_LOOSE, typer.Option(..., help="Action to take on conflict")] = "throw-error",
|
|
36
59
|
which: Annotated[Optional[str], typer.Option(..., help="Specific items to process")] = None,
|
|
37
60
|
interactive: Annotated[bool, typer.Option(..., help="Run in interactive mode")] = False):
|
|
38
61
|
from machineconfig.profile.create_links import ConfigMapper, read_mapper
|
|
39
|
-
|
|
40
62
|
mapper_full = read_mapper()["private"]
|
|
41
63
|
if which is None:
|
|
42
64
|
assert interactive is True
|
|
@@ -51,4 +73,11 @@ def main_private_from_parser(method: Annotated[Literal["symlink", "copy"], typer
|
|
|
51
73
|
items_objections: dict[str, list[ConfigMapper]] = {item: mapper_full[item] for item in items_chosen if item in mapper_full}
|
|
52
74
|
|
|
53
75
|
from machineconfig.profile.create_links import apply_mapper
|
|
54
|
-
|
|
76
|
+
method_map: dict[str, Literal["symlink", "copy"]] = {
|
|
77
|
+
"s": "symlink",
|
|
78
|
+
"symlink": "symlink",
|
|
79
|
+
"c": "copy",
|
|
80
|
+
"copy": "copy",
|
|
81
|
+
}
|
|
82
|
+
method = method_map[method]
|
|
83
|
+
apply_mapper(mapper_data=items_objections, on_conflict=ON_CONFLICT_MAPPER[on_conflict], method=method)
|
|
@@ -1,23 +1,16 @@
|
|
|
1
1
|
"""shell"""
|
|
2
2
|
|
|
3
|
-
from machineconfig.utils.path_extended import PathExtended
|
|
4
|
-
from machineconfig.utils.source_of_truth import CONFIG_ROOT
|
|
5
3
|
from pathlib import Path
|
|
6
|
-
import platform
|
|
7
|
-
import os
|
|
8
|
-
import subprocess
|
|
9
|
-
from rich.console import Console
|
|
10
|
-
from rich.panel import Panel
|
|
11
4
|
|
|
12
5
|
|
|
13
|
-
system = platform.system()
|
|
14
|
-
sep = ";" if system == "Windows" else ":" # PATH separator, this is special for PATH object, not to be confused with PathExtended.sep (normal paths), usually / or \
|
|
15
|
-
PATH = os.environ["PATH"].split(sep)
|
|
16
|
-
console = Console()
|
|
17
|
-
BOX_WIDTH = 100 # Define BOX_WIDTH or get it from a config
|
|
18
|
-
|
|
19
6
|
|
|
20
7
|
def get_shell_profile_path() -> Path:
|
|
8
|
+
import platform
|
|
9
|
+
import subprocess
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
from rich.panel import Panel
|
|
12
|
+
system = platform.system()
|
|
13
|
+
console = Console()
|
|
21
14
|
if system == "Windows":
|
|
22
15
|
result = subprocess.run(["pwsh", "-Command", "$PROFILE"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False)
|
|
23
16
|
if result.returncode == 0 and result.stdout.strip():
|
|
@@ -37,8 +30,34 @@ def get_shell_profile_path() -> Path:
|
|
|
37
30
|
return profile_path
|
|
38
31
|
|
|
39
32
|
|
|
33
|
+
def get_nu_shell_profile_path() -> Path:
|
|
34
|
+
import platform
|
|
35
|
+
from rich.console import Console
|
|
36
|
+
from rich.panel import Panel
|
|
37
|
+
system = platform.system()
|
|
38
|
+
console = Console()
|
|
39
|
+
if system == "Windows":
|
|
40
|
+
profile_path = Path.home().joinpath(r"AppData\Roaming\nushell")
|
|
41
|
+
elif system == "Linux":
|
|
42
|
+
profile_path = Path.home().joinpath(".config/nushell")
|
|
43
|
+
elif system == "Darwin":
|
|
44
|
+
profile_path = Path.home().joinpath("Library/Application Support/nushell")
|
|
45
|
+
else:
|
|
46
|
+
raise ValueError(f"""Not implemented for this system {system}""")
|
|
47
|
+
console.print(Panel(f"""🐚 NU SHELL PROFILE | Working with path: `{profile_path}`""", title="[bold cyan]Nu Shell Profile[/bold cyan]", border_style="cyan"))
|
|
48
|
+
return profile_path
|
|
49
|
+
|
|
50
|
+
|
|
40
51
|
def create_default_shell_profile() -> None:
|
|
41
52
|
shell_profile_path = get_shell_profile_path()
|
|
53
|
+
import platform
|
|
54
|
+
import subprocess
|
|
55
|
+
from rich.console import Console
|
|
56
|
+
from rich.panel import Panel
|
|
57
|
+
from machineconfig.utils.source_of_truth import CONFIG_ROOT
|
|
58
|
+
from machineconfig.utils.path_extended import PathExtended
|
|
59
|
+
system = platform.system()
|
|
60
|
+
console = Console()
|
|
42
61
|
if not shell_profile_path.exists():
|
|
43
62
|
console.print(Panel(f"""🆕 PROFILE | Profile does not exist at `{shell_profile_path}`. Creating a new one.""", title="[bold blue]Profile[/bold blue]", border_style="blue"))
|
|
44
63
|
shell_profile_path.parent.mkdir(parents=True, exist_ok=True)
|
|
@@ -79,117 +98,38 @@ def create_default_shell_profile() -> None:
|
|
|
79
98
|
console.print(Panel("✅ Profile updated successfully", title="[bold blue]Profile[/bold blue]", border_style="blue"))
|
|
80
99
|
|
|
81
100
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
# console.print(Panel("🔄 Adding sources to shell profile", title="[bold blue]Sources[/bold blue]", border_style="blue"))
|
|
115
|
-
|
|
116
|
-
# if choice is None:
|
|
117
|
-
# choice_obj = choose_from_options(msg="Which patch to add?", options=sources + ["all", "none(EXIT)"], default="none(EXIT)", multi=True)
|
|
118
|
-
# if isinstance(choice_obj, str):
|
|
119
|
-
# if choice_obj == "all":
|
|
120
|
-
# choice = choice_obj
|
|
121
|
-
# elif choice_obj == "none(EXIT)":
|
|
122
|
-
# return
|
|
123
|
-
# else:
|
|
124
|
-
# sources = [choice_obj]
|
|
125
|
-
# else: # isinstance(choice_obj, list):
|
|
126
|
-
# sources = choice_obj
|
|
127
|
-
# elif choice == "none(EXIT)":
|
|
128
|
-
# return
|
|
129
|
-
|
|
130
|
-
# if isinstance(profile_path, str):
|
|
131
|
-
# profile_path_obj = PathExtended(profile_path)
|
|
132
|
-
# else:
|
|
133
|
-
# profile_path_obj = get_shell_profile_path()
|
|
134
|
-
# profile = profile_path_obj.read_text(encoding="utf-8")
|
|
135
|
-
|
|
136
|
-
# for a_file in sources:
|
|
137
|
-
# tmp = a_file.replace("REPO_ROOT", REPO_ROOT.as_posix()).replace("LIBRARY_ROOT", LIBRARY_ROOT.as_posix())
|
|
138
|
-
# file = PathExtended(tmp).collapseuser() # this makes the shell profile interuseable across machines.
|
|
139
|
-
# file = file.as_posix() if system == "Linux" else str(file)
|
|
140
|
-
# if file not in profile:
|
|
141
|
-
# if system == "Windows":
|
|
142
|
-
# profile += f"\n. {file}"
|
|
143
|
-
# console.print(f"➕ Added PowerShell source: {file}")
|
|
144
|
-
# elif system == "Linux":
|
|
145
|
-
# profile += f"\nsource {file}"
|
|
146
|
-
# console.print(f"➕ Added Bash source: {file}")
|
|
147
|
-
# else:
|
|
148
|
-
# raise ValueError(f"Not implemented for this system {system}")
|
|
149
|
-
# else:
|
|
150
|
-
# console.print(f"⏭️ Source already present: {file}")
|
|
151
|
-
|
|
152
|
-
# profile_path_obj.write_text(profile, encoding="utf-8")
|
|
153
|
-
# console.print(Panel("✅ Shell profile updated with sources", title="[bold blue]Sources[/bold blue]", border_style="blue"))
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
# def main_add_patches_to_shell_profile(profile_path: Optional[str], choice: Optional[str]) -> None:
|
|
157
|
-
# patches: list[str] = [item.as_posix() for item in PathExtended(LIBRARY_ROOT).joinpath(f"profile/patches/{system.lower()}").search()]
|
|
158
|
-
|
|
159
|
-
# console.print(Panel("🩹 Adding patches to shell profile", title="[bold blue]Patches[/bold blue]", border_style="blue"))
|
|
160
|
-
|
|
161
|
-
# if choice is None:
|
|
162
|
-
# choice_chosen = choose_from_options(msg="Which patch to add?", options=list(patches) + ["all", "none(EXIT)"], default="none(EXIT)", multi=False)
|
|
163
|
-
# assert isinstance(choice_chosen, str), f"Choice must be a string or a list of strings, not {type(choice)}"
|
|
164
|
-
# choice = choice_chosen
|
|
165
|
-
# if choice == "none(EXIT)":
|
|
166
|
-
# return None
|
|
167
|
-
# elif str(choice) == "all":
|
|
168
|
-
# console.print("📌 Adding all patches to profile")
|
|
169
|
-
# else:
|
|
170
|
-
# patches = [choice]
|
|
171
|
-
# console.print(f"📌 Adding selected patch: {choice}")
|
|
172
|
-
|
|
173
|
-
# profile_path_obj = PathExtended(profile_path) if isinstance(profile_path, str) else get_shell_profile_path()
|
|
174
|
-
# profile = profile_path_obj.read_text(encoding="utf-8")
|
|
175
|
-
|
|
176
|
-
# for patch_path in patches:
|
|
177
|
-
# patch_path_obj = PathExtended(patch_path)
|
|
178
|
-
# patch = patch_path_obj.read_text(encoding="utf-8")
|
|
179
|
-
# if patch in profile:
|
|
180
|
-
# console.print(f"⏭️ Patch already present: {patch_path_obj.name}")
|
|
181
|
-
# else:
|
|
182
|
-
# profile += "\n" + patch
|
|
183
|
-
# console.print(f"➕ Added patch: {patch_path_obj.name}")
|
|
184
|
-
|
|
185
|
-
# if system == "Linux":
|
|
186
|
-
# res = Terminal().run("cat /proc/version").op
|
|
187
|
-
# if "microsoft" in res.lower() or "wsl" in res.lower():
|
|
188
|
-
# profile += "\ncd ~" # this is to make sure that the current dir is not in the windows file system, which is terribly slow and its a bad idea to be there anyway.
|
|
189
|
-
# console.print("📌 WSL detected - adding 'cd ~' to profile to avoid Windows filesystem")
|
|
190
|
-
|
|
191
|
-
# profile_path_obj.write_text(profile, encoding="utf-8")
|
|
192
|
-
# console.print(Panel("✅ Shell profile updated with patches", title="[bold blue]Patches[/bold blue]", border_style="blue"))
|
|
101
|
+
def create_nu_shell_profile() -> None:
|
|
102
|
+
from rich.console import Console
|
|
103
|
+
from rich.panel import Panel
|
|
104
|
+
from machineconfig.utils.source_of_truth import CONFIG_ROOT
|
|
105
|
+
from machineconfig.utils.path_extended import PathExtended
|
|
106
|
+
console = Console()
|
|
107
|
+
nu_profile_path = get_nu_shell_profile_path()
|
|
108
|
+
config_dir = nu_profile_path
|
|
109
|
+
config_file = config_dir.joinpath("config.nu")
|
|
110
|
+
if not config_dir.exists():
|
|
111
|
+
console.print(Panel(f"""🆕 NU SHELL CONFIG | Config directory does not exist at `{config_dir}`. Creating a new one.""", title="[bold cyan]Nu Shell Config[/bold cyan]", border_style="cyan"))
|
|
112
|
+
config_dir.mkdir(parents=True, exist_ok=True)
|
|
113
|
+
if not config_file.exists():
|
|
114
|
+
console.print(Panel(f"""🆕 NU SHELL CONFIG | config.nu file does not exist at `{config_file}`. Creating a new one.""", title="[bold cyan]Nu Shell Config[/bold cyan]", border_style="cyan"))
|
|
115
|
+
config_file.write_text("", encoding="utf-8")
|
|
116
|
+
config_content = config_file.read_text(encoding="utf-8")
|
|
117
|
+
from machineconfig.profile.create_helper import copy_assets_to_machine
|
|
118
|
+
copy_assets_to_machine("settings")
|
|
119
|
+
copy_assets_to_machine("scripts")
|
|
120
|
+
init_script = PathExtended(CONFIG_ROOT).joinpath("settings/shells/nushell/init.nu")
|
|
121
|
+
source_line = f"""use {str(init_script)}"""
|
|
122
|
+
was_config_updated = False
|
|
123
|
+
if source_line in config_content:
|
|
124
|
+
console.print(Panel("🔄 NU SHELL CONFIG | Skipping init script sourcing - already present in config.nu", title="[bold cyan]Nu Shell Config[/bold cyan]", border_style="cyan"))
|
|
125
|
+
else:
|
|
126
|
+
console.print(Panel("📝 NU SHELL CONFIG | Adding init script sourcing to config.nu", title="[bold cyan]Nu Shell Config[/bold cyan]", border_style="cyan"))
|
|
127
|
+
config_content += "\n" + source_line + "\n"
|
|
128
|
+
was_config_updated = True
|
|
129
|
+
if was_config_updated:
|
|
130
|
+
config_dir.mkdir(parents=True, exist_ok=True)
|
|
131
|
+
config_file.write_text(config_content, encoding="utf-8")
|
|
132
|
+
console.print(Panel("✅ Nu shell config updated successfully", title="[bold cyan]Nu Shell Config[/bold cyan]", border_style="cyan"))
|
|
193
133
|
|
|
194
134
|
|
|
195
135
|
if __name__ == "__main__":
|
|
@@ -27,7 +27,7 @@ wrap_in_shell_script() {
|
|
|
27
27
|
|
|
28
28
|
if [[ -f "$OP_PROGRAM_PATH" ]]; then
|
|
29
29
|
printf "%b\n" "${GREEN}🚀 Taking over from python script @ ${OP_PROGRAM_PATH}${RESET}"
|
|
30
|
-
bat --style=
|
|
30
|
+
bat --style=full --theme=OneHalfDark --paging=never "$OP_PROGRAM_PATH"
|
|
31
31
|
printf "%b\n" "${GREEN}▶ Running...${RESET}"
|
|
32
32
|
. "$OP_PROGRAM_PATH"
|
|
33
33
|
status=$?
|
|
@@ -130,7 +130,7 @@ def croshell(
|
|
|
130
130
|
fire_line = f"uv run --python 3.14 --with visidata,pyarrow vd {str(file_obj)}"
|
|
131
131
|
elif marimo:
|
|
132
132
|
if Path.home().joinpath("code/machineconfig").exists(): requirements = f"""--with marimo --project "{str(Path.home().joinpath("code/machineconfig"))}" """
|
|
133
|
-
else: requirements = """--python 3.14 --with "marimo,machineconfig[plot]>=7.
|
|
133
|
+
else: requirements = """--python 3.14 --with "marimo,machineconfig[plot]>=7.39" """
|
|
134
134
|
fire_line = f"""
|
|
135
135
|
cd {str(pyfile.parent)}
|
|
136
136
|
uv run --python 3.14 --with "marimo" marimo convert {pyfile.name} -o marimo_nb.py
|
|
@@ -138,14 +138,14 @@ uv run {requirements} marimo edit --host 0.0.0.0 marimo_nb.py
|
|
|
138
138
|
"""
|
|
139
139
|
elif jupyter:
|
|
140
140
|
if Path.home().joinpath("code/machineconfig").exists(): requirements = f"""--project "{str(Path.home().joinpath("code/machineconfig"))}" --with jupyterlab """
|
|
141
|
-
else: requirements = """--with "machineconfig[plot]>=7.
|
|
141
|
+
else: requirements = """--with "machineconfig[plot]>=7.39" """
|
|
142
142
|
fire_line = f"uv run {requirements} jupyter-lab {str(nb_target)}"
|
|
143
143
|
elif vscode:
|
|
144
144
|
fire_line = f"""
|
|
145
145
|
cd {str(pyfile.parent)}
|
|
146
146
|
uv init --python 3.14
|
|
147
147
|
uv venv
|
|
148
|
-
uv add "machineconfig[plot]>=7.
|
|
148
|
+
uv add "machineconfig[plot]>=7.39"
|
|
149
149
|
# code serve-web
|
|
150
150
|
code --new-window {str(pyfile)}
|
|
151
151
|
"""
|
|
@@ -153,7 +153,7 @@ code --new-window {str(pyfile)}
|
|
|
153
153
|
if interpreter == "ipython": profile = f" --profile {ipython_profile} --no-banner"
|
|
154
154
|
else: profile = ""
|
|
155
155
|
if Path.home().joinpath("code/machineconfig").exists(): ve_line = f"""--project "{str(Path.home().joinpath("code/machineconfig"))}" """
|
|
156
|
-
else: ve_line = """--python 3.14 --with "machineconfig[plot]>=7.
|
|
156
|
+
else: ve_line = """--python 3.14 --with "machineconfig[plot]>=7.39" """
|
|
157
157
|
# ve_path_maybe, ipython_profile_maybe = get_ve_path_and_ipython_profile(Path.cwd())
|
|
158
158
|
# --python 3.14
|
|
159
159
|
fire_line = f"uv run {ve_line} {interpreter} {interactivity} {profile} {str(pyfile)}"
|
|
@@ -5,10 +5,10 @@ Minimalist programs that only print scripts without frills so it can be sourced
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
import typer
|
|
8
|
-
import platform
|
|
9
8
|
|
|
10
9
|
|
|
11
10
|
def define_scripts():
|
|
11
|
+
import platform
|
|
12
12
|
if platform.system() != "Linux":
|
|
13
13
|
raise RuntimeError("This command is only supported on Linux systems.")
|
|
14
14
|
from machineconfig.setup_linux import INTERACTIVE as script_path
|
|
@@ -1,33 +1,22 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
from typing import Literal, Annotated
|
|
3
|
+
from typing import Literal, Annotated
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
import typer
|
|
6
6
|
import machineconfig.scripts.python.helpers_devops.cli_config_dotfile as dotfile_module
|
|
7
|
+
import machineconfig.profile.create_links_export as create_links_export
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
def private(method: Annotated[Literal["symlink", "copy"], typer.Option(..., "--method", "-m", help="Method to use for linking files")],
|
|
10
|
-
on_conflict: Annotated[Literal["throw-error", "overwrite-self-managed", "backup-self-managed", "overwrite-default-path", "backup-default-path"], typer.Option(..., "--on-conflict", "-o", help="Action to take on conflict")] = "throw-error",
|
|
11
|
-
which: Annotated[Optional[str], typer.Option(..., "--which", "-w", help="Specific items to process")] = None,
|
|
12
|
-
interactive: Annotated[bool, typer.Option(..., "--interactive", "-ia", help="Run in interactive mode")] = False):
|
|
13
|
-
"""🔗 Manage private configuration files."""
|
|
14
|
-
import machineconfig.profile.create_links_export as create_links_export
|
|
15
|
-
create_links_export.main_private_from_parser(method=method, on_conflict=on_conflict, which=which, interactive=interactive)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def public(method: Annotated[Literal["symlink", "copy"], typer.Option(..., "--method", "-m", help="Method to use for setting up the config file.")],
|
|
19
|
-
on_conflict: Annotated[Literal["throw-error", "overwrite-default-path", "backup-default-path"], typer.Option(..., "--on-conflict", "-o", help="Action to take on conflict")] = "throw-error",
|
|
20
|
-
which: Annotated[Optional[str], typer.Option(..., "--which", "-w", help="Specific items to process")] = None,
|
|
21
|
-
interactive: Annotated[bool, typer.Option(..., "--interactive", "-ia", help="Run in interactive mode")] = False):
|
|
22
|
-
"""🔗 Manage public configuration files."""
|
|
23
|
-
import machineconfig.profile.create_links_export as create_links_export
|
|
24
|
-
create_links_export.main_public_from_parser(method=method, on_conflict=on_conflict, which=which, interactive=interactive)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def shell():
|
|
9
|
+
def shell(which: Annotated[Literal["default", "d", "nushell", "n"], typer.Option(..., "--which", "-w", help="Which shell profile to create/configure")]="default"):
|
|
28
10
|
"""🔗 Configure your shell profile."""
|
|
29
|
-
from machineconfig.profile.create_shell_profile import create_default_shell_profile
|
|
30
|
-
|
|
11
|
+
from machineconfig.profile.create_shell_profile import create_default_shell_profile, create_nu_shell_profile
|
|
12
|
+
match which:
|
|
13
|
+
case "nushell" | "n":
|
|
14
|
+
create_nu_shell_profile()
|
|
15
|
+
return
|
|
16
|
+
case "default" | "d":
|
|
17
|
+
create_default_shell_profile()
|
|
18
|
+
return
|
|
19
|
+
typer.echo(f"[red]Error:[/] Unknown shell profile type: {which}")
|
|
31
20
|
|
|
32
21
|
|
|
33
22
|
def path():
|
|
@@ -39,7 +28,7 @@ def path():
|
|
|
39
28
|
uv_with = ["textual"]
|
|
40
29
|
uv_project_dir = None
|
|
41
30
|
if not Path.home().joinpath("code/machineconfig").exists():
|
|
42
|
-
uv_with.append("machineconfig>=7.
|
|
31
|
+
uv_with.append("machineconfig>=7.39")
|
|
43
32
|
else:
|
|
44
33
|
uv_project_dir = str(Path.home().joinpath("code/machineconfig"))
|
|
45
34
|
run_shell_script(get_uv_command_executing_python_script(python_script=path.read_text(encoding="utf-8"), uv_with=uv_with, uv_project_dir=uv_project_dir)[0])
|
|
@@ -82,23 +71,29 @@ def starship_theme():
|
|
|
82
71
|
typer.echo("❌ Please enter a valid number")
|
|
83
72
|
|
|
84
73
|
|
|
85
|
-
def copy_assets(which: Annotated[Literal["scripts", "settings", "both"], typer.Argument(..., help="Which assets to copy")]):
|
|
74
|
+
def copy_assets(which: Annotated[Literal["scripts", "s", "settings", "t", "both", "b"], typer.Argument(..., help="Which assets to copy")]):
|
|
86
75
|
"""🔗 Copy asset files from library to machine."""
|
|
87
76
|
import machineconfig.profile.create_helper as create_helper
|
|
88
77
|
match which:
|
|
89
|
-
case "both":
|
|
78
|
+
case "both" | "b":
|
|
79
|
+
create_helper.copy_assets_to_machine(which="scripts")
|
|
80
|
+
create_helper.copy_assets_to_machine(which="settings")
|
|
81
|
+
return
|
|
82
|
+
case "scripts" | "s":
|
|
90
83
|
create_helper.copy_assets_to_machine(which="scripts")
|
|
84
|
+
return
|
|
85
|
+
case "settings" | "t":
|
|
91
86
|
create_helper.copy_assets_to_machine(which="settings")
|
|
92
|
-
|
|
93
|
-
|
|
87
|
+
return
|
|
88
|
+
typer.echo(f"[red]Error:[/] Unknown asset type: {which}")
|
|
94
89
|
|
|
95
90
|
|
|
96
91
|
def get_app():
|
|
97
92
|
config_apps = typer.Typer(help="⚙️ [c] configuration subcommands", no_args_is_help=True, add_help_option=False, add_completion=False)
|
|
98
|
-
config_apps.command("private", no_args_is_help=True, help="🔗 [v] Manage private configuration files.")(
|
|
99
|
-
config_apps.command("v", no_args_is_help=True, hidden=True)(
|
|
100
|
-
config_apps.command("public", no_args_is_help=True, help="🔗 [b] Manage public configuration files.")(
|
|
101
|
-
config_apps.command("b", no_args_is_help=True, help="Manage public configuration files.", hidden=True)(
|
|
93
|
+
config_apps.command("private", no_args_is_help=True, help="🔗 [v] Manage private configuration files.")(create_links_export.main_private_from_parser)
|
|
94
|
+
config_apps.command("v", no_args_is_help=True, hidden=True)(create_links_export.main_private_from_parser)
|
|
95
|
+
config_apps.command("public", no_args_is_help=True, help="🔗 [b] Manage public configuration files.")(create_links_export.main_public_from_parser)
|
|
96
|
+
config_apps.command("b", no_args_is_help=True, help="Manage public configuration files.", hidden=True)(create_links_export.main_public_from_parser)
|
|
102
97
|
config_apps.command("dotfile", no_args_is_help=True, help="🔗 [d] Manage dotfiles.")(dotfile_module.main)
|
|
103
98
|
config_apps.command("d", no_args_is_help=True, hidden=True)(dotfile_module.main)
|
|
104
99
|
config_apps.command("shell", no_args_is_help=False, help="🔗 [s] Configure your shell profile.")(shell)
|
|
@@ -1,24 +1,26 @@
|
|
|
1
1
|
|
|
2
2
|
"""Like yadm and dotter."""
|
|
3
3
|
|
|
4
|
+
from machineconfig.profile.create_links_export import ON_CONFLICT_LOOSE, ON_CONFLICT_MAPPER
|
|
4
5
|
from typing import Annotated, Literal
|
|
5
6
|
import typer
|
|
6
7
|
|
|
7
8
|
|
|
9
|
+
|
|
8
10
|
def main(
|
|
9
11
|
file: Annotated[str, typer.Argument(help="file/folder path.")],
|
|
10
|
-
method: Annotated[Literal["symlink", "copy"], typer.Option(..., "--method", "-m", help="Method to use for linking files")] = "copy",
|
|
11
|
-
on_conflict: Annotated[
|
|
12
|
-
sensitivity: Annotated[Literal["private", "public"], typer.Option(..., "--sensitivity", "-s", help="Sensitivity of the config file.")] = "private",
|
|
12
|
+
method: Annotated[Literal["symlink", "s", "copy", "c"], typer.Option(..., "--method", "-m", help="Method to use for linking files")] = "copy",
|
|
13
|
+
on_conflict: Annotated[ON_CONFLICT_LOOSE, typer.Option(..., "--on-conflict", "-o", help="Action to take on conflict")] = "throw-error",
|
|
14
|
+
sensitivity: Annotated[Literal["private", "v", "public", "b"], typer.Option(..., "--sensitivity", "-s", help="Sensitivity of the config file.")] = "private",
|
|
13
15
|
destination: Annotated[str, typer.Option("--destination", "-d", help="destination folder (override the default, use at your own risk)")] = "",) -> None:
|
|
14
16
|
from rich.console import Console
|
|
15
17
|
from rich.panel import Panel
|
|
16
18
|
from machineconfig.utils.links import symlink_map, copy_map
|
|
17
19
|
from pathlib import Path
|
|
18
20
|
match sensitivity:
|
|
19
|
-
case "private":
|
|
21
|
+
case "private" | "v":
|
|
20
22
|
backup_root = Path.home().joinpath("dotfiles/mapper")
|
|
21
|
-
case "public":
|
|
23
|
+
case "public" | "b":
|
|
22
24
|
from machineconfig.utils.source_of_truth import CONFIG_ROOT
|
|
23
25
|
backup_root = Path(CONFIG_ROOT).joinpath("dotfiles/mapper")
|
|
24
26
|
|
|
@@ -32,18 +34,19 @@ def main(
|
|
|
32
34
|
dest_path.mkdir(parents=True, exist_ok=True)
|
|
33
35
|
new_path = dest_path.joinpath(orig_path.name)
|
|
34
36
|
|
|
37
|
+
|
|
35
38
|
from machineconfig.utils.path_extended import PathExtended
|
|
36
39
|
match method:
|
|
37
|
-
case "copy":
|
|
40
|
+
case "copy" | "c":
|
|
38
41
|
try:
|
|
39
|
-
copy_map(config_file_default_path=PathExtended(orig_path), self_managed_config_file_path=PathExtended(new_path), on_conflict=on_conflict)
|
|
42
|
+
copy_map(config_file_default_path=PathExtended(orig_path), self_managed_config_file_path=PathExtended(new_path), on_conflict=ON_CONFLICT_MAPPER[on_conflict])
|
|
40
43
|
except Exception as e:
|
|
41
44
|
typer.echo(f"[red]Error:[/] {e}")
|
|
42
45
|
typer.Exit(code=1)
|
|
43
46
|
return
|
|
44
|
-
case "symlink":
|
|
47
|
+
case "symlink" | "s":
|
|
45
48
|
try:
|
|
46
|
-
symlink_map(config_file_default_path=PathExtended(orig_path), self_managed_config_file_path=PathExtended(new_path), on_conflict=on_conflict)
|
|
49
|
+
symlink_map(config_file_default_path=PathExtended(orig_path), self_managed_config_file_path=PathExtended(new_path), on_conflict=ON_CONFLICT_MAPPER[on_conflict])
|
|
47
50
|
except Exception as e:
|
|
48
51
|
typer.echo(f"[red]Error:[/] {e}")
|
|
49
52
|
typer.Exit(code=1)
|
|
@@ -8,38 +8,38 @@ in the event that username@github.com is not mentioned in the remote url.
|
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
from typing import Annotated, Optional
|
|
10
10
|
import typer
|
|
11
|
-
from machineconfig.scripts.python.helpers_repos.
|
|
11
|
+
from machineconfig.scripts.python.helpers_repos.cloud_repo_sync import main as secure_repo_main
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
DirectoryArgument = Annotated[Optional[str], typer.Argument(help="📁 Directory containing repo(s).")]
|
|
15
15
|
RecursiveOption = Annotated[bool, typer.Option("--recursive", "-r", help="🔍 Recurse into nested repositories.")]
|
|
16
|
-
|
|
16
|
+
UVsyncOption = Annotated[bool, typer.Option("--uv-sync/--no-uv-sync", "-u/-ns", help="Automatic uv sync after pulls.")]
|
|
17
17
|
CloudOption = Annotated[Optional[str], typer.Option("--cloud", "-c", help="☁️ Upload to or download from this cloud remote.")]
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
def push(directory: DirectoryArgument = None, recursive: RecursiveOption = False,
|
|
20
|
+
def push(directory: DirectoryArgument = None, recursive: RecursiveOption = False, auto_uv_sync: UVsyncOption = False) -> None:
|
|
21
21
|
"""🚀 Push changes across repositories."""
|
|
22
22
|
from machineconfig.scripts.python.helpers_repos.entrypoint import git_operations
|
|
23
|
-
git_operations(directory, pull=False, commit=False, push=True, recursive=recursive, auto_uv_sync=
|
|
23
|
+
git_operations(directory, pull=False, commit=False, push=True, recursive=recursive, auto_uv_sync=auto_uv_sync)
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
def pull(directory: DirectoryArgument = None, recursive: RecursiveOption = False,
|
|
26
|
+
def pull(directory: DirectoryArgument = None, recursive: RecursiveOption = False, auto_uv_sync: UVsyncOption = False) -> None:
|
|
27
27
|
"""⬇️ Pull changes across repositories."""
|
|
28
28
|
from machineconfig.scripts.python.helpers_repos.entrypoint import git_operations
|
|
29
29
|
|
|
30
|
-
git_operations(directory, pull=True, commit=False, push=False, recursive=recursive, auto_uv_sync=
|
|
30
|
+
git_operations(directory, pull=True, commit=False, push=False, recursive=recursive, auto_uv_sync=auto_uv_sync)
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
def commit(directory: DirectoryArgument = None, recursive: RecursiveOption = False,
|
|
33
|
+
def commit(directory: DirectoryArgument = None, recursive: RecursiveOption = False, auto_uv_sync: UVsyncOption = False) -> None:
|
|
34
34
|
"""💾 Commit changes across repositories."""
|
|
35
35
|
from machineconfig.scripts.python.helpers_repos.entrypoint import git_operations
|
|
36
|
-
git_operations(directory, pull=False, commit=True, push=False, recursive=recursive, auto_uv_sync=
|
|
36
|
+
git_operations(directory, pull=False, commit=True, push=False, recursive=recursive, auto_uv_sync=auto_uv_sync)
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
def sync(directory: DirectoryArgument = None, recursive: RecursiveOption = False,
|
|
39
|
+
def sync(directory: DirectoryArgument = None, recursive: RecursiveOption = False, auto_uv_sync: UVsyncOption = False) -> None:
|
|
40
40
|
"""🔄 Pull, commit, and push changes across repositories."""
|
|
41
41
|
from machineconfig.scripts.python.helpers_repos.entrypoint import git_operations
|
|
42
|
-
git_operations(directory, pull=True, commit=True, push=True, recursive=recursive, auto_uv_sync=
|
|
42
|
+
git_operations(directory, pull=True, commit=True, push=True, recursive=recursive, auto_uv_sync=auto_uv_sync)
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
def capture(directory: DirectoryArgument = None, cloud: CloudOption = None) -> None:
|
|
@@ -179,3 +179,4 @@ def get_app():
|
|
|
179
179
|
mirror_app.command(name="ctb", help="Check out to the main branch defined in the specification", hidden=True)(checkout_to_branch_command)
|
|
180
180
|
|
|
181
181
|
return repos_apps
|
|
182
|
+
|
|
@@ -9,10 +9,8 @@ def copy_both_assets():
|
|
|
9
9
|
create_helper.copy_assets_to_machine(which="settings")
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
def update(
|
|
12
|
+
def update(copy_assets: Annotated[bool, typer.Option("--assets-copy/--no-assets-copy", "-a/-na", help="Copy (overwrite) assets to the machine after the update")] = True):
|
|
13
13
|
"""🔄 UPDATE uv and machineconfig"""
|
|
14
|
-
# from machineconfig.utils.source_of_truth import LIBRARY_ROOT
|
|
15
|
-
# repo_root = LIBRARY_ROOT.parent.parent
|
|
16
14
|
from pathlib import Path
|
|
17
15
|
if Path.home().joinpath("code", "machineconfig").exists():
|
|
18
16
|
shell_script = """
|
|
@@ -36,7 +34,7 @@ uv tool install --upgrade machineconfig
|
|
|
36
34
|
else:
|
|
37
35
|
from machineconfig.utils.code import run_shell_script
|
|
38
36
|
run_shell_script(shell_script)
|
|
39
|
-
if
|
|
37
|
+
if copy_assets:
|
|
40
38
|
copy_both_assets()
|
|
41
39
|
|
|
42
40
|
def install(no_copy_assets: Annotated[bool, typer.Option("--no-assets-copy", "-na", help="Copy (overwrite) assets to the machine after the update")] = False):
|
|
@@ -48,9 +46,9 @@ def install(no_copy_assets: Annotated[bool, typer.Option("--no-assets-copy", "-n
|
|
|
48
46
|
else:
|
|
49
47
|
import platform
|
|
50
48
|
if platform.system() == "Windows":
|
|
51
|
-
run_shell_script(r"""& "$HOME\.local\bin\uv.exe" tool install --upgrade "machineconfig>=7.
|
|
49
|
+
run_shell_script(r"""& "$HOME\.local\bin\uv.exe" tool install --upgrade "machineconfig>=7.39" """)
|
|
52
50
|
else:
|
|
53
|
-
run_shell_script("""$HOME/.local/bin/uv tool install --upgrade "machineconfig>=7.
|
|
51
|
+
run_shell_script("""$HOME/.local/bin/uv tool install --upgrade "machineconfig>=7.39" """)
|
|
54
52
|
from machineconfig.profile.create_shell_profile import create_default_shell_profile
|
|
55
53
|
if not no_copy_assets:
|
|
56
54
|
create_default_shell_profile() # involves copying assets too
|
|
@@ -75,7 +73,7 @@ def navigate():
|
|
|
75
73
|
path = Path(navigator.__file__).resolve().parent.joinpath("devops_navigator.py")
|
|
76
74
|
from machineconfig.utils.code import run_shell_script
|
|
77
75
|
if Path.home().joinpath("code/machineconfig").exists(): executable = f"""--project "{str(Path.home().joinpath("code/machineconfig"))}" --with textual"""
|
|
78
|
-
else: executable = """--with "machineconfig>=7.
|
|
76
|
+
else: executable = """--with "machineconfig>=7.39,textual" """
|
|
79
77
|
run_shell_script(f"""uv run {executable} {path}""")
|
|
80
78
|
|
|
81
79
|
|