machineconfig 7.55__py3-none-any.whl → 7.57__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.

@@ -1844,12 +1844,12 @@
1844
1844
  "fileNamePattern": {
1845
1845
  "amd64": {
1846
1846
  "linux": "miniserve-{version}-x86_64-unknown-linux-musl",
1847
- "darwin": "miniserve-{version}-x86_64-apple-darwin",
1847
+ "macos": "miniserve-{version}-x86_64-apple-darwin",
1848
1848
  "windows": "miniserve-{version}-x86_64-pc-windows-msvc.exe"
1849
1849
  },
1850
1850
  "arm64": {
1851
1851
  "linux": "miniserve-{version}-aarch64-unknown-linux-musl",
1852
- "darwin": "miniserve-{version}-aarch64-apple-darwin",
1852
+ "macos": "miniserve-{version}-aarch64-apple-darwin",
1853
1853
  "windows": "miniserve-{version}-aarch64-pc-windows-msvc.exe"
1854
1854
  }
1855
1855
  }
@@ -2200,14 +2200,14 @@
2200
2200
  "doc": "🖥️ Text-based desktop environment inside your terminal",
2201
2201
  "fileNamePattern": {
2202
2202
  "amd64": {
2203
- "linux": null,
2204
- "macos": null,
2205
- "windows": null
2203
+ "linux": "vtm_linux_x86_64.tar.7z",
2204
+ "macos": "vtm_macos_any.tar.7z",
2205
+ "windows": "vtm_windows_x86_64.7z"
2206
2206
  },
2207
2207
  "arm64": {
2208
- "linux": null,
2209
- "macos": null,
2210
- "windows": null
2208
+ "linux": "vtm_linux_arm64.tar.7z",
2209
+ "macos": "vtm_macos_any.tar.7z",
2210
+ "windows": "vtm_windows_arm64.7z"
2211
2211
  }
2212
2212
  }
2213
2213
  },
@@ -107,7 +107,7 @@ def croshell(
107
107
  fire_line = f"uv run --python 3.14 --with visidata,pyarrow vd {str(file_obj)}"
108
108
  elif marimo:
109
109
  if Path.home().joinpath("code/machineconfig").exists(): requirements = f"""--with marimo --project "{str(Path.home().joinpath("code/machineconfig"))}" """
110
- else: requirements = """--python 3.14 --with "marimo,cowsay,machineconfig[plot]>=7.55" """
110
+ else: requirements = """--python 3.14 --with "marimo,cowsay,machineconfig[plot]>=7.57" """
111
111
  fire_line = f"""
112
112
  cd {str(pyfile.parent)}
113
113
  uv run --python 3.14 --with "marimo" marimo convert {pyfile.name} -o marimo_nb.py
@@ -115,14 +115,14 @@ uv run {requirements} marimo edit --host 0.0.0.0 marimo_nb.py
115
115
  """
116
116
  elif jupyter:
117
117
  if Path.home().joinpath("code/machineconfig").exists(): requirements = f"""--project "{str(Path.home().joinpath("code/machineconfig"))}" --with jupyterlab """
118
- else: requirements = """--with "cowsay,machineconfig[plot]>=7.55" """
118
+ else: requirements = """--with "cowsay,machineconfig[plot]>=7.57" """
119
119
  fire_line = f"uv run {requirements} jupyter-lab {str(nb_target)}"
120
120
  elif vscode:
121
121
  fire_line = f"""
122
122
  cd {str(pyfile.parent)}
123
123
  uv init --python 3.14
124
124
  uv venv
125
- uv add "cowsay,machineconfig[plot]>=7.55"
125
+ uv add "cowsay,machineconfig[plot]>=7.57"
126
126
  # code serve-web
127
127
  code --new-window {str(pyfile)}
128
128
  """
@@ -130,7 +130,7 @@ code --new-window {str(pyfile)}
130
130
  if interpreter == "ipython": profile = f" --profile {ipython_profile} --no-banner"
131
131
  else: profile = ""
132
132
  if Path.home().joinpath("code/machineconfig").exists(): ve_line = f"""--project "{str(Path.home().joinpath("code/machineconfig"))}" """
133
- else: ve_line = """--python 3.14 --with "cowsay,machineconfig[plot]>=7.55" """
133
+ else: ve_line = """--python 3.14 --with "cowsay,machineconfig[plot]>=7.57" """
134
134
  # ve_path_maybe, ipython_profile_maybe = get_ve_path_and_ipython_profile(Path.cwd())
135
135
  # --python 3.14
136
136
  fire_line = f"uv run {ve_line} {interpreter} {interactivity} {profile} {str(pyfile)}"
@@ -2,7 +2,7 @@
2
2
  # /// script
3
3
  # requires-python = ">=3.13"
4
4
  # dependencies = [
5
- # "machineconfig>=7.55",
5
+ # "machineconfig>=7.57",
6
6
  # "textual",
7
7
  # "pyperclip",
8
8
  # ]
@@ -12,7 +12,9 @@ def main(
12
12
  method: Annotated[Literal["symlink", "s", "copy", "c"], typer.Option(..., "--method", "-m", help="Method to use for linking files")] = "copy",
13
13
  on_conflict: Annotated[ON_CONFLICT_LOOSE, typer.Option(..., "--on-conflict", "-o", help="Action to take on conflict")] = "throw-error",
14
14
  sensitivity: Annotated[Literal["private", "v", "public", "b"], typer.Option(..., "--sensitivity", "-s", help="Sensitivity of the config file.")] = "private",
15
- destination: Annotated[str, typer.Option("--destination", "-d", help="destination folder (override the default, use at your own risk)")] = "",) -> None:
15
+ destination: Annotated[str, typer.Option("--destination", "-d", help="destination folder (override the default, use at your own risk)")] = "",
16
+ shared: Annotated[bool, typer.Option("--shared", "-sh", help="Whether the config file is shared across destinations directory.")] = False,
17
+ ) -> None:
16
18
  from rich.console import Console
17
19
  from rich.panel import Panel
18
20
  from machineconfig.utils.links import symlink_map, copy_map
@@ -27,14 +29,22 @@ def main(
27
29
  console = Console()
28
30
  orig_path = Path(file).expanduser().absolute()
29
31
  if destination == "":
30
- new_path = backup_root.joinpath(orig_path.relative_to(Path.home()))
31
- new_path.parent.mkdir(parents=True, exist_ok=True)
32
+ if shared:
33
+ new_path = backup_root.joinpath("shared").joinpath(orig_path.name)
34
+ new_path.parent.mkdir(parents=True, exist_ok=True)
35
+ else:
36
+ new_path = backup_root.joinpath(orig_path.relative_to(Path.home()))
37
+ new_path.parent.mkdir(parents=True, exist_ok=True)
32
38
  else:
33
- dest_path = Path(destination).expanduser().absolute()
34
- dest_path.mkdir(parents=True, exist_ok=True)
35
- new_path = dest_path.joinpath(orig_path.name)
36
-
37
-
39
+ if shared:
40
+ dest_path = Path(destination).expanduser().absolute()
41
+ dest_path.mkdir(parents=True, exist_ok=True)
42
+ new_path = dest_path.joinpath("shared").joinpath(orig_path.name)
43
+ new_path.parent.mkdir(parents=True, exist_ok=True)
44
+ else:
45
+ dest_path = Path(destination).expanduser().absolute()
46
+ dest_path.mkdir(parents=True, exist_ok=True)
47
+ new_path = dest_path.joinpath(orig_path.name)
38
48
  from machineconfig.utils.path_extended import PathExtended
39
49
  match method:
40
50
  case "copy" | "c":
@@ -52,9 +52,9 @@ def install(no_copy_assets: Annotated[bool, typer.Option("--no-assets-copy", "-n
52
52
  else:
53
53
  import platform
54
54
  if platform.system() == "Windows":
55
- run_shell_script(r"""& "$HOME\.local\bin\uv.exe" tool install --upgrade "machineconfig>=7.55" """)
55
+ run_shell_script(r"""& "$HOME\.local\bin\uv.exe" tool install --upgrade "machineconfig>=7.57" """)
56
56
  else:
57
- run_shell_script("""$HOME/.local/bin/uv tool install --upgrade "machineconfig>=7.55" """)
57
+ run_shell_script("""$HOME/.local/bin/uv tool install --upgrade "machineconfig>=7.57" """)
58
58
  from machineconfig.profile.create_shell_profile import create_default_shell_profile
59
59
  if not no_copy_assets:
60
60
  create_default_shell_profile() # involves copying assets too
@@ -79,7 +79,7 @@ def navigate():
79
79
  path = Path(navigator.__file__).resolve().parent.joinpath("devops_navigator.py")
80
80
  from machineconfig.utils.code import run_shell_script
81
81
  if Path.home().joinpath("code/machineconfig").exists(): executable = f"""--project "{str(Path.home().joinpath("code/machineconfig"))}" --with textual"""
82
- else: executable = """--with "machineconfig>=7.55,textual" """
82
+ else: executable = """--with "machineconfig>=7.57,textual" """
83
83
  run_shell_script(f"""uv run {executable} {path}""")
84
84
 
85
85
 
@@ -54,7 +54,12 @@ def main(
54
54
  else:
55
55
  cloud_resolved = cloud
56
56
  repo_local_root = PathExtended.cwd() if repo is None else PathExtended(repo).expanduser().absolute()
57
- repo_local_obj = git.Repo(repo_local_root, search_parent_directories=True)
57
+ try:
58
+ repo_local_obj = git.Repo(repo_local_root, search_parent_directories=True)
59
+ except git.InvalidGitRepositoryError:
60
+ typer.echo(f"[red]Error:[/] The specified path '{repo_local_root}' is not a valid git repository.")
61
+ typer.Exit(code=1)
62
+ return ""
58
63
  repo_local_root = PathExtended(repo_local_obj.working_dir) # cwd might have been in a sub directory of repo_root, so its better to redefine it.
59
64
  PathExtended(CONFIG_ROOT).joinpath("remote").mkdir(parents=True, exist_ok=True)
60
65
  repo_remote_root = PathExtended(CONFIG_ROOT).joinpath("remote", repo_local_root.rel2home())
@@ -99,7 +104,7 @@ git pull originEnc master
99
104
  uv_project_dir = f"""{str(Path.home().joinpath("code/machineconfig"))}"""
100
105
  uv_with = None
101
106
  else:
102
- uv_with = ["machineconfig>=7.55"]
107
+ uv_with = ["machineconfig>=7.57"]
103
108
  uv_project_dir = None
104
109
 
105
110
  import tempfile
@@ -8,7 +8,7 @@ def analyze_repo_development(repo_path: Annotated[str, typer.Argument(..., help=
8
8
  from pathlib import Path
9
9
  count_lines_path = Path(count_lines.__file__)
10
10
  # --project $HOME/code/ machineconfig --group plot
11
- cmd = f"""uv run --python 3.14 --with "machineconfig[plot]>=7.55" {count_lines_path} analyze-over-time {repo_path}"""
11
+ cmd = f"""uv run --python 3.14 --with "machineconfig[plot]>=7.57" {count_lines_path} analyze-over-time {repo_path}"""
12
12
  from machineconfig.utils.code import run_shell_script
13
13
  run_shell_script(cmd)
14
14
 
@@ -17,7 +17,7 @@ def path():
17
17
  uv_with = ["textual"]
18
18
  uv_project_dir = None
19
19
  if not Path.home().joinpath("code/machineconfig").exists():
20
- uv_with.append("machineconfig>=7.55")
20
+ uv_with.append("machineconfig>=7.57")
21
21
  else:
22
22
  uv_project_dir = str(Path.home().joinpath("code/machineconfig"))
23
23
  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])
@@ -95,7 +95,7 @@ def get_installation_choices() -> list[str]:
95
95
  choices = [
96
96
  Choice(value="install_machineconfig", title="🐍 Install machineconfig cli.", checked=False),
97
97
  Choice(value="sysabc", title="📥 Install System Package Manager (Needed for other apps to be installed).", checked=False),
98
- Choice(value="termabc", title="⚡ Install Terminal CLI apps essentials", checked=False),
98
+ Choice(value="termabc", title="⚡ Install Terminal CLI apps essentials (group `termabc`)", checked=False),
99
99
  Choice(value="install_shell_profile", title="🐚 Configure Shell Profile And Map Other Configs.", checked=False),
100
100
  Choice(value="install_ssh_server", title="🔒 [ADVANCED] Configure SSH Server", checked=False),
101
101
  Choice(value="retrieve_repositories", title="📚 [ADVANCED] Retrieve Repositories", checked=False),
@@ -13,9 +13,9 @@ import typer
13
13
  console = Console()
14
14
 
15
15
 
16
- def get_add_ssh_key_script(path_to_key: PathExtended):
16
+ def get_add_ssh_key_script(path_to_key: PathExtended) -> str:
17
17
  console.print(Panel("🔑 SSH KEY CONFIGURATION", title="[bold blue]SSH Setup[/bold blue]"))
18
- if system() == "Linux":
18
+ if system() == "Linux" or system() == "Darwin":
19
19
  authorized_keys = PathExtended.home().joinpath(".ssh/authorized_keys")
20
20
  console.print(Panel(f"🐧 Linux SSH configuration\n📄 Authorized keys file: {authorized_keys}", title="[bold blue]System Info[/bold blue]"))
21
21
  elif system() == "Windows":
@@ -35,7 +35,7 @@ def get_add_ssh_key_script(path_to_key: PathExtended):
35
35
  program = ""
36
36
  else:
37
37
  console.print(Panel(f"➕ Adding new SSH key to authorized keys\n🔑 Key file: {path_to_key.name}", title="[bold blue]Action[/bold blue]"))
38
- if system() == "Linux":
38
+ if system() == "Linux" or system() == "Darwin":
39
39
  program = f"cat {path_to_key} >> ~/.ssh/authorized_keys"
40
40
  elif system() == "Windows":
41
41
  program_path = LIBRARY_ROOT.joinpath("setup_windows/add-sshkey.ps1")
@@ -48,14 +48,14 @@ def get_add_ssh_key_script(path_to_key: PathExtended):
48
48
  raise NotImplementedError
49
49
  else:
50
50
  console.print(Panel(f"📝 Creating new authorized_keys file\n🔑 Using key: {path_to_key.name}", title="[bold blue]Action[/bold blue]"))
51
- if system() == "Linux":
51
+ if system() == "Linux" or system() == "Darwin":
52
52
  program = f"cat {path_to_key} > ~/.ssh/authorized_keys"
53
53
  else:
54
54
  program_path = LIBRARY_ROOT.joinpath("setup_windows/openssh-server_add-sshkey.ps1")
55
55
  program = PathExtended(program_path).expanduser().read_text(encoding="utf-8").replace('$sshfile=""', f'$sshfile="{path_to_key}"')
56
56
  console.print(Panel("🔧 Configured PowerShell script for Windows\n📝 Set key path in script", title="[bold blue]Configuration[/bold blue]"))
57
57
 
58
- if system() == "Linux":
58
+ if system() == "Linux" or system() == "Darwin":
59
59
  program += """
60
60
  sudo chmod 700 ~/.ssh
61
61
  sudo chmod 644 ~/.ssh/authorized_keys
@@ -66,6 +66,16 @@ sudo service ssh --full-restart
66
66
  return program
67
67
 
68
68
 
69
+ """
70
+ Common pitfalls:
71
+ 🚫 Wrong line endings (LF/CRLF) in config files
72
+ 🌐 Network port conflicts (try 2222 -> 2223) between WSL and Windows
73
+ sudo service ssh restart
74
+ sudo service ssh status
75
+ sudo nano /etc/ssh/sshd_config
76
+ """
77
+
78
+
69
79
  def main(pub_path: Annotated[Optional[str], typer.Argument(..., help="Path to the public key file")] = None,
70
80
  pub_choose: Annotated[bool, typer.Option(..., "--choose", "-c", help="Choose from available public keys in ~/.ssh")] = False,
71
81
  pub_val: Annotated[bool, typer.Option(..., "--paste", "-p", help="Paste the public key content manually")] = False,
@@ -127,6 +137,12 @@ def main(pub_path: Annotated[Optional[str], typer.Argument(..., help="Path to th
127
137
  console.print(Panel("🚀 SSH KEY AUTHORIZATION READY\nRun the generated script to apply changes", box=box.DOUBLE_EDGE, title_align="left"))
128
138
  from machineconfig.utils.code import run_shell_script
129
139
  run_shell_script(script=program)
140
+ import socket
141
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
142
+ s.connect(('8.8.8.8', 80))
143
+ local_ip_v4 = s.getsockname()[0]
144
+ s.close()
145
+ console.print(Panel(f"🌐 This computer is accessible at: {local_ip_v4}", title="[bold green]Network Info[/bold green]", border_style="green"))
130
146
  console.print(Panel("✅ SSH KEY AUTHORIZATION COMPLETED", box=box.DOUBLE_EDGE, title_align="left"))
131
147
 
132
148
 
@@ -7,7 +7,7 @@ $user = ''
7
7
  $sharePath = ''
8
8
  $driveLetter = ''
9
9
 
10
- uv run --python 3.14 --with "machineconfig>=7.55" python -m machineconfig.scripts.python.mount_ssh
10
+ uv run --python 3.14 --with "machineconfig>=7.57" 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
@@ -190,6 +190,6 @@ end
190
190
 
191
191
 
192
192
  -- and finally, return the configuration to wezterm
193
- config.enable_osc133 = false -- to silence: P>|WezTerm 20240203-110809-5046fc22\
193
+ -- config.enable_osc133 = false -- to silence: P>|WezTerm 20240203-110809-5046fc22\
194
194
 
195
195
  return config
@@ -2,16 +2,16 @@
2
2
  . <( curl -sSL "https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_linux/uv.sh")
3
3
  . <( curl -sSL "https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/scripts/linux/wrap_mcfg")
4
4
 
5
- alias devops='$HOME/.local/bin/uvx --python 3.14 --from "machineconfig>=7.55" devops'
6
- alias cloud='$HOME/.local/bin/uvx --python 3.14 --from "machineconfig>=7.55" cloud'
7
- alias agents='$HOME/.local/bin/uvx --python 3.14 --from "machineconfig>=7.55" agents'
8
- alias sessions='$HOME/.local/bin/uvx --python 3.14 --from "machineconfig>=7.55" sessions'
9
- alias ftpx='$HOME/.local/bin/uvx --python 3.14 --from "machineconfig>=7.55" ftpx'
10
- alias fire='$HOME/.local/bin/uvx --python 3.14 --from "machineconfig>=7.55" fire'
11
- alias croshell='$HOME/.local/bin/uvx --python 3.14 --from "machineconfig>=7.55" croshell'
12
- alias utils='$HOME/.local/bin/uvx --python 3.14 --from "machineconfig>=7.55" utils'
13
- alias terminal='$HOME/.local/bin/uvx --python 3.14 --from "machineconfig>=7.55" terminal'
14
- alias msearch='$HOME/.local/bin/uvx --python 3.14 --from "machineconfig>=7.55" msearch'
5
+ alias devops='$HOME/.local/bin/uvx --python 3.14 --from "machineconfig>=7.57" devops'
6
+ alias cloud='$HOME/.local/bin/uvx --python 3.14 --from "machineconfig>=7.57" cloud'
7
+ alias agents='$HOME/.local/bin/uvx --python 3.14 --from "machineconfig>=7.57" agents'
8
+ alias sessions='$HOME/.local/bin/uvx --python 3.14 --from "machineconfig>=7.57" sessions'
9
+ alias ftpx='$HOME/.local/bin/uvx --python 3.14 --from "machineconfig>=7.57" ftpx'
10
+ alias fire='$HOME/.local/bin/uvx --python 3.14 --from "machineconfig>=7.57" fire'
11
+ alias croshell='$HOME/.local/bin/uvx --python 3.14 --from "machineconfig>=7.57" croshell'
12
+ alias utils='$HOME/.local/bin/uvx --python 3.14 --from "machineconfig>=7.57" utils'
13
+ alias terminal='$HOME/.local/bin/uvx --python 3.14 --from "machineconfig>=7.57" terminal'
14
+ alias msearch='$HOME/.local/bin/uvx --python 3.14 --from "machineconfig>=7.57" msearch'
15
15
 
16
16
  alias d='wrap_in_shell_script devops'
17
17
  alias c='wrap_in_shell_script cloud'
@@ -3,16 +3,16 @@
3
3
  iex (iwr "https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_windows/uv.ps1").Content
4
4
  iex (iwr "https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/scripts/windows/wrap_mcfg.ps1").Content
5
5
 
6
- function devops { & "$HOME\.local\bin\uvx.exe" --python 3.14 --from "machineconfig>=7.55" devops $args }
7
- function cloud { & "$HOME\.local\bin\uvx.exe" --python 3.14 --from "machineconfig>=7.55" cloud $args }
8
- function agents { & "$HOME\.local\bin\uvx.exe" --python 3.14 --from "machineconfig>=7.55" agents $args }
9
- function sessions { & "$HOME\.local\bin\uvx.exe" --python 3.14 --from "machineconfig>=7.55" sessions $args }
10
- function ftpx { & "$HOME\.local\bin\uvx.exe" --python 3.14 --from "machineconfig>=7.55" ftpx $args }
11
- function fire { & "$HOME\.local\bin\uvx.exe" --python 3.14 --from "machineconfig>=7.55" fire $args }
12
- function croshell { & "$HOME\.local\bin\uvx.exe" --python 3.14 --from "machineconfig>=7.55" croshell $args }
13
- function utils { & "$HOME\.local\bin\uvx.exe" --python 3.14 --from "machineconfig>=7.55" utils $args }
14
- function terminal { & "$HOME\.local\bin\uvx.exe" --python 3.14 --from "machineconfig>=7.55" terminal $args }
15
- function msearch { & "$HOME\.local\bin\uvx.exe" --python 3.14 --from "machineconfig>=7.55" msearch $args }
6
+ function devops { & "$HOME\.local\bin\uvx.exe" --python 3.14 --from "machineconfig>=7.57" devops $args }
7
+ function cloud { & "$HOME\.local\bin\uvx.exe" --python 3.14 --from "machineconfig>=7.57" cloud $args }
8
+ function agents { & "$HOME\.local\bin\uvx.exe" --python 3.14 --from "machineconfig>=7.57" agents $args }
9
+ function sessions { & "$HOME\.local\bin\uvx.exe" --python 3.14 --from "machineconfig>=7.57" sessions $args }
10
+ function ftpx { & "$HOME\.local\bin\uvx.exe" --python 3.14 --from "machineconfig>=7.57" ftpx $args }
11
+ function fire { & "$HOME\.local\bin\uvx.exe" --python 3.14 --from "machineconfig>=7.57" fire $args }
12
+ function croshell { & "$HOME\.local\bin\uvx.exe" --python 3.14 --from "machineconfig>=7.57" croshell $args }
13
+ function utils { & "$HOME\.local\bin\uvx.exe" --python 3.14 --from "machineconfig>=7.57" utils $args }
14
+ function terminal { & "$HOME\.local\bin\uvx.exe" --python 3.14 --from "machineconfig>=7.57" terminal $args }
15
+ function msearch { & "$HOME\.local\bin\uvx.exe" --python 3.14 --from "machineconfig>=7.57" msearch $args }
16
16
 
17
17
  function d { wrap_in_shell_script devops @args }
18
18
  function c { wrap_in_shell_script cloud @args }
@@ -200,6 +200,10 @@ class Installer:
200
200
  assert download_link is not None, "download_link must be set"
201
201
  assert version_to_be_installed is not None, "version_to_be_installed must be set"
202
202
  downloaded = PathExtended(download_link).download(folder=INSTALL_TMP_DIR).decompress()
203
+ if downloaded.is_dir() and len(downloaded.search("*", r=True)) == 1:
204
+ only_file_in = next(downloaded.glob("*"))
205
+ if only_file_in.is_file() and only_file_in.suffix in [".7z", ".zip", ".tar.gz", ".tar"]: # further decompress
206
+ downloaded = only_file_in.decompress()
203
207
  return downloaded, version_to_be_installed
204
208
 
205
209
  # --------------------------- Arch / template helpers ---------------------------
@@ -480,9 +480,6 @@ class PathExtended(type(Path()), Path): # type: ignore # pylint: disable=E0241
480
480
  **kwargs: Any,
481
481
  ) -> "PathExtended":
482
482
  path_resolved, slf = self._resolve_path(folder, name, path, self.name).expanduser().resolve(), self.expanduser().resolve()
483
- # if use_7z: # benefits over regular zip and encrypt: can handle very large files with low memory footprint
484
- # path_resolved = path_resolved + '.7z' if not path_resolved.suffix == '.7z' else path_resolved
485
- # with install_n_import("py7zr").SevenZipFile(file=path_resolved, mode=mode, password=pwd) as archive: archive.writeall(path=str(slf), arcname=None)
486
483
  arcname_obj = PathExtended(arcname or slf.name)
487
484
  if arcname_obj.name != slf.name:
488
485
  arcname_obj /= slf.name # arcname has to start from somewhere and end with filename
@@ -555,15 +552,6 @@ class PathExtended(type(Path()), Path): # type: ignore # pylint: disable=E0241
555
552
  folder = folder if not content else folder.parent
556
553
  if slf.suffix == ".7z":
557
554
  raise NotImplementedError("I have not implemented this yet")
558
- # if overwrite: P(folder).delete(sure=True)
559
- # result = folder
560
- # import py7zr
561
- # with py7zr.SevenZipFile(file=slf, mode='r', password=pwd) as archive:
562
- # if pattern is not None:
563
- # import re
564
- # pat = re.compile(pattern)
565
- # archive.extract(path=folder, targets=[f for f in archive.getnames() if pat.match(f)])
566
- # else: archive.extractall(path=folder)
567
555
  else:
568
556
  if overwrite:
569
557
  if not content:
@@ -698,19 +686,52 @@ class PathExtended(type(Path()), Path): # type: ignore # pylint: disable=E0241
698
686
  return ret
699
687
 
700
688
  def decompress(self, folder: OPLike = None, name: Optional[str] = None, path: OPLike = None, inplace: bool = False, orig: bool = False, verbose: bool = True) -> "PathExtended":
701
- if ".tar.gz" in str(self) or ".tgz" in str(self):
689
+ if str(self).endswith(".tar.gz") or str(self).endswith(".tgz"):
702
690
  # res = self.ungz_untar(folder=folder, path=path, name=name, inplace=inplace, verbose=verbose, orig=orig)
703
691
  return self.ungz(name=f"tmp_{randstr()}.tar", inplace=inplace).untar(folder=folder, name=name, path=path, inplace=True, orig=orig, verbose=verbose) # this works for .tgz suffix as well as .tar.gz
704
- elif ".gz" in str(self):
692
+ elif str(self).endswith(".tar"):
693
+ res = self.untar(folder=folder, name=name, path=path, inplace=inplace, orig=orig, verbose=verbose)
694
+ elif str(self).endswith(".gz"):
705
695
  res = self.ungz(folder=folder, path=path, name=name, inplace=inplace, verbose=verbose, orig=orig)
706
- elif ".tar.bz" in str(self) or "tbz" in str(self):
696
+ elif str(self).endswith(".tar.bz") or str(self).endswith(".tbz"):
707
697
  res = self.unbz(name=f"tmp_{randstr()}.tar", inplace=inplace)
708
698
  return res.untar(folder=folder, name=name, path=path, inplace=True, orig=orig, verbose=verbose)
709
- elif ".tar.xz" in str(self):
699
+ elif str(self).endswith(".tar.xz"):
710
700
  # res = self.unxz_untar(folder=folder, path=path, name=name, inplace=inplace, verbose=verbose, orig=orig)
711
701
  res = self.unxz(inplace=inplace).untar(folder=folder, name=name, path=path, inplace=True, orig=orig, verbose=verbose)
712
- elif ".zip" in str(self):
702
+ elif str(self).endswith(".zip"):
713
703
  res = self.unzip(folder=folder, path=path, name=name, inplace=inplace, verbose=verbose, orig=orig)
704
+ elif str(self).endswith(".7z"):
705
+ def unzip_7z(archive_path: str, dest_dir: Optional[str] = None) -> Path:
706
+ """
707
+ Uncompresses a .7z archive to a directory and returns the Path to the extraction directory.
708
+
709
+ :param archive_path: path to the .7z archive file
710
+ :param dest_dir: optional path to directory to extract into; if None a temporary dir will be created
711
+ :return: pathlib.Path pointing to the destination directory where contents were extracted
712
+ :raises: FileNotFoundError if archive does not exist; py7zr.Bad7zFile or other error if extraction fails
713
+ """
714
+ import py7zr
715
+ import tempfile
716
+ from pathlib import Path
717
+ archive_path_obj = Path(archive_path)
718
+ if not archive_path_obj.is_file():
719
+ raise FileNotFoundError(f"Archive file not found: {archive_path_obj!r}")
720
+ if dest_dir is None:
721
+ # create a temporary directory
722
+ dest = Path(tempfile.mkdtemp(prefix=f"unzip7z_{archive_path_obj.stem}_"))
723
+ else:
724
+ dest = Path(dest_dir)
725
+ dest.mkdir(parents=True, exist_ok=True)
726
+ # Perform extraction
727
+ with py7zr.SevenZipFile(str(archive_path_obj), mode='r') as archive:
728
+ archive.extractall(path=str(dest))
729
+ # Return the extraction directory path
730
+ return dest
731
+ from machineconfig.utils.code import run_lambda_function
732
+ destination_dir = str(self.expanduser().resolve()).replace(".7z", "")
733
+ run_lambda_function(lambda: unzip_7z(archive_path=str(self), dest_dir=destination_dir), uv_project_dir=None, uv_with=["py7zr"])
734
+ res = PathExtended(destination_dir)
714
735
  else:
715
736
  res = self
716
737
  return res
@@ -8,7 +8,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.55"
11
+ MACHINECONFIG_VERSION = "machineconfig>=7.57"
12
12
  DEFAULT_PICKLE_SUBDIR = "tmp_results/tmp_scripts/ssh"
13
13
 
14
14
  class SSH:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: machineconfig
3
- Version: 7.55
3
+ Version: 7.57
4
4
  Summary: Dotfiles management package
5
5
  Author-email: Alex Al-Saffar <programmer@usa.com>
6
6
  License: Apache 2.0
@@ -51,10 +51,43 @@ Requires-Dist: python-magic>=0.4.27; extra == "plot"
51
51
  </p>
52
52
 
53
53
 
54
- # Welcome to machineconfig
54
+ # 🧠 Welcome to **Machineconfig**
55
+
56
+ **Machineconfig** is a cli-based **Digital Life Manager** — It's called so because no existing category of software fully captures its scope. At the same time, it is a *Package Manager*, *Configuration Manager*, *Automation Tool*, *Dotfiles Manager*, *Data Solution*, and *Code Manager*, among other functionalities covered, all rolled into one seamless experience.
57
+
58
+
59
+ ## 💡 Motivation
60
+
61
+ But why do we need such a tool to combine all those functionalities?? Because you need one tool to manager your stack and dev-environment, put it together and maintain it.
62
+ Consider this concrete scenario: When setting up a new machine, VM, or Docker container, you often face dependency chains like this:
63
+
64
+ ```mermaid
65
+ flowchart TD
66
+ A["Need to setup my [dev] environment"] --> B["need my tool x, e.g.: yadm"]
67
+ B --> C["Requires git"]
68
+ C --> D["Requires package manager, e.g. brew"]
69
+ D --> E["Requires curl"]
70
+ E --> F["Requires network setup / system update"]
71
+ F --> G["Requires system configuration access"]
72
+ G --> H["Finally ready to start setup the tool x."]
73
+ ```
74
+
75
+ Machineconfig builds on shoulder of giants. A suite of best-in-class stack of projects on github are used, the most starred, active and written in Rust tools are used when possible. The goal is to provide a seamless experience that abstracts away the complexity of setting up and maintaining your digital environment. The goal of machineconfig is to replicate your setup, config, code, data and secrets on any machine, any os, in 5 minutes, using minimal user input. Then, from that point, machineconfig will help you maintain, update, backup and sync your digital life across all your devices, automatically.
76
+
77
+
78
+ ## ⚙️ Functional Overview
79
+
80
+ | Category | Comparable Tools | Description |
81
+ |------------------------|----------------------------------------------|-----------------------------------------------------------|
82
+ | **Package Manager** | `winget`, `apt`, `brew`, `nix` | Installs and manages software packages across systems. |
83
+ | **Configuration Manager** | `Ansible`, `Chef`, `Puppet` | Configures and maintains system‐level preferences. |
84
+ | **Automation Tool** | `Airflow`, `Prefect`, `Dagster`, `Celery` | Automates repetitive tasks, pipelines, orchestration. |
85
+ | **Dotfiles Manager** | `chezmoi`, `yadm`, `rcm`, `GNU Stow` | Synchronises dotfiles & personal configs across systems. |
86
+ | **Data Solution** | `rclone`, `rsync` | Handles backups, mirroring and secure file sync. |
87
+ | **Code Manager** | `strong‐box`, `Vault` | Manages and protects code snippets, secrets and creds. |
88
+
89
+ ---
55
90
 
56
- Machineconfig is a package for managing configuration files (aka dotfiles). The idea is to collect those critical, time-consuming-files-to-setup in one directory and reference them via symbolic links from their original locations. Thus, when a new machine is to be setup, all that is required is to clone the repo in that machine and create the symbolic links.
57
- Dotfiles are divided into private and public. Examples of private ones are, `~/.gitconfig`, `~/.ssh`, etc. Whereas public config files are ones like `lfrc`. The private dotfiles are placed @ `~/dotfiles`. The files therein are encrypted before backedup.
58
91
 
59
92
  # Install On Windows:
60
93
 
@@ -68,10 +101,11 @@ iex (iwr bit.ly/cfgwindows).Content # Or, if UV is installed: iex (uvx machinec
68
101
  iex (iwr bit.ly/cfgwq).Content
69
102
  ```
70
103
 
104
+
71
105
  # Install On Linux and MacOS
72
106
 
73
107
  ```bash
74
- # install tool the tool only:
108
+ # install the tool only:
75
109
  curl -LsSf https://astral.sh/uv/install.sh | sh # Skip if UV is already installed
76
110
  uv tool install --upgrade --python 3.14 machineconfig
77
111
  # interactive install of machineconfig and following on to run it and make basic machine configuration (RECOMMENDED):
@@ -51,7 +51,7 @@ machineconfig/cluster/templates/cli_trogon.py,sha256=PFWGy8SFYIhT9r3ZV4oIEYfImsQ
51
51
  machineconfig/jobs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
52
  machineconfig/jobs/installer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
53
  machineconfig/jobs/installer/check_installations.py,sha256=hkHmmT7Bx3_QWRn2v8dCKOzAapFzqHRzbe-Q08GLnKE,10743
54
- machineconfig/jobs/installer/installer_data.json,sha256=C9IwwiS29812Iwco2rEzANHebIpwbigiHtSdC3HB-Vc,110056
54
+ machineconfig/jobs/installer/installer_data.json,sha256=cG5leLVPS6wvqqdmqEWwpfrcygeYLFhEkYGO_EBAVGE,110168
55
55
  machineconfig/jobs/installer/package_groups.py,sha256=HUCnLV6s3qkGXjT4VomOUUzMSqrUX_aJibPfPUWhYrU,4720
56
56
  machineconfig/jobs/installer/custom/boxes.py,sha256=ws8QRbDn48oKhbQntr54I0nSfkwINbprjTy0HOpuX40,1974
57
57
  machineconfig/jobs/installer/custom/gh.py,sha256=gn7TUSrsLx7uqFqj1Z-iYglS0EYBSgtJ9jWHxaJIfXM,4119
@@ -111,14 +111,14 @@ machineconfig/scripts/nu/wrap_mcfg.nu,sha256=9heiUHVkHjI_AMXT5QJJixk7ZK_hJNV_A8l
111
111
  machineconfig/scripts/python/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
112
112
  machineconfig/scripts/python/agents.py,sha256=aVbLQDgpngXZm4taHcED4sAxyHvV2_Dz5VW3apPcQcY,10651
113
113
  machineconfig/scripts/python/cloud.py,sha256=yAD6ciKiEtv2CH3g2NScDK5cpCZQi7Vu8yyeehw_cU8,1263
114
- machineconfig/scripts/python/croshell.py,sha256=uYzXdxeWznbORlwW5SZ_ADyPa-MLNMooVEN0zah69mc,7132
114
+ machineconfig/scripts/python/croshell.py,sha256=8zYPwVanp2psAC_6XLQnfgXrlmkYVFkdjUrtssq4m_U,7132
115
115
  machineconfig/scripts/python/define.py,sha256=AtuVac6tJeDMcxtbWmQh1TH3dYAPSGFdO51b75zJVeI,717
116
116
  machineconfig/scripts/python/devops.py,sha256=x7CnxOnZPSrCwjflnJ6sht1M7g0nzY2SxyPtmNputSA,2212
117
117
  machineconfig/scripts/python/devops_navigator.py,sha256=5Cm384D4S8_GsvMzTwr0C16D0ktf8_5Mk5bEJncwDO8,237
118
118
  machineconfig/scripts/python/explore.py,sha256=3kNglM1KYp57U8yrbWeHEslN458-xieRuFYsJAhrpIs,1247
119
119
  machineconfig/scripts/python/fire_jobs.py,sha256=zLLgPfqCSpXBeU5kC4XEcojscZFy-K0K3dbbGqkTczU,13135
120
120
  machineconfig/scripts/python/ftpx.py,sha256=8tmhKBZgSuhFZZYaT4JAIgeXMKmxJhxg5aJQFbbdtDg,9857
121
- machineconfig/scripts/python/interactive.py,sha256=nPnAydEv4S_twd0_Yetgc57a03GHWkjZXXc88XiNlew,11487
121
+ machineconfig/scripts/python/interactive.py,sha256=PzZw2BP0ucWCZg2FYOFx0twruv4gE0Fhi1djCScmM2A,11505
122
122
  machineconfig/scripts/python/machineconfig.py,sha256=l211lxHRcQ6BH7x3FwQHSJCYbYs6RJL5e0POjyWAW9A,3048
123
123
  machineconfig/scripts/python/msearch.py,sha256=3NbwJFJtrvPSVyOfa6ogPjD-NVuRJHeAQ1WriDXCduU,737
124
124
  machineconfig/scripts/python/sessions.py,sha256=Mex8Y2NM0Z3JiO7-qEKew9lA29FfUDo_tB3-1jJ79bs,9532
@@ -156,7 +156,7 @@ machineconfig/scripts/python/ai/solutions/opencode/opencode.json,sha256=nahHKRw1
156
156
  machineconfig/scripts/python/ai/solutions/opencode/opencode.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
157
157
  machineconfig/scripts/python/env_manager/__init__.py,sha256=E4LAHbU1wo2dLjE36ntv8U7QNTe8TasujUAYK9SLvWk,6
158
158
  machineconfig/scripts/python/env_manager/path_manager_backend.py,sha256=ZVGlGJALhg7zNABDdwXxL7MFbL2BXPebObipXSLGbic,1552
159
- machineconfig/scripts/python/env_manager/path_manager_tui.py,sha256=XPeHhS7eOYbpBkVgHPNAYkBP79CAjLt7Ct7wK4JSwJ0,6932
159
+ machineconfig/scripts/python/env_manager/path_manager_tui.py,sha256=9Wux_YbqGFSbnABJwepre-FEUesSCyTdU3j3GHE7-cU,6932
160
160
  machineconfig/scripts/python/helpers_agents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
161
161
  machineconfig/scripts/python/helpers_agents/fire_agents_help_launch.py,sha256=YD6-rtudHNip8tx85amSmOZZIHBP9khq4az3dF41j6U,5934
162
162
  machineconfig/scripts/python/helpers_agents/fire_agents_help_search.py,sha256=qIfSS_su2YJ1Gb0_lu4cbjlJlYMBw0v52NTGiSrGjk8,2991
@@ -187,11 +187,11 @@ machineconfig/scripts/python/helpers_croshell/viewer.py,sha256=heQNjB9fwn3xxbPgM
187
187
  machineconfig/scripts/python/helpers_croshell/viewer_template.py,sha256=ve3Q1-iKhCLc0VJijKvAeOYp2xaFOeIOC_XW956GWCc,3944
188
188
  machineconfig/scripts/python/helpers_devops/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
189
189
  machineconfig/scripts/python/helpers_devops/cli_config.py,sha256=VLR7tH1SdR3ftWSNjyt0LHc1gRssYJXYvkLjtydxVOM,5007
190
- machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py,sha256=SL6P3Ioib3P9OWG1GmULb5-l4ySYZ1RuuIDCHY4lCyU,3502
190
+ machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py,sha256=ZSiEwGgKf9p62jKTqtVbM6qiiEhxy_Qhj8oSYq7pHew,4139
191
191
  machineconfig/scripts/python/helpers_devops/cli_data.py,sha256=79Xvx7YnbueruEnl69hrDg2AhVxf_zCUdlVcKfeMGyQ,1774
192
192
  machineconfig/scripts/python/helpers_devops/cli_nw.py,sha256=u_2l5Cc3dFnh0seKrbH9j-Z0bUCrgy45MOM6HCjgkQg,7562
193
193
  machineconfig/scripts/python/helpers_devops/cli_repos.py,sha256=mFrhosIFCCT70d82NYUxp9ta6BYeAHQNhsx7CEmWcg4,12478
194
- machineconfig/scripts/python/helpers_devops/cli_self.py,sha256=8oGw1spvee1Q-cqTOyZlAXuiCRMJbAkkI1OBhCbSu1I,6993
194
+ machineconfig/scripts/python/helpers_devops/cli_self.py,sha256=Q60PoM3BMFd-_vcTpctTD5T850j5uBaP9Q71DctzQr0,6993
195
195
  machineconfig/scripts/python/helpers_devops/cli_share_file.py,sha256=AL04784ncdP9ue5bKyqJfXrMksxjFKtuv_w353kQQsI,6298
196
196
  machineconfig/scripts/python/helpers_devops/cli_share_server.py,sha256=S2xQ7sDVvfvGKcJNlquXj9Gc0ofk2EXnfvpRx2AWVD8,6278
197
197
  machineconfig/scripts/python/helpers_devops/cli_terminal.py,sha256=k_PzXaiGyE0vXr0Ii1XcJz2A7UvyPJrR31TRWt4RKRI,6019
@@ -228,9 +228,9 @@ machineconfig/scripts/python/helpers_navigator/search_bar.py,sha256=kDi8Jhxap8wd
228
228
  machineconfig/scripts/python/helpers_repos/action.py,sha256=8je051kpGZ7A_GRsQyWKhPZ8xVW7tSm4bnPu6VjxaXk,9755
229
229
  machineconfig/scripts/python/helpers_repos/action_helper.py,sha256=XRCtkGkNrxauqUd9qkxtfJt02Mx2gejSYDLL0jyWn24,6176
230
230
  machineconfig/scripts/python/helpers_repos/clone.py,sha256=9RZgs2OD2RUH6UiZKCuUvRyweDBomAm2lDG2qJmhry0,5436
231
- machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py,sha256=XQs1obGuFBB9VTxhS-chhRki9-KqkWNgtDxfJf2Fxt8,11271
231
+ machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py,sha256=lDA2JRsuASn5T5JAeW26AZnmiUG-danPrKZIk7Qe1ZI,11479
232
232
  machineconfig/scripts/python/helpers_repos/count_lines.py,sha256=Q5c7b-DxvTlQmljoic7niTuiAVyFlwYvkVQ7uRJHiTo,16009
233
- machineconfig/scripts/python/helpers_repos/count_lines_frontend.py,sha256=EJ9-m5iym0pws5qdvL61oLk6Ns41dVVSnK9oR7U3qnM,607
233
+ machineconfig/scripts/python/helpers_repos/count_lines_frontend.py,sha256=_ZB9vLawCqAF8QDcuPx63JK_J8I8Hq6c9F1xbDs8VvM,607
234
234
  machineconfig/scripts/python/helpers_repos/entrypoint.py,sha256=WYEFGUJp9HWImlFjbs_hiFZrUqM_KEYm5VvSUjWd04I,2810
235
235
  machineconfig/scripts/python/helpers_repos/grource.py,sha256=lHxyfsIQr4pbu71Ekqu-9nohR7LXbN2wufw7LPTyOgM,14639
236
236
  machineconfig/scripts/python/helpers_repos/record.py,sha256=FQo0swuJZOp0I2XGK-t1OQU4zJHmQ2z9zTpDD30Tmg4,11001
@@ -238,11 +238,10 @@ machineconfig/scripts/python/helpers_repos/sync.py,sha256=P0P7Dog2uFDvwxcLP3YHPw
238
238
  machineconfig/scripts/python/helpers_repos/update.py,sha256=cUIMUMm-50HrY6fzxSMZnFplhToVjVPZMm1j_otTha4,11060
239
239
  machineconfig/scripts/python/helpers_sessions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
240
240
  machineconfig/scripts/python/helpers_sessions/sessions_multiprocess.py,sha256=F6D-e0v405UFy-aj_pNWudxZkstPvjYR0UXLx-PR8Ms,3136
241
- machineconfig/scripts/python/helpers_utils/path.py,sha256=VSdwuJRS5AvQY0MezG4mp9fAGUn5YRrgy9bSXAflPQI,3982
241
+ machineconfig/scripts/python/helpers_utils/path.py,sha256=dfVXs2b_NURy1oiuGGbkpODJLEGHwQFB13eux1ib0h4,3982
242
242
  machineconfig/scripts/python/nw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
243
- machineconfig/scripts/python/nw/add_ssh_key.py,sha256=9JLmWu8pE7PAL5VuCFd19iVEdCR90LwY6_9P7gKQzEE,9373
244
243
  machineconfig/scripts/python/nw/devops_add_identity.py,sha256=aPjcHbTLhxYwWYcandyAHdwuO15ZBu3fB82u6bI0tMQ,3773
245
- machineconfig/scripts/python/nw/devops_add_ssh_key.py,sha256=CkIl85hZLtG9k7yXLSzqi88YrilHV4hIUWHAPBwxWjw,8922
244
+ machineconfig/scripts/python/nw/devops_add_ssh_key.py,sha256=hPmrJb6Q8dbvZBkj00va4najYDKziQ9A7CfZ3TZPccI,9560
246
245
  machineconfig/scripts/python/nw/mount_drive,sha256=zemKofv7hOmRN_V3qK0q580GkfWw3VdikyVVQyiu8j8,3514
247
246
  machineconfig/scripts/python/nw/mount_nfs,sha256=Dri4hGiM2GxpqqxpdBPbf7dRHrr7P1HzZy6xtrHYQfU,1855
248
247
  machineconfig/scripts/python/nw/mount_nfs.py,sha256=lOMDY4RS7tx8gsCazVR5tNNwFbaRyO2PJlnwBCDQgCM,3573
@@ -259,7 +258,7 @@ machineconfig/scripts/windows/wrap_mcfg.ps1,sha256=tFCj4wK7B35Uf6kdGCRV7EIr1xZFT
259
258
  machineconfig/scripts/windows/mounts/mount_nfs.ps1,sha256=XrAdzpxE6a4OccSmWJ7YWHJTnsZK8uXnFE5j9GOPA20,2026
260
259
  machineconfig/scripts/windows/mounts/mount_nw.ps1,sha256=puxcfZc3ZCJerm8pj8OZGVoTYkhzp-h7oV-MrksSqIE,454
261
260
  machineconfig/scripts/windows/mounts/mount_smb.ps1,sha256=PzYWpIO9BpwXjdWlUQL9pnMRnOGNSkxfh4bHukJFme8,69
262
- machineconfig/scripts/windows/mounts/mount_ssh.ps1,sha256=AggbHLu8HQ_qTn2yNC7TkVbn3YgIoBYW0btNIHvh1JM,322
261
+ machineconfig/scripts/windows/mounts/mount_ssh.ps1,sha256=IxLt9BX0VFHBVY6Dz_ngHyhyg9xhtdXBzJSRE5mSXEk,322
263
262
  machineconfig/scripts/windows/mounts/share_cloud.cmd,sha256=exD7JCdxw2LqVjw2MKCYHbVZlEqmelXtwnATng-dhJ4,1028
264
263
  machineconfig/scripts/windows/mounts/share_smb.ps1,sha256=U7x8ULYSjbgzTtiHNSKQuTaZ_apilDvkGV5Xm5hXk5M,384
265
264
  machineconfig/scripts/windows/mounts/unlock_bitlocker.ps1,sha256=Wv-SLscdckV-1mG3p82VXKPY9zW3hgkRmcLUXIZ1daE,253
@@ -344,7 +343,7 @@ machineconfig/settings/shells/pwsh/init.ps1,sha256=T0Zw9mfQa8rgDTxRk40UbzBq-7gkM
344
343
  machineconfig/settings/shells/pwsh/profile.ps1,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
345
344
  machineconfig/settings/shells/starship/starship.toml,sha256=d5lWKC0AnTcriRAZV1opEZy76QknSpKFgJ3jyW9_vZ0,1305
346
345
  machineconfig/settings/shells/vtm/settings.xml,sha256=5TNXd-i0eUGo2w3tuhY9aOkwoJdqih8_HO_U6uL2Dts,18262
347
- machineconfig/settings/shells/wezterm/wezterm.lua,sha256=Ab4MLm2Yqct0LWGK4kzfQWt6fbAfZcnjg3n8p_vf0_w,6293
346
+ machineconfig/settings/shells/wezterm/wezterm.lua,sha256=_ERpROSN3XNtbZJgL1jkAb8DhwGjUjOYuAW6p43CA00,6296
348
347
  machineconfig/settings/shells/wt/settings.json,sha256=Nzk9IpD-Bp36wKJAgG7XAa0GVwW3I29xNjUW5AYfxEI,10599
349
348
  machineconfig/settings/shells/zsh/init.sh,sha256=LcT8AOecHoCtmmkXkSlAROJy-xD1re6wvPEIEzgPN5U,3054
350
349
  machineconfig/settings/streamlit/config.toml,sha256=O3d4ax88hoW7gm5r51xmCcPssQ8ol-oFz_d0NUDlU4k,483
@@ -381,7 +380,7 @@ machineconfig/setup_linux/others/cli_installation.sh,sha256=gVvszYZJgKPRJx2SEaE3
381
380
  machineconfig/setup_linux/others/mint_keyboard_shortcuts.sh,sha256=F5dbg0n9RHsKGPn8fIdZMn3p0RrHEkb8rWBGsdVGbus,1207
382
381
  machineconfig/setup_linux/ssh/openssh_all.sh,sha256=3dg6HEUFbHQOzLfSAtzK_D_GB8rGCCp_aBnxNdnidVc,824
383
382
  machineconfig/setup_linux/ssh/openssh_wsl.sh,sha256=1eeRGrloVB34K5z8yWVUMG5b9pV-WBfHgV9jqXiYgCQ,1398
384
- machineconfig/setup_linux/web_shortcuts/interactive.sh,sha256=ezbGhAov4Cctmfw7CYk7-epshdavBQq8S6O4570BkMQ,1606
383
+ machineconfig/setup_linux/web_shortcuts/interactive.sh,sha256=fK_KeDExbFX358VCtFXW-9bCi11WY5aVwjSAZJcZ3yY,1606
385
384
  machineconfig/setup_mac/__init__.py,sha256=PfdhwY4Ss-rfP7b4-9fvKwxCDtNAd-u1JdhFYnE7CwI,518
386
385
  machineconfig/setup_mac/apps_gui.sh,sha256=3alvddg918oMlJB2aUWJWpGGoaq5atlxcaOwhnyXlRI,9517
387
386
  machineconfig/setup_mac/uv.sh,sha256=CSN8oCBKS-LK1vJJqYOhAMcrouTf4Q_F3cpplc_ddMA,1157
@@ -396,7 +395,7 @@ machineconfig/setup_windows/ssh/add_identity.ps1,sha256=b8ZXpmNUSw3IMYvqSY7ClpdW
396
395
  machineconfig/setup_windows/ssh/openssh-server.ps1,sha256=OMlYQdvuJQNxF5EILLPizB6BZAT3jAmDsv1WcVVxpFQ,2529
397
396
  machineconfig/setup_windows/ssh/openssh-server_add_key.ps1,sha256=91cL3K4H2saAuzOS1GxGicpc64ZDpgvPY39YPBWyxZI,269
398
397
  machineconfig/setup_windows/ssh/openssh-server_copy-ssh-id.ps1,sha256=-7pElYiGFXUvO4dp6rW0LXmNo65h3hFTHJWyHbmO3Xc,745
399
- machineconfig/setup_windows/web_shortcuts/interactive.ps1,sha256=8369NWE412ieGBcNzRYz0SeJI4sMS_GF2YKsyEdZ8uY,1939
398
+ machineconfig/setup_windows/web_shortcuts/interactive.ps1,sha256=dLbfrZVSo8CWntYKeX1sRTd-aL-2F5WPRUJIQru3ugE,1939
400
399
  machineconfig/setup_windows/web_shortcuts/quick_init.ps1,sha256=8TOw-ZxaWA6mZkOICAQtpQfqB2fUyD4HVfqokpxCCqI,655
401
400
  machineconfig/setup_windows/wt_and_pwsh/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
402
401
  machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py,sha256=ogxJnwpdcpH7N6dFJu95UCNoGYirZKQho_3X0F_hmXs,6791
@@ -409,13 +408,13 @@ machineconfig/utils/links.py,sha256=m5-MfendBa8YiPPyS-lWiuu6Ru1-jU3hg3BYQgIaWg8,
409
408
  machineconfig/utils/meta.py,sha256=4ocYH3Zi6bVN6FVgXoGIfoasV6oxi67I9rQ8hvyYinc,9892
410
409
  machineconfig/utils/notifications.py,sha256=tuXIudcip0tEioG-bm8BbLr3FMDve4f6BktlznBhKxM,9013
411
410
  machineconfig/utils/options.py,sha256=VWYx3EKJxIp-CJ8gDGYdjclKSc1tMUhyrC8v3seeneo,7447
412
- machineconfig/utils/path_extended.py,sha256=F9xjmuJ4JMqI6Ap2Hypvfz81BlBe-VsN0CfBaHWGEnQ,49293
411
+ machineconfig/utils/path_extended.py,sha256=-WYWs5bxcu8iXI4OHGH-eK0gevDOWR8SB4fKoD5JhWY,50515
413
412
  machineconfig/utils/path_helper.py,sha256=VnsWxAKSniw-GZ5zUie56463vTjaFDyoMnH2Xf88HO8,10557
414
413
  machineconfig/utils/procs.py,sha256=YPA_vEYQGwPd_o_Lc6nOTBo5BrB1tSs8PJ42XiGpenM,10957
415
414
  machineconfig/utils/scheduler.py,sha256=fguwvINyaupOxdU5Uadyxalh_jXTXDzt0ioEgjEOKcM,14705
416
415
  machineconfig/utils/scheduling.py,sha256=vcJgajeJPSWkJNlarYJSmLvasdOuCtBM4druOAB1Nwc,11089
417
416
  machineconfig/utils/source_of_truth.py,sha256=ZAnCRltiM07ig--P6g9_6nEAvNFC4X4ERFTVcvpIYsE,764
418
- machineconfig/utils/ssh.py,sha256=nCCyJAKyFdv0xnMMROGeMK-MKDPiyebVtOpZ1iOsxJg,39262
417
+ machineconfig/utils/ssh.py,sha256=AWiMjHq8nGzdExL_cpJBgMgBNWtznGin1kECGRiYQcY,39262
419
418
  machineconfig/utils/terminal.py,sha256=VDgsjTjBmMGgZN0YIc0pJ8YksLDrBtiXON1EThy7_is,4264
420
419
  machineconfig/utils/tst.py,sha256=6u1GI49NdcpxH2BYGAusNfY5q9G_ytCGVzFM5b6HYpM,674
421
420
  machineconfig/utils/upgrade_packages.py,sha256=e4iJn_9vL2zCJxAR2dhKJjM0__ALKgI5yB1uBRxSjhQ,6994
@@ -438,14 +437,14 @@ machineconfig/utils/installer_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQ
438
437
  machineconfig/utils/installer_utils/github_release_bulk.py,sha256=WJf_qZlF02SmIc6C7o1h4Gy4gAaJAfeAS8O9s2Itj-k,6535
439
438
  machineconfig/utils/installer_utils/installer.py,sha256=2xhzgAyifm5sHsb0y6d94UMWwRpGWMmsCCalsrnRHKA,9023
440
439
  machineconfig/utils/installer_utils/installer_abc.py,sha256=_QihkKgi7-IGrQQoy8muD0iL_n65ebvqDgiv43sCudI,8984
441
- machineconfig/utils/installer_utils/installer_class.py,sha256=t9OlHF3br7zuYuLuO75voedRPrDmo9YOXSDxRNXe3Jk,17188
440
+ machineconfig/utils/installer_utils/installer_class.py,sha256=H2e5kjGfS47Rwy6SF7bqDLDiZ4WQ-mmsNz1gWAip3ro,17497
442
441
  machineconfig/utils/schemas/fire_agents/fire_agents_input.py,sha256=d3pwhmE-EuHPxaIoTTZeUdDUEK9QqtimV8zO3vV-7N4,2052
443
442
  machineconfig/utils/schemas/installer/installer_types.py,sha256=QClRY61QaduBPJoSpdmTIdgS9LS-RvE-QZ-D260tD3o,1214
444
443
  machineconfig/utils/schemas/layouts/layout_types.py,sha256=TcqlZdGVoH8htG5fHn1KWXhRdPueAcoyApppZsPAPto,2020
445
444
  machineconfig/utils/schemas/repos/repos_types.py,sha256=ECVr-3IVIo8yjmYmVXX2mnDDN1SLSwvQIhx4KDDQHBQ,405
446
445
  machineconfig/utils/ssh_utils/utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
447
- machineconfig-7.55.dist-info/METADATA,sha256=-cP7Etyg42MQdY9EXG7XvVTQmJKoZaMeqyyABCBTuuw,3743
448
- machineconfig-7.55.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
449
- machineconfig-7.55.dist-info/entry_points.txt,sha256=_JNgkzaa_gVAWyZ6UwPwXXQqURRSvAGhrVQ1RiU2sHc,746
450
- machineconfig-7.55.dist-info/top_level.txt,sha256=porRtB8qms8fOIUJgK-tO83_FeH6Bpe12oUVC670teA,14
451
- machineconfig-7.55.dist-info/RECORD,,
446
+ machineconfig-7.57.dist-info/METADATA,sha256=DOiMOr-khnZAboqskT6w5SNnd6CwXf0QTGQA8dhp6tQ,5939
447
+ machineconfig-7.57.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
448
+ machineconfig-7.57.dist-info/entry_points.txt,sha256=_JNgkzaa_gVAWyZ6UwPwXXQqURRSvAGhrVQ1RiU2sHc,746
449
+ machineconfig-7.57.dist-info/top_level.txt,sha256=porRtB8qms8fOIUJgK-tO83_FeH6Bpe12oUVC670teA,14
450
+ machineconfig-7.57.dist-info/RECORD,,
@@ -1,148 +0,0 @@
1
- """SSH"""
2
-
3
- from platform import system
4
- from machineconfig.utils.source_of_truth import LIBRARY_ROOT
5
- from machineconfig.utils.path_extended import PathExtended
6
- from rich.console import Console
7
- from rich.panel import Panel
8
- from rich import box # Import box
9
- from typing import Optional, Annotated
10
- import typer
11
-
12
-
13
- console = Console()
14
-
15
-
16
- def get_add_ssh_key_script(path_to_key: PathExtended):
17
- console.print(Panel("🔑 SSH KEY CONFIGURATION", title="[bold blue]SSH Setup[/bold blue]"))
18
- if system() == "Linux" or system() == "Darwin":
19
- authorized_keys = PathExtended.home().joinpath(".ssh/authorized_keys")
20
- console.print(Panel(f"🐧 Linux SSH configuration\n📄 Authorized keys file: {authorized_keys}", title="[bold blue]System Info[/bold blue]"))
21
- elif system() == "Windows":
22
- authorized_keys = PathExtended("C:/ProgramData/ssh/administrators_authorized_keys")
23
- console.print(Panel(f"🪟 Windows SSH configuration\n📄 Authorized keys file: {authorized_keys}", title="[bold blue]System Info[/bold blue]"))
24
- else:
25
- console.print(Panel("❌ ERROR: Unsupported operating system\nOnly Linux and Windows are supported", title="[bold red]Error[/bold red]"))
26
- raise NotImplementedError
27
-
28
- if authorized_keys.exists():
29
- split = "\n"
30
- keys_text = authorized_keys.read_text(encoding="utf-8").split(split)
31
- key_count = len([k for k in keys_text if k.strip()])
32
- console.print(Panel(f"🔍 Current SSH authorization status\n✅ Found {key_count} authorized key(s)", title="[bold blue]Status[/bold blue]"))
33
- if path_to_key.read_text(encoding="utf-8") in authorized_keys.read_text(encoding="utf-8"):
34
- console.print(Panel(f"⚠️ Key already authorized\nKey: {path_to_key.name}\nStatus: Already present in authorized_keys file\nNo action required", title="[bold yellow]Warning[/bold yellow]"))
35
- program = ""
36
- else:
37
- console.print(Panel(f"➕ Adding new SSH key to authorized keys\n🔑 Key file: {path_to_key.name}", title="[bold blue]Action[/bold blue]"))
38
- if system() == "Linux":
39
- program = f"cat {path_to_key} >> ~/.ssh/authorized_keys"
40
- elif system() == "Windows":
41
- program_path = LIBRARY_ROOT.joinpath("setup_windows/add-sshkey.ps1")
42
- program = program_path.expanduser().read_text(encoding="utf-8")
43
- place_holder = r'$sshfile = "$env:USERPROFILE\.ssh\pubkey.pub"'
44
- assert place_holder in program, f"This section performs string manipulation on the script {program_path} to add the key to the authorized_keys file. The script has changed and the string {place_holder} is not found."
45
- program = program.replace(place_holder, f'$sshfile = "{path_to_key}"')
46
- console.print(Panel("🔧 Configured PowerShell script for Windows\n📝 Replaced placeholder with actual key path", title="[bold blue]Configuration[/bold blue]"))
47
- else:
48
- raise NotImplementedError
49
- else:
50
- console.print(Panel(f"📝 Creating new authorized_keys file\n🔑 Using key: {path_to_key.name}", title="[bold blue]Action[/bold blue]"))
51
- if system() == "Linux":
52
- program = f"cat {path_to_key} > ~/.ssh/authorized_keys"
53
- else:
54
- program_path = LIBRARY_ROOT.joinpath("setup_windows/openssh-server_add-sshkey.ps1")
55
- program = PathExtended(program_path).expanduser().read_text(encoding="utf-8").replace('$sshfile=""', f'$sshfile="{path_to_key}"')
56
- console.print(Panel("🔧 Configured PowerShell script for Windows\n📝 Set key path in script", title="[bold blue]Configuration[/bold blue]"))
57
-
58
- if system() == "Linux" or system() == "Darwin":
59
- program += """
60
- sudo chmod 700 ~/.ssh
61
- sudo chmod 644 ~/.ssh/authorized_keys
62
- sudo chmod 644 ~/.ssh/*.pub
63
- sudo service ssh --full-restart
64
- # from superuser.com/questions/215504/permissions-on-private-key-in-ssh-folder
65
- """
66
- return program
67
-
68
-
69
-
70
- """
71
- # Common pitfalls:
72
- # 🚫 Wrong line endings (LF/CRLF) in config files
73
- # 🌐 Network port conflicts (try 2222 -> 2223) between WSL and Windows
74
- # sudo service ssh restart
75
- # sudo service ssh status
76
- # sudo nano /etc/ssh/sshd_config
77
- """
78
-
79
-
80
- def main(pub_path: Annotated[Optional[str], typer.Argument(..., help="Path to the public key file")] = None,
81
- pub_choose: Annotated[bool, typer.Option(..., "--choose", "-c", help="Choose from available public keys in ~/.ssh")] = False,
82
- pub_val: Annotated[bool, typer.Option(..., "--paste", "-p", help="Paste the public key content manually")] = False,
83
- from_github: Annotated[Optional[str], typer.Option(..., "--from-github", "-g", help="Fetch public keys from a GitHub username")] = None
84
- ) -> None:
85
- if pub_path:
86
- key_path = PathExtended(pub_path).expanduser().absolute()
87
- if not key_path.exists():
88
- console.print(Panel(f"❌ ERROR: Provided key path does not exist\nPath: {key_path}", title="[bold red]Error[/bold red]"))
89
- raise FileNotFoundError(f"Provided key path does not exist: {key_path}")
90
- console.print(Panel(f"📄 Using provided public key file: {key_path}", title="[bold blue]Info[/bold blue]"))
91
- program = get_add_ssh_key_script(key_path)
92
- from machineconfig.utils.code import run_shell_script
93
- run_shell_script(script=program)
94
- console.print(Panel("✅ SSH KEY AUTHORIZATION COMPLETED", box=box.DOUBLE_EDGE, title_align="left"))
95
- return
96
- elif pub_choose:
97
- console.print(Panel("🔐 SSH PUBLIC KEY AUTHORIZATION TOOL", box=box.DOUBLE_EDGE, title_align="left"))
98
- console.print(Panel("🔍 Searching for public keys...", title="[bold blue]SSH Setup[/bold blue]", border_style="blue"))
99
- pub_keys = PathExtended.home().joinpath(".ssh").search("*.pub")
100
- if pub_keys:
101
- console.print(Panel(f"✅ Found {len(pub_keys)} public key(s)", title="[bold green]Status[/bold green]", border_style="green"))
102
- else:
103
- console.print(Panel("⚠️ No public keys found", title="[bold yellow]Warning[/bold yellow]", border_style="yellow"))
104
- return
105
- console.print(Panel(f"🔄 Processing all {len(pub_keys)} public keys...", title="[bold blue]Processing[/bold blue]", border_style="blue"))
106
- program = "\n\n\n".join([get_add_ssh_key_script(key) for key in pub_keys])
107
-
108
- elif pub_val:
109
- console.print(Panel("📋 Please provide a filename and paste the public key content", title="[bold blue]Input Required[/bold blue]", border_style="blue"))
110
- key_filename = input("📝 File name (default: my_pasted_key.pub): ") or "my_pasted_key.pub"
111
- key_path = PathExtended.home().joinpath(f".ssh/{key_filename}")
112
- key_path.write_text(input("🔑 Paste the public key here: "), encoding="utf-8")
113
- console.print(Panel(f"💾 Key saved to: {key_path}", title="[bold green]Success[/bold green]", border_style="green"))
114
- program = get_add_ssh_key_script(key_path)
115
- elif from_github:
116
- console.print(Panel(f"🌐 Fetching public keys from GitHub user: {from_github}", title="[bold blue]GitHub Fetch[/bold blue]", border_style="blue"))
117
- import requests
118
- # $pubkey_url = 'https://github.com/thisismygitrepo.keys' # $pubkey_string = (Invoke-WebRequest $pubkey_url).Content
119
- response = requests.get(f"https://api.github.com/users/{from_github}/keys")
120
- if response.status_code != 200:
121
- console.print(Panel(f"❌ ERROR: Failed to fetch keys from GitHub user {from_github}\nStatus Code: {response.status_code}", title="[bold red]Error[/bold red]", border_style="red"))
122
- raise RuntimeError(f"Failed to fetch keys from GitHub user {from_github}: Status Code {response.status_code}")
123
- keys = response.json()
124
- if not keys:
125
- console.print(Panel(f"⚠️ No public keys found for GitHub user: {from_github}", title="[bold yellow]Warning[/bold yellow]", border_style="yellow"))
126
- return
127
- console.print(Panel(f"✅ Found {len(keys)} public key(s) for user: {from_github}", title="[bold green]Success[/bold green]", border_style="green"))
128
- key_path = PathExtended.home().joinpath(f".ssh/{from_github}_github_keys.pub")
129
- key_path.write_text("\n".join([key["key"] for key in keys]), encoding="utf-8")
130
- console.print(Panel(f"💾 Keys saved to: {key_path}", title="[bold green]Success[/bold green]", border_style="green"))
131
- program = get_add_ssh_key_script(key_path)
132
- else:
133
- console.print(Panel("❌ ERROR: No method provided to add SSH key\nUse --help for options", title="[bold red]Error[/bold red]", border_style="red"))
134
- raise ValueError("No method provided to add SSH key. Use --help for options.")
135
- console.print(Panel("🚀 SSH KEY AUTHORIZATION READY\nRun the generated script to apply changes", box=box.DOUBLE_EDGE, title_align="left"))
136
- from machineconfig.utils.code import run_shell_script
137
- run_shell_script(script=program)
138
- import socket
139
- s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
140
- s.connect(('8.8.8.8',80))
141
- local_ip_v4 = s.getsockname()[0]
142
- s.close()
143
- print(f"This computer is @ {local_ip_v4}")
144
- console.print(Panel("✅ SSH KEY AUTHORIZATION COMPLETED", box=box.DOUBLE_EDGE, title_align="left"))
145
-
146
-
147
- if __name__ == "__main__":
148
- pass