machineconfig 7.51__py3-none-any.whl → 7.53__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/jobs/installer/custom_dev/brave.py +1 -1
- machineconfig/jobs/installer/custom_dev/code.py +4 -1
- machineconfig/jobs/installer/custom_dev/nerfont_windows_helper.py +0 -9
- machineconfig/jobs/installer/custom_dev/sysabc.py +140 -0
- machineconfig/jobs/installer/custom_dev/wezterm.py +2 -15
- machineconfig/jobs/installer/installer_data.json +689 -9
- machineconfig/jobs/installer/linux_scripts/redis.sh +1 -0
- machineconfig/jobs/installer/package_groups.py +23 -72
- machineconfig/logger.py +0 -1
- machineconfig/profile/create_links_export.py +8 -3
- machineconfig/profile/mapper.toml +1 -4
- machineconfig/scripts/python/croshell.py +20 -43
- machineconfig/scripts/python/devops.py +1 -1
- machineconfig/scripts/python/env_manager/path_manager_tui.py +1 -1
- machineconfig/scripts/python/fire_jobs.py +52 -39
- machineconfig/scripts/python/helpers_croshell/crosh.py +1 -1
- machineconfig/scripts/python/helpers_devops/cli_config.py +3 -19
- machineconfig/scripts/python/helpers_devops/cli_self.py +12 -6
- machineconfig/scripts/python/helpers_devops/cli_utils.py +1 -80
- machineconfig/scripts/python/helpers_fire_command/file_wrangler.py +0 -17
- machineconfig/scripts/python/helpers_msearch/scripts_linux/fzfg +1 -1
- machineconfig/scripts/python/helpers_repos/clone.py +0 -1
- machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py +1 -1
- machineconfig/scripts/python/helpers_repos/count_lines_frontend.py +1 -1
- machineconfig/scripts/python/helpers_sessions/sessions_multiprocess.py +2 -2
- machineconfig/scripts/python/helpers_utils/path.py +106 -0
- machineconfig/scripts/python/interactive.py +9 -15
- machineconfig/scripts/python/sessions.py +2 -2
- machineconfig/scripts/python/utils.py +7 -3
- machineconfig/scripts/windows/mounts/mount_ssh.ps1 +1 -1
- machineconfig/settings/yazi/init.lua +45 -24
- machineconfig/setup_linux/__init__.py +0 -1
- machineconfig/setup_linux/web_shortcuts/interactive.sh +11 -10
- machineconfig/setup_mac/__init__.py +2 -3
- machineconfig/setup_windows/__init__.py +0 -3
- machineconfig/setup_windows/web_shortcuts/interactive.ps1 +11 -10
- machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +15 -0
- machineconfig/utils/installer.py +11 -27
- machineconfig/utils/installer_utils/installer.py +9 -50
- machineconfig/utils/installer_utils/installer_abc.py +0 -68
- machineconfig/utils/io.py +0 -1
- machineconfig/utils/path_helper.py +57 -6
- machineconfig/utils/ssh.py +3 -3
- {machineconfig-7.51.dist-info → machineconfig-7.53.dist-info}/METADATA +5 -3
- {machineconfig-7.51.dist-info → machineconfig-7.53.dist-info}/RECORD +50 -52
- machineconfig/jobs/installer/linux_scripts/timescaledb.sh +0 -71
- machineconfig/jobs/installer/powershell_scripts/archive_pygraphviz.ps1 +0 -12
- machineconfig/setup_linux/apps.sh +0 -66
- machineconfig/setup_mac/apps.sh +0 -73
- machineconfig/setup_windows/apps.ps1 +0 -62
- /machineconfig/{jobs/installer/powershell_scripts → setup_windows/ssh}/openssh-server_add_key.ps1 +0 -0
- /machineconfig/{jobs/installer/powershell_scripts → setup_windows/ssh}/openssh-server_copy-ssh-id.ps1 +0 -0
- {machineconfig-7.51.dist-info → machineconfig-7.53.dist-info}/WHEEL +0 -0
- {machineconfig-7.51.dist-info → machineconfig-7.53.dist-info}/entry_points.txt +0 -0
- {machineconfig-7.51.dist-info → machineconfig-7.53.dist-info}/top_level.txt +0 -0
machineconfig/utils/installer.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"""package manager"""
|
|
2
2
|
|
|
3
|
-
from machineconfig.utils.installer_utils.installer_abc import check_if_installed_already
|
|
3
|
+
from machineconfig.utils.installer_utils.installer_abc import check_if_installed_already
|
|
4
4
|
from machineconfig.utils.installer_utils.installer_class import Installer
|
|
5
5
|
from machineconfig.utils.schemas.installer.installer_types import InstallerData, InstallerDataFiles, get_normalized_arch, get_os_name, OPERATING_SYSTEMS, CPU_ARCHITECTURES
|
|
6
|
-
from machineconfig.jobs.installer.package_groups import
|
|
6
|
+
from machineconfig.jobs.installer.package_groups import PACKAGE_GROUP2NAMES
|
|
7
7
|
from machineconfig.utils.path_extended import PathExtended
|
|
8
8
|
from machineconfig.utils.source_of_truth import INSTALL_VERSION_ROOT, LINUX_INSTALL_PATH
|
|
9
9
|
from machineconfig.utils.io import read_json
|
|
@@ -18,7 +18,7 @@ from joblib import Parallel, delayed
|
|
|
18
18
|
def check_latest():
|
|
19
19
|
console = Console() # Added console initialization
|
|
20
20
|
console.print(Panel("🔍 CHECKING FOR LATEST VERSIONS", title="Status", expand=False)) # Replaced print with Panel
|
|
21
|
-
installers = get_installers(os=get_os_name(), arch=get_normalized_arch(), which_cats=["
|
|
21
|
+
installers = get_installers(os=get_os_name(), arch=get_normalized_arch(), which_cats=["termabc"])
|
|
22
22
|
installers_github = []
|
|
23
23
|
for inst__ in installers:
|
|
24
24
|
app_name = inst__["appName"]
|
|
@@ -91,7 +91,7 @@ def get_installed_cli_apps():
|
|
|
91
91
|
return apps
|
|
92
92
|
|
|
93
93
|
|
|
94
|
-
def get_installers(os: OPERATING_SYSTEMS, arch: CPU_ARCHITECTURES, which_cats: Optional[list[
|
|
94
|
+
def get_installers(os: OPERATING_SYSTEMS, arch: CPU_ARCHITECTURES, which_cats: Optional[list[str]]) -> list[InstallerData]:
|
|
95
95
|
res_all = get_all_installer_data_files()
|
|
96
96
|
acceptable_apps_names: list[str] | None = None
|
|
97
97
|
if which_cats is not None:
|
|
@@ -105,8 +105,13 @@ def get_installers(os: OPERATING_SYSTEMS, arch: CPU_ARCHITECTURES, which_cats: O
|
|
|
105
105
|
if acceptable_apps_names is not None:
|
|
106
106
|
if installer_data["appName"] not in acceptable_apps_names:
|
|
107
107
|
continue
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
try:
|
|
109
|
+
if installer_data["fileNamePattern"][arch][os] is None:
|
|
110
|
+
continue
|
|
111
|
+
except KeyError as ke:
|
|
112
|
+
print(f"❌ ERROR: Missing key in installer data: {ke}")
|
|
113
|
+
print(f"Installer data: {installer_data}")
|
|
114
|
+
raise KeyError(f"Missing key in installer data: {ke}")
|
|
110
115
|
all_installers.append(installer_data)
|
|
111
116
|
return all_installers
|
|
112
117
|
|
|
@@ -119,27 +124,6 @@ def get_all_installer_data_files() -> list[InstallerData]:
|
|
|
119
124
|
return res_final
|
|
120
125
|
|
|
121
126
|
|
|
122
|
-
def dynamically_extract_installers_system_groups_from_scripts():
|
|
123
|
-
res_final: list[InstallerData] = []
|
|
124
|
-
from platform import system
|
|
125
|
-
if system() == "Windows":
|
|
126
|
-
from machineconfig.setup_windows import APPS
|
|
127
|
-
options_system = parse_apps_installer_windows(APPS.read_text(encoding="utf-8"))
|
|
128
|
-
elif system() == "Linux":
|
|
129
|
-
from machineconfig.setup_linux import APPS
|
|
130
|
-
options_system = parse_apps_installer_linux(APPS.read_text(encoding="utf-8"))
|
|
131
|
-
elif system() == "Darwin":
|
|
132
|
-
from machineconfig.setup_mac import APPS
|
|
133
|
-
options_system = parse_apps_installer_linux(APPS.read_text(encoding="utf-8"))
|
|
134
|
-
else:
|
|
135
|
-
raise NotImplementedError(f"❌ System {system()} not supported")
|
|
136
|
-
os_name = get_os_name()
|
|
137
|
-
for group_name, (docs, script) in options_system.items():
|
|
138
|
-
item: InstallerData = {"appName": group_name, "doc": docs, "repoURL": "CMD", "fileNamePattern": {"amd64": {os_name: script}, "arm64": {os_name: script}}}
|
|
139
|
-
res_final.append(item)
|
|
140
|
-
return res_final
|
|
141
|
-
|
|
142
|
-
|
|
143
127
|
def install_bulk(installers_data: list[InstallerData], safe: bool = False, jobs: int = 10, fresh: bool = False):
|
|
144
128
|
print("🚀 BULK INSTALLATION PROCESS 🚀")
|
|
145
129
|
if fresh:
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
"""Devops Devapps Install"""
|
|
2
2
|
|
|
3
|
-
from machineconfig.utils.installer import dynamically_extract_installers_system_groups_from_scripts
|
|
4
3
|
import typer
|
|
5
4
|
from rich.console import Console
|
|
6
5
|
from rich.panel import Panel
|
|
7
6
|
from rich.table import Table
|
|
8
|
-
from typing import Optional,
|
|
9
|
-
from machineconfig.jobs.installer.package_groups import
|
|
7
|
+
from typing import Optional, Annotated
|
|
8
|
+
from machineconfig.jobs.installer.package_groups import PACKAGE_GROUP2NAMES
|
|
10
9
|
|
|
11
10
|
console = Console()
|
|
12
11
|
|
|
@@ -36,7 +35,7 @@ def _handle_installer_not_found(search_term: str, all_names: list[str]) -> None:
|
|
|
36
35
|
if len(all_names) > 10:
|
|
37
36
|
console.print(f" [dim]... and {len(all_names) - 10} more[/dim]")
|
|
38
37
|
|
|
39
|
-
panel = Panel(f"[bold blue]💡 Use 'ia' to interactively browse all available installers.[/bold blue]\n[bold blue]💡 Use one of the categories: {list(
|
|
38
|
+
panel = Panel(f"[bold blue]💡 Use 'ia' to interactively browse all available installers.[/bold blue]\n[bold blue]💡 Use one of the categories: {list(PACKAGE_GROUP2NAMES.keys())}[/bold blue]", title="[yellow]Helpful Tips[/yellow]", border_style="yellow")
|
|
40
39
|
console.print(panel)
|
|
41
40
|
|
|
42
41
|
|
|
@@ -63,7 +62,7 @@ def main(
|
|
|
63
62
|
else:
|
|
64
63
|
if group:
|
|
65
64
|
typer.echo("❌ You must provide a group name when using the --group/-g option.")
|
|
66
|
-
res =
|
|
65
|
+
res = get_group_name_to_repr()
|
|
67
66
|
console.print("[bold blue]Here are the available groups:[/bold blue]")
|
|
68
67
|
table = Table(show_header=True, header_style="bold magenta")
|
|
69
68
|
table.add_column("Group", style="cyan", no_wrap=True)
|
|
@@ -87,16 +86,12 @@ def main(
|
|
|
87
86
|
raise typer.Exit(1)
|
|
88
87
|
|
|
89
88
|
|
|
90
|
-
def
|
|
89
|
+
def get_group_name_to_repr() -> dict[str, str]:
|
|
91
90
|
# Build category options and maintain a mapping from display text to actual category name
|
|
92
91
|
category_display_to_name: dict[str, str] = {}
|
|
93
92
|
for group_name, group_values in PACKAGE_GROUP2NAMES.items():
|
|
94
93
|
display = f"📦 {group_name:<20}" + " -- " + f"{'|'.join(group_values):<60}"
|
|
95
94
|
category_display_to_name[display] = group_name
|
|
96
|
-
options_system = dynamically_extract_installers_system_groups_from_scripts()
|
|
97
|
-
for item in options_system:
|
|
98
|
-
display = f"📦 {item['appName']:<20} -- {item['doc']:<60}"
|
|
99
|
-
category_display_to_name[display] = item['appName']
|
|
100
95
|
return category_display_to_name
|
|
101
96
|
|
|
102
97
|
|
|
@@ -110,9 +105,9 @@ def install_interactively():
|
|
|
110
105
|
for x in installers:
|
|
111
106
|
installer_options.append(Installer(installer_data=x).get_description())
|
|
112
107
|
|
|
113
|
-
category_display_to_name =
|
|
108
|
+
category_display_to_name = get_group_name_to_repr()
|
|
114
109
|
options = list(category_display_to_name.keys()) + ["─" * 50] + installer_options
|
|
115
|
-
program_names = choose_from_options(multi=True, msg="Categories are prefixed with 📦", options=options, header="🚀 CHOOSE DEV APP OR CATEGORY", default="📦
|
|
110
|
+
program_names = choose_from_options(multi=True, msg="Categories are prefixed with 📦", options=options, header="🚀 CHOOSE DEV APP OR CATEGORY", default="📦 termabc", fzf=True)
|
|
116
111
|
installation_messages: list[str] = []
|
|
117
112
|
for _an_idx, a_program_name in enumerate(program_names):
|
|
118
113
|
if a_program_name.startswith("─"): # 50 dashes separator
|
|
@@ -120,7 +115,7 @@ def install_interactively():
|
|
|
120
115
|
if a_program_name.startswith("📦 "):
|
|
121
116
|
category_name = category_display_to_name.get(a_program_name)
|
|
122
117
|
if category_name:
|
|
123
|
-
install_group(package_group=
|
|
118
|
+
install_group(package_group=category_name)
|
|
124
119
|
else:
|
|
125
120
|
installer_idx = installer_options.index(a_program_name)
|
|
126
121
|
an_installer_data = installers[installer_idx]
|
|
@@ -140,43 +135,7 @@ def install_group(package_group: str):
|
|
|
140
135
|
installers_ = get_installers(os=get_os_name(), arch=get_normalized_arch(), which_cats=[package_group])
|
|
141
136
|
install_bulk(installers_data=installers_)
|
|
142
137
|
return
|
|
143
|
-
|
|
144
|
-
from machineconfig.utils.schemas.installer.installer_types import get_normalized_arch, get_os_name
|
|
145
|
-
from machineconfig.utils.code import run_shell_script
|
|
146
|
-
for an_item in options_system:
|
|
147
|
-
if an_item["appName"] == package_group:
|
|
148
|
-
panel = Panel(f"[bold yellow]Installing programs from category: [green]{package_group}[/green][/bold yellow]", title="[bold blue]📦 Category Installation[/bold blue]", border_style="blue", padding=(1, 2))
|
|
149
|
-
console.print(panel)
|
|
150
|
-
program = an_item["fileNamePattern"][get_normalized_arch()][get_os_name()]
|
|
151
|
-
if program is not None:
|
|
152
|
-
run_shell_script(program)
|
|
153
|
-
break
|
|
154
|
-
else:
|
|
155
|
-
console.print(f"❌ [red]Group '{package_group}' not found.[/red]", style="bold")
|
|
156
|
-
_handle_installer_not_found(package_group, all_names=list(PACKAGE_GROUP2NAMES.keys()) + [item['appName'] for item in options_system])
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
def choose_from_system_package_groups(options_system: dict[str, tuple[str, str]]) -> str:
|
|
160
|
-
from machineconfig.utils.options import choose_from_options
|
|
161
|
-
display_options = []
|
|
162
|
-
for group_name, (description, _) in options_system.items():
|
|
163
|
-
if description:
|
|
164
|
-
display_options.append(f"{group_name:<20} - {description}")
|
|
165
|
-
else:
|
|
166
|
-
display_options.append(group_name)
|
|
167
|
-
program_names = choose_from_options(multi=True, msg="", options=sorted(display_options), header="🚀 CHOOSE DEV APP", fzf=True)
|
|
168
|
-
program = ""
|
|
169
|
-
for display_name in program_names:
|
|
170
|
-
# Extract the actual group name (everything before " - " if present)
|
|
171
|
-
group_name = display_name.split(" - ")[0].strip() if " - " in display_name else display_name.strip()
|
|
172
|
-
console.print(f"\n[bold cyan]⚙️ Installing: [yellow]{group_name}[/yellow][/bold cyan]", style="bold")
|
|
173
|
-
_, sub_program = options_system[group_name] # Extract content from tuple
|
|
174
|
-
if sub_program.startswith("#winget"):
|
|
175
|
-
sub_program = sub_program[1:]
|
|
176
|
-
program += "\n" + sub_program
|
|
177
|
-
return program
|
|
178
|
-
|
|
179
|
-
|
|
138
|
+
print(f"❌ ERROR: Unknown package group: {package_group}. Available groups are: {list(PACKAGE_GROUP2NAMES.keys())}")
|
|
180
139
|
def install_clis(clis_names: list[str]):
|
|
181
140
|
from machineconfig.utils.schemas.installer.installer_types import get_normalized_arch, get_os_name
|
|
182
141
|
from machineconfig.utils.installer import get_installers
|
|
@@ -191,71 +191,3 @@ def check_if_installed_already(exe_name: str, version: Optional[str], use_cache:
|
|
|
191
191
|
return ("⚠️ NotInstalled", "None", version or "unknown")
|
|
192
192
|
|
|
193
193
|
|
|
194
|
-
def parse_apps_installer_linux(txt: str) -> dict[str, tuple[str, str]]:
|
|
195
|
-
"""Parse Linux shell installation scripts into logical chunks.
|
|
196
|
-
|
|
197
|
-
Splits scripts by # --GROUP:<name>:<description> comment signatures into a dictionary
|
|
198
|
-
mapping block names to (description, shell script content) tuples.
|
|
199
|
-
|
|
200
|
-
Returns:
|
|
201
|
-
dict[str, tuple[str, str]]: Dictionary mapping block/section names to (description, installation_script) tuples
|
|
202
|
-
"""
|
|
203
|
-
chunks = txt.split('# --GROUP:')
|
|
204
|
-
res: dict[str, tuple[str, str]] = {}
|
|
205
|
-
|
|
206
|
-
for chunk in chunks[1:]: # Skip first empty chunk before first group
|
|
207
|
-
lines = chunk.split('\n')
|
|
208
|
-
# First line contains the group name and description in format "NAME:DESCRIPTION"
|
|
209
|
-
group_line = lines[0].strip()
|
|
210
|
-
|
|
211
|
-
# Extract group name and description
|
|
212
|
-
if ':' in group_line:
|
|
213
|
-
parts = group_line.split(':', 1) # Split only on first colon
|
|
214
|
-
group_name = parts[0].strip()
|
|
215
|
-
group_description = parts[1].strip() if len(parts) > 1 else ""
|
|
216
|
-
else:
|
|
217
|
-
group_name = group_line
|
|
218
|
-
group_description = ""
|
|
219
|
-
|
|
220
|
-
# Rest is the content
|
|
221
|
-
content = '\n'.join(lines[1:]).strip()
|
|
222
|
-
|
|
223
|
-
if group_name and content:
|
|
224
|
-
res[group_name] = (group_description, content)
|
|
225
|
-
|
|
226
|
-
return res
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
def parse_apps_installer_windows(txt: str) -> dict[str, tuple[str, str]]:
|
|
230
|
-
"""Parse Windows PowerShell installation scripts into logical chunks.
|
|
231
|
-
|
|
232
|
-
Splits scripts by # --GROUP:<name>:<description> comment signatures into a dictionary
|
|
233
|
-
mapping block names to (description, PowerShell script content) tuples.
|
|
234
|
-
|
|
235
|
-
Returns:
|
|
236
|
-
dict[str, tuple[str, str]]: Dictionary mapping block/section names to (description, installation_script) tuples
|
|
237
|
-
"""
|
|
238
|
-
chunks = txt.split('# --GROUP:')
|
|
239
|
-
res: dict[str, tuple[str, str]] = {}
|
|
240
|
-
|
|
241
|
-
for chunk in chunks[1:]: # Skip first chunk before first group
|
|
242
|
-
lines = chunk.split('\n')
|
|
243
|
-
# First line contains the group name and description in format "NAME:DESCRIPTION"
|
|
244
|
-
group_line = lines[0].strip()
|
|
245
|
-
|
|
246
|
-
# Extract group name and description
|
|
247
|
-
if ':' in group_line:
|
|
248
|
-
parts = group_line.split(':', 1) # Split only on first colon
|
|
249
|
-
group_name = parts[0].strip()
|
|
250
|
-
group_description = parts[1].strip() if len(parts) > 1 else ""
|
|
251
|
-
else:
|
|
252
|
-
group_name = group_line
|
|
253
|
-
group_description = ""
|
|
254
|
-
|
|
255
|
-
# Rest is the content
|
|
256
|
-
content = '\n'.join(lines[1:]).strip()
|
|
257
|
-
|
|
258
|
-
if group_name and content:
|
|
259
|
-
res[group_name] = (group_description, content)
|
|
260
|
-
|
|
261
|
-
return res
|
machineconfig/utils/io.py
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
from machineconfig.utils.path_extended import PathExtended
|
|
2
|
-
from machineconfig.utils.options import choose_from_options
|
|
3
2
|
from machineconfig.utils.source_of_truth import EXCLUDE_DIRS
|
|
4
3
|
from rich.console import Console
|
|
5
4
|
from rich.panel import Panel
|
|
6
5
|
import platform
|
|
7
6
|
import subprocess
|
|
8
7
|
from pathlib import Path
|
|
9
|
-
|
|
8
|
+
from typing import Optional
|
|
10
9
|
|
|
11
10
|
console = Console()
|
|
12
11
|
|
|
@@ -83,6 +82,7 @@ def match_file_name(sub_string: str, search_root: PathExtended, suffixes: set[st
|
|
|
83
82
|
if len(reduced_scripts) == 1:
|
|
84
83
|
return PathExtended(reduced_scripts[0])
|
|
85
84
|
elif len(reduced_scripts) > 1:
|
|
85
|
+
from machineconfig.utils.options import choose_from_options
|
|
86
86
|
choice = choose_from_options(multi=False, msg="Multiple matches found", options=reduced_scripts, fzf=True)
|
|
87
87
|
return PathExtended(choice)
|
|
88
88
|
print(f"Result: This still generated {len(reduced_scripts)} results.")
|
|
@@ -97,19 +97,27 @@ def match_file_name(sub_string: str, search_root: PathExtended, suffixes: set[st
|
|
|
97
97
|
reduced_scripts = [a_potential_match for a_potential_match in partial_path_matches if sub_string in a_potential_match.as_posix()]
|
|
98
98
|
if len(reduced_scripts) == 1:
|
|
99
99
|
return PathExtended(reduced_scripts[0])
|
|
100
|
-
print(f"Result: This still generated {len(reduced_scripts)} results.")
|
|
100
|
+
print(f"Result: This still generated {len(reduced_scripts)} results.")
|
|
101
|
+
|
|
101
102
|
try:
|
|
102
|
-
|
|
103
|
+
|
|
104
|
+
if len(partial_path_matches) == 0:
|
|
105
|
+
print("No partial path matches found, trying to do fd with --no-ignore ...")
|
|
106
|
+
fzf_cmd = f"cd '{search_root_obj}'; fd --no-ignore --type file --strip-cwd-prefix | fzf --ignore-case --exact --query={sub_string}"
|
|
107
|
+
else:
|
|
108
|
+
fzf_cmd = f"cd '{search_root_obj}'; fd --type file --strip-cwd-prefix | fzf --ignore-case --exact --query={sub_string}"
|
|
103
109
|
console.print(Panel(f"🔍 Second attempt: SEARCH STRATEGY | Using fd to search for '{sub_string}' in '{search_root_obj}' ...\n{fzf_cmd}", title="Search Strategy", expand=False))
|
|
104
110
|
search_res_raw = subprocess.run(fzf_cmd, stdout=subprocess.PIPE, text=True, check=True, shell=True).stdout
|
|
105
|
-
search_res = search_res_raw.strip().split("
|
|
111
|
+
search_res = search_res_raw.strip().split("\n")
|
|
106
112
|
except subprocess.CalledProcessError as cpe:
|
|
107
113
|
console.print(Panel(f"❌ ERROR | FZF search failed with '{sub_string}' in '{search_root_obj}'.\n{cpe}", title="Error", expand=False))
|
|
108
114
|
import sys
|
|
109
|
-
|
|
110
115
|
sys.exit(f"💥 FILE NOT FOUND | Path {sub_string} does not exist @ root {search_root_obj}. No search results.")
|
|
111
116
|
if len(search_res) == 1:
|
|
112
117
|
return search_root_obj.joinpath(search_res_raw)
|
|
118
|
+
elif len(search_res) == 0:
|
|
119
|
+
msg = Panel(f"💥 FILE NOT FOUND | Path {sub_string} does not exist @ root {search_root_obj}. No search results", title="File Not Found", expand=False)
|
|
120
|
+
raise FileNotFoundError(msg)
|
|
113
121
|
|
|
114
122
|
print(f"⚠️ WARNING | Multiple search results found for `{sub_string}`:\n'{search_res}'")
|
|
115
123
|
cmd = f"cd '{search_root_obj}'; fd --type file | fzf --select-1 --query={sub_string}"
|
|
@@ -121,3 +129,46 @@ def match_file_name(sub_string: str, search_root: PathExtended, suffixes: set[st
|
|
|
121
129
|
msg = Panel(f"💥 FILE NOT FOUND | Path {sub_string} does not exist @ root {search_root_obj}. No search results", title="File Not Found", expand=False)
|
|
122
130
|
raise FileNotFoundError(msg) from cpe
|
|
123
131
|
return search_root_obj.joinpath(res)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def search_for_files_of_interest(path_obj: PathExtended, suffixes: set[str]):
|
|
135
|
+
if path_obj.joinpath(".venv").exists():
|
|
136
|
+
path_objects = path_obj.search("*", not_in=[".venv"])
|
|
137
|
+
files: list[PathExtended] = []
|
|
138
|
+
for a_path_obj in path_objects:
|
|
139
|
+
files += search_for_files_of_interest(path_obj=a_path_obj, suffixes=suffixes)
|
|
140
|
+
return files
|
|
141
|
+
if path_obj.is_file():
|
|
142
|
+
return [path_obj]
|
|
143
|
+
files: list[PathExtended] = []
|
|
144
|
+
for a_suffix in suffixes:
|
|
145
|
+
if a_suffix == ".py":
|
|
146
|
+
files += path_obj.search(pattern="*.py", r=True, not_in=["__init__.py"])
|
|
147
|
+
else:
|
|
148
|
+
files += path_obj.search(pattern=f"*{a_suffix}", r=True)
|
|
149
|
+
return files
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def get_choice_file(path: str, suffixes: Optional[set[str]]):
|
|
153
|
+
path_obj = sanitize_path(path)
|
|
154
|
+
if suffixes is None:
|
|
155
|
+
import platform
|
|
156
|
+
if platform.system() == "Windows":
|
|
157
|
+
suffixes = {".py", ".ps1", ".sh"}
|
|
158
|
+
elif platform.system() in ["Linux", "Darwin"]:
|
|
159
|
+
suffixes = {".py", ".sh"}
|
|
160
|
+
else:
|
|
161
|
+
suffixes = {".py"}
|
|
162
|
+
if not path_obj.exists():
|
|
163
|
+
print(f"🔍 Searching for file matching `{path}` under `{PathExtended.cwd()}`, but only if suffix matches {suffixes}")
|
|
164
|
+
choice_file = match_file_name(sub_string=path, search_root=PathExtended.cwd(), suffixes=suffixes)
|
|
165
|
+
elif path_obj.is_dir():
|
|
166
|
+
print(f"🔍 Searching recursively for Python, PowerShell and Shell scripts in directory `{path_obj}`")
|
|
167
|
+
files = search_for_files_of_interest(path_obj, suffixes=suffixes)
|
|
168
|
+
print(f"🔍 Got #{len(files)} results.")
|
|
169
|
+
from machineconfig.utils.options import choose_from_options
|
|
170
|
+
choice_file = choose_from_options(multi=False, options=files, fzf=True, msg="Choose one option")
|
|
171
|
+
choice_file = PathExtended(choice_file)
|
|
172
|
+
else:
|
|
173
|
+
choice_file = path_obj
|
|
174
|
+
return choice_file
|
machineconfig/utils/ssh.py
CHANGED
|
@@ -2,13 +2,13 @@ from typing import Callable, Optional, Any, Union, cast
|
|
|
2
2
|
import os
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
import platform
|
|
5
|
-
from machineconfig.scripts.python.
|
|
5
|
+
from machineconfig.scripts.python.helpers_utils.path import MachineSpecs
|
|
6
6
|
import rich.console
|
|
7
7
|
from machineconfig.utils.terminal import Response
|
|
8
8
|
from machineconfig.utils.accessories import pprint, randstr
|
|
9
9
|
from machineconfig.utils.meta import lambda_to_python_script
|
|
10
10
|
UV_RUN_CMD = "$HOME/.local/bin/uv run" if platform.system() != "Windows" else """& "$env:USERPROFILE/.local/bin/uv" run"""
|
|
11
|
-
MACHINECONFIG_VERSION = "machineconfig>=7.
|
|
11
|
+
MACHINECONFIG_VERSION = "machineconfig>=7.53"
|
|
12
12
|
DEFAULT_PICKLE_SUBDIR = "tmp_results/tmp_scripts/ssh"
|
|
13
13
|
|
|
14
14
|
class SSH:
|
|
@@ -113,7 +113,7 @@ class SSH:
|
|
|
113
113
|
if self.progress and self.task is not None:
|
|
114
114
|
self.progress.update(self.task, completed=transferred, total=total)
|
|
115
115
|
self.tqdm_wrap = RichProgressWrapper
|
|
116
|
-
from machineconfig.scripts.python.
|
|
116
|
+
from machineconfig.scripts.python.helpers_utils.path import get_machine_specs
|
|
117
117
|
self.local_specs: MachineSpecs = get_machine_specs()
|
|
118
118
|
resp = self.run_shell(command="""~/.local/bin/utils get-machine-specs """, verbose_output=False, description="Getting remote machine specs", strict_stderr=False, strict_return_code=False)
|
|
119
119
|
json_str = resp.op
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: machineconfig
|
|
3
|
-
Version: 7.
|
|
3
|
+
Version: 7.53
|
|
4
4
|
Summary: Dotfiles management package
|
|
5
5
|
Author-email: Alex Al-Saffar <programmer@usa.com>
|
|
6
6
|
License: Apache 2.0
|
|
@@ -65,7 +65,9 @@ iex (iwr bit.ly/cfgwindows).Content
|
|
|
65
65
|
iex (uvx machineconfig define)
|
|
66
66
|
# Permanent install:
|
|
67
67
|
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" # Skip if UV is already installed
|
|
68
|
-
|
|
68
|
+
uv tool install --upgrade --python 3.14 machineconfig both
|
|
69
|
+
devops config copy-assets
|
|
70
|
+
|
|
69
71
|
```
|
|
70
72
|
|
|
71
73
|
# Install On Linux and MacOS
|
|
@@ -77,7 +79,7 @@ uvx install --upgrade machineconfig
|
|
|
77
79
|
. <(uvx machineconfig define)
|
|
78
80
|
# Permanent install:
|
|
79
81
|
curl -LsSf https://astral.sh/uv/install.sh | sh # Skip if UV is already installed
|
|
80
|
-
|
|
82
|
+
uv tool install --upgrade --upgrade 3.14 machineconfig
|
|
81
83
|
```
|
|
82
84
|
|
|
83
85
|
|