machineconfig 7.57__py3-none-any.whl → 7.79__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/cluster/sessions_managers/utils/maker.py +21 -9
- machineconfig/jobs/installer/custom/boxes.py +2 -2
- machineconfig/jobs/installer/custom/hx.py +3 -3
- machineconfig/jobs/installer/custom_dev/cloudflare_warp_cli.py +23 -0
- machineconfig/jobs/installer/custom_dev/dubdb_adbc.py +1 -1
- machineconfig/jobs/installer/custom_dev/nerfont_windows_helper.py +1 -1
- machineconfig/jobs/installer/custom_dev/sysabc.py +36 -28
- machineconfig/jobs/installer/custom_dev/wezterm.py +0 -4
- machineconfig/jobs/installer/installer_data.json +127 -25
- machineconfig/jobs/installer/package_groups.py +20 -13
- machineconfig/profile/create_links_export.py +2 -2
- machineconfig/scripts/__init__.py +0 -4
- machineconfig/scripts/linux/wrap_mcfg +1 -1
- machineconfig/scripts/python/agents.py +22 -17
- machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +3 -0
- machineconfig/scripts/python/croshell.py +22 -17
- machineconfig/scripts/python/devops.py +3 -4
- machineconfig/scripts/python/devops_navigator.py +0 -4
- machineconfig/scripts/python/env_manager/path_manager_tui.py +1 -1
- machineconfig/scripts/python/fire_jobs.py +19 -18
- machineconfig/scripts/python/ftpx.py +36 -12
- machineconfig/scripts/python/helpers/ast_search.py +74 -0
- machineconfig/scripts/python/helpers/qr_code.py +166 -0
- machineconfig/scripts/python/helpers/repo_rag.py +325 -0
- machineconfig/scripts/python/helpers/symantic_search.py +25 -0
- machineconfig/scripts/python/helpers_cloud/cloud_copy.py +28 -21
- machineconfig/scripts/python/helpers_cloud/cloud_helpers.py +1 -1
- machineconfig/scripts/python/helpers_cloud/cloud_mount.py +19 -17
- machineconfig/scripts/python/helpers_cloud/cloud_sync.py +8 -7
- machineconfig/scripts/python/helpers_croshell/crosh.py +2 -2
- machineconfig/scripts/python/helpers_croshell/start_slidev.py +6 -7
- machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +4 -5
- machineconfig/scripts/python/helpers_devops/cli_nw.py +88 -7
- machineconfig/scripts/python/helpers_devops/cli_self.py +7 -6
- machineconfig/scripts/python/helpers_devops/cli_share_file.py +9 -9
- machineconfig/scripts/python/helpers_devops/cli_share_server.py +13 -12
- machineconfig/scripts/python/helpers_devops/cli_terminal.py +7 -6
- machineconfig/scripts/python/helpers_devops/cli_utils.py +2 -73
- machineconfig/scripts/python/helpers_devops/devops_backup_retrieve.py +4 -4
- machineconfig/scripts/python/helpers_devops/devops_status.py +7 -19
- machineconfig/scripts/python/helpers_fire_command/file_wrangler.py +2 -3
- machineconfig/scripts/python/helpers_fire_command/fire_jobs_route_helper.py +23 -13
- machineconfig/scripts/python/helpers_navigator/command_tree.py +50 -18
- machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py +7 -4
- machineconfig/scripts/python/helpers_repos/count_lines_frontend.py +1 -1
- machineconfig/scripts/python/helpers_repos/entrypoint.py +2 -1
- machineconfig/scripts/python/helpers_repos/record.py +2 -1
- machineconfig/scripts/python/helpers_sessions/sessions_multiprocess.py +5 -5
- machineconfig/scripts/python/helpers_utils/download.py +152 -0
- machineconfig/scripts/python/helpers_utils/path.py +81 -31
- machineconfig/scripts/python/interactive.py +2 -2
- machineconfig/scripts/python/{machineconfig.py → mcfg_entry.py} +4 -0
- machineconfig/scripts/python/msearch.py +21 -2
- machineconfig/scripts/python/nw/address.py +132 -0
- machineconfig/scripts/python/nw/devops_add_ssh_key.py +8 -5
- machineconfig/scripts/python/nw/ssh_debug_linux.py +7 -7
- machineconfig/scripts/python/nw/ssh_debug_windows.py +4 -4
- machineconfig/scripts/python/nw/wsl_windows_transfer.py +3 -2
- machineconfig/scripts/python/sessions.py +35 -20
- machineconfig/scripts/python/terminal.py +2 -2
- machineconfig/scripts/python/utils.py +12 -10
- machineconfig/scripts/windows/mounts/mount_ssh.ps1 +1 -1
- machineconfig/settings/lf/windows/lfcd.ps1 +1 -1
- machineconfig/settings/shells/nushell/config.nu +2 -2
- machineconfig/settings/shells/nushell/env.nu +45 -6
- machineconfig/settings/shells/nushell/init.nu +282 -95
- machineconfig/settings/shells/pwsh/init.ps1 +1 -0
- machineconfig/settings/shells/zsh/init.sh +0 -7
- machineconfig/setup_linux/web_shortcuts/interactive.sh +10 -10
- machineconfig/setup_windows/uv.ps1 +8 -1
- machineconfig/setup_windows/web_shortcuts/interactive.ps1 +10 -10
- machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +3 -2
- machineconfig/utils/accessories.py +7 -4
- machineconfig/utils/code.py +6 -4
- machineconfig/utils/files/headers.py +2 -2
- machineconfig/utils/installer_utils/install_from_url.py +180 -0
- machineconfig/utils/installer_utils/installer_class.py +53 -47
- machineconfig/utils/installer_utils/{installer.py → installer_cli.py} +71 -65
- machineconfig/utils/{installer.py → installer_utils/installer_runner.py} +1 -25
- machineconfig/utils/links.py +2 -2
- machineconfig/utils/meta.py +30 -16
- machineconfig/utils/options.py +4 -4
- machineconfig/utils/path_extended.py +3 -3
- machineconfig/utils/path_helper.py +33 -31
- machineconfig/utils/schemas/layouts/layout_types.py +1 -1
- machineconfig/utils/ssh.py +143 -409
- machineconfig/utils/ssh_utils/abc.py +8 -0
- machineconfig/utils/ssh_utils/copy_from_here.py +110 -0
- machineconfig/utils/ssh_utils/copy_to_here.py +302 -0
- machineconfig/utils/ssh_utils/utils.py +141 -0
- machineconfig/utils/ssh_utils/wsl.py +168 -0
- machineconfig/utils/upgrade_packages.py +2 -1
- machineconfig/utils/ve.py +11 -4
- {machineconfig-7.57.dist-info → machineconfig-7.79.dist-info}/METADATA +1 -1
- {machineconfig-7.57.dist-info → machineconfig-7.79.dist-info}/RECORD +102 -92
- {machineconfig-7.57.dist-info → machineconfig-7.79.dist-info}/entry_points.txt +2 -2
- machineconfig/jobs/installer/linux_scripts/pgsql.sh +0 -41
- machineconfig/scripts/python/explore.py +0 -49
- /machineconfig/jobs/installer/linux_scripts/{warp-cli.sh → cloudflare_warp_cli.sh} +0 -0
- /machineconfig/{settings/shells/pwsh/profile.ps1 → scripts/python/helpers_fire_command/f.py} +0 -0
- /machineconfig/scripts/{Restore-ThunderbirdProfile.ps1 → windows/mounts/Restore-ThunderbirdProfile.ps1} +0 -0
- /machineconfig/utils/installer_utils/{installer_abc.py → installer_locator_utils.py} +0 -0
- {machineconfig-7.57.dist-info → machineconfig-7.79.dist-info}/WHEEL +0 -0
- {machineconfig-7.57.dist-info → machineconfig-7.79.dist-info}/top_level.txt +0 -0
machineconfig/utils/meta.py
CHANGED
|
@@ -29,7 +29,8 @@ except (ImportError, ModuleNotFoundError) as ex:
|
|
|
29
29
|
return txt
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
def lambda_to_python_script(lmb: Callable[[], Any],
|
|
32
|
+
def lambda_to_python_script(lmb: Callable[[], Any],
|
|
33
|
+
in_global: bool, import_module: bool) -> str:
|
|
33
34
|
"""
|
|
34
35
|
caveats: always use keyword arguments in the lambda call for best results.
|
|
35
36
|
return statement not allowed in the wrapped function (otherwise it can be put in the global space)
|
|
@@ -55,6 +56,16 @@ def lambda_to_python_script(lmb: Callable[[], Any], in_global: bool, import_modu
|
|
|
55
56
|
import types as _types
|
|
56
57
|
from pathlib import Path as _Path
|
|
57
58
|
|
|
59
|
+
def _stringify_annotation(annotation: Any) -> Any:
|
|
60
|
+
if annotation is _inspect.Signature.empty or annotation is _inspect.Parameter.empty:
|
|
61
|
+
return annotation
|
|
62
|
+
if isinstance(annotation, str):
|
|
63
|
+
return annotation
|
|
64
|
+
try:
|
|
65
|
+
return _inspect.formatannotation(annotation)
|
|
66
|
+
except Exception:
|
|
67
|
+
return str(annotation)
|
|
68
|
+
|
|
58
69
|
# sanity checks
|
|
59
70
|
if not (callable(lmb) and isinstance(lmb, _types.LambdaType)):
|
|
60
71
|
raise TypeError("Expected a lambda function object")
|
|
@@ -174,16 +185,18 @@ def lambda_to_python_script(lmb: Callable[[], Any], in_global: bool, import_modu
|
|
|
174
185
|
else:
|
|
175
186
|
new_default = param.default
|
|
176
187
|
|
|
177
|
-
|
|
188
|
+
normalized_annotation = _stringify_annotation(param.annotation)
|
|
189
|
+
|
|
178
190
|
if new_default is _inspect.Parameter.empty:
|
|
179
|
-
new_param = _inspect.Parameter(name, param.kind, annotation=
|
|
191
|
+
new_param = _inspect.Parameter(name, param.kind, annotation=normalized_annotation)
|
|
180
192
|
else:
|
|
181
193
|
new_param = _inspect.Parameter(
|
|
182
|
-
name, param.kind, default=new_default, annotation=
|
|
194
|
+
name, param.kind, default=new_default, annotation=normalized_annotation
|
|
183
195
|
)
|
|
184
196
|
new_params.append(new_param)
|
|
185
197
|
|
|
186
|
-
|
|
198
|
+
return_annotation = _stringify_annotation(sig.return_annotation)
|
|
199
|
+
new_sig = _inspect.Signature(parameters=new_params, return_annotation=return_annotation)
|
|
187
200
|
|
|
188
201
|
# If in_global mode, return kwargs as global assignments + dedented body
|
|
189
202
|
if in_global:
|
|
@@ -200,15 +213,11 @@ def lambda_to_python_script(lmb: Callable[[], Any], in_global: bool, import_modu
|
|
|
200
213
|
|
|
201
214
|
# Build type annotation string if available
|
|
202
215
|
if param.annotation is not _inspect.Parameter.empty:
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
type_str = str(param.annotation)
|
|
209
|
-
except Exception:
|
|
210
|
-
type_str = str(param.annotation)
|
|
211
|
-
global_assignments.append(f"{name}: {type_str} = {repr(value)}")
|
|
216
|
+
annotation_literal = _stringify_annotation(param.annotation)
|
|
217
|
+
if isinstance(annotation_literal, str):
|
|
218
|
+
global_assignments.append(f"{name}: {repr(annotation_literal)} = {repr(value)}")
|
|
219
|
+
else:
|
|
220
|
+
global_assignments.append(f"{name} = {repr(value)}")
|
|
212
221
|
else:
|
|
213
222
|
global_assignments.append(f"{name} = {repr(value)}")
|
|
214
223
|
|
|
@@ -233,10 +242,15 @@ def lambda_to_python_script(lmb: Callable[[], Any], in_global: bool, import_modu
|
|
|
233
242
|
|
|
234
243
|
if "Optional" in result_text or "Any" in result_text or "Union" in result_text or "Literal" in result_text:
|
|
235
244
|
result_text = "from typing import Optional, Any, Union, Literal\n\n" + result_text
|
|
236
|
-
|
|
237
245
|
if import_prefix:
|
|
238
246
|
result_text = f"{import_prefix}{result_text}"
|
|
239
247
|
return result_text
|
|
240
248
|
|
|
241
249
|
if __name__ == "__main__":
|
|
242
|
-
|
|
250
|
+
from machineconfig.utils.code import print_code
|
|
251
|
+
import_code_robust = "<import_code_robust>"
|
|
252
|
+
res = lambda_to_python_script(
|
|
253
|
+
lambda: print_code(code=import_code_robust, lexer="python", desc="import as module code"),
|
|
254
|
+
in_global=True, import_module=False
|
|
255
|
+
)
|
|
256
|
+
print(res)
|
machineconfig/utils/options.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
|
-
from machineconfig.utils.installer_utils.
|
|
2
|
+
from machineconfig.utils.installer_utils.installer_locator_utils import check_tool_exists
|
|
3
3
|
from rich.text import Text
|
|
4
4
|
from rich.panel import Panel
|
|
5
5
|
from rich.console import Console
|
|
@@ -14,10 +14,10 @@ from typing import Optional, Union, Iterable, overload, Literal, cast
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
@overload
|
|
17
|
-
def choose_from_options[T](
|
|
17
|
+
def choose_from_options[T](options: Iterable[T], msg: str, multi: Literal[False], custom_input: bool = False, header: str = "", tail: str = "", prompt: str = "", default: Optional[T] = None, fzf: bool = False) -> T: ...
|
|
18
18
|
@overload
|
|
19
|
-
def choose_from_options[T](
|
|
20
|
-
def choose_from_options[T](
|
|
19
|
+
def choose_from_options[T](options: Iterable[T], msg: str, multi: Literal[True], custom_input: bool = True, header: str = "", tail: str = "", prompt: str = "", default: Optional[T] = None, fzf: bool = False, ) -> list[T]: ...
|
|
20
|
+
def choose_from_options[T](options: Iterable[T], msg: str, multi: bool, custom_input: bool = True, header: str = "", tail: str = "", prompt: str = "", default: Optional[T] = None, fzf: bool = False, ) -> Union[T, list[T]]:
|
|
21
21
|
# TODO: replace with https://github.com/tmbo/questionary
|
|
22
22
|
# # also see https://github.com/charmbracelet/gum
|
|
23
23
|
options_strings: list[str] = [str(x) for x in options]
|
|
@@ -16,6 +16,7 @@ OPLike: TypeAlias = Union[str, "PathExtended", Path, None]
|
|
|
16
16
|
PLike: TypeAlias = Union[str, "PathExtended", Path]
|
|
17
17
|
FILE_MODE: TypeAlias = Literal["r", "w", "x", "a"]
|
|
18
18
|
SHUTIL_FORMATS: TypeAlias = Literal["zip", "tar", "gztar", "bztar", "xztar"]
|
|
19
|
+
DECOMPRESS_SUPPORTED_FORMATS = [".tar.gz", ".tgz", ".tar", ".gz", ".tar.bz", ".tbz", ".tar.xz", ".zip", ".7z"]
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
def _is_user_admin() -> bool:
|
|
@@ -152,7 +153,6 @@ class PathExtended(type(Path()), Path): # type: ignore # pylint: disable=E0241
|
|
|
152
153
|
# ======================================= File Editing / Reading ===================================
|
|
153
154
|
def download(self, folder: OPLike = None, name: Optional[str] = None, allow_redirects: bool = True, timeout: Optional[int] = None, params: Any = None) -> "PathExtended":
|
|
154
155
|
import requests
|
|
155
|
-
|
|
156
156
|
response = requests.get(self.as_url_str(), allow_redirects=allow_redirects, timeout=timeout, params=params) # Alternative: from urllib import request; request.urlopen(url).read().decode('utf-8').
|
|
157
157
|
assert response.status_code == 200, f"Download failed with status code {response.status_code}\n{response.text}"
|
|
158
158
|
if name is not None:
|
|
@@ -711,7 +711,7 @@ class PathExtended(type(Path()), Path): # type: ignore # pylint: disable=E0241
|
|
|
711
711
|
:return: pathlib.Path pointing to the destination directory where contents were extracted
|
|
712
712
|
:raises: FileNotFoundError if archive does not exist; py7zr.Bad7zFile or other error if extraction fails
|
|
713
713
|
"""
|
|
714
|
-
import py7zr
|
|
714
|
+
import py7zr # type: ignore
|
|
715
715
|
import tempfile
|
|
716
716
|
from pathlib import Path
|
|
717
717
|
archive_path_obj = Path(archive_path)
|
|
@@ -809,7 +809,7 @@ class PathExtended(type(Path()), Path): # type: ignore # pylint: disable=E0241
|
|
|
809
809
|
path = self
|
|
810
810
|
else:
|
|
811
811
|
try:
|
|
812
|
-
path = self.
|
|
812
|
+
path = PathExtended(self.expanduser().absolute().relative_to(Path.home()))
|
|
813
813
|
except ValueError as ve:
|
|
814
814
|
if strict:
|
|
815
815
|
raise ve
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
from machineconfig.utils.path_extended import PathExtended
|
|
2
1
|
from machineconfig.utils.source_of_truth import EXCLUDE_DIRS
|
|
3
2
|
from rich.console import Console
|
|
4
3
|
from rich.panel import Panel
|
|
@@ -10,8 +9,8 @@ from typing import Optional
|
|
|
10
9
|
console = Console()
|
|
11
10
|
|
|
12
11
|
|
|
13
|
-
def sanitize_path(a_path: str) ->
|
|
14
|
-
path =
|
|
12
|
+
def sanitize_path(a_path: str) -> Path:
|
|
13
|
+
path = Path(a_path)
|
|
15
14
|
if Path.cwd() == Path.home() and not path.exists():
|
|
16
15
|
result = input("Current working directory is home, and passed path is not full path, are you sure you want to continue, [y]/n? ") or "y"
|
|
17
16
|
if result == "y":
|
|
@@ -22,13 +21,13 @@ def sanitize_path(a_path: str) -> PathExtended:
|
|
|
22
21
|
if platform.system() == "Windows": # path copied from Linux/Mac to Windows
|
|
23
22
|
# For Linux: /home/username, for Mac: /Users/username
|
|
24
23
|
skip_parts = 3 if path.as_posix().startswith("/home") else 3 # Both have 3 parts to skip
|
|
25
|
-
path =
|
|
24
|
+
path = Path.home().joinpath(*path.parts[skip_parts:])
|
|
26
25
|
assert path.exists(), f"File not found: {path}"
|
|
27
26
|
source_os = "Linux" if path.as_posix().startswith("/home") else "macOS"
|
|
28
27
|
console.print(Panel(f"🔗 PATH MAPPING | {source_os} → Windows: `{a_path}` ➡️ `{path}`", title="Path Mapping", expand=False))
|
|
29
|
-
elif platform.system() in ["Linux", "Darwin"] and
|
|
28
|
+
elif platform.system() in ["Linux", "Darwin"] and Path.home().as_posix() not in path.as_posix(): # copied between Unix-like systems with different username
|
|
30
29
|
skip_parts = 3 # Both /home/username and /Users/username have 3 parts to skip
|
|
31
|
-
path =
|
|
30
|
+
path = Path.home().joinpath(*path.parts[skip_parts:])
|
|
32
31
|
assert path.exists(), f"File not found: {path}"
|
|
33
32
|
current_os = "Linux" if platform.system() == "Linux" else "macOS"
|
|
34
33
|
source_os = "Linux" if path.as_posix().startswith("/home") else "macOS"
|
|
@@ -36,12 +35,12 @@ def sanitize_path(a_path: str) -> PathExtended:
|
|
|
36
35
|
elif path.as_posix().startswith("C:"):
|
|
37
36
|
if platform.system() in ["Linux", "Darwin"]: # path copied from Windows to Linux/Mac
|
|
38
37
|
xx = str(a_path).replace("\\\\", "/")
|
|
39
|
-
path =
|
|
38
|
+
path = Path.home().joinpath(*Path(xx).parts[3:]) # exclude C:\\Users\\username
|
|
40
39
|
assert path.exists(), f"File not found: {path}"
|
|
41
40
|
target_os = "Linux" if platform.system() == "Linux" else "macOS"
|
|
42
41
|
console.print(Panel(f"🔗 PATH MAPPING | Windows → {target_os}: `{a_path}` ➡️ `{path}`", title="Path Mapping", expand=False))
|
|
43
|
-
elif platform.system() == "Windows" and
|
|
44
|
-
path =
|
|
42
|
+
elif platform.system() == "Windows" and Path.home().as_posix() not in path.as_posix(): # copied from Windows to Windows with different username
|
|
43
|
+
path = Path.home().joinpath(*path.parts[2:])
|
|
45
44
|
assert path.exists(), f"File not found: {path}"
|
|
46
45
|
console.print(Panel(f"🔗 PATH MAPPING | Windows → Windows: `{a_path}` ➡️ `{path}`", title="Path Mapping", expand=False))
|
|
47
46
|
return path.expanduser().absolute()
|
|
@@ -66,12 +65,12 @@ def find_scripts(root: Path, name_substring: str, suffixes: set[str]) -> tuple[l
|
|
|
66
65
|
return filename_matches, partial_path_matches
|
|
67
66
|
|
|
68
67
|
|
|
69
|
-
def match_file_name(sub_string: str, search_root:
|
|
68
|
+
def match_file_name(sub_string: str, search_root: Path, suffixes: set[str]) -> Path:
|
|
70
69
|
search_root_obj = search_root.absolute()
|
|
71
70
|
# assume subscript is filename only, not a sub_path. There is no need to fzf over the paths.
|
|
72
71
|
filename_matches, partial_path_matches = find_scripts(search_root_obj, sub_string, suffixes)
|
|
73
72
|
if len(filename_matches) == 1:
|
|
74
|
-
return
|
|
73
|
+
return Path(filename_matches[0])
|
|
75
74
|
console.print(Panel(f"Partial filename {search_root_obj} match with case-insensitivity failed. This generated #{len(filename_matches)} results.", title="Search", expand=False))
|
|
76
75
|
if len(filename_matches) < 20:
|
|
77
76
|
print("\n".join([a_potential_match.as_posix() for a_potential_match in filename_matches]))
|
|
@@ -80,23 +79,23 @@ def match_file_name(sub_string: str, search_root: PathExtended, suffixes: set[st
|
|
|
80
79
|
# let's see if avoiding .lower() helps narrowing down to one result
|
|
81
80
|
reduced_scripts = [a_potential_match for a_potential_match in filename_matches if sub_string in a_potential_match.name]
|
|
82
81
|
if len(reduced_scripts) == 1:
|
|
83
|
-
return
|
|
82
|
+
return Path(reduced_scripts[0])
|
|
84
83
|
elif len(reduced_scripts) > 1:
|
|
85
84
|
from machineconfig.utils.options import choose_from_options
|
|
86
85
|
choice = choose_from_options(multi=False, msg="Multiple matches found", options=reduced_scripts, fzf=True)
|
|
87
|
-
return
|
|
86
|
+
return Path(choice)
|
|
88
87
|
print(f"Result: This still generated {len(reduced_scripts)} results.")
|
|
89
88
|
if len(reduced_scripts) < 10:
|
|
90
89
|
print("\n".join([a_potential_match.as_posix() for a_potential_match in reduced_scripts]))
|
|
91
90
|
|
|
92
91
|
console.print(Panel(f"Partial path match with case-insensitivity failed. This generated #{len(partial_path_matches)} results.", title="Search", expand=False))
|
|
93
92
|
if len(partial_path_matches) == 1:
|
|
94
|
-
return
|
|
93
|
+
return Path(partial_path_matches[0])
|
|
95
94
|
elif len(partial_path_matches) > 1:
|
|
96
95
|
print("Try to narrow down partial_path_matches search by case-sensitivity.")
|
|
97
96
|
reduced_scripts = [a_potential_match for a_potential_match in partial_path_matches if sub_string in a_potential_match.as_posix()]
|
|
98
97
|
if len(reduced_scripts) == 1:
|
|
99
|
-
return
|
|
98
|
+
return Path(reduced_scripts[0])
|
|
100
99
|
print(f"Result: This still generated {len(reduced_scripts)} results.")
|
|
101
100
|
|
|
102
101
|
try:
|
|
@@ -131,21 +130,24 @@ def match_file_name(sub_string: str, search_root: PathExtended, suffixes: set[st
|
|
|
131
130
|
return search_root_obj.joinpath(res)
|
|
132
131
|
|
|
133
132
|
|
|
134
|
-
def search_for_files_of_interest(path_obj:
|
|
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
|
|
133
|
+
def search_for_files_of_interest(path_obj: Path, suffixes: set[str]) -> list[Path]:
|
|
141
134
|
if path_obj.is_file():
|
|
142
135
|
return [path_obj]
|
|
143
|
-
files: list[
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
136
|
+
files: list[Path] = []
|
|
137
|
+
directories_to_visit: list[Path] = [path_obj]
|
|
138
|
+
while directories_to_visit:
|
|
139
|
+
current_dir = directories_to_visit.pop()
|
|
140
|
+
for entry in current_dir.iterdir():
|
|
141
|
+
if entry.is_dir():
|
|
142
|
+
if entry.name == ".venv":
|
|
143
|
+
continue
|
|
144
|
+
directories_to_visit.append(entry)
|
|
145
|
+
continue
|
|
146
|
+
if entry.suffix not in suffixes:
|
|
147
|
+
continue
|
|
148
|
+
if entry.suffix == ".py" and entry.name == "__init__.py":
|
|
149
|
+
continue
|
|
150
|
+
files.append(entry)
|
|
149
151
|
return files
|
|
150
152
|
|
|
151
153
|
|
|
@@ -160,15 +162,15 @@ def get_choice_file(path: str, suffixes: Optional[set[str]]):
|
|
|
160
162
|
else:
|
|
161
163
|
suffixes = {".py"}
|
|
162
164
|
if not path_obj.exists():
|
|
163
|
-
print(f"🔍 Searching for file matching `{path}` under `{
|
|
164
|
-
choice_file = match_file_name(sub_string=path, search_root=
|
|
165
|
+
print(f"🔍 Searching for file matching `{path}` under `{Path.cwd()}`, but only if suffix matches {suffixes}")
|
|
166
|
+
choice_file = match_file_name(sub_string=path, search_root=Path.cwd(), suffixes=suffixes)
|
|
165
167
|
elif path_obj.is_dir():
|
|
166
168
|
print(f"🔍 Searching recursively for Python, PowerShell and Shell scripts in directory `{path_obj}`")
|
|
167
169
|
files = search_for_files_of_interest(path_obj, suffixes=suffixes)
|
|
168
170
|
print(f"🔍 Got #{len(files)} results.")
|
|
169
171
|
from machineconfig.utils.options import choose_from_options
|
|
170
172
|
choice_file = choose_from_options(multi=False, options=files, fzf=True, msg="Choose one option")
|
|
171
|
-
choice_file =
|
|
173
|
+
choice_file = Path(choice_file)
|
|
172
174
|
else:
|
|
173
175
|
choice_file = path_obj
|
|
174
176
|
return choice_file
|