machineconfig 3.83__py3-none-any.whl → 3.86__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of machineconfig might be problematic. Click here for more details.
- machineconfig/cluster/sessions_managers/zellij_local.py +2 -2
- machineconfig/cluster/sessions_managers/zellij_remote.py +2 -2
- machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +2 -2
- machineconfig/jobs/python/vscode/api.py +8 -7
- machineconfig/scripts/python/ai/initai.py +1 -11
- machineconfig/scripts/python/cloud_copy.py +33 -27
- machineconfig/scripts/python/cloud_manager.py +0 -2
- machineconfig/scripts/python/cloud_mount.py +13 -10
- machineconfig/scripts/python/cloud_sync.py +30 -28
- machineconfig/scripts/python/croshell.py +46 -53
- machineconfig/scripts/python/dotfile.py +16 -16
- machineconfig/scripts/python/fire_agents.py +4 -5
- machineconfig/scripts/python/fire_jobs.py +30 -14
- machineconfig/scripts/python/fire_jobs_args_helper.py +43 -15
- machineconfig/scripts/python/fire_jobs_layout_helper.py +24 -16
- machineconfig/scripts/python/helpers/helpers4.py +0 -2
- machineconfig/scripts/python/repos.py +10 -88
- machineconfig/scripts/python/repos_helper_action.py +335 -0
- machineconfig/scripts/python/scheduler.py +0 -1
- machineconfig/scripts/python/share_terminal.py +41 -0
- machineconfig/scripts/python/start_slidev.py +15 -13
- machineconfig/scripts/python/start_terminals.py +19 -19
- machineconfig/scripts/python/t4.py +17 -0
- machineconfig/scripts/python/wifi_conn.py +16 -14
- machineconfig/scripts/python/wsl_windows_transfer.py +23 -29
- machineconfig/utils/accessories.py +45 -7
- machineconfig/utils/ai/generate_file_checklist.py +17 -17
- {machineconfig-3.83.dist-info → machineconfig-3.86.dist-info}/METADATA +1 -1
- {machineconfig-3.83.dist-info → machineconfig-3.86.dist-info}/RECORD +32 -32
- {machineconfig-3.83.dist-info → machineconfig-3.86.dist-info}/entry_points.txt +5 -5
- machineconfig/cluster/templates/cli_gooey.py +0 -115
- machineconfig/jobs/python/vscode/link_ve.py +0 -63
- machineconfig/jobs/python/vscode/select_interpreter.py +0 -87
- {machineconfig-3.83.dist-info → machineconfig-3.86.dist-info}/WHEEL +0 -0
- {machineconfig-3.83.dist-info → machineconfig-3.86.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
from machineconfig.utils.path_extended import PathExtended as PathExtended
|
|
2
|
+
from machineconfig.utils.accessories import randstr
|
|
3
|
+
from machineconfig.scripts.python.repos_helper_update import update_repository
|
|
4
|
+
|
|
5
|
+
from typing import Optional
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from enum import Enum
|
|
8
|
+
|
|
9
|
+
from rich import print as pprint
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class GitAction(Enum):
|
|
13
|
+
commit = "commit"
|
|
14
|
+
push = "push"
|
|
15
|
+
pull = "pull"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class GitOperationResult:
|
|
20
|
+
"""Result of a git operation on a single repository."""
|
|
21
|
+
repo_path: PathExtended
|
|
22
|
+
action: str
|
|
23
|
+
success: bool
|
|
24
|
+
message: str
|
|
25
|
+
is_git_repo: bool = True
|
|
26
|
+
had_changes: bool = False
|
|
27
|
+
remote_count: int = 0
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class GitOperationSummary:
|
|
32
|
+
"""Summary of all git operations performed."""
|
|
33
|
+
# Basic statistics
|
|
34
|
+
total_paths_processed: int = 0
|
|
35
|
+
git_repos_found: int = 0
|
|
36
|
+
non_git_paths: int = 0
|
|
37
|
+
|
|
38
|
+
# Per-operation statistics
|
|
39
|
+
commits_attempted: int = 0
|
|
40
|
+
commits_successful: int = 0
|
|
41
|
+
commits_no_changes: int = 0
|
|
42
|
+
commits_failed: int = 0
|
|
43
|
+
|
|
44
|
+
pulls_attempted: int = 0
|
|
45
|
+
pulls_successful: int = 0
|
|
46
|
+
pulls_failed: int = 0
|
|
47
|
+
|
|
48
|
+
pushes_attempted: int = 0
|
|
49
|
+
pushes_successful: int = 0
|
|
50
|
+
pushes_failed: int = 0
|
|
51
|
+
|
|
52
|
+
def __post_init__(self):
|
|
53
|
+
self.failed_operations: list[GitOperationResult] = []
|
|
54
|
+
self.repos_without_remotes: list[PathExtended] = []
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def git_action(path: PathExtended, action: GitAction, mess: Optional[str] = None, r: bool = False, auto_sync: bool = True) -> GitOperationResult:
|
|
58
|
+
"""Perform git actions using Python instead of shell scripts. Returns detailed operation result."""
|
|
59
|
+
from git.exc import InvalidGitRepositoryError
|
|
60
|
+
from git.repo import Repo
|
|
61
|
+
|
|
62
|
+
try:
|
|
63
|
+
repo = Repo(str(path), search_parent_directories=False)
|
|
64
|
+
except InvalidGitRepositoryError:
|
|
65
|
+
pprint(f"⚠️ Skipping {path} because it is not a git repository.")
|
|
66
|
+
if r:
|
|
67
|
+
results = [git_action(path=sub_path, action=action, mess=mess, r=r, auto_sync=auto_sync) for sub_path in path.search()]
|
|
68
|
+
# For recursive calls, we need to aggregate results somehow
|
|
69
|
+
# For now, return success if all recursive operations succeeded
|
|
70
|
+
all_successful = all(result.success for result in results)
|
|
71
|
+
return GitOperationResult(
|
|
72
|
+
repo_path=path,
|
|
73
|
+
action=action.value,
|
|
74
|
+
success=all_successful,
|
|
75
|
+
message=f"Recursive operation: {len([r for r in results if r.success])}/{len(results)} succeeded",
|
|
76
|
+
is_git_repo=False
|
|
77
|
+
)
|
|
78
|
+
else:
|
|
79
|
+
return GitOperationResult(
|
|
80
|
+
repo_path=path,
|
|
81
|
+
action=action.value,
|
|
82
|
+
success=False,
|
|
83
|
+
message="Not a git repository",
|
|
84
|
+
is_git_repo=False
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
print(f">>>>>>>>> 🔧{action} - {path}")
|
|
88
|
+
remote_count = len(repo.remotes)
|
|
89
|
+
|
|
90
|
+
try:
|
|
91
|
+
if action == GitAction.commit:
|
|
92
|
+
if mess is None:
|
|
93
|
+
mess = "auto_commit_" + randstr()
|
|
94
|
+
|
|
95
|
+
# Check if there are changes to commit
|
|
96
|
+
if repo.is_dirty() or repo.untracked_files:
|
|
97
|
+
repo.git.add(A=True) # Stage all changes
|
|
98
|
+
repo.index.commit(mess)
|
|
99
|
+
print(f"✅ Committed changes with message: {mess}")
|
|
100
|
+
return GitOperationResult(
|
|
101
|
+
repo_path=path,
|
|
102
|
+
action=action.value,
|
|
103
|
+
success=True,
|
|
104
|
+
message=f"Committed changes with message: {mess}",
|
|
105
|
+
had_changes=True,
|
|
106
|
+
remote_count=remote_count
|
|
107
|
+
)
|
|
108
|
+
else:
|
|
109
|
+
print("ℹ️ No changes to commit")
|
|
110
|
+
return GitOperationResult(
|
|
111
|
+
repo_path=path,
|
|
112
|
+
action=action.value,
|
|
113
|
+
success=True,
|
|
114
|
+
message="No changes to commit",
|
|
115
|
+
had_changes=False,
|
|
116
|
+
remote_count=remote_count
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
elif action == GitAction.push:
|
|
120
|
+
if not repo.remotes:
|
|
121
|
+
print("⚠️ No remotes configured for push")
|
|
122
|
+
return GitOperationResult(
|
|
123
|
+
repo_path=path,
|
|
124
|
+
action=action.value,
|
|
125
|
+
success=False,
|
|
126
|
+
message="No remotes configured",
|
|
127
|
+
remote_count=0
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
success = True
|
|
131
|
+
failed_remotes = []
|
|
132
|
+
for remote in repo.remotes:
|
|
133
|
+
try:
|
|
134
|
+
print(f"🚀 Pushing to {remote.url}")
|
|
135
|
+
remote.push(repo.active_branch.name)
|
|
136
|
+
print(f"✅ Pushed to {remote.name}")
|
|
137
|
+
except Exception as e:
|
|
138
|
+
print(f"❌ Failed to push to {remote.name}: {e}")
|
|
139
|
+
failed_remotes.append(f"{remote.name}: {str(e)}")
|
|
140
|
+
success = False
|
|
141
|
+
|
|
142
|
+
message = "Push successful" if success else f"Push failed for: {', '.join(failed_remotes)}"
|
|
143
|
+
return GitOperationResult(
|
|
144
|
+
repo_path=path,
|
|
145
|
+
action=action.value,
|
|
146
|
+
success=success,
|
|
147
|
+
message=message,
|
|
148
|
+
remote_count=remote_count
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
elif action == GitAction.pull:
|
|
152
|
+
# Use the enhanced update function with uv sync support
|
|
153
|
+
try:
|
|
154
|
+
update_repository(repo, auto_sync=auto_sync, allow_password_prompt=False)
|
|
155
|
+
print("✅ Pull completed")
|
|
156
|
+
return GitOperationResult(
|
|
157
|
+
repo_path=path,
|
|
158
|
+
action=action.value,
|
|
159
|
+
success=True,
|
|
160
|
+
message="Pull completed successfully",
|
|
161
|
+
remote_count=remote_count
|
|
162
|
+
)
|
|
163
|
+
except Exception as e:
|
|
164
|
+
print(f"❌ Pull failed: {e}")
|
|
165
|
+
return GitOperationResult(
|
|
166
|
+
repo_path=path,
|
|
167
|
+
action=action.value,
|
|
168
|
+
success=False,
|
|
169
|
+
message=f"Pull failed: {str(e)}",
|
|
170
|
+
remote_count=remote_count
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
except Exception as e:
|
|
174
|
+
print(f"❌ Error performing {action} on {path}: {e}")
|
|
175
|
+
return GitOperationResult(
|
|
176
|
+
repo_path=path,
|
|
177
|
+
action=action.value,
|
|
178
|
+
success=False,
|
|
179
|
+
message=f"Error: {str(e)}",
|
|
180
|
+
remote_count=remote_count
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
# This should never be reached, but just in case
|
|
184
|
+
return GitOperationResult(
|
|
185
|
+
repo_path=path,
|
|
186
|
+
action=action.value,
|
|
187
|
+
success=False,
|
|
188
|
+
message="Unknown error",
|
|
189
|
+
remote_count=remote_count
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def print_git_operations_summary(summary: GitOperationSummary, operations_performed: list[str]) -> None:
|
|
194
|
+
"""Print a detailed summary of git operations similar to repos_helper_record.py."""
|
|
195
|
+
print("\n📊 Git Operations Summary:")
|
|
196
|
+
print(f" Total paths processed: {summary.total_paths_processed}")
|
|
197
|
+
print(f" Git repositories found: {summary.git_repos_found}")
|
|
198
|
+
print(f" Non-git paths skipped: {summary.non_git_paths}")
|
|
199
|
+
|
|
200
|
+
# Show per-operation statistics
|
|
201
|
+
if "commit" in operations_performed:
|
|
202
|
+
print("\n💾 Commit Operations:")
|
|
203
|
+
print(f" Attempted: {summary.commits_attempted}")
|
|
204
|
+
print(f" Successful: {summary.commits_successful}")
|
|
205
|
+
print(f" No changes: {summary.commits_no_changes}")
|
|
206
|
+
print(f" Failed: {summary.commits_failed}")
|
|
207
|
+
|
|
208
|
+
if "pull" in operations_performed:
|
|
209
|
+
print("\n⬇️ Pull Operations:")
|
|
210
|
+
print(f" Attempted: {summary.pulls_attempted}")
|
|
211
|
+
print(f" Successful: {summary.pulls_successful}")
|
|
212
|
+
print(f" Failed: {summary.pulls_failed}")
|
|
213
|
+
|
|
214
|
+
if "push" in operations_performed:
|
|
215
|
+
print("\n🚀 Push Operations:")
|
|
216
|
+
print(f" Attempted: {summary.pushes_attempted}")
|
|
217
|
+
print(f" Successful: {summary.pushes_successful}")
|
|
218
|
+
print(f" Failed: {summary.pushes_failed}")
|
|
219
|
+
|
|
220
|
+
# Show repositories without remotes (important for push operations)
|
|
221
|
+
if summary.repos_without_remotes:
|
|
222
|
+
print(f"\n⚠️ WARNING: {len(summary.repos_without_remotes)} repositories have no remote configurations:")
|
|
223
|
+
for repo_path in summary.repos_without_remotes:
|
|
224
|
+
print(f" • {repo_path.name} ({repo_path})")
|
|
225
|
+
print(" These repositories cannot be pushed to remote servers.")
|
|
226
|
+
else:
|
|
227
|
+
if "push" in operations_performed:
|
|
228
|
+
print("\n✅ All repositories have remote configurations.")
|
|
229
|
+
|
|
230
|
+
# Show failed operations
|
|
231
|
+
if summary.failed_operations:
|
|
232
|
+
print(f"\n❌ FAILED OPERATIONS ({len(summary.failed_operations)} total):")
|
|
233
|
+
|
|
234
|
+
# Group failed operations by type
|
|
235
|
+
failed_by_action = {}
|
|
236
|
+
for failed_op in summary.failed_operations:
|
|
237
|
+
if failed_op.action not in failed_by_action:
|
|
238
|
+
failed_by_action[failed_op.action] = []
|
|
239
|
+
failed_by_action[failed_op.action].append(failed_op)
|
|
240
|
+
|
|
241
|
+
for action, failures in failed_by_action.items():
|
|
242
|
+
print(f"\n {action.upper()} failures ({len(failures)}):")
|
|
243
|
+
for failure in failures:
|
|
244
|
+
if not failure.is_git_repo:
|
|
245
|
+
print(f" • {failure.repo_path.name} ({failure.repo_path}) - Not a git repository")
|
|
246
|
+
else:
|
|
247
|
+
print(f" • {failure.repo_path.name} ({failure.repo_path}) - {failure.message}")
|
|
248
|
+
else:
|
|
249
|
+
print("\n✅ All git operations completed successfully!")
|
|
250
|
+
|
|
251
|
+
# Overall success assessment
|
|
252
|
+
total_failed = len(summary.failed_operations)
|
|
253
|
+
total_operations = (summary.commits_attempted + summary.pulls_attempted +
|
|
254
|
+
summary.pushes_attempted)
|
|
255
|
+
|
|
256
|
+
if total_failed == 0 and total_operations > 0:
|
|
257
|
+
print(f"\n🎉 SUCCESS: All {total_operations} operations completed successfully!")
|
|
258
|
+
elif total_operations == 0:
|
|
259
|
+
print("\n📝 No git operations were performed.")
|
|
260
|
+
else:
|
|
261
|
+
success_rate = ((total_operations - total_failed) / total_operations * 100) if total_operations > 0 else 0
|
|
262
|
+
print(f"\n⚖️ SUMMARY: {total_operations - total_failed}/{total_operations} operations succeeded ({success_rate:.1f}% success rate)")
|
|
263
|
+
if total_failed > 0:
|
|
264
|
+
print(" Review the failed operations above for details on what needs attention.")
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def perform_git_operations(repos_root: PathExtended, pull: bool, commit: bool, push: bool, recursive: bool, auto_sync: bool) -> None:
|
|
268
|
+
"""Perform git operations on all repositories and provide detailed summary."""
|
|
269
|
+
print(f"\n🔄 Performing Git actions on repositories @ `{repos_root}`...")
|
|
270
|
+
|
|
271
|
+
# Initialize summary tracking
|
|
272
|
+
summary = GitOperationSummary()
|
|
273
|
+
operations_performed = []
|
|
274
|
+
|
|
275
|
+
# Determine which operations to perform
|
|
276
|
+
if pull:
|
|
277
|
+
operations_performed.append("pull")
|
|
278
|
+
if commit:
|
|
279
|
+
operations_performed.append("commit")
|
|
280
|
+
if push:
|
|
281
|
+
operations_performed.append("push")
|
|
282
|
+
|
|
283
|
+
for a_path in repos_root.search("*"):
|
|
284
|
+
print(f"{('Handling ' + str(a_path)).center(80, '-')}")
|
|
285
|
+
summary.total_paths_processed += 1
|
|
286
|
+
|
|
287
|
+
# Check if this is a git repository first
|
|
288
|
+
from git.exc import InvalidGitRepositoryError
|
|
289
|
+
from git.repo import Repo
|
|
290
|
+
|
|
291
|
+
try:
|
|
292
|
+
repo = Repo(str(a_path), search_parent_directories=False)
|
|
293
|
+
summary.git_repos_found += 1
|
|
294
|
+
|
|
295
|
+
# Track repos without remotes
|
|
296
|
+
if len(repo.remotes) == 0:
|
|
297
|
+
summary.repos_without_remotes.append(a_path)
|
|
298
|
+
|
|
299
|
+
# Now perform the actual operations
|
|
300
|
+
if pull:
|
|
301
|
+
result = git_action(path=a_path, action=GitAction.pull, r=recursive, auto_sync=auto_sync)
|
|
302
|
+
summary.pulls_attempted += 1
|
|
303
|
+
if result.success:
|
|
304
|
+
summary.pulls_successful += 1
|
|
305
|
+
else:
|
|
306
|
+
summary.pulls_failed += 1
|
|
307
|
+
summary.failed_operations.append(result)
|
|
308
|
+
|
|
309
|
+
if commit:
|
|
310
|
+
result = git_action(a_path, action=GitAction.commit, r=recursive, auto_sync=auto_sync)
|
|
311
|
+
summary.commits_attempted += 1
|
|
312
|
+
if result.success:
|
|
313
|
+
if result.had_changes:
|
|
314
|
+
summary.commits_successful += 1
|
|
315
|
+
else:
|
|
316
|
+
summary.commits_no_changes += 1
|
|
317
|
+
else:
|
|
318
|
+
summary.commits_failed += 1
|
|
319
|
+
summary.failed_operations.append(result)
|
|
320
|
+
|
|
321
|
+
if push:
|
|
322
|
+
result = git_action(a_path, action=GitAction.push, r=recursive, auto_sync=auto_sync)
|
|
323
|
+
summary.pushes_attempted += 1
|
|
324
|
+
if result.success:
|
|
325
|
+
summary.pushes_successful += 1
|
|
326
|
+
else:
|
|
327
|
+
summary.pushes_failed += 1
|
|
328
|
+
summary.failed_operations.append(result)
|
|
329
|
+
|
|
330
|
+
except InvalidGitRepositoryError:
|
|
331
|
+
summary.non_git_paths += 1
|
|
332
|
+
pprint(f"⚠️ Skipping {a_path} because it is not a git repository.")
|
|
333
|
+
|
|
334
|
+
# Print the detailed summary
|
|
335
|
+
print_git_operations_summary(summary, operations_performed)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Optional
|
|
5
|
+
# import typer
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
reference:
|
|
10
|
+
# https://github.com/tsl0922/ttyd/wiki/Serving-web-fonts
|
|
11
|
+
# -t "fontFamily=CaskaydiaCove" bash
|
|
12
|
+
# --terminal-type xterm-kitty
|
|
13
|
+
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def share_terminal(port: int, password: Optional[str]) -> None:
|
|
18
|
+
if password is None:
|
|
19
|
+
pwd_path = Path.home().joinpath("dotfiles/creds/passwords/quick_password")
|
|
20
|
+
if pwd_path.exists():
|
|
21
|
+
password = pwd_path.read_text(encoding="utf-8").strip()
|
|
22
|
+
else:
|
|
23
|
+
raise ValueError("Password not provided and default password file does not exist.")
|
|
24
|
+
|
|
25
|
+
import socket
|
|
26
|
+
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
27
|
+
s.connect(('8.8.8.8',80))
|
|
28
|
+
local_ip_v4 = s.getsockname()[0]
|
|
29
|
+
s.close()
|
|
30
|
+
|
|
31
|
+
print(f"\n🌐 Access your terminal at: http://{local_ip_v4}:{port}\n")
|
|
32
|
+
|
|
33
|
+
code = f"""
|
|
34
|
+
#!/bin/bash
|
|
35
|
+
uv run --python 3.13 --with machineconfig install -ttyd
|
|
36
|
+
|
|
37
|
+
ttyd --writable -t enableSixel=true --port {port} --credential "$USER:{password}" -t 'theme={"background": "black"}' bash
|
|
38
|
+
|
|
39
|
+
"""
|
|
40
|
+
import subprocess
|
|
41
|
+
subprocess.run(code, shell=True, check=True)
|
|
@@ -6,6 +6,8 @@ from machineconfig.utils.source_of_truth import CONFIG_PATH
|
|
|
6
6
|
from machineconfig.utils.code import print_code
|
|
7
7
|
from machineconfig.utils.path_extended import PathExtended as PathExtended
|
|
8
8
|
from machineconfig.utils.terminal import Terminal
|
|
9
|
+
from typing import Annotated, Optional
|
|
10
|
+
import typer
|
|
9
11
|
import subprocess
|
|
10
12
|
import platform
|
|
11
13
|
|
|
@@ -47,28 +49,24 @@ def jupyter_to_markdown(file: PathExtended):
|
|
|
47
49
|
return op_dir
|
|
48
50
|
|
|
49
51
|
|
|
50
|
-
def main(
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
def main(
|
|
53
|
+
directory: Annotated[Optional[str], typer.Option("-d", "--directory", help="📁 Directory of the report.")] = None,
|
|
54
|
+
jupyter_file: Annotated[Optional[str], typer.Option("-j", "--jupyter-file", help="📓 Jupyter notebook file to convert to slides. If not provided, slides.md is used.")] = None,
|
|
55
|
+
) -> None:
|
|
53
56
|
print("\n" + "=" * 50)
|
|
54
57
|
print("🎥 Welcome to the Slidev Presentation Tool")
|
|
55
58
|
print("=" * 50 + "\n")
|
|
56
59
|
|
|
57
|
-
parser = argparse.ArgumentParser()
|
|
58
|
-
parser.add_argument("-d", "--directory", default=None, help="📁 Directory of the report.")
|
|
59
|
-
parser.add_argument("-j", "--jupyter-file", default=None, help="📓 Jupyter notebook file to convert to slides. If not provided, slides.md is used.")
|
|
60
|
-
args = parser.parse_args()
|
|
61
|
-
|
|
62
60
|
port = PORT_DEFAULT
|
|
63
61
|
|
|
64
|
-
if
|
|
62
|
+
if jupyter_file is not None:
|
|
65
63
|
print("📓 Jupyter file provided. Converting to markdown...")
|
|
66
|
-
report_dir = jupyter_to_markdown(PathExtended(
|
|
64
|
+
report_dir = jupyter_to_markdown(PathExtended(jupyter_file))
|
|
67
65
|
else:
|
|
68
|
-
if
|
|
66
|
+
if directory is None:
|
|
69
67
|
report_dir = PathExtended.cwd()
|
|
70
68
|
else:
|
|
71
|
-
report_dir = PathExtended(
|
|
69
|
+
report_dir = PathExtended(directory)
|
|
72
70
|
|
|
73
71
|
assert report_dir.exists(), f"❌ Directory {report_dir} does not exist."
|
|
74
72
|
assert report_dir.is_dir(), f"❌ {report_dir} is not a directory."
|
|
@@ -108,5 +106,9 @@ def main() -> None:
|
|
|
108
106
|
print_code(code=program, lexer="bash", desc="Run the following command to start the presentation")
|
|
109
107
|
|
|
110
108
|
|
|
109
|
+
def arg_parser() -> None:
|
|
110
|
+
typer.run(main)
|
|
111
|
+
|
|
112
|
+
|
|
111
113
|
if __name__ == "__main__":
|
|
112
|
-
|
|
114
|
+
arg_parser()
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
from machineconfig.utils.options import choose_from_options, get_ssh_hosts
|
|
4
4
|
import platform
|
|
5
5
|
from itertools import cycle
|
|
6
|
-
from typing import Literal
|
|
6
|
+
from typing import Literal, Optional, Annotated
|
|
7
|
+
import typer
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
COLOR_SCHEMES = ["Campbell", "Campbell Powershell", "Solarized Dark", "Ubuntu-ColorScheme", "Retro"]
|
|
@@ -70,40 +71,35 @@ wt --window {window} --title {hosts[0]} powershell -Command "ssh {host_linux} {s
|
|
|
70
71
|
return cmd
|
|
71
72
|
|
|
72
73
|
|
|
73
|
-
def main(
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
def main(
|
|
75
|
+
panes: Annotated[Optional[int], typer.Option("--panes", "-p", help="🔲 The number of panes to open.")] = 4,
|
|
76
|
+
vertical: Annotated[bool, typer.Option("--vertical", "-V", help="↕️ Switch orientation to vertical from default horizontal.")] = False,
|
|
77
|
+
window: Annotated[int, typer.Option("--window", "-w", help="🪟 The window ID to use.")] = 0,
|
|
78
|
+
hosts: Annotated[Optional[list[str]], typer.Option("--hosts", "-H", help="🌐 The hosts to connect to.")] = None,
|
|
79
|
+
) -> None:
|
|
76
80
|
print("\n" + "=" * 50)
|
|
77
81
|
print("🖥️ Welcome to the Terminal Starter Tool")
|
|
78
82
|
print("=" * 50 + "\n")
|
|
79
83
|
|
|
80
|
-
|
|
81
|
-
parser.add_argument("--panes", "-p", type=int, help="🔲 The number of panes to open.", default=4)
|
|
82
|
-
parser.add_argument("--vertical", "-V", action="store_true", help="↕️ Switch orientation to vertical from default horizontal.")
|
|
83
|
-
parser.add_argument("--window", "-w", type=int, help="🪟 The window ID to use.", default=0) # 0 refers to this window.
|
|
84
|
-
parser.add_argument("--hosts", "-H", type=str, nargs="*", help="🌐 The hosts to connect to.", default=None)
|
|
85
|
-
args = parser.parse_args()
|
|
86
|
-
|
|
87
|
-
if args.panes:
|
|
84
|
+
if panes:
|
|
88
85
|
print("🔲 Configuring panes...")
|
|
89
|
-
cmd = f"wt --window {
|
|
86
|
+
cmd = f"wt --window {window} --colorScheme '{next(THEMES_ITER)}' pwsh -NoExit -Command '{next(INIT_COMMANDS_ITER)}' "
|
|
90
87
|
cmd += f" `; new-tab --colorScheme '{next(THEMES_ITER)}' --profile pwsh --title 't2' --tabColor '#f59218' "
|
|
91
88
|
cmd += f" `; new-tab --colorScheme '{next(THEMES_ITER)}' --profile pwsh --title 't3' --tabColor '#009999' "
|
|
92
|
-
for idx in range(
|
|
89
|
+
for idx in range(panes):
|
|
93
90
|
if idx % 2 == 0:
|
|
94
91
|
cmd += f" `; move-focus down split-pane --horizontal --size {next(SIZE_ITER)} --colorScheme '{next(THEMES_ITER)}' pwsh -NoExit -Command '{next(INIT_COMMANDS_ITER)}' "
|
|
95
92
|
else:
|
|
96
93
|
cmd += f" `; move-focus up split-pane --vertical --size {next(SIZE_ITER)} --colorScheme '{next(THEMES_ITER)}' pwsh -NoExit -Command '{next(INIT_COMMANDS_ITER)}' "
|
|
97
94
|
|
|
98
95
|
else:
|
|
99
|
-
if
|
|
96
|
+
if hosts is None:
|
|
100
97
|
print("🌐 No hosts provided. Displaying options...")
|
|
101
98
|
hosts = choose_from_options(msg="Select hosts:", options=get_ssh_hosts() + [THIS_MACHINE], multi=True, fzf=True)
|
|
102
99
|
else:
|
|
103
|
-
print("🌐 Using provided hosts:",
|
|
104
|
-
hosts = args.hosts
|
|
100
|
+
print("🌐 Using provided hosts:", hosts)
|
|
105
101
|
assert isinstance(hosts, list)
|
|
106
|
-
cmd = main_windows_and_wsl(window=
|
|
102
|
+
cmd = main_windows_and_wsl(window=window, hosts=hosts, orientation="vertical" if vertical else "horizontal")
|
|
107
103
|
|
|
108
104
|
print("\n📋 Generated Command:")
|
|
109
105
|
print("-" * 50)
|
|
@@ -117,5 +113,9 @@ def main():
|
|
|
117
113
|
print("✅ Command saved successfully!\n")
|
|
118
114
|
|
|
119
115
|
|
|
116
|
+
def arg_parser() -> None:
|
|
117
|
+
typer.run(main)
|
|
118
|
+
|
|
119
|
+
|
|
120
120
|
if __name__ == "__main__":
|
|
121
|
-
|
|
121
|
+
arg_parser()
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
import typer
|
|
3
|
+
from typing import Annotated
|
|
4
|
+
|
|
5
|
+
def func(name: str):
|
|
6
|
+
print(f"Hello, {name}! from func")
|
|
7
|
+
|
|
8
|
+
def hello(*, name: Annotated[str, typer.Option(..., help="Name to greet")]):
|
|
9
|
+
print(f"Hello, {name}!")
|
|
10
|
+
|
|
11
|
+
def main():
|
|
12
|
+
typer.run(hello)
|
|
13
|
+
|
|
14
|
+
if __name__ == "__main__":
|
|
15
|
+
# typer.run(hello)
|
|
16
|
+
main()
|
|
17
|
+
pass
|
|
@@ -28,7 +28,8 @@ Usage examples:
|
|
|
28
28
|
|
|
29
29
|
"""
|
|
30
30
|
|
|
31
|
-
import
|
|
31
|
+
from typing import Annotated
|
|
32
|
+
import typer
|
|
32
33
|
import configparser
|
|
33
34
|
from pathlib import Path
|
|
34
35
|
import os
|
|
@@ -262,24 +263,21 @@ def manual_network_selection() -> bool:
|
|
|
262
263
|
return False
|
|
263
264
|
|
|
264
265
|
|
|
265
|
-
def main(
|
|
266
|
+
def main(
|
|
267
|
+
ssid: Annotated[str, typer.Option("-n", "--ssid", help="🔗 SSID of WiFi (from config)")] = "MyPhoneHotSpot",
|
|
268
|
+
manual: Annotated[bool, typer.Option("-m", "--manual", help="🔍 Manual network selection mode")] = False,
|
|
269
|
+
list_: Annotated[bool, typer.Option("-l", "--list", help="📡 List available networks only")] = False,
|
|
270
|
+
) -> None:
|
|
266
271
|
"""Main function with fallback network selection"""
|
|
267
272
|
console.print(Panel("📶 Welcome to the WiFi Connector Tool", title="[bold blue]WiFi Connection[/bold blue]", border_style="blue"))
|
|
268
273
|
|
|
269
|
-
parser = argparse.ArgumentParser(description="WiFi Connector")
|
|
270
|
-
parser.add_argument("-n", "--ssid", help="🔗 SSID of WiFi (from config)", default="MyPhoneHotSpot")
|
|
271
|
-
parser.add_argument("-m", "--manual", action="store_true", help="🔍 Manual network selection mode")
|
|
272
|
-
parser.add_argument("-l", "--list", action="store_true", help="📡 List available networks only")
|
|
273
|
-
|
|
274
|
-
args = parser.parse_args()
|
|
275
|
-
|
|
276
274
|
# If user just wants to list networks
|
|
277
|
-
if
|
|
275
|
+
if list_:
|
|
278
276
|
display_available_networks()
|
|
279
277
|
return
|
|
280
278
|
|
|
281
279
|
# If user wants manual mode, skip config and go straight to selection
|
|
282
|
-
if
|
|
280
|
+
if manual:
|
|
283
281
|
console.print("[blue]🔍 Manual network selection mode[/blue]")
|
|
284
282
|
if manual_network_selection():
|
|
285
283
|
console.print("[green]🎉 Successfully connected![/green]")
|
|
@@ -288,9 +286,9 @@ def main():
|
|
|
288
286
|
return
|
|
289
287
|
|
|
290
288
|
# Try to connect using configuration first
|
|
291
|
-
console.print(f"[blue]🔍 Attempting to connect to configured network: {
|
|
289
|
+
console.print(f"[blue]🔍 Attempting to connect to configured network: {ssid}[/blue]")
|
|
292
290
|
|
|
293
|
-
if try_config_connection(
|
|
291
|
+
if try_config_connection(ssid):
|
|
294
292
|
console.print("[green]🎉 Successfully connected using configuration![/green]")
|
|
295
293
|
return
|
|
296
294
|
|
|
@@ -306,6 +304,10 @@ def main():
|
|
|
306
304
|
console.print("[blue]👋 Goodbye![/blue]")
|
|
307
305
|
|
|
308
306
|
|
|
307
|
+
def arg_parser() -> None:
|
|
308
|
+
typer.run(main)
|
|
309
|
+
|
|
310
|
+
|
|
309
311
|
def get_current_wifi_name() -> str:
|
|
310
312
|
"""Get the name of the currently connected WiFi network"""
|
|
311
313
|
console.print("\n[blue]🔍 Checking current WiFi connection...[/blue]")
|
|
@@ -413,4 +415,4 @@ def create_new_connection(name: str, ssid: str, password: str):
|
|
|
413
415
|
|
|
414
416
|
|
|
415
417
|
if __name__ == "__main__":
|
|
416
|
-
|
|
418
|
+
arg_parser()
|