machineconfig 7.64__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 +4 -2
- machineconfig/jobs/installer/custom_dev/sysabc.py +26 -0
- machineconfig/jobs/installer/installer_data.json +70 -2
- machineconfig/profile/create_links_export.py +2 -2
- machineconfig/scripts/__init__.py +0 -4
- 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 +1 -1
- 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 +13 -13
- 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/start_slidev.py +6 -7
- 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 +7 -7
- machineconfig/scripts/python/helpers_devops/cli_share_server.py +12 -11
- machineconfig/scripts/python/helpers_devops/cli_terminal.py +6 -5
- machineconfig/scripts/python/helpers_devops/cli_utils.py +2 -1
- machineconfig/scripts/python/helpers_devops/devops_status.py +7 -19
- machineconfig/scripts/python/helpers_fire_command/fire_jobs_route_helper.py +20 -9
- machineconfig/scripts/python/helpers_navigator/command_tree.py +50 -18
- machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py +5 -3
- machineconfig/scripts/python/helpers_repos/count_lines_frontend.py +1 -1
- machineconfig/scripts/python/helpers_utils/download.py +4 -3
- machineconfig/scripts/python/helpers_utils/path.py +81 -31
- machineconfig/scripts/python/interactive.py +1 -1
- 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/terminal.py +2 -2
- machineconfig/scripts/python/utils.py +10 -9
- 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/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 +4 -2
- machineconfig/utils/installer_utils/install_from_url.py +180 -0
- machineconfig/utils/installer_utils/installer_class.py +18 -10
- machineconfig/utils/installer_utils/installer_cli.py +14 -9
- machineconfig/utils/links.py +2 -2
- machineconfig/utils/meta.py +2 -2
- machineconfig/utils/options.py +3 -3
- machineconfig/utils/path_extended.py +1 -1
- machineconfig/utils/path_helper.py +0 -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.64.dist-info → machineconfig-7.79.dist-info}/METADATA +1 -1
- {machineconfig-7.64.dist-info → machineconfig-7.79.dist-info}/RECORD +77 -68
- {machineconfig-7.64.dist-info → machineconfig-7.79.dist-info}/entry_points.txt +2 -2
- machineconfig/scripts/python/explore.py +0 -49
- /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-7.64.dist-info → machineconfig-7.79.dist-info}/WHEEL +0 -0
- {machineconfig-7.64.dist-info → machineconfig-7.79.dist-info}/top_level.txt +0 -0
|
@@ -3,9 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
import typer
|
|
5
5
|
|
|
6
|
-
from typing import Optional
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
from typing import Annotated, Literal, TypedDict
|
|
6
|
+
from typing import Optional, Annotated, Literal, TypedDict
|
|
9
7
|
|
|
10
8
|
|
|
11
9
|
def path():
|
|
@@ -17,43 +15,76 @@ def path():
|
|
|
17
15
|
uv_with = ["textual"]
|
|
18
16
|
uv_project_dir = None
|
|
19
17
|
if not Path.home().joinpath("code/machineconfig").exists():
|
|
20
|
-
uv_with.append("machineconfig>=7.
|
|
18
|
+
uv_with.append("machineconfig>=7.79")
|
|
21
19
|
else:
|
|
22
20
|
uv_project_dir = str(Path.home().joinpath("code/machineconfig"))
|
|
23
21
|
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])
|
|
24
22
|
|
|
25
23
|
|
|
26
|
-
def init_project(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
24
|
+
def init_project(
|
|
25
|
+
name: Annotated[Optional[str], typer.Option("--name", "-n", help="Name of the project.")]= None,
|
|
26
|
+
tmp_directory: Annotated[bool, typer.Option("--tmp-directory/--no-tmp-directory", "-t/-nt", help="Use a temporary directory for the project initialization.")]= False,
|
|
27
|
+
python: Annotated[Literal["3.13", "3.14"], typer.Option("--python", "-p", help="Python version for the uv virtual environment.")]= "3.13",
|
|
28
|
+
packages: Annotated[Optional[str], typer.Option("--packages", "-p", help="Additional packages to include in the uv virtual environment.")]= None,
|
|
29
|
+
group: Annotated[Optional[str], typer.Option("--group", "-g", help="Group name for the packages.")]= "plot",
|
|
30
|
+
types_packages: Annotated[bool, typer.Option("--types-packages/--no-types-packages", "-T/-NT", help="Include types packages for better type hinting.")]= True,
|
|
31
|
+
linting_debug_packages: Annotated[bool, typer.Option("--linting-debug-packages/--no-linting-debug-packages", "-L/-NL", help="Include linting and debugging packages.")]= True,
|
|
32
|
+
ia_packages: Annotated[bool, typer.Option("--ia-packages/--no-ia-packages", "-I/-NI", help="Include interactive and IA packages.")]= True,
|
|
33
|
+
plot_packages: Annotated[bool, typer.Option("--plot-packages/--no-plot-packages", "-P/-NP", help="Include plotting packages.")]= True,
|
|
34
|
+
data_packages: Annotated[bool, typer.Option("--data-packages/--no-data-packages", "-D/-ND", help="Include data manipulation packages.")]= True,
|
|
35
|
+
) -> None:
|
|
36
|
+
if packages is not None:
|
|
37
|
+
packages_add_line = f"uv add {packages}"
|
|
38
|
+
else:
|
|
39
|
+
packages_add_line = ""
|
|
40
|
+
from pathlib import Path
|
|
41
|
+
if not tmp_directory:
|
|
42
|
+
repo_root = Path.cwd()
|
|
43
|
+
if not (repo_root / "pyproject.toml").exists():
|
|
44
|
+
typer.echo("❌ Error: pyproject.toml not found.", err=True)
|
|
45
|
+
raise typer.Exit(code=1)
|
|
46
|
+
starting_code = ""
|
|
47
|
+
else:
|
|
48
|
+
if name is not None:
|
|
49
|
+
from machineconfig.utils.accessories import randstr
|
|
50
|
+
repo_root = Path.home().joinpath(f"tmp_results/tmp_projects/{name}")
|
|
51
|
+
else:
|
|
52
|
+
from machineconfig.utils.accessories import randstr
|
|
53
|
+
repo_root = Path.home().joinpath(f"tmp_results/tmp_projects/{randstr(6)}")
|
|
54
|
+
repo_root.mkdir(parents=True, exist_ok=True)
|
|
55
|
+
print(f"Using temporary directory for project initialization: {repo_root}")
|
|
56
|
+
starting_code = f"""
|
|
57
|
+
cd {repo_root}
|
|
58
|
+
uv init --python {python}
|
|
59
|
+
uv venv
|
|
51
60
|
"""
|
|
52
|
-
|
|
53
|
-
|
|
61
|
+
print(f"Adding group `{group}` with common data science and plotting packages...")
|
|
62
|
+
total_packages: list[str] = []
|
|
63
|
+
|
|
64
|
+
if types_packages:
|
|
65
|
+
total_packages.append("types-python-dateutil types-pyyaml types-requests types-tqdm types-mysqlclient types-paramiko types-pytz types-sqlalchemy types-toml types-urllib3")
|
|
66
|
+
if linting_debug_packages:
|
|
67
|
+
total_packages.append("mypy pyright ruff pylint pyrefly cleanpy ipdb pudb")
|
|
68
|
+
if ia_packages:
|
|
69
|
+
total_packages.append("ipython ipykernel jupyterlab nbformat marimo")
|
|
70
|
+
if plot_packages:
|
|
71
|
+
total_packages.append("python-magic matplotlib plotly kaleido")
|
|
72
|
+
if data_packages:
|
|
73
|
+
total_packages.append("numpy pandas polars duckdb-engine sqlalchemy psycopg2-binary pyarrow tqdm openpyxl")
|
|
74
|
+
from machineconfig.utils.ve import get_ve_activate_line
|
|
75
|
+
script = f"""
|
|
76
|
+
{starting_code}
|
|
77
|
+
{packages_add_line}
|
|
78
|
+
uv add --group {group} {" ".join(total_packages)}
|
|
79
|
+
{get_ve_activate_line(ve_root=str(repo_root.joinpath(".venv")))}
|
|
80
|
+
ls
|
|
81
|
+
"""
|
|
82
|
+
from machineconfig.utils.code import exit_then_run_shell_script
|
|
83
|
+
exit_then_run_shell_script(script)
|
|
54
84
|
|
|
55
85
|
|
|
56
86
|
def edit_file_with_hx(path: Annotated[Optional[str], typer.Argument(..., help="The root directory of the project to edit, or a file path.")] = None) -> None:
|
|
87
|
+
from pathlib import Path
|
|
57
88
|
if path is None:
|
|
58
89
|
root_path = Path.cwd()
|
|
59
90
|
print(f"No path provided. Using current working directory: {root_path}")
|
|
@@ -82,6 +113,13 @@ class MachineSpecs(TypedDict):
|
|
|
82
113
|
system: str
|
|
83
114
|
distro: str
|
|
84
115
|
home_dir: str
|
|
116
|
+
hostname: str
|
|
117
|
+
release: str
|
|
118
|
+
version: str
|
|
119
|
+
machine: str
|
|
120
|
+
processor: str
|
|
121
|
+
python_version: str
|
|
122
|
+
user: str
|
|
85
123
|
|
|
86
124
|
|
|
87
125
|
def get_machine_specs() -> MachineSpecs:
|
|
@@ -90,11 +128,21 @@ def get_machine_specs() -> MachineSpecs:
|
|
|
90
128
|
UV_RUN_CMD = "$HOME/.local/bin/uv run" if platform.system() != "Windows" else """& "$env:USERPROFILE/.local/bin/uv" run"""
|
|
91
129
|
command = f"""{UV_RUN_CMD} --with distro python -c "import distro; print(distro.name(pretty=True))" """
|
|
92
130
|
import subprocess
|
|
131
|
+
from pathlib import Path
|
|
132
|
+
import socket
|
|
133
|
+
import os
|
|
93
134
|
distro = subprocess.run(command, shell=True, capture_output=True, text=True).stdout.strip()
|
|
94
135
|
specs: MachineSpecs = {
|
|
95
136
|
"system": platform.system(),
|
|
96
137
|
"distro": distro,
|
|
97
138
|
"home_dir": str(Path.home()),
|
|
139
|
+
"hostname": socket.gethostname(),
|
|
140
|
+
"release": platform.release(),
|
|
141
|
+
"version": platform.version(),
|
|
142
|
+
"machine": platform.machine(),
|
|
143
|
+
"processor": platform.processor() or "Unknown",
|
|
144
|
+
"python_version": platform.python_version(),
|
|
145
|
+
"user": os.getenv("USER") or os.getenv("USERNAME") or "Unknown",
|
|
98
146
|
}
|
|
99
147
|
print(specs)
|
|
100
148
|
from machineconfig.utils.source_of_truth import CONFIG_ROOT
|
|
@@ -104,3 +152,5 @@ def get_machine_specs() -> MachineSpecs:
|
|
|
104
152
|
path.write_text(json.dumps(specs, indent=4), encoding="utf-8")
|
|
105
153
|
return specs
|
|
106
154
|
|
|
155
|
+
if __name__ == "__main__":
|
|
156
|
+
get_machine_specs()
|
|
@@ -111,7 +111,7 @@ def execute_installations(selected_options: list[str]) -> None:
|
|
|
111
111
|
console.print(Panel("⚡ [bold bright_yellow]CLI APPLICATIONS[/bold bright_yellow]\n[italic]Command-line tools installation[/italic]", border_style="bright_yellow"))
|
|
112
112
|
console.print("🔧 Installing CLI applications", style="bold cyan")
|
|
113
113
|
try:
|
|
114
|
-
from machineconfig.utils.installer_utils.installer_cli import
|
|
114
|
+
from machineconfig.utils.installer_utils.installer_cli import main_installer_cli as devops_devapps_install_main
|
|
115
115
|
devops_devapps_install_main(group=True, which=maybe_a_group, interactive=False)
|
|
116
116
|
console.print("✅ CLI applications installed successfully", style="bold green")
|
|
117
117
|
except Exception as e:
|
|
@@ -1,8 +1,27 @@
|
|
|
1
1
|
|
|
2
2
|
import typer
|
|
3
|
+
from typing import Annotated
|
|
3
4
|
|
|
4
5
|
|
|
5
|
-
def
|
|
6
|
+
def machineconfig_search(
|
|
7
|
+
directory: Annotated[str, typer.Option(..., "--directory", "-d", help="The directory to search")] = ".",
|
|
8
|
+
ast: Annotated[bool, typer.Option(..., "--ast", "-a", help="The abstract syntax tree search/ tree sitter search of symbols")] = False):
|
|
9
|
+
|
|
10
|
+
if ast:
|
|
11
|
+
from machineconfig.scripts.python.helpers.ast_search import get_repo_symbols
|
|
12
|
+
symbols = get_repo_symbols(directory)
|
|
13
|
+
from machineconfig.utils.options import choose_from_options
|
|
14
|
+
try:
|
|
15
|
+
res = choose_from_options(options=symbols, msg="Select a symbol to search for:", fzf=True, multi=False)
|
|
16
|
+
from rich import print_json
|
|
17
|
+
import json
|
|
18
|
+
res_json = json.dumps(res, indent=4)
|
|
19
|
+
print_json(res_json)
|
|
20
|
+
return None
|
|
21
|
+
except Exception as e:
|
|
22
|
+
print(f"❌ Error during selection: {e}")
|
|
23
|
+
return None
|
|
24
|
+
|
|
6
25
|
from machineconfig.scripts.python.helpers_msearch import FZFG_LINUX_PATH, FZFG_WINDOWS_PATH
|
|
7
26
|
import platform
|
|
8
27
|
if platform.system() == "Linux":
|
|
@@ -17,5 +36,5 @@ def machineconfig_find():
|
|
|
17
36
|
|
|
18
37
|
def main():
|
|
19
38
|
app = typer.Typer(add_completion=False, no_args_is_help=True)
|
|
20
|
-
app.command(name="msearch", help="machineconfig search helper", no_args_is_help=False)(
|
|
39
|
+
app.command(name="msearch", help="machineconfig search helper", no_args_is_help=False)(machineconfig_search)
|
|
21
40
|
app()
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
|
|
2
|
+
from typing import cast, Optional
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def get_all_ipv4_addresses() -> list[tuple[str, str]]:
|
|
6
|
+
import psutil
|
|
7
|
+
import socket
|
|
8
|
+
result: list[tuple[str, str]] = []
|
|
9
|
+
for iface, addrs in psutil.net_if_addrs().items():
|
|
10
|
+
for addr in addrs:
|
|
11
|
+
if addr.family == socket.AF_INET:
|
|
12
|
+
ip = addr.address
|
|
13
|
+
result.append((iface, ip))
|
|
14
|
+
return result
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def select_lan_ipv4(prefer_vpn: bool) -> Optional[str]:
|
|
18
|
+
"""
|
|
19
|
+
Choose the best 'real LAN' IPv4:
|
|
20
|
+
- Excludes loopback/link-local and (by default) VPN/tunnel/container ifaces
|
|
21
|
+
- Prefers physical-looking ifaces (eth/en*/wlan/wl*)
|
|
22
|
+
- Prefers RFC1918 LANs: 192.168/16 > 10/8 > 172.16/12
|
|
23
|
+
- Requires interface is UP
|
|
24
|
+
Set prefer_vpn=True to allow tunnel/VPN ifaces to compete.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
import ipaddress
|
|
28
|
+
import re
|
|
29
|
+
from collections.abc import Sequence
|
|
30
|
+
import psutil
|
|
31
|
+
|
|
32
|
+
# Down-rank or exclude: tunnels/VPNs/bridges/containers (add your own if needed)
|
|
33
|
+
VIRTUAL_IFACE_PAT = re.compile(
|
|
34
|
+
r"^(?:lo|loopback|docker\d*|br-.*|veth.*|virbr.*|bridge.*|"
|
|
35
|
+
r"vboxnet.*|vmnet.*|zt.*|ham.*|tailscale.*|wg\d*|utun\d*|llw\d*|awdl\d*|"
|
|
36
|
+
r"tun\d*|tap\d*|cloudflarewarp.*|warp.*)$",
|
|
37
|
+
re.IGNORECASE,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# Light preference for names that look like real NICs
|
|
41
|
+
PHYSICAL_IFACE_PAT = re.compile(
|
|
42
|
+
r"^(?:eth\d*|en\d*|enp.*|ens.*|eno.*|wlan\d*|wl.*|.*wifi.*|.*ethernet.*)$",
|
|
43
|
+
re.IGNORECASE,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
# Known noisy CIDRs to avoid
|
|
47
|
+
NOISY_NETS: list[ipaddress.IPv4Network] = [
|
|
48
|
+
ipaddress.IPv4Network("100.64.0.0/10"), # CGNAT (Tailscale/others)
|
|
49
|
+
ipaddress.IPv4Network("172.17.0.0/16"), # docker0 default
|
|
50
|
+
ipaddress.IPv4Network("172.18.0.0/16"),
|
|
51
|
+
ipaddress.IPv4Network("172.19.0.0/16"),
|
|
52
|
+
ipaddress.IPv4Network("192.168.49.0/24"), # minikube default
|
|
53
|
+
ipaddress.IPv4Network("10.0.2.0/24"), # VirtualBox NAT
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
def _in_any(ip: ipaddress.IPv4Address, nets: Sequence[ipaddress.IPv4Network]) -> bool:
|
|
57
|
+
return any(ip in n for n in nets)
|
|
58
|
+
|
|
59
|
+
stats = psutil.net_if_stats()
|
|
60
|
+
best = None
|
|
61
|
+
best_score = -10**9
|
|
62
|
+
import socket
|
|
63
|
+
for iface, addrs in psutil.net_if_addrs().items():
|
|
64
|
+
st = stats.get(iface)
|
|
65
|
+
if not st or not st.isup:
|
|
66
|
+
continue
|
|
67
|
+
|
|
68
|
+
for a in addrs:
|
|
69
|
+
if a.family != socket.AF_INET or not a.address:
|
|
70
|
+
continue
|
|
71
|
+
|
|
72
|
+
ip_str = a.address
|
|
73
|
+
try:
|
|
74
|
+
ip = cast(ipaddress.IPv4Address, ipaddress.ip_address(ip_str))
|
|
75
|
+
except ValueError:
|
|
76
|
+
continue
|
|
77
|
+
|
|
78
|
+
# Exclude unusable classes
|
|
79
|
+
if ip.is_loopback or ip.is_link_local: # 127.0.0.0/8, 169.254.0.0/16
|
|
80
|
+
continue
|
|
81
|
+
|
|
82
|
+
# Hard filter: if it looks virtual and we don't prefer VPNs, skip it
|
|
83
|
+
if not prefer_vpn and VIRTUAL_IFACE_PAT.match(iface):
|
|
84
|
+
continue
|
|
85
|
+
|
|
86
|
+
# Hard filter: known noisy subnets (docker, cgnat, etc.)
|
|
87
|
+
if _in_any(ip, NOISY_NETS) and not prefer_vpn:
|
|
88
|
+
continue
|
|
89
|
+
|
|
90
|
+
# Base score
|
|
91
|
+
score = 0
|
|
92
|
+
|
|
93
|
+
# Prefer physical-looking names
|
|
94
|
+
if PHYSICAL_IFACE_PAT.match(iface):
|
|
95
|
+
score += 200
|
|
96
|
+
|
|
97
|
+
# Broadcast present usually means L2 LAN (not point-to-point)
|
|
98
|
+
# (psutil puts it on the same entry as .broadcast)
|
|
99
|
+
if getattr(a, "broadcast", None):
|
|
100
|
+
score += 100
|
|
101
|
+
|
|
102
|
+
# Prefer private RFC1918; rank families
|
|
103
|
+
if ip.is_private:
|
|
104
|
+
# Order: 192.168.x.x > 10.x.x.x > 172.16-31.x.x
|
|
105
|
+
ip_net = ipaddress.IPv4Network((ip, 32), strict=False)
|
|
106
|
+
if ipaddress.IPv4Network("192.168.0.0/16").supernet_of(ip_net):
|
|
107
|
+
score += 90
|
|
108
|
+
elif ipaddress.IPv4Network("10.0.0.0/8").supernet_of(ip_net):
|
|
109
|
+
score += 70
|
|
110
|
+
elif ipaddress.IPv4Network("172.16.0.0/12").supernet_of(ip_net):
|
|
111
|
+
score += 50
|
|
112
|
+
else:
|
|
113
|
+
# Public on a NIC is unusual for a home/office LAN
|
|
114
|
+
score -= 50
|
|
115
|
+
|
|
116
|
+
# Slight nudge by interface speed if known (>0 means psutil knows it)
|
|
117
|
+
# (Many tunnels report 0)
|
|
118
|
+
if getattr(st, "speed", 0) > 0:
|
|
119
|
+
score += 20
|
|
120
|
+
|
|
121
|
+
# Deterministic tie-breaker: prefer shorter iface name (eth0 over eth10)
|
|
122
|
+
score -= len(iface) * 0.01
|
|
123
|
+
|
|
124
|
+
if score > best_score:
|
|
125
|
+
best_score = score
|
|
126
|
+
best = ip_str
|
|
127
|
+
|
|
128
|
+
return best
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
if __name__ == "__main__":
|
|
132
|
+
print(select_lan_ipv4(False) or "No LAN IPv4 found")
|
|
@@ -137,11 +137,14 @@ def main(pub_path: Annotated[Optional[str], typer.Argument(..., help="Path to th
|
|
|
137
137
|
console.print(Panel("🚀 SSH KEY AUTHORIZATION READY\nRun the generated script to apply changes", box=box.DOUBLE_EDGE, title_align="left"))
|
|
138
138
|
from machineconfig.utils.code import run_shell_script
|
|
139
139
|
run_shell_script(script=program)
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
140
|
+
|
|
141
|
+
import machineconfig.scripts.python.nw.address as helper
|
|
142
|
+
res = helper.select_lan_ipv4(prefer_vpn=False)
|
|
143
|
+
if res is None:
|
|
144
|
+
console.print(Panel("❌ ERROR: Could not determine local LAN IPv4 address", title="[bold red]Error[/bold red]", border_style="red"))
|
|
145
|
+
raise typer.Exit(code=1)
|
|
146
|
+
local_ip_v4 = res
|
|
147
|
+
|
|
145
148
|
console.print(Panel(f"🌐 This computer is accessible at: {local_ip_v4}", title="[bold green]Network Info[/bold green]", border_style="green"))
|
|
146
149
|
console.print(Panel("✅ SSH KEY AUTHORIZATION COMPLETED", box=box.DOUBLE_EDGE, title_align="left"))
|
|
147
150
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import subprocess
|
|
2
|
-
# from machineconfig.utils.schemas.layouts.layout_types import LayoutConfig
|
|
3
1
|
import typer
|
|
4
2
|
from typing import Annotated
|
|
5
3
|
|
|
@@ -26,6 +24,7 @@ def choose_zellij_session(
|
|
|
26
24
|
typer.Exit()
|
|
27
25
|
return
|
|
28
26
|
cmd = "zellij list-sessions"
|
|
27
|
+
import subprocess
|
|
29
28
|
sessions: list[str] = subprocess.check_output(cmd, shell=True).decode().strip().split("\n")
|
|
30
29
|
# filter out empty lines and keep raw lines (they contain creation info)
|
|
31
30
|
sessions = [s for s in sessions if s.strip()]
|
|
@@ -63,6 +62,7 @@ def choose_zellij_session(
|
|
|
63
62
|
|
|
64
63
|
def get_session_tabs() -> list[tuple[str, str]]:
|
|
65
64
|
cmd = "zellij list-sessions"
|
|
65
|
+
import subprocess
|
|
66
66
|
sessions: list[str] = subprocess.check_output(cmd, shell=True).decode().strip().split("\n")
|
|
67
67
|
sessions = [strip_ansi_codes(s) for s in sessions]
|
|
68
68
|
active_sessions = [s for s in sessions if "EXITED" not in s]
|
|
@@ -6,6 +6,7 @@ from machineconfig.scripts.python.helpers_utils.download import download
|
|
|
6
6
|
import typer
|
|
7
7
|
from typing import Annotated
|
|
8
8
|
|
|
9
|
+
|
|
9
10
|
def kill_process(
|
|
10
11
|
# name: Annotated[Optional[str], typer.Option(..., "--name", "-n", help="Name of the process to kill")],
|
|
11
12
|
# command: Annotated[str, typer.Option(..., "--command", "-c", help="Match by command line instead of process name")] = "",
|
|
@@ -29,27 +30,27 @@ def upgrade_packages():
|
|
|
29
30
|
|
|
30
31
|
def get_app() -> typer.Typer:
|
|
31
32
|
app = typer.Typer(help="🛠️ utilities operations", no_args_is_help=True, add_help_option=False, add_completion=False)
|
|
32
|
-
app.command(name="kill-process", no_args_is_help=False, help="[k] Choose a process to kill")(kill_process)
|
|
33
|
+
app.command(name="kill-process", no_args_is_help=False, help="⚔️ [k] Choose a process to kill")(kill_process)
|
|
33
34
|
app.command(name="k", no_args_is_help=False, help="Choose a process to kill", hidden=True)(kill_process)
|
|
34
35
|
|
|
35
|
-
app.command("path", no_args_is_help=False, help="📚
|
|
36
|
+
app.command("path", no_args_is_help=False, help="📚 [p] NAVIGATE PATH variable with TUI")(path)
|
|
36
37
|
app.command("p", no_args_is_help=False, help="NAVIGATE PATH variable with TUI", hidden=True)(path)
|
|
37
38
|
|
|
38
|
-
app.command(name="upgrade-packages", no_args_is_help=False, help="[up] Upgrade project dependencies.")(upgrade_packages)
|
|
39
|
+
app.command(name="upgrade-packages", no_args_is_help=False, help="⬆️ [up] Upgrade project dependencies.")(upgrade_packages)
|
|
39
40
|
app.command(name="up", no_args_is_help=False, hidden=True)(upgrade_packages)
|
|
40
41
|
|
|
41
|
-
app.command(name="download", no_args_is_help=True, help="[d] Download a file from a URL and optionally decompress it.")(download)
|
|
42
|
+
app.command(name="download", no_args_is_help=True, help="⬇️ [d] Download a file from a URL and optionally decompress it.")(download)
|
|
42
43
|
app.command(name="d", no_args_is_help=True, hidden=True)(download)
|
|
43
|
-
app.command(name="get-machine-specs", no_args_is_help=False, help="[g] Get machine specifications.")(get_machine_specs)
|
|
44
|
+
app.command(name="get-machine-specs", no_args_is_help=False, help="💻 [g] Get machine specifications.")(get_machine_specs)
|
|
44
45
|
app.command(name="g", no_args_is_help=False, hidden=True)(get_machine_specs)
|
|
45
|
-
app.command(name="init-project", no_args_is_help=False, help="[i] Initialize a project with a uv virtual environment and install dev packages.")(init_project)
|
|
46
|
+
app.command(name="init-project", no_args_is_help=False, help="🚀 [i] Initialize a project with a uv virtual environment and install dev packages.")(init_project)
|
|
46
47
|
app.command(name="i", no_args_is_help=False, hidden=True)(init_project)
|
|
47
|
-
app.command(name="edit", no_args_is_help=False, help="[e] Open a file in the default editor.")(edit_file_with_hx)
|
|
48
|
+
app.command(name="edit", no_args_is_help=False, help="✏️ [e] Open a file in the default editor.")(edit_file_with_hx)
|
|
48
49
|
app.command(name="e", no_args_is_help=False, hidden=True)(edit_file_with_hx)
|
|
49
50
|
|
|
50
|
-
app.command(name="pdf-merge", no_args_is_help=True, help="[pm] Merge two PDF files into one.")(merge_pdfs)
|
|
51
|
+
app.command(name="pdf-merge", no_args_is_help=True, help="📄 [pm] Merge two PDF files into one.")(merge_pdfs)
|
|
51
52
|
app.command(name="pm", no_args_is_help=True, hidden=True)(merge_pdfs)
|
|
52
|
-
app.command(name="pdf-compress", no_args_is_help=True, help="[pc] Compress a PDF file.")(compress_pdf)
|
|
53
|
+
app.command(name="pdf-compress", no_args_is_help=True, help="📦 [pc] Compress a PDF file.")(compress_pdf)
|
|
53
54
|
app.command(name="pc", no_args_is_help=True, hidden=True)(compress_pdf)
|
|
54
55
|
|
|
55
56
|
# app.command(name="copy", no_args_is_help=True, help="[c] Copy files or directories.")(copy)
|
|
@@ -7,7 +7,7 @@ $user = ''
|
|
|
7
7
|
$sharePath = ''
|
|
8
8
|
$driveLetter = ''
|
|
9
9
|
|
|
10
|
-
uv run --python 3.14 --with "machineconfig>=7.
|
|
10
|
+
uv run --python 3.14 --with "machineconfig>=7.79" python -m machineconfig.scripts.python.mount_ssh
|
|
11
11
|
|
|
12
12
|
net use T: \\sshfs.kr\$user@$host.local
|
|
13
13
|
# this worked: net use T: \\sshfs\alex@alex-p51s-5.local
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
function lfcd {
|
|
19
19
|
$tmp = [System.IO.Path]::GetTempFileName()
|
|
20
|
-
|
|
20
|
+
& "$env:USERPROFILE\AppData\Local\Microsoft\WindowsApps\lf.exe" -last-dir-path="$tmp" $args
|
|
21
21
|
if (Test-Path -PathType Leaf "$tmp")
|
|
22
22
|
{
|
|
23
23
|
$dir = Get-Content "$tmp"
|
|
@@ -1,13 +1,52 @@
|
|
|
1
|
+
# machineconfig Nushell environment setup
|
|
1
2
|
|
|
3
|
+
def reduce_non_empty [segments: list<string>] -> list<string> {
|
|
4
|
+
segments
|
|
5
|
+
| reduce --fold [] { |segment, acc|
|
|
6
|
+
if (($segment | str length) > 0) {
|
|
7
|
+
$acc | append $segment
|
|
8
|
+
} else {
|
|
9
|
+
$acc
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
2
13
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
14
|
+
let default_root = ($env.HOME | path join ".config" "machineconfig")
|
|
15
|
+
let config_root = (
|
|
16
|
+
$env.CONFIG_ROOT?
|
|
17
|
+
| default $default_root
|
|
18
|
+
| path expand
|
|
19
|
+
)
|
|
6
20
|
|
|
21
|
+
load-env { CONFIG_ROOT: $config_root }
|
|
7
22
|
|
|
23
|
+
let existing_segments = (
|
|
24
|
+
$env.PATH?
|
|
25
|
+
| default ""
|
|
26
|
+
| split row (char esep)
|
|
27
|
+
| reduce_non_empty
|
|
28
|
+
)
|
|
8
29
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
30
|
+
let desired_paths = [
|
|
31
|
+
($config_root | path join "scripts")
|
|
32
|
+
($env.HOME | path join "dotfiles" "scripts" "linux")
|
|
33
|
+
($env.HOME | path join ".local" "bin")
|
|
34
|
+
($env.HOME | path join ".cargo" "bin")
|
|
35
|
+
"/usr/games"
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
let merged_segments = (
|
|
39
|
+
$desired_paths
|
|
40
|
+
| reduce --fold $existing_segments { |entry, acc|
|
|
41
|
+
if (($entry | path exists) and (not ($entry in $acc))) {
|
|
42
|
+
$acc | append $entry
|
|
43
|
+
} else {
|
|
44
|
+
$acc
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
let new_path = ($merged_segments | str join (char esep))
|
|
50
|
+
load-env { PATH: $new_path }
|
|
12
51
|
|
|
13
52
|
|