machineconfig 1.9__py3-none-any.whl → 1.91__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 (53) hide show
  1. machineconfig/__init__.py +1 -1
  2. machineconfig/jobs/python/check_installations.py +7 -5
  3. machineconfig/jobs/python/checkout_version.py +27 -32
  4. machineconfig/jobs/python/create_bootable_media.py +1 -1
  5. machineconfig/jobs/python/python_cargo_build_share.py +2 -2
  6. machineconfig/jobs/python/tasks.py +2 -2
  7. machineconfig/jobs/python_custom_installers/{helix.py → hx.py} +17 -5
  8. machineconfig/profile/create.py +23 -21
  9. machineconfig/profile/create_hardlinks.py +101 -0
  10. machineconfig/profile/shell.py +5 -5
  11. machineconfig/scripts/python/cloud_copy.py +19 -16
  12. machineconfig/scripts/python/cloud_repo_sync.py +92 -47
  13. machineconfig/scripts/python/cloud_sync.py +70 -63
  14. machineconfig/scripts/python/croshell.py +6 -6
  15. machineconfig/scripts/python/devops.py +19 -20
  16. machineconfig/scripts/python/devops_backup_retrieve.py +19 -10
  17. machineconfig/scripts/python/devops_devapps_install.py +80 -62
  18. machineconfig/scripts/python/devops_update_repos.py +5 -5
  19. machineconfig/scripts/python/dotfile.py +4 -4
  20. machineconfig/scripts/python/fire_jobs.py +57 -23
  21. machineconfig/scripts/python/gh_models.py +53 -0
  22. machineconfig/scripts/python/mount_nfs.py +1 -1
  23. machineconfig/scripts/python/mount_nw_drive.py +3 -3
  24. machineconfig/scripts/python/mount_ssh.py +2 -3
  25. machineconfig/scripts/python/pomodoro.py +1 -1
  26. machineconfig/scripts/python/repos.py +21 -22
  27. machineconfig/scripts/python/scheduler.py +1 -1
  28. machineconfig/scripts/python/start_slidev.py +10 -4
  29. machineconfig/scripts/python/start_terminals.py +5 -4
  30. machineconfig/scripts/python/wifi_conn.py +34 -42
  31. machineconfig/scripts/python/wsl_windows_transfer.py +1 -1
  32. machineconfig/setup_windows/wt_and_pwsh/set_pwsh_theme.py +1 -1
  33. machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +3 -2
  34. machineconfig/utils/installer.py +78 -39
  35. machineconfig/utils/procs.py +2 -2
  36. machineconfig/utils/scheduling.py +3 -3
  37. machineconfig/utils/utils.py +131 -52
  38. machineconfig/utils/ve.py +145 -95
  39. {machineconfig-1.9.dist-info → machineconfig-1.91.dist-info}/METADATA +160 -155
  40. machineconfig-1.91.dist-info/RECORD +69 -0
  41. machineconfig/jobs/python_custom_installers/azuredatastudio.py +0 -36
  42. machineconfig/jobs/python_custom_installers/bypass_paywall.py +0 -30
  43. machineconfig/jobs/python_custom_installers/docker_desktop.py +0 -52
  44. machineconfig/jobs/python_custom_installers/goes.py +0 -35
  45. machineconfig/jobs/python_custom_installers/lvim.py +0 -48
  46. machineconfig/jobs/python_custom_installers/ngrok.py +0 -39
  47. machineconfig/jobs/python_custom_installers/nvim.py +0 -48
  48. machineconfig/jobs/python_custom_installers/vscode.py +0 -45
  49. machineconfig/jobs/python_custom_installers/wezterm.py +0 -41
  50. machineconfig-1.9.dist-info/RECORD +0 -76
  51. {machineconfig-1.9.dist-info → machineconfig-1.91.dist-info}/LICENSE +0 -0
  52. {machineconfig-1.9.dist-info → machineconfig-1.91.dist-info}/WHEEL +0 -0
  53. {machineconfig-1.9.dist-info → machineconfig-1.91.dist-info}/top_level.txt +0 -0
@@ -1,14 +1,15 @@
1
1
 
2
2
  """utils"""
3
3
 
4
-
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
4
+ import git
5
+ from crocodile.file_management import P, Read
7
6
  from crocodile.core import randstr
8
7
  from crocodile.meta import Terminal
8
+
9
+ from machineconfig.utils.utils import CONFIG_PATH, DEFAULTS_PATH, PROGRAM_PATH, write_shell_script, get_shell_file_executing_python_script, get_shell_script, choose_one_option
9
10
  import argparse
10
11
  import platform
11
- from typing import Optional
12
+ from typing import Optional, Literal
12
13
  # import sys
13
14
  # import subprocess
14
15
 
@@ -22,13 +23,14 @@ def get_wt_cmd(wd1: P, wd2: P) -> str:
22
23
 
23
24
 
24
25
  def get_zellij_cmd(wd1: P, wd2: P) -> str:
25
- lines = [f""" zellij action new-tab --name gitdiff""",
26
- f"""zellij action new-pane --direction down --name local --cwd ./data """,
27
- f"""zellij action write-chars "cd '{wd1}'; git status" """,
28
- f"""zellij action move-focus up; zellij action close-pane """,
29
- f"""zellij action new-pane --direction down --name remote --cwd code """,
30
- f"""zellij action write-chars "cd '{wd2}' """,
31
- f"""git status" """
26
+ _ = wd1, wd2
27
+ lines = [""" zellij action new-tab --name gitdiff""",
28
+ """zellij action new-pane --direction down --name local --cwd ./data """,
29
+ """zellij action write-chars "cd '{wd1}'; git status" """,
30
+ """zellij action move-focus up; zellij action close-pane """,
31
+ """zellij action new-pane --direction down --name remote --cwd code """,
32
+ """zellij action write-chars "cd '{wd2}' """,
33
+ """git status" """
32
34
  ]
33
35
  return "; ".join(lines)
34
36
 
@@ -43,20 +45,23 @@ def args_parser():
43
45
 
44
46
  parser.add_argument("--cloud", "-c", help="rclone cloud profile name.", default=None)
45
47
  parser.add_argument("--message", "-m", help="Commit Message", default=f"new message {randstr()}")
46
- parser.add_argument("--skip_confirmation", "-s", help="Skip confirmation.", action="store_true", default=False)
48
+ # parser.add_argument("--skip_confirmation", "-s", help="Skip confirmation.", action="store_true", default=False)
47
49
  # parser.add_argument("--key", "-k", help="Key for encryption", default=None)
48
50
  parser.add_argument("--pwd", "-p", help="Password for encryption", default=None)
49
- parser.add_argument("--no_push", "-u", help="push to reomte.", action="store_true") # default is False
51
+ # parser.add_argument("--no_push", "-u", help="push to reomte.", action="store_true") # default is False
52
+ parser.add_argument("--action", "-a", help="Action to take if merge fails.", choices=["ask", "pushLocalMerge", "overwriteLocal", "InspectRepos", "RemoveLocalRclone"], default="ask")
50
53
  args = parser.parse_args()
51
54
 
52
55
  # if args.share:
53
56
  # from machineconfig.scripts.cloud.dotfiles import put
54
57
  # put()
55
58
  # return None
56
- main(cloud=args.cloud, path=args.path, message=args.message, skip_confirmation=args.skip_confirmation, pwd=args.pwd, push=not args.no_push)
59
+ main(cloud=args.cloud, path=args.path, message=args.message, action=args.action)
57
60
 
58
61
 
59
- 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):
62
+ def main(cloud: Optional[str] = None, path: Optional[str] = None, message: Optional[str] = None,
63
+ action: Literal["ask", "pushLocalMerge", "overwriteLocal", "InspectRepos", "RemoveLocalRclone"] = "ask",
64
+ pwd: Optional[str] = None):
60
65
  if cloud is None:
61
66
  try:
62
67
  cloud_resolved = Read.ini(DEFAULTS_PATH)['general']['rclone_config_name']
@@ -67,7 +72,7 @@ def main(cloud: Optional[str] = None, path: Optional[str] = None, message: Optio
67
72
  else: cloud_resolved = cloud
68
73
  # repo_root = P(args.repo).expanduser().absolute()
69
74
  repo_local_root = P.cwd() if path is None else P(path).expanduser().absolute()
70
- repo_local_obj = install_n_import("git", "gitpython").Repo(repo_local_root, search_parent_directories=True)
75
+ repo_local_obj = git.Repo(repo_local_root, search_parent_directories=True)
71
76
  repo_local_root = P(repo_local_obj.working_dir) # cwd might have been in a sub directory of repo_root, so its better to redefine it.
72
77
  CONFIG_PATH.joinpath("remote").create()
73
78
  repo_remote_root = CONFIG_PATH.joinpath("remote", repo_local_root.rel2home()) # .delete(sure=True)
@@ -79,7 +84,7 @@ def main(cloud: Optional[str] = None, path: Optional[str] = None, message: Optio
79
84
  print("Remote does not exist, creating it and exiting ... ")
80
85
  repo_local_root.to_cloud(cloud=cloud_resolved, zip=True, encrypt=True, rel2home=True, pwd=pwd, os_specific=False)
81
86
  return ""
82
- repo_remote_obj = install_n_import("git", "gitpython").Repo(repo_remote_root)
87
+ repo_remote_obj = git.Repo(repo_remote_root)
83
88
  if repo_remote_obj.is_dirty():
84
89
  print("=" * 50, '\n', f"WRANING: the remote `{repo_remote_root}` is dirty, please commit or stash changes before proceeding.", '\n', "=" * 50)
85
90
 
@@ -102,49 +107,76 @@ echo '-> Fetching originEnc remote.'
102
107
  git pull originEnc master
103
108
 
104
109
  """
105
- suffix = '.ps1' if platform.system() == 'Windows' else '.sh'
106
- res = Terminal().run(f". {P.tmpfile(suffix=suffix).write_text(script)}", shell="powershell").capture().print()
110
+
111
+ shell_path = get_shell_script(shell_script=script)
112
+ res = Terminal().run(f". {shell_path}", shell="powershell").capture().print()
107
113
 
108
114
  if res.is_successful(strict_err=True, strict_returcode=True):
109
115
  print("\n", "Pull succeeded, removing originEnc, the local copy of remote & pushing merged repo_root to remote ... ")
110
116
  repo_remote_root.delete(sure=True)
111
117
  from git.remote import Remote
112
118
  Remote.remove(repo_local_obj, "originEnc")
113
- if push:
114
- repo_local_root.to_cloud(cloud=cloud_resolved, zip=True, encrypt=True, rel2home=True, pwd=pwd, os_specific=False)
119
+ repo_local_root.to_cloud(cloud=cloud_resolved, zip=True, encrypt=True, rel2home=True, pwd=pwd, os_specific=False)
115
120
  else:
116
- print(f"Failed to pull, keeping local copy of remote at {repo_remote_root} ... ")
121
+ print(f"Failed to merge with no errors, keeping local copy of remote at {repo_remote_root} ... ")
117
122
 
118
- if push:
119
- if skip_confirmation: resp = "y"
120
- else: resp = input(f"Would you like to proceed syncing `{repo_local_root}` to `{cloud_resolved}` by pushing local changes to remote and deleting local copy of remote? y/[n] ") or "n"
121
- else: resp = "n"
122
-
123
- if resp.lower() == "y":
124
- delete_remote_repo_copy_and_push_local(remote_repo=repo_remote_root.str, local_repo=repo_local_root.str, cloud=cloud_resolved)
125
- else:
126
- program = f"""
123
+ # ================================================================================
124
+ option1 = 'Delete remote copy and push local:'
125
+ program_1_py = f"""
127
126
  from machineconfig.scripts.python.cloud_repo_sync import delete_remote_repo_copy_and_push_local as func
128
- func(remote_repo=r'{repo_remote_root.str}', local_repo=r'{repo_local_root.str}', cloud=r'{cloud_resolved}')
127
+ func(remote_repo=r'{repo_remote_root.to_str()}', local_repo=r'{repo_local_root.to_str()}', cloud=r'{cloud_resolved}')
129
128
  """
130
- shell_file = get_shell_file_executing_python_script(python_script=program)
131
- print(f"When ready, use this snippet: \n. {shell_file}")
132
- print(f"""
133
- Or, if you want to delete local repo and replace with remote, run the following bash commands:
134
-
129
+ shell_file_1 = get_shell_file_executing_python_script(python_script=program_1_py, ve_name="ve")
130
+ # ================================================================================
131
+
132
+ option2 = 'Delete local repo and replace it with remote copy:'
133
+ program_2 = f"""
135
134
  rm -rfd {repo_local_root}
136
135
  mv {repo_remote_root} {repo_local_root}
136
+ sudo chmod 600 ~/.ssh/*
137
+ sudo chmod 700 ~/.ssh
138
+ """
137
139
 
138
- """)
139
- if platform.system() == "Windows":
140
- program = get_wt_cmd(wd1=repo_local_root, wd2=repo_remote_root)
141
- write_shell_script(program=program, execute=True)
142
- return None
143
- elif platform.system() == "Linux":
144
- program = get_zellij_cmd(wd1=repo_local_root, wd2=repo_remote_root)
145
- write_shell_script(program=program, execute=True)
146
- return None
147
- else: raise NotImplementedError(f"Platform {platform.system()} not implemented.")
140
+ shell_file_2 = get_shell_script(shell_script=program_2)
141
+
142
+ # ================================================================================
143
+ option3 = 'Inspect repos:'
144
+ program_3_py = f"""
145
+ from machineconfig.scripts.python.cloud_repo_sync import inspect_repos as func
146
+ func(repo_local_root=r'{repo_local_root.to_str()}', repo_remote_root=r'{repo_remote_root.to_str()}')
147
+ """
148
+ shell_file_3 = get_shell_file_executing_python_script(python_script=program_3_py, ve_name="ve")
149
+ # ================================================================================
150
+
151
+ option4 = 'Remove problematic rclone file from repo and replace with remote:'
152
+ program_4 = """
153
+ rm ~/dotfiles/creds/rclone/rclone.conf
154
+ cp ~/.config/machineconfig/remote/dotfiles/creds/rclone/rclone.conf ~/dotfiles/creds/rclone
155
+ """
156
+ shell_file_4 = get_shell_script(shell_script=program_4)
157
+ # ================================================================================
158
+
159
+ print(f"• {option1:75} 👉 {shell_file_1}")
160
+ print(f"• {option2:75} 👉 {shell_file_2}")
161
+ print(f"• {option3:75} 👉 {shell_file_3}")
162
+ print(f"• {option4:75} 👉 {shell_file_4}")
163
+
164
+ match action:
165
+ case "ask":
166
+ choice = choose_one_option(options=[option1, option2, option3, option4])
167
+ if choice == option1: PROGRAM_PATH.write_text(shell_file_1.read_text())
168
+ elif choice == option2: PROGRAM_PATH.write_text(program_2)
169
+ elif choice == option3: PROGRAM_PATH.write_text(shell_file_3.read_text())
170
+ elif choice == option4: PROGRAM_PATH.write_text(program_4)
171
+ else: raise NotImplementedError(f"Choice {choice} not implemented.")
172
+ case "pushLocalMerge":
173
+ PROGRAM_PATH.write_text(shell_file_1.read_text())
174
+ case "overwriteLocal":
175
+ PROGRAM_PATH.write_text(program_2)
176
+ case "InspectRepos":
177
+ PROGRAM_PATH.write_text(shell_file_3.read_text())
178
+ case "RemoveLocalRclone":
179
+ PROGRAM_PATH.write_text(program_4)
148
180
 
149
181
 
150
182
  def delete_remote_repo_copy_and_push_local(remote_repo: str, local_repo: str, cloud: str):
@@ -158,5 +190,18 @@ def delete_remote_repo_copy_and_push_local(remote_repo: str, local_repo: str, cl
158
190
  repo_root_path.to_cloud(cloud=cloud, zip=True, encrypt=True, rel2home=True, os_specific=False)
159
191
 
160
192
 
193
+ def inspect_repos(repo_local_root: str, repo_remote_root: str):
194
+ if platform.system() == "Windows":
195
+ program = get_wt_cmd(wd1=P(repo_local_root), wd2=P(repo_local_root))
196
+ write_shell_script(program=program, execute=True)
197
+ return None
198
+ elif platform.system() == "Linux":
199
+ program = get_zellij_cmd(wd1=P(repo_local_root), wd2=P(repo_remote_root))
200
+ write_shell_script(program=program, execute=True)
201
+ return None
202
+ else: raise NotImplementedError(f"Platform {platform.system()} not implemented.")
203
+
204
+
205
+
161
206
  if __name__ == "__main__":
162
207
  args_parser()
@@ -4,8 +4,8 @@ TODO: use tap typed-argument-parser to parse args
4
4
  TODO: use typer to make clis
5
5
  """
6
6
 
7
- from crocodile.file_management import P, Read, Struct
8
- # from crocodile.core import install_n_import
7
+ from crocodile.file_management import P, Read
8
+ from crocodile.core import Struct
9
9
  from machineconfig.utils.utils import PROGRAM_PATH, DEFAULTS_PATH
10
10
  from machineconfig.scripts.python.cloud_mount import get_mprocs_mount_txt
11
11
  import argparse
@@ -22,12 +22,12 @@ ES = "^" # chosen carefully to not mean anything on any shell. `$` was a bad ch
22
22
 
23
23
 
24
24
  class ArgsDefaults:
25
- # source: str = None
26
- # target: str = None
27
- encrypt: bool = False
28
- zip_: bool = False
29
- overwrite: bool = False
30
- share: bool = False
25
+ # source: str=None
26
+ # target: str=None
27
+ encrypt: bool=False
28
+ zip_: bool=False
29
+ overwrite: bool=False
30
+ share: bool=False
31
31
  rel2home = False
32
32
  root = None
33
33
  os_specific = False
@@ -35,19 +35,19 @@ class ArgsDefaults:
35
35
  pwd = None
36
36
 
37
37
 
38
- @dataclass(config=ConfigDict(extra="forbid", frozen=True))
38
+ @dataclass(config=ConfigDict(extra="forbid", frozen=False))
39
39
  class Args():
40
40
  cloud: Optional[str] = None
41
41
 
42
- zip: bool = ArgsDefaults.zip_
43
- overwrite: bool = ArgsDefaults.overwrite
44
- share: bool = ArgsDefaults.share
42
+ zip: bool=ArgsDefaults.zip_
43
+ overwrite: bool=ArgsDefaults.overwrite
44
+ share: bool=ArgsDefaults.share
45
45
 
46
46
  root: Optional[str] = ArgsDefaults.root
47
- os_specific: bool = ArgsDefaults.os_specific
48
- rel2home: bool = ArgsDefaults.rel2home
47
+ os_specific: bool=ArgsDefaults.os_specific
48
+ rel2home: bool=ArgsDefaults.rel2home
49
49
 
50
- encrypt: bool = ArgsDefaults.encrypt
50
+ encrypt: bool=ArgsDefaults.encrypt
51
51
  key: Optional[str] = ArgsDefaults.key
52
52
  pwd: Optional[str] = ArgsDefaults.pwd
53
53
 
@@ -70,7 +70,7 @@ def absolute(path: str) -> P:
70
70
  return obj.absolute()
71
71
 
72
72
 
73
- def get_secure_share_cloud_config(interactive: bool = True) -> Args:
73
+ def get_secure_share_cloud_config(interactive: bool=True) -> Args:
74
74
  if os.environ.get("CLOUD_CONFIG_NAME") is not None:
75
75
  default_cloud = os.environ.get("CLOUD_CONFIG_NAME")
76
76
  assert default_cloud is not None
@@ -98,7 +98,7 @@ def get_secure_share_cloud_config(interactive: bool = True) -> Args:
98
98
  pwd=pwd, encrypt=True,
99
99
  zip=True, overwrite=True, share=True,
100
100
  rel2home=True, root="myshare", os_specific=False,)
101
- Struct(res.__dict__).print(as_config=True, title=f"⚠️ Using SecureShare cloud config")
101
+ Struct(res.__dict__).print(as_config=True, title="⚠️ Using SecureShare cloud config")
102
102
  return res
103
103
 
104
104
 
@@ -113,55 +113,62 @@ def find_cloud_config(path: P):
113
113
 
114
114
 
115
115
  def parse_cloud_source_target(args: Args, source: str, target: str) -> tuple[str, str, str]:
116
+ config = args.config
117
+ root = args.root
118
+ rel2home = args.rel2home
119
+ pwd = args.pwd
120
+ encrypt = args.encrypt
121
+ zip_arg = args.zip
122
+ share = args.share
123
+ os_specific = args.os_specific
124
+
125
+ if config == "ss":
126
+ maybe_config = get_secure_share_cloud_config()
127
+ elif config is not None:
128
+ maybe_config = Args.from_config(absolute(config))
129
+ else:
130
+ maybe_config = None
131
+
116
132
  if source.startswith(":"): # default cloud name is omitted cloud_name: # or ES in source
117
133
  # At the moment, this cloud.json defaults overrides the args and is activated only when source or target are just ":"
118
134
  # consider activating it by a flag, and also not not overriding explicitly passed args options.
119
- assert ES not in target, f"Not Implemented here yet."
135
+ assert ES not in target, "Not Implemented here yet."
120
136
  path = absolute(target)
121
- if args.config is None:
122
- maybe_config: Optional[Args] = find_cloud_config(path=path)
123
- else:
124
- if args.config == "ss": maybe_config = get_secure_share_cloud_config()
125
- else: maybe_config = Args.from_config(absolute(args.config))
137
+ if maybe_config is None: maybe_config: Optional[Args] = find_cloud_config(path=path)
126
138
 
127
139
  if maybe_config is None:
128
- default_cloud: str = Read.ini(DEFAULTS_PATH)['general']['rclone_config_name']
140
+ default_cloud: str=Read.ini(DEFAULTS_PATH)['general']['rclone_config_name']
129
141
  print(f"⚠️ Using default cloud: {default_cloud}")
130
142
  source = default_cloud + ":" + source[1:]
131
143
  else:
132
144
  tmp = maybe_config
133
145
  source = f"{tmp.cloud}:" + source[1:]
134
- args.root = tmp.root
135
- args.rel2home = tmp.rel2home
136
- args.pwd = tmp.pwd
137
- args.encrypt = tmp.encrypt
138
- args.zip = tmp.zip
139
- args.share = tmp.share
140
- # args.jh = 22
146
+ root = tmp.root
147
+ rel2home = tmp.rel2home
148
+ pwd = tmp.pwd
149
+ encrypt = tmp.encrypt
150
+ zip_arg = tmp.zip
151
+ share = tmp.share
141
152
 
142
153
  if target.startswith(":"): # default cloud name is omitted cloud_name: # or ES in target
143
- assert ES not in source, f"Not Implemented here yet."
154
+ assert ES not in source, "Not Implemented here yet."
144
155
  path = absolute(source)
145
- if args.config is None:
146
- maybe_config = find_cloud_config(path)
147
- else:
148
- if args.config == "ss": maybe_config = get_secure_share_cloud_config()
149
- else: maybe_config = Args.from_config(absolute(args.config))
150
-
151
- if maybe_config is not None:
152
- tmp = maybe_config
153
- target = f"{tmp.cloud}:" + target[1:]
154
- args.root = tmp.root
155
- args.rel2home = tmp.rel2home
156
- args.pwd = tmp.pwd
157
- args.encrypt = tmp.encrypt
158
- args.zip = tmp.zip
159
- args.share = tmp.share
156
+ if maybe_config is None: maybe_config = find_cloud_config(path)
160
157
 
161
- else:
158
+ if maybe_config is None:
162
159
  default_cloud = Read.ini(DEFAULTS_PATH)['general']['rclone_config_name']
163
160
  print(f"⚠️ Using default cloud: {default_cloud}")
164
161
  target = default_cloud + ":" + target[1:]
162
+ else:
163
+ tmp = maybe_config
164
+ target = f"{tmp.cloud}:" + target[1:]
165
+ root = tmp.root
166
+ rel2home = tmp.rel2home
167
+ pwd = tmp.pwd
168
+ encrypt = tmp.encrypt
169
+ zip_arg = tmp.zip
170
+ share = tmp.share
171
+
165
172
 
166
173
  if ":" in source and (source[1] != ":" if len(source) > 1 else True): # avoid the deceptive case of "C:/"
167
174
  source_parts: list[str] = source.split(":")
@@ -170,37 +177,37 @@ def parse_cloud_source_target(args: Args, source: str, target: str) -> tuple[str
170
177
  if len(source_parts) > 1 and source_parts[1] == ES: # the source path is to be inferred from target.
171
178
  assert ES not in target, f"You can't use expand symbol `{ES}` in both source and target. Cyclical inference dependency arised."
172
179
  target_obj = absolute(target)
173
- remote_path = target_obj.get_remote_path(os_specific=args.os_specific, root=args.root, rel2home=args.rel2home, strict=False)
180
+ remote_path = target_obj.get_remote_path(os_specific=os_specific, root=root, rel2home=rel2home, strict=False)
174
181
  source = f"{cloud}:{remote_path.as_posix()}"
175
-
176
182
  else: # source path is mentioned, target? maybe.
177
183
  if target == ES: # target path is to be inferred from source.
178
- raise NotImplementedError(f"There is no .get_local_path method yet")
184
+ raise NotImplementedError("There is no .get_local_path method yet")
179
185
  else:
180
186
  target_obj = absolute(target)
181
- if args.zip and ".zip" not in source: source += ".zip"
182
- if args.encrypt and ".enc" not in source: source += ".enc"
187
+ if zip_arg and ".zip" not in source: source += ".zip"
188
+ if encrypt and ".enc" not in source: source += ".enc"
183
189
 
184
190
  elif ":" in target and (target[1] != ":" if len(target) > 1 else True): # avoid the case of "C:/"
185
191
  target_parts: list[str] = target.split(":")
186
192
  cloud = target.split(":")[0]
187
193
 
188
194
  if len(target_parts) > 1 and target_parts[1] == ES: # the target path is to be inferred from source.
189
- assert ES not in source, f"You can't use $ in both source and target. Cyclical inference dependency arised."
195
+ assert ES not in source, "You can't use $ in both source and target. Cyclical inference dependency arised."
190
196
  source_obj = absolute(source)
191
- remote_path = source_obj.get_remote_path(os_specific=args.os_specific, root=args.root, rel2home=args.rel2home, strict=False)
197
+ remote_path = source_obj.get_remote_path(os_specific=os_specific, root=root, rel2home=rel2home, strict=False)
192
198
  target = f"{cloud}:{remote_path.as_posix()}"
193
199
  else: # target path is mentioned, source? maybe.
194
200
  target = str(target)
195
201
  if source == ES:
196
- raise NotImplementedError(f"There is no .get_local_path method yet")
202
+ raise NotImplementedError("There is no .get_local_path method yet")
197
203
  else:
198
204
  source_obj = absolute(source)
199
- if args.zip and ".zip" not in target: target += ".zip"
200
- if args.encrypt and ".enc" not in target: target += ".enc"
205
+ if zip_arg and ".zip" not in target: target += ".zip"
206
+ if encrypt and ".enc" not in target: target += ".enc"
201
207
  else:
202
208
  raise ValueError("Either source or target must be a remote path (i.e. machine:path)")
203
209
  Struct({"cloud": cloud, "source": str(source), "target": str(target)}).print(as_config=True, title="CLI Resolution")
210
+ _ = pwd, encrypt, zip_arg, share
204
211
  return cloud, str(source), str(target)
205
212
 
206
213
 
@@ -224,11 +231,11 @@ def args_parser():
224
231
 
225
232
  args = parser.parse_args()
226
233
  args_dict = vars(args)
227
- source: str = args_dict.pop("source")
228
- target: str = args_dict.pop("target")
229
- verbose: bool = args_dict.pop("verbose")
230
- delete: bool = args_dict.pop("delete")
231
- bisync: bool = args_dict.pop("bisync")
234
+ source: str=args_dict.pop("source")
235
+ target: str=args_dict.pop("target")
236
+ verbose: bool=args_dict.pop("verbose")
237
+ delete: bool=args_dict.pop("delete")
238
+ bisync: bool=args_dict.pop("bisync")
232
239
  transfers: int = args_dict.pop("transfers")
233
240
  args_obj = Args(**args_dict)
234
241
 
@@ -43,7 +43,7 @@ except Exception as e:
43
43
  return pycode
44
44
 
45
45
 
46
- def get_read_pyfile_pycode(path: P, as_module: bool, cmd: str = ""):
46
+ def get_read_pyfile_pycode(path: P, as_module: bool, cmd: str=""):
47
47
  if as_module: pycode = fr"""
48
48
  import sys
49
49
  sys.path.append(r'{path.parent}')
@@ -72,8 +72,8 @@ def build_parser():
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="")
74
74
  parser.add_argument("--cmd", "-c", dest="cmd", help="python command to interpret", default="")
75
- parser.add_argument("--terminal", "-t", dest="terminal", help=f"specify which terminal to be used. Default console host.", default="") # can choose `wt`
76
- parser.add_argument("--shell", "-S", dest="shell", help=f"specify which shell to be used. Defaults to CMD.", default="")
75
+ parser.add_argument("--terminal", "-t", dest="terminal", help="specify which terminal to be used. Default console host.", default="") # can choose `wt`
76
+ parser.add_argument("--shell", "-S", dest="shell", help="specify which shell to be used. Defaults to CMD.", default="")
77
77
 
78
78
  args = parser.parse_args()
79
79
  # print(f"Crocodile.run: args of the firing command = {args.__dict__}")
@@ -142,10 +142,10 @@ print_logo(logo="crocodile")
142
142
  ve = get_ve_profile(P(file)) if args.ve is None else str(args.ve)
143
143
 
144
144
  final_program = f"""
145
- # deactivate
146
- . activate_ve {ve}
145
+ . $HOME/scripts/activate_ve '{ve}'
147
146
  {interpreter} """
148
- if interpreter == "ipython": final_program += f"{interactivity} --profile {profile} --no-banner"
147
+ if interpreter == "ipython":
148
+ final_program += f"{interactivity} --profile {profile} --no-banner"
149
149
  final_program += f" {str(pyfile)}"
150
150
  print(f"🔥 sourcing ... {pyfile}")
151
151
  # print(f"Running ... {final_program}")
@@ -1,9 +1,8 @@
1
1
 
2
2
 
3
-
4
3
  """devops
5
4
  """
6
- from crocodile.file_management import P
5
+
7
6
  from machineconfig.utils.utils import display_options, PROGRAM_PATH, write_shell_script
8
7
  from platform import system
9
8
  from enum import Enum
@@ -49,19 +48,19 @@ def main(which: Optional[str] = None):
49
48
 
50
49
  elif choice_key == Options.ve.value:
51
50
  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()}")
51
+ reply: bool=False
52
+ # if P.cwd().joinpath(".ve.ini").exists():
53
+ # reply = input("Detected .ve.ini file. Do you want to use it to build ve? (y/[n]): ") == "y"
54
+ # if reply:
55
+ # from machineconfig.utils.ve import get_ve_install_script_from_specs
56
+ # program_win = get_ve_install_script_from_specs(repo_root=P.cwd().to_str(), system="Windows")
57
+ # program_lin = get_ve_install_script_from_specs(repo_root=P.cwd().to_str(), system="Linux")
58
+ # install_reply = input("Proceed with installation? (y/[n]): ") == "y"
59
+ # if not install_reply: program = ""
60
+ # else:
61
+ # if system() == "Windows": program = program_win
62
+ # elif system() == "Linux": program = program_lin
63
+ # else: raise ValueError(f"Unknown system: {system()}")
65
64
 
66
65
  if not reply:
67
66
  from machineconfig.utils.ve import get_ve_install_script
@@ -92,18 +91,18 @@ def main(which: Optional[str] = None):
92
91
  program = helper.main()
93
92
 
94
93
  elif choice_key == Options.ssh_setup.value:
95
- program_windows = f"""Invoke-WebRequest https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_windows/openssh_all.ps1 | Invoke-Expression # https://github.com/thisismygitrepo.keys"""
96
- program_linux = f"""curl https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_linux/openssh_all.sh | sudo bash # https://github.com/thisismygitrepo.keys"""
94
+ program_windows = """Invoke-WebRequest https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_windows/openssh_all.ps1 | Invoke-Expression # https://github.com/thisismygitrepo.keys"""
95
+ program_linux = """curl https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_linux/openssh_all.sh | sudo bash # https://github.com/thisismygitrepo.keys"""
97
96
  program = program_linux if system() == "Linux" else program_windows
98
97
 
99
98
  elif choice_key == Options.ssh_setup_wsl.value:
100
- program = f"""curl https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_linux/openssh_wsl.sh | sudo bash"""
99
+ program = """curl https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_linux/openssh_wsl.sh | sudo bash"""
101
100
 
102
101
  elif choice_key == Options.backup.value:
103
- from machineconfig.scripts.python.devops_backup_retrieve import main as helper
102
+ from machineconfig.scripts.python.devops_backup_retrieve import main_backup_retrieve as helper
104
103
  program = helper(direction="BACKUP")
105
104
  elif choice_key == Options.retreive.value:
106
- from machineconfig.scripts.python.devops_backup_retrieve import main as helper
105
+ from machineconfig.scripts.python.devops_backup_retrieve import main_backup_retrieve as helper
107
106
  program = helper(direction="RETRIEVE")
108
107
 
109
108
  elif choice_key == Options.scheduler.value:
@@ -4,7 +4,7 @@
4
4
 
5
5
  # import subprocess
6
6
  from crocodile.file_management import Read, P
7
- from machineconfig.utils.utils import LIBRARY_ROOT, DEFAULTS_PATH, print_code, choose_cloud_interactively, display_options
7
+ from machineconfig.utils.utils import LIBRARY_ROOT, DEFAULTS_PATH, print_code, choose_cloud_interactively, choose_multiple_options
8
8
  from machineconfig.scripts.python.cloud_sync import ES
9
9
  from platform import system
10
10
  from typing import Any, Literal, Optional
@@ -13,23 +13,25 @@ from typing import Any, Literal, Optional
13
13
  OPTIONS = Literal["BACKUP", "RETRIEVE"]
14
14
 
15
15
 
16
- def main(direction: OPTIONS, which: Optional[str] = None):
16
+ def main_backup_retrieve(direction: OPTIONS, which: Optional[str] = None):
17
17
  try:
18
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
 
22
- bu_file: dict[str, Any] = LIBRARY_ROOT.joinpath("profile/backup.toml").readit()
22
+ bu_file: dict[str, Any] = Read.toml(LIBRARY_ROOT.joinpath("profile/backup.toml"))
23
23
  if system() == "Linux": bu_file = {key: val for key, val in bu_file.items() if "windows" not in key}
24
24
  elif system() == "Windows": bu_file = {key: val for key, val in bu_file.items() if "linux" not in key}
25
25
 
26
26
  if which is None:
27
- choice_key = display_options(msg=f"WHICH FILE of the following do you want to {direction}?", options=['all'] + list(bu_file.keys()))
28
- assert isinstance(choice_key, str)
29
- else: choice_key = which
27
+ choices = choose_multiple_options(msg=f"WHICH FILE of the following do you want to {direction}?", options=['all'] + list(bu_file.keys()))
28
+ else:
29
+ choices = which.split(",") if isinstance(which, str) else which
30
30
 
31
- if choice_key == "all": items = bu_file
32
- else: items = {choice_key: bu_file[choice_key]}
31
+ if "all" in choices: items = bu_file
32
+ else:
33
+ # items = {choices: bu_file[choices]}
34
+ items = {key: val for key, val in bu_file.items() if key in choices}
33
35
 
34
36
  program = f"""$cloud = "{cloud}:{ES}" \n """ if system() == "Windows" else f"""cloud="{cloud}:{ES}" \n """
35
37
  for item_name, item in items.items():
@@ -42,11 +44,18 @@ def main(direction: OPTIONS, which: Optional[str] = None):
42
44
  if flags: flags = "-" + flags
43
45
  if direction == "BACKUP": program += f"""\ncloud_copy "{P(item['path']).as_posix()}" $cloud {flags}\n"""
44
46
  elif direction == "RETRIEVE": program += f"""\ncloud_copy $cloud "{P(item['path']).as_posix()}" {flags}\n"""
45
- else: raise RuntimeError(f"Unknown direction: {direction}")
46
- if item_name == "dotfiles" and system() == "Linux": program += f"""\nchmod 700 ~/.ssh/*\n"""
47
+ else:
48
+ raise RuntimeError(f"Unknown direction: {direction}")
49
+ if item_name == "dotfiles" and system() == "Linux": program += """\nchmod 700 ~/.ssh/*\n"""
47
50
  print_code(program, lexer="shell", desc=f"{direction} script")
48
51
  return program
49
52
 
50
53
 
54
+ def main(direction: OPTIONS, which: Optional[str] = None):
55
+ code = main_backup_retrieve(direction=direction, which=which)
56
+ from machineconfig.utils.utils import write_shell_script
57
+ write_shell_script(program=code, desc="backup_retrieve.sh")
58
+
59
+
51
60
  if __name__ == "__main__":
52
61
  pass