machineconfig 4.97__py3-none-any.whl → 4.99__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 (55) hide show
  1. machineconfig/cluster/remote/script_execution.py +1 -1
  2. machineconfig/jobs/installer/custom/gh.py +68 -39
  3. machineconfig/jobs/installer/custom/hx.py +1 -1
  4. machineconfig/jobs/installer/custom_dev/bypass_paywall.py +1 -1
  5. machineconfig/jobs/installer/custom_dev/wezterm.py +68 -35
  6. machineconfig/jobs/installer/installer_data.json +1 -1
  7. machineconfig/jobs/installer/package_groups.py +2 -1
  8. machineconfig/jobs/python/python_ve_symlink.py +1 -1
  9. machineconfig/profile/create.py +59 -40
  10. machineconfig/profile/shell.py +1 -1
  11. machineconfig/scripts/python/cloud_copy.py +1 -1
  12. machineconfig/scripts/python/cloud_mount.py +1 -1
  13. machineconfig/scripts/python/cloud_repo_sync.py +1 -1
  14. machineconfig/scripts/python/croshell.py +1 -1
  15. machineconfig/scripts/python/devops.py +1 -1
  16. machineconfig/scripts/python/devops_add_identity.py +1 -1
  17. machineconfig/scripts/python/devops_add_ssh_key.py +1 -1
  18. machineconfig/scripts/python/devops_backup_retrieve.py +1 -1
  19. machineconfig/scripts/python/devops_update_repos.py +135 -65
  20. machineconfig/scripts/python/dotfile.py +41 -15
  21. machineconfig/scripts/python/fire_jobs.py +1 -1
  22. machineconfig/scripts/python/ftpx.py +101 -49
  23. machineconfig/scripts/python/helpers/helpers2.py +2 -2
  24. machineconfig/scripts/python/helpers/helpers4.py +1 -1
  25. machineconfig/scripts/python/helpers/repo_sync_helpers.py +1 -1
  26. machineconfig/scripts/python/interactive.py +1 -1
  27. machineconfig/scripts/python/mount_nfs.py +13 -7
  28. machineconfig/scripts/python/mount_ssh.py +1 -1
  29. machineconfig/scripts/python/repos.py +7 -6
  30. machineconfig/scripts/python/repos_helper_action.py +1 -1
  31. machineconfig/scripts/python/repos_helper_clone.py +4 -4
  32. machineconfig/scripts/python/repos_helper_record.py +1 -1
  33. machineconfig/scripts/python/sessions.py +5 -1
  34. machineconfig/scripts/python/share_terminal.py +14 -7
  35. machineconfig/scripts/python/start_slidev.py +1 -1
  36. machineconfig/scripts/python/wsl_windows_transfer.py +1 -1
  37. machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +1 -1
  38. machineconfig/utils/code.py +1 -1
  39. machineconfig/utils/installer.py +1 -1
  40. machineconfig/{scripts/python/devops_devapps_install.py → utils/installer_utils/installer.py} +2 -3
  41. machineconfig/utils/installer_utils/installer_abc.py +1 -1
  42. machineconfig/utils/installer_utils/installer_class.py +1 -1
  43. machineconfig/utils/links.py +1 -1
  44. machineconfig/utils/path_extended.py +4 -2
  45. machineconfig/utils/path_helper.py +1 -1
  46. machineconfig/utils/scheduler.py +1 -1
  47. {machineconfig-4.97.dist-info → machineconfig-4.99.dist-info}/METADATA +1 -1
  48. {machineconfig-4.97.dist-info → machineconfig-4.99.dist-info}/RECORD +54 -55
  49. machineconfig/cluster/templates/utils.py +0 -51
  50. /machineconfig/cluster/{templates → remote}/run_cloud.py +0 -0
  51. /machineconfig/cluster/{templates → remote}/run_cluster.py +0 -0
  52. /machineconfig/cluster/{templates → remote}/run_remote.py +0 -0
  53. {machineconfig-4.97.dist-info → machineconfig-4.99.dist-info}/WHEEL +0 -0
  54. {machineconfig-4.97.dist-info → machineconfig-4.99.dist-info}/entry_points.txt +0 -0
  55. {machineconfig-4.97.dist-info → machineconfig-4.99.dist-info}/top_level.txt +0 -0
@@ -1,20 +1,26 @@
1
1
  """Update repositories with fancy output"""
2
2
 
3
- import git
4
3
  from pathlib import Path
4
+
5
+ import git
6
+ from rich.console import Console
7
+ from rich.panel import Panel
8
+ from rich.table import Table
9
+ from rich.text import Text
10
+
5
11
  from machineconfig.scripts.python.repos_helper_update import RepositoryUpdateResult, run_uv_sync, update_repository
6
- from machineconfig.utils.path_extended import PathExtended as PathExtended
7
- from machineconfig.utils.source_of_truth import DEFAULTS_PATH
8
12
  from machineconfig.utils.io import read_ini
13
+ from machineconfig.utils.source_of_truth import DEFAULTS_PATH
14
+
15
+
16
+ console = Console()
9
17
 
10
18
 
11
19
  def _display_summary(results: list[RepositoryUpdateResult]) -> None:
12
20
  """Display a comprehensive summary of all repository update operations."""
13
- print("\n" + "=" * 80)
14
- print("📊 REPOSITORY UPDATE SUMMARY")
15
- print("=" * 80)
16
21
 
17
- # Calculate statistics
22
+ console.rule("[bold blue]📊 Repository Update Summary[/bold blue]")
23
+
18
24
  total_repos = len(results)
19
25
  successful_repos = sum(1 for r in results if r["status"] == "success")
20
26
  error_repos = sum(1 for r in results if r["status"] == "error")
@@ -27,106 +33,161 @@ def _display_summary(results: list[RepositoryUpdateResult]) -> None:
27
33
  uv_sync_runs = sum(1 for r in results if r["uv_sync_ran"])
28
34
  uv_sync_successes = sum(1 for r in results if r["uv_sync_ran"] and r["uv_sync_success"])
29
35
 
30
- # Overview statistics
31
- print("📈 OVERVIEW:")
32
- print(f" Total repositories processed: {total_repos}")
33
- print(f" Successful updates: {successful_repos}")
34
- print(f" ❌ Failed updates: {error_repos}")
35
- print(f" ⏭️ Skipped: {skipped_repos}")
36
+ overview_lines = [
37
+ f"[bold]Total repositories processed:[/] {total_repos}",
38
+ f" Successful updates: {successful_repos}",
39
+ f" Failed updates: {error_repos}",
40
+ f"⏭️ Skipped: {skipped_repos}",
41
+ ]
36
42
  if auth_failed_repos > 0:
37
- print(f" 🔐 Authentication failed: {auth_failed_repos}")
38
- print()
39
-
40
- print("🔄 CHANGES:")
41
- print(f" Repositories with new commits: {repos_with_changes}")
42
- print(f" Repositories with dependency changes: {repos_with_dep_changes}")
43
- print(f" Repositories with uncommitted changes: {repos_with_uncommitted}")
44
- print()
45
-
46
- print("📦 UV SYNC:")
47
- print(f" uv sync operations attempted: {uv_sync_runs}")
48
- print(f" uv sync operations successful: {uv_sync_successes}")
43
+ overview_lines.append(f"🔐 Authentication failed: {auth_failed_repos}")
44
+
45
+ console.print(
46
+ Panel(
47
+ "\n".join(overview_lines),
48
+ title=" Overview",
49
+ border_style="blue",
50
+ padding=(1, 2),
51
+ )
52
+ )
53
+
54
+ changes_lines = [
55
+ f"Repositories with new commits: {repos_with_changes}",
56
+ f"Repositories with dependency changes: {repos_with_dep_changes}",
57
+ f"Repositories with uncommitted changes: {repos_with_uncommitted}",
58
+ ]
59
+ console.print(
60
+ Panel(
61
+ "\n".join(changes_lines),
62
+ title="� Changes",
63
+ border_style="magenta",
64
+ padding=(1, 2),
65
+ )
66
+ )
67
+
68
+ uv_sync_lines = [
69
+ f"uv sync operations attempted: {uv_sync_runs}",
70
+ f"uv sync operations successful: {uv_sync_successes}",
71
+ ]
49
72
  if uv_sync_runs > uv_sync_successes:
50
- print(f" uv sync operations failed: {uv_sync_runs - uv_sync_successes}")
51
- print()
73
+ uv_sync_lines.append(f"uv sync operations failed: {uv_sync_runs - uv_sync_successes}")
74
+
75
+ console.print(
76
+ Panel(
77
+ "\n".join(uv_sync_lines),
78
+ title="📦 uv sync",
79
+ border_style="cyan",
80
+ padding=(1, 2),
81
+ )
82
+ )
83
+
84
+ table = Table(title="📋 Detailed Results", show_lines=True, header_style="bold blue")
85
+ table.add_column("Repository", style="bold")
86
+ table.add_column("Status")
87
+ table.add_column("Details", overflow="fold")
52
88
 
53
- # Detailed results per repository
54
- print("📋 DETAILED RESULTS:")
55
89
  for result in results:
56
90
  repo_name = Path(result["repo_path"]).name
57
91
  status_icon = {"success": "✅", "error": "❌", "skipped": "⏭️", "auth_failed": "🔐"}.get(result["status"], "❓")
58
- print(f" {status_icon} {repo_name}")
92
+ status_label = result["status"].replace("_", " ").title()
93
+
94
+ detail_lines: list[str] = []
59
95
 
60
96
  if result["status"] == "error" and result["error_message"]:
61
- print(f" 💥 Error: {result['error_message']}")
97
+ detail_lines.append(f"💥 Error: {result['error_message']}")
62
98
 
63
99
  if result["commits_changed"]:
64
- print(f" 🔄 Updated: {result['commit_before'][:8]} → {result['commit_after'][:8]}")
100
+ detail_lines.append(f"🔄 Updated: {result['commit_before'][:8]} → {result['commit_after'][:8]}")
65
101
  elif result["status"] == "success":
66
- print(" 📍 Already up to date")
102
+ detail_lines.append("📍 Already up to date")
67
103
 
68
104
  if result["had_uncommitted_changes"]:
69
105
  files_str = ", ".join(result["uncommitted_files"])
70
- print(f" ⚠️ Had uncommitted changes: {files_str}")
106
+ detail_lines.append(f"⚠️ Uncommitted changes: {files_str}")
71
107
 
72
108
  if result["dependencies_changed"]:
73
109
  changes = []
74
110
  if result["pyproject_changed"]:
75
111
  changes.append("pyproject.toml")
76
- print(f" 📋 Dependencies changed: {', '.join(changes)}")
112
+ if changes:
113
+ detail_lines.append(f"📋 Dependencies changed: {', '.join(changes)}")
77
114
 
78
115
  if result["uv_sync_ran"]:
79
116
  sync_status = "✅" if result["uv_sync_success"] else "❌"
80
- print(f" 📦 uv sync: {sync_status}")
117
+ detail_lines.append(f"📦 uv sync: {sync_status}")
81
118
 
82
119
  if result["is_machineconfig_repo"] and result["permissions_updated"]:
83
- print(" 🛠 Updated permissions for machineconfig files")
120
+ detail_lines.append("🛠 Updated permissions for machineconfig files")
84
121
 
85
122
  if result["remotes_processed"]:
86
- print(f" 📡 Processed remotes: {', '.join(result['remotes_processed'])}")
123
+ detail_lines.append(f"📡 Processed remotes: {', '.join(result['remotes_processed'])}")
87
124
  if result["remotes_skipped"]:
88
- print(f" ⏭️ Skipped remotes: {', '.join(result['remotes_skipped'])}")
125
+ detail_lines.append(f"⏭️ Skipped remotes: {', '.join(result['remotes_skipped'])}")
126
+
127
+ table.add_row(f"{status_icon} {repo_name}", status_label, "\n".join(detail_lines) or "—")
89
128
 
90
- print("\n" + "=" * 80)
129
+ console.print(table)
91
130
 
92
- # Final status
93
131
  if error_repos == 0 and auth_failed_repos == 0:
94
- print("🎉 All repositories processed successfully!")
132
+ summary_text = Text("🎉 All repositories processed successfully!", style="green", justify="center")
133
+ border = "green"
95
134
  elif successful_repos > 0:
96
- print(f"⚠️ {successful_repos}/{total_repos} repositories processed successfully")
135
+ summary_text = Text(
136
+ f"⚠️ {successful_repos}/{total_repos} repositories processed successfully",
137
+ style="yellow",
138
+ justify="center",
139
+ )
140
+ border = "yellow"
97
141
  else:
98
- print("❌ No repositories were successfully processed")
99
- print("=" * 80)
142
+ summary_text = Text("❌ No repositories were successfully processed", style="red", justify="center")
143
+ border = "red"
144
+
145
+ console.print(Panel(summary_text, title="Summary", border_style=border, padding=(1, 2)))
100
146
 
101
147
 
102
148
  def main(verbose: bool = True, allow_password_prompt: bool = False) -> None:
103
149
  """Main function to update all configured repositories."""
104
150
  _ = verbose
105
- repos: list[PathExtended] = [PathExtended.home() / "code/machineconfig", PathExtended.home() / "code/crocodile"]
151
+ repos: list[Path] = [Path.home() / "code/machineconfig", Path.home() / "code/crocodile"]
106
152
  try:
107
153
  tmp = read_ini(DEFAULTS_PATH)["general"]["repos"].split(",")
108
154
  if tmp[-1] == "":
109
155
  tmp = tmp[:-1]
110
156
  for item in tmp:
111
- item_obj = PathExtended(item).expanduser()
157
+ item_obj = Path(item).expanduser()
112
158
  if item_obj not in repos:
113
159
  repos.append(item_obj)
114
160
  except (FileNotFoundError, KeyError, IndexError):
115
- print(f"""
116
- ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
117
- ┃ 🚫 Configuration Error: Missing {DEFAULTS_PATH} or section [general] or key repos
118
- ┃ ℹ️ Using default repositories instead
119
- ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━""")
120
- print("""
121
- ┌────────────────────────────────────────────────────────────────
122
- │ ✨ Example Configuration:
123
-
124
- │ [general]
125
- │ repos = ~/code/repo1,~/code/repo2
126
- │ rclone_config_name = onedrivePersonal
127
- │ email_config_name = Yahoo3
128
- │ to_email = myemail@email.com
129
- └────────────────────────────────────────────────────────────────""")
161
+ console.print(
162
+ Panel(
163
+ "\n".join(
164
+ [
165
+ f"🚫 Configuration error: missing {DEFAULTS_PATH} or the [general] section / repos key.",
166
+ "ℹ️ Using default repositories instead.",
167
+ ]
168
+ ),
169
+ title="Configuration Missing",
170
+ border_style="red",
171
+ padding=(1, 2),
172
+ )
173
+ )
174
+ console.print(
175
+ Panel(
176
+ "\n".join(
177
+ [
178
+ "✨ Example configuration:",
179
+ "",
180
+ "[general]",
181
+ "repos = ~/code/repo1,~/code/repo2",
182
+ "rclone_config_name = onedrivePersonal",
183
+ "email_config_name = Yahoo3",
184
+ "to_email = myemail@email.com",
185
+ ]
186
+ ),
187
+ border_style="cyan",
188
+ padding=(1, 2),
189
+ )
190
+ )
130
191
 
131
192
  # Process repositories
132
193
  results: list[RepositoryUpdateResult] = []
@@ -164,9 +225,18 @@ def main(verbose: bool = True, allow_password_prompt: bool = False) -> None:
164
225
  "permissions_updated": False,
165
226
  }
166
227
  results.append(error_result)
167
- print(f"""❌ Repository Error: Path: {expanded_path}
168
- Exception: {ex}
169
- {"-" * 50}""")
228
+ console.print(
229
+ Panel(
230
+ "\n".join(
231
+ [
232
+ f"❌ Repository error: {expanded_path}",
233
+ f"Exception: {ex}",
234
+ ]
235
+ ),
236
+ border_style="red",
237
+ padding=(1, 2),
238
+ )
239
+ )
170
240
 
171
241
  # Run uv sync for repositories where pyproject.toml changed but sync wasn't run yet
172
242
  for repo_path in repos_with_changes:
@@ -1,10 +1,17 @@
1
1
  """Like yadm and dotter."""
2
2
 
3
- from machineconfig.utils.path_extended import PathExtended as PathExtended
4
- from machineconfig.utils.links import symlink_func
5
- from machineconfig.utils.source_of_truth import LIBRARY_ROOT, REPO_ROOT
6
3
  from typing import Annotated
4
+
7
5
  import typer
6
+ from rich.console import Console
7
+ from rich.panel import Panel
8
+
9
+ from machineconfig.utils.links import symlink_func
10
+ from machineconfig.utils.path_extended import PathExtended
11
+ from machineconfig.utils.source_of_truth import LIBRARY_ROOT, REPO_ROOT
12
+
13
+
14
+ console = Console()
8
15
 
9
16
 
10
17
  def main(
@@ -30,18 +37,37 @@ def main(
30
37
 
31
38
  symlink_func(this=orig_path, to_this=new_path, prioritize_to_this=overwrite)
32
39
 
33
- print("""
34
- ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
35
- ┃ ✅ Symbolic Link Created Successfully
36
-
37
- 🔄 To enshrine this mapping, add the following to mapper.toml:
38
- ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━""")
39
- print(f"""
40
- 📝 Edit configuration file: nano {PathExtended(LIBRARY_ROOT)}/symlinks/mapper.toml
41
-
42
- [{new_path.parent.name}]
43
- {orig_path.name.split(".")[0]} = {{ this = '{orig_path.collapseuser().as_posix()}', to_this = '{new_path.collapseuser().as_posix()}' }}
44
- """)
40
+ console.print(
41
+ Panel(
42
+ "\n".join(
43
+ [
44
+ "✅ Symbolic link created successfully!",
45
+ "🔄 Add the following snippet to mapper.toml to persist this mapping:",
46
+ ]
47
+ ),
48
+ title="Symlink Created",
49
+ border_style="green",
50
+ padding=(1, 2),
51
+ )
52
+ )
53
+
54
+ mapper_snippet = "\n".join(
55
+ [
56
+ f"[bold]📝 Edit configuration file:[/] [cyan]nano {PathExtended(LIBRARY_ROOT)}/symlinks/mapper.toml[/cyan]",
57
+ "",
58
+ f"[{new_path.parent.name}]",
59
+ f"{orig_path.name.split('.')[0]} = {{ this = '{orig_path.collapseuser().as_posix()}', to_this = '{new_path.collapseuser().as_posix()}' }}",
60
+ ]
61
+ )
62
+
63
+ console.print(
64
+ Panel(
65
+ mapper_snippet,
66
+ title="Mapper Entry",
67
+ border_style="cyan",
68
+ padding=(1, 2),
69
+ )
70
+ )
45
71
 
46
72
 
47
73
  def arg_parser() -> None:
@@ -15,7 +15,7 @@ from machineconfig.utils.ve import get_ve_activate_line, get_ve_path_and_ipython
15
15
  from machineconfig.utils.options import choose_from_options
16
16
  from machineconfig.utils.path_helper import match_file_name, sanitize_path
17
17
 
18
- from machineconfig.utils.path_extended import PathExtended as PathExtended
18
+ from machineconfig.utils.path_extended import PathExtended
19
19
  from machineconfig.utils.accessories import get_repo_root, randstr
20
20
  from machineconfig.scripts.python.fire_jobs_args_helper import FireJobArgs, extract_kwargs, parse_fire_args_from_context
21
21
  import platform
@@ -8,12 +8,18 @@ Currently, the only way to work around this is to predifine the host in ~/.ssh/c
8
8
 
9
9
  import typer
10
10
  from typing_extensions import Annotated
11
+ from rich.console import Console
12
+ from rich.panel import Panel
13
+
11
14
  from machineconfig.utils.ssh import SSH
12
- from machineconfig.utils.path_extended import PathExtended as PathExtended
15
+ from machineconfig.utils.path_extended import PathExtended
13
16
  from machineconfig.scripts.python.helpers.helpers2 import ES
14
17
  from machineconfig.utils.accessories import pprint
15
18
 
16
19
 
20
+ console = Console()
21
+
22
+
17
23
  def main(
18
24
  source: Annotated[str, typer.Argument(help="Source path (machine:path)")],
19
25
  target: Annotated[str, typer.Argument(help="Target path (machine:path)")],
@@ -21,11 +27,19 @@ def main(
21
27
  zipFirst: Annotated[bool, typer.Option("--zipFirst", "-z", help="Zip before sending.")] = False,
22
28
  cloud: Annotated[bool, typer.Option("--cloud", "-c", help="Transfer through the cloud.")] = False,
23
29
  ) -> None:
24
- print("""
25
- ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
26
- ┃ 🚀 FTP File Transfer
27
- ┃ 📋 Starting transfer process...
28
- ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━""")
30
+ console.print(
31
+ Panel(
32
+ "\n".join(
33
+ [
34
+ "🚀 FTP File Transfer",
35
+ "📋 Starting transfer process...",
36
+ ]
37
+ ),
38
+ title="Transfer Initialisation",
39
+ border_style="blue",
40
+ padding=(1, 2),
41
+ )
42
+ )
29
43
 
30
44
  # Initialize variables
31
45
  resolved_source: str | None = None
@@ -94,69 +108,107 @@ def main(
94
108
  try:
95
109
  ssh = SSH(rf"{machine}")
96
110
  except AuthenticationException:
97
- print("""
98
- ┌────────────────────────────────────────────────────────────────
99
- │ 🔑 Authentication Failed
100
- │ Trying manual authentication...
101
-
102
- ⚠️ Caution: Ensure that username is passed appropriately
103
- │ This exception only handles password authentication
104
- └────────────────────────────────────────────────────────────────""")
111
+ console.print(
112
+ Panel(
113
+ "\n".join(
114
+ [
115
+ "🔑 Authentication failed. Trying manual authentication...",
116
+ "⚠️ Ensure that the username is provided correctly; only password prompts are handled here.",
117
+ ]
118
+ ),
119
+ title="Authentication Required",
120
+ border_style="yellow",
121
+ padding=(1, 2),
122
+ )
123
+ )
105
124
  import getpass
106
125
 
107
126
  pwd = getpass.getpass()
108
127
  ssh = SSH(rf"{machine}", pwd=pwd)
109
128
 
110
129
  if cloud:
111
- print("""
112
- ┌────────────────────────────────────────────────────────────────
113
- ☁️ Cloud Transfer Mode
114
- │ Uploading from remote to cloud...
115
- └────────────────────────────────────────────────────────────────""")
130
+ console.print(
131
+ Panel.fit(
132
+ "☁️ Cloud transfer mode — uploading from remote to cloud...",
133
+ title="Cloud Upload",
134
+ border_style="cyan",
135
+ )
136
+ )
116
137
  ssh.run(f"cloud_copy {resolved_source} :^", desc="Uploading from remote to the cloud.").print()
117
- print("""
118
- ┌────────────────────────────────────────────────────────────────
119
- ⬇️ Cloud Transfer Mode
120
- │ Downloading from cloud to local...
121
- └────────────────────────────────────────────────────────────────""")
138
+ console.print(
139
+ Panel.fit(
140
+ "⬇️ Cloud transfer mode — downloading from cloud to local...",
141
+ title="Cloud Download",
142
+ border_style="cyan",
143
+ )
144
+ )
122
145
  ssh.run_locally(f"cloud_copy :^ {resolved_target}").print()
123
146
  received_file = PathExtended(resolved_target) # type: ignore
124
147
  else:
125
148
  if source_is_remote:
126
149
  assert resolved_source is not None, """
127
150
  ❌ Path Error: Source must be a remote path (machine:path)"""
128
- print(f"""
129
- ┌────────────────────────────────────────────────────────────────
130
- │ 📥 Transfer Mode: Remote → Local
131
- │ Source: {resolved_source}
132
- │ Target: {resolved_target}
133
- │ Options: {"ZIP compression" if zipFirst else "No compression"}, {"Recursive" if recursive else "Non-recursive"}
134
- └────────────────────────────────────────────────────────────────""")
151
+ target_display = resolved_target or "<auto>"
152
+ console.print(
153
+ Panel(
154
+ "\n".join(
155
+ [
156
+ "📥 Transfer Mode: Remote Local",
157
+ f"Source: [cyan]{resolved_source}[/cyan]",
158
+ f"Target: [cyan]{target_display}[/cyan]",
159
+ f"Options: {'ZIP compression' if zipFirst else 'No compression'}, {'Recursive' if recursive else 'Non-recursive'}",
160
+ ]
161
+ ),
162
+ title="Transfer Details",
163
+ border_style="cyan",
164
+ padding=(1, 2),
165
+ )
166
+ )
135
167
  received_file = ssh.copy_to_here(source=resolved_source, target=resolved_target, z=zipFirst, r=recursive)
136
168
  else:
137
169
  assert resolved_source is not None, """
138
170
  ❌ Path Error: Target must be a remote path (machine:path)"""
139
- print(f"""
140
- ┌────────────────────────────────────────────────────────────────
141
- │ 📤 Transfer Mode: Local → Remote
142
- │ Source: {resolved_source}
143
- │ Target: {resolved_target}
144
- │ Options: {"ZIP compression" if zipFirst else "No compression"}, {"Recursive" if recursive else "Non-recursive"}
145
- └────────────────────────────────────────────────────────────────""")
171
+ target_display = resolved_target or "<auto>"
172
+ console.print(
173
+ Panel(
174
+ "\n".join(
175
+ [
176
+ "📤 Transfer Mode: Local Remote",
177
+ f"Source: [cyan]{resolved_source}[/cyan]",
178
+ f"Target: [cyan]{target_display}[/cyan]",
179
+ f"Options: {'ZIP compression' if zipFirst else 'No compression'}, {'Recursive' if recursive else 'Non-recursive'}",
180
+ ]
181
+ ),
182
+ title="Transfer Details",
183
+ border_style="cyan",
184
+ padding=(1, 2),
185
+ )
186
+ )
146
187
  received_file = ssh.copy_from_here(source=resolved_source, target=resolved_target, z=zipFirst, r=recursive)
147
188
 
148
189
  if source_is_remote and isinstance(received_file, PathExtended):
149
- print(f"""
150
- ┌────────────────────────────────────────────────────────────────
151
- │ 📁 File Received
152
- │ Parent: {repr(received_file.parent)}
153
- File: {repr(received_file)}
154
- └────────────────────────────────────────────────────────────────""")
155
- print("""
156
- ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
157
- ┃ ✅ Transfer Complete
158
- ┃ File transfer process finished successfully
159
- ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━""")
190
+ console.print(
191
+ Panel(
192
+ "\n".join(
193
+ [
194
+ "📁 File Received",
195
+ f"Parent: [cyan]{repr(received_file.parent)}[/cyan]",
196
+ f"File: [cyan]{repr(received_file)}[/cyan]",
197
+ ]
198
+ ),
199
+ title="Transfer Result",
200
+ border_style="green",
201
+ padding=(1, 2),
202
+ )
203
+ )
204
+ console.print(
205
+ Panel(
206
+ "File transfer process finished successfully",
207
+ title="✅ Transfer Complete",
208
+ border_style="green",
209
+ padding=(1, 2),
210
+ )
211
+ )
160
212
 
161
213
 
162
214
  def main_from_parser() -> None:
@@ -104,7 +104,7 @@ def parse_cloud_source_target(args: Args, source: str, target: str) -> tuple[str
104
104
  if len(source_parts) > 1 and source_parts[1] == ES: # the source path is to be inferred from target.
105
105
  assert ES not in target, f"You can't use expand symbol `{ES}` in both source and target. Cyclical inference dependency arised."
106
106
  target_obj = absolute(target)
107
- from machineconfig.utils.path_extended import PathExtended as PathExtended
107
+ from machineconfig.utils.path_extended import PathExtended
108
108
 
109
109
  remote_path = PathExtended(target_obj).get_remote_path(os_specific=os_specific, root=root, rel2home=rel2home, strict=False)
110
110
  source = f"{cloud}:{remote_path.as_posix()}"
@@ -124,7 +124,7 @@ def parse_cloud_source_target(args: Args, source: str, target: str) -> tuple[str
124
124
  if len(target_parts) > 1 and target_parts[1] == ES: # the target path is to be inferred from source.
125
125
  assert ES not in source, "You can't use $ in both source and target. Cyclical inference dependency arised."
126
126
  source_obj = absolute(source)
127
- from machineconfig.utils.path_extended import PathExtended as PathExtended
127
+ from machineconfig.utils.path_extended import PathExtended
128
128
 
129
129
  remote_path = PathExtended(source_obj).get_remote_path(os_specific=os_specific, root=root, rel2home=rel2home, strict=False)
130
130
  target = f"{cloud}:{remote_path.as_posix()}"
@@ -1,7 +1,7 @@
1
1
 
2
2
  from typing import Optional
3
3
  import os
4
- from machineconfig.utils.path_extended import PathExtended as PathExtended
4
+ from machineconfig.utils.path_extended import PathExtended
5
5
 
6
6
 
7
7
  def search_for_files_of_interest(path_obj: PathExtended):
@@ -1,4 +1,4 @@
1
- from machineconfig.utils.path_extended import PathExtended as PathExtended
1
+ from machineconfig.utils.path_extended import PathExtended
2
2
  from machineconfig.utils.terminal import Response
3
3
  from machineconfig.scripts.python.get_zellij_cmd import get_zellij_cmd
4
4
  from machineconfig.utils.source_of_truth import CONFIG_PATH, DEFAULTS_PATH
@@ -124,7 +124,7 @@ def execute_installations(selected_options: list[str]) -> None:
124
124
  console.print(Panel("⚡ [bold bright_yellow]CLI APPLICATIONS[/bold bright_yellow]\n[italic]Command-line tools installation[/italic]", border_style="bright_yellow"))
125
125
  console.print("🔧 Installing CLI applications", style="bold cyan")
126
126
  try:
127
- from machineconfig.scripts.python.devops_devapps_install import main as devops_devapps_install_main
127
+ from machineconfig.utils.installer_utils.installer import main as devops_devapps_install_main
128
128
  devops_devapps_install_main(group=maybe_a_group) # type: ignore
129
129
  console.print("✅ CLI applications installed successfully", style="bold green")
130
130
  except Exception as e:
@@ -1,6 +1,7 @@
1
1
  """NFS mounting script"""
2
2
 
3
- from machineconfig.utils.path_extended import PathExtended as PathExtended
3
+ from pathlib import Path
4
+
4
5
  from machineconfig.utils.ssh import SSH
5
6
  from machineconfig.utils.options import choose_from_options, choose_ssh_host
6
7
 
@@ -30,17 +31,22 @@ def main():
30
31
  print(f"📁 Share Path: {share_path}\n")
31
32
 
32
33
  if platform.system() in ["Linux", "Darwin"]:
33
- mount_path_1 = PathExtended(share_path)
34
- mount_path_2 = PathExtended.home().joinpath(f"data/mount_nfs/{remote_server}")
34
+ mount_path_1 = Path(share_path)
35
+ mount_path_2 = Path.home().joinpath("data/mount_nfs", remote_server)
35
36
  if str(mount_path_1).startswith("/home"):
36
- mount_path_3 = PathExtended.home().joinpath(*mount_path_1.parts[3:])
37
+ mount_path_3 = Path.home().joinpath(*mount_path_1.parts[3:])
37
38
  else:
38
39
  mount_path_3 = mount_path_2
39
40
 
40
41
  print("🔧 Preparing mount paths...")
41
- local_mount_point = choose_from_options(msg="📂 Choose mount path OR input custom one:", options=[mount_path_1, mount_path_2, mount_path_3], default=mount_path_2, custom_input=True, multi=False)
42
- assert isinstance(local_mount_point, PathExtended), f" local_mount_point must be a pathlib.Path. Got {type(local_mount_point)}"
43
- local_mount_point = PathExtended(local_mount_point).expanduser()
42
+ local_mount_point_choice = choose_from_options(
43
+ msg="📂 Choose mount path OR input custom one:",
44
+ options=[mount_path_1, mount_path_2, mount_path_3],
45
+ default=mount_path_2,
46
+ custom_input=True,
47
+ multi=False,
48
+ )
49
+ local_mount_point = Path(local_mount_point_choice).expanduser()
44
50
 
45
51
  txt = f"""
46
52
  share_info={share_info}
@@ -3,7 +3,7 @@
3
3
  from platform import system
4
4
  import subprocess
5
5
  from machineconfig.utils.ssh import SSH
6
- from machineconfig.utils.path_extended import PathExtended as PathExtended
6
+ from machineconfig.utils.path_extended import PathExtended
7
7
 
8
8
  from machineconfig.utils.options import choose_ssh_host
9
9