machineconfig 1.7__py3-none-any.whl → 1.8__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 +2 -2
- machineconfig/jobs/python/check_installations.py +37 -31
- 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_linux_installers/dev → script_installer}/azure_data_studio.py +6 -5
- machineconfig/jobs/{python_windows_installers/dev → script_installer}/bypass_paywall.py +5 -4
- machineconfig/jobs/script_installer/code.py +34 -0
- machineconfig/jobs/{python_linux_installers/dev → script_installer}/docker_desktop.py +2 -2
- machineconfig/jobs/script_installer/ngrok.py +29 -0
- machineconfig/jobs/script_installer/skim.py +21 -0
- machineconfig/jobs/script_installer/wezterm.py +34 -0
- machineconfig/profile/create.py +8 -6
- machineconfig/profile/shell.py +15 -13
- machineconfig/scripts/python/cloud_copy.py +14 -13
- machineconfig/scripts/python/cloud_mount.py +27 -11
- machineconfig/scripts/python/cloud_repo_sync.py +32 -14
- machineconfig/scripts/python/cloud_sync.py +9 -9
- machineconfig/scripts/python/croshell.py +3 -3
- 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 +13 -14
- machineconfig/scripts/python/devops_update_repos.py +5 -4
- machineconfig/scripts/python/dotfile.py +8 -4
- machineconfig/scripts/python/fire_jobs.py +95 -24
- machineconfig/scripts/python/ftpx.py +1 -1
- 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 +21 -20
- machineconfig/scripts/python/snapshot.py +2 -2
- machineconfig/scripts/python/start_slidev.py +104 -0
- 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 +96 -204
- machineconfig/utils/scheduling.py +1 -1
- machineconfig/utils/utils.py +102 -51
- machineconfig/utils/ve.py +96 -13
- {machineconfig-1.7.dist-info → machineconfig-1.8.dist-info}/METADATA +8 -8
- machineconfig-1.8.dist-info/RECORD +70 -0
- 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/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/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 → script_installer}/__init__.py +0 -0
- {machineconfig-1.7.dist-info → machineconfig-1.8.dist-info}/WHEEL +0 -0
- {machineconfig-1.7.dist-info → machineconfig-1.8.dist-info}/top_level.txt +0 -0
|
@@ -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):
|
|
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,16 @@ 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
60
|
|
|
61
61
|
parser.add_argument("--config", "-c", help="path to cloud.json file.", default=None)
|
|
62
62
|
|
|
@@ -67,7 +67,7 @@ def arg_parser() -> None:
|
|
|
67
67
|
args_obj = Args(**args_dict)
|
|
68
68
|
Struct(args_obj.__dict__).print(as_config=True, title=f"CLI config")
|
|
69
69
|
|
|
70
|
-
if args_obj.config == "ss" and (source.startswith("http") or source.startswith("bit.ly")): return
|
|
70
|
+
if args_obj.config == "ss" and (source.startswith("http") or source.startswith("bit.ly")): return get_securely_shared_file(url=source, folder=target)
|
|
71
71
|
if args_obj.rel2home is True and args_obj.root is None: args_obj.root = "myhome"
|
|
72
72
|
|
|
73
73
|
cloud, source, target = parse_cloud_source_target(args=args_obj, source=source, target=target)
|
|
@@ -84,7 +84,8 @@ def arg_parser() -> None:
|
|
|
84
84
|
zip=args_obj.zip, encrypt=args_obj.encrypt, pwd=args_obj.pwd,
|
|
85
85
|
rel2home=args_obj.rel2home, root=args_obj.root, os_specific=args_obj.os_specific, strict=False,
|
|
86
86
|
share=args_obj.share)
|
|
87
|
-
if args_obj.share:
|
|
87
|
+
if args_obj.share:
|
|
88
|
+
print(res.as_url_str())
|
|
88
89
|
else: raise ValueError(f"Cloud `{cloud}` not found in source or target.")
|
|
89
90
|
|
|
90
91
|
|
|
@@ -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,19 +42,23 @@ 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]
|
|
45
|
+
def mount(cloud: Optional[str], network: Optional[str], destination: Optional[str]) -> None:
|
|
44
46
|
|
|
45
47
|
config = get_rclone_config()
|
|
46
48
|
if cloud is None:
|
|
47
|
-
res =
|
|
49
|
+
res = choose_one_option(msg="which cloud", options=config.sections(), header="CLOUD MOUNT", default=None)
|
|
48
50
|
if type(res) is str: cloud = res
|
|
49
51
|
else: raise ValueError("no cloud selected")
|
|
50
|
-
|
|
52
|
+
|
|
53
|
+
|
|
51
54
|
if network is None:
|
|
52
|
-
mount_loc =
|
|
55
|
+
if destination is None: mount_loc = P(DEFAULT_MOUNT).expanduser().joinpath(cloud)
|
|
56
|
+
else: mount_loc = P(destination)
|
|
57
|
+
|
|
53
58
|
if platform.system() == "Windows": mount_loc.parent.create()
|
|
54
59
|
elif platform.system() == "Linux": mount_loc.create()
|
|
55
60
|
else: raise ValueError("unsupported platform")
|
|
61
|
+
|
|
56
62
|
elif network and platform.system() == "Windows": mount_loc = "X: --network-mode"
|
|
57
63
|
else: raise ValueError("network mount only supported on windows")
|
|
58
64
|
|
|
@@ -63,6 +69,15 @@ def mount(cloud: Optional[str] = None, network: Optional[str] = None) -> None:
|
|
|
63
69
|
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
70
|
"""
|
|
65
71
|
elif platform.system() == "Linux": txt = f"""
|
|
72
|
+
|
|
73
|
+
ZJ_SESSIONS=$(zellij list-sessions)
|
|
74
|
+
|
|
75
|
+
if [[ "${{ZJ_SESSIONS}}" != *"(current)"* ]]; then
|
|
76
|
+
echo "Not inside a zellij session ..."
|
|
77
|
+
echo '{mount_cmd}'
|
|
78
|
+
exit 1
|
|
79
|
+
fi
|
|
80
|
+
|
|
66
81
|
zellij run --direction down --name rclone -- {mount_cmd}
|
|
67
82
|
sleep 1; zellij action resize decrease down
|
|
68
83
|
sleep 0.2; zellij action resize decrease up
|
|
@@ -90,9 +105,10 @@ zellij action move-focus up
|
|
|
90
105
|
def main():
|
|
91
106
|
parser = argparse.ArgumentParser(description='mount cloud')
|
|
92
107
|
parser.add_argument('cloud', nargs='?', type=str, default=None, help='cloud to mount')
|
|
108
|
+
parser.add_argument('destination', nargs='?', type=str, default=None, help='destination to mount')
|
|
93
109
|
parser.add_argument('--network', type=str, default=None, help='mount network drive')
|
|
94
110
|
args = parser.parse_args()
|
|
95
|
-
mount(cloud=args.cloud, network=args.network)
|
|
111
|
+
mount(cloud=args.cloud, network=args.network, destination=args.destination)
|
|
96
112
|
|
|
97
113
|
|
|
98
114
|
if __name__ == '__main__':
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
|
|
2
2
|
"""utils"""
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
from machineconfig.utils.utils import CONFIG_PATH, DEFAULTS_PATH, write_shell_script, get_shell_file_executing_python_script
|
|
6
|
+
from crocodile.file_management import P, Read, install_n_import
|
|
7
|
+
from crocodile.core import randstr
|
|
8
|
+
from crocodile.meta import Terminal
|
|
6
9
|
import argparse
|
|
7
10
|
import platform
|
|
8
11
|
from typing import Optional
|
|
@@ -10,10 +13,23 @@ from typing import Optional
|
|
|
10
13
|
# import subprocess
|
|
11
14
|
|
|
12
15
|
|
|
13
|
-
def get_wt_cmd(wd1:
|
|
14
|
-
|
|
16
|
+
def get_wt_cmd(wd1: P, wd2: P) -> str:
|
|
17
|
+
lines = [
|
|
18
|
+
f"""wt --window 0 new-tab --profile pwsh --title "gitdiff" --tabColor `#3b04d1 --startingDirectory {wd1} ` --colorScheme "Solarized Dark" """,
|
|
19
|
+
f"""split-pane --horizontal --profile pwsh --startingDirectory {wd2} --size 0.5 --colorScheme "Tango Dark" -- pwsh -Interactive """
|
|
20
|
+
]
|
|
21
|
+
return " `; ".join(lines)
|
|
15
22
|
|
|
16
|
-
def get_zellij_cmd(wd1:
|
|
23
|
+
def get_zellij_cmd(wd1: P, wd2: P) -> str:
|
|
24
|
+
lines = [f""" zellij action new-tab --name gitdiff""",
|
|
25
|
+
f"""zellij action new-pane --direction down --name local --cwd ./data """,
|
|
26
|
+
f"""zellij action write-chars "cd '{wd1}'; git status" """,
|
|
27
|
+
f"""zellij action move-focus up; zellij action close-pane """,
|
|
28
|
+
f"""zellij action new-pane --direction down --name remote --cwd code """,
|
|
29
|
+
f"""zellij action write-chars "cd '{wd2}' """,
|
|
30
|
+
f"""git status" """
|
|
31
|
+
]
|
|
32
|
+
return "; ".join(lines)
|
|
17
33
|
|
|
18
34
|
|
|
19
35
|
def args_parser():
|
|
@@ -25,7 +41,7 @@ def args_parser():
|
|
|
25
41
|
# parser.add_argument("--share", help="Repository path, defaults to cwd.", action="store_true", default=False)
|
|
26
42
|
|
|
27
43
|
parser.add_argument("--cloud", "-c", help="rclone cloud profile name.", default=None)
|
|
28
|
-
parser.add_argument("--message", "-m", help="Commit Message", default=f"new message {
|
|
44
|
+
parser.add_argument("--message", "-m", help="Commit Message", default=f"new message {randstr()}")
|
|
29
45
|
parser.add_argument("--skip_confirmation", "-s", help="Skip confirmation.", action="store_true", default=False)
|
|
30
46
|
# parser.add_argument("--key", "-k", help="Key for encryption", default=None)
|
|
31
47
|
parser.add_argument("--pwd", "-p", help="Password for encryption", default=None)
|
|
@@ -41,15 +57,17 @@ def args_parser():
|
|
|
41
57
|
|
|
42
58
|
def main(cloud: Optional[str] = None, path: Optional[str] = None, message: Optional[str] = None, skip_confirmation: bool = False, pwd: Optional[str] = None, push: bool = True):
|
|
43
59
|
if cloud is None:
|
|
44
|
-
try:
|
|
60
|
+
try:
|
|
61
|
+
cloud_resolved = Read.ini(DEFAULTS_PATH)['general']['rclone_config_name']
|
|
62
|
+
print(f"⚠️ Using default cloud: `{cloud_resolved}` from {DEFAULTS_PATH} ⚠️")
|
|
45
63
|
except FileNotFoundError:
|
|
46
64
|
print(f"No cloud profile found @ {DEFAULTS_PATH}, please set one up or provide one via the --cloud flag.")
|
|
47
65
|
return ""
|
|
48
66
|
else: cloud_resolved = cloud
|
|
49
|
-
# repo_root =
|
|
50
|
-
repo_root =
|
|
51
|
-
repo_obj =
|
|
52
|
-
repo_root =
|
|
67
|
+
# repo_root = P(args.repo).expanduser().absolute()
|
|
68
|
+
repo_root = P.cwd() if path is None else P(path).expanduser().absolute()
|
|
69
|
+
repo_obj = install_n_import("git", "gitpython").Repo(repo_root, search_parent_directories=True)
|
|
70
|
+
repo_root = P(repo_obj.working_dir) # cwd might have been in a sub directory of repo_root, so its better to redefine it.
|
|
53
71
|
CONFIG_PATH.joinpath("remote").create()
|
|
54
72
|
repo_sync_root = CONFIG_PATH.joinpath("remote", repo_root.rel2home()) # .delete(sure=True)
|
|
55
73
|
try:
|
|
@@ -60,7 +78,7 @@ def main(cloud: Optional[str] = None, path: Optional[str] = None, message: Optio
|
|
|
60
78
|
print("Remote does not exist, creating it and exiting ... ")
|
|
61
79
|
repo_root.to_cloud(cloud=cloud_resolved, zip=True, encrypt=True, rel2home=True, pwd=pwd, os_specific=False)
|
|
62
80
|
return ""
|
|
63
|
-
repo_sync_obj =
|
|
81
|
+
repo_sync_obj = install_n_import("git", "gitpython").Repo(repo_sync_root)
|
|
64
82
|
if repo_sync_obj.is_dirty():
|
|
65
83
|
print("=" * 50, '\n', f"WRANING: the remote `{repo_sync_root}` is dirty, please commit or stash changes before proceeding.", '\n', "=" * 50)
|
|
66
84
|
|
|
@@ -84,7 +102,7 @@ git pull originEnc master
|
|
|
84
102
|
|
|
85
103
|
"""
|
|
86
104
|
suffix = '.ps1' if platform.system() == 'Windows' else '.sh'
|
|
87
|
-
res =
|
|
105
|
+
res = Terminal().run(f". {P.tmpfile(suffix=suffix).write_text(script)}", shell="powershell").capture().print()
|
|
88
106
|
|
|
89
107
|
if res.is_successful(strict_err=True, strict_returcode=True):
|
|
90
108
|
print("\n", "Pull succeeded, removing originEnc, the local copy of remote & pushing merged repo_root to remote ... ")
|
|
@@ -122,8 +140,8 @@ func(remote_repo=r'{repo_sync_root.str}', local_repo=r'{repo_root.str}', cloud=r
|
|
|
122
140
|
|
|
123
141
|
|
|
124
142
|
def delete_remote_repo_copy_and_push_local(remote_repo: str, local_repo: str, cloud: str):
|
|
125
|
-
repo_sync_root =
|
|
126
|
-
repo_root_path =
|
|
143
|
+
repo_sync_root = P(remote_repo).expanduser().absolute()
|
|
144
|
+
repo_root_path = P(local_repo).expanduser().absolute()
|
|
127
145
|
repo_sync_root.delete(sure=True)
|
|
128
146
|
from git.remote import Remote
|
|
129
147
|
from git.repo import Repo
|
|
@@ -39,8 +39,6 @@ from pydantic import ConfigDict
|
|
|
39
39
|
|
|
40
40
|
@dataclass(config=ConfigDict(extra="forbid", frozen=True))
|
|
41
41
|
class Args():
|
|
42
|
-
# source: str
|
|
43
|
-
# target: str
|
|
44
42
|
cloud: Optional[str] = None
|
|
45
43
|
|
|
46
44
|
zip: bool = ArgsDefaults.zip_
|
|
@@ -81,12 +79,14 @@ def get_secure_share_cloud_config(interactive: bool = True) -> Args:
|
|
|
81
79
|
cloud = default_cloud
|
|
82
80
|
else:
|
|
83
81
|
try:
|
|
84
|
-
|
|
82
|
+
default_cloud__ = Read.ini(DEFAULTS_PATH)['general']['rclone_config_name']
|
|
85
83
|
except Exception:
|
|
86
|
-
|
|
87
|
-
if
|
|
88
|
-
|
|
89
|
-
|
|
84
|
+
default_cloud__ = 'No default cloud found.'
|
|
85
|
+
if default_cloud__ == 'No default cloud found.' or interactive:
|
|
86
|
+
# assert default_cloud is not None
|
|
87
|
+
cloud = input(f"Enter cloud name (default {default_cloud__}): ") or default_cloud__
|
|
88
|
+
else:
|
|
89
|
+
cloud = default_cloud__
|
|
90
90
|
|
|
91
91
|
default_password_path = P.home().joinpath("dotfiles/creds/passwords/quick_password")
|
|
92
92
|
if default_password_path.exists():
|
|
@@ -99,7 +99,7 @@ def get_secure_share_cloud_config(interactive: bool = True) -> Args:
|
|
|
99
99
|
res = Args(cloud=cloud,
|
|
100
100
|
pwd=pwd, encrypt=True,
|
|
101
101
|
zip=True, overwrite=True, share=True,
|
|
102
|
-
rel2home=True, root="
|
|
102
|
+
rel2home=True, root="myshare", os_specific=False,)
|
|
103
103
|
Struct(res.__dict__).print(as_config=True, title=f"⚠️ Using SecureShare cloud config")
|
|
104
104
|
return res
|
|
105
105
|
|
|
@@ -215,7 +215,7 @@ def args_parser():
|
|
|
215
215
|
parser.add_argument("--transfers", "-t", help="Number of threads in syncing.", default=10) # default is False
|
|
216
216
|
parser.add_argument("--root", "-R", help="Remote root.", default="myhome") # default is False
|
|
217
217
|
|
|
218
|
-
|
|
218
|
+
parser.add_argument("--key", "-k", help="Key for encryption", default=None)
|
|
219
219
|
parser.add_argument("--pwd", "-P", help="Password for encryption", default=None)
|
|
220
220
|
parser.add_argument("--encrypt", "-e", help="Decrypt after receiving.", action="store_true") # default is False
|
|
221
221
|
parser.add_argument("--zip", "-z", help="unzip after receiving.", action="store_true") # default is False
|
|
@@ -34,7 +34,7 @@ def get_read_data_pycode(path: str):
|
|
|
34
34
|
p = P(r\'{path}\').absolute()
|
|
35
35
|
try:
|
|
36
36
|
dat = p.readit()
|
|
37
|
-
if type(dat) ==
|
|
37
|
+
if type(dat) == Struct: dat.print(as_config=True, title=p.name)
|
|
38
38
|
else: print(f"Succcesfully read the file {{p.name}}")
|
|
39
39
|
except Exception as e:
|
|
40
40
|
print(e)
|
|
@@ -67,7 +67,7 @@ def build_parser():
|
|
|
67
67
|
parser.add_argument("--fzf", "-F", help="search with fuzzy finder for python scripts and run them", action="store_true", default=False)
|
|
68
68
|
|
|
69
69
|
# OPTIONAL KEYWORD
|
|
70
|
-
parser.add_argument("--
|
|
70
|
+
parser.add_argument("--ve", "-v", help="virtual enviroment to use, defaults to activated ve, if existed, else ve.", default=None)
|
|
71
71
|
parser.add_argument("--profile", "-P", help="ipython profile to use, defaults to default profile.", default=None)
|
|
72
72
|
parser.add_argument("--read", "-r", dest="read", help="read a binary file.", default="")
|
|
73
73
|
parser.add_argument("--file", "-f", dest="file", help="python file path to interpret", default="")
|
|
@@ -131,7 +131,7 @@ print_logo(logo="crocodile")
|
|
|
131
131
|
pyfile.write_text(total_program, encoding='utf-8')
|
|
132
132
|
if profile is None: profile = "default"
|
|
133
133
|
|
|
134
|
-
ve = get_ve_profile(P(file)) if args.
|
|
134
|
+
ve = get_ve_profile(P(file)) if args.ve is None else str(args.ve)
|
|
135
135
|
|
|
136
136
|
final_program = f"""
|
|
137
137
|
# deactivate
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
|
|
2
|
+
|
|
3
|
+
|
|
2
4
|
"""devops
|
|
3
5
|
"""
|
|
4
|
-
|
|
5
|
-
from platform import system
|
|
6
|
-
# import subprocess
|
|
7
|
-
# import crocodile.toolbox as tb
|
|
6
|
+
from crocodile.file_management import P
|
|
8
7
|
from machineconfig.utils.utils import display_options, PROGRAM_PATH, write_shell_script
|
|
8
|
+
from platform import system
|
|
9
9
|
from enum import Enum
|
|
10
10
|
from typing import Optional
|
|
11
11
|
|
|
@@ -48,8 +48,24 @@ def main(which: Optional[str] = None):
|
|
|
48
48
|
program = helper.main()
|
|
49
49
|
|
|
50
50
|
elif choice_key == Options.ve.value:
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
program = ""
|
|
52
|
+
reply: bool = False
|
|
53
|
+
if P.cwd().joinpath(".ve.ini").exists():
|
|
54
|
+
reply = input("Detected .ve.ini file. Do you want to use it to build ve? (y/[n]): ") == "y"
|
|
55
|
+
if reply:
|
|
56
|
+
from machineconfig.utils.ve import get_ve_install_script_from_specs
|
|
57
|
+
program_win = get_ve_install_script_from_specs(repo_root=P.cwd().str, system="Windows")
|
|
58
|
+
program_lin = get_ve_install_script_from_specs(repo_root=P.cwd().str, system="Linux")
|
|
59
|
+
install_reply = input("Proceed with installation? (y/[n]): ") == "y"
|
|
60
|
+
if not install_reply: program = ""
|
|
61
|
+
else:
|
|
62
|
+
if system() == "Windows": program = program_win
|
|
63
|
+
elif system() == "Linux": program = program_lin
|
|
64
|
+
else: raise ValueError(f"Unknown system: {system()}")
|
|
65
|
+
|
|
66
|
+
if not reply:
|
|
67
|
+
from machineconfig.utils.ve import get_ve_install_script
|
|
68
|
+
program = get_ve_install_script()
|
|
53
69
|
|
|
54
70
|
elif choice_key == Options.cli_install.value:
|
|
55
71
|
import machineconfig.scripts.python.devops_devapps_install as helper
|
|
@@ -2,20 +2,21 @@
|
|
|
2
2
|
"""ID
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
# from platform import system
|
|
7
|
+
from crocodile.file_management import P
|
|
7
8
|
from machineconfig.utils.utils import display_options
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
def main():
|
|
11
|
-
private_keys =
|
|
12
|
+
private_keys = P.home().joinpath(".ssh").search("*.pub").apply(lambda x: x.with_name(x.stem)).filter(lambda x: x.exists())
|
|
12
13
|
choice = display_options(msg="Path to private key to be used when ssh'ing: ", options=private_keys.apply(str).list + ["I have the path to the key file", "I want to paste the key itself"])
|
|
13
|
-
if choice == "I have the path to the key file": path_to_key =
|
|
14
|
-
elif choice == "I want to paste the key itself": path_to_key =
|
|
15
|
-
elif isinstance(choice, str): path_to_key =
|
|
14
|
+
if choice == "I have the path to the key file": path_to_key = P(input("Input path here: ")).expanduser().absolute()
|
|
15
|
+
elif choice == "I want to paste the key itself": path_to_key = P.home().joinpath(f".ssh/{input('file name (default: my_pasted_key): ') or 'my_pasted_key'}").write_text(input("Paste the private key here: "))
|
|
16
|
+
elif isinstance(choice, str): path_to_key = P(choice)
|
|
16
17
|
else: raise NotImplementedError(f"Choice {choice} not supported")
|
|
17
18
|
txt = f"IdentityFile {path_to_key.collapseuser().as_posix()}" # adds this id for all connections, no host specified.
|
|
18
|
-
config_path =
|
|
19
|
+
config_path = P.home().joinpath(".ssh/config")
|
|
19
20
|
if config_path.exists(): config_path.modify_text(txt_search=txt, txt_alt=txt, replace_line=True, notfound_append=True, prepend=True) # note that Identity line must come on top of config file otherwise it won't work, hence `prepend=True`
|
|
20
21
|
else: config_path.write_text(txt)
|
|
21
22
|
program = f"echo 'Finished adding identity to ssh config file. {'*'*50} Consider reloading config file.'"
|
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
"""SSH
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
from platform import system
|
|
7
7
|
from machineconfig.utils.utils import LIBRARY_ROOT, display_options
|
|
8
|
+
from crocodile.file_management import P
|
|
8
9
|
|
|
9
10
|
|
|
10
|
-
def get_add_ssh_key_script(path_to_key:
|
|
11
|
-
if system() == "Linux": authorized_keys =
|
|
12
|
-
elif system() == "Windows": authorized_keys =
|
|
11
|
+
def get_add_ssh_key_script(path_to_key: P):
|
|
12
|
+
if system() == "Linux": authorized_keys = P.home().joinpath(".ssh/authorized_keys")
|
|
13
|
+
elif system() == "Windows": authorized_keys = P("C:/ProgramData/ssh/administrators_authorized_keys")
|
|
13
14
|
else: raise NotImplementedError
|
|
14
15
|
|
|
15
16
|
if authorized_keys.exists():
|
|
@@ -35,7 +36,7 @@ def get_add_ssh_key_script(path_to_key: tb.P):
|
|
|
35
36
|
program = f"cat {path_to_key} > ~/.ssh/authorized_keys"
|
|
36
37
|
else:
|
|
37
38
|
program = LIBRARY_ROOT.joinpath("setup_windows/openssh-server_add-sshkey.ps1")
|
|
38
|
-
program =
|
|
39
|
+
program = P(program).expanduser().read_text().replace('$sshfile=""', f'$sshfile="{path_to_key}"')
|
|
39
40
|
|
|
40
41
|
if system() == "Linux": program += f"""
|
|
41
42
|
|
|
@@ -50,17 +51,17 @@ sudo service ssh --full-restart
|
|
|
50
51
|
|
|
51
52
|
|
|
52
53
|
def main():
|
|
53
|
-
pub_keys =
|
|
54
|
+
pub_keys = P.home().joinpath(".ssh").search("*.pub")
|
|
54
55
|
all_keys_option = f"all pub keys available ({len(pub_keys)})"
|
|
55
56
|
i_have_path_option = "I have the path to the key file"
|
|
56
57
|
i_paste_option = "I want to paste the key itself"
|
|
57
58
|
res = display_options("Which public key to add? ", options=pub_keys.apply(str).list + [all_keys_option, i_have_path_option, i_paste_option])
|
|
58
59
|
assert isinstance(res, str), f"Got {res} of type {type(res)} instead of str."
|
|
59
60
|
if res == all_keys_option: program = "\n\n\n".join(pub_keys.apply(get_add_ssh_key_script))
|
|
60
|
-
elif res == i_have_path_option: program = get_add_ssh_key_script(
|
|
61
|
-
elif res == i_paste_option: program = get_add_ssh_key_script(
|
|
61
|
+
elif res == i_have_path_option: program = get_add_ssh_key_script(P(input("Path: ")).expanduser().absolute())
|
|
62
|
+
elif res == i_paste_option: program = get_add_ssh_key_script(P.home().joinpath(f".ssh/{input('file name (default: my_pasted_key.pub): ') or 'my_pasted_key.pub'}").write_text(input("Paste the pub key here: ")))
|
|
62
63
|
else:
|
|
63
|
-
program = get_add_ssh_key_script(
|
|
64
|
+
program = get_add_ssh_key_script(P(res))
|
|
64
65
|
print(program)
|
|
65
66
|
return program
|
|
66
67
|
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"""BR: Backup and Retrieve
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from platform import system
|
|
6
5
|
# import subprocess
|
|
7
|
-
|
|
6
|
+
from crocodile.file_management import Read, P
|
|
8
7
|
from machineconfig.utils.utils import LIBRARY_ROOT, DEFAULTS_PATH, print_code, choose_cloud_interactively, display_options
|
|
9
8
|
from machineconfig.scripts.python.cloud_sync import ES
|
|
9
|
+
from platform import system
|
|
10
10
|
from typing import Any, Literal, Optional
|
|
11
11
|
|
|
12
12
|
|
|
@@ -15,7 +15,7 @@ OPTIONS = Literal["BACKUP", "RETRIEVE"]
|
|
|
15
15
|
|
|
16
16
|
def main(direction: OPTIONS, which: Optional[str] = None):
|
|
17
17
|
try:
|
|
18
|
-
cloud: str =
|
|
18
|
+
cloud: str = Read.ini(DEFAULTS_PATH)['general']['rclone_config_name']
|
|
19
19
|
print(f"\n{'--' * 50}\n ⚠️ Using default cloud: `{cloud}` ⚠️\n{'--' * 50}\n")
|
|
20
20
|
except (FileNotFoundError, KeyError, IndexError): cloud = choose_cloud_interactively()
|
|
21
21
|
|
|
@@ -40,8 +40,8 @@ def main(direction: OPTIONS, which: Optional[str] = None):
|
|
|
40
40
|
flags += 'r' if item['rel2home'] == 'True' else ''
|
|
41
41
|
flags += 'o' if system().lower() in item_name else ''
|
|
42
42
|
if flags: flags = "-" + flags
|
|
43
|
-
if direction == "BACKUP": program += f"""\ncloud_copy "{
|
|
44
|
-
elif direction == "RETRIEVE": program += f"""\ncloud_copy $cloud "{
|
|
43
|
+
if direction == "BACKUP": program += f"""\ncloud_copy "{P(item['path']).as_posix()}" $cloud {flags}\n"""
|
|
44
|
+
elif direction == "RETRIEVE": program += f"""\ncloud_copy $cloud "{P(item['path']).as_posix()}" {flags}\n"""
|
|
45
45
|
else: raise RuntimeError(f"Unknown direction: {direction}")
|
|
46
46
|
if item_name == "dotfiles" and system() == "Linux": program += f"""\nchmod 700 ~/.ssh/*\n"""
|
|
47
47
|
print_code(program, lexer="shell", desc=f"{direction} script")
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"""Devops Devapps Install
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from platform import system
|
|
6
5
|
# import subprocess
|
|
7
|
-
|
|
6
|
+
from crocodile.core import List as L
|
|
8
7
|
from machineconfig.utils.utils import LIBRARY_ROOT, choose_multiple_options
|
|
9
|
-
from machineconfig.utils.installer import
|
|
8
|
+
from machineconfig.utils.installer import get_installers, Installer, install_all
|
|
9
|
+
from platform import system
|
|
10
10
|
from typing import Any, Optional, Literal, TypeAlias
|
|
11
11
|
|
|
12
12
|
|
|
@@ -15,7 +15,7 @@ WHICH: TypeAlias = Literal["AllEssentials", "EssentialsAndOthers", "SystemInstal
|
|
|
15
15
|
|
|
16
16
|
def main(which: Optional[str] = None):
|
|
17
17
|
sys = system()
|
|
18
|
-
installers =
|
|
18
|
+
installers = get_installers(dev=False, system=sys) + get_installers(dev=True, system=sys)
|
|
19
19
|
default = "AllEssentials"
|
|
20
20
|
options = ["SystemInstallers", "OtherDevApps", "EssentialsAndOthers", "PrecheckedCloudInstaller"]
|
|
21
21
|
options = [default] + options
|
|
@@ -34,10 +34,10 @@ def main(which: Optional[str] = None):
|
|
|
34
34
|
|
|
35
35
|
def get_program(program_name: str, options: list[str], installers: list[Installer]):
|
|
36
36
|
if program_name == "AllEssentials" or program_name == "EssentialsAndOthers":
|
|
37
|
-
installers_ =
|
|
37
|
+
installers_ = get_installers(dev=False, system=system())
|
|
38
38
|
if program_name == "EssentialsAndOthers":
|
|
39
|
-
installers_ +=
|
|
40
|
-
|
|
39
|
+
installers_ += get_installers(dev=True, system=system())
|
|
40
|
+
install_all(installers=L(installers))
|
|
41
41
|
program = ""
|
|
42
42
|
elif program_name == "SystemInstallers":
|
|
43
43
|
if system() == "Windows": options_system = parse_apps_installer_windows(LIBRARY_ROOT.joinpath("setup_windows/apps.ps1").read_text())
|
|
@@ -50,9 +50,10 @@ def get_program(program_name: str, options: list[str], installers: list[Installe
|
|
|
50
50
|
if sub_program.startswith("#winget"): sub_program = sub_program[1:]
|
|
51
51
|
program += "\n" + sub_program
|
|
52
52
|
elif program_name == "OtherDevApps":
|
|
53
|
-
installers =
|
|
53
|
+
installers = get_installers(dev=True, system=system())
|
|
54
54
|
options__: list[str] = [x.get_description() for x in installers]
|
|
55
|
-
program_names = choose_multiple_options(msg="", options=sorted(options__), header="CHOOSE DEV APP")
|
|
55
|
+
program_names = choose_multiple_options(msg="", options=sorted(options__) + ["all"], header="CHOOSE DEV APP")
|
|
56
|
+
if "all" in program_names: program_names = options__
|
|
56
57
|
program = ""
|
|
57
58
|
for name in program_names:
|
|
58
59
|
try:
|
|
@@ -62,8 +63,6 @@ def get_program(program_name: str, options: list[str], installers: list[Installe
|
|
|
62
63
|
print(f"{options__=}")
|
|
63
64
|
raise ve
|
|
64
65
|
sub_program = installers[idx].install_robust(version=None) # finish the task
|
|
65
|
-
# sub_program = "echo 'Finished Installation'" # write an empty program
|
|
66
|
-
# program += "\n" + ""sub_program
|
|
67
66
|
elif program_name == "PrecheckedCloudInstaller":
|
|
68
67
|
from machineconfig.jobs.python.check_installations import PrecheckedCloudInstaller
|
|
69
68
|
ci = PrecheckedCloudInstaller()
|
|
@@ -97,7 +96,7 @@ def parse_apps_installer_windows(txt: str) -> dict[str, Any]:
|
|
|
97
96
|
if idx == 0: continue
|
|
98
97
|
if idx == 1: chunks.append(item)
|
|
99
98
|
else: chunks.append("winget install" + item)
|
|
100
|
-
# progs =
|
|
99
|
+
# progs = L(txt.splitlines()).filter(lambda x: x.startswith("winget ") or x.startswith("#winget"))
|
|
101
100
|
res: dict[str, str] = {}
|
|
102
101
|
for a_chunk in chunks:
|
|
103
102
|
try:
|
|
@@ -110,8 +109,8 @@ def parse_apps_installer_windows(txt: str) -> dict[str, Any]:
|
|
|
110
109
|
except IndexError as e:
|
|
111
110
|
print(a_chunk)
|
|
112
111
|
raise e
|
|
113
|
-
#
|
|
114
|
-
#
|
|
112
|
+
# Struct(res).print(as_config=True)
|
|
113
|
+
# L(chunks).print(sep="-----------------------------------------------------------------------\n\n")
|
|
115
114
|
# import time
|
|
116
115
|
# time.sleep(10)
|
|
117
116
|
return res
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
"""Update
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from
|
|
6
|
-
|
|
5
|
+
from crocodile.file_management import P, Read
|
|
6
|
+
from crocodile.core import install_n_import
|
|
7
7
|
from machineconfig.utils.utils import DEFAULTS_PATH
|
|
8
|
+
from platform import system
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
sep = "\n"
|
|
@@ -14,7 +15,7 @@ def main(verbose: bool = True) -> str:
|
|
|
14
15
|
_ = verbose
|
|
15
16
|
repos: list[str] = ["~/code/crocodile", "~/code/machineconfig", ]
|
|
16
17
|
try:
|
|
17
|
-
tmp =
|
|
18
|
+
tmp = Read.ini(DEFAULTS_PATH)['general']['repos'].split(",")
|
|
18
19
|
if tmp[-1] == "": tmp = tmp[:-1]
|
|
19
20
|
repos += tmp
|
|
20
21
|
except (FileNotFoundError, KeyError, IndexError):
|
|
@@ -30,7 +31,7 @@ to_email = myemail@email.com
|
|
|
30
31
|
repos_objs = []
|
|
31
32
|
for a_package_path in repos:
|
|
32
33
|
try:
|
|
33
|
-
repo =
|
|
34
|
+
repo = install_n_import("git", "gitpython").Repo(str(P(a_package_path).expanduser()), search_parent_directories=True)
|
|
34
35
|
repos_objs.append(repo)
|
|
35
36
|
except Exception as ex:
|
|
36
37
|
print(ex)
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
"""Like yadm and dotter.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
from crocodile.file_management import P
|
|
4
7
|
from machineconfig.profile.create import symlink
|
|
5
8
|
from machineconfig.utils.utils import LIBRARY_ROOT, REPO_ROOT
|
|
9
|
+
import argparse
|
|
6
10
|
|
|
7
11
|
|
|
8
12
|
def main():
|
|
@@ -15,14 +19,14 @@ def main():
|
|
|
15
19
|
parser.add_argument("-d", "--dest", help=f"destination folder", default="")
|
|
16
20
|
|
|
17
21
|
args = parser.parse_args()
|
|
18
|
-
orig_path =
|
|
22
|
+
orig_path = P(args.file).expanduser().absolute()
|
|
19
23
|
if args.dest == "":
|
|
20
24
|
if "Local" in orig_path: junction = orig_path.split(at="Local", sep=-1)[1]
|
|
21
25
|
elif "Roaming" in orig_path: junction = orig_path.split(at="Roaming", sep=-1)[1]
|
|
22
26
|
elif ".config" in orig_path: junction = orig_path.split(at=".config", sep=-1)[1]
|
|
23
27
|
else: junction = orig_path.rel2home()
|
|
24
28
|
new_path = REPO_ROOT.joinpath(junction)
|
|
25
|
-
else: new_path =
|
|
29
|
+
else: new_path = P(args.dest).expanduser().absolute().create().joinpath(orig_path.name)
|
|
26
30
|
|
|
27
31
|
symlink(this=orig_path, to_this=new_path, prioritize_to_this=args.overwrite)
|
|
28
32
|
|