machineconfig 5.17__py3-none-any.whl → 5.19__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of machineconfig might be problematic. Click here for more details.
- machineconfig/cluster/sessions_managers/wt_local.py +6 -1
- machineconfig/cluster/sessions_managers/wt_local_manager.py +4 -2
- machineconfig/cluster/sessions_managers/wt_remote_manager.py +4 -2
- machineconfig/cluster/sessions_managers/wt_utils/status_reporter.py +4 -2
- machineconfig/cluster/sessions_managers/zellij_local_manager.py +1 -1
- machineconfig/cluster/sessions_managers/zellij_utils/status_reporter.py +3 -1
- machineconfig/profile/create.py +108 -140
- machineconfig/profile/create_frontend.py +58 -0
- machineconfig/profile/shell.py +45 -9
- machineconfig/scripts/python/ai/solutions/_shared.py +9 -1
- machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +1 -1
- machineconfig/scripts/python/ai/solutions/generic.py +12 -2
- machineconfig/scripts/python/count_lines_frontend.py +1 -1
- machineconfig/scripts/python/devops.py +90 -54
- machineconfig/scripts/python/dotfile.py +14 -8
- machineconfig/scripts/python/interactive.py +3 -21
- machineconfig/scripts/python/share_terminal.py +1 -1
- machineconfig/setup_linux/__init__.py +11 -0
- machineconfig/setup_linux/{openssh_all.sh → ssh/openssh_all.sh} +1 -0
- machineconfig/setup_linux/web_shortcuts/interactive.sh +1 -1
- machineconfig/setup_windows/__init__.py +12 -0
- machineconfig/setup_windows/apps.ps1 +1 -0
- machineconfig/setup_windows/{openssh_all.ps1 → ssh/openssh_all.ps1} +5 -5
- machineconfig/setup_windows/web_shortcuts/interactive.ps1 +1 -1
- machineconfig/utils/code.py +7 -4
- machineconfig/utils/files/dbms.py +355 -0
- machineconfig/utils/files/read.py +2 -2
- machineconfig/utils/installer.py +5 -5
- machineconfig/utils/links.py +128 -104
- machineconfig/utils/procs.py +4 -4
- machineconfig/utils/scheduler.py +10 -14
- {machineconfig-5.17.dist-info → machineconfig-5.19.dist-info}/METADATA +1 -1
- {machineconfig-5.17.dist-info → machineconfig-5.19.dist-info}/RECORD +41 -51
- machineconfig/scripts/windows/dotfile.ps1 +0 -1
- machineconfig/setup_linux/others/openssh-server_add_pub_key.sh +0 -57
- machineconfig/setup_linux/web_shortcuts/croshell.sh +0 -11
- machineconfig/setup_linux/web_shortcuts/ssh.sh +0 -52
- machineconfig/setup_windows/symlinks.ps1 +0 -5
- machineconfig/setup_windows/symlinks2linux.ps1 +0 -1
- machineconfig/setup_windows/web_shortcuts/all.ps1 +0 -18
- machineconfig/setup_windows/web_shortcuts/ascii_art.ps1 +0 -36
- machineconfig/setup_windows/web_shortcuts/croshell.ps1 +0 -16
- machineconfig/setup_windows/web_shortcuts/ssh.ps1 +0 -11
- machineconfig/setup_windows/wsl_refresh.ps1 +0 -8
- machineconfig/setup_windows/wt_and_pwsh.ps1 +0 -9
- /machineconfig/setup_linux/{openssh_wsl.sh → ssh/openssh_wsl.sh} +0 -0
- /machineconfig/setup_windows/{quirks.ps1 → others/power_options.ps1} +0 -0
- /machineconfig/setup_windows/{openssh-server.ps1 → ssh/openssh-server.ps1} +0 -0
- /machineconfig/setup_windows/{openssh-server_add-sshkey.ps1 → ssh/openssh-server_add-sshkey.ps1} +0 -0
- /machineconfig/setup_windows/{openssh-server_add_identity.ps1 → ssh/openssh-server_add_identity.ps1} +0 -0
- {machineconfig-5.17.dist-info → machineconfig-5.19.dist-info}/WHEEL +0 -0
- {machineconfig-5.17.dist-info → machineconfig-5.19.dist-info}/entry_points.txt +0 -0
- {machineconfig-5.17.dist-info → machineconfig-5.19.dist-info}/top_level.txt +0 -0
machineconfig/utils/links.py
CHANGED
|
@@ -84,195 +84,219 @@ def build_links(target_paths: list[tuple[PLike, str]], repo_root: PLike):
|
|
|
84
84
|
links_path.symlink_to(target=a_target_path)
|
|
85
85
|
|
|
86
86
|
|
|
87
|
-
def
|
|
88
|
-
|
|
87
|
+
def symlink_map(config_file_default_path: PathExtended, self_managed_config_file_path: PathExtended,
|
|
88
|
+
on_conflict: Literal["throwError", "overwriteSelfManaged", "backupSelfManaged", "overwriteDefaultPath", "backupDefaultPath"]
|
|
89
|
+
) -> SymlinkResult:
|
|
90
|
+
"""helper function. creates a symlink from `config_file_default_path` to `self_managed_config_file_path`.
|
|
89
91
|
|
|
90
92
|
Returns a dict with 'action' and 'details' keys describing what was done.
|
|
91
93
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
on_conflict strategies:
|
|
95
|
+
- throwError: Raise exception when files differ
|
|
96
|
+
- overwriteSelfManaged: Delete self_managed_config_file_path (self-managed), move config_file_default_path to self_managed_config_file_path, create symlink
|
|
97
|
+
- backupSelfManaged: Backup self_managed_config_file_path (self-managed), move config_file_default_path to self_managed_config_file_path, create symlink
|
|
98
|
+
- overwriteDefaultPath: Delete config_file_default_path (default path), create symlink to self_managed_config_file_path
|
|
99
|
+
- backupDefaultPath: Backup config_file_default_path (default path), create symlink to self_managed_config_file_path
|
|
95
100
|
|
|
96
|
-
|
|
97
|
-
this: exists AND to_this doesn't exist AND this is a symlink pointing to to_this ===> Resolution: AUTO: delete this symlink, create symlink to to_this (touch to_this)
|
|
98
|
-
this: exists AND to_this doesn't exist AND this is a concrete path ===> Resolution: AUTO: move this to to_this, then create symlink from this to to_this.
|
|
99
|
-
|
|
100
|
-
this: doesn't exist AND to_this exists ===> Resolution: AUTO: create link from this to to_this
|
|
101
|
-
this: doesn't exist AND to_this doesn't exist ===> Resolution: AUTO: create link from this to to_this (touch to_this)
|
|
101
|
+
Note: `config_file_default_path` is the default system location, `self_managed_config_file_path` is the self-managed config location
|
|
102
102
|
|
|
103
103
|
"""
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
config_file_default_path = PathExtended(config_file_default_path).expanduser().absolute()
|
|
105
|
+
self_managed_config_file_path = PathExtended(self_managed_config_file_path).expanduser().absolute()
|
|
106
106
|
action_taken = ""
|
|
107
107
|
details = ""
|
|
108
108
|
|
|
109
109
|
# Case analysis based on docstring
|
|
110
|
-
if
|
|
111
|
-
if
|
|
112
|
-
if
|
|
110
|
+
if config_file_default_path.exists():
|
|
111
|
+
if self_managed_config_file_path.exists():
|
|
112
|
+
if config_file_default_path.is_symlink():
|
|
113
113
|
# Check if symlink already points to correct target
|
|
114
114
|
try:
|
|
115
|
-
if
|
|
116
|
-
# Case:
|
|
115
|
+
if config_file_default_path.readlink().resolve() == self_managed_config_file_path.resolve():
|
|
116
|
+
# Case: config_file_default_path exists AND self_managed_config_file_path exists AND config_file_default_path is a symlink pointing to self_managed_config_file_path
|
|
117
117
|
action_taken = "already_linked"
|
|
118
118
|
details = "Symlink already correctly points to target"
|
|
119
|
-
console.print(Panel(f"✅ ALREADY LINKED | {
|
|
119
|
+
console.print(Panel(f"✅ ALREADY LINKED | {config_file_default_path} ➡️ {self_managed_config_file_path}", title="Already Linked", expand=False))
|
|
120
120
|
return {"action": action_taken, "details": details}
|
|
121
121
|
else:
|
|
122
|
-
# Case:
|
|
122
|
+
# Case: config_file_default_path exists AND self_managed_config_file_path exists AND config_file_default_path is a symlink pointing to somewhere else
|
|
123
123
|
action_taken = "relinking"
|
|
124
124
|
details = "Updated existing symlink to point to new target"
|
|
125
|
-
console.print(Panel(f"🔄 RELINKING | Updating symlink from {
|
|
126
|
-
|
|
125
|
+
console.print(Panel(f"🔄 RELINKING | Updating symlink from {config_file_default_path} ➡️ {self_managed_config_file_path}", title="Relinking", expand=False))
|
|
126
|
+
config_file_default_path.delete(sure=True)
|
|
127
127
|
except OSError:
|
|
128
128
|
# Broken symlink case
|
|
129
129
|
action_taken = "fixing_broken_link"
|
|
130
130
|
details = "Removed broken symlink and will create new one"
|
|
131
|
-
console.print(Panel(f"🔄 FIXING BROKEN LINK | Fixing broken symlink from {
|
|
132
|
-
|
|
131
|
+
console.print(Panel(f"🔄 FIXING BROKEN LINK | Fixing broken symlink from {config_file_default_path} ➡️ {self_managed_config_file_path}", title="Fixing Broken Link", expand=False))
|
|
132
|
+
config_file_default_path.delete(sure=True)
|
|
133
133
|
else:
|
|
134
|
-
# Case:
|
|
135
|
-
if files_are_identical(
|
|
134
|
+
# Case: config_file_default_path exists AND self_managed_config_file_path exists AND config_file_default_path is a concrete path
|
|
135
|
+
if files_are_identical(config_file_default_path, self_managed_config_file_path):
|
|
136
136
|
# Files are identical, just delete this and create symlink
|
|
137
137
|
action_taken = "identical_files"
|
|
138
138
|
details = "Files identical, removed source and will create symlink"
|
|
139
|
-
console.print(Panel(f"🔗 IDENTICAL FILES | Files are identical, deleting {
|
|
140
|
-
|
|
139
|
+
console.print(Panel(f"🔗 IDENTICAL FILES | Files are identical, deleting {config_file_default_path} and creating symlink to {self_managed_config_file_path}", title="Identical Files", expand=False))
|
|
140
|
+
config_file_default_path.delete(sure=True)
|
|
141
141
|
else:
|
|
142
|
-
# Files are different, use
|
|
143
|
-
if
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
action_taken = "backing_up_source"
|
|
147
|
-
details = f"Backed up source to {backup_name}, prioritizing target"
|
|
148
|
-
console.print(Panel(f"📦 BACKING UP | Moving {this} to {backup_name}, prioritizing {to_this}", title="Backing Up", expand=False))
|
|
149
|
-
this.move(path=backup_name)
|
|
150
|
-
else:
|
|
151
|
-
# prioritize `this`: to_this is backed up, to_this is deleted, this content moved to to_this location
|
|
152
|
-
backup_name = f"{to_this}.orig_{randstr()}"
|
|
142
|
+
# Files are different, use on_conflict strategy
|
|
143
|
+
if on_conflict == "throwError":
|
|
144
|
+
raise RuntimeError(f"Conflict detected: {config_file_default_path} and {self_managed_config_file_path} both exist with different content")
|
|
145
|
+
elif on_conflict == "overwriteSelfManaged":
|
|
153
146
|
action_taken = "backing_up_target"
|
|
154
|
-
details =
|
|
155
|
-
console.print(Panel(f"📦
|
|
156
|
-
|
|
157
|
-
|
|
147
|
+
details = "Overwriting self-managed config, moving default path to self-managed location"
|
|
148
|
+
console.print(Panel(f"📦 OVERWRITE SELF-MANAGED | Deleting {self_managed_config_file_path}, moving {config_file_default_path} to {self_managed_config_file_path}", title="Overwrite Self-Managed", expand=False))
|
|
149
|
+
self_managed_config_file_path.delete(sure=True)
|
|
150
|
+
config_file_default_path.move(path=self_managed_config_file_path)
|
|
151
|
+
elif on_conflict == "backupSelfManaged":
|
|
152
|
+
backup_name = f"{self_managed_config_file_path}.orig_{randstr()}"
|
|
153
|
+
action_taken = "backing_up_target"
|
|
154
|
+
details = f"Backed up self-managed config to {backup_name}"
|
|
155
|
+
console.print(Panel(f"📦 BACKUP SELF-MANAGED | Moving {self_managed_config_file_path} to {backup_name}, moving {config_file_default_path} to {self_managed_config_file_path}", title="Backup Self-Managed", expand=False))
|
|
156
|
+
self_managed_config_file_path.move(path=backup_name)
|
|
157
|
+
config_file_default_path.move(path=self_managed_config_file_path)
|
|
158
|
+
elif on_conflict == "overwriteDefaultPath":
|
|
159
|
+
action_taken = "backing_up_source"
|
|
160
|
+
details = "Overwriting default path, creating symlink to self-managed config"
|
|
161
|
+
console.print(Panel(f"📦 OVERWRITE DEFAULT | Deleting {config_file_default_path}, creating symlink to {self_managed_config_file_path}", title="Overwrite Default", expand=False))
|
|
162
|
+
config_file_default_path.delete(sure=True)
|
|
163
|
+
elif on_conflict == "backupDefaultPath":
|
|
164
|
+
backup_name = f"{config_file_default_path}.orig_{randstr()}"
|
|
165
|
+
action_taken = "backing_up_source"
|
|
166
|
+
details = f"Backed up default path to {backup_name}"
|
|
167
|
+
console.print(Panel(f"📦 BACKUP DEFAULT | Moving {config_file_default_path} to {backup_name}, creating symlink to {self_managed_config_file_path}", title="Backup Default", expand=False))
|
|
168
|
+
config_file_default_path.move(path=backup_name)
|
|
158
169
|
else:
|
|
159
|
-
#
|
|
160
|
-
if
|
|
161
|
-
# Case:
|
|
170
|
+
# self_managed_config_file_path doesn't exist
|
|
171
|
+
if config_file_default_path.is_symlink():
|
|
172
|
+
# Case: config_file_default_path exists AND self_managed_config_file_path doesn't exist AND config_file_default_path is a symlink (pointing anywhere)
|
|
162
173
|
action_taken = "relinking_to_new_target"
|
|
163
174
|
details = "Removed existing symlink, will create target and new symlink"
|
|
164
|
-
console.print(Panel(f"🔄 RELINKING | Updating symlink from {
|
|
165
|
-
|
|
166
|
-
# Create
|
|
167
|
-
|
|
168
|
-
|
|
175
|
+
console.print(Panel(f"🔄 RELINKING | Updating symlink from {config_file_default_path} ➡️ {self_managed_config_file_path}", title="Relinking", expand=False))
|
|
176
|
+
config_file_default_path.delete(sure=True)
|
|
177
|
+
# Create self_managed_config_file_path
|
|
178
|
+
self_managed_config_file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
179
|
+
self_managed_config_file_path.touch()
|
|
169
180
|
else:
|
|
170
|
-
# Case:
|
|
181
|
+
# Case: config_file_default_path exists AND self_managed_config_file_path doesn't exist AND config_file_default_path is a concrete path
|
|
171
182
|
action_taken = "moving_to_target"
|
|
172
183
|
details = "Moved source to target location, will create symlink"
|
|
173
|
-
console.print(Panel(f"📁 MOVING | Moving {
|
|
174
|
-
|
|
184
|
+
console.print(Panel(f"📁 MOVING | Moving {config_file_default_path} to {self_managed_config_file_path}, then creating symlink", title="Moving", expand=False))
|
|
185
|
+
config_file_default_path.move(path=self_managed_config_file_path)
|
|
175
186
|
else:
|
|
176
|
-
#
|
|
177
|
-
if
|
|
178
|
-
# Case:
|
|
187
|
+
# config_file_default_path doesn't exist
|
|
188
|
+
if self_managed_config_file_path.exists():
|
|
189
|
+
# Case: config_file_default_path doesn't exist AND self_managed_config_file_path exists
|
|
179
190
|
action_taken = "new_link"
|
|
180
191
|
details = "Creating new symlink to existing target"
|
|
181
|
-
console.print(Panel(f"🆕 NEW LINK | Creating new symlink from {
|
|
192
|
+
console.print(Panel(f"🆕 NEW LINK | Creating new symlink from {config_file_default_path} ➡️ {self_managed_config_file_path}", title="New Link", expand=False))
|
|
182
193
|
else:
|
|
183
|
-
# Case:
|
|
194
|
+
# Case: config_file_default_path doesn't exist AND self_managed_config_file_path doesn't exist
|
|
184
195
|
action_taken = "new_link_and_target"
|
|
185
196
|
details = "Creating target file and new symlink"
|
|
186
|
-
console.print(Panel(f"🆕 NEW LINK & TARGET | Creating {
|
|
187
|
-
|
|
188
|
-
|
|
197
|
+
console.print(Panel(f"🆕 NEW LINK & TARGET | Creating {self_managed_config_file_path} and symlink from {config_file_default_path} ➡️ {self_managed_config_file_path}", title="New Link & Target", expand=False))
|
|
198
|
+
self_managed_config_file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
199
|
+
self_managed_config_file_path.touch()
|
|
189
200
|
|
|
190
201
|
# Create the symlink
|
|
191
202
|
try:
|
|
192
203
|
action_taken = action_taken or "linking"
|
|
193
204
|
details = details or "Creating symlink"
|
|
194
|
-
console.print(Panel(f"🔗 LINKING | Creating symlink from {
|
|
195
|
-
PathExtended(
|
|
205
|
+
console.print(Panel(f"🔗 LINKING | Creating symlink from {config_file_default_path} ➡️ {self_managed_config_file_path}", title="Linking", expand=False))
|
|
206
|
+
PathExtended(config_file_default_path).symlink_to(target=self_managed_config_file_path, verbose=True, overwrite=True)
|
|
196
207
|
return {"action": action_taken, "details": details}
|
|
197
208
|
except Exception as ex:
|
|
198
209
|
action_taken = "error"
|
|
199
210
|
details = f"Failed to create symlink: {str(ex)}"
|
|
200
|
-
console.print(Panel(f"❌ ERROR | Failed at linking {
|
|
211
|
+
console.print(Panel(f"❌ ERROR | Failed at linking {config_file_default_path} ➡️ {self_managed_config_file_path}. Reason: {ex}", title="Error", expand=False))
|
|
201
212
|
return {"action": action_taken, "details": details}
|
|
202
213
|
|
|
203
214
|
|
|
204
|
-
def
|
|
205
|
-
|
|
206
|
-
|
|
215
|
+
def copy_map(config_file_default_path: PathExtended, self_managed_config_file_path: PathExtended, on_conflict: Literal["throwError", "overwriteSelfManaged", "backupSelfManaged", "overwriteDefaultPath", "backupDefaultPath"]) -> CopyResult:
|
|
216
|
+
config_file_default_path = PathExtended(config_file_default_path).expanduser().absolute()
|
|
217
|
+
self_managed_config_file_path = PathExtended(self_managed_config_file_path).expanduser().absolute()
|
|
207
218
|
action_taken = ""
|
|
208
219
|
details = ""
|
|
209
220
|
|
|
210
|
-
if
|
|
211
|
-
if
|
|
212
|
-
if
|
|
221
|
+
if config_file_default_path.exists():
|
|
222
|
+
if self_managed_config_file_path.exists():
|
|
223
|
+
if config_file_default_path.is_symlink():
|
|
213
224
|
try:
|
|
214
|
-
if
|
|
225
|
+
if config_file_default_path.readlink().resolve() == self_managed_config_file_path.resolve():
|
|
215
226
|
action_taken = "already_linked"
|
|
216
227
|
details = "Symlink already correctly points to target"
|
|
217
|
-
console.print(Panel(f"✅ ALREADY LINKED | {
|
|
228
|
+
console.print(Panel(f"✅ ALREADY LINKED | {config_file_default_path} ➡️ {self_managed_config_file_path}", title="Already Linked", expand=False))
|
|
218
229
|
return {"action": action_taken, "details": details}
|
|
219
230
|
else:
|
|
220
231
|
action_taken = "relinking"
|
|
221
232
|
details = "Updated existing symlink to point to new target"
|
|
222
|
-
console.print(Panel(f"🔄 RELINKING | Updating symlink from {
|
|
223
|
-
|
|
233
|
+
console.print(Panel(f"🔄 RELINKING | Updating symlink from {config_file_default_path} ➡️ {self_managed_config_file_path}", title="Relinking", expand=False))
|
|
234
|
+
config_file_default_path.delete(sure=True)
|
|
224
235
|
except OSError:
|
|
225
236
|
action_taken = "fixing_broken_link"
|
|
226
237
|
details = "Removed broken symlink and will create new one"
|
|
227
|
-
console.print(Panel(f"🔄 FIXING BROKEN LINK | Fixing broken symlink from {
|
|
228
|
-
|
|
238
|
+
console.print(Panel(f"🔄 FIXING BROKEN LINK | Fixing broken symlink from {config_file_default_path} ➡️ {self_managed_config_file_path}", title="Fixing Broken Link", expand=False))
|
|
239
|
+
config_file_default_path.delete(sure=True)
|
|
229
240
|
else:
|
|
230
|
-
if
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
241
|
+
if on_conflict == "throwError":
|
|
242
|
+
raise RuntimeError(f"Conflict detected: {config_file_default_path} and {self_managed_config_file_path} both exist with different content")
|
|
243
|
+
elif on_conflict == "overwriteSelfManaged":
|
|
244
|
+
action_taken = "backing_up_target"
|
|
245
|
+
details = "Overwriting self-managed config, moving default path to self-managed location"
|
|
246
|
+
console.print(Panel(f"📦 OVERWRITE SELF-MANAGED | Deleting {self_managed_config_file_path}, moving {config_file_default_path} to {self_managed_config_file_path}", title="Overwrite Self-Managed", expand=False))
|
|
247
|
+
self_managed_config_file_path.delete(sure=True)
|
|
248
|
+
config_file_default_path.move(path=self_managed_config_file_path)
|
|
249
|
+
elif on_conflict == "backupSelfManaged":
|
|
250
|
+
backup_name = f"{self_managed_config_file_path}.orig_{randstr()}"
|
|
238
251
|
action_taken = "backing_up_target"
|
|
239
|
-
details = f"Backed up
|
|
240
|
-
console.print(Panel(f"📦
|
|
241
|
-
|
|
242
|
-
|
|
252
|
+
details = f"Backed up self-managed config to {backup_name}"
|
|
253
|
+
console.print(Panel(f"📦 BACKUP SELF-MANAGED | Moving {self_managed_config_file_path} to {backup_name}, moving {config_file_default_path} to {self_managed_config_file_path}", title="Backup Self-Managed", expand=False))
|
|
254
|
+
self_managed_config_file_path.move(path=backup_name)
|
|
255
|
+
config_file_default_path.move(path=self_managed_config_file_path)
|
|
256
|
+
elif on_conflict == "overwriteDefaultPath":
|
|
257
|
+
action_taken = "backing_up_source"
|
|
258
|
+
details = "Overwriting default path, creating symlink to self-managed config"
|
|
259
|
+
console.print(Panel(f"📦 OVERWRITE DEFAULT | Deleting {config_file_default_path}, copying {self_managed_config_file_path}", title="Overwrite Default", expand=False))
|
|
260
|
+
config_file_default_path.delete(sure=True)
|
|
261
|
+
elif on_conflict == "backupDefaultPath":
|
|
262
|
+
backup_name = f"{config_file_default_path}.orig_{randstr()}"
|
|
263
|
+
action_taken = "backing_up_source"
|
|
264
|
+
details = f"Backed up default path to {backup_name}"
|
|
265
|
+
console.print(Panel(f"📦 BACKUP DEFAULT | Moving {config_file_default_path} to {backup_name}, copying {self_managed_config_file_path}", title="Backup Default", expand=False))
|
|
266
|
+
config_file_default_path.move(path=backup_name)
|
|
243
267
|
else:
|
|
244
|
-
if
|
|
268
|
+
if config_file_default_path.is_symlink():
|
|
245
269
|
action_taken = "relinking_to_new_target"
|
|
246
270
|
details = "Removed existing symlink, will create target and new symlink"
|
|
247
|
-
console.print(Panel(f"🔄 RELINKING | Updating symlink from {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
271
|
+
console.print(Panel(f"🔄 RELINKING | Updating symlink from {config_file_default_path} ➡️ {self_managed_config_file_path}", title="Relinking", expand=False))
|
|
272
|
+
config_file_default_path.delete(sure=True)
|
|
273
|
+
self_managed_config_file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
274
|
+
self_managed_config_file_path.touch()
|
|
251
275
|
else:
|
|
252
276
|
action_taken = "moving_to_target"
|
|
253
277
|
details = "Moved source to target location, will copy"
|
|
254
|
-
console.print(Panel(f"📁 MOVING | Moving {
|
|
255
|
-
|
|
278
|
+
console.print(Panel(f"📁 MOVING | Moving {config_file_default_path} to {self_managed_config_file_path}, then copying", title="Moving", expand=False))
|
|
279
|
+
config_file_default_path.move(path=self_managed_config_file_path)
|
|
256
280
|
else:
|
|
257
|
-
if
|
|
281
|
+
if self_managed_config_file_path.exists():
|
|
258
282
|
action_taken = "new_link"
|
|
259
283
|
details = "Copying existing target to source location"
|
|
260
|
-
console.print(Panel(f"🆕 NEW LINK | Copying {
|
|
284
|
+
console.print(Panel(f"🆕 NEW LINK | Copying {self_managed_config_file_path} to {config_file_default_path}", title="New Link", expand=False))
|
|
261
285
|
else:
|
|
262
286
|
action_taken = "new_link_and_target"
|
|
263
287
|
details = "Creating target file and copying to source"
|
|
264
|
-
console.print(Panel(f"🆕 NEW LINK & TARGET | Creating {
|
|
265
|
-
|
|
266
|
-
|
|
288
|
+
console.print(Panel(f"🆕 NEW LINK & TARGET | Creating {self_managed_config_file_path} and copying to {config_file_default_path}", title="New Link & Target", expand=False))
|
|
289
|
+
self_managed_config_file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
290
|
+
self_managed_config_file_path.touch()
|
|
267
291
|
|
|
268
292
|
try:
|
|
269
293
|
action_taken = action_taken or "copying"
|
|
270
294
|
details = details or "Copying file"
|
|
271
|
-
console.print(Panel(f"📋 COPYING | Copying {
|
|
272
|
-
|
|
295
|
+
console.print(Panel(f"📋 COPYING | Copying {self_managed_config_file_path} to {config_file_default_path}", title="Copying", expand=False))
|
|
296
|
+
self_managed_config_file_path.copy(path=config_file_default_path, overwrite=True, verbose=True)
|
|
273
297
|
return {"action": action_taken, "details": details}
|
|
274
298
|
except Exception as ex:
|
|
275
299
|
action_taken = "error"
|
|
276
300
|
details = f"Failed to copy file: {str(ex)}"
|
|
277
|
-
console.print(Panel(f"❌ ERROR | Failed at copying {
|
|
301
|
+
console.print(Panel(f"❌ ERROR | Failed at copying {self_managed_config_file_path} to {config_file_default_path}. Reason: {ex}", title="Error", expand=False))
|
|
278
302
|
return {"action": action_taken, "details": details}
|
machineconfig/utils/procs.py
CHANGED
|
@@ -40,16 +40,16 @@ def get_processes_accessing_file(path: str):
|
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
def kill_process(name: str):
|
|
43
|
-
print(f"⚠️ Attempting to kill process: {name}...")
|
|
43
|
+
console.print(f"⚠️ Attempting to kill process: {name}...", style="yellow")
|
|
44
44
|
killed = False
|
|
45
45
|
for proc in psutil.process_iter():
|
|
46
46
|
if proc.name() == name:
|
|
47
47
|
proc.kill()
|
|
48
|
-
print(f"💀 Process {name} (PID: {proc.pid}) terminated successfully")
|
|
48
|
+
console.print(f"💀 Process {name} (PID: {proc.pid}) terminated successfully", style="green")
|
|
49
49
|
killed = True
|
|
50
50
|
if not killed:
|
|
51
|
-
print(f"❓ No process with name '{name}' was found")
|
|
52
|
-
|
|
51
|
+
console.print(f"❓ No process with name '{name}' was found", style="red")
|
|
52
|
+
console.rule(style="dim")
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
class ProcessManager:
|
machineconfig/utils/scheduler.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
|
|
1
2
|
from pathlib import Path
|
|
2
|
-
from typing import Callable, Optional, Union, Any,
|
|
3
|
+
from typing import Callable, Optional, Union, Any, TypeVar, Protocol, List, Generic
|
|
3
4
|
import logging
|
|
4
5
|
import time
|
|
5
6
|
from datetime import datetime, timezone, timedelta
|
|
@@ -147,10 +148,6 @@ T = TypeVar("T")
|
|
|
147
148
|
T2 = TypeVar("T2")
|
|
148
149
|
|
|
149
150
|
|
|
150
|
-
class PrintFunc(Protocol):
|
|
151
|
-
def __call__(self, msg: str) -> Union[NoReturn, None]: ...
|
|
152
|
-
|
|
153
|
-
|
|
154
151
|
def to_pickle(obj: Any, path: Path) -> None:
|
|
155
152
|
import pickle
|
|
156
153
|
|
|
@@ -159,9 +156,8 @@ def to_pickle(obj: Any, path: Path) -> None:
|
|
|
159
156
|
|
|
160
157
|
|
|
161
158
|
class Cache(Generic[T]): # This class helps to accelrate access to latest data coming from expensive function. The class has two flavours, memory-based and disk-based variants."""
|
|
162
|
-
# source_func: Callable[[], T]
|
|
163
159
|
def __init__(
|
|
164
|
-
self, source_func: Callable[[], T], expire: timedelta, logger:
|
|
160
|
+
self, source_func: Callable[[], T], expire: timedelta, logger: LoggerTemplate, path: Optional[Path] = None, saver: Callable[[T, Path], Any] = to_pickle, reader: Callable[[Path], T] = from_pickle, name: Optional[str] = None
|
|
165
161
|
) -> None:
|
|
166
162
|
self.cache: T
|
|
167
163
|
self.source_func = source_func # function which when called returns a fresh object to be frozen.
|
|
@@ -209,7 +205,7 @@ class Cache(Generic[T]): # This class helps to accelrate access to latest data
|
|
|
209
205
|
🔍 Error: {ex}
|
|
210
206
|
════════════════════════════════════════════════════════
|
|
211
207
|
"""
|
|
212
|
-
self.logger(msg1 + msg2)
|
|
208
|
+
self.logger.warning(msg1 + msg2)
|
|
213
209
|
self.cache = self.source_func()
|
|
214
210
|
self.last_call_is_fresh = True
|
|
215
211
|
self.time_produced = datetime.now()
|
|
@@ -221,7 +217,7 @@ class Cache(Generic[T]): # This class helps to accelrate access to latest data
|
|
|
221
217
|
if self.logger:
|
|
222
218
|
# Previous cache never existed or there was an explicit fresh order.
|
|
223
219
|
why = "There was an explicit fresh order." if fresh else "Previous cache never existed or is corrupted."
|
|
224
|
-
self.logger(f"""
|
|
220
|
+
self.logger.warning(f"""
|
|
225
221
|
🆕 ════════════════════ NEW CACHE ════════════════════
|
|
226
222
|
🔄 {self.name} cache: Populating fresh cache from source func
|
|
227
223
|
ℹ️ Reason: {why}
|
|
@@ -239,7 +235,7 @@ class Cache(Generic[T]): # This class helps to accelrate access to latest data
|
|
|
239
235
|
return self(fresh=True)
|
|
240
236
|
if age > self.expire:
|
|
241
237
|
if self.logger:
|
|
242
|
-
self.logger(f"""
|
|
238
|
+
self.logger.warning(f"""
|
|
243
239
|
🔄 ════════════════════ CACHE UPDATE ════════════════════
|
|
244
240
|
⚠️ {self.name} cache: Updating cache from source func
|
|
245
241
|
⏱️ Age = {age} > {self.expire}
|
|
@@ -251,7 +247,7 @@ class Cache(Generic[T]): # This class helps to accelrate access to latest data
|
|
|
251
247
|
self.save(self.cache, self.path)
|
|
252
248
|
else:
|
|
253
249
|
if self.logger:
|
|
254
|
-
self.logger(f"""
|
|
250
|
+
self.logger.warning(f"""
|
|
255
251
|
✅ ════════════════════ USING CACHE ════════════════════
|
|
256
252
|
📦 {self.name} cache: Using cached values
|
|
257
253
|
⏱️ Lag = {age}
|
|
@@ -260,7 +256,7 @@ class Cache(Generic[T]): # This class helps to accelrate access to latest data
|
|
|
260
256
|
|
|
261
257
|
@staticmethod
|
|
262
258
|
def as_decorator(
|
|
263
|
-
expire: timedelta, logger:
|
|
259
|
+
expire: timedelta, logger: LoggerTemplate, path: Optional[Path] = None, saver: Callable[[T2, Path], Any] = to_pickle, reader: Callable[[Path], T2] = from_pickle, name: Optional[str] = None
|
|
264
260
|
): # -> Callable[..., 'Cache[T2]']:
|
|
265
261
|
def decorator(source_func: Callable[[], T2]) -> Cache["T2"]:
|
|
266
262
|
res = Cache(source_func=source_func, expire=expire, logger=logger, path=path, name=name, reader=reader, saver=saver)
|
|
@@ -276,8 +272,8 @@ class Cache(Generic[T]): # This class helps to accelrate access to latest data
|
|
|
276
272
|
returned_path = self.path.from_cloud(cloud=cloud, rel2home=rel2home, root=root)
|
|
277
273
|
if returned_path is None and not exists:
|
|
278
274
|
raise FileNotFoundError(f"❌ Failed to get @ {self.path}. Build the cache first with signed API.")
|
|
279
|
-
elif returned_path is None and exists
|
|
280
|
-
self.logger(f"""
|
|
275
|
+
elif returned_path is None and exists:
|
|
276
|
+
self.logger.warning(f"""
|
|
281
277
|
⚠️ ════════════════════ CLOUD FETCH WARNING ════════════════════
|
|
282
278
|
🔄 Failed to get fresh data from cloud
|
|
283
279
|
📦 Using old cache @ {self.path}
|