machineconfig 2.0__py3-none-any.whl → 2.2__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/cloud_manager.py +0 -3
- machineconfig/cluster/data_transfer.py +0 -1
- machineconfig/cluster/file_manager.py +0 -1
- machineconfig/cluster/job_params.py +0 -3
- machineconfig/cluster/loader_runner.py +0 -3
- machineconfig/cluster/remote_machine.py +0 -1
- machineconfig/cluster/script_notify_upon_completion.py +0 -1
- machineconfig/cluster/sessions_managers/archive/create_zellij_template.py +5 -6
- machineconfig/cluster/sessions_managers/archive/session_managers.py +0 -1
- machineconfig/cluster/sessions_managers/enhanced_command_runner.py +17 -57
- machineconfig/cluster/sessions_managers/wt_local.py +36 -110
- machineconfig/cluster/sessions_managers/wt_local_manager.py +42 -112
- machineconfig/cluster/sessions_managers/wt_remote.py +23 -30
- machineconfig/cluster/sessions_managers/wt_remote_manager.py +20 -62
- machineconfig/cluster/sessions_managers/wt_utils/layout_generator.py +10 -15
- machineconfig/cluster/sessions_managers/wt_utils/process_monitor.py +27 -127
- machineconfig/cluster/sessions_managers/wt_utils/remote_executor.py +10 -43
- machineconfig/cluster/sessions_managers/wt_utils/session_manager.py +22 -101
- machineconfig/cluster/sessions_managers/wt_utils/status_reporter.py +11 -39
- machineconfig/cluster/sessions_managers/zellij_local.py +49 -102
- machineconfig/cluster/sessions_managers/zellij_local_manager.py +34 -78
- machineconfig/cluster/sessions_managers/zellij_remote.py +17 -24
- machineconfig/cluster/sessions_managers/zellij_remote_manager.py +7 -13
- machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +4 -2
- machineconfig/cluster/sessions_managers/zellij_utils/layout_generator.py +6 -6
- machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +18 -88
- machineconfig/cluster/sessions_managers/zellij_utils/remote_executor.py +2 -6
- machineconfig/cluster/sessions_managers/zellij_utils/session_manager.py +12 -40
- machineconfig/cluster/sessions_managers/zellij_utils/status_reporter.py +3 -2
- machineconfig/cluster/templates/cli_click.py +0 -1
- machineconfig/cluster/templates/cli_gooey.py +0 -2
- machineconfig/cluster/templates/cli_trogon.py +0 -1
- machineconfig/cluster/templates/run_cloud.py +0 -1
- machineconfig/cluster/templates/run_cluster.py +0 -1
- machineconfig/cluster/templates/run_remote.py +0 -1
- machineconfig/cluster/templates/utils.py +27 -46
- machineconfig/jobs/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/linux/msc/cli_agents.sh +16 -0
- machineconfig/jobs/python/check_installations.py +2 -1
- machineconfig/jobs/python/create_bootable_media.py +0 -2
- machineconfig/jobs/python/python_ve_symlink.py +9 -11
- machineconfig/jobs/python/tasks.py +0 -1
- machineconfig/jobs/python/vscode/api.py +5 -5
- machineconfig/jobs/python/vscode/link_ve.py +13 -14
- machineconfig/jobs/python/vscode/select_interpreter.py +21 -22
- machineconfig/jobs/python/vscode/sync_code.py +9 -13
- machineconfig/jobs/python_custom_installers/archive/ngrok.py +13 -13
- machineconfig/jobs/python_custom_installers/dev/aider.py +7 -15
- machineconfig/jobs/python_custom_installers/dev/alacritty.py +9 -18
- machineconfig/jobs/python_custom_installers/dev/brave.py +10 -19
- machineconfig/jobs/python_custom_installers/dev/bypass_paywall.py +8 -15
- machineconfig/jobs/python_custom_installers/dev/code.py +12 -32
- machineconfig/jobs/python_custom_installers/dev/cursor.py +3 -14
- machineconfig/jobs/python_custom_installers/dev/docker_desktop.py +8 -7
- machineconfig/jobs/python_custom_installers/dev/espanso.py +15 -19
- machineconfig/jobs/python_custom_installers/dev/goes.py +5 -12
- machineconfig/jobs/python_custom_installers/dev/lvim.py +9 -17
- machineconfig/jobs/python_custom_installers/dev/nerdfont.py +12 -19
- machineconfig/jobs/python_custom_installers/dev/redis.py +12 -20
- machineconfig/jobs/python_custom_installers/dev/wezterm.py +12 -19
- machineconfig/jobs/python_custom_installers/dev/winget.py +5 -23
- machineconfig/jobs/python_custom_installers/docker.py +12 -21
- machineconfig/jobs/python_custom_installers/gh.py +11 -19
- machineconfig/jobs/python_custom_installers/hx.py +32 -16
- machineconfig/jobs/python_custom_installers/warp-cli.py +12 -20
- machineconfig/jobs/python_generic_installers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/python_generic_installers/config.json +1 -1
- machineconfig/jobs/python_linux_installers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/windows/archive/archive_pygraphviz.ps1 +1 -1
- machineconfig/jobs/windows/msc/cli_agents.bat +0 -0
- machineconfig/jobs/windows/msc/cli_agents.ps1 +0 -0
- machineconfig/jobs/windows/start_terminal.ps1 +1 -1
- machineconfig/profile/create.py +38 -26
- machineconfig/profile/create_hardlinks.py +29 -20
- machineconfig/profile/shell.py +56 -32
- machineconfig/scripts/__init__.py +0 -2
- machineconfig/scripts/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/cloud/init.sh +2 -2
- machineconfig/scripts/linux/checkout_versions +1 -1
- machineconfig/scripts/linux/choose_wezterm_theme +1 -1
- machineconfig/scripts/linux/cloud_copy +1 -1
- machineconfig/scripts/linux/cloud_manager +1 -1
- machineconfig/scripts/linux/cloud_mount +1 -1
- machineconfig/scripts/linux/cloud_repo_sync +1 -1
- machineconfig/scripts/linux/cloud_sync +1 -1
- machineconfig/scripts/linux/croshell +1 -1
- machineconfig/scripts/linux/devops +7 -7
- machineconfig/scripts/linux/fire +1 -1
- machineconfig/scripts/linux/fire_agents +3 -2
- machineconfig/scripts/linux/ftpx +1 -1
- machineconfig/scripts/linux/gh_models +1 -1
- machineconfig/scripts/linux/kill_process +1 -1
- machineconfig/scripts/linux/mcinit +1 -1
- machineconfig/scripts/linux/repos +1 -1
- machineconfig/scripts/linux/scheduler +1 -1
- machineconfig/scripts/linux/start_slidev +1 -1
- machineconfig/scripts/linux/start_terminals +1 -1
- machineconfig/scripts/linux/url2md +1 -1
- machineconfig/scripts/linux/warp-cli.sh +122 -0
- machineconfig/scripts/linux/wifi_conn +1 -1
- machineconfig/scripts/python/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_devapps_install.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/fire_agents.cpython-313.pyc +0 -0
- machineconfig/scripts/python/ai/__init__.py +0 -0
- machineconfig/scripts/python/ai/generate_files.py +83 -0
- machineconfig/scripts/python/ai/instructions/python/dev.instructions.md +2 -2
- machineconfig/scripts/python/ai/mcinit.py +14 -7
- machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +10 -5
- machineconfig/scripts/python/archive/tmate_conn.py +5 -5
- machineconfig/scripts/python/archive/tmate_start.py +7 -7
- machineconfig/scripts/python/choose_wezterm_theme.py +35 -32
- machineconfig/scripts/python/cloud_copy.py +23 -14
- machineconfig/scripts/python/cloud_mount.py +36 -24
- machineconfig/scripts/python/cloud_repo_sync.py +40 -27
- machineconfig/scripts/python/cloud_sync.py +4 -4
- machineconfig/scripts/python/croshell.py +40 -29
- machineconfig/scripts/python/devops.py +45 -27
- machineconfig/scripts/python/devops_add_identity.py +15 -25
- machineconfig/scripts/python/devops_add_ssh_key.py +8 -8
- machineconfig/scripts/python/devops_backup_retrieve.py +18 -16
- machineconfig/scripts/python/devops_devapps_install.py +25 -20
- machineconfig/scripts/python/devops_update_repos.py +232 -59
- machineconfig/scripts/python/dotfile.py +17 -15
- machineconfig/scripts/python/fire_agents.py +48 -22
- machineconfig/scripts/python/fire_jobs.py +93 -58
- machineconfig/scripts/python/ftpx.py +26 -15
- machineconfig/scripts/python/get_zellij_cmd.py +8 -7
- machineconfig/scripts/python/helpers/cloud_helpers.py +33 -28
- machineconfig/scripts/python/helpers/helpers2.py +27 -16
- machineconfig/scripts/python/helpers/helpers4.py +45 -32
- machineconfig/scripts/python/helpers/helpers5.py +1 -1
- machineconfig/scripts/python/helpers/repo_sync_helpers.py +32 -10
- machineconfig/scripts/python/mount_nfs.py +9 -16
- machineconfig/scripts/python/mount_nw_drive.py +10 -5
- machineconfig/scripts/python/mount_ssh.py +9 -7
- machineconfig/scripts/python/repos.py +216 -58
- machineconfig/scripts/python/snapshot.py +0 -1
- machineconfig/scripts/python/start_slidev.py +11 -6
- machineconfig/scripts/python/start_terminals.py +22 -16
- machineconfig/scripts/python/viewer_template.py +0 -1
- machineconfig/scripts/python/wifi_conn.py +49 -75
- machineconfig/scripts/python/wsl_windows_transfer.py +9 -7
- machineconfig/scripts/windows/checkout_version.ps1 +1 -3
- machineconfig/scripts/windows/choose_wezterm_theme.ps1 +1 -3
- machineconfig/scripts/windows/cloud_copy.ps1 +2 -6
- machineconfig/scripts/windows/cloud_manager.ps1 +1 -1
- machineconfig/scripts/windows/cloud_repo_sync.ps1 +1 -2
- machineconfig/scripts/windows/cloud_sync.ps1 +2 -2
- machineconfig/scripts/windows/croshell.ps1 +2 -2
- machineconfig/scripts/windows/devops.ps1 +1 -4
- machineconfig/scripts/windows/dotfile.ps1 +1 -3
- machineconfig/scripts/windows/fire.ps1 +1 -1
- machineconfig/scripts/windows/ftpx.ps1 +2 -2
- machineconfig/scripts/windows/gpt.ps1 +1 -1
- machineconfig/scripts/windows/kill_process.ps1 +1 -2
- machineconfig/scripts/windows/mcinit.ps1 +1 -1
- machineconfig/scripts/windows/mount_nfs.ps1 +1 -1
- machineconfig/scripts/windows/mount_ssh.ps1 +1 -1
- machineconfig/scripts/windows/pomodoro.ps1 +1 -1
- machineconfig/scripts/windows/py2exe.ps1 +1 -3
- machineconfig/scripts/windows/repos.ps1 +1 -1
- machineconfig/scripts/windows/scheduler.ps1 +1 -1
- machineconfig/scripts/windows/snapshot.ps1 +2 -2
- machineconfig/scripts/windows/start_slidev.ps1 +1 -1
- machineconfig/scripts/windows/start_terminals.ps1 +1 -1
- machineconfig/scripts/windows/wifi_conn.ps1 +1 -1
- machineconfig/scripts/windows/wsl_windows_transfer.ps1 +1 -3
- machineconfig/settings/lf/linux/lfrc +2 -1
- machineconfig/settings/linters/.ruff_cache/.gitignore +2 -0
- machineconfig/settings/linters/.ruff_cache/CACHEDIR.TAG +1 -0
- machineconfig/settings/lvim/windows/archive/config_additional.lua +1 -1
- machineconfig/settings/svim/linux/init.toml +1 -1
- machineconfig/settings/svim/windows/init.toml +1 -1
- machineconfig/setup_linux/web_shortcuts/croshell.sh +3 -52
- machineconfig/setup_linux/web_shortcuts/interactive.sh +6 -6
- machineconfig/setup_linux/web_shortcuts/ssh.sh +0 -4
- machineconfig/setup_windows/web_shortcuts/all.ps1 +2 -2
- machineconfig/setup_windows/web_shortcuts/ascii_art.ps1 +1 -1
- machineconfig/setup_windows/web_shortcuts/croshell.ps1 +1 -1
- machineconfig/setup_windows/web_shortcuts/interactive.ps1 +5 -5
- machineconfig/setup_windows/wt_and_pwsh/install_fonts.ps1 +51 -15
- machineconfig/setup_windows/wt_and_pwsh/set_pwsh_theme.py +58 -13
- machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +45 -37
- machineconfig/utils/ai/generate_file_checklist.py +8 -10
- machineconfig/utils/ai/url2md.py +4 -2
- machineconfig/utils/cloud/onedrive/setup_oauth.py +1 -0
- machineconfig/utils/cloud/onedrive/transaction.py +63 -98
- machineconfig/utils/code.py +62 -41
- machineconfig/utils/installer.py +29 -35
- machineconfig/utils/installer_utils/installer_abc.py +11 -11
- machineconfig/utils/installer_utils/installer_class.py +155 -74
- machineconfig/utils/links.py +112 -31
- machineconfig/utils/notifications.py +211 -0
- machineconfig/utils/options.py +41 -42
- machineconfig/utils/path.py +13 -6
- machineconfig/utils/path_reduced.py +614 -311
- machineconfig/utils/procs.py +48 -42
- machineconfig/utils/scheduling.py +0 -1
- machineconfig/utils/source_of_truth.py +27 -0
- machineconfig/utils/ssh.py +146 -85
- machineconfig/utils/terminal.py +84 -37
- machineconfig/utils/upgrade_packages.py +91 -0
- machineconfig/utils/utils2.py +39 -50
- machineconfig/utils/utils5.py +195 -116
- machineconfig/utils/ve.py +13 -5
- {machineconfig-2.0.dist-info → machineconfig-2.2.dist-info}/METADATA +14 -13
- {machineconfig-2.0.dist-info → machineconfig-2.2.dist-info}/RECORD +212 -237
- machineconfig/jobs/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/jobs/python/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/jobs/python/__pycache__/python_ve_symlink.cpython-311.pyc +0 -0
- machineconfig/jobs/python/archive/python_tools.txt +0 -12
- machineconfig/jobs/python/vscode/__pycache__/select_interpreter.cpython-311.pyc +0 -0
- machineconfig/jobs/python_custom_installers/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/jobs/python_generic_installers/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/jobs/python_generic_installers/update.py +0 -3
- machineconfig/jobs/python_linux_installers/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/profile/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/profile/__pycache__/create.cpython-311.pyc +0 -0
- machineconfig/profile/__pycache__/shell.cpython-311.pyc +0 -0
- machineconfig/scripts/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/scripts/linux/activate_ve +0 -87
- machineconfig/scripts/python/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/cloud_copy.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/cloud_mount.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/cloud_sync.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/croshell.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_backup_retrieve.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_devapps_install.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/fire_agents.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/fire_jobs.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/fire_jobs.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/get_zellij_cmd.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/repos.cpython-311.pyc +0 -0
- machineconfig/scripts/python/ai/__pycache__/init.cpython-311.pyc +0 -0
- machineconfig/scripts/python/ai/__pycache__/mcinit.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/cloud_helpers.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/helpers2.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/helpers4.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/helpers4.cpython-313.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/repo_sync_helpers.cpython-311.pyc +0 -0
- machineconfig/scripts/windows/activate_ve.ps1 +0 -54
- machineconfig/setup_linux/web_shortcuts/all.sh +0 -48
- machineconfig/setup_linux/web_shortcuts/update_system.sh +0 -48
- machineconfig/utils/utils.py +0 -95
- /machineconfig/setup_linux/web_shortcuts/{tmp.sh → android.sh} +0 -0
- {machineconfig-2.0.dist-info → machineconfig-2.2.dist-info}/WHEEL +0 -0
- {machineconfig-2.0.dist-info → machineconfig-2.2.dist-info}/top_level.txt +0 -0
|
@@ -43,12 +43,14 @@ import json
|
|
|
43
43
|
|
|
44
44
|
def get_rclone_token(section: str):
|
|
45
45
|
import platform
|
|
46
|
+
|
|
46
47
|
if platform.system() == "Windows":
|
|
47
48
|
rclone_file_path = Path(os.getenv("APPDATA", "")) / "rclone" / "rclone.conf"
|
|
48
49
|
else:
|
|
49
50
|
rclone_file_path = Path.home() / ".config" / "rclone" / "rclone.conf"
|
|
50
51
|
if rclone_file_path.exists():
|
|
51
52
|
import configparser
|
|
53
|
+
|
|
52
54
|
config = configparser.ConfigParser()
|
|
53
55
|
config.read(rclone_file_path)
|
|
54
56
|
if section in config:
|
|
@@ -57,9 +59,11 @@ def get_rclone_token(section: str):
|
|
|
57
59
|
return dict(results)
|
|
58
60
|
return None
|
|
59
61
|
|
|
62
|
+
|
|
60
63
|
# Configuration - Will be loaded from rclone config
|
|
61
64
|
_cached_config = None
|
|
62
65
|
|
|
66
|
+
|
|
63
67
|
def get_config(section: str = "odp") -> dict[str, Any]:
|
|
64
68
|
"""
|
|
65
69
|
Get OneDrive configuration from rclone config.
|
|
@@ -83,31 +87,32 @@ def get_config(section: str = "odp") -> dict[str, Any]:
|
|
|
83
87
|
except json.JSONDecodeError:
|
|
84
88
|
raise Exception(f"Invalid token format in rclone config section '{section}'")
|
|
85
89
|
|
|
86
|
-
_cached_config = {
|
|
87
|
-
"token": token_data,
|
|
88
|
-
"drive_id": rclone_config.get("drive_id"),
|
|
89
|
-
"drive_type": rclone_config.get("drive_type", "personal")
|
|
90
|
-
}
|
|
90
|
+
_cached_config = {"token": token_data, "drive_id": rclone_config.get("drive_id"), "drive_type": rclone_config.get("drive_type", "personal")}
|
|
91
91
|
|
|
92
92
|
return _cached_config
|
|
93
93
|
|
|
94
|
+
|
|
94
95
|
def get_token() -> dict[str, Any]:
|
|
95
96
|
"""Get the current token from rclone config."""
|
|
96
97
|
return get_config()["token"]
|
|
97
98
|
|
|
99
|
+
|
|
98
100
|
def get_drive_id():
|
|
99
101
|
"""Get the drive ID from rclone config."""
|
|
100
102
|
return get_config()["drive_id"]
|
|
101
103
|
|
|
104
|
+
|
|
102
105
|
def get_drive_type():
|
|
103
106
|
"""Get the drive type from rclone config."""
|
|
104
107
|
return get_config()["drive_type"]
|
|
105
108
|
|
|
109
|
+
|
|
106
110
|
def clear_config_cache():
|
|
107
111
|
"""Clear the cached config to force reload from rclone."""
|
|
108
112
|
global _cached_config
|
|
109
113
|
_cached_config = None
|
|
110
114
|
|
|
115
|
+
|
|
111
116
|
# OAuth2 Configuration - You'll need to set these up in Azure App Registration
|
|
112
117
|
CLIENT_ID = os.getenv("ONEDRIVE_CLIENT_ID", "your_client_id_here")
|
|
113
118
|
CLIENT_SECRET = os.getenv("ONEDRIVE_CLIENT_SECRET", "your_client_secret_here") # Optional for public clients
|
|
@@ -133,10 +138,10 @@ def is_token_valid() -> bool:
|
|
|
133
138
|
return False
|
|
134
139
|
|
|
135
140
|
# Remove timezone info for parsing (rclone format includes timezone)
|
|
136
|
-
if
|
|
137
|
-
expiry_str = expiry_str.split(
|
|
138
|
-
elif
|
|
139
|
-
expiry_str = expiry_str.replace(
|
|
141
|
+
if "+" in expiry_str:
|
|
142
|
+
expiry_str = expiry_str.split("+")[0]
|
|
143
|
+
elif "Z" in expiry_str:
|
|
144
|
+
expiry_str = expiry_str.replace("Z", "")
|
|
140
145
|
|
|
141
146
|
expiry_time = datetime.fromisoformat(expiry_str)
|
|
142
147
|
current_time = datetime.now()
|
|
@@ -195,9 +200,9 @@ def make_graph_request(method: str, endpoint: str, **kwargs: Any) -> requests.Re
|
|
|
195
200
|
if not token:
|
|
196
201
|
raise Exception("Failed to get valid access token")
|
|
197
202
|
|
|
198
|
-
headers = kwargs.get(
|
|
199
|
-
headers[
|
|
200
|
-
kwargs[
|
|
203
|
+
headers = kwargs.get("headers", {})
|
|
204
|
+
headers["Authorization"] = f"Bearer {token}"
|
|
205
|
+
kwargs["headers"] = headers
|
|
201
206
|
|
|
202
207
|
url = f"{GRAPH_API_BASE}/{endpoint.lstrip('/')}"
|
|
203
208
|
response = requests.request(method, url, **kwargs)
|
|
@@ -228,12 +233,12 @@ def push_to_onedrive(local_path: str, remote_path: str) -> bool:
|
|
|
228
233
|
return False
|
|
229
234
|
|
|
230
235
|
# Ensure remote path starts with /
|
|
231
|
-
if not remote_path.startswith(
|
|
232
|
-
remote_path =
|
|
236
|
+
if not remote_path.startswith("/"):
|
|
237
|
+
remote_path = "/" + remote_path
|
|
233
238
|
|
|
234
239
|
# Create parent directories if they don't exist
|
|
235
240
|
remote_dir = os.path.dirname(remote_path)
|
|
236
|
-
if remote_dir and remote_dir !=
|
|
241
|
+
if remote_dir and remote_dir != "/":
|
|
237
242
|
create_remote_directory(remote_dir)
|
|
238
243
|
|
|
239
244
|
try:
|
|
@@ -253,15 +258,15 @@ def push_to_onedrive(local_path: str, remote_path: str) -> bool:
|
|
|
253
258
|
def simple_upload(local_file: Path, remote_path: str) -> bool:
|
|
254
259
|
"""Upload small files using simple upload."""
|
|
255
260
|
try:
|
|
256
|
-
with open(local_file,
|
|
261
|
+
with open(local_file, "rb") as f:
|
|
257
262
|
file_content = f.read()
|
|
258
263
|
|
|
259
264
|
# URL encode the remote path and use specific drive
|
|
260
|
-
encoded_path = quote(remote_path, safe=
|
|
265
|
+
encoded_path = quote(remote_path, safe="/")
|
|
261
266
|
drive_id = get_drive_id()
|
|
262
267
|
endpoint = f"drives/{drive_id}/root:{encoded_path}:/content"
|
|
263
268
|
|
|
264
|
-
response = make_graph_request(
|
|
269
|
+
response = make_graph_request("PUT", endpoint, data=file_content)
|
|
265
270
|
|
|
266
271
|
if response.status_code in [200, 201]:
|
|
267
272
|
print(f"Successfully uploaded: {local_file} -> {remote_path}")
|
|
@@ -279,28 +284,23 @@ def resumable_upload(local_file: Path, remote_path: str) -> bool:
|
|
|
279
284
|
"""Upload large files using resumable upload."""
|
|
280
285
|
try:
|
|
281
286
|
# Create upload session using specific drive
|
|
282
|
-
encoded_path = quote(remote_path, safe=
|
|
287
|
+
encoded_path = quote(remote_path, safe="/")
|
|
283
288
|
drive_id = get_drive_id()
|
|
284
289
|
endpoint = f"drives/{drive_id}/root:{encoded_path}:/createUploadSession"
|
|
285
290
|
|
|
286
|
-
item_data = {
|
|
287
|
-
"item": {
|
|
288
|
-
"@microsoft.graph.conflictBehavior": "replace",
|
|
289
|
-
"name": local_file.name
|
|
290
|
-
}
|
|
291
|
-
}
|
|
291
|
+
item_data = {"item": {"@microsoft.graph.conflictBehavior": "replace", "name": local_file.name}}
|
|
292
292
|
|
|
293
|
-
response = make_graph_request(
|
|
293
|
+
response = make_graph_request("POST", endpoint, json=item_data)
|
|
294
294
|
|
|
295
295
|
if response.status_code != 200:
|
|
296
296
|
print(f"Failed to create upload session: {response.status_code} - {response.text}")
|
|
297
297
|
return False
|
|
298
298
|
|
|
299
|
-
upload_url = response.json()[
|
|
299
|
+
upload_url = response.json()["uploadUrl"]
|
|
300
300
|
file_size = local_file.stat().st_size
|
|
301
301
|
chunk_size = 320 * 1024 # 320KB chunks
|
|
302
302
|
|
|
303
|
-
with open(local_file,
|
|
303
|
+
with open(local_file, "rb") as f:
|
|
304
304
|
bytes_uploaded = 0
|
|
305
305
|
|
|
306
306
|
while bytes_uploaded < file_size:
|
|
@@ -310,10 +310,7 @@ def resumable_upload(local_file: Path, remote_path: str) -> bool:
|
|
|
310
310
|
|
|
311
311
|
chunk_end = min(bytes_uploaded + len(chunk_data) - 1, file_size - 1)
|
|
312
312
|
|
|
313
|
-
headers = {
|
|
314
|
-
'Content-Range': f'bytes {bytes_uploaded}-{chunk_end}/{file_size}',
|
|
315
|
-
'Content-Length': str(len(chunk_data))
|
|
316
|
-
}
|
|
313
|
+
headers = {"Content-Range": f"bytes {bytes_uploaded}-{chunk_end}/{file_size}", "Content-Length": str(len(chunk_data))}
|
|
317
314
|
|
|
318
315
|
chunk_response = requests.put(upload_url, data=chunk_data, headers=headers)
|
|
319
316
|
|
|
@@ -345,16 +342,16 @@ def pull_from_onedrive(remote_path: str, local_path: str) -> bool:
|
|
|
345
342
|
True if successful, False otherwise
|
|
346
343
|
"""
|
|
347
344
|
# Ensure remote path starts with /
|
|
348
|
-
if not remote_path.startswith(
|
|
349
|
-
remote_path =
|
|
345
|
+
if not remote_path.startswith("/"):
|
|
346
|
+
remote_path = "/" + remote_path
|
|
350
347
|
|
|
351
348
|
try:
|
|
352
349
|
# Get file metadata and download URL using specific drive
|
|
353
|
-
encoded_path = quote(remote_path, safe=
|
|
350
|
+
encoded_path = quote(remote_path, safe="/")
|
|
354
351
|
drive_id = get_drive_id()
|
|
355
352
|
endpoint = f"drives/{drive_id}/root:{encoded_path}"
|
|
356
353
|
|
|
357
|
-
response = make_graph_request(
|
|
354
|
+
response = make_graph_request("GET", endpoint)
|
|
358
355
|
|
|
359
356
|
if response.status_code == 404:
|
|
360
357
|
print(f"File not found in OneDrive: {remote_path}")
|
|
@@ -366,12 +363,12 @@ def pull_from_onedrive(remote_path: str, local_path: str) -> bool:
|
|
|
366
363
|
file_info = response.json()
|
|
367
364
|
|
|
368
365
|
# Check if it's a file (not a folder)
|
|
369
|
-
if
|
|
366
|
+
if "folder" in file_info:
|
|
370
367
|
print(f"Path is a folder, not a file: {remote_path}")
|
|
371
368
|
return False
|
|
372
369
|
|
|
373
370
|
# Get download URL
|
|
374
|
-
download_url = file_info.get(
|
|
371
|
+
download_url = file_info.get("@microsoft.graph.downloadUrl")
|
|
375
372
|
if not download_url:
|
|
376
373
|
print("No download URL available")
|
|
377
374
|
return False
|
|
@@ -384,10 +381,10 @@ def pull_from_onedrive(remote_path: str, local_path: str) -> bool:
|
|
|
384
381
|
download_response = requests.get(download_url, stream=True)
|
|
385
382
|
download_response.raise_for_status()
|
|
386
383
|
|
|
387
|
-
file_size = int(file_info.get(
|
|
384
|
+
file_size = int(file_info.get("size", 0))
|
|
388
385
|
bytes_downloaded = 0
|
|
389
386
|
|
|
390
|
-
with open(local_file,
|
|
387
|
+
with open(local_file, "wb") as f:
|
|
391
388
|
for chunk in download_response.iter_content(chunk_size=8192):
|
|
392
389
|
if chunk:
|
|
393
390
|
f.write(chunk)
|
|
@@ -415,20 +412,20 @@ def create_remote_directory(remote_path: str) -> bool:
|
|
|
415
412
|
Returns:
|
|
416
413
|
True if successful or already exists, False otherwise
|
|
417
414
|
"""
|
|
418
|
-
if not remote_path or remote_path ==
|
|
415
|
+
if not remote_path or remote_path == "/":
|
|
419
416
|
return True
|
|
420
417
|
|
|
421
418
|
# Ensure remote path starts with /
|
|
422
|
-
if not remote_path.startswith(
|
|
423
|
-
remote_path =
|
|
419
|
+
if not remote_path.startswith("/"):
|
|
420
|
+
remote_path = "/" + remote_path
|
|
424
421
|
|
|
425
422
|
try:
|
|
426
423
|
# Check if directory already exists using specific drive
|
|
427
|
-
encoded_path = quote(remote_path, safe=
|
|
424
|
+
encoded_path = quote(remote_path, safe="/")
|
|
428
425
|
drive_id = get_drive_id()
|
|
429
426
|
endpoint = f"drives/{drive_id}/root:{encoded_path}"
|
|
430
427
|
|
|
431
|
-
response = make_graph_request(
|
|
428
|
+
response = make_graph_request("GET", endpoint)
|
|
432
429
|
|
|
433
430
|
if response.status_code == 200:
|
|
434
431
|
# Directory already exists
|
|
@@ -439,26 +436,22 @@ def create_remote_directory(remote_path: str) -> bool:
|
|
|
439
436
|
|
|
440
437
|
# Create parent directory first
|
|
441
438
|
parent_dir = os.path.dirname(remote_path)
|
|
442
|
-
if parent_dir and parent_dir !=
|
|
439
|
+
if parent_dir and parent_dir != "/":
|
|
443
440
|
if not create_remote_directory(parent_dir):
|
|
444
441
|
return False
|
|
445
442
|
|
|
446
443
|
# Create the directory
|
|
447
444
|
dir_name = os.path.basename(remote_path)
|
|
448
|
-
parent_encoded = quote(parent_dir if parent_dir else
|
|
445
|
+
parent_encoded = quote(parent_dir if parent_dir else "/", safe="/")
|
|
449
446
|
|
|
450
|
-
if parent_dir and parent_dir !=
|
|
447
|
+
if parent_dir and parent_dir != "/":
|
|
451
448
|
endpoint = f"drives/{drive_id}/root:{parent_encoded}:/children"
|
|
452
449
|
else:
|
|
453
450
|
endpoint = f"drives/{drive_id}/root/children"
|
|
454
451
|
|
|
455
|
-
folder_data = {
|
|
456
|
-
"name": dir_name,
|
|
457
|
-
"folder": {},
|
|
458
|
-
"@microsoft.graph.conflictBehavior": "replace"
|
|
459
|
-
}
|
|
452
|
+
folder_data = {"name": dir_name, "folder": {}, "@microsoft.graph.conflictBehavior": "replace"}
|
|
460
453
|
|
|
461
|
-
response = make_graph_request(
|
|
454
|
+
response = make_graph_request("POST", endpoint, json=folder_data)
|
|
462
455
|
|
|
463
456
|
if response.status_code in [200, 201]:
|
|
464
457
|
return True
|
|
@@ -487,20 +480,13 @@ def refresh_access_token() -> Optional[dict[str, Any]]:
|
|
|
487
480
|
print("🔄 Refreshing access token...")
|
|
488
481
|
|
|
489
482
|
# Prepare the token refresh request
|
|
490
|
-
data = {
|
|
491
|
-
'client_id': CLIENT_ID,
|
|
492
|
-
'grant_type': 'refresh_token',
|
|
493
|
-
'refresh_token': refresh_token,
|
|
494
|
-
'scope': 'https://graph.microsoft.com/Files.ReadWrite.All offline_access'
|
|
495
|
-
}
|
|
483
|
+
data = {"client_id": CLIENT_ID, "grant_type": "refresh_token", "refresh_token": refresh_token, "scope": "https://graph.microsoft.com/Files.ReadWrite.All offline_access"}
|
|
496
484
|
|
|
497
485
|
# Add client secret if available (for confidential clients)
|
|
498
486
|
if CLIENT_SECRET and CLIENT_SECRET != "your_client_secret_here":
|
|
499
|
-
data[
|
|
487
|
+
data["client_secret"] = CLIENT_SECRET
|
|
500
488
|
|
|
501
|
-
headers = {
|
|
502
|
-
'Content-Type': 'application/x-www-form-urlencoded'
|
|
503
|
-
}
|
|
489
|
+
headers = {"Content-Type": "application/x-www-form-urlencoded"}
|
|
504
490
|
|
|
505
491
|
try:
|
|
506
492
|
response = requests.post(OAUTH_TOKEN_ENDPOINT, data=data, headers=headers)
|
|
@@ -509,15 +495,15 @@ def refresh_access_token() -> Optional[dict[str, Any]]:
|
|
|
509
495
|
token_data = response.json()
|
|
510
496
|
|
|
511
497
|
# Calculate expiry time (tokens typically last 1 hour)
|
|
512
|
-
expires_in = token_data.get(
|
|
498
|
+
expires_in = token_data.get("expires_in", 3600) # Default to 1 hour
|
|
513
499
|
expiry_time = datetime.now() + timedelta(seconds=expires_in)
|
|
514
500
|
|
|
515
501
|
# Update the cached token configuration
|
|
516
502
|
new_token = {
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
503
|
+
"access_token": token_data["access_token"],
|
|
504
|
+
"token_type": token_data.get("token_type", "Bearer"),
|
|
505
|
+
"refresh_token": token_data.get("refresh_token", refresh_token), # Use new or keep old
|
|
506
|
+
"expiry": expiry_time.isoformat(),
|
|
521
507
|
}
|
|
522
508
|
|
|
523
509
|
# Update the cached config
|
|
@@ -564,7 +550,7 @@ def save_token_to_file(token_data: dict[str, Any], file_path: Optional[str] = No
|
|
|
564
550
|
# Create directory if it doesn't exist
|
|
565
551
|
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
|
566
552
|
|
|
567
|
-
with open(file_path,
|
|
553
|
+
with open(file_path, "w") as f:
|
|
568
554
|
json.dump(token_data, f, indent=2)
|
|
569
555
|
|
|
570
556
|
# Set restrictive permissions (readable only by owner)
|
|
@@ -593,7 +579,7 @@ def load_token_from_file(file_path: Optional[str] = None) -> Optional[dict[str,
|
|
|
593
579
|
|
|
594
580
|
try:
|
|
595
581
|
if os.path.exists(file_path):
|
|
596
|
-
with open(file_path,
|
|
582
|
+
with open(file_path, "r") as f:
|
|
597
583
|
token_data = json.load(f)
|
|
598
584
|
|
|
599
585
|
# Update the cached config token
|
|
@@ -624,14 +610,7 @@ def get_authorization_url() -> str:
|
|
|
624
610
|
"""
|
|
625
611
|
from urllib.parse import urlencode
|
|
626
612
|
|
|
627
|
-
params = {
|
|
628
|
-
'client_id': CLIENT_ID,
|
|
629
|
-
'response_type': 'code',
|
|
630
|
-
'redirect_uri': REDIRECT_URI,
|
|
631
|
-
'response_mode': 'query',
|
|
632
|
-
'scope': 'https://graph.microsoft.com/Files.ReadWrite.All offline_access',
|
|
633
|
-
'state': 'onedrive_auth'
|
|
634
|
-
}
|
|
613
|
+
params = {"client_id": CLIENT_ID, "response_type": "code", "redirect_uri": REDIRECT_URI, "response_mode": "query", "scope": "https://graph.microsoft.com/Files.ReadWrite.All offline_access", "state": "onedrive_auth"}
|
|
635
614
|
|
|
636
615
|
auth_url = f"https://login.microsoftonline.com/common/oauth2/v2.0/authorize?{urlencode(params)}"
|
|
637
616
|
return auth_url
|
|
@@ -648,21 +627,13 @@ def exchange_authorization_code(authorization_code: str) -> Optional[dict[str, A
|
|
|
648
627
|
Returns:
|
|
649
628
|
Token dictionary or None if failed
|
|
650
629
|
"""
|
|
651
|
-
data = {
|
|
652
|
-
'client_id': CLIENT_ID,
|
|
653
|
-
'grant_type': 'authorization_code',
|
|
654
|
-
'code': authorization_code,
|
|
655
|
-
'redirect_uri': REDIRECT_URI,
|
|
656
|
-
'scope': 'https://graph.microsoft.com/Files.ReadWrite.All offline_access'
|
|
657
|
-
}
|
|
630
|
+
data = {"client_id": CLIENT_ID, "grant_type": "authorization_code", "code": authorization_code, "redirect_uri": REDIRECT_URI, "scope": "https://graph.microsoft.com/Files.ReadWrite.All offline_access"}
|
|
658
631
|
|
|
659
632
|
# Add client secret if available
|
|
660
633
|
if CLIENT_SECRET and CLIENT_SECRET != "your_client_secret_here":
|
|
661
|
-
data[
|
|
634
|
+
data["client_secret"] = CLIENT_SECRET
|
|
662
635
|
|
|
663
|
-
headers = {
|
|
664
|
-
'Content-Type': 'application/x-www-form-urlencoded'
|
|
665
|
-
}
|
|
636
|
+
headers = {"Content-Type": "application/x-www-form-urlencoded"}
|
|
666
637
|
|
|
667
638
|
try:
|
|
668
639
|
response = requests.post(OAUTH_TOKEN_ENDPOINT, data=data, headers=headers)
|
|
@@ -671,15 +642,10 @@ def exchange_authorization_code(authorization_code: str) -> Optional[dict[str, A
|
|
|
671
642
|
token_data = response.json()
|
|
672
643
|
|
|
673
644
|
# Calculate expiry time
|
|
674
|
-
expires_in = token_data.get(
|
|
645
|
+
expires_in = token_data.get("expires_in", 3600)
|
|
675
646
|
expiry_time = datetime.now() + timedelta(seconds=expires_in)
|
|
676
647
|
|
|
677
|
-
new_token = {
|
|
678
|
-
'access_token': token_data['access_token'],
|
|
679
|
-
'token_type': token_data.get('token_type', 'Bearer'),
|
|
680
|
-
'refresh_token': token_data['refresh_token'],
|
|
681
|
-
'expiry': expiry_time.isoformat()
|
|
682
|
-
}
|
|
648
|
+
new_token = {"access_token": token_data["access_token"], "token_type": token_data.get("token_type", "Bearer"), "refresh_token": token_data["refresh_token"], "expiry": expiry_time.isoformat()}
|
|
683
649
|
|
|
684
650
|
# Update cached config and save
|
|
685
651
|
global _cached_config
|
|
@@ -793,4 +759,3 @@ if __name__ == "__main__":
|
|
|
793
759
|
|
|
794
760
|
# Uncomment to test with a file
|
|
795
761
|
# push_to_onedrive('/home/alex/Downloads/users.xlsx', '/Documents/users.xlsx')
|
|
796
|
-
|
machineconfig/utils/code.py
CHANGED
|
@@ -1,61 +1,98 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
2
|
import platform
|
|
3
|
+
from typing import Optional
|
|
3
4
|
import subprocess
|
|
4
5
|
from rich.console import Console
|
|
5
6
|
from rich.panel import Panel
|
|
6
7
|
from rich.syntax import Syntax
|
|
7
|
-
from machineconfig.utils.utils2 import randstr
|
|
8
|
-
from machineconfig.utils.path_reduced import P as PathExtended
|
|
9
|
-
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
from machineconfig.utils.utils2 import randstr
|
|
10
|
+
from machineconfig.utils.ve import get_ve_activate_line
|
|
11
|
+
from machineconfig.utils.path_reduced import PathExtended as PathExtended
|
|
12
|
+
from machineconfig.utils.source_of_truth import PROGRAM_PATH
|
|
12
13
|
|
|
13
14
|
|
|
14
|
-
def get_shell_script_executing_python_file(python_file: str, func: Optional[str]
|
|
15
|
-
if func is None:
|
|
16
|
-
|
|
15
|
+
def get_shell_script_executing_python_file(python_file: str, func: Optional[str], ve_path: str, strict_execution: bool = True):
|
|
16
|
+
if func is None:
|
|
17
|
+
exec_line = f"""python {python_file}"""
|
|
18
|
+
else:
|
|
19
|
+
exec_line = f"""python -m fire {python_file} {func}"""
|
|
17
20
|
shell_script = f"""
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
echo "Executing `{exec_line}`"
|
|
22
|
+
{get_ve_activate_line(ve_path)}
|
|
20
23
|
{exec_line}
|
|
21
24
|
deactivate || true
|
|
22
25
|
"""
|
|
23
26
|
|
|
24
27
|
if strict_execution:
|
|
25
|
-
if platform.system() == "Windows":
|
|
26
|
-
|
|
28
|
+
if platform.system() == "Windows":
|
|
29
|
+
shell_script = """$ErrorActionPreference = "Stop" """ + "\n" + shell_script
|
|
30
|
+
if platform.system() in ["Linux", "Darwin"]:
|
|
31
|
+
shell_script = "set -e" + "\n" + shell_script
|
|
27
32
|
|
|
28
|
-
if platform.system() in ["Linux", "Darwin"]:
|
|
33
|
+
if platform.system() in ["Linux", "Darwin"]:
|
|
34
|
+
shell_script = "#!/bin/bash" + "\n" + shell_script # vs #!/usr/bin/env bash
|
|
29
35
|
return shell_script
|
|
30
36
|
|
|
31
37
|
|
|
38
|
+
def get_shell_file_executing_python_script(python_script: str, ve_path: str, verbose: bool = True):
|
|
39
|
+
if verbose:
|
|
40
|
+
python_script = (
|
|
41
|
+
f"""
|
|
42
|
+
code = r'''{python_script}''' """
|
|
43
|
+
+ """
|
|
44
|
+
try:
|
|
45
|
+
from machineconfig.utils.utils import print_code
|
|
46
|
+
print_code(code=code, lexer="python", desc="Python Script")
|
|
47
|
+
except ImportError:
|
|
48
|
+
from rich.console import Console
|
|
49
|
+
from rich.panel import Panel
|
|
50
|
+
console = Console()
|
|
51
|
+
console.print(Panel(f'''📜 PYTHON SCRIPT:\n\n{{code}}''', title="Python Script", expand=False))
|
|
52
|
+
"""
|
|
53
|
+
+ python_script
|
|
54
|
+
)
|
|
55
|
+
python_file = PathExtended.tmp().joinpath("tmp_scripts", "python", randstr() + ".py")
|
|
56
|
+
python_file.parent.mkdir(parents=True, exist_ok=True)
|
|
57
|
+
python_file.write_text(python_script, encoding="utf-8")
|
|
58
|
+
shell_script = get_shell_script_executing_python_file(python_file=str(python_file), func=None, ve_path=ve_path)
|
|
59
|
+
shell_file = write_shell_script_to_file(shell_script)
|
|
60
|
+
return shell_file
|
|
61
|
+
|
|
62
|
+
|
|
32
63
|
def write_shell_script_to_file(shell_script: str):
|
|
33
|
-
if platform.system() in ["Linux", "Darwin"]:
|
|
34
|
-
|
|
35
|
-
|
|
64
|
+
if platform.system() in ["Linux", "Darwin"]:
|
|
65
|
+
suffix = ".sh"
|
|
66
|
+
elif platform.system() == "Windows":
|
|
67
|
+
suffix = ".ps1"
|
|
68
|
+
else:
|
|
69
|
+
raise NotImplementedError(f"Platform {platform.system()} not implemented.")
|
|
36
70
|
shell_file = PathExtended.tmp().joinpath("tmp_scripts", "shell", randstr() + suffix)
|
|
37
71
|
shell_file.parent.mkdir(parents=True, exist_ok=True)
|
|
38
72
|
shell_file.write_text(shell_script, encoding="utf-8")
|
|
39
73
|
return shell_file
|
|
40
74
|
|
|
75
|
+
|
|
41
76
|
# Enhanced print/log/error/exception statements for better clarity and consistency
|
|
42
77
|
# Improved formatting and language of messages
|
|
43
78
|
# Ensured consistent use of f-strings with triple quotes where applicable
|
|
44
79
|
|
|
80
|
+
|
|
45
81
|
def write_shell_script_to_default_program_path(program: str, desc: str, preserve_cwd: bool, display: bool, execute: bool):
|
|
46
82
|
if preserve_cwd:
|
|
47
83
|
if platform.system() == "Windows":
|
|
48
84
|
program = "$orig_path = $pwd\n" + program + "\ncd $orig_path"
|
|
49
85
|
else:
|
|
50
86
|
program = 'orig_path=$(cd -- "." && pwd)\n' + program + '\ncd "$orig_path" || exit'
|
|
51
|
-
if display:
|
|
87
|
+
if display:
|
|
88
|
+
print_code(code=program, lexer="shell", desc=desc, subtitle=str(PROGRAM_PATH))
|
|
52
89
|
PROGRAM_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
53
90
|
PROGRAM_PATH.write_text(program, encoding="utf-8")
|
|
54
91
|
if execute:
|
|
55
92
|
result = subprocess.run(f". {PROGRAM_PATH}", shell=True, capture_output=True, text=True)
|
|
56
93
|
success = result.returncode == 0 and result.stderr == ""
|
|
57
94
|
if not success:
|
|
58
|
-
print(
|
|
95
|
+
print("❌ 🛠️ EXECUTION | Shell script running failed")
|
|
59
96
|
if result.stdout:
|
|
60
97
|
print(f"STDOUT: {result.stdout}")
|
|
61
98
|
if result.stderr:
|
|
@@ -63,30 +100,14 @@ def write_shell_script_to_default_program_path(program: str, desc: str, preserve
|
|
|
63
100
|
print(f"Return code: {result.returncode}")
|
|
64
101
|
return None
|
|
65
102
|
|
|
66
|
-
def get_shell_file_executing_python_script(python_script: str, ve_name: str, verbose: bool=True):
|
|
67
|
-
if verbose:
|
|
68
|
-
python_script = f"""
|
|
69
|
-
code = r'''{python_script}''' """ + """
|
|
70
|
-
try:
|
|
71
|
-
from machineconfig.utils.utils import print_code
|
|
72
|
-
print_code(code=code, lexer="python", desc="Python Script")
|
|
73
|
-
except ImportError:
|
|
74
|
-
from rich.console import Console
|
|
75
|
-
from rich.panel import Panel
|
|
76
|
-
console = Console()
|
|
77
|
-
console.print(Panel(f'''📜 PYTHON SCRIPT:\n\n{{code}}''', title="Python Script", expand=False))
|
|
78
|
-
""" + python_script
|
|
79
|
-
python_file = PathExtended.tmp().joinpath("tmp_scripts", "python", randstr() + ".py")
|
|
80
|
-
python_file.parent.mkdir(parents=True, exist_ok=True)
|
|
81
|
-
python_file.write_text(python_script, encoding="utf-8")
|
|
82
|
-
shell_script = get_shell_script_executing_python_file(python_file=str(python_file), ve_name=ve_name)
|
|
83
|
-
shell_file = write_shell_script_to_file(shell_script)
|
|
84
|
-
return shell_file
|
|
85
103
|
|
|
86
|
-
def print_code(code: str, lexer: str, desc: str, subtitle: str=""):
|
|
104
|
+
def print_code(code: str, lexer: str, desc: str, subtitle: str = ""):
|
|
87
105
|
if lexer == "shell":
|
|
88
|
-
if platform.system() == "Windows":
|
|
89
|
-
|
|
90
|
-
|
|
106
|
+
if platform.system() == "Windows":
|
|
107
|
+
lexer = "powershell"
|
|
108
|
+
elif platform.system() in ["Linux", "Darwin"]:
|
|
109
|
+
lexer = "sh"
|
|
110
|
+
else:
|
|
111
|
+
raise NotImplementedError(f"Platform {platform.system()} not supported for lexer {lexer}")
|
|
91
112
|
console = Console()
|
|
92
113
|
console.print(Panel(Syntax(code=code, lexer=lexer), title=f"📄 {desc}", subtitle=subtitle), style="bold red")
|