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,79 +1,261 @@
1
-
2
- from crocodile.file_management import P, Read
3
- from machineconfig.utils.utils import PROGRAM_PATH
4
- from machineconfig.scripts.python.cloud_mount import get_mprocs_mount_txt
5
- import argparse
6
-
7
- """
8
-
9
- """
10
-
11
- # TODO add --vfs-cache-mode full
12
-
13
-
14
- def args_parser():
15
- parser = argparse.ArgumentParser(description="""A wrapper for rclone sync and rclone bisync, with some extra features.""")
16
-
17
- parser.add_argument("source", help="source", default=None)
18
- parser.add_argument("target", help="target", default=None)
19
-
20
- parser.add_argument("--transfers", "-t", help="Number of threads in syncing.", default=10) # default is False
21
- # parser.add_argument("--key", "-k", help="Key for encryption", default=None)
22
- # parser.add_argument("--pwd", "-P", help="Password for encryption", default=None)
23
- parser.add_argument("--bisync", "-b", help="Bidirectional sync.", action="store_true") # default is False
24
- parser.add_argument("--delete", "-D", help="Delete files in remote that are not in local.", action="store_true") # default is False
25
-
26
- parser.add_argument("--verbose", "-v", help="Verbosity of mprocs to show details of syncing.", action="store_true") # default is False
27
-
28
- args = parser.parse_args()
29
-
30
- if ":" in args.source:
31
- source = args.source
32
- target = P(args.target).expanduser().absolute()
33
- cloud = source.split(":")[0]
34
- localpath = target
35
- elif ":" in args.target:
36
- source = args.target # unchanged
37
- target = P(args.source).expanduser().absolute()
38
- cloud = source.split(":")[0]
39
- localpath = target
40
- else: # user did not specify remotepath, so it will be inferred here
41
- # but first we need to know whether the cloud is source or target
42
- remotes = Read.ini(P.home().joinpath(".config/rclone/rclone.conf")).sections()
43
- for a_remote in remotes:
44
- if args.source == a_remote:
45
- target = P(args.target).expanduser().absolute()
46
- source = f"{args.source}:{'myhome/generic_os' / target.rel2home()}"
47
- cloud = args.source
48
- localpath = target
49
- break
50
- if args.target == a_remote:
51
- source = P(args.source).expanduser().absolute()
52
- target = f"{args.target}:{'myhome/generic_os' / source.rel2home()}"
53
- cloud = args.target
54
- localpath = source
55
- break
56
- else:
57
- print(f"Could not find a remote in {remotes} that matches {args.source} or {args.target}.")
58
- raise ValueError
59
-
60
- # map short flags to long flags (-u -> --upload), for easier use in the script
61
- if args.bisync: print(f"Syncing {source} {'<>' * 7} {target}`")
62
- else: print(f"Syncing {source} {'>' * 15} {target}`")
63
-
64
- if args.bisync: rclone_cmd = f"""rclone bisync {source} {target}"""
65
- else: rclone_cmd = f"""rclone sync {source} {target}"""
66
-
67
- rclone_cmd += f" --progress --transfers={args.transfers} --verbose"
68
- if args.bisync: rclone_cmd += " --resync"
69
- if args.delete: rclone_cmd += " --delete-during"
70
-
71
- if args.verbose: txt = get_mprocs_mount_txt(cloud=cloud, rclone_cmd=rclone_cmd, localpath=localpath)
72
- else: txt = f"""cd ~\n{rclone_cmd}"""
73
- print(r'running command'.center(100, '-'))
74
- print(txt)
75
- PROGRAM_PATH.write_text(txt)
76
-
77
-
78
- if __name__ == '__main__':
79
- args_parser()
1
+
2
+ """CS
3
+ TODO: use tap typed-argument-parser to parse args
4
+ TODO: use typer to make clis
5
+ """
6
+
7
+ from crocodile.file_management import P, Read, Struct
8
+ from crocodile.core import install_n_import
9
+ from machineconfig.utils.utils import PROGRAM_PATH, DEFAULTS_PATH
10
+ from machineconfig.scripts.python.cloud_mount import get_mprocs_mount_txt
11
+ import argparse
12
+ import os
13
+ from typing import Optional
14
+ # from dataclasses import dataclass
15
+ # from tap import Tap
16
+
17
+
18
+ ES = "^" # chosen carefully to not mean anything on any shell. `$` was a bad choice.
19
+
20
+
21
+ class ArgsDefaults:
22
+ # source: str = None
23
+ # target: str = None
24
+ encrypt: bool = False
25
+ zip_: bool = False
26
+ overwrite: bool = False
27
+ share: bool = False
28
+ rel2home = False
29
+ root = None
30
+ os_specific = False
31
+ key = None
32
+ pwd = None
33
+
34
+
35
+ install_n_import("pydantic")
36
+ from pydantic.dataclasses import dataclass # type: ignore # ruffle: ignore
37
+ from pydantic import ConfigDict
38
+
39
+
40
+ @dataclass(config=ConfigDict(extra="forbid", frozen=True))
41
+ class Args():
42
+ cloud: Optional[str] = None
43
+
44
+ zip: bool = ArgsDefaults.zip_
45
+ overwrite: bool = ArgsDefaults.overwrite
46
+ share: bool = ArgsDefaults.share
47
+
48
+ root: Optional[str] = ArgsDefaults.root
49
+ os_specific: bool = ArgsDefaults.os_specific
50
+ rel2home: bool = ArgsDefaults.rel2home
51
+
52
+ encrypt: bool = ArgsDefaults.encrypt
53
+ key: Optional[str] = ArgsDefaults.key
54
+ pwd: Optional[str] = ArgsDefaults.pwd
55
+
56
+ config: Optional[str] = None
57
+
58
+ @staticmethod
59
+ def from_config(config_path: P):
60
+ # from crocodile.core import install_n_import
61
+ # install_n_import("pydantic")
62
+ # from pydantic import BaseModel, ConfigDict
63
+ return Args(**Read.json(config_path))
64
+
65
+
66
+ def absolute(path: str) -> P:
67
+ obj = P(path).expanduser()
68
+ if not path.startswith(".") and obj.exists(): return obj
69
+ try_absing = P.cwd().joinpath(path)
70
+ if try_absing.exists(): return try_absing
71
+ print(f"Warning: {path} was not resolved to absolute one, trying out resolving symlinks (This may result in unintended paths)")
72
+ return obj.absolute()
73
+
74
+
75
+ def get_secure_share_cloud_config(interactive: bool = True) -> Args:
76
+ if os.environ.get("CLOUD_CONFIG_NAME") is not None:
77
+ default_cloud = os.environ.get("CLOUD_CONFIG_NAME")
78
+ assert default_cloud is not None
79
+ cloud = default_cloud
80
+ else:
81
+ try:
82
+ default_cloud__ = Read.ini(DEFAULTS_PATH)['general']['rclone_config_name']
83
+ except Exception:
84
+ default_cloud__ = 'No default cloud found.'
85
+ if default_cloud__ == 'No default cloud found.' or interactive:
86
+ # assert default_cloud is not None
87
+ cloud = input(f"Enter cloud name (default {default_cloud__}): ") or default_cloud__
88
+ else:
89
+ cloud = default_cloud__
90
+
91
+ default_password_path = P.home().joinpath("dotfiles/creds/passwords/quick_password")
92
+ if default_password_path.exists():
93
+ pwd = default_password_path.read_text().strip()
94
+ default_message = "defaults to quick_password"
95
+ else:
96
+ pwd = ""
97
+ default_message = "no default password found"
98
+ pwd = input(f"Enter encryption password ({default_message}): ") or pwd
99
+ res = Args(cloud=cloud,
100
+ pwd=pwd, encrypt=True,
101
+ zip=True, overwrite=True, share=True,
102
+ rel2home=True, root="myshare", os_specific=False,)
103
+ Struct(res.__dict__).print(as_config=True, title=f"⚠️ Using SecureShare cloud config")
104
+ return res
105
+
106
+
107
+ def find_cloud_config(path: P):
108
+ for _i in range(len(path.parts)):
109
+ if path.joinpath("cloud.json").exists():
110
+ res = Args.from_config(path.joinpath("cloud.json"))
111
+ Struct(res.__dict__).print(as_config=True, title=f"⚠️ Using default cloud config @ {path.joinpath('cloud.json')} ")
112
+ return res
113
+ path = path.parent
114
+ return None
115
+
116
+
117
+ def parse_cloud_source_target(args: Args, source: str, target: str) -> tuple[str, str, str]:
118
+ if source.startswith(":"): # default cloud name is omitted cloud_name: # or ES in source
119
+ # At the moment, this cloud.json defaults overrides the args and is activated only when source or target are just ":"
120
+ # consider activating it by a flag, and also not not overriding explicitly passed args options.
121
+ assert ES not in target, f"Not Implemented here yet."
122
+ path = absolute(target)
123
+ if args.config is None:
124
+ maybe_config: Optional[Args] = find_cloud_config(path=path)
125
+ else:
126
+ if args.config == "ss": maybe_config = get_secure_share_cloud_config()
127
+ else: maybe_config = Args.from_config(absolute(args.config))
128
+
129
+ if maybe_config is None:
130
+ default_cloud: str = Read.ini(DEFAULTS_PATH)['general']['rclone_config_name']
131
+ print(f"⚠️ Using default cloud: {default_cloud}")
132
+ source = default_cloud + ":" + source[1:]
133
+ else:
134
+ tmp = maybe_config
135
+ source = f"{tmp.cloud}:" + source[1:]
136
+ args.root = tmp.root
137
+ args.rel2home = tmp.rel2home
138
+ args.pwd = tmp.pwd
139
+ args.encrypt = tmp.encrypt
140
+ args.zip = tmp.zip
141
+ args.share = tmp.share
142
+ # args.jh = 22
143
+
144
+ if target.startswith(":"): # default cloud name is omitted cloud_name: # or ES in target
145
+ assert ES not in source, f"Not Implemented here yet."
146
+ path = absolute(source)
147
+ if args.config is None:
148
+ maybe_config = find_cloud_config(path)
149
+ else:
150
+ if args.config == "ss": maybe_config = get_secure_share_cloud_config()
151
+ else: maybe_config = Args.from_config(absolute(args.config))
152
+
153
+ if maybe_config is not None:
154
+ tmp = maybe_config
155
+ target = f"{tmp.cloud}:" + target[1:]
156
+ args.root = tmp.root
157
+ args.rel2home = tmp.rel2home
158
+ args.pwd = tmp.pwd
159
+ args.encrypt = tmp.encrypt
160
+ args.zip = tmp.zip
161
+ args.share = tmp.share
162
+
163
+ else:
164
+ default_cloud = Read.ini(DEFAULTS_PATH)['general']['rclone_config_name']
165
+ print(f"⚠️ Using default cloud: {default_cloud}")
166
+ target = default_cloud + ":" + target[1:]
167
+
168
+ if ":" in source and (source[1] != ":" if len(source) > 1 else True): # avoid the deceptive case of "C:/"
169
+ source_parts: list[str] = source.split(":")
170
+ cloud = source_parts[0]
171
+
172
+ if len(source_parts) > 1 and source_parts[1] == ES: # the source path is to be inferred from target.
173
+ assert ES not in target, f"You can't use expand symbol `{ES}` in both source and target. Cyclical inference dependency arised."
174
+ target_obj = absolute(target)
175
+ remote_path = target_obj.get_remote_path(os_specific=args.os_specific, root=args.root, rel2home=args.rel2home, strict=False)
176
+ source = f"{cloud}:{remote_path.as_posix()}"
177
+
178
+ else: # source path is mentioned, target? maybe.
179
+ if target == ES: # target path is to be inferred from source.
180
+ raise NotImplementedError(f"There is no .get_local_path method yet")
181
+ else:
182
+ target_obj = absolute(target)
183
+ if args.zip and ".zip" not in source: source += ".zip"
184
+ if args.encrypt and ".enc" not in source: source += ".enc"
185
+
186
+ elif ":" in target and (target[1] != ":" if len(target) > 1 else True): # avoid the case of "C:/"
187
+ target_parts: list[str] = target.split(":")
188
+ cloud = target.split(":")[0]
189
+
190
+ if len(target_parts) > 1 and target_parts[1] == ES: # the target path is to be inferred from source.
191
+ assert ES not in source, f"You can't use $ in both source and target. Cyclical inference dependency arised."
192
+ source_obj = absolute(source)
193
+ remote_path = source_obj.get_remote_path(os_specific=args.os_specific, root=args.root, rel2home=args.rel2home, strict=False)
194
+ target = f"{cloud}:{remote_path.as_posix()}"
195
+ else: # target path is mentioned, source? maybe.
196
+ target = str(target)
197
+ if source == ES:
198
+ raise NotImplementedError(f"There is no .get_local_path method yet")
199
+ else:
200
+ source_obj = absolute(source)
201
+ if args.zip and ".zip" not in target: target += ".zip"
202
+ if args.encrypt and ".enc" not in target: target += ".enc"
203
+ else:
204
+ raise ValueError("Either source or target must be a remote path (i.e. machine:path)")
205
+ Struct({"cloud": cloud, "source": str(source), "target": str(target)}).print(as_config=True, title="CLI Resolution")
206
+ return cloud, str(source), str(target)
207
+
208
+
209
+ def args_parser():
210
+ parser = argparse.ArgumentParser(description="""A wrapper for rclone sync and rclone bisync, with some extra features.""")
211
+
212
+ parser.add_argument("source", help="source", default=None)
213
+ parser.add_argument("target", help="target", default=None)
214
+
215
+ parser.add_argument("--transfers", "-t", help="Number of threads in syncing.", default=10) # default is False
216
+ parser.add_argument("--root", "-R", help="Remote root.", default="myhome") # default is False
217
+
218
+ parser.add_argument("--key", "-k", help="Key for encryption", default=None)
219
+ parser.add_argument("--pwd", "-P", help="Password for encryption", default=None)
220
+ parser.add_argument("--encrypt", "-e", help="Decrypt after receiving.", action="store_true") # default is False
221
+ parser.add_argument("--zip", "-z", help="unzip after receiving.", action="store_true") # default is False
222
+
223
+ parser.add_argument("--bisync", "-b", help="Bidirectional sync.", action="store_true") # default is False
224
+ parser.add_argument("--delete", "-D", help="Delete files in remote that are not in local.", action="store_true") # default is False
225
+ parser.add_argument("--verbose", "-v", help="Verbosity of mprocs to show details of syncing.", action="store_true") # default is False
226
+
227
+ args = parser.parse_args()
228
+ args_dict = vars(args)
229
+ source: str = args_dict.pop("source")
230
+ target: str = args_dict.pop("target")
231
+ verbose: bool = args_dict.pop("verbose")
232
+ delete: bool = args_dict.pop("delete")
233
+ bisync: bool = args_dict.pop("bisync")
234
+ transfers: int = args_dict.pop("transfers")
235
+ args_obj = Args(**args_dict)
236
+
237
+ args_obj.os_specific = False
238
+ args_obj.rel2home = True
239
+
240
+ cloud, source, target = parse_cloud_source_target(args=args_obj, source=source, target=target)
241
+ # map short flags to long flags (-u -> --upload), for easier use in the script
242
+ if bisync:
243
+ print(f"SYNCING 🔄️ {source} {'<>' * 7} {target}`")
244
+ rclone_cmd = f"""rclone bisync '{source}' '{target}' --resync"""
245
+ else:
246
+ print(f"SYNCING {source} {'>' * 15} {target}`")
247
+ rclone_cmd = f"""rclone sync '{source}' '{target}' """
248
+
249
+ rclone_cmd += f" --progress --transfers={transfers} --verbose"
250
+ # rclone_cmd += f" --vfs-cache-mode full"
251
+ if delete: rclone_cmd += " --delete-during"
252
+
253
+ if verbose: txt = get_mprocs_mount_txt(cloud=cloud, rclone_cmd=rclone_cmd, cloud_brand="Unknown")
254
+ else: txt = f"""{rclone_cmd}"""
255
+ print(r'running command'.center(100, '-'))
256
+ print(txt)
257
+ PROGRAM_PATH.write_text(txt)
258
+
259
+
260
+ if __name__ == '__main__':
261
+ args_parser()
@@ -0,0 +1,151 @@
1
+
2
+
3
+ """
4
+ croshell
5
+ """
6
+
7
+ import argparse
8
+ # import subprocess
9
+ # import platform
10
+ from crocodile.file_management import P, randstr
11
+ from machineconfig.utils.ve import get_ipython_profile, get_ve_profile
12
+ from machineconfig.utils.utils import PROGRAM_PATH, display_options
13
+
14
+
15
+ def add_print_header_pycode(path: str, title: str):
16
+ return f"""
17
+ pycode = P(r'{path}').read_text(encoding="utf-8")
18
+ pycode = pycode.split("except Exception: print(pycode)")[2]
19
+
20
+ try:
21
+ from rich.text import Text
22
+ from rich.panel import Panel
23
+ from rich.console import Console
24
+ from rich.syntax import Syntax
25
+ console = Console()
26
+ if pycode.strip() != "":
27
+ console.print(Panel(Syntax(pycode, lexer="python"), title='{title}'), style="bold red")
28
+ except Exception: print(pycode)
29
+ """
30
+
31
+
32
+ def get_read_data_pycode(path: str):
33
+ pycode = f"""
34
+ p = P(r\'{path}\').absolute()
35
+ try:
36
+ dat = p.readit()
37
+ if type(dat) == Struct: dat.print(as_config=True, title=p.name)
38
+ else: print(f"Succcesfully read the file {{p.name}}")
39
+ except Exception as e:
40
+ print(e)
41
+
42
+ """
43
+ return pycode
44
+
45
+
46
+ def get_read_pyfile_pycode(path: P, as_module: bool, cmd: str = ""):
47
+ if as_module: pycode = fr"""
48
+ import sys
49
+ sys.path.append(r'{path.parent}')
50
+ from {path.stem} import *
51
+ {cmd}
52
+ """
53
+ else: pycode = f"""
54
+ __file__ = P(r'{path}')
55
+ {path.read_text(encoding="utf-8")}
56
+ """
57
+ return pycode
58
+
59
+
60
+ def build_parser():
61
+ parser = argparse.ArgumentParser(description="Generic Parser to launch crocodile shell.")
62
+ # A FLAG:
63
+ parser.add_argument("--module", '-m', help="flag to run the file as a module as opposed to main.", action="store_true", default=False) # default is running as main, unless indicated by --module flag.
64
+ parser.add_argument("--newWindow", "-w", help="flag for running in new window.", action="store_true", default=False)
65
+ parser.add_argument("--nonInteratctive", "-N", help="flag for a non-interactive session.", action="store_true", default=False)
66
+ parser.add_argument("--python", "-p", help="flag to use python over IPython.", action="store_true", default=False)
67
+ parser.add_argument("--fzf", "-F", help="search with fuzzy finder for python scripts and run them", action="store_true", default=False)
68
+
69
+ # OPTIONAL KEYWORD
70
+ parser.add_argument("--ve", "-v", help="virtual enviroment to use, defaults to activated ve, if existed, else ve.", default=None)
71
+ parser.add_argument("--profile", "-P", help="ipython profile to use, defaults to default profile.", default=None)
72
+ parser.add_argument("--read", "-r", dest="read", help="read a binary file.", default="")
73
+ parser.add_argument("--file", "-f", dest="file", help="python file path to interpret", default="")
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="")
77
+
78
+ args = parser.parse_args()
79
+ # print(f"Crocodile.run: args of the firing command = {args.__dict__}")
80
+
81
+ # ==================================================================================
82
+ # flags processing
83
+ interactivity = '' if args.nonInteratctive else '-i'
84
+ interpreter = 'python' if args.python else 'ipython'
85
+ profile = args.profile
86
+ file = P.cwd() # initialization value, could be modified according to args.
87
+
88
+ if args.cmd != "":
89
+ import textwrap
90
+ program = textwrap.dedent(args.cmd)
91
+
92
+ elif args.fzf:
93
+ options = P.cwd().search("*.py", r=True).apply(str).list
94
+ file = display_options(msg="Choose a python file to run", options=options, fzf=True, multi=False, )
95
+ assert isinstance(file, str)
96
+ if profile is None: profile = profile = get_ipython_profile(P(file))
97
+ program = P(file).read_text(encoding='utf-8')
98
+
99
+ elif args.file != "":
100
+ file = P(args.file.lstrip()).expanduser().absolute()
101
+ if profile is None: profile = profile = get_ipython_profile(P(file))
102
+ program = get_read_pyfile_pycode(file, as_module=args.module, cmd=args.cmd)
103
+
104
+ elif args.read != "":
105
+ file = P(str(args.read).lstrip()).expanduser().absolute()
106
+ if profile is None: profile = profile = get_ipython_profile(P(file))
107
+ program = get_read_data_pycode(str(file))
108
+
109
+ else: # just run croshell.py interactively
110
+ program = ""
111
+ # program = f" --profile {get_ipython_profile(P.cwd())} --no-banner -m crocodile.croshell" # --term-title croshell
112
+ # from IPython import start_ipython
113
+ # start_ipython(argv=program.split(' ')[1:])
114
+ # return
115
+ # Clear-Host;
116
+ # # --autocall 1 in order to enable shell-like behaviour: e.g.: P x is interpretred as P(x)
117
+
118
+ preprogram = """
119
+ from crocodile.croshell import *
120
+ print_header()
121
+ print_logo(logo="crocodile")
122
+ """
123
+
124
+ pyfile = P.tmp().joinpath(f"tmp_scripts/python/croshell/{randstr()}.py").create(parents_only=True)
125
+
126
+ if args.read != "": title = "Reading Data"
127
+ elif args.file != "": title = "Running Python File"
128
+ else: title = "Executed code"
129
+ total_program = preprogram + add_print_header_pycode(str(pyfile), title=title) + program
130
+
131
+ pyfile.write_text(total_program, encoding='utf-8')
132
+ if profile is None: profile = "default"
133
+
134
+ ve = get_ve_profile(P(file)) if args.ve is None else str(args.ve)
135
+
136
+ final_program = f"""
137
+ # deactivate
138
+ . activate_ve {ve}
139
+ {interpreter} """
140
+ if interpreter == "ipython": final_program += f"{interactivity} --profile {profile} --no-banner"
141
+ final_program += f" {str(pyfile)}"
142
+ print(f"🔥 sourcing ... {pyfile}")
143
+ PROGRAM_PATH.write_text(final_program)
144
+
145
+ # if platform.system() == "Windows":
146
+ # return subprocess.run([f"powershell", "-Command", res], shell=True, capture_output=False, text=True, check=True)
147
+ # else: return subprocess.run([res], shell=True, capture_output=False, text=True, check=True)
148
+
149
+
150
+ if __name__ == "__main__":
151
+ build_parser()