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

Files changed (104) hide show
  1. machineconfig/cluster/sessions_managers/utils/maker.py +4 -2
  2. machineconfig/jobs/installer/custom/yazi.py +120 -0
  3. machineconfig/jobs/installer/custom_dev/nerdfont.py +1 -1
  4. machineconfig/jobs/installer/custom_dev/nerfont_windows_helper.py +26 -12
  5. machineconfig/jobs/installer/custom_dev/sysabc.py +26 -5
  6. machineconfig/jobs/installer/installer_data.json +232 -96
  7. machineconfig/jobs/installer/powershell_scripts/install_fonts.ps1 +129 -34
  8. machineconfig/profile/create_helper.py +0 -12
  9. machineconfig/profile/create_links_export.py +2 -2
  10. machineconfig/profile/mapper.toml +2 -2
  11. machineconfig/scripts/__init__.py +0 -4
  12. machineconfig/scripts/python/agents.py +22 -17
  13. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +4 -0
  14. machineconfig/scripts/python/croshell.py +22 -17
  15. machineconfig/scripts/python/devops.py +1 -1
  16. machineconfig/scripts/python/devops_navigator.py +0 -4
  17. machineconfig/scripts/python/env_manager/env_manager_tui.py +204 -0
  18. machineconfig/scripts/python/env_manager/path_manager_tui.py +1 -1
  19. machineconfig/scripts/python/fire_jobs.py +13 -13
  20. machineconfig/scripts/python/ftpx.py +36 -12
  21. machineconfig/scripts/python/helpers/ast_search.py +74 -0
  22. machineconfig/scripts/python/helpers/qr_code.py +166 -0
  23. machineconfig/scripts/python/helpers/repo_rag.py +325 -0
  24. machineconfig/scripts/python/helpers/symantic_search.py +25 -0
  25. machineconfig/scripts/python/helpers_cloud/cloud_copy.py +28 -21
  26. machineconfig/scripts/python/helpers_cloud/cloud_helpers.py +1 -1
  27. machineconfig/scripts/python/helpers_cloud/cloud_mount.py +19 -17
  28. machineconfig/scripts/python/helpers_cloud/cloud_sync.py +8 -7
  29. machineconfig/scripts/python/helpers_croshell/start_slidev.py +6 -7
  30. machineconfig/scripts/python/helpers_devops/cli_config.py +10 -0
  31. machineconfig/scripts/python/helpers_devops/cli_nw.py +90 -10
  32. machineconfig/scripts/python/helpers_devops/cli_self.py +8 -7
  33. machineconfig/scripts/python/helpers_devops/cli_share_file.py +7 -7
  34. machineconfig/scripts/python/helpers_devops/cli_share_server.py +12 -11
  35. machineconfig/scripts/python/helpers_devops/cli_terminal.py +8 -10
  36. machineconfig/scripts/python/helpers_devops/cli_utils.py +2 -1
  37. machineconfig/scripts/python/helpers_devops/devops_status.py +7 -19
  38. machineconfig/scripts/python/helpers_fire_command/fire_jobs_route_helper.py +20 -9
  39. machineconfig/scripts/python/helpers_msearch/scripts_linux/fzfg +2 -2
  40. machineconfig/scripts/python/helpers_msearch/scripts_windows/fzfg.ps1 +58 -1
  41. machineconfig/scripts/python/helpers_navigator/command_tree.py +50 -18
  42. machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py +5 -3
  43. machineconfig/scripts/python/helpers_repos/count_lines.py +40 -11
  44. machineconfig/scripts/python/helpers_repos/count_lines_frontend.py +1 -1
  45. machineconfig/scripts/python/helpers_utils/download.py +4 -3
  46. machineconfig/scripts/python/helpers_utils/path.py +87 -34
  47. machineconfig/scripts/python/interactive.py +1 -1
  48. machineconfig/scripts/python/{machineconfig.py → mcfg_entry.py} +4 -0
  49. machineconfig/scripts/python/msearch.py +55 -6
  50. machineconfig/scripts/python/nw/address.py +132 -0
  51. machineconfig/scripts/python/nw/devops_add_ssh_key.py +8 -5
  52. machineconfig/scripts/python/terminal.py +2 -2
  53. machineconfig/scripts/python/utils.py +12 -11
  54. machineconfig/scripts/windows/mounts/mount_ssh.ps1 +1 -1
  55. machineconfig/settings/lf/windows/lfcd.ps1 +1 -1
  56. machineconfig/settings/shells/nushell/config.nu +2 -2
  57. machineconfig/settings/shells/nushell/env.nu +45 -6
  58. machineconfig/settings/shells/nushell/init.nu +282 -95
  59. machineconfig/settings/shells/pwsh/init.ps1 +1 -0
  60. machineconfig/settings/yazi/init.lua +4 -0
  61. machineconfig/settings/yazi/keymap_linux.toml +11 -4
  62. machineconfig/settings/yazi/theme.toml +4 -0
  63. machineconfig/settings/yazi/yazi_linux.toml +84 -0
  64. machineconfig/settings/yazi/yazi_windows.toml +58 -0
  65. machineconfig/setup_linux/web_shortcuts/interactive.sh +10 -10
  66. machineconfig/setup_windows/uv.ps1 +8 -1
  67. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +10 -10
  68. machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +3 -2
  69. machineconfig/utils/accessories.py +7 -4
  70. machineconfig/utils/code.py +4 -2
  71. machineconfig/utils/installer_utils/github_release_bulk.py +104 -62
  72. machineconfig/utils/installer_utils/install_from_url.py +200 -0
  73. machineconfig/utils/installer_utils/installer_class.py +25 -74
  74. machineconfig/utils/installer_utils/installer_cli.py +40 -50
  75. machineconfig/utils/installer_utils/installer_helper.py +100 -0
  76. machineconfig/utils/installer_utils/installer_runner.py +5 -8
  77. machineconfig/utils/links.py +2 -2
  78. machineconfig/utils/meta.py +2 -2
  79. machineconfig/utils/options.py +3 -3
  80. machineconfig/utils/path_extended.py +1 -1
  81. machineconfig/utils/path_helper.py +0 -1
  82. machineconfig/utils/ssh.py +143 -409
  83. machineconfig/utils/ssh_utils/abc.py +8 -0
  84. machineconfig/utils/ssh_utils/copy_from_here.py +110 -0
  85. machineconfig/utils/ssh_utils/copy_to_here.py +302 -0
  86. machineconfig/utils/ssh_utils/utils.py +141 -0
  87. machineconfig/utils/ssh_utils/wsl.py +210 -0
  88. machineconfig/utils/upgrade_packages.py +2 -1
  89. machineconfig/utils/ve.py +11 -4
  90. {machineconfig-7.64.dist-info → machineconfig-7.83.dist-info}/METADATA +2 -2
  91. {machineconfig-7.64.dist-info → machineconfig-7.83.dist-info}/RECORD +96 -89
  92. {machineconfig-7.64.dist-info → machineconfig-7.83.dist-info}/entry_points.txt +2 -2
  93. machineconfig/scripts/python/explore.py +0 -49
  94. machineconfig/scripts/python/helpers_msearch/scripts_linux/fzfag +0 -17
  95. machineconfig/scripts/python/helpers_msearch/scripts_linux/fzfrga +0 -21
  96. machineconfig/scripts/python/helpers_msearch/scripts_linux/skrg +0 -4
  97. machineconfig/scripts/python/helpers_msearch/scripts_windows/fzfb.ps1 +0 -3
  98. machineconfig/scripts/python/helpers_msearch/scripts_windows/fzfrga.bat +0 -20
  99. machineconfig/settings/yazi/yazi.toml +0 -17
  100. machineconfig/setup_linux/others/cli_installation.sh +0 -137
  101. /machineconfig/{settings/shells/pwsh/profile.ps1 → scripts/python/helpers_fire_command/f.py} +0 -0
  102. /machineconfig/scripts/{Restore-ThunderbirdProfile.ps1 → windows/mounts/Restore-ThunderbirdProfile.ps1} +0 -0
  103. {machineconfig-7.64.dist-info → machineconfig-7.83.dist-info}/WHEEL +0 -0
  104. {machineconfig-7.64.dist-info → machineconfig-7.83.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,210 @@
1
+ import os
2
+ import platform
3
+ import stat
4
+ import shutil
5
+ import subprocess
6
+ from pathlib import Path, PureWindowsPath
7
+
8
+
9
+ def _ensure_relative_path(requested: Path | str) -> Path:
10
+ path = Path(requested)
11
+ if path.is_absolute():
12
+ raise ValueError("paths must be relative to the home directory")
13
+ if any(part == ".." for part in path.parts):
14
+ raise ValueError("paths must stay within the home directory")
15
+ return path
16
+
17
+
18
+ def _remove_path(path: Path) -> None:
19
+ if path.is_symlink() or path.is_file():
20
+ path.unlink()
21
+ return
22
+ shutil.rmtree(path)
23
+
24
+
25
+ def _ensure_wsl_environment() -> None:
26
+ if os.environ.get("WSL_DISTRO_NAME"):
27
+ return
28
+ if "microsoft" in platform.release().lower():
29
+ return
30
+ raise RuntimeError("copy_when_inside_wsl must run inside WSL")
31
+
32
+
33
+ def _ensure_windows_environment() -> None:
34
+ if os.name != "nt":
35
+ raise RuntimeError("copy_when_inside_windows must run inside Windows")
36
+ if os.environ.get("WSL_DISTRO_NAME"):
37
+ raise RuntimeError("copy_when_inside_windows must run inside Windows")
38
+
39
+
40
+ def _infer_windows_home_from_permissions() -> Path:
41
+ base_dir = Path("/mnt/c/Users")
42
+ try:
43
+ entries = list(base_dir.iterdir())
44
+ except FileNotFoundError as exc:
45
+ raise RuntimeError("unable to find /mnt/c/Users") from exc
46
+ candidates: list[Path] = []
47
+ for entry in entries:
48
+ if not entry.is_dir():
49
+ continue
50
+ if entry.name.lower() == "public" or entry.name.lower() == "all users":
51
+ continue
52
+ try:
53
+ mode = stat.S_IMODE(entry.stat().st_mode)
54
+ except OSError:
55
+ continue
56
+ if mode == 0o777:
57
+ candidates.append(entry)
58
+ if len(candidates) != 1:
59
+ options = ", ".join(sorted(candidate.name for candidate in candidates)) or "none"
60
+ raise RuntimeError(f"unable to infer Windows home directory (candidates: {options})")
61
+ return candidates[0]
62
+
63
+
64
+ def _resolve_windows_home_from_wsl() -> Path:
65
+ user_profile = os.environ.get("USERPROFILE")
66
+ if user_profile:
67
+ windows_path = PureWindowsPath(user_profile)
68
+ drive = windows_path.drive
69
+ if drive:
70
+ drive_letter = drive.rstrip(":").lower()
71
+ tail = Path(*windows_path.parts[1:])
72
+ candidate = Path("/mnt") / drive_letter / tail
73
+ if candidate.exists():
74
+ return candidate
75
+ return _infer_windows_home_from_permissions()
76
+
77
+
78
+ def _decode_wsl_output(raw_bytes: bytes) -> str:
79
+ try:
80
+ return raw_bytes.decode("utf-16-le")
81
+ except UnicodeDecodeError:
82
+ return raw_bytes.decode()
83
+
84
+
85
+ def _get_single_wsl_distribution() -> str:
86
+ process = subprocess.run(["wsl.exe", "-l"], capture_output=True, text=False, check=True)
87
+ stdout = _decode_wsl_output(process.stdout).replace("\ufeff", "")
88
+ distributions: list[str] = []
89
+ for raw_line in stdout.splitlines():
90
+ line = raw_line.strip()
91
+ if not line or line.lower().startswith("windows subsystem for linux"):
92
+ continue
93
+ normalized = line.lstrip("* ").replace("(Default)", "").strip()
94
+ if normalized:
95
+ distributions.append(normalized)
96
+ if len(distributions) != 1:
97
+ raise RuntimeError("unable to pick a single WSL distribution")
98
+ return distributions[0]
99
+
100
+
101
+ def _resolve_wsl_home_on_windows() -> Path:
102
+ distribution = _get_single_wsl_distribution()
103
+ home_root = Path(rf"\\wsl$\{distribution}\home")
104
+ try:
105
+ entries = list(home_root.iterdir())
106
+ except FileNotFoundError as exc:
107
+ raise RuntimeError(f"unable to locate WSL home directories for {distribution}") from exc
108
+ except OSError as exc:
109
+ raise RuntimeError(f"unable to inspect WSL home directories for {distribution}") from exc
110
+ user_dirs = [entry for entry in entries if entry.is_dir()]
111
+ if len(user_dirs) != 1:
112
+ options = ", ".join(sorted(entry.name for entry in user_dirs)) or "none"
113
+ raise RuntimeError(f"unable to infer WSL user directory (candidates: {options})")
114
+ return user_dirs[0]
115
+
116
+
117
+ def _quote_for_powershell(path: Path) -> str:
118
+ return "'" + str(path).replace("'", "''") + "'"
119
+
120
+
121
+ def _run_windows_copy_command(source_path: Path, target_path: Path) -> None:
122
+ source_is_dir = source_path.is_dir()
123
+ parent_literal = _quote_for_powershell(target_path.parent)
124
+ source_literal = _quote_for_powershell(source_path)
125
+ target_literal = _quote_for_powershell(target_path)
126
+ script = (
127
+ "$ErrorActionPreference = 'Stop'; "
128
+ f"New-Item -ItemType Directory -Path {parent_literal} -Force | Out-Null; "
129
+ f"Copy-Item -LiteralPath {source_literal} -Destination {target_literal}"
130
+ f"{' -Recurse' if source_is_dir else ''} -Force"
131
+ )
132
+ print(f"Copying {source_path} to {target_path}")
133
+ subprocess.run(
134
+ ["powershell.exe", "-NoLogo", "-NoProfile", "-Command", script],
135
+ check=True,
136
+ )
137
+
138
+
139
+ def _ensure_symlink(link_path: Path, target_path: Path) -> None:
140
+ if not target_path.exists():
141
+ raise FileNotFoundError(target_path)
142
+ if link_path.is_symlink():
143
+ existing_target = Path(os.path.realpath(link_path))
144
+ desired_target = Path(os.path.realpath(target_path))
145
+ if os.path.normcase(str(existing_target)) == os.path.normcase(str(desired_target)):
146
+ return
147
+ link_path.unlink()
148
+ elif link_path.exists():
149
+ raise FileExistsError(link_path)
150
+ link_path.symlink_to(target_path, target_is_directory=True)
151
+
152
+
153
+ def copy_when_inside_wsl(source: Path | str, target: Path | str, overwrite: bool) -> None:
154
+ _ensure_wsl_environment()
155
+ source_relative = _ensure_relative_path(source)
156
+ target_relative = _ensure_relative_path(target)
157
+ source_path = Path.home() / source_relative
158
+ target_path = _resolve_windows_home_from_wsl() / target_relative
159
+ if not source_path.exists():
160
+ raise FileNotFoundError(source_path)
161
+ if target_path.exists():
162
+ if not overwrite:
163
+ raise FileExistsError(target_path)
164
+ _remove_path(target_path)
165
+ target_path.parent.mkdir(parents=True, exist_ok=True)
166
+ if source_path.is_dir():
167
+ shutil.copytree(source_path, target_path, dirs_exist_ok=False)
168
+ return
169
+ print(f"Copying {source_path} to {target_path}")
170
+ shutil.copy2(source_path, target_path)
171
+
172
+
173
+ def copy_when_inside_windows(source: Path | str, target: Path | str, overwrite: bool) -> None:
174
+ _ensure_windows_environment()
175
+ source_relative = _ensure_relative_path(source)
176
+ target_relative = _ensure_relative_path(target)
177
+ source_path = Path.home() / source_relative
178
+ target_path = _resolve_wsl_home_on_windows() / target_relative
179
+ if not source_path.exists():
180
+ raise FileNotFoundError(source_path)
181
+ if target_path.exists():
182
+ if not overwrite:
183
+ raise FileExistsError(target_path)
184
+ _remove_path(target_path)
185
+ _run_windows_copy_command(source_path, target_path)
186
+
187
+
188
+ def link_wsl_and_windows() -> None:
189
+ system = platform.system()
190
+ if system == "Darwin":
191
+ raise RuntimeError("link_wsl_and_windows is not designed for macOS")
192
+ try:
193
+ _ensure_wsl_environment()
194
+ except RuntimeError:
195
+ try:
196
+ _ensure_windows_environment()
197
+ except RuntimeError as exc:
198
+ raise RuntimeError("link_wsl_and_windows must run inside Windows or WSL") from exc
199
+ target_path = _resolve_wsl_home_on_windows()
200
+ link_path = Path.home() / "wsl"
201
+ _ensure_symlink(link_path, target_path)
202
+ return
203
+ target_path = _resolve_windows_home_from_wsl()
204
+ link_path = Path.home() / "win"
205
+ _ensure_symlink(link_path, target_path)
206
+
207
+
208
+ if __name__ == "__main__":
209
+ copy_when_inside_wsl(Path("projects/source.txt"), Path("windows_projects/source.txt"), True)
210
+ copy_when_inside_windows(Path("documents/example.txt"), Path("linux_documents/example.txt"), True)
@@ -164,8 +164,9 @@ def upgrade_machine_config_version() -> None:
164
164
  except (UnicodeDecodeError, PermissionError):
165
165
  # Skip files that can't be read as text
166
166
  pass
167
-
168
167
  print(f"Updated {files_updated} files with version constraint")
168
+ from machineconfig.utils.code import exit_then_run_shell_script
169
+ exit_then_run_shell_script(f"cd current_dir; uv sync")
169
170
 
170
171
 
171
172
  if __name__ == "__main__":
machineconfig/utils/ve.py CHANGED
@@ -1,14 +1,15 @@
1
- from machineconfig.utils.io import read_ini
2
- import platform
1
+
3
2
  from typing import Optional
4
- from pathlib import Path
5
3
 
6
4
 
7
- def get_ve_path_and_ipython_profile(init_path: Path) -> tuple[Optional[str], Optional[str]]:
5
+ def get_ve_path_and_ipython_profile(init_path: "Path") -> tuple[Optional[str], Optional[str]]:
8
6
  """Works with .ve.ini .venv and .ve_path"""
9
7
  ve_path: Optional[str] = None
10
8
  ipy_profile: Optional[str] = None
11
9
  tmp = init_path
10
+
11
+ from machineconfig.utils.io import read_ini
12
+
12
13
  for _ in init_path.parents:
13
14
  if tmp.joinpath(".ve.ini").exists():
14
15
  ini = read_ini(tmp.joinpath(".ve.ini"))
@@ -39,6 +40,8 @@ def get_ve_path_and_ipython_profile(init_path: Path) -> tuple[Optional[str], Opt
39
40
 
40
41
 
41
42
  def get_ve_activate_line(ve_root: str):
43
+ import platform
44
+ from pathlib import Path
42
45
  if platform.system() == "Windows":
43
46
  q = Path(ve_root).expanduser().relative_to(Path.home()).as_posix()
44
47
  activate_ve_line = f". $HOME/{q}/Scripts/activate.ps1"
@@ -47,3 +50,7 @@ def get_ve_activate_line(ve_root: str):
47
50
  else:
48
51
  raise NotImplementedError(f"Platform {platform.system()} not supported.")
49
52
  return activate_ve_line
53
+
54
+
55
+ if __name__ == "__main__":
56
+ from pathlib import Path
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: machineconfig
3
- Version: 7.64
3
+ Version: 7.83
4
4
  Summary: Dotfiles management package
5
5
  Author-email: Alex Al-Saffar <programmer@usa.com>
6
6
  License: Apache 2.0
@@ -53,7 +53,7 @@ Requires-Dist: python-magic>=0.4.27; extra == "plot"
53
53
 
54
54
  # 🧠 Welcome to **Machineconfig**
55
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.
56
+ **Machineconfig** is a cli-based **Stack Manager** — 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, that is consistent across different platforms.
57
57
 
58
58
 
59
59
  ## 💡 Motivation