machineconfig 1.5__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.

Files changed (155) hide show
  1. machineconfig/__init__.py +8 -5
  2. machineconfig/jobs/python/check_installations.py +173 -163
  3. machineconfig/jobs/python/checkout_version.py +117 -0
  4. machineconfig/jobs/python/create_bootable_media.py +14 -14
  5. machineconfig/jobs/python/create_zellij_template.py +59 -56
  6. machineconfig/jobs/python/python_cargo_build_share.py +50 -45
  7. machineconfig/jobs/python/python_ve_symlink.py +20 -18
  8. machineconfig/jobs/python/tasks.py +4 -0
  9. machineconfig/jobs/script_installer/azure_data_studio.py +22 -0
  10. machineconfig/jobs/script_installer/bypass_paywall.py +23 -0
  11. machineconfig/jobs/script_installer/code.py +34 -0
  12. machineconfig/jobs/script_installer/docker_desktop.py +41 -0
  13. machineconfig/jobs/script_installer/ngrok.py +29 -0
  14. machineconfig/jobs/{python_linux_installers → script_installer}/skim.py +21 -19
  15. machineconfig/jobs/script_installer/wezterm.py +34 -0
  16. machineconfig/profile/create.py +107 -200
  17. machineconfig/profile/shell.py +127 -0
  18. machineconfig/scripts/__init__.py +6 -6
  19. machineconfig/scripts/python/cloud_copy.py +93 -0
  20. machineconfig/scripts/python/cloud_manager.py +38 -0
  21. machineconfig/scripts/python/cloud_mount.py +115 -52
  22. machineconfig/scripts/python/cloud_repo_sync.py +154 -114
  23. machineconfig/scripts/python/cloud_sync.py +261 -79
  24. machineconfig/scripts/python/croshell.py +151 -0
  25. machineconfig/scripts/python/devops.py +119 -87
  26. machineconfig/scripts/python/devops_add_identity.py +27 -23
  27. machineconfig/scripts/python/devops_add_ssh_key.py +70 -55
  28. machineconfig/scripts/python/devops_backup_retrieve.py +52 -46
  29. machineconfig/scripts/python/devops_devapps_install.py +120 -91
  30. machineconfig/scripts/python/devops_update_repos.py +82 -68
  31. machineconfig/scripts/python/dotfile.py +42 -38
  32. machineconfig/scripts/python/fire_jobs.py +351 -98
  33. machineconfig/scripts/python/ftpx.py +82 -0
  34. machineconfig/scripts/python/mount_nfs.py +54 -3
  35. machineconfig/scripts/python/mount_nw_drive.py +31 -0
  36. machineconfig/scripts/python/mount_ssh.py +44 -20
  37. machineconfig/scripts/python/onetimeshare.py +60 -51
  38. machineconfig/scripts/python/pomodoro.py +41 -37
  39. machineconfig/scripts/python/repos.py +195 -128
  40. machineconfig/scripts/python/scheduler.py +52 -0
  41. machineconfig/scripts/python/snapshot.py +21 -21
  42. machineconfig/scripts/python/start_slidev.py +104 -0
  43. machineconfig/scripts/python/start_terminals.py +97 -0
  44. machineconfig/scripts/python/wifi_conn.py +90 -71
  45. machineconfig/scripts/python/{transfer_wsl_win.py → wsl_windows_transfer.py} +47 -39
  46. machineconfig/setup_windows/wt_and_pwsh/set_pwsh_theme.py +44 -48
  47. machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +136 -130
  48. machineconfig/utils/installer.py +251 -0
  49. machineconfig/utils/procs.py +114 -64
  50. machineconfig/utils/scheduling.py +188 -0
  51. machineconfig/utils/utils.py +353 -249
  52. machineconfig/utils/ve.py +222 -0
  53. {machineconfig-1.5.dist-info → machineconfig-1.8.dist-info}/METADATA +140 -110
  54. machineconfig-1.8.dist-info/RECORD +70 -0
  55. {machineconfig-1.5.dist-info → machineconfig-1.8.dist-info}/WHEEL +1 -1
  56. machineconfig/jobs/python/python_linux_installers_all.py +0 -73
  57. machineconfig/jobs/python/python_ve_installer.py +0 -73
  58. machineconfig/jobs/python/python_windows_installers_all.py +0 -23
  59. machineconfig/jobs/python_generic_installers/archive/nvim.py +0 -15
  60. machineconfig/jobs/python_generic_installers/archive/strongbox.py +0 -32
  61. machineconfig/jobs/python_generic_installers/archive/vtm.py +0 -25
  62. machineconfig/jobs/python_generic_installers/broot.py +0 -39
  63. machineconfig/jobs/python_generic_installers/browsh.py +0 -25
  64. machineconfig/jobs/python_generic_installers/bw.py +0 -26
  65. machineconfig/jobs/python_generic_installers/chatgpt.py +0 -24
  66. machineconfig/jobs/python_generic_installers/cpufetch.py +0 -23
  67. machineconfig/jobs/python_generic_installers/delta.py +0 -59
  68. machineconfig/jobs/python_generic_installers/dev/__init__.py +0 -0
  69. machineconfig/jobs/python_generic_installers/dev/autogpt.py +0 -28
  70. machineconfig/jobs/python_generic_installers/dev/bw.py +0 -29
  71. machineconfig/jobs/python_generic_installers/dev/evcxr.py +0 -22
  72. machineconfig/jobs/python_generic_installers/dev/kondo.py +0 -21
  73. machineconfig/jobs/python_generic_installers/dev/lvim.py +0 -60
  74. machineconfig/jobs/python_generic_installers/dev/ngrok.py +0 -35
  75. machineconfig/jobs/python_generic_installers/dev/opencommit.py +0 -21
  76. machineconfig/jobs/python_generic_installers/dev/qrcp.py +0 -25
  77. machineconfig/jobs/python_generic_installers/dev/qrscan.py +0 -16
  78. machineconfig/jobs/python_generic_installers/dev/rust-analyzer.py +0 -24
  79. machineconfig/jobs/python_generic_installers/dev/termscp.py +0 -23
  80. machineconfig/jobs/python_generic_installers/dev/tldr.py +0 -25
  81. machineconfig/jobs/python_generic_installers/dev/tokei.py +0 -24
  82. machineconfig/jobs/python_generic_installers/diskonaut.py +0 -26
  83. machineconfig/jobs/python_generic_installers/dua.py +0 -21
  84. machineconfig/jobs/python_generic_installers/evcxr.py +0 -21
  85. machineconfig/jobs/python_generic_installers/gitui.py +0 -23
  86. machineconfig/jobs/python_generic_installers/gopass.py +0 -19
  87. machineconfig/jobs/python_generic_installers/helix.py +0 -45
  88. machineconfig/jobs/python_generic_installers/kondo.py +0 -20
  89. machineconfig/jobs/python_generic_installers/lf.py +0 -25
  90. machineconfig/jobs/python_generic_installers/lvim.py +0 -34
  91. machineconfig/jobs/python_generic_installers/mprocs.py +0 -20
  92. machineconfig/jobs/python_generic_installers/navi.py +0 -20
  93. machineconfig/jobs/python_generic_installers/ots.py +0 -26
  94. machineconfig/jobs/python_generic_installers/ouch.py +0 -25
  95. machineconfig/jobs/python_generic_installers/pomodoro.py +0 -19
  96. machineconfig/jobs/python_generic_installers/procs.py +0 -20
  97. machineconfig/jobs/python_generic_installers/qrcp.py +0 -22
  98. machineconfig/jobs/python_generic_installers/qrscan.py +0 -14
  99. machineconfig/jobs/python_generic_installers/rclone.py +0 -21
  100. machineconfig/jobs/python_generic_installers/rust-analyzer.py +0 -24
  101. machineconfig/jobs/python_generic_installers/tere.py +0 -26
  102. machineconfig/jobs/python_generic_installers/termscp.py +0 -23
  103. machineconfig/jobs/python_generic_installers/tldr.py +0 -24
  104. machineconfig/jobs/python_generic_installers/tokei.py +0 -21
  105. machineconfig/jobs/python_generic_installers/vtm.py +0 -26
  106. machineconfig/jobs/python_generic_installers/watchexec.py +0 -21
  107. machineconfig/jobs/python_linux_installers/archive/__init__.py +0 -0
  108. machineconfig/jobs/python_linux_installers/archive/ranger.py +0 -18
  109. machineconfig/jobs/python_linux_installers/bandwhich.py +0 -11
  110. machineconfig/jobs/python_linux_installers/bottom.py +0 -17
  111. machineconfig/jobs/python_linux_installers/btop.py +0 -17
  112. machineconfig/jobs/python_linux_installers/dev/bandwhich.py +0 -13
  113. machineconfig/jobs/python_linux_installers/dev/bytehound.py +0 -20
  114. machineconfig/jobs/python_linux_installers/dev/nnn.py +0 -21
  115. machineconfig/jobs/python_linux_installers/gotty.py +0 -16
  116. machineconfig/jobs/python_linux_installers/joshuto.py +0 -28
  117. machineconfig/jobs/python_linux_installers/mcfly.py +0 -12
  118. machineconfig/jobs/python_linux_installers/nnn.py +0 -18
  119. machineconfig/jobs/python_linux_installers/topgrade.py +0 -15
  120. machineconfig/jobs/python_linux_installers/viu.py +0 -19
  121. machineconfig/jobs/python_linux_installers/xplr.py +0 -22
  122. machineconfig/jobs/python_linux_installers/zellij.py +0 -31
  123. machineconfig/jobs/python_windows_installers/archive/ntop.py +0 -20
  124. machineconfig/jobs/python_windows_installers/bat.py +0 -16
  125. machineconfig/jobs/python_windows_installers/boxes.py +0 -19
  126. machineconfig/jobs/python_windows_installers/bypass_paywall.py +0 -18
  127. machineconfig/jobs/python_windows_installers/dev/bypass_paywall.py +0 -21
  128. machineconfig/jobs/python_windows_installers/dev/obs_background_removal_plugin.py +0 -20
  129. machineconfig/jobs/python_windows_installers/fd.py +0 -17
  130. machineconfig/jobs/python_windows_installers/fzf.py +0 -19
  131. machineconfig/jobs/python_windows_installers/obs_background_removal_plugin.py +0 -19
  132. machineconfig/jobs/python_windows_installers/rg.py +0 -15
  133. machineconfig/jobs/python_windows_installers/ugrep.py +0 -14
  134. machineconfig/jobs/python_windows_installers/zoomit.py +0 -20
  135. machineconfig/jobs/python_windows_installers/zoxide.py +0 -20
  136. machineconfig/profile/fix_shell_profiles.py +0 -8
  137. machineconfig/scripts/python/archive/__init__.py +0 -0
  138. machineconfig/scripts/python/archive/bu_gdrive_rx.py +0 -41
  139. machineconfig/scripts/python/archive/bu_gdrive_sx.py +0 -40
  140. machineconfig/scripts/python/archive/bu_onedrive_rx.py +0 -59
  141. machineconfig/scripts/python/archive/bu_onedrive_sx.py +0 -45
  142. machineconfig/scripts/python/chatgpt.py +0 -28
  143. machineconfig/scripts/python/choose_ohmybash_theme.py +0 -25
  144. machineconfig/scripts/python/choose_ohmyposh_theme.py +0 -40
  145. machineconfig/scripts/python/cloud_rx.py +0 -42
  146. machineconfig/scripts/python/cloud_sx.py +0 -40
  147. machineconfig/scripts/python/ftprx.py +0 -37
  148. machineconfig/scripts/python/ftpsx.py +0 -36
  149. machineconfig/scripts/python/im2text.py +0 -15
  150. machineconfig/scripts/python/tmate_conn.py +0 -28
  151. machineconfig/scripts/python/tmate_start.py +0 -31
  152. machineconfig/utils/to_exe.py +0 -7
  153. machineconfig-1.5.dist-info/RECORD +0 -147
  154. /machineconfig/jobs/{python_generic_installers/archive → script_installer}/__init__.py +0 -0
  155. {machineconfig-1.5.dist-info → machineconfig-1.8.dist-info}/top_level.txt +0 -0
@@ -1,200 +1,107 @@
1
-
2
- """
3
- This script Takes away all config files from the computer, place them in one directory
4
- `dotfiles`, and create symlinks to those files from thier original locations.
5
- """
6
-
7
- import crocodile.toolbox as tb
8
- from crocodile.environment import DotFiles, system, PathVar, UserName # ProgramFiles, WindowsApps # , exe
9
- from machineconfig.utils.utils import symlink, LIBRARY_ROOT, REPO_ROOT, display_options
10
- # import os
11
- import subprocess
12
- from rich.console import Console
13
-
14
-
15
- ERROR_LIST = [] # append to this after every exception captured.
16
- CONFIG_ROOT = LIBRARY_ROOT.parent.parent.joinpath("settings")
17
- OTHER_SYSTEM = "windows" if system == "Linux" else "linux"
18
-
19
- # =================== SYMLINKS ====================================
20
-
21
-
22
- def link_ssh(overwrite=True):
23
- """The function can link aribtrary number of files without linking the directory itself (which is not doable in toml config file)"""
24
- path = tb.P.home().joinpath(".ssh")
25
- target = DotFiles.joinpath("creds/.ssh")
26
- for item in target.search("*"):
27
- # if "authorized_keys" in item: continue
28
- symlink(path.joinpath(item.name), item, prioritize_to_this=overwrite)
29
- if system == "Linux": # permissions of ~/dotfiles/.ssh should be adjusted
30
- try:
31
- subprocess.run(f"chmod 700 ~/.ssh/")
32
- subprocess.run(f"chmod 700 {target.collapseuser().as_posix()}/") # may require sudo
33
- subprocess.run(f"chmod 600 {target.collapseuser().as_posix()}/*")
34
- except Exception as e:
35
- ERROR_LIST.append(e)
36
- print("Caught error", e)
37
-
38
-
39
- def link_aws(overwrite=True):
40
- path = tb.P.home().joinpath(".aws")
41
- target = DotFiles.joinpath("aws/.aws")
42
- for item in target.search("*"): symlink(path.joinpath(item.name), item, prioritize_to_this=overwrite)
43
-
44
-
45
- def main_symlinks(choice=None):
46
- symlink_mapper = LIBRARY_ROOT.joinpath("profile/mapper.toml").readit()
47
- symlink_mapper['wsl_windows']['home']["to_this"] = symlink_mapper['wsl_windows']['home']["to_this"].replace("username", UserName)
48
- symlink_mapper['wsl_linux']['home']["to_this"] = symlink_mapper['wsl_linux']['home']["to_this"].replace("username", UserName)
49
-
50
- overwrite = True
51
- exclude = ["autostart_windows"] # "wsl_linux", "wsl_windows"
52
-
53
- program_keys_raw = list(symlink_mapper.keys()) + ["aws", "ssh"]
54
- program_keys = []
55
- for program_key in program_keys_raw:
56
- if program_key in exclude or OTHER_SYSTEM in program_key:
57
- # print(f"Skipping {program_key} for {system}")
58
- continue
59
- else: program_keys.append(program_key)
60
-
61
- program_keys.sort()
62
- if choice is None:
63
- choice = display_options(msg="Which symlink to create?", options=program_keys + ["all", "none"], default="none")
64
- if str(choice) == "none": return
65
-
66
- overwrite = display_options(msg="Overwrite existing source file?", options=["yes", "no"], default="yes") == "yes"
67
-
68
- if str(choice) == "all" and system == "Windows" and not tb.Terminal.is_user_admin():
69
- print("*" * 200)
70
- 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.")
71
- elif choice == "all": program_keys = program_keys
72
- else: program_keys = [choice]
73
-
74
- for program_key in program_keys:
75
- if program_key == "aws":
76
- link_aws(overwrite=overwrite)
77
- continue
78
- elif program_key == "ssh":
79
- link_ssh(overwrite=overwrite)
80
- continue
81
- for file_key, file_map in symlink_mapper[program_key].items():
82
- try: symlink(this=file_map['this'], to_this=file_map['to_this'].replace("REPO_ROOT", REPO_ROOT.as_posix()).replace("LIBRARY_ROOT", LIBRARY_ROOT.as_posix()), prioritize_to_this=overwrite)
83
- except Exception as ex: print("Config error: ", program_key, file_key, "missing keys 'this ==> to_this'.", ex)
84
-
85
- if system == "Linux": tb.Terminal().run(f'chmod +x {LIBRARY_ROOT.joinpath(f"scripts/{system.lower()}")} -R')
86
-
87
-
88
- # --------------------------------------- SHELL PROFILE --------------------------------------------------------
89
- # The following is not a symlink creation, but modification of shell profile by additing dirs to PATH
90
- # Shell profile is either in dotfiles and is synced (as in Windows), hence no need for update, or is updated on the fly (for Linux)
91
- # for windows it won't change the profile, if the profile was modified already e.g. due to syncing
92
-
93
-
94
- def get_shell_profile_path():
95
- if system == "Windows": profile_path = tb.Terminal().run("$profile", shell="pwsh").op2path()
96
- elif system == "Linux": profile_path = tb.P("~/.bashrc").expanduser()
97
- else: raise ValueError(f"Not implemented for this system {system}")
98
- print(f"Working on shell profile `{profile_path}`")
99
- return profile_path
100
-
101
-
102
- def main_env_path(choice=None, profile_path=None):
103
- env_path = LIBRARY_ROOT.joinpath("profile/env_path.toml").readit()
104
- dirs = env_path[f'path_{system.lower()}']['extension']
105
-
106
- print(f"Current PATH: ", "\n============")
107
- tb.get_env().PATH.print()
108
-
109
- if choice is None:
110
- choice = display_options(msg="Which directory to add?", options=dirs + ["all", "none"], default="none")
111
- if str(choice) != "all": dirs = [choice]
112
- if choice == "none": return
113
-
114
- addition = PathVar.append_temporarily(dirs=dirs)
115
- profile_path = profile_path or get_shell_profile_path()
116
- profile_path.copy(name=profile_path.name + f".orig_" + tb.randstr())
117
- profile_path.modify_text(addition, addition, replace_line=False, notfound_append=True)
118
-
119
-
120
- def main_add_sources_to_shell_profile(profile_path=None, choice=None):
121
- sources = LIBRARY_ROOT.joinpath("profile/sources.toml").readit()[system.lower()]['files']
122
-
123
- if choice is None:
124
- choice = display_options(msg="Which patch to add?", options=sources + ["all", "none"], default="none")
125
- if str(choice) != "all": sources = [choice]
126
- if choice == "none": return
127
-
128
- profile_path = profile_path or get_shell_profile_path()
129
- profile = profile_path.read_text()
130
-
131
- for a_file in sources:
132
- file = a_file.replace("REPO_ROOT", REPO_ROOT.as_posix()).replace("LIBRARY_ROOT", LIBRARY_ROOT.as_posix())
133
- file = tb.P(file).collapseuser() # this makes the shell profile interuseable across machines.
134
- file = file.as_posix() if system == "Linux" else str(file)
135
- if file not in profile:
136
- if system == "Windows": profile += f"\n. {file}"
137
- elif system == "Linux": profile += f"\nsource {file}"
138
- else: raise ValueError(f"Not implemented for this system {system}")
139
- else: print(f"SKIPPED source `{file}`, it is already sourced in shell profile.")
140
- profile_path.write_text(profile)
141
-
142
-
143
- def main_add_patches_to_shell_profile(profile_path=None, choice=None):
144
- patches = LIBRARY_ROOT.joinpath(f"profile/patches/{system.lower()}").search()
145
-
146
- if choice is None:
147
- choice = display_options(msg="Which patch to add?", options=patches.list + ["all", "none"], default="none")
148
- if choice == "none": return
149
- if str(choice) == "all": patches = patches
150
- else: patches = [choice]
151
-
152
- profile_path = profile_path or get_shell_profile_path()
153
- profile = profile_path.read_text()
154
-
155
- for patch_path in patches:
156
- patch = patch_path.read_text()
157
- if patch in profile: print(f"Skipping `{patch_path.name}`; patch already in profile")
158
- else: profile += "\n" + patch
159
-
160
- if system == "Linux":
161
- res = tb.Terminal().run("cat /proc/version").op
162
- if "microsoft" in res.lower() or "wsl" in res.lower():
163
- 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.
164
-
165
- profile_path.write_text(profile)
166
-
167
-
168
- def main(choice=None):
169
- console = Console()
170
- print("\n")
171
- console.rule(f"CREATING SYMLINKS")
172
-
173
- # the only common choice among all programs below is "all".
174
- main_symlinks(choice=choice)
175
-
176
- # print("\n")
177
- # console.rule(f"ADDING ENV PATH")
178
- # main_env_path(choice=choice)
179
- # print("\n")
180
- # console.rule(f"ADDING SOURCES TO SHELL PROFILE")
181
- # main_add_sources_to_shell_profile(choice=choice)
182
- # print("\n")
183
- # console.rule(f"ADDING PATCHES TO SHELL PROFILE")
184
- # main_add_patches_to_shell_profile(choice=choice)
185
-
186
- profile_path = get_shell_profile_path()
187
- profile = profile_path.read_text()
188
- source = f". {LIBRARY_ROOT.joinpath('settings/shells/pwsh/init.ps1').collapseuser()}" if system == "Windows" else f"source {LIBRARY_ROOT.joinpath('settings/shells/bash/init.sh')}"
189
- if source in profile: print(f"Skipping sourcing init script; already in profile")
190
- else:
191
- profile += "\n" + source + "\n"
192
- if system == "Linux":
193
- res = tb.Terminal().run("cat /proc/version").op
194
- if "microsoft" in res.lower() or "wsl" in res.lower():
195
- 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.
196
- profile_path.write_text(profile)
197
-
198
-
199
- if __name__ == '__main__':
200
- pass
1
+
2
+ """
3
+ This script Takes away all config files from the computer, place them in one directory
4
+ `dotfiles`, and create symlinks to those files from thier original locations.
5
+
6
+ """
7
+
8
+
9
+ from crocodile.environment import system, UserName # ProgramFiles, WindowsApps # , exe
10
+ from crocodile.meta import Terminal
11
+ from crocodile.file_management import P
12
+ from machineconfig.utils.utils import symlink, LIBRARY_ROOT, REPO_ROOT, display_options
13
+ from machineconfig.profile.shell import create_default_shell_profile
14
+ # import os
15
+ import subprocess
16
+ from rich.console import Console
17
+ from typing import Optional, Any
18
+
19
+
20
+ ERROR_LIST: list[Any] = [] # append to this after every exception captured.
21
+ CONFIG_ROOT = LIBRARY_ROOT.parent.parent.joinpath("settings")
22
+ OTHER_SYSTEM = "windows" if system == "Linux" else "linux"
23
+ SYSTEM = system.lower()
24
+
25
+
26
+ # =================== SYMLINKS ====================================
27
+
28
+
29
+ def symlink_contents(source_dir: P, target_dir: P, overwrite: bool = True):
30
+ for a_target in target_dir.expanduser().search("*"):
31
+ symlink(this=source_dir.joinpath(a_target.name), to_this=a_target, prioritize_to_this=overwrite)
32
+
33
+
34
+ def main_symlinks(choice: Optional[str] = None):
35
+ symlink_mapper = LIBRARY_ROOT.joinpath("profile/mapper.toml").readit()
36
+ symlink_mapper['wsl_windows']['home']["to_this"] = symlink_mapper['wsl_windows']['home']["to_this"].replace("username", UserName)
37
+ symlink_mapper['wsl_linux']['home']["to_this"] = symlink_mapper['wsl_linux']['home']["to_this"].replace("username", UserName)
38
+
39
+ overwrite = True
40
+ exclude: list[str] = [] # "wsl_linux", "wsl_windows"
41
+
42
+ program_keys_raw: list[str] = list(symlink_mapper.keys())
43
+ program_keys: list[str] = []
44
+ for program_key in program_keys_raw:
45
+ if program_key in exclude or OTHER_SYSTEM in program_key:
46
+ # print(f"Skipping {program_key} for {system}")
47
+ continue
48
+ else: program_keys.append(program_key)
49
+
50
+ program_keys.sort()
51
+ if choice is None:
52
+ choice_selected = display_options(msg="Which symlink to create?", options=program_keys + ["all", "none(EXIT)"], default="none(EXIT)", fzf=True, multi=True)
53
+ assert isinstance(choice_selected, list)
54
+ if len(choice_selected) == 1 and choice_selected[0] == "none(EXIT)": return # terminate function.
55
+ elif len(choice_selected) == 1 and choice_selected[0] == "all": choice_selected = "all" # i.e. program_keys = program_keys
56
+ # overwrite = display_options(msg="Overwrite existing source file?", options=["yes", "no"], default="yes") == "yes"
57
+ from rich.prompt import Confirm
58
+ overwrite = Confirm.ask("Overwrite existing source file?", default=True)
59
+
60
+ else: choice_selected = choice
61
+
62
+ if isinstance(choice_selected, str):
63
+ if str(choice_selected) == "all" and system == "Windows" and not Terminal.is_user_admin():
64
+ print("*" * 200)
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.")
66
+ elif choice_selected == "all":
67
+ print(f"{program_keys=}")
68
+ pass # i.e. program_keys = program_keys
69
+ else: program_keys = [choice_selected]
70
+ else: program_keys = choice_selected
71
+
72
+ for program_key in program_keys:
73
+ for file_key, file_map in symlink_mapper[program_key].items():
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()))
76
+ if "contents" in file_map:
77
+ try: symlink_contents(source_dir=this, target_dir=to_this, overwrite=overwrite)
78
+ except Exception as ex: print("Config error: ", program_key, file_key, "missing keys 'this ==> to_this'.", ex)
79
+ else:
80
+ try: symlink(this=this, to_this=to_this, prioritize_to_this=overwrite)
81
+ except Exception as ex: print("Config error: ", program_key, file_key, "missing keys 'this ==> to_this'.", ex)
82
+
83
+ if program_key == "ssh" and system == "Linux": # permissions of ~/dotfiles/.ssh should be adjusted
84
+ try:
85
+ subprocess.run(f"chmod 700 ~/.ssh/", check=True)
86
+ subprocess.run(f"chmod 700 ~/dotfiles/creds/.ssh/", check=True) # may require sudo
87
+ subprocess.run(f"chmod 600 ~/dotfiles/creds/.ssh//*", check=True)
88
+ except Exception as e:
89
+ ERROR_LIST.append(e)
90
+ print("Caught error", e)
91
+
92
+ if system == "Linux": Terminal().run(f'chmod +x {LIBRARY_ROOT.joinpath(f"scripts/{system.lower()}")} -R')
93
+
94
+
95
+ def main(choice: Optional[str] = None):
96
+ console = Console()
97
+ print("\n")
98
+ console.rule(f"CREATING SYMLINKS")
99
+ main_symlinks(choice=choice)
100
+
101
+ print("\n")
102
+ console.rule(f"CREATING SYMLINKS")
103
+ create_default_shell_profile()
104
+
105
+
106
+ if __name__ == '__main__':
107
+ pass
@@ -0,0 +1,127 @@
1
+
2
+ """shell
3
+ """
4
+
5
+ from crocodile.environment import PathVar
6
+ from crocodile.core import randstr
7
+ from crocodile.file_management import P
8
+ from crocodile.meta import Terminal
9
+ from machineconfig.utils.utils import LIBRARY_ROOT, REPO_ROOT, display_options
10
+ import platform
11
+ from typing import Optional
12
+
13
+
14
+ system = platform.system()
15
+
16
+ # --------------------------------------- SHELL PROFILE --------------------------------------------------------
17
+ # modification of shell profile by additing dirs to PATH
18
+ # Shell profile is either in dotfiles and is synced (as in Windows), hence no need for update, or is updated on the fly (for Linux)
19
+ # for windows it won't change the profile, if the profile was modified already e.g. due to syncing
20
+
21
+
22
+ def create_default_shell_profile():
23
+ profile_path = get_shell_profile_path()
24
+ profile = profile_path.read_text()
25
+ if system == "Windows": source = f". {LIBRARY_ROOT.joinpath('settings/shells/pwsh/init.ps1').collapseuser().str.replace('~', '$HOME')}"
26
+ else: source = f"source {LIBRARY_ROOT.joinpath('settings/shells/bash/init.sh').collapseuser().str.replace('~', '$HOME')}"
27
+
28
+ if source in profile: print(f"Skipping sourcing init script; already in profile")
29
+ else:
30
+ profile += "\n" + source + "\n"
31
+ if system == "Linux":
32
+ res = Terminal().run("cat /proc/version").op
33
+ if "microsoft" in res.lower() or "wsl" in res.lower():
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.
35
+ profile_path.create(parents_only=True).write_text(profile)
36
+
37
+
38
+ def get_shell_profile_path():
39
+ if system == "Windows":
40
+ res = Terminal().run("$profile", shell="pwsh").op2path()
41
+ if isinstance(res, P): profile_path = res
42
+ else: raise ValueError(f"Could not get profile path for Windows. Got {res}")
43
+ elif system == "Linux": profile_path = P("~/.bashrc").expanduser()
44
+ else: raise ValueError(f"Not implemented for this system {system}")
45
+ print(f"Working on shell profile `{profile_path}`")
46
+ return profile_path
47
+
48
+
49
+ def main_env_path(choice: Optional[str] = None, profile_path: Optional[str] = None):
50
+ env_path = LIBRARY_ROOT.joinpath("profile/env_path.toml").readit()
51
+ dirs = env_path[f'path_{system.lower()}']['extension']
52
+
53
+ print(f"Current PATH: ", "\n============")
54
+ P.get_env().PATH.print()
55
+
56
+ if choice is None:
57
+ tmp = display_options(msg="Which directory to add?", options=dirs + ["all", "none(EXIT)"], default="none(EXIT)")
58
+ assert isinstance(tmp, str), f"Choice must be a string or a list of strings, not {type(choice)}"
59
+ choice = tmp
60
+ if str(choice) != "all": dirs = [choice]
61
+ if choice == "none(EXIT)": return
62
+
63
+ addition = PathVar.append_temporarily(dirs=dirs)
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())
66
+ profile_path_obj.modify_text(addition, addition, replace_line=False, notfound_append=True)
67
+
68
+
69
+ def main_add_sources_to_shell_profile(profile_path: Optional[str] = None, choice: Optional[str] = None):
70
+ sources: list[str] = LIBRARY_ROOT.joinpath("profile/sources.toml").readit()[system.lower()]['files']
71
+
72
+ if choice is None:
73
+ choice_obj = display_options(msg="Which patch to add?", options=sources + ["all", "none(EXIT)"], default="none(EXIT)", multi=True)
74
+ if isinstance(choice_obj, str):
75
+ if choice_obj == "all": choice = choice_obj
76
+ elif choice_obj == "none(EXIT)": return
77
+ else: sources = [choice_obj]
78
+ else: # isinstance(choice_obj, list):
79
+ sources = choice_obj
80
+ elif choice == "none(EXIT)": return
81
+
82
+ if isinstance(profile_path, str):
83
+ profile_path_obj = P(profile_path)
84
+ else: profile_path_obj = get_shell_profile_path()
85
+ profile = profile_path_obj.read_text()
86
+
87
+ for a_file in sources:
88
+ tmp = a_file.replace("REPO_ROOT", REPO_ROOT.as_posix()).replace("LIBRARY_ROOT", LIBRARY_ROOT.as_posix())
89
+ file = P(tmp).collapseuser() # this makes the shell profile interuseable across machines.
90
+ file = file.as_posix() if system == "Linux" else str(file)
91
+ if file not in profile:
92
+ if system == "Windows": profile += f"\n. {file}"
93
+ elif system == "Linux": profile += f"\nsource {file}"
94
+ else: raise ValueError(f"Not implemented for this system {system}")
95
+ else: print(f"SKIPPED source `{file}`, it is already sourced in shell profile.")
96
+ profile_path_obj.write_text(profile)
97
+
98
+
99
+ def main_add_patches_to_shell_profile(profile_path: Optional[str] = None, choice: Optional[str] = None):
100
+ patches: list[str] = list(LIBRARY_ROOT.joinpath(f"profile/patches/{system.lower()}").search().apply(lambda x: x.as_posix()))
101
+ if choice is None:
102
+ choice_chosen = display_options(msg="Which patch to add?", options=list(patches) + ["all", "none(EXIT)"], default="none(EXIT)", multi=False)
103
+ assert isinstance(choice_chosen, str), f"Choice must be a string or a list of strings, not {type(choice)}"
104
+ choice = choice_chosen
105
+ if choice == "none(EXIT)": return None
106
+ elif str(choice) == "all": pass # i.e. patches = patches
107
+ else: patches = [choice]
108
+
109
+ profile_path_obj = P(profile_path) if isinstance(profile_path, str) else get_shell_profile_path()
110
+ profile = profile_path_obj.read_text()
111
+
112
+ for patch_path in patches:
113
+ patch_path_obj = P(patch_path)
114
+ patch = patch_path_obj.read_text()
115
+ if patch in profile: print(f"Skipping `{patch_path_obj.name}`; patch already in profile")
116
+ else: profile += "\n" + patch
117
+
118
+ if system == "Linux":
119
+ res = Terminal().run("cat /proc/version").op
120
+ if "microsoft" in res.lower() or "wsl" in res.lower():
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.
122
+
123
+ profile_path_obj.write_text(profile)
124
+
125
+
126
+ if __name__ == '__main__':
127
+ pass
@@ -1,6 +1,6 @@
1
-
2
-
3
- version = "0.5"
4
- release_notes = """
5
- created toml file for symlinks
6
- """
1
+
2
+
3
+ version = "0.5"
4
+ release_notes = """
5
+ created toml file for symlinks
6
+ """
@@ -0,0 +1,93 @@
1
+
2
+ """CC
3
+ """
4
+
5
+ from crocodile.file_management import P, Struct
6
+ from crocodile.meta import RepeatUntilNoException
7
+ import getpass
8
+ from machineconfig.scripts.python.cloud_sync import parse_cloud_source_target, ArgsDefaults, Args
9
+ import argparse
10
+ import os
11
+ # from dataclasses import dataclass
12
+ # from pydantic import BaseModel
13
+ from typing import Optional
14
+
15
+
16
+ @RepeatUntilNoException()
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)
19
+
20
+ if os.environ.get("DECRYPTION_PASSWORD") is not None:
21
+ pwd: str = str(os.environ.get("DECRYPTION_PASSWORD"))
22
+ else:
23
+ pwd = getpass.getpass(prompt="Enter decryption password: ")
24
+
25
+ if url is None:
26
+ if os.environ.get("SHARE_URL") is not None:
27
+ url = os.environ.get("SHARE_URL")
28
+ assert url is not None
29
+ else:
30
+ url = input("Enter share url: ")
31
+
32
+ from rich.progress import Progress
33
+ with Progress(transient=True) as progress:
34
+ _task = progress.add_task("Downloading ... ", total=None)
35
+ url_obj = P(url).download(folder=folder_obj)
36
+ with Progress(transient=True) as progress:
37
+ _task = progress.add_task("Decrypting ... ", total=None)
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))
41
+ print(f"Decrypted to {res}")
42
+
43
+
44
+ def arg_parser() -> None:
45
+ parser = argparse.ArgumentParser(description='Cloud CLI. It wraps rclone with sane defaults for optimum type time.')
46
+
47
+ # positional argument
48
+ parser.add_argument("source", help="file/folder path to be taken from here.")
49
+ parser.add_argument("target", help="file/folder path to be be sent to here.")
50
+
51
+ parser.add_argument("--overwrite", "-w", help="Overwrite existing file.", action="store_true", default=ArgsDefaults.overwrite)
52
+ parser.add_argument("--share", "-s", help="Share file / directory", action="store_true", default=ArgsDefaults.share)
53
+ parser.add_argument("--rel2home", "-r", help="Relative to `myhome` folder", action="store_true", default=ArgsDefaults.rel2home)
54
+ parser.add_argument("--root", "-R", help="Remote root. None is the default, unless rel2home is raied, making the default `myhome`.", default=ArgsDefaults.root)
55
+
56
+ parser.add_argument("--key", "-k", help="Key for encryption", type=str, default=ArgsDefaults.key)
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
+
61
+ parser.add_argument("--config", "-c", help="path to cloud.json file.", default=None)
62
+
63
+ args = parser.parse_args()
64
+ args_dict = vars(args)
65
+ source: str = args_dict.pop("source")
66
+ target: str = args_dict.pop("target")
67
+ args_obj = Args(**args_dict)
68
+ Struct(args_obj.__dict__).print(as_config=True, title=f"CLI config")
69
+
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
+ if args_obj.rel2home is True and args_obj.root is None: args_obj.root = "myhome"
72
+
73
+ cloud, source, target = parse_cloud_source_target(args=args_obj, source=source, target=target)
74
+
75
+ assert args_obj.key is None, f"Key is not supported yet."
76
+ if cloud in source:
77
+ P(target).from_cloud(cloud=cloud, remotepath=source.replace(cloud + ":", ""),
78
+ unzip=args_obj.zip, decrypt=args_obj.encrypt, pwd=args_obj.pwd,
79
+ overwrite=args_obj.overwrite,
80
+ rel2home=args_obj.rel2home, os_specific=args_obj.os_specific, root=args_obj.root, strict=False,
81
+ )
82
+ elif cloud in target:
83
+ res = P(source).to_cloud(cloud=cloud, remotepath=target.replace(cloud + ":", ""),
84
+ zip=args_obj.zip, encrypt=args_obj.encrypt, pwd=args_obj.pwd,
85
+ rel2home=args_obj.rel2home, root=args_obj.root, os_specific=args_obj.os_specific, strict=False,
86
+ share=args_obj.share)
87
+ if args_obj.share:
88
+ print(res.as_url_str())
89
+ else: raise ValueError(f"Cloud `{cloud}` not found in source or target.")
90
+
91
+
92
+ if __name__ == "__main__":
93
+ arg_parser()
@@ -0,0 +1,38 @@
1
+
2
+ """Run cloud manager.
3
+ """
4
+
5
+ from crocodile.cluster.loader_runner import CloudManager
6
+ import argparse
7
+
8
+
9
+ def main():
10
+ parser = argparse.ArgumentParser()
11
+ parser.add_argument("-c", "--cloud", help="Rclone Config Name", action="store", type=str, default=None)
12
+ parser.add_argument("-s", "--serve", help="Start job server", action="store_true", default=False)
13
+ parser.add_argument("-R", "--reset_local", help="Clear local cache", action="store_true", default=False)
14
+ parser.add_argument("-r", "--rerun_jobs", help="Re-run jobs by bringing them back from wherever to the queue.", action="store_true", default=False)
15
+ parser.add_argument("-L", "--release_lock", help="Release lock.", action="store_true", default=False)
16
+ parser.add_argument("-f", "--queue_failed_jobs", help="Bring failed jobs back to queued jobs for a re-trial.", action="store_true", default=False)
17
+ parser.add_argument("-m", "--monitor_cloud", help="Monitor workers instead of running a job server.", action="store_true", default=False)
18
+ parser.add_argument("-j", "--num_jobs", help="Number of jobs the server will run in parallel.", action="store", type=int, default=1)
19
+ args = parser.parse_args()
20
+
21
+ cm = CloudManager(max_jobs=args.num_jobs, cloud=args.cloud, reset_local=args.reset_local)
22
+ if args.release_lock:
23
+ cm.claim_lock()
24
+ cm.release_lock()
25
+ if args.queue_failed_jobs:
26
+ cm.clean_failed_jobs_mess()
27
+ if args.rerun_jobs:
28
+ cm.rerun_jobs()
29
+ if args.monitor_cloud:
30
+ cm.run_monitor()
31
+ if args.serve:
32
+ cm.serve()
33
+ import sys
34
+ sys.exit(0)
35
+
36
+
37
+ if __name__ == '__main__':
38
+ main()