machineconfig 1.7__py3-none-any.whl → 1.9__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/__init__.py +4 -2
- machineconfig/jobs/python/check_installations.py +38 -32
- machineconfig/jobs/python/create_bootable_media.py +4 -4
- machineconfig/jobs/python/create_zellij_template.py +3 -2
- machineconfig/jobs/python/python_cargo_build_share.py +14 -9
- machineconfig/jobs/python/python_ve_symlink.py +6 -6
- machineconfig/jobs/python_custom_installers/azuredatastudio.py +36 -0
- machineconfig/jobs/python_custom_installers/bypass_paywall.py +30 -0
- machineconfig/jobs/{python_linux_installers/dev → python_custom_installers}/docker_desktop.py +15 -4
- machineconfig/jobs/python_custom_installers/gh.py +53 -0
- machineconfig/jobs/python_custom_installers/goes.py +35 -0
- machineconfig/jobs/python_custom_installers/helix.py +43 -0
- machineconfig/jobs/python_custom_installers/lvim.py +48 -0
- machineconfig/jobs/python_custom_installers/ngrok.py +39 -0
- machineconfig/jobs/python_custom_installers/nvim.py +48 -0
- machineconfig/jobs/python_custom_installers/vscode.py +45 -0
- machineconfig/jobs/python_custom_installers/wezterm.py +41 -0
- machineconfig/profile/create.py +12 -7
- machineconfig/profile/shell.py +15 -13
- machineconfig/scripts/python/choose_wezterm_theme.py +96 -0
- machineconfig/scripts/python/cloud_copy.py +18 -13
- machineconfig/scripts/python/cloud_mount.py +41 -15
- machineconfig/scripts/python/cloud_repo_sync.py +57 -31
- machineconfig/scripts/python/cloud_sync.py +13 -15
- machineconfig/scripts/python/croshell.py +19 -10
- machineconfig/scripts/python/devops.py +22 -6
- machineconfig/scripts/python/devops_add_identity.py +7 -6
- machineconfig/scripts/python/devops_add_ssh_key.py +10 -9
- machineconfig/scripts/python/devops_backup_retrieve.py +5 -5
- machineconfig/scripts/python/devops_devapps_install.py +24 -19
- machineconfig/scripts/python/devops_update_repos.py +5 -4
- machineconfig/scripts/python/dotfile.py +8 -4
- machineconfig/scripts/python/fire_jobs.py +165 -55
- machineconfig/scripts/python/ftpx.py +18 -8
- machineconfig/scripts/python/mount_nfs.py +13 -10
- machineconfig/scripts/python/mount_nw_drive.py +4 -3
- machineconfig/scripts/python/mount_ssh.py +8 -5
- machineconfig/scripts/python/repos.py +26 -21
- machineconfig/scripts/python/snapshot.py +2 -2
- machineconfig/scripts/python/start_slidev.py +104 -0
- machineconfig/scripts/python/start_terminals.py +1 -1
- machineconfig/setup_windows/wt_and_pwsh/set_pwsh_theme.py +20 -34
- machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +11 -12
- machineconfig/utils/installer.py +177 -217
- machineconfig/utils/scheduling.py +1 -1
- machineconfig/utils/utils.py +107 -54
- machineconfig/utils/ve.py +120 -16
- machineconfig-1.9.dist-info/LICENSE +201 -0
- {machineconfig-1.7.dist-info → machineconfig-1.9.dist-info}/METADATA +155 -140
- machineconfig-1.9.dist-info/RECORD +76 -0
- {machineconfig-1.7.dist-info → machineconfig-1.9.dist-info}/WHEEL +1 -1
- machineconfig/jobs/python_generic_installers/archive/gopass.py +0 -18
- machineconfig/jobs/python_generic_installers/archive/nvim.py +0 -20
- machineconfig/jobs/python_generic_installers/archive/opencommit.py +0 -25
- machineconfig/jobs/python_generic_installers/archive/strongbox.py +0 -33
- machineconfig/jobs/python_generic_installers/dev/__init__.py +0 -0
- machineconfig/jobs/python_linux_installers/archive/__init__.py +0 -0
- machineconfig/jobs/python_linux_installers/archive/bandwhich.py +0 -14
- machineconfig/jobs/python_linux_installers/archive/ranger.py +0 -19
- machineconfig/jobs/python_linux_installers/dev/azure_data_studio.py +0 -21
- machineconfig/jobs/python_linux_installers/dev/bytehound.py +0 -20
- machineconfig/jobs/python_linux_installers/dev/nnn.py +0 -22
- machineconfig/jobs/python_windows_installers/archive/ntop.py +0 -21
- machineconfig/jobs/python_windows_installers/dev/bypass_paywall.py +0 -22
- machineconfig/jobs/python_windows_installers/dev/obs_background_removal_plugin.py +0 -22
- machineconfig/scripts/python/choose_ohmybash_theme.py +0 -31
- machineconfig/scripts/python/choose_ohmyposh_theme.py +0 -57
- machineconfig/utils/pandas_type.py +0 -37
- machineconfig/utils/to_exe.py +0 -7
- machineconfig-1.7.dist-info/RECORD +0 -81
- /machineconfig/jobs/{python_generic_installers/archive → python_custom_installers}/__init__.py +0 -0
- {machineconfig-1.7.dist-info → machineconfig-1.9.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
|
|
2
|
+
"""vs code installer as per https://code.visualstudio.com/docs/setup/linux
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Optional
|
|
6
|
+
import platform
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
config_dict = {
|
|
10
|
+
"repo_url": "CUSTOM",
|
|
11
|
+
"doc": "Visual Studio Code",
|
|
12
|
+
"filename_template_windows_amd_64": "VSCodeSetup-{}.exe",
|
|
13
|
+
"filename_template_linux_amd_64": "code_{}.deb",
|
|
14
|
+
"strip_v": True,
|
|
15
|
+
"exe_name": "code"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def main(version: Optional[str] = None):
|
|
20
|
+
|
|
21
|
+
if platform.system() == 'Linux':
|
|
22
|
+
code = """
|
|
23
|
+
|
|
24
|
+
sudo apt-get install wget gpg
|
|
25
|
+
wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > packages.microsoft.gpg
|
|
26
|
+
sudo install -D -o root -g root -m 644 packages.microsoft.gpg /etc/apt/keyrings/packages.microsoft.gpg
|
|
27
|
+
sudo sh -c 'echo "deb [arch=amd64,arm64,armhf signed-by=/etc/apt/keyrings/packages.microsoft.gpg] https://packages.microsoft.com/repos/code stable main" > /etc/apt/sources.list.d/vscode.list'
|
|
28
|
+
rm -f packages.microsoft.gpg
|
|
29
|
+
|
|
30
|
+
sudo apt install apt-transport-https -y
|
|
31
|
+
sudo apt update
|
|
32
|
+
sudo apt install code -y # or code-insiders
|
|
33
|
+
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
elif platform.system() == 'Windows':
|
|
37
|
+
code = "winget install -e --id Microsoft.VisualStudioCode"
|
|
38
|
+
else:
|
|
39
|
+
raise NotImplementedError(f"Unsupported platform: {platform.system()}")
|
|
40
|
+
_ = version
|
|
41
|
+
return code
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
if __name__ == '__main__':
|
|
45
|
+
pass
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
|
|
2
|
+
"""wezterm installer
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from machineconfig.utils.installer import Installer
|
|
6
|
+
from typing import Optional
|
|
7
|
+
import platform
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
config_dict = {
|
|
11
|
+
"repo_url": "https://github.com/wez/wezterm",
|
|
12
|
+
"doc": "cross-platform terminal emulator",
|
|
13
|
+
"filename_template_windows_amd_64": "WezTerm-windows-{}.zip",
|
|
14
|
+
"filename_template_linux_amd_64": "wezterm-{}.Ubuntu22.04.deb",
|
|
15
|
+
"strip_v": False,
|
|
16
|
+
"exe_name": "wezterm"
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def main(version: Optional[str]):
|
|
21
|
+
if platform.system() == "Windows":
|
|
22
|
+
program = "winget install --Id wez.wezterm --source winget --accept-package-agreements --accept-source-agreements"
|
|
23
|
+
elif platform.system() == "Linux":
|
|
24
|
+
inst = Installer.from_dict(d=config_dict, name="wezterm")
|
|
25
|
+
program = ""
|
|
26
|
+
# as per https://wezfurlong.org/wezterm/install/linux.html#installing-on-ubuntu-and-debian-based-systems
|
|
27
|
+
downloaded, version_to_be_installed = inst.download(version=version)
|
|
28
|
+
_= version_to_be_installed
|
|
29
|
+
|
|
30
|
+
program = f"""
|
|
31
|
+
sudo apt install -y {downloaded}
|
|
32
|
+
rm {downloaded}
|
|
33
|
+
"""
|
|
34
|
+
else:
|
|
35
|
+
raise NotImplementedError("unsupported platform")
|
|
36
|
+
return program
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
if __name__ == "__main__":
|
|
40
|
+
# main(version=None)
|
|
41
|
+
pass
|
machineconfig/profile/create.py
CHANGED
|
@@ -5,8 +5,10 @@ This script Takes away all config files from the computer, place them in one dir
|
|
|
5
5
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
from crocodile.environment import system, UserName # ProgramFiles, WindowsApps # , exe
|
|
10
|
+
from crocodile.meta import Terminal
|
|
11
|
+
from crocodile.file_management import P
|
|
10
12
|
from machineconfig.utils.utils import symlink, LIBRARY_ROOT, REPO_ROOT, display_options
|
|
11
13
|
from machineconfig.profile.shell import create_default_shell_profile
|
|
12
14
|
# import os
|
|
@@ -24,7 +26,7 @@ SYSTEM = system.lower()
|
|
|
24
26
|
# =================== SYMLINKS ====================================
|
|
25
27
|
|
|
26
28
|
|
|
27
|
-
def symlink_contents(source_dir:
|
|
29
|
+
def symlink_contents(source_dir: P, target_dir: P, overwrite: bool = True):
|
|
28
30
|
for a_target in target_dir.expanduser().search("*"):
|
|
29
31
|
symlink(this=source_dir.joinpath(a_target.name), to_this=a_target, prioritize_to_this=overwrite)
|
|
30
32
|
|
|
@@ -58,7 +60,7 @@ def main_symlinks(choice: Optional[str] = None):
|
|
|
58
60
|
else: choice_selected = choice
|
|
59
61
|
|
|
60
62
|
if isinstance(choice_selected, str):
|
|
61
|
-
if str(choice_selected) == "all" and system == "Windows" and not
|
|
63
|
+
if str(choice_selected) == "all" and system == "Windows" and not Terminal.is_user_admin():
|
|
62
64
|
print("*" * 200)
|
|
63
65
|
raise RuntimeError(f"Run terminal as admin and try again, otherwise, there will be too many popups for admin requests and no chance to terminate the program.")
|
|
64
66
|
elif choice_selected == "all":
|
|
@@ -69,8 +71,8 @@ def main_symlinks(choice: Optional[str] = None):
|
|
|
69
71
|
|
|
70
72
|
for program_key in program_keys:
|
|
71
73
|
for file_key, file_map in symlink_mapper[program_key].items():
|
|
72
|
-
this =
|
|
73
|
-
to_this =
|
|
74
|
+
this = P(file_map['this'])
|
|
75
|
+
to_this = P(file_map['to_this'].replace("REPO_ROOT", REPO_ROOT.as_posix()).replace("LIBRARY_ROOT", LIBRARY_ROOT.as_posix()))
|
|
74
76
|
if "contents" in file_map:
|
|
75
77
|
try: symlink_contents(source_dir=this, target_dir=to_this, overwrite=overwrite)
|
|
76
78
|
except Exception as ex: print("Config error: ", program_key, file_key, "missing keys 'this ==> to_this'.", ex)
|
|
@@ -82,12 +84,15 @@ def main_symlinks(choice: Optional[str] = None):
|
|
|
82
84
|
try:
|
|
83
85
|
subprocess.run(f"chmod 700 ~/.ssh/", check=True)
|
|
84
86
|
subprocess.run(f"chmod 700 ~/dotfiles/creds/.ssh/", check=True) # may require sudo
|
|
85
|
-
subprocess.run(f"chmod 600 ~/dotfiles/creds/.ssh
|
|
87
|
+
subprocess.run(f"chmod 600 ~/dotfiles/creds/.ssh/*", check=True)
|
|
86
88
|
except Exception as e:
|
|
87
89
|
ERROR_LIST.append(e)
|
|
88
90
|
print("Caught error", e)
|
|
89
91
|
|
|
90
|
-
if system == "Linux":
|
|
92
|
+
if system == "Linux": Terminal().run(f'chmod +x {LIBRARY_ROOT.joinpath(f"scripts/{system.lower()}")} -R')
|
|
93
|
+
print("\n\n", "*" * 200)
|
|
94
|
+
if len(ERROR_LIST) > 0:
|
|
95
|
+
print("Errors caught: ", ERROR_LIST)
|
|
91
96
|
|
|
92
97
|
|
|
93
98
|
def main(choice: Optional[str] = None):
|
machineconfig/profile/shell.py
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
from crocodile.environment import PathVar
|
|
6
|
-
|
|
6
|
+
from crocodile.core import randstr
|
|
7
|
+
from crocodile.file_management import P
|
|
8
|
+
from crocodile.meta import Terminal
|
|
7
9
|
from machineconfig.utils.utils import LIBRARY_ROOT, REPO_ROOT, display_options
|
|
8
10
|
import platform
|
|
9
11
|
from typing import Optional
|
|
@@ -27,7 +29,7 @@ def create_default_shell_profile():
|
|
|
27
29
|
else:
|
|
28
30
|
profile += "\n" + source + "\n"
|
|
29
31
|
if system == "Linux":
|
|
30
|
-
res =
|
|
32
|
+
res = Terminal().run("cat /proc/version").op
|
|
31
33
|
if "microsoft" in res.lower() or "wsl" in res.lower():
|
|
32
34
|
profile += "\ncd ~" # this is to make sure that the current dir is not in the windows file system, which is terribly slow and its a bad idea to be there anyway.
|
|
33
35
|
profile_path.create(parents_only=True).write_text(profile)
|
|
@@ -35,10 +37,10 @@ def create_default_shell_profile():
|
|
|
35
37
|
|
|
36
38
|
def get_shell_profile_path():
|
|
37
39
|
if system == "Windows":
|
|
38
|
-
res =
|
|
39
|
-
if isinstance(res,
|
|
40
|
+
res = Terminal().run("$profile", shell="pwsh").op2path()
|
|
41
|
+
if isinstance(res, P): profile_path = res
|
|
40
42
|
else: raise ValueError(f"Could not get profile path for Windows. Got {res}")
|
|
41
|
-
elif system == "Linux": profile_path =
|
|
43
|
+
elif system == "Linux": profile_path = P("~/.bashrc").expanduser()
|
|
42
44
|
else: raise ValueError(f"Not implemented for this system {system}")
|
|
43
45
|
print(f"Working on shell profile `{profile_path}`")
|
|
44
46
|
return profile_path
|
|
@@ -49,7 +51,7 @@ def main_env_path(choice: Optional[str] = None, profile_path: Optional[str] = No
|
|
|
49
51
|
dirs = env_path[f'path_{system.lower()}']['extension']
|
|
50
52
|
|
|
51
53
|
print(f"Current PATH: ", "\n============")
|
|
52
|
-
|
|
54
|
+
P.get_env().PATH.print()
|
|
53
55
|
|
|
54
56
|
if choice is None:
|
|
55
57
|
tmp = display_options(msg="Which directory to add?", options=dirs + ["all", "none(EXIT)"], default="none(EXIT)")
|
|
@@ -59,8 +61,8 @@ def main_env_path(choice: Optional[str] = None, profile_path: Optional[str] = No
|
|
|
59
61
|
if choice == "none(EXIT)": return
|
|
60
62
|
|
|
61
63
|
addition = PathVar.append_temporarily(dirs=dirs)
|
|
62
|
-
profile_path_obj =
|
|
63
|
-
profile_path_obj.copy(name=profile_path_obj.name + f".orig_" +
|
|
64
|
+
profile_path_obj = P(profile_path) if isinstance(profile_path, str) else get_shell_profile_path()
|
|
65
|
+
profile_path_obj.copy(name=profile_path_obj.name + f".orig_" + randstr())
|
|
64
66
|
profile_path_obj.modify_text(addition, addition, replace_line=False, notfound_append=True)
|
|
65
67
|
|
|
66
68
|
|
|
@@ -78,13 +80,13 @@ def main_add_sources_to_shell_profile(profile_path: Optional[str] = None, choice
|
|
|
78
80
|
elif choice == "none(EXIT)": return
|
|
79
81
|
|
|
80
82
|
if isinstance(profile_path, str):
|
|
81
|
-
profile_path_obj =
|
|
83
|
+
profile_path_obj = P(profile_path)
|
|
82
84
|
else: profile_path_obj = get_shell_profile_path()
|
|
83
85
|
profile = profile_path_obj.read_text()
|
|
84
86
|
|
|
85
87
|
for a_file in sources:
|
|
86
88
|
tmp = a_file.replace("REPO_ROOT", REPO_ROOT.as_posix()).replace("LIBRARY_ROOT", LIBRARY_ROOT.as_posix())
|
|
87
|
-
file =
|
|
89
|
+
file = P(tmp).collapseuser() # this makes the shell profile interuseable across machines.
|
|
88
90
|
file = file.as_posix() if system == "Linux" else str(file)
|
|
89
91
|
if file not in profile:
|
|
90
92
|
if system == "Windows": profile += f"\n. {file}"
|
|
@@ -104,17 +106,17 @@ def main_add_patches_to_shell_profile(profile_path: Optional[str] = None, choice
|
|
|
104
106
|
elif str(choice) == "all": pass # i.e. patches = patches
|
|
105
107
|
else: patches = [choice]
|
|
106
108
|
|
|
107
|
-
profile_path_obj =
|
|
109
|
+
profile_path_obj = P(profile_path) if isinstance(profile_path, str) else get_shell_profile_path()
|
|
108
110
|
profile = profile_path_obj.read_text()
|
|
109
111
|
|
|
110
112
|
for patch_path in patches:
|
|
111
|
-
patch_path_obj =
|
|
113
|
+
patch_path_obj = P(patch_path)
|
|
112
114
|
patch = patch_path_obj.read_text()
|
|
113
115
|
if patch in profile: print(f"Skipping `{patch_path_obj.name}`; patch already in profile")
|
|
114
116
|
else: profile += "\n" + patch
|
|
115
117
|
|
|
116
118
|
if system == "Linux":
|
|
117
|
-
res =
|
|
119
|
+
res = Terminal().run("cat /proc/version").op
|
|
118
120
|
if "microsoft" in res.lower() or "wsl" in res.lower():
|
|
119
121
|
profile += "\ncd ~" # this is to make sure that the current dir is not in the windows file system, which is terribly slow and its a bad idea to be there anyway.
|
|
120
122
|
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
|
|
2
|
+
"""
|
|
3
|
+
Choose a theme for Wezterm
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from machineconfig.utils.utils import choose_one_option, P
|
|
7
|
+
from typing import Any
|
|
8
|
+
import time
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
schemes_list = [
|
|
12
|
+
'Pro',
|
|
13
|
+
'Spiderman',
|
|
14
|
+
'shades-of-purple',
|
|
15
|
+
'synthwave',
|
|
16
|
+
'Symfonic',
|
|
17
|
+
'PaulMillr',
|
|
18
|
+
'Neon',
|
|
19
|
+
'LiquidCarbonTransparentInverse',
|
|
20
|
+
'Laser',
|
|
21
|
+
'IR_Black',
|
|
22
|
+
'Hurtado',
|
|
23
|
+
'Homebrew',
|
|
24
|
+
'Hipster Green',
|
|
25
|
+
'Firefly Traditional',
|
|
26
|
+
'Elementary',
|
|
27
|
+
'deep',
|
|
28
|
+
'Dark Pastel',
|
|
29
|
+
'Bright Lights',
|
|
30
|
+
'Adventure',
|
|
31
|
+
'Nancy (terminal.sexy)',
|
|
32
|
+
'Bim (Gogh)',
|
|
33
|
+
'BlueDolphin',
|
|
34
|
+
'Borland',
|
|
35
|
+
'Grass (Gogh)',
|
|
36
|
+
'Greenscreen (light) (terminal.sexy)',
|
|
37
|
+
'Grayscale (dark) (terminal.sexy)',
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def main2():
|
|
42
|
+
option = choose_one_option(options=schemes_list, header="Choose a theme for Wezterm", fzf=True)
|
|
43
|
+
set_theme(option)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def set_theme(theme: str):
|
|
47
|
+
txt_lines = P("~/.config/wezterm/wezterm.lua").expanduser().read_text().splitlines()
|
|
48
|
+
res_lines = []
|
|
49
|
+
for line in txt_lines:
|
|
50
|
+
if 'config.color_scheme = ' in line:
|
|
51
|
+
res_lines.append(f"config.color_scheme = '{theme}'")
|
|
52
|
+
else: res_lines.append(line)
|
|
53
|
+
P("~/.config/wezterm/wezterm.lua").expanduser().write_text('\n'.join(res_lines))
|
|
54
|
+
time.sleep(0.1)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def main():
|
|
58
|
+
import curses # not availble on windows: https://docs.python.org/3/howto/curses.html
|
|
59
|
+
# from curses import wrapper
|
|
60
|
+
curses.wrapper(accessory)
|
|
61
|
+
|
|
62
|
+
def accessory(stdscr: Any):
|
|
63
|
+
import curses
|
|
64
|
+
options = schemes_list
|
|
65
|
+
current_option = 0
|
|
66
|
+
page_size = stdscr.getmaxyx()[0] - 1 # curses.LINES - 1 # Number of lines in the terminal, -1 for status line
|
|
67
|
+
|
|
68
|
+
while True:
|
|
69
|
+
stdscr.clear()
|
|
70
|
+
|
|
71
|
+
# Calculate start and end indices for options
|
|
72
|
+
start_index = (current_option // page_size) * page_size
|
|
73
|
+
end_index = start_index + page_size
|
|
74
|
+
|
|
75
|
+
# Display options
|
|
76
|
+
for i, option in enumerate(options[start_index:end_index]):
|
|
77
|
+
if start_index + i == current_option:
|
|
78
|
+
stdscr.addstr(i, 0, option, curses.A_REVERSE) # Highlighted
|
|
79
|
+
else:
|
|
80
|
+
stdscr.addstr(i, 0, option)
|
|
81
|
+
|
|
82
|
+
# Display status line
|
|
83
|
+
status_line = f"Option {current_option+1} of {len(options)}. Use arrow keys to navigate, Enter to select."
|
|
84
|
+
stdscr.addstr(page_size, 0, status_line)
|
|
85
|
+
|
|
86
|
+
# Get key press
|
|
87
|
+
key = stdscr.getch()
|
|
88
|
+
|
|
89
|
+
# Handle key press
|
|
90
|
+
if key == curses.KEY_UP and current_option > 0:
|
|
91
|
+
current_option -= 1
|
|
92
|
+
elif key == curses.KEY_DOWN and current_option < len(options) - 1:
|
|
93
|
+
current_option += 1
|
|
94
|
+
elif key == ord('\n'): # Enter key
|
|
95
|
+
break # Exit the loop
|
|
96
|
+
set_theme(options[current_option])
|
|
@@ -14,12 +14,13 @@ from typing import Optional
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
@RepeatUntilNoException()
|
|
17
|
-
def
|
|
17
|
+
def get_securely_shared_file(url: Optional[str] = None, folder: Optional[str] = None) -> None:
|
|
18
|
+
folder_obj = P.cwd() if folder is None else P(folder)
|
|
18
19
|
|
|
19
20
|
if os.environ.get("DECRYPTION_PASSWORD") is not None:
|
|
20
|
-
pwd = os.environ.get("DECRYPTION_PASSWORD")
|
|
21
|
+
pwd: str = str(os.environ.get("DECRYPTION_PASSWORD"))
|
|
21
22
|
else:
|
|
22
|
-
pwd = getpass.getpass("Enter decryption password: ")
|
|
23
|
+
pwd = getpass.getpass(prompt="Enter decryption password: ")
|
|
23
24
|
|
|
24
25
|
if url is None:
|
|
25
26
|
if os.environ.get("SHARE_URL") is not None:
|
|
@@ -31,10 +32,12 @@ def get_shared_file(url: Optional[str] = None, folder: Optional[str] = None):
|
|
|
31
32
|
from rich.progress import Progress
|
|
32
33
|
with Progress(transient=True) as progress:
|
|
33
34
|
_task = progress.add_task("Downloading ... ", total=None)
|
|
34
|
-
url_obj = P(url).download(folder=
|
|
35
|
+
url_obj = P(url).download(folder=folder_obj)
|
|
35
36
|
with Progress(transient=True) as progress:
|
|
36
37
|
_task = progress.add_task("Decrypting ... ", total=None)
|
|
37
|
-
|
|
38
|
+
tmp_folder = P.tmpdir(prefix="tmp_unzip")
|
|
39
|
+
res = url_obj.decrypt(pwd=pwd, inplace=True).unzip(inplace=True, folder=tmp_folder)
|
|
40
|
+
res.search("*").apply(lambda x: x.move(folder=folder_obj, overwrite=True))
|
|
38
41
|
print(f"Decrypted to {res}")
|
|
39
42
|
|
|
40
43
|
|
|
@@ -44,19 +47,17 @@ def arg_parser() -> None:
|
|
|
44
47
|
# positional argument
|
|
45
48
|
parser.add_argument("source", help="file/folder path to be taken from here.")
|
|
46
49
|
parser.add_argument("target", help="file/folder path to be be sent to here.")
|
|
47
|
-
|
|
48
|
-
# parser.add_argument("--recursive", "-r", help="Send recursively.", action="store_true") # default is False
|
|
49
|
-
parser.add_argument("--encrypt", "-e", help="Decrypt after receiving.", action="store_true", default=ArgsDefaults.encrypt)
|
|
50
|
-
parser.add_argument("--zip", "-z", help="unzip after receiving.", action="store_true", default=ArgsDefaults.zip_)
|
|
50
|
+
|
|
51
51
|
parser.add_argument("--overwrite", "-w", help="Overwrite existing file.", action="store_true", default=ArgsDefaults.overwrite)
|
|
52
52
|
parser.add_argument("--share", "-s", help="Share file / directory", action="store_true", default=ArgsDefaults.share)
|
|
53
|
-
# optional argument
|
|
54
53
|
parser.add_argument("--rel2home", "-r", help="Relative to `myhome` folder", action="store_true", default=ArgsDefaults.rel2home)
|
|
55
54
|
parser.add_argument("--root", "-R", help="Remote root. None is the default, unless rel2home is raied, making the default `myhome`.", default=ArgsDefaults.root)
|
|
56
|
-
parser.add_argument("--os_specific", "-o", help="OS specific path (relevant only when relative flag is raised as well.", action="store_true", default=ArgsDefaults.os_specific)
|
|
57
55
|
|
|
58
56
|
parser.add_argument("--key", "-k", help="Key for encryption", type=str, default=ArgsDefaults.key)
|
|
59
57
|
parser.add_argument("--pwd", "-p", help="Password for encryption", type=str, default=ArgsDefaults.pwd)
|
|
58
|
+
parser.add_argument("--encrypt", "-e", help="Decrypt after receiving.", action="store_true", default=ArgsDefaults.encrypt)
|
|
59
|
+
parser.add_argument("--zip", "-z", help="unzip after receiving.", action="store_true", default=ArgsDefaults.zip_)
|
|
60
|
+
parser.add_argument("--os_specific", "-o", help="choose path specific for this OS.", action="store_true", default=ArgsDefaults.os_specific)
|
|
60
61
|
|
|
61
62
|
parser.add_argument("--config", "-c", help="path to cloud.json file.", default=None)
|
|
62
63
|
|
|
@@ -67,7 +68,7 @@ def arg_parser() -> None:
|
|
|
67
68
|
args_obj = Args(**args_dict)
|
|
68
69
|
Struct(args_obj.__dict__).print(as_config=True, title=f"CLI config")
|
|
69
70
|
|
|
70
|
-
if args_obj.config == "ss" and (source.startswith("http") or source.startswith("bit.ly")): return
|
|
71
|
+
if args_obj.config == "ss" and (source.startswith("http") or source.startswith("bit.ly")): return get_securely_shared_file(url=source, folder=target)
|
|
71
72
|
if args_obj.rel2home is True and args_obj.root is None: args_obj.root = "myhome"
|
|
72
73
|
|
|
73
74
|
cloud, source, target = parse_cloud_source_target(args=args_obj, source=source, target=target)
|
|
@@ -84,7 +85,11 @@ def arg_parser() -> None:
|
|
|
84
85
|
zip=args_obj.zip, encrypt=args_obj.encrypt, pwd=args_obj.pwd,
|
|
85
86
|
rel2home=args_obj.rel2home, root=args_obj.root, os_specific=args_obj.os_specific, strict=False,
|
|
86
87
|
share=args_obj.share)
|
|
87
|
-
if args_obj.share:
|
|
88
|
+
if args_obj.share:
|
|
89
|
+
print(res.as_url_str())
|
|
90
|
+
if P(source).is_dir(): share_url_path = P(source).joinpath(".share_url")
|
|
91
|
+
else: share_url_path = P(source).with_suffix(".share_url")
|
|
92
|
+
share_url_path.write_text(res.as_url_str())
|
|
88
93
|
else: raise ValueError(f"Cloud `{cloud}` not found in source or target.")
|
|
89
94
|
|
|
90
95
|
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
"""Cloud mount script
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
from machineconfig.utils.utils import PROGRAM_PATH,
|
|
5
|
+
|
|
6
|
+
from machineconfig.utils.utils import PROGRAM_PATH, choose_one_option
|
|
7
|
+
from crocodile.file_management import P, Read
|
|
8
|
+
|
|
7
9
|
import platform
|
|
8
10
|
import argparse
|
|
9
11
|
from typing import Optional
|
|
@@ -13,17 +15,17 @@ DEFAULT_MOUNT = "~/data/rclone"
|
|
|
13
15
|
|
|
14
16
|
|
|
15
17
|
def get_rclone_config():
|
|
16
|
-
if platform.system() == "Windows": config =
|
|
17
|
-
elif platform.system() == "Linux": config =
|
|
18
|
+
if platform.system() == "Windows": config = Read.ini(P.home().joinpath("AppData/Roaming/rclone/rclone.conf"))
|
|
19
|
+
elif platform.system() == "Linux": config = Read.ini(P.home().joinpath(".config/rclone/rclone.conf"))
|
|
18
20
|
else: raise ValueError("unsupported platform")
|
|
19
21
|
return config
|
|
20
22
|
|
|
21
23
|
|
|
22
24
|
def get_mprocs_mount_txt(cloud: str, rclone_cmd: str, cloud_brand: str): # cloud_brand = config[cloud]["type"]
|
|
23
|
-
# config =
|
|
25
|
+
# config = Read.ini(P.home().joinpath(".config/rclone/rclone.conf"))
|
|
24
26
|
header = f"{' ' + cloud + ' | ' + cloud_brand + ' '}".center(50, "=")
|
|
25
27
|
if platform.system() == "Windows":
|
|
26
|
-
sub_text_path =
|
|
28
|
+
sub_text_path = P.tmpfile(suffix=".ps1").write_text(f"""
|
|
27
29
|
echo "{header}"
|
|
28
30
|
iex 'rclone about {cloud}:'
|
|
29
31
|
echo 'See {DEFAULT_MOUNT}/{cloud} for the mounted cloud'
|
|
@@ -40,29 +42,52 @@ mprocs "echo 'see {DEFAULT_MOUNT}/{cloud} for the mounted cloud'; rclone about {
|
|
|
40
42
|
return txt
|
|
41
43
|
|
|
42
44
|
|
|
43
|
-
def mount(cloud: Optional[str]
|
|
44
|
-
|
|
45
|
+
def mount(cloud: Optional[str], network: Optional[str], destination: Optional[str]) -> None:
|
|
45
46
|
config = get_rclone_config()
|
|
46
47
|
if cloud is None:
|
|
47
|
-
res =
|
|
48
|
+
res = choose_one_option(msg="which cloud", options=config.sections(), header="CLOUD MOUNT", default=None)
|
|
48
49
|
if type(res) is str: cloud = res
|
|
49
50
|
else: raise ValueError("no cloud selected")
|
|
50
|
-
|
|
51
|
+
|
|
51
52
|
if network is None:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
if destination is None:
|
|
54
|
+
mount_loc = P(DEFAULT_MOUNT).expanduser().joinpath(cloud)
|
|
55
|
+
else:
|
|
56
|
+
mount_loc = P(destination)
|
|
57
|
+
|
|
58
|
+
if platform.system() == "Windows":
|
|
59
|
+
mount_loc.parent.create()
|
|
60
|
+
elif platform.system() == "Linux":
|
|
61
|
+
try: mount_loc.create()
|
|
62
|
+
except (FileExistsError, OSError) as err:
|
|
63
|
+
# We need a umount command here.
|
|
64
|
+
print(err)
|
|
65
|
+
pass
|
|
55
66
|
else: raise ValueError("unsupported platform")
|
|
67
|
+
|
|
56
68
|
elif network and platform.system() == "Windows": mount_loc = "X: --network-mode"
|
|
57
69
|
else: raise ValueError("network mount only supported on windows")
|
|
58
70
|
|
|
59
71
|
mount_cmd = f"rclone mount {cloud}: {mount_loc} --vfs-cache-mode full --file-perms=0777"
|
|
60
72
|
|
|
61
73
|
# txt = get_mprocs_mount_txt(cloud, mount_cmd)
|
|
62
|
-
if platform.system() == "Windows":
|
|
74
|
+
if platform.system() == "Windows":
|
|
75
|
+
|
|
76
|
+
txt = f"""
|
|
63
77
|
wt --window 0 --profile "Windows PowerShell" --startingDirectory "$HOME/data/rclone" `; split-pane --horizontal --profile "Command Prompt" --size 0.2 powershell -Command "{mount_cmd}" `; split-pane --vertical --profile "Windows PowerShell" --size 0.2 powershell -NoExit -Command "rclone about {cloud}:" `; move-focus up
|
|
64
78
|
"""
|
|
65
79
|
elif platform.system() == "Linux": txt = f"""
|
|
80
|
+
|
|
81
|
+
ZJ_SESSIONS=$(zellij list-sessions)
|
|
82
|
+
|
|
83
|
+
if [[ "${{ZJ_SESSIONS}}" != *"(current)"* ]]; then
|
|
84
|
+
echo "Not inside a zellij session ..."
|
|
85
|
+
echo '{mount_cmd} --daemon'
|
|
86
|
+
# exit 1
|
|
87
|
+
|
|
88
|
+
{mount_cmd} --daemon
|
|
89
|
+
fi
|
|
90
|
+
|
|
66
91
|
zellij run --direction down --name rclone -- {mount_cmd}
|
|
67
92
|
sleep 1; zellij action resize decrease down
|
|
68
93
|
sleep 0.2; zellij action resize decrease up
|
|
@@ -90,9 +115,10 @@ zellij action move-focus up
|
|
|
90
115
|
def main():
|
|
91
116
|
parser = argparse.ArgumentParser(description='mount cloud')
|
|
92
117
|
parser.add_argument('cloud', nargs='?', type=str, default=None, help='cloud to mount')
|
|
118
|
+
parser.add_argument('destination', nargs='?', type=str, default=None, help='destination to mount')
|
|
93
119
|
parser.add_argument('--network', type=str, default=None, help='mount network drive')
|
|
94
120
|
args = parser.parse_args()
|
|
95
|
-
mount(cloud=args.cloud, network=args.network)
|
|
121
|
+
mount(cloud=args.cloud, network=args.network, destination=args.destination)
|
|
96
122
|
|
|
97
123
|
|
|
98
124
|
if __name__ == '__main__':
|