machineconfig 1.9__py3-none-any.whl → 1.92__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 (55) hide show
  1. machineconfig/__init__.py +2 -4
  2. machineconfig/jobs/python/check_installations.py +14 -6
  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} +21 -6
  8. machineconfig/profile/create.py +23 -21
  9. machineconfig/profile/create_hardlinks.py +101 -0
  10. machineconfig/profile/shell.py +10 -7
  11. machineconfig/scripts/python/cloud_copy.py +19 -16
  12. machineconfig/scripts/python/cloud_repo_sync.py +94 -47
  13. machineconfig/scripts/python/cloud_sync.py +78 -61
  14. machineconfig/scripts/python/croshell.py +6 -6
  15. machineconfig/scripts/python/devops.py +22 -22
  16. machineconfig/scripts/python/devops_add_ssh_key.py +1 -1
  17. machineconfig/scripts/python/devops_backup_retrieve.py +19 -10
  18. machineconfig/scripts/python/devops_devapps_install.py +80 -62
  19. machineconfig/scripts/python/devops_update_repos.py +5 -5
  20. machineconfig/scripts/python/dotfile.py +4 -4
  21. machineconfig/scripts/python/fire_jobs.py +115 -63
  22. machineconfig/scripts/python/gh_models.py +55 -0
  23. machineconfig/scripts/python/mount_nfs.py +1 -1
  24. machineconfig/scripts/python/mount_nw_drive.py +3 -3
  25. machineconfig/scripts/python/mount_ssh.py +2 -3
  26. machineconfig/scripts/python/pomodoro.py +1 -1
  27. machineconfig/scripts/python/repos.py +22 -23
  28. machineconfig/scripts/python/scheduler.py +1 -1
  29. machineconfig/scripts/python/start_slidev.py +12 -6
  30. machineconfig/scripts/python/start_terminals.py +5 -4
  31. machineconfig/scripts/python/wifi_conn.py +34 -42
  32. machineconfig/scripts/python/wsl_windows_transfer.py +1 -1
  33. machineconfig/settings/__init__.py +0 -0
  34. machineconfig/setup_windows/wt_and_pwsh/set_pwsh_theme.py +1 -1
  35. machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +3 -2
  36. machineconfig/utils/installer.py +86 -41
  37. machineconfig/utils/procs.py +2 -2
  38. machineconfig/utils/scheduling.py +3 -3
  39. machineconfig/utils/utils.py +136 -56
  40. machineconfig/utils/ve.py +145 -95
  41. {machineconfig-1.9.dist-info → machineconfig-1.92.dist-info}/METADATA +160 -155
  42. machineconfig-1.92.dist-info/RECORD +70 -0
  43. machineconfig/jobs/python_custom_installers/azuredatastudio.py +0 -36
  44. machineconfig/jobs/python_custom_installers/bypass_paywall.py +0 -30
  45. machineconfig/jobs/python_custom_installers/docker_desktop.py +0 -52
  46. machineconfig/jobs/python_custom_installers/goes.py +0 -35
  47. machineconfig/jobs/python_custom_installers/lvim.py +0 -48
  48. machineconfig/jobs/python_custom_installers/ngrok.py +0 -39
  49. machineconfig/jobs/python_custom_installers/nvim.py +0 -48
  50. machineconfig/jobs/python_custom_installers/vscode.py +0 -45
  51. machineconfig/jobs/python_custom_installers/wezterm.py +0 -41
  52. machineconfig-1.9.dist-info/RECORD +0 -76
  53. {machineconfig-1.9.dist-info → machineconfig-1.92.dist-info}/LICENSE +0 -0
  54. {machineconfig-1.9.dist-info → machineconfig-1.92.dist-info}/WHEEL +0 -0
  55. {machineconfig-1.9.dist-info → machineconfig-1.92.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,79 @@ 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} ... ")
117
-
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"
121
+ print(f"Failed to merge with no errors, keeping local copy of remote at {repo_remote_root} ... ")
122
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 $HOME/.ssh/*
137
+ sudo chmod 700 $HOME/.ssh
138
+ """
139
+
140
+ shell_file_2 = get_shell_script(shell_script=program_2)
137
141
 
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.")
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 = f"""
153
+ rm $HOME/dotfiles/creds/rclone/rclone.conf
154
+ cp $HOME/.config/machineconfig/remote/dotfiles/creds/rclone/rclone.conf $HOME/dotfiles/creds/rclone
155
+ cd $HOME/dotfiles
156
+ git commit -am "finished merging"
157
+ . {shell_file_1}
158
+ """
159
+ shell_file_4 = get_shell_script(shell_script=program_4)
160
+ # ================================================================================
161
+
162
+ print(f"• {option1:75} 👉 {shell_file_1}")
163
+ print(f"• {option2:75} 👉 {shell_file_2}")
164
+ print(f"• {option3:75} 👉 {shell_file_3}")
165
+ print(f"• {option4:75} 👉 {shell_file_4}")
166
+
167
+ match action:
168
+ case "ask":
169
+ choice = choose_one_option(options=[option1, option2, option3, option4], fzf=False)
170
+ if choice == option1: PROGRAM_PATH.write_text(shell_file_1.read_text())
171
+ elif choice == option2: PROGRAM_PATH.write_text(program_2)
172
+ elif choice == option3: PROGRAM_PATH.write_text(shell_file_3.read_text())
173
+ elif choice == option4: PROGRAM_PATH.write_text(program_4)
174
+ else: raise NotImplementedError(f"Choice {choice} not implemented.")
175
+ case "pushLocalMerge":
176
+ PROGRAM_PATH.write_text(shell_file_1.read_text())
177
+ case "overwriteLocal":
178
+ PROGRAM_PATH.write_text(program_2)
179
+ case "InspectRepos":
180
+ PROGRAM_PATH.write_text(shell_file_3.read_text())
181
+ case "RemoveLocalRclone":
182
+ PROGRAM_PATH.write_text(program_4)
148
183
 
149
184
 
150
185
  def delete_remote_repo_copy_and_push_local(remote_repo: str, local_repo: str, cloud: str):
@@ -158,5 +193,17 @@ def delete_remote_repo_copy_and_push_local(remote_repo: str, local_repo: str, cl
158
193
  repo_root_path.to_cloud(cloud=cloud, zip=True, encrypt=True, rel2home=True, os_specific=False)
159
194
 
160
195
 
196
+ def inspect_repos(repo_local_root: str, repo_remote_root: str):
197
+ if platform.system() == "Windows":
198
+ program = get_wt_cmd(wd1=P(repo_local_root), wd2=P(repo_local_root))
199
+ write_shell_script(program=program, execute=True, desc="Inspecting repos ...", preserve_cwd=True, display=True)
200
+ return None
201
+ elif platform.system() == "Linux":
202
+ program = get_zellij_cmd(wd1=P(repo_local_root), wd2=P(repo_remote_root))
203
+ write_shell_script(program=program, execute=True, desc="Inspecting repos ...", preserve_cwd=True, display=True)
204
+ return None
205
+ else: raise NotImplementedError(f"Platform {platform.system()} not implemented.")
206
+
207
+
161
208
  if __name__ == "__main__":
162
209
  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,13 +35,13 @@ 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
47
  os_specific: bool = ArgsDefaults.os_specific
@@ -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,71 @@ 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
+ if config == "ss":
118
+ maybe_config = get_secure_share_cloud_config()
119
+ elif config is not None:
120
+ maybe_config = Args.from_config(absolute(config))
121
+ else:
122
+ maybe_config = None
123
+
124
+ if maybe_config is not None:
125
+ if args.zip == ArgsDefaults.zip_: args.zip = maybe_config.zip
126
+ if args.encrypt == ArgsDefaults.encrypt: args.encrypt = maybe_config.encrypt
127
+ if args.share == ArgsDefaults.share: args.share = maybe_config.share
128
+ if args.root == ArgsDefaults.root: args.root = maybe_config.root
129
+ if args.rel2home == ArgsDefaults.rel2home: args.rel2home = maybe_config.rel2home
130
+ if args.pwd == ArgsDefaults.pwd: args.pwd = maybe_config.pwd
131
+ if args.os_specific == ArgsDefaults.os_specific: args.os_specific = maybe_config.os_specific
132
+
133
+ root = args.root
134
+ rel2home = args.rel2home
135
+ pwd = args.pwd
136
+ encrypt = args.encrypt
137
+ zip_arg = args.zip
138
+ share = args.share
139
+ os_specific = args.os_specific
140
+
116
141
  if source.startswith(":"): # default cloud name is omitted cloud_name: # or ES in source
117
142
  # At the moment, this cloud.json defaults overrides the args and is activated only when source or target are just ":"
118
143
  # 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."
144
+ assert ES not in target, "Not Implemented here yet."
120
145
  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))
146
+ if maybe_config is None: maybe_config: Optional[Args] = find_cloud_config(path=path)
126
147
 
127
148
  if maybe_config is None:
128
- default_cloud: str = Read.ini(DEFAULTS_PATH)['general']['rclone_config_name']
149
+ default_cloud: str=Read.ini(DEFAULTS_PATH)['general']['rclone_config_name']
129
150
  print(f"⚠️ Using default cloud: {default_cloud}")
130
151
  source = default_cloud + ":" + source[1:]
131
152
  else:
132
153
  tmp = maybe_config
133
154
  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
155
+ root = tmp.root
156
+ rel2home = tmp.rel2home
157
+ pwd = tmp.pwd
158
+ encrypt = tmp.encrypt
159
+ zip_arg = tmp.zip
160
+ share = tmp.share
141
161
 
142
162
  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."
163
+ assert ES not in source, "Not Implemented here yet."
144
164
  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))
165
+ if maybe_config is None: maybe_config = find_cloud_config(path)
150
166
 
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
160
-
161
- else:
167
+ if maybe_config is None:
162
168
  default_cloud = Read.ini(DEFAULTS_PATH)['general']['rclone_config_name']
163
169
  print(f"⚠️ Using default cloud: {default_cloud}")
164
170
  target = default_cloud + ":" + target[1:]
171
+ else:
172
+ tmp = maybe_config
173
+ target = f"{tmp.cloud}:" + target[1:]
174
+ root = tmp.root
175
+ rel2home = tmp.rel2home
176
+ pwd = tmp.pwd
177
+ encrypt = tmp.encrypt
178
+ zip_arg = tmp.zip
179
+ share = tmp.share
180
+
165
181
 
166
182
  if ":" in source and (source[1] != ":" if len(source) > 1 else True): # avoid the deceptive case of "C:/"
167
183
  source_parts: list[str] = source.split(":")
@@ -170,37 +186,38 @@ def parse_cloud_source_target(args: Args, source: str, target: str) -> tuple[str
170
186
  if len(source_parts) > 1 and source_parts[1] == ES: # the source path is to be inferred from target.
171
187
  assert ES not in target, f"You can't use expand symbol `{ES}` in both source and target. Cyclical inference dependency arised."
172
188
  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)
189
+ remote_path = target_obj.get_remote_path(os_specific=os_specific, root=root, rel2home=rel2home, strict=False)
174
190
  source = f"{cloud}:{remote_path.as_posix()}"
175
-
176
191
  else: # source path is mentioned, target? maybe.
177
192
  if target == ES: # target path is to be inferred from source.
178
- raise NotImplementedError(f"There is no .get_local_path method yet")
193
+ raise NotImplementedError("There is no .get_local_path method yet")
179
194
  else:
180
195
  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"
196
+ if zip_arg and ".zip" not in source:
197
+ source += ".zip"
198
+ if encrypt and ".enc" not in source:
199
+ source += ".enc"
183
200
 
184
201
  elif ":" in target and (target[1] != ":" if len(target) > 1 else True): # avoid the case of "C:/"
185
202
  target_parts: list[str] = target.split(":")
186
203
  cloud = target.split(":")[0]
187
-
188
204
  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."
205
+ assert ES not in source, "You can't use $ in both source and target. Cyclical inference dependency arised."
190
206
  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)
207
+ remote_path = source_obj.get_remote_path(os_specific=os_specific, root=root, rel2home=rel2home, strict=False)
192
208
  target = f"{cloud}:{remote_path.as_posix()}"
193
209
  else: # target path is mentioned, source? maybe.
194
210
  target = str(target)
195
211
  if source == ES:
196
- raise NotImplementedError(f"There is no .get_local_path method yet")
212
+ raise NotImplementedError("There is no .get_local_path method yet")
197
213
  else:
198
214
  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"
215
+ if zip_arg and ".zip" not in target: target += ".zip"
216
+ if encrypt and ".enc" not in target: target += ".enc"
201
217
  else:
202
218
  raise ValueError("Either source or target must be a remote path (i.e. machine:path)")
203
219
  Struct({"cloud": cloud, "source": str(source), "target": str(target)}).print(as_config=True, title="CLI Resolution")
220
+ _ = pwd, encrypt, zip_arg, share
204
221
  return cloud, str(source), str(target)
205
222
 
206
223
 
@@ -224,11 +241,11 @@ def args_parser():
224
241
 
225
242
  args = parser.parse_args()
226
243
  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")
244
+ source: str=args_dict.pop("source")
245
+ target: str=args_dict.pop("target")
246
+ verbose: bool=args_dict.pop("verbose")
247
+ delete: bool=args_dict.pop("delete")
248
+ bisync: bool=args_dict.pop("bisync")
232
249
  transfers: int = args_dict.pop("transfers")
233
250
  args_obj = Args(**args_dict)
234
251
 
@@ -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:
@@ -111,8 +110,9 @@ def main(which: Optional[str] = None):
111
110
  program = helper()
112
111
 
113
112
  else: raise ValueError(f"Unimplemented choice: {choice_key}")
114
- if program: write_shell_script(program, display=True, preserve_cwd=True, desc="Shell script prepared by Python.", execute=True if which is not None else False)
115
- else: write_shell_script("echo 'Done.'", display=False, ) # Python did not return any script to run.
113
+ if program:
114
+ write_shell_script(program=program, display=True, preserve_cwd=True, desc="Shell script prepared by Python.", execute=True if which is not None else False)
115
+ else: write_shell_script(program="echo 'Done.'", display=False, desc="Shell script prepared by Python.", preserve_cwd=True, execute=False) # Python did not return any script to run.
116
116
 
117
117
 
118
118
  if __name__ == "__main__":
@@ -38,7 +38,7 @@ def get_add_ssh_key_script(path_to_key: P):
38
38
  program = LIBRARY_ROOT.joinpath("setup_windows/openssh-server_add-sshkey.ps1")
39
39
  program = P(program).expanduser().read_text().replace('$sshfile=""', f'$sshfile="{path_to_key}"')
40
40
 
41
- if system() == "Linux": program += f"""
41
+ if system() == "Linux": program += """
42
42
 
43
43
  sudo chmod 700 ~/.ssh
44
44
  sudo chmod 644 ~/.ssh/authorized_keys
@@ -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