machineconfig 1.97__py3-none-any.whl → 2.0__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 (166) hide show
  1. machineconfig/cluster/cloud_manager.py +22 -26
  2. machineconfig/cluster/data_transfer.py +2 -2
  3. machineconfig/cluster/distribute.py +0 -2
  4. machineconfig/cluster/file_manager.py +4 -4
  5. machineconfig/cluster/job_params.py +1 -1
  6. machineconfig/cluster/loader_runner.py +8 -8
  7. machineconfig/cluster/remote_machine.py +4 -4
  8. machineconfig/cluster/script_execution.py +2 -2
  9. machineconfig/cluster/sessions_managers/archive/create_zellij_template.py +1 -1
  10. machineconfig/cluster/sessions_managers/enhanced_command_runner.py +23 -23
  11. machineconfig/cluster/sessions_managers/wt_local.py +78 -76
  12. machineconfig/cluster/sessions_managers/wt_local_manager.py +91 -91
  13. machineconfig/cluster/sessions_managers/wt_remote.py +39 -39
  14. machineconfig/cluster/sessions_managers/wt_remote_manager.py +94 -91
  15. machineconfig/cluster/sessions_managers/wt_utils/layout_generator.py +56 -54
  16. machineconfig/cluster/sessions_managers/wt_utils/process_monitor.py +49 -49
  17. machineconfig/cluster/sessions_managers/wt_utils/remote_executor.py +18 -18
  18. machineconfig/cluster/sessions_managers/wt_utils/session_manager.py +42 -42
  19. machineconfig/cluster/sessions_managers/wt_utils/status_reporter.py +36 -36
  20. machineconfig/cluster/sessions_managers/zellij_local.py +43 -46
  21. machineconfig/cluster/sessions_managers/zellij_local_manager.py +139 -120
  22. machineconfig/cluster/sessions_managers/zellij_remote.py +35 -35
  23. machineconfig/cluster/sessions_managers/zellij_remote_manager.py +33 -33
  24. machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +15 -15
  25. machineconfig/cluster/sessions_managers/zellij_utils/layout_generator.py +25 -26
  26. machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +49 -49
  27. machineconfig/cluster/sessions_managers/zellij_utils/remote_executor.py +5 -5
  28. machineconfig/cluster/sessions_managers/zellij_utils/session_manager.py +15 -15
  29. machineconfig/cluster/sessions_managers/zellij_utils/status_reporter.py +11 -11
  30. machineconfig/cluster/templates/utils.py +3 -3
  31. machineconfig/jobs/__pycache__/__init__.cpython-311.pyc +0 -0
  32. machineconfig/jobs/python/__pycache__/__init__.cpython-311.pyc +0 -0
  33. machineconfig/jobs/python/__pycache__/python_ve_symlink.cpython-311.pyc +0 -0
  34. machineconfig/jobs/python/check_installations.py +8 -9
  35. machineconfig/jobs/python/python_cargo_build_share.py +2 -2
  36. machineconfig/jobs/python/vscode/link_ve.py +7 -7
  37. machineconfig/jobs/python/vscode/select_interpreter.py +7 -7
  38. machineconfig/jobs/python/vscode/sync_code.py +5 -5
  39. machineconfig/jobs/python_custom_installers/archive/ngrok.py +2 -2
  40. machineconfig/jobs/python_custom_installers/dev/aider.py +3 -3
  41. machineconfig/jobs/python_custom_installers/dev/alacritty.py +3 -3
  42. machineconfig/jobs/python_custom_installers/dev/brave.py +3 -3
  43. machineconfig/jobs/python_custom_installers/dev/bypass_paywall.py +5 -5
  44. machineconfig/jobs/python_custom_installers/dev/code.py +3 -3
  45. machineconfig/jobs/python_custom_installers/dev/cursor.py +9 -9
  46. machineconfig/jobs/python_custom_installers/dev/docker_desktop.py +4 -4
  47. machineconfig/jobs/python_custom_installers/dev/espanso.py +4 -4
  48. machineconfig/jobs/python_custom_installers/dev/goes.py +4 -4
  49. machineconfig/jobs/python_custom_installers/dev/lvim.py +4 -4
  50. machineconfig/jobs/python_custom_installers/dev/nerdfont.py +3 -3
  51. machineconfig/jobs/python_custom_installers/dev/redis.py +3 -3
  52. machineconfig/jobs/python_custom_installers/dev/wezterm.py +3 -3
  53. machineconfig/jobs/python_custom_installers/dev/winget.py +27 -27
  54. machineconfig/jobs/python_custom_installers/docker.py +3 -3
  55. machineconfig/jobs/python_custom_installers/gh.py +7 -7
  56. machineconfig/jobs/python_custom_installers/hx.py +1 -1
  57. machineconfig/jobs/python_custom_installers/warp-cli.py +3 -3
  58. machineconfig/jobs/python_generic_installers/config.json +412 -389
  59. machineconfig/jobs/python_windows_installers/dev/config.json +1 -1
  60. machineconfig/logger.py +50 -0
  61. machineconfig/profile/__pycache__/__init__.cpython-311.pyc +0 -0
  62. machineconfig/profile/__pycache__/create.cpython-311.pyc +0 -0
  63. machineconfig/profile/__pycache__/shell.cpython-311.pyc +0 -0
  64. machineconfig/profile/create.py +23 -16
  65. machineconfig/profile/create_hardlinks.py +8 -8
  66. machineconfig/profile/shell.py +41 -37
  67. machineconfig/scripts/__pycache__/__init__.cpython-311.pyc +0 -0
  68. machineconfig/scripts/__pycache__/__init__.cpython-313.pyc +0 -0
  69. machineconfig/scripts/linux/devops +2 -2
  70. machineconfig/scripts/linux/fire +1 -0
  71. machineconfig/scripts/linux/fire_agents +0 -1
  72. machineconfig/scripts/linux/mcinit +1 -1
  73. machineconfig/scripts/python/__pycache__/__init__.cpython-311.pyc +0 -0
  74. machineconfig/scripts/python/__pycache__/__init__.cpython-313.pyc +0 -0
  75. machineconfig/scripts/python/__pycache__/croshell.cpython-311.pyc +0 -0
  76. machineconfig/scripts/python/__pycache__/devops.cpython-311.pyc +0 -0
  77. machineconfig/scripts/python/__pycache__/devops.cpython-313.pyc +0 -0
  78. machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-311.pyc +0 -0
  79. machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-313.pyc +0 -0
  80. machineconfig/scripts/python/__pycache__/fire_agents.cpython-311.pyc +0 -0
  81. machineconfig/scripts/python/__pycache__/fire_jobs.cpython-311.pyc +0 -0
  82. machineconfig/scripts/python/__pycache__/repos.cpython-311.pyc +0 -0
  83. machineconfig/scripts/python/ai/__pycache__/init.cpython-311.pyc +0 -0
  84. machineconfig/scripts/python/ai/__pycache__/mcinit.cpython-311.pyc +0 -0
  85. machineconfig/scripts/python/ai/chatmodes/Thinking-Beast-Mode.chatmode.md +337 -0
  86. machineconfig/scripts/python/ai/chatmodes/Ultimate-Transparent-Thinking-Beast-Mode.chatmode.md +644 -0
  87. machineconfig/scripts/python/ai/chatmodes/deepResearch.chatmode.md +81 -0
  88. machineconfig/scripts/python/ai/configs/.gemini/settings.json +81 -0
  89. machineconfig/scripts/python/ai/instructions/python/dev.instructions.md +45 -0
  90. machineconfig/scripts/python/ai/mcinit.py +103 -0
  91. machineconfig/scripts/python/ai/prompts/allLintersAndTypeCheckers.prompt.md +5 -0
  92. machineconfig/scripts/python/ai/prompts/research-report-skeleton.prompt.md +38 -0
  93. machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +47 -0
  94. machineconfig/scripts/python/archive/tmate_conn.py +5 -5
  95. machineconfig/scripts/python/archive/tmate_start.py +3 -3
  96. machineconfig/scripts/python/choose_wezterm_theme.py +2 -2
  97. machineconfig/scripts/python/cloud_copy.py +19 -18
  98. machineconfig/scripts/python/cloud_mount.py +9 -7
  99. machineconfig/scripts/python/cloud_repo_sync.py +11 -11
  100. machineconfig/scripts/python/cloud_sync.py +1 -1
  101. machineconfig/scripts/python/croshell.py +14 -14
  102. machineconfig/scripts/python/devops.py +6 -6
  103. machineconfig/scripts/python/devops_add_identity.py +8 -6
  104. machineconfig/scripts/python/devops_add_ssh_key.py +18 -18
  105. machineconfig/scripts/python/devops_backup_retrieve.py +13 -13
  106. machineconfig/scripts/python/devops_devapps_install.py +3 -3
  107. machineconfig/scripts/python/devops_update_repos.py +1 -1
  108. machineconfig/scripts/python/dotfile.py +2 -2
  109. machineconfig/scripts/python/fire_agents.py +183 -41
  110. machineconfig/scripts/python/fire_jobs.py +17 -17
  111. machineconfig/scripts/python/ftpx.py +2 -2
  112. machineconfig/scripts/python/gh_models.py +94 -94
  113. machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-311.pyc +0 -0
  114. machineconfig/scripts/python/helpers/__pycache__/cloud_helpers.cpython-311.pyc +0 -0
  115. machineconfig/scripts/python/helpers/__pycache__/helpers2.cpython-311.pyc +0 -0
  116. machineconfig/scripts/python/helpers/__pycache__/helpers4.cpython-311.pyc +0 -0
  117. machineconfig/scripts/python/helpers/cloud_helpers.py +3 -3
  118. machineconfig/scripts/python/helpers/helpers2.py +1 -1
  119. machineconfig/scripts/python/helpers/helpers4.py +8 -6
  120. machineconfig/scripts/python/helpers/helpers5.py +7 -7
  121. machineconfig/scripts/python/helpers/repo_sync_helpers.py +1 -1
  122. machineconfig/scripts/python/mount_nfs.py +3 -2
  123. machineconfig/scripts/python/mount_nw_drive.py +4 -4
  124. machineconfig/scripts/python/mount_ssh.py +3 -2
  125. machineconfig/scripts/python/repos.py +8 -8
  126. machineconfig/scripts/python/scheduler.py +1 -1
  127. machineconfig/scripts/python/start_slidev.py +8 -7
  128. machineconfig/scripts/python/start_terminals.py +1 -1
  129. machineconfig/scripts/python/viewer.py +40 -40
  130. machineconfig/scripts/python/wifi_conn.py +65 -66
  131. machineconfig/scripts/python/wsl_windows_transfer.py +1 -1
  132. machineconfig/scripts/windows/mcinit.ps1 +1 -1
  133. machineconfig/settings/linters/.ruff.toml +2 -2
  134. machineconfig/settings/shells/ipy/profiles/default/startup/playext.py +71 -71
  135. machineconfig/settings/shells/wt/settings.json +8 -8
  136. machineconfig/setup_linux/web_shortcuts/tmp.sh +2 -0
  137. machineconfig/setup_windows/wt_and_pwsh/set_pwsh_theme.py +10 -7
  138. machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +9 -7
  139. machineconfig/utils/ai/browser_user_wrapper.py +5 -5
  140. machineconfig/utils/ai/generate_file_checklist.py +11 -12
  141. machineconfig/utils/ai/url2md.py +1 -1
  142. machineconfig/utils/cloud/onedrive/setup_oauth.py +4 -4
  143. machineconfig/utils/cloud/onedrive/transaction.py +129 -129
  144. machineconfig/utils/code.py +13 -6
  145. machineconfig/utils/installer.py +51 -53
  146. machineconfig/utils/installer_utils/installer_abc.py +21 -10
  147. machineconfig/utils/installer_utils/installer_class.py +42 -16
  148. machineconfig/utils/io_save.py +3 -15
  149. machineconfig/utils/options.py +10 -3
  150. machineconfig/utils/path.py +5 -0
  151. machineconfig/utils/path_reduced.py +201 -149
  152. machineconfig/utils/procs.py +23 -23
  153. machineconfig/utils/scheduling.py +11 -12
  154. machineconfig/utils/ssh.py +270 -0
  155. machineconfig/utils/terminal.py +180 -0
  156. machineconfig/utils/utils.py +1 -2
  157. machineconfig/utils/utils2.py +43 -0
  158. machineconfig/utils/utils5.py +163 -34
  159. machineconfig/utils/ve.py +2 -2
  160. {machineconfig-1.97.dist-info → machineconfig-2.0.dist-info}/METADATA +13 -8
  161. {machineconfig-1.97.dist-info → machineconfig-2.0.dist-info}/RECORD +163 -149
  162. machineconfig/cluster/self_ssh.py +0 -57
  163. machineconfig/scripts/python/ai/init.py +0 -56
  164. machineconfig/scripts/python/ai/rules/python/dev.md +0 -31
  165. {machineconfig-1.97.dist-info → machineconfig-2.0.dist-info}/WHEEL +0 -0
  166. {machineconfig-1.97.dist-info → machineconfig-2.0.dist-info}/top_level.txt +0 -0
@@ -1,11 +1,11 @@
1
1
  from typing import Optional
2
2
  import platform
3
+ import subprocess
3
4
  from rich.console import Console
4
5
  from rich.panel import Panel
5
6
  from rich.syntax import Syntax
6
7
  from machineconfig.utils.utils2 import randstr
7
8
  from machineconfig.utils.path_reduced import P as PathExtended
8
- from crocodile.meta import Terminal
9
9
 
10
10
 
11
11
  PROGRAM_PATH = (PathExtended.home().joinpath("tmp_results", "shells", "python_return_command") + (".ps1" if platform.system() == "Windows" else ".sh"))
@@ -35,7 +35,7 @@ def write_shell_script_to_file(shell_script: str):
35
35
  else: raise NotImplementedError(f"Platform {platform.system()} not implemented.")
36
36
  shell_file = PathExtended.tmp().joinpath("tmp_scripts", "shell", randstr() + suffix)
37
37
  shell_file.parent.mkdir(parents=True, exist_ok=True)
38
- shell_file.write_text(shell_script)
38
+ shell_file.write_text(shell_script, encoding="utf-8")
39
39
  return shell_file
40
40
 
41
41
  # Enhanced print/log/error/exception statements for better clarity and consistency
@@ -50,9 +50,17 @@ def write_shell_script_to_default_program_path(program: str, desc: str, preserve
50
50
  program = 'orig_path=$(cd -- "." && pwd)\n' + program + '\ncd "$orig_path" || exit'
51
51
  if display: print_code(code=program, lexer="shell", desc=desc, subtitle=str(PROGRAM_PATH))
52
52
  PROGRAM_PATH.parent.mkdir(parents=True, exist_ok=True)
53
- PROGRAM_PATH.write_text(program)
53
+ PROGRAM_PATH.write_text(program, encoding="utf-8")
54
54
  if execute:
55
- Terminal().run(f". {PROGRAM_PATH}", shell="powershell").capture().print_if_unsuccessful(desc="đŸ› ī¸ EXECUTION | Shell script running", strict_err=True, strict_returncode=True)
55
+ result = subprocess.run(f". {PROGRAM_PATH}", shell=True, capture_output=True, text=True)
56
+ success = result.returncode == 0 and result.stderr == ""
57
+ if not success:
58
+ print(f"❌ đŸ› ī¸ EXECUTION | Shell script running failed")
59
+ if result.stdout:
60
+ print(f"STDOUT: {result.stdout}")
61
+ if result.stderr:
62
+ print(f"STDERR: {result.stderr}")
63
+ print(f"Return code: {result.returncode}")
56
64
  return None
57
65
 
58
66
  def get_shell_file_executing_python_script(python_script: str, ve_name: str, verbose: bool=True):
@@ -70,7 +78,7 @@ except ImportError:
70
78
  """ + python_script
71
79
  python_file = PathExtended.tmp().joinpath("tmp_scripts", "python", randstr() + ".py")
72
80
  python_file.parent.mkdir(parents=True, exist_ok=True)
73
- python_file.write_text(python_script)
81
+ python_file.write_text(python_script, encoding="utf-8")
74
82
  shell_script = get_shell_script_executing_python_file(python_file=str(python_file), ve_name=ve_name)
75
83
  shell_file = write_shell_script_to_file(shell_script)
76
84
  return shell_file
@@ -82,4 +90,3 @@ def print_code(code: str, lexer: str, desc: str, subtitle: str=""):
82
90
  else: raise NotImplementedError(f"Platform {platform.system()} not supported for lexer {lexer}")
83
91
  console = Console()
84
92
  console.print(Panel(Syntax(code=code, lexer=lexer), title=f"📄 {desc}", subtitle=subtitle), style="bold red")
85
-
@@ -6,7 +6,6 @@ from rich.console import Console
6
6
  from rich.panel import Panel # Added import
7
7
 
8
8
  from machineconfig.utils.path_reduced import P as PathExtended
9
- from crocodile.meta import Terminal
10
9
  from machineconfig.utils.utils import INSTALL_VERSION_ROOT
11
10
  from machineconfig.utils.utils2 import read_json
12
11
 
@@ -23,14 +22,14 @@ def check_latest():
23
22
  # installers += get_installers(system=platform.system(), dev=True)
24
23
  installers_github = []
25
24
  for inst__ in installers:
26
- if "ntop" in inst__.name:
25
+ if "ntop" in inst__.name:
27
26
  print(f"â­ī¸ Skipping {inst__.name} (ntop)")
28
27
  continue
29
28
  if "github" not in inst__.repo_url:
30
29
  print(f"â­ī¸ Skipping {inst__.name} (not a GitHub release)")
31
30
  continue
32
31
  installers_github.append(inst__)
33
-
32
+
34
33
  print(f"\n🔍 Checking {len(installers_github)} GitHub-based installers...\n")
35
34
 
36
35
  def func(inst: Installer):
@@ -41,9 +40,9 @@ def check_latest():
41
40
 
42
41
  print("\nâŗ Processing installers...\n")
43
42
  res = [func(inst) for inst in installers_github]
44
-
43
+
45
44
  print("\n📊 Generating results table...\n")
46
-
45
+
47
46
  # Convert to list of dictionaries and group by status
48
47
  result_data = []
49
48
  for tool, status, current_ver, new_ver in res:
@@ -53,17 +52,17 @@ def check_latest():
53
52
  "Current Version": current_ver,
54
53
  "New Version": new_ver
55
54
  })
56
-
55
+
57
56
  # Group by status
58
- grouped_data = {}
57
+ grouped_data: dict[str, list[dict[str, Any]]] = {}
59
58
  for item in result_data:
60
59
  status = item["Status"]
61
60
  if status not in grouped_data:
62
61
  grouped_data[status] = []
63
62
  grouped_data[status].append(item)
64
-
63
+
65
64
  console.print(Panel("📊 INSTALLATION STATUS SUMMARY", title="Status", expand=False))
66
-
65
+
67
66
  # Print each group
68
67
  for status, items in grouped_data.items():
69
68
  print(f"\n{status.upper()}:")
@@ -76,16 +75,16 @@ def check_latest():
76
75
 
77
76
  def get_installed_cli_apps():
78
77
  print(f"\n{'='*80}\n🔍 LISTING INSTALLED CLI APPS 🔍\n{'='*80}")
79
- if platform.system() == "Windows":
78
+ if platform.system() == "Windows":
80
79
  print("đŸĒŸ Searching for Windows executables...")
81
80
  apps = PathExtended.home().joinpath("AppData/Local/Microsoft/WindowsApps").search("*.exe", not_in=["notepad"])
82
- elif platform.system() in ["Linux", "Darwin"]:
81
+ elif platform.system() in ["Linux", "Darwin"]:
83
82
  print(f"🐧 Searching for {platform.system()} executables...")
84
83
  if platform.system() == "Linux":
85
84
  apps = PathExtended(LINUX_INSTALL_PATH).search("*") + PathExtended("/usr/local/bin").search("*")
86
85
  else: # Darwin/macOS
87
86
  apps = PathExtended("/usr/local/bin").search("*") + PathExtended("/opt/homebrew/bin").search("*")
88
- else:
87
+ else:
89
88
  error_msg = f"❌ ERROR: System {platform.system()} not supported"
90
89
  print(error_msg)
91
90
  raise NotImplementedError(error_msg)
@@ -111,11 +110,11 @@ def get_installers(system: str, dev: bool) -> list[Installer]:
111
110
 
112
111
  def get_all_dicts(system: str) -> dict[CATEGORY, dict[str, dict[str, Any]]]:
113
112
  print(f"\n{'='*80}\n📂 LOADING CONFIGURATION FILES 📂\n{'='*80}")
114
-
113
+
115
114
  print(f"🔍 Importing OS-specific installers for {system}...")
116
- if system == "Windows":
115
+ if system == "Windows":
117
116
  import machineconfig.jobs.python_windows_installers as os_specific_installer
118
- else:
117
+ else:
119
118
  import machineconfig.jobs.python_linux_installers as os_specific_installer
120
119
 
121
120
  print("🔍 Importing generic installers...")
@@ -133,10 +132,10 @@ def get_all_dicts(system: str) -> dict[CATEGORY, dict[str, dict[str, Any]]]:
133
132
 
134
133
  print(f"""📄 Loading OS-generic config from: {path_os_generic.joinpath("config.json")}""")
135
134
  res_final["OS_GENERIC"] = read_json(path=path_os_generic.joinpath("config.json"))
136
-
135
+
137
136
  print(f"""📄 Loading OS-specific dev config from: {path_os_specific_dev.joinpath("config.json")}""")
138
137
  res_final["OS_SPECIFIC_DEV"] = read_json(path=path_os_specific_dev.joinpath("config.json"))
139
-
138
+
140
139
  print(f"""📄 Loading OS-generic dev config from: {path_os_generic_dev.joinpath("config.json")}""")
141
140
  res_final["OS_GENERIC_DEV"] = read_json(path=path_os_generic_dev.joinpath("config.json"))
142
141
 
@@ -166,74 +165,73 @@ def get_all_dicts(system: str) -> dict[CATEGORY, dict[str, dict[str, Any]]]:
166
165
 
167
166
  res_final["CUSTOM"] = res_custom
168
167
  res_final["CUSTOM_DEV"] = res_custom_dev
169
-
168
+
170
169
  print(f"✅ Configuration loading complete:\n - OS_SPECIFIC: {len(res_final['OS_SPECIFIC'])} items\n - OS_GENERIC: {len(res_final['OS_GENERIC'])} items\n - CUSTOM: {len(res_final['CUSTOM'])} items\n{'='*80}")
171
170
  return res_final
172
171
 
173
172
 
174
173
  def install_all(installers: list[Installer], safe: bool=False, jobs: int = 10, fresh: bool=False):
175
174
  print(f"\n{'='*80}\n🚀 BULK INSTALLATION PROCESS 🚀\n{'='*80}")
176
- if fresh:
175
+ if fresh:
177
176
  print("🧹 Fresh install requested - clearing version cache...")
178
177
  INSTALL_VERSION_ROOT.delete(sure=True)
179
178
  print("✅ Version cache cleared")
180
-
179
+
181
180
  if safe:
182
- print("âš ī¸ Safe installation mode activated...")
183
- from machineconfig.jobs.python.check_installations import APP_SUMMARY_PATH
184
- apps_dir = APP_SUMMARY_PATH.readit()
185
-
186
- if platform.system().lower() == "windows":
187
- print("đŸĒŸ Moving applications to Windows Apps folder...")
188
- # PathExtended.get_env().WindowsPaths().WindowsApps)
189
- folder = PathExtended.home().joinpath("AppData/Local/Microsoft/WindowsApps")
190
- apps_dir.search("*").apply(lambda app: app.move(folder=folder))
191
- elif platform.system().lower() in ["linux", "darwin"]:
192
- system_name = "Linux" if platform.system().lower() == "linux" else "macOS"
193
- print(f"🐧 Moving applications to {system_name} bin folder...")
194
- if platform.system().lower() == "linux":
195
- install_path = LINUX_INSTALL_PATH
196
- else: # Darwin/macOS
197
- install_path = "/usr/local/bin"
198
- Terminal().run(f"sudo mv {apps_dir.as_posix()}/* {install_path}/").capture().print_if_unsuccessful(desc=f"MOVING executable to {install_path}", strict_err=True, strict_returncode=True)
199
- else:
200
- error_msg = f"❌ ERROR: System {platform.system()} not supported"
201
- print(error_msg)
202
- raise NotImplementedError(error_msg)
203
-
204
- apps_dir.delete(sure=True)
205
- print(f"✅ Safe installation completed\n{'='*80}")
206
- return None
207
-
181
+ pass
182
+ # print("âš ī¸ Safe installation mode activated...")
183
+ # from machineconfig.jobs.python.check_installations import APP_SUMMARY_PATH
184
+ # if platform.system().lower() == "windows":
185
+ # print("đŸĒŸ Moving applications to Windows Apps folder...")
186
+ # # PathExtended.get_env().WindowsPaths().WindowsApps)
187
+ # folder = PathExtended.home().joinpath("AppData/Local/Microsoft/WindowsApps")
188
+ # apps_dir.search("*").apply(lambda app: app.move(folder=folder))
189
+ # elif platform.system().lower() in ["linux", "darwin"]:
190
+ # system_name = "Linux" if platform.system().lower() == "linux" else "macOS"
191
+ # print(f"🐧 Moving applications to {system_name} bin folder...")
192
+ # if platform.system().lower() == "linux":
193
+ # install_path = LINUX_INSTALL_PATH
194
+ # else: # Darwin/macOS
195
+ # install_path = "/usr/local/bin"
196
+ # Terminal().run(f"sudo mv {apps_dir.as_posix()}/* {install_path}/").capture().print_if_unsuccessful(desc=f"MOVING executable to {install_path}", strict_err=True, strict_returncode=True)
197
+ # else:
198
+ # error_msg = f"❌ ERROR: System {platform.system()} not supported"
199
+ # print(error_msg)
200
+ # raise NotImplementedError(error_msg)
201
+
202
+ # apps_dir.delete(sure=True)
203
+ # print(f"✅ Safe installation completed\n{'='*80}")
204
+ # return None
205
+
208
206
  print(f"🚀 Starting installation of {len(installers)} packages...")
209
207
  print(f"\n{'='*80}\nđŸ“Ļ INSTALLING FIRST PACKAGE đŸ“Ļ\n{'='*80}")
210
208
  installers[0].install(version=None)
211
209
  installers_remaining = installers[1:]
212
210
  print(f"\n{'='*80}\nđŸ“Ļ INSTALLING REMAINING PACKAGES đŸ“Ļ\n{'='*80}")
213
-
211
+
214
212
  # Use joblib for parallel processing of remaining installers
215
213
  res = Parallel(n_jobs=jobs)(
216
- delayed(lambda x: x.install_robust(version=None))(installer)
214
+ delayed(lambda x: x.install_robust(version=None))(installer)
217
215
  for installer in installers_remaining
218
216
  )
219
-
217
+
220
218
  console = Console()
221
-
219
+
222
220
  print("\n")
223
221
  console.rule("📊 INSTALLATION RESULTS SUMMARY 📊")
224
-
222
+
225
223
  print("\n")
226
224
  console.rule("✓ Same Version Apps")
227
225
  same_version_results = [r for r in res if r and 'same version' in str(r)]
228
226
  for result in same_version_results:
229
227
  print(f" {result}")
230
-
228
+
231
229
  print("\n")
232
230
  console.rule("âŦ†ī¸ Updated Apps")
233
231
  updated_results = [r for r in res if r and 'updated from' in str(r)]
234
232
  for result in updated_results:
235
233
  print(f" {result}")
236
-
234
+
237
235
  print("\n")
238
236
  console.rule("❌ Failed Apps")
239
237
  failed_results = [r for r in res if r and 'Failed at' in str(r)]
@@ -1,6 +1,6 @@
1
1
  from machineconfig.utils.path_reduced import P as PathExtended
2
- from crocodile.meta import Terminal
3
2
  from typing import Optional, TypeAlias, Literal
3
+ import subprocess
4
4
 
5
5
  # LINUX_INSTALL_PATH = '/usr/local/bin'
6
6
  # LINUX_INSTALL_PATH = '~/.local/bin'
@@ -18,12 +18,12 @@ def find_move_delete_windows(downloaded_file_path: PathExtended, exe_name: Optio
18
18
  else:
19
19
  print(f"🔎 Searching for executable in: {downloaded_file_path}")
20
20
  if exe_name is None:
21
- exe = downloaded_file_path.search("*.exe", r=True).list[0]
21
+ exe = downloaded_file_path.search("*.exe", r=True)[0]
22
22
  print(f"✅ Found executable: {exe}")
23
23
  else:
24
24
  tmp = downloaded_file_path.search(f"{exe_name}.exe", r=True)
25
25
  if len(tmp) == 1:
26
- exe = tmp.list[0]
26
+ exe = tmp[0]
27
27
  print(f"✅ Found exact match for {exe_name}.exe: {exe}")
28
28
  else:
29
29
  search_res = downloaded_file_path.search("*.exe", r=True)
@@ -31,10 +31,10 @@ def find_move_delete_windows(downloaded_file_path: PathExtended, exe_name: Optio
31
31
  print(f"❌ ERROR: No executable found in {downloaded_file_path}")
32
32
  raise IndexError(f"No executable found in {downloaded_file_path}")
33
33
  elif len(search_res) == 1:
34
- exe = search_res.list[0]
34
+ exe = search_res[0]
35
35
  print(f"✅ Found single executable: {exe}")
36
36
  else:
37
- exe = search_res.sort(lambda x: x.size("kb")).list[-1]
37
+ exe = max(search_res, key=lambda x: x.size("kb"))
38
38
  print(f"✅ Selected largest executable ({exe.size('kb')} KB): {exe}")
39
39
  if rename_to and exe.name != rename_to:
40
40
  print(f"đŸˇī¸ Renaming '{exe.name}' to '{rename_to}'")
@@ -62,7 +62,7 @@ def find_move_delete_linux(downloaded: PathExtended, tool_name: str, delete: Opt
62
62
  print(f"🔎 Searching for executable in: {downloaded}")
63
63
  res = downloaded.search(f"*{tool_name}*", folders=False, r=True)
64
64
  if len(res) == 1:
65
- exe = res.list[0]
65
+ exe = res[0]
66
66
  print(f"✅ Found match for pattern '*{tool_name}*': {exe}")
67
67
  else:
68
68
  exe_search_res = downloaded.search(tool_name, folders=False, r=True)
@@ -70,10 +70,10 @@ def find_move_delete_linux(downloaded: PathExtended, tool_name: str, delete: Opt
70
70
  print(f"❌ ERROR: No search results for `{tool_name}` in `{downloaded}`")
71
71
  raise IndexError(f"No executable found in {downloaded}")
72
72
  elif len(exe_search_res) == 1:
73
- exe = exe_search_res.list[0]
73
+ exe = exe_search_res[0]
74
74
  print(f"✅ Found exact match for '{tool_name}': {exe}")
75
75
  else:
76
- exe = exe_search_res.sort(lambda x: x.size("kb")).list[-1]
76
+ exe = max(exe_search_res, key=lambda x: x.size("kb"))
77
77
  print(f"✅ Selected largest executable ({exe.size('kb')} KB): {exe}")
78
78
 
79
79
  if rename_to and exe.name != rename_to:
@@ -87,7 +87,18 @@ def find_move_delete_linux(downloaded: PathExtended, tool_name: str, delete: Opt
87
87
  # exe.move(folder=LINUX_INSTALL_PATH, overwrite=False)
88
88
  if "/usr" in LINUX_INSTALL_PATH:
89
89
  print("🔑 Using sudo to move file to system directory...")
90
- Terminal().run(f"sudo mv {exe} {LINUX_INSTALL_PATH}/").capture().print_if_unsuccessful(desc=f"MOVING executable `{exe}` to {LINUX_INSTALL_PATH}", strict_err=True, strict_returncode=True)
90
+ cmd = f"sudo mv {exe} {LINUX_INSTALL_PATH}/"
91
+ result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
92
+ success = result.returncode == 0 and result.stderr == ""
93
+ if not success:
94
+ desc = f"MOVING executable `{exe}` to {LINUX_INSTALL_PATH}"
95
+ print(f"❌ {desc} failed")
96
+ if result.stdout:
97
+ print(f"STDOUT: {result.stdout}")
98
+ if result.stderr:
99
+ print(f"STDERR: {result.stderr}")
100
+ print(f"Return code: {result.returncode}")
101
+ raise RuntimeError(f"Failed to move executable: {result.stderr or result.stdout}")
91
102
  else:
92
103
  exe.move(folder=LINUX_INSTALL_PATH, overwrite=True)
93
104
 
@@ -98,4 +109,4 @@ def find_move_delete_linux(downloaded: PathExtended, tool_name: str, delete: Opt
98
109
 
99
110
  exe_new_location = PathExtended(LINUX_INSTALL_PATH).joinpath(exe.name)
100
111
  print(f"✅ Executable installed at: {exe_new_location}\n{'='*80}")
101
- return exe_new_location
112
+ return exe_new_location
@@ -1,11 +1,11 @@
1
1
 
2
2
  from machineconfig.utils.path_reduced import P as PathExtended
3
- from crocodile.meta import Terminal
4
3
  from machineconfig.utils.installer_utils.installer_abc import find_move_delete_linux, find_move_delete_windows
5
4
  from machineconfig.utils.utils import INSTALL_TMP_DIR, INSTALL_VERSION_ROOT, LIBRARY_ROOT, check_tool_exists
6
5
  from machineconfig.utils.utils2 import pprint, read_json
7
6
 
8
7
  import platform
8
+ import subprocess
9
9
  from typing import Any, Optional
10
10
  from pathlib import Path
11
11
 
@@ -68,12 +68,14 @@ class Installer:
68
68
  def install_robust(self, version: Optional[str]):
69
69
  try:
70
70
  print(f"\n{'='*80}\n🚀 INSTALLING {self.exe_name.upper()} 🚀\n{'='*80}")
71
- old_version_cli = Terminal().run(f"{self.exe_name} --version").op.replace("\n", "")
71
+ result_old = subprocess.run(f"{self.exe_name} --version", shell=True, capture_output=True, text=True)
72
+ old_version_cli = result_old.stdout.strip()
72
73
  print(f"📊 Current version: {old_version_cli or 'Not installed'}")
73
74
 
74
75
  self.install(version=version)
75
76
 
76
- new_version_cli = Terminal().run(f"{self.exe_name} --version").op.replace("\n", "")
77
+ result_new = subprocess.run(f"{self.exe_name} --version", shell=True, capture_output=True, text=True)
78
+ new_version_cli = result_new.stdout.strip()
77
79
  print(f"📊 New version: {new_version_cli}")
78
80
 
79
81
  if old_version_cli == new_version_cli:
@@ -104,9 +106,16 @@ class Installer:
104
106
  program: str = runpy.run_path(str(installer_path), run_name=None)['main'](version=version)
105
107
  # print(program)
106
108
  print("🚀 Running installation script...")
107
- Terminal(stdin=None, stdout=None, stderr=None).run_script(script=program, shell="default").print(desc="Running custom installer", capture=True)
108
- # import subprocess
109
- # subprocess.run(program, shell=True, check=True)
109
+ if platform.system() == "Linux": script = "#!/bin/bash" + "\n" + program
110
+ else: script = program
111
+ script_file = PathExtended.tmpfile(name="tmp_shell_script", suffix=".ps1" if platform.system() == "Windows" else ".sh", folder="tmp_scripts").write_text(script, newline=None if platform.system() == "Windows" else "\n")
112
+ if platform.system() == "Windows":
113
+ start_cmd = "powershell"
114
+ full_command = f"{start_cmd} {script_file}"
115
+ else:
116
+ start_cmd = "bash"
117
+ full_command = f"{start_cmd} {script_file}"
118
+ subprocess.run(full_command, stdin=None, stdout=None, stderr=None, shell=True, text=True)
110
119
  version_to_be_installed = str(version)
111
120
  print(f"✅ Custom installation completed\n{'='*80}")
112
121
 
@@ -116,7 +125,15 @@ class Installer:
116
125
  desc = package_manager + " installation"
117
126
  version_to_be_installed = package_manager + "Latest"
118
127
  print(f"🚀 Running: {self.repo_url}")
119
- Terminal().run(self.repo_url, shell="default").capture().print_if_unsuccessful(desc=desc, strict_err=True, strict_returncode=True)
128
+ result = subprocess.run(self.repo_url, shell=True, capture_output=True, text=True)
129
+ success = result.returncode == 0 and result.stderr == ""
130
+ if not success:
131
+ print(f"❌ {desc} failed")
132
+ if result.stdout:
133
+ print(f"STDOUT: {result.stdout}")
134
+ if result.stderr:
135
+ print(f"STDERR: {result.stderr}")
136
+ print(f"Return code: {result.returncode}")
120
137
  print(f"✅ Package manager installation completed\n{'='*80}")
121
138
 
122
139
  else:
@@ -125,7 +142,16 @@ class Installer:
125
142
  if str(downloaded).endswith(".deb"):
126
143
  print(f"đŸ“Ļ Installing .deb package: {downloaded}")
127
144
  assert platform.system() == "Linux"
128
- Terminal().run(f"sudo nala install -y {downloaded}").capture().print_if_unsuccessful(desc="Installing .deb", strict_err=True, strict_returncode=True)
145
+ result = subprocess.run(f"sudo nala install -y {downloaded}", shell=True, capture_output=True, text=True)
146
+ success = result.returncode == 0 and result.stderr == ""
147
+ if not success:
148
+ desc = "Installing .deb"
149
+ print(f"❌ {desc} failed")
150
+ if result.stdout:
151
+ print(f"STDOUT: {result.stdout}")
152
+ if result.stderr:
153
+ print(f"STDERR: {result.stderr}")
154
+ print(f"Return code: {result.returncode}")
129
155
  print("đŸ—‘ī¸ Cleaning up .deb package...")
130
156
  downloaded.delete(sure=True)
131
157
  print(f"✅ DEB package installation completed\n{'='*80}")
@@ -154,7 +180,7 @@ class Installer:
154
180
 
155
181
  print(f"💾 Saving version information to: {INSTALL_VERSION_ROOT.joinpath(self.exe_name)}")
156
182
  INSTALL_VERSION_ROOT.joinpath(self.exe_name).parent.mkdir(parents=True, exist_ok=True)
157
- INSTALL_VERSION_ROOT.joinpath(self.exe_name).write_text(version_to_be_installed)
183
+ INSTALL_VERSION_ROOT.joinpath(self.exe_name).write_text(version_to_be_installed, encoding="utf-8")
158
184
  print(f"✅ Installation completed successfully!\n{'='*80}")
159
185
 
160
186
  def download(self, version: Optional[str]):
@@ -240,19 +266,19 @@ class Installer:
240
266
  if use_cache:
241
267
  print("đŸ—‚ī¸ Using cached version information...")
242
268
  if tmp_path.exists():
243
- existing_version = tmp_path.read_text().rstrip()
269
+ existing_version = tmp_path.read_text(encoding="utf-8").rstrip()
244
270
  print(f"📄 Found cached version: {existing_version}")
245
271
  else:
246
272
  existing_version = None
247
273
  print("â„šī¸ No cached version information found")
248
274
  else:
249
275
  print("🔍 Checking installed version directly...")
250
- resp = Terminal().run(exe_name, "--version", check=False).capture()
251
- if resp.op == '':
276
+ result = subprocess.run([exe_name, "--version"], check=False, capture_output=True, text=True)
277
+ if result.stdout.strip() == '':
252
278
  existing_version = None
253
279
  print("â„šī¸ Could not detect installed version")
254
280
  else:
255
- existing_version = resp.op.strip()
281
+ existing_version = result.stdout.strip()
256
282
  print(f"📄 Detected installed version: {existing_version}")
257
283
 
258
284
  if existing_version is not None:
@@ -262,11 +288,11 @@ class Installer:
262
288
  return ("✅ Uptodate", version.strip(), version_to_be_installed.strip())
263
289
  else:
264
290
  print(f"🔄 {exe_name} needs update: {existing_version.rstrip()} → {version_to_be_installed}")
265
- tmp_path.write_text(version_to_be_installed)
291
+ tmp_path.write_text(version_to_be_installed, encoding="utf-8")
266
292
  return ("❌ Outdated", existing_version.strip(), version_to_be_installed.strip())
267
293
  else:
268
294
  print(f"đŸ“Ļ {exe_name} is not installed. Will install version: {version_to_be_installed}")
269
- tmp_path.write_text(version_to_be_installed)
295
+ tmp_path.write_text(version_to_be_installed, encoding="utf-8")
270
296
 
271
297
  print(f"{'='*80}")
272
- return ("âš ī¸ NotInstalled", "None", version_to_be_installed.strip())
298
+ return ("âš ī¸ NotInstalled", "None", version_to_be_installed.strip())
@@ -5,16 +5,8 @@ from pathlib import Path
5
5
  import json
6
6
  import pickle
7
7
  import configparser
8
-
9
- try:
10
- import toml # type: ignore
11
- except Exception: # pragma: no cover
12
- toml = None # type: ignore
13
-
14
- try:
15
- import yaml # type: ignore
16
- except Exception: # pragma: no cover
17
- yaml = None # type: ignore
8
+ import toml
9
+ import yaml
18
10
 
19
11
 
20
12
  PathLike = Union[str, Path]
@@ -46,8 +38,6 @@ def save_json(obj: Any, path: PathLike, indent: Optional[int] = None, verbose: b
46
38
 
47
39
 
48
40
  def save_toml(obj: Mapping[str, Any], path: PathLike, verbose: bool = False) -> Path:
49
- if toml is None:
50
- raise RuntimeError("toml package is required to write TOML files")
51
41
  path_obj = _ensure_parent(path)
52
42
  with open(path_obj, "w", encoding="utf-8") as fh:
53
43
  toml.dump(obj, fh)
@@ -57,8 +47,6 @@ def save_toml(obj: Mapping[str, Any], path: PathLike, verbose: bool = False) ->
57
47
 
58
48
 
59
49
  def save_yaml(obj: Any, path: PathLike, verbose: bool = False) -> Path:
60
- if yaml is None:
61
- raise RuntimeError("PyYAML is required to write YAML files")
62
50
  path_obj = _ensure_parent(path)
63
51
  with open(path_obj, "w", encoding="utf-8") as fh:
64
52
  yaml.safe_dump(obj, fh, sort_keys=False)
@@ -80,7 +68,7 @@ def save_ini(path: PathLike, obj: Mapping[str, Mapping[str, Any]], verbose: bool
80
68
 
81
69
 
82
70
  class Save:
83
- """Drop-in replacement for crocodile's Save helper.
71
+ """
84
72
 
85
73
  Provides static methods for common serialization formats while ensuring
86
74
  parent directories exist and returning a `P` path object.
@@ -1,4 +1,4 @@
1
- from crocodile.meta import Terminal
1
+
2
2
  from pathlib import Path
3
3
  from rich.text import Text
4
4
  from rich.panel import Panel
@@ -27,7 +27,13 @@ def check_tool_exists(tool_name: str, install_script: Optional[str] = None) -> b
27
27
  if res is False and install_script is not None:
28
28
  console = Console()
29
29
  console.print(Panel(f"đŸ“Ĩ INSTALLING TOOL | Installing {tool_name}...", border_style="bold blue", expand=False))
30
- Terminal().run(install_script, shell="powershell").print()
30
+ result = subprocess.run(install_script, shell=True, capture_output=True, text=True)
31
+ print(f"Command: {install_script}")
32
+ if result.stdout:
33
+ print(f"STDOUT: {result.stdout}")
34
+ if result.stderr:
35
+ print(f"STDERR: {result.stderr}")
36
+ print(f"Return code: {result.returncode}")
31
37
  return check_tool_exists(tool_name=tool_name, install_script=None)
32
38
  return res
33
39
 
@@ -130,7 +136,8 @@ def display_options(msg: str, options: Iterable[T], header: str="", tail: str=""
130
136
  def choose_cloud_interactively() -> str:
131
137
  console = Console()
132
138
  console.print(Panel("🔍 LISTING CLOUD REMOTES | Fetching available cloud remotes...", border_style="bold blue", expand=False))
133
- tmp = Terminal().run("rclone listremotes").op_if_successfull_or_default(strict_returcode=False)
139
+ result = subprocess.run("rclone listremotes", shell=True, capture_output=True, text=True)
140
+ tmp = result.stdout if result.returncode == 0 else None
134
141
  if isinstance(tmp, str):
135
142
  remotes: list[str] = [x.replace(":", "") for x in tmp.splitlines()]
136
143
 
@@ -13,6 +13,11 @@ console = Console()
13
13
 
14
14
  def sanitize_path(a_path: PathExtended) -> PathExtended:
15
15
  path = PathExtended(a_path)
16
+ if Path.cwd() == Path.home() and not path.exists():
17
+ result = input("Current working directory is home, and passed path is not full path, are you sure you want to continue, [y]/n? ") or "y"
18
+ if result == "y":
19
+ import sys
20
+ sys.exit()
16
21
  if path.as_posix().startswith("/home") or path.as_posix().startswith("/Users"):
17
22
  if platform.system() == "Windows": # path copied from Linux/Mac to Windows
18
23
  # For Linux: /home/username, for Mac: /Users/username