machineconfig 6.81__py3-none-any.whl → 6.83__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.

@@ -25,6 +25,7 @@ mcfg "$@"
25
25
 
26
26
  if [[ -f "$OP_PROGRAM_PATH" ]]; then
27
27
  printf "%b\n" "${GREEN}✅ Found op program:${RESET} ${OP_PROGRAM_PATH}"
28
+ bat "$OP_PROGRAM_PATH"
28
29
  printf "%b\n" "${GREEN}▶ Running...${RESET}"
29
30
  . "$OP_PROGRAM_PATH"
30
31
  status=$?
@@ -2,7 +2,7 @@
2
2
  # /// script
3
3
  # requires-python = ">=3.13"
4
4
  # dependencies = [
5
- # "machineconfig>=6.81",
5
+ # "machineconfig>=6.83",
6
6
  # "textual",
7
7
  # "pyperclip",
8
8
  # ]
@@ -46,7 +46,7 @@ def path():
46
46
  uv_with = ["textual"]
47
47
  uv_project_dir = None
48
48
  if not Path.home().joinpath("code/machineconfig").exists():
49
- uv_with.append("machineconfig>=6.81")
49
+ uv_with.append("machineconfig>=6.83")
50
50
  else:
51
51
  uv_project_dir = str(Path.home().joinpath("code/machineconfig"))
52
52
  run_shell_script(get_uv_command_executing_python_script(python_script=path.read_text(encoding="utf-8"), uv_with=uv_with, uv_project_dir=uv_project_dir)[0])
@@ -41,9 +41,9 @@ def install(no_copy_assets: Annotated[bool, typer.Option("--no-assets-copy", "-n
41
41
  else:
42
42
  import platform
43
43
  if platform.system() == "Windows":
44
- run_shell_script(r"""& "$HOME\.local\bin\uv.exe" tool install --upgrade "machineconfig>=6.81" """)
44
+ run_shell_script(r"""& "$HOME\.local\bin\uv.exe" tool install --upgrade "machineconfig>=6.83" """)
45
45
  else:
46
- run_shell_script("""$HOME/.local/bin/uv tool install --upgrade "machineconfig>=6.81" """)
46
+ run_shell_script("""$HOME/.local/bin/uv tool install --upgrade "machineconfig>=6.83" """)
47
47
  from machineconfig.profile.create_shell_profile import create_default_shell_profile
48
48
  if not no_copy_assets:
49
49
  create_default_shell_profile() # involves copying assets too
@@ -68,7 +68,7 @@ def navigate():
68
68
  path = Path(navigator.__file__).resolve().parent.joinpath("devops_navigator.py")
69
69
  from machineconfig.utils.code import run_shell_script
70
70
  if Path.home().joinpath("code/machineconfig").exists(): executable = f"""--project "{str(Path.home().joinpath("code/machineconfig"))}" --with textual"""
71
- else: executable = """--with "machineconfig>=6.81,textual" """
71
+ else: executable = """--with "machineconfig>=6.83,textual" """
72
72
  run_shell_script(f"""uv run {executable} {path}""")
73
73
 
74
74
 
@@ -1,60 +1,13 @@
1
+ from machineconfig.scripts.python.helpers_repos.action_helper import GitAction, GitOperationResult, GitOperationSummary, print_git_operations_summary
1
2
  from machineconfig.utils.path_extended import PathExtended
2
3
  from machineconfig.utils.accessories import randstr
3
4
  from machineconfig.scripts.python.helpers_repos.update import update_repository
4
5
 
5
- from typing import Optional
6
- from dataclasses import dataclass
7
- from enum import Enum
6
+ from typing import Optional, Dict, Any, List, cast
7
+ import concurrent.futures
8
+ import os
8
9
 
9
10
  from rich import print as pprint
10
- from rich.table import Table
11
- from rich.panel import Panel
12
- from rich.columns import Columns
13
-
14
-
15
- class GitAction(Enum):
16
- commit = "commit"
17
- push = "push"
18
- pull = "pull"
19
-
20
-
21
- @dataclass
22
- class GitOperationResult:
23
- """Result of a git operation on a single repository."""
24
- repo_path: PathExtended
25
- action: str
26
- success: bool
27
- message: str
28
- is_git_repo: bool = True
29
- had_changes: bool = False
30
- remote_count: int = 0
31
-
32
-
33
- @dataclass
34
- class GitOperationSummary:
35
- """Summary of all git operations performed."""
36
- # Basic statistics
37
- total_paths_processed: int = 0
38
- git_repos_found: int = 0
39
- non_git_paths: int = 0
40
-
41
- # Per-operation statistics
42
- commits_attempted: int = 0
43
- commits_successful: int = 0
44
- commits_no_changes: int = 0
45
- commits_failed: int = 0
46
-
47
- pulls_attempted: int = 0
48
- pulls_successful: int = 0
49
- pulls_failed: int = 0
50
-
51
- pushes_attempted: int = 0
52
- pushes_successful: int = 0
53
- pushes_failed: int = 0
54
-
55
- def __post_init__(self):
56
- self.failed_operations: list[GitOperationResult] = []
57
- self.repos_without_remotes: list[PathExtended] = []
58
11
 
59
12
 
60
13
  def git_action(path: PathExtended, action: GitAction, mess: Optional[str], r: bool, auto_uv_sync: bool) -> GitOperationResult:
@@ -76,16 +29,10 @@ def git_action(path: PathExtended, action: GitAction, mess: Optional[str], r: bo
76
29
  action=action.value,
77
30
  success=all_successful,
78
31
  message=f"Recursive operation: {len([r for r in results if r.success])}/{len(results)} succeeded",
79
- is_git_repo=False
32
+ is_git_repo=False,
80
33
  )
81
34
  else:
82
- return GitOperationResult(
83
- repo_path=path,
84
- action=action.value,
85
- success=False,
86
- message="Not a git repository",
87
- is_git_repo=False
88
- )
35
+ return GitOperationResult(repo_path=path, action=action.value, success=False, message="Not a git repository", is_git_repo=False)
89
36
 
90
37
  print(f">>>>>>>>> 🔧{action} - {path}")
91
38
  remote_count = len(repo.remotes)
@@ -106,30 +53,19 @@ def git_action(path: PathExtended, action: GitAction, mess: Optional[str], r: bo
106
53
  success=True,
107
54
  message=f"Committed changes with message: {mess}",
108
55
  had_changes=True,
109
- remote_count=remote_count
56
+ remote_count=remote_count,
110
57
  )
111
58
  else:
112
59
  print("ℹ️ No changes to commit")
113
60
  return GitOperationResult(
114
- repo_path=path,
115
- action=action.value,
116
- success=True,
117
- message="No changes to commit",
118
- had_changes=False,
119
- remote_count=remote_count
61
+ repo_path=path, action=action.value, success=True, message="No changes to commit", had_changes=False, remote_count=remote_count
120
62
  )
121
63
 
122
64
  elif action == GitAction.push:
123
65
  if not repo.remotes:
124
66
  print("⚠️ No remotes configured for push")
125
- return GitOperationResult(
126
- repo_path=path,
127
- action=action.value,
128
- success=False,
129
- message="No remotes configured",
130
- remote_count=0
131
- )
132
-
67
+ return GitOperationResult(repo_path=path, action=action.value, success=False, message="No remotes configured", remote_count=0)
68
+
133
69
  success = True
134
70
  failed_remotes = []
135
71
  for remote in repo.remotes:
@@ -141,15 +77,9 @@ def git_action(path: PathExtended, action: GitAction, mess: Optional[str], r: bo
141
77
  print(f"❌ Failed to push to {remote.name}: {e}")
142
78
  failed_remotes.append(f"{remote.name}: {str(e)}")
143
79
  success = False
144
-
80
+
145
81
  message = "Push successful" if success else f"Push failed for: {', '.join(failed_remotes)}"
146
- return GitOperationResult(
147
- repo_path=path,
148
- action=action.value,
149
- success=success,
150
- message=message,
151
- remote_count=remote_count
152
- )
82
+ return GitOperationResult(repo_path=path, action=action.value, success=success, message=message, remote_count=remote_count)
153
83
 
154
84
  elif action == GitAction.pull:
155
85
  # Use the enhanced update function with uv sync support
@@ -157,222 +87,123 @@ def git_action(path: PathExtended, action: GitAction, mess: Optional[str], r: bo
157
87
  update_repository(repo, auto_uv_sync=auto_uv_sync, allow_password_prompt=False)
158
88
  print("✅ Pull completed")
159
89
  return GitOperationResult(
160
- repo_path=path,
161
- action=action.value,
162
- success=True,
163
- message="Pull completed successfully",
164
- remote_count=remote_count
90
+ repo_path=path, action=action.value, success=True, message="Pull completed successfully", remote_count=remote_count
165
91
  )
166
92
  except Exception as e:
167
93
  print(f"❌ Pull failed: {e}")
168
94
  return GitOperationResult(
169
- repo_path=path,
170
- action=action.value,
171
- success=False,
172
- message=f"Pull failed: {str(e)}",
173
- remote_count=remote_count
95
+ repo_path=path, action=action.value, success=False, message=f"Pull failed: {str(e)}", remote_count=remote_count
174
96
  )
175
97
 
176
98
  except Exception as e:
177
99
  print(f"❌ Error performing {action} on {path}: {e}")
178
- return GitOperationResult(
179
- repo_path=path,
180
- action=action.value,
181
- success=False,
182
- message=f"Error: {str(e)}",
183
- remote_count=remote_count
184
- )
100
+ return GitOperationResult(repo_path=path, action=action.value, success=False, message=f"Error: {str(e)}", remote_count=remote_count)
185
101
 
186
102
  # This should never be reached, but just in case
187
- return GitOperationResult(
188
- repo_path=path,
189
- action=action.value,
190
- success=False,
191
- message="Unknown error",
192
- remote_count=remote_count
193
- )
194
-
195
-
196
- def print_git_operations_summary(summary: GitOperationSummary, operations_performed: list[str]) -> None:
197
- """Print a detailed summary of git operations with rich formatting and tables."""
198
- from rich.console import Console
199
- console = Console()
200
-
201
- # Main summary panel
202
- summary_stats = [
203
- f"Total paths processed: {summary.total_paths_processed}",
204
- f"Git repositories found: {summary.git_repos_found}",
205
- f"Non-git paths skipped: {summary.non_git_paths}"
206
- ]
207
-
208
- console.print(Panel.fit(
209
- "\n".join(summary_stats),
210
- title="[bold blue]📊 Git Operations Summary[/bold blue]",
211
- border_style="blue"
212
- ))
213
-
214
- # Statistics panels in columns
215
- stat_panels = []
216
-
217
- if "commit" in operations_performed:
218
- commit_stats = [
219
- f"Attempted: {summary.commits_attempted}",
220
- f"Successful: {summary.commits_successful}",
221
- f"No changes: {summary.commits_no_changes}",
222
- f"Failed: {summary.commits_failed}"
223
- ]
224
- stat_panels.append(Panel.fit(
225
- "\n".join(commit_stats),
226
- title="[bold green]💾 Commit Operations[/bold green]",
227
- border_style="green"
228
- ))
229
-
230
- if "pull" in operations_performed:
231
- pull_stats = [
232
- f"Attempted: {summary.pulls_attempted}",
233
- f"Successful: {summary.pulls_successful}",
234
- f"Failed: {summary.pulls_failed}"
235
- ]
236
- stat_panels.append(Panel.fit(
237
- "\n".join(pull_stats),
238
- title="[bold cyan]⬇️ Pull Operations[/bold cyan]",
239
- border_style="cyan"
240
- ))
241
-
242
- if "push" in operations_performed:
243
- push_stats = [
244
- f"Attempted: {summary.pushes_attempted}",
245
- f"Successful: {summary.pushes_successful}",
246
- f"Failed: {summary.pushes_failed}"
247
- ]
248
- stat_panels.append(Panel.fit(
249
- "\n".join(push_stats),
250
- title="[bold magenta]🚀 Push Operations[/bold magenta]",
251
- border_style="magenta"
252
- ))
253
-
254
- if stat_panels:
255
- console.print(Columns(stat_panels, equal=True, expand=True))
256
-
257
- # Repositories without remotes warning
258
- if summary.repos_without_remotes:
259
- repos_table = Table(title="[bold yellow]⚠️ Repositories Without Remotes[/bold yellow]")
260
- repos_table.add_column("Repository Name", style="cyan", no_wrap=True)
261
- repos_table.add_column("Full Path", style="dim")
262
-
263
- for repo_path in summary.repos_without_remotes:
264
- repos_table.add_row(repo_path.name, str(repo_path))
265
-
266
- console.print(repos_table)
267
- console.print("[yellow]These repositories cannot be pushed to remote servers.[/yellow]")
268
- elif "push" in operations_performed:
269
- console.print("[green]✅ All repositories have remote configurations.[/green]")
270
-
271
- # Failed operations table
272
- if summary.failed_operations:
273
- failed_table = Table(title=f"[bold red]❌ Failed Operations ({len(summary.failed_operations)} total)[/bold red]")
274
- failed_table.add_column("Action", style="bold red", no_wrap=True)
275
- failed_table.add_column("Repository", style="cyan", no_wrap=True)
276
- failed_table.add_column("Problem", style="red")
277
-
278
- # Group failed operations by type for better organization
279
- failed_by_action = {}
280
- for failed_op in summary.failed_operations:
281
- if failed_op.action not in failed_by_action:
282
- failed_by_action[failed_op.action] = []
283
- failed_by_action[failed_op.action].append(failed_op)
284
-
285
- for action, failures in failed_by_action.items():
286
- for failure in failures:
287
- repo_name = failure.repo_path.name if failure.is_git_repo else f"{failure.repo_path.name} (not git repo)"
288
- problem = failure.message if failure.is_git_repo else "Not a git repository"
289
- failed_table.add_row(action.upper(), repo_name, problem)
290
-
291
- console.print(failed_table)
292
- else:
293
- console.print("[green]✅ All git operations completed successfully![/green]")
294
-
295
- # Overall success assessment
296
- total_failed = len(summary.failed_operations)
297
- total_operations = (summary.commits_attempted + summary.pulls_attempted +
298
- summary.pushes_attempted)
299
-
300
- if total_failed == 0 and total_operations > 0:
301
- console.print(f"\n[bold green]🎉 SUCCESS: All {total_operations} operations completed successfully![/bold green]")
302
- elif total_operations == 0:
303
- console.print("\n[blue]📝 No git operations were performed.[/blue]")
304
- else:
305
- success_rate = ((total_operations - total_failed) / total_operations * 100) if total_operations > 0 else 0
306
- if total_failed > 0:
307
- console.print(f"\n[bold yellow]⚖️ SUMMARY: {total_operations - total_failed}/{total_operations} operations succeeded ({success_rate:.1f}% success rate)[/bold yellow]")
308
- console.print("[yellow]Review the failed operations table above for details on what needs attention.[/yellow]")
309
- else:
310
- console.print(f"\n[bold green]⚖️ SUMMARY: {total_operations}/{total_operations} operations succeeded (100% success rate)[/bold green]")
103
+ return GitOperationResult(repo_path=path, action=action.value, success=False, message="Unknown error", remote_count=remote_count)
311
104
 
312
105
 
313
106
  def perform_git_operations(repos_root: PathExtended, pull: bool, commit: bool, push: bool, recursive: bool, auto_uv_sync: bool) -> None:
314
107
  """Perform git operations on all repositories and provide detailed summary."""
315
108
  print(f"\n🔄 Performing Git actions on repositories @ `{repos_root}`...")
316
109
  summary = GitOperationSummary()
317
- operations_performed = []
318
- # Determine which operations to perform
110
+ # Keep track of which operations we are performing
111
+ operations_performed: List[str] = []
319
112
  if pull:
320
113
  operations_performed.append("pull")
321
114
  if commit:
322
115
  operations_performed.append("commit")
323
116
  if push:
324
117
  operations_performed.append("push")
325
-
326
- for a_path in repos_root.search("*"):
327
- print(f"{('Handling ' + str(a_path)).center(80, '-')}")
328
- summary.total_paths_processed += 1
329
-
330
- # Check if this is a git repository first
118
+
119
+ # Collect all candidate paths first
120
+ paths = list(repos_root.search("*"))
121
+
122
+ def _process_path(a_path: PathExtended) -> Dict[str, Any]:
123
+ """Worker that processes a single path and returns metadata and results."""
331
124
  from git.exc import InvalidGitRepositoryError
332
125
  from git.repo import Repo
333
-
126
+
127
+ result_payload: Dict[str, Any] = {"path": a_path, "is_git": False, "results": [], "repo_remotes_count": 0}
128
+ print(f"{('Handling ' + str(a_path)).center(80, '-')}")
129
+
334
130
  try:
335
131
  repo = Repo(str(a_path), search_parent_directories=False)
336
- summary.git_repos_found += 1
337
-
338
- # Track repos without remotes
339
- if len(repo.remotes) == 0:
340
- summary.repos_without_remotes.append(a_path)
341
-
342
- # Now perform the actual operations
132
+ except InvalidGitRepositoryError:
133
+ result_payload["non_git"] = True
134
+ pprint(f"⚠️ Skipping {a_path} because it is not a git repository.")
135
+ return result_payload
136
+
137
+ # It's a git repo
138
+ result_payload["is_git"] = True
139
+ result_payload["repo_remotes_count"] = len(repo.remotes)
140
+
141
+ # Perform configured operations sequentially for this repo (the repo-level work is done concurrently between repos)
142
+ try:
343
143
  if pull:
344
- result = git_action(path=a_path, action=GitAction.pull, mess=None, r=recursive, auto_uv_sync=auto_uv_sync)
345
- summary.pulls_attempted += 1
346
- if result.success:
347
- summary.pulls_successful += 1
348
- else:
349
- summary.pulls_failed += 1
350
- summary.failed_operations.append(result)
351
-
144
+ r = git_action(path=a_path, action=GitAction.pull, mess=None, r=recursive, auto_uv_sync=auto_uv_sync)
145
+ result_payload["results"].append(r)
352
146
  if commit:
353
- result = git_action(a_path, action=GitAction.commit, mess=None, r=recursive, auto_uv_sync=auto_uv_sync)
354
- summary.commits_attempted += 1
355
- if result.success:
356
- if result.had_changes:
357
- summary.commits_successful += 1
358
- else:
359
- summary.commits_no_changes += 1
360
- else:
361
- summary.commits_failed += 1
362
- summary.failed_operations.append(result)
363
-
147
+ r = git_action(path=a_path, action=GitAction.commit, mess=None, r=recursive, auto_uv_sync=auto_uv_sync)
148
+ result_payload["results"].append(r)
364
149
  if push:
365
- result = git_action(a_path, action=GitAction.push, mess=None, r=recursive, auto_uv_sync=auto_uv_sync)
366
- summary.pushes_attempted += 1
367
- if result.success:
368
- summary.pushes_successful += 1
369
- else:
370
- summary.pushes_failed += 1
371
- summary.failed_operations.append(result)
372
-
373
- except InvalidGitRepositoryError:
374
- summary.non_git_paths += 1
375
- pprint(f"⚠️ Skipping {a_path} because it is not a git repository.")
150
+ r = git_action(path=a_path, action=GitAction.push, mess=None, r=recursive, auto_uv_sync=auto_uv_sync)
151
+ result_payload["results"].append(r)
152
+ except Exception as e:
153
+ # Capture any unexpected exception for this path
154
+ pprint(f"❌ Error processing {a_path}: {e}")
155
+
156
+ return result_payload
157
+
158
+ # Choose a reasonable number of workers
159
+ max_workers = min(32, (os.cpu_count() or 1) * 5, len(paths) or 1)
160
+
161
+ # Run the workers in parallel and aggregate results
162
+ with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as exc:
163
+ future_to_path = {exc.submit(_process_path, p): p for p in paths}
164
+ for fut in concurrent.futures.as_completed(future_to_path):
165
+ payload = fut.result()
166
+ a_path = cast(PathExtended, payload.get("path"))
167
+ summary.total_paths_processed += 1
168
+
169
+ if not payload.get("is_git"):
170
+ summary.non_git_paths += 1
171
+ continue
172
+
173
+ # git repo found
174
+ summary.git_repos_found += 1
175
+ if payload.get("repo_remotes_count", 0) == 0:
176
+ summary.repos_without_remotes.append(a_path)
177
+
178
+ for r in payload.get("results", []):
179
+ action_name = r.action if hasattr(r, "action") else ""
180
+ # Pull
181
+ if action_name == "pull":
182
+ summary.pulls_attempted += 1
183
+ if r.success:
184
+ summary.pulls_successful += 1
185
+ else:
186
+ summary.pulls_failed += 1
187
+ summary.failed_operations.append(r)
188
+ # Commit
189
+ elif action_name == "commit":
190
+ summary.commits_attempted += 1
191
+ if r.success:
192
+ if getattr(r, "had_changes", False):
193
+ summary.commits_successful += 1
194
+ else:
195
+ summary.commits_no_changes += 1
196
+ else:
197
+ summary.commits_failed += 1
198
+ summary.failed_operations.append(r)
199
+ # Push
200
+ elif action_name == "push":
201
+ summary.pushes_attempted += 1
202
+ if r.success:
203
+ summary.pushes_successful += 1
204
+ else:
205
+ summary.pushes_failed += 1
206
+ summary.failed_operations.append(r)
376
207
 
377
208
  # Print the detailed summary
378
- print_git_operations_summary(summary, operations_performed)
209
+ print_git_operations_summary(summary, operations_performed)
@@ -0,0 +1,150 @@
1
+ from enum import Enum
2
+ from machineconfig.utils.path_extended import PathExtended
3
+
4
+
5
+ from dataclasses import dataclass
6
+
7
+ from rich.columns import Columns
8
+ from rich.panel import Panel
9
+ from rich.table import Table
10
+
11
+
12
+ @dataclass
13
+ class GitOperationResult:
14
+ """Result of a git operation on a single repository."""
15
+ repo_path: PathExtended
16
+ action: str
17
+ success: bool
18
+ message: str
19
+ is_git_repo: bool = True
20
+ had_changes: bool = False
21
+ remote_count: int = 0
22
+
23
+
24
+ class GitAction(Enum):
25
+ commit = "commit"
26
+ push = "push"
27
+ pull = "pull"
28
+
29
+
30
+ @dataclass
31
+ class GitOperationSummary:
32
+ """Summary of all git operations performed."""
33
+
34
+ # Basic statistics
35
+ total_paths_processed: int = 0
36
+ git_repos_found: int = 0
37
+ non_git_paths: int = 0
38
+
39
+ # Per-operation statistics
40
+ commits_attempted: int = 0
41
+ commits_successful: int = 0
42
+ commits_no_changes: int = 0
43
+ commits_failed: int = 0
44
+
45
+ pulls_attempted: int = 0
46
+ pulls_successful: int = 0
47
+ pulls_failed: int = 0
48
+
49
+ pushes_attempted: int = 0
50
+ pushes_successful: int = 0
51
+ pushes_failed: int = 0
52
+
53
+ def __post_init__(self):
54
+ self.failed_operations: list[GitOperationResult] = []
55
+ self.repos_without_remotes: list[PathExtended] = []
56
+
57
+
58
+ def print_git_operations_summary(summary: GitOperationSummary, operations_performed: list[str]) -> None:
59
+ """Print a detailed summary of git operations with rich formatting and tables."""
60
+ from rich.console import Console
61
+
62
+ console = Console()
63
+
64
+ # Main summary panel
65
+ summary_stats = [
66
+ f"Total paths processed: {summary.total_paths_processed}",
67
+ f"Git repositories found: {summary.git_repos_found}",
68
+ f"Non-git paths skipped: {summary.non_git_paths}",
69
+ ]
70
+
71
+ console.print(Panel.fit("\n".join(summary_stats), title="[bold blue]📊 Git Operations Summary[/bold blue]", border_style="blue"))
72
+
73
+ # Statistics panels in columns
74
+ stat_panels = []
75
+
76
+ if "commit" in operations_performed:
77
+ commit_stats = [
78
+ f"Attempted: {summary.commits_attempted}",
79
+ f"Successful: {summary.commits_successful}",
80
+ f"No changes: {summary.commits_no_changes}",
81
+ f"Failed: {summary.commits_failed}",
82
+ ]
83
+ stat_panels.append(Panel.fit("\n".join(commit_stats), title="[bold green]💾 Commit Operations[/bold green]", border_style="green"))
84
+
85
+ if "pull" in operations_performed:
86
+ pull_stats = [f"Attempted: {summary.pulls_attempted}", f"Successful: {summary.pulls_successful}", f"Failed: {summary.pulls_failed}"]
87
+ stat_panels.append(Panel.fit("\n".join(pull_stats), title="[bold cyan]⬇️ Pull Operations[/bold cyan]", border_style="cyan"))
88
+
89
+ if "push" in operations_performed:
90
+ push_stats = [f"Attempted: {summary.pushes_attempted}", f"Successful: {summary.pushes_successful}", f"Failed: {summary.pushes_failed}"]
91
+ stat_panels.append(Panel.fit("\n".join(push_stats), title="[bold magenta]🚀 Push Operations[/bold magenta]", border_style="magenta"))
92
+
93
+ if stat_panels:
94
+ console.print(Columns(stat_panels, equal=True, expand=True))
95
+
96
+ # Repositories without remotes warning
97
+ if summary.repos_without_remotes:
98
+ repos_table = Table(title="[bold yellow]⚠️ Repositories Without Remotes[/bold yellow]")
99
+ repos_table.add_column("Repository Name", style="cyan", no_wrap=True)
100
+ repos_table.add_column("Full Path", style="dim")
101
+
102
+ for repo_path in summary.repos_without_remotes:
103
+ repos_table.add_row(repo_path.name, str(repo_path))
104
+
105
+ console.print(repos_table)
106
+ console.print("[yellow]These repositories cannot be pushed to remote servers.[/yellow]")
107
+ elif "push" in operations_performed:
108
+ console.print("[green]✅ All repositories have remote configurations.[/green]")
109
+
110
+ # Failed operations table
111
+ if summary.failed_operations:
112
+ failed_table = Table(title=f"[bold red]❌ Failed Operations ({len(summary.failed_operations)} total)[/bold red]")
113
+ failed_table.add_column("Action", style="bold red", no_wrap=True)
114
+ failed_table.add_column("Repository", style="cyan", no_wrap=True)
115
+ failed_table.add_column("Problem", style="red")
116
+
117
+ # Group failed operations by type for better organization
118
+ failed_by_action = {}
119
+ for failed_op in summary.failed_operations:
120
+ if failed_op.action not in failed_by_action:
121
+ failed_by_action[failed_op.action] = []
122
+ failed_by_action[failed_op.action].append(failed_op)
123
+
124
+ for action, failures in failed_by_action.items():
125
+ for failure in failures:
126
+ repo_name = failure.repo_path.name if failure.is_git_repo else f"{failure.repo_path.name} (not git repo)"
127
+ problem = failure.message if failure.is_git_repo else "Not a git repository"
128
+ failed_table.add_row(action.upper(), repo_name, problem)
129
+
130
+ console.print(failed_table)
131
+ else:
132
+ console.print("[green]✅ All git operations completed successfully![/green]")
133
+
134
+ # Overall success assessment
135
+ total_failed = len(summary.failed_operations)
136
+ total_operations = summary.commits_attempted + summary.pulls_attempted + summary.pushes_attempted
137
+
138
+ if total_failed == 0 and total_operations > 0:
139
+ console.print(f"\n[bold green]🎉 SUCCESS: All {total_operations} operations completed successfully![/bold green]")
140
+ elif total_operations == 0:
141
+ console.print("\n[blue]📝 No git operations were performed.[/blue]")
142
+ else:
143
+ success_rate = ((total_operations - total_failed) / total_operations * 100) if total_operations > 0 else 0
144
+ if total_failed > 0:
145
+ console.print(
146
+ f"\n[bold yellow]⚖️ SUMMARY: {total_operations - total_failed}/{total_operations} operations succeeded ({success_rate:.1f}% success rate)[/bold yellow]"
147
+ )
148
+ console.print("[yellow]Review the failed operations table above for details on what needs attention.[/yellow]")
149
+ else:
150
+ console.print(f"\n[bold green]⚖️ SUMMARY: {total_operations}/{total_operations} operations succeeded (100% success rate)[/bold green]")
@@ -80,7 +80,7 @@ git pull originEnc master
80
80
  uv_project_dir = f"""{str(Path.home().joinpath("code/machineconfig"))}"""
81
81
  uv_with = None
82
82
  else:
83
- uv_with = ["machineconfig>=6.81"]
83
+ uv_with = ["machineconfig>=6.83"]
84
84
  uv_project_dir = None
85
85
 
86
86
  import tempfile
@@ -5,7 +5,7 @@
5
5
  # mkdir ~/data/local
6
6
  # sudo mount -o nolock,noatime,nodiratime,proto=tcp,timeo=600,retrans=2,noac alex-p51s-5:/home/alex/data/local ./data/local
7
7
 
8
- uv run --python 3.14 --with "machineconfig>=6.81" python -m machineconfig.scripts.python.mount_nfs
8
+ uv run --python 3.14 --with "machineconfig>=6.83" python -m machineconfig.scripts.python.mount_nfs
9
9
  # Check if remote server is reachable and share folder exists
10
10
  if ! ping -c 1 "$remote_server" &> /dev/null; then
11
11
  echo "💥 Error: Remote server $remote_server is not reachable."
@@ -7,7 +7,7 @@ $user = ''
7
7
  $sharePath = ''
8
8
  $driveLetter = ''
9
9
 
10
- uv run --python 3.14 --with "machineconfig>=6.81" python -m machineconfig.scripts.python.mount_ssh
10
+ uv run --python 3.14 --with "machineconfig>=6.83" python -m machineconfig.scripts.python.mount_ssh
11
11
 
12
12
  net use T: \\sshfs.kr\$user@$host.local
13
13
  # this worked: net use T: \\sshfs\alex@alex-p51s-5.local
@@ -1,7 +1,7 @@
1
1
  #!/bin/bash
2
2
  . <( curl -sSL "https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_linux/uv.sh")
3
3
  mcfg() {
4
- "$HOME/.local/bin/uv" run --python 3.14 --with "machineconfig>=6.81" mcfg "$@"
4
+ "$HOME/.local/bin/uv" run --python 3.14 --with "machineconfig>=6.83" mcfg "$@"
5
5
  }
6
6
  alias d="mcfg devops"
7
7
  alias c="mcfg cloud"
@@ -2,7 +2,7 @@
2
2
 
3
3
  iex (iwr "https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/machineconfig/setup_windows/uv.ps1").Content
4
4
  function mcfg {
5
- & "$HOME\.local\bin\uv.exe" run --python 3.14 --with "machineconfig>=6.81" mcfg $args
5
+ & "$HOME\.local\bin\uv.exe" run --python 3.14 --with "machineconfig>=6.83" mcfg $args
6
6
  }
7
7
  function d { mcfg devops @args }
8
8
  function c { mcfg cloud @args }
@@ -8,7 +8,7 @@ from machineconfig.utils.terminal import Response
8
8
  from machineconfig.utils.accessories import pprint, randstr
9
9
  from machineconfig.utils.meta import lambda_to_python_script
10
10
  UV_RUN_CMD = "$HOME/.local/bin/uv run" if platform.system() != "Windows" else """& "$env:USERPROFILE/.local/bin/uv" run"""
11
- MACHINECONFIG_VERSION = "machineconfig>=6.81"
11
+ MACHINECONFIG_VERSION = "machineconfig>=6.83"
12
12
  DEFAULT_PICKLE_SUBDIR = "tmp_results/tmp_scripts/ssh"
13
13
 
14
14
  class SSH:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: machineconfig
3
- Version: 6.81
3
+ Version: 6.83
4
4
  Summary: Dotfiles management package
5
5
  Author-email: Alex Al-Saffar <programmer@usa.com>
6
6
  License: Apache 2.0
@@ -106,7 +106,7 @@ machineconfig/scripts/linux/fzfag,sha256=x0rX7vM_YjKLZ822D2Xh0HdaTj5kR_gG3g_5_w6
106
106
  machineconfig/scripts/linux/fzffg,sha256=jjeeyFkWmBbwH2taRqC3EOzZep2KR-ZYoI4UI-5kHqg,1090
107
107
  machineconfig/scripts/linux/fzfg,sha256=ClGnJZUsIk4y0qs3W5iXGo-nd0FaqAHMsnh8uoXQFy8,1190
108
108
  machineconfig/scripts/linux/fzfrga,sha256=xSdws6ae28ZXkkqz_uupZ0MYw_vxE2qpLT2DLS3WITM,460
109
- machineconfig/scripts/linux/mcfgs,sha256=l8xt5BLEmN_Xa7OD9ZgpPc85hG4R1cM5CIRFYQi2VjI,1125
109
+ machineconfig/scripts/linux/mcfgs,sha256=O47lVLPPK2uRCAdt_Ll87PsukTY_cAGa35ZFdjZEM5w,1150
110
110
  machineconfig/scripts/linux/skrg,sha256=JgQJGwxaChr148bDnpTB0rrqZMe2o2zGSDA9x_oUhWM,133
111
111
  machineconfig/scripts/linux/warp-cli.sh,sha256=shFFZ9viet_DSEEHT8kxlGRHoJpO6o85pKYnc3rIkaA,3868
112
112
  machineconfig/scripts/linux/z_ls,sha256=h5YJYfnJrmtLe4c2iKk5aZdaK_Zeaj3CpQX8SSr7fr0,3310
@@ -159,7 +159,7 @@ machineconfig/scripts/python/ai/solutions/opencode/opencode.json,sha256=nahHKRw1
159
159
  machineconfig/scripts/python/ai/solutions/opencode/opencode.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
160
160
  machineconfig/scripts/python/env_manager/__init__.py,sha256=E4LAHbU1wo2dLjE36ntv8U7QNTe8TasujUAYK9SLvWk,6
161
161
  machineconfig/scripts/python/env_manager/path_manager_backend.py,sha256=ZVGlGJALhg7zNABDdwXxL7MFbL2BXPebObipXSLGbic,1552
162
- machineconfig/scripts/python/env_manager/path_manager_tui.py,sha256=-pd5Qi571_RHEnA_b7LXPu2B7gt2qNb9KN6Z_XBOQLE,6932
162
+ machineconfig/scripts/python/env_manager/path_manager_tui.py,sha256=VL_VuM9XuZL6dekAOq_vpU4meluHnwSv6_MTxIo1_30,6932
163
163
  machineconfig/scripts/python/helpers_cloud/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
164
164
  machineconfig/scripts/python/helpers_cloud/cloud_copy.py,sha256=OV1w3ajFVFs6FJytjIPOntYB_aW2ywGohKi73V4Dm2Y,8691
165
165
  machineconfig/scripts/python/helpers_cloud/cloud_helpers.py,sha256=GA-bxXouUmknk9fyQAsPT-Xl3RG9-yBed71a2tu9Pig,4914
@@ -175,12 +175,12 @@ machineconfig/scripts/python/helpers_croshell/start_slidev.py,sha256=HfJReOusTPh
175
175
  machineconfig/scripts/python/helpers_croshell/viewer.py,sha256=heQNjB9fwn3xxbPgMofhv1Lp6Vtkl76YjjexWWBM0pM,2041
176
176
  machineconfig/scripts/python/helpers_croshell/viewer_template.py,sha256=ve3Q1-iKhCLc0VJijKvAeOYp2xaFOeIOC_XW956GWCc,3944
177
177
  machineconfig/scripts/python/helpers_devops/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
178
- machineconfig/scripts/python/helpers_devops/cli_config.py,sha256=DuKqawGdSMdOMfQyAJrDSnTc7s30LjgORS4HII3_dzI,7218
178
+ machineconfig/scripts/python/helpers_devops/cli_config.py,sha256=AhnxhxlmnfktAOJ7p46HHide2OGcoj4Ti7VhnHg_nYM,7218
179
179
  machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py,sha256=fluxRtD6hlbh131_RmeKr2Dy8tZpeC4H9-wp2sYt0dM,2486
180
180
  machineconfig/scripts/python/helpers_devops/cli_data.py,sha256=79Xvx7YnbueruEnl69hrDg2AhVxf_zCUdlVcKfeMGyQ,1774
181
181
  machineconfig/scripts/python/helpers_devops/cli_nw.py,sha256=B5Xa9pV5MdC4vPo3EmKaHvNMlThsY3c5F92YPE5j3rI,4176
182
182
  machineconfig/scripts/python/helpers_devops/cli_repos.py,sha256=Xwkv1adqHZvTfRSPWiqSK3PZ1XADyx3llw_YkbxaKyE,12505
183
- machineconfig/scripts/python/helpers_devops/cli_self.py,sha256=kT8Bh6z3UVlqbVZE16a8f7AJEP6D4iYLSZUA1SOUc5c,6225
183
+ machineconfig/scripts/python/helpers_devops/cli_self.py,sha256=ixRdjOHgLdyfAz8jRucgCnWpNtpioH6U4yuri4CBSwQ,6225
184
184
  machineconfig/scripts/python/helpers_devops/cli_share_server.py,sha256=q9pFJ6AxPuygMr3onMNOKEuuQHbVE_6Qoyo7xRT5FX0,4196
185
185
  machineconfig/scripts/python/helpers_devops/cli_terminal.py,sha256=k_PzXaiGyE0vXr0Ii1XcJz2A7UvyPJrR31TRWt4RKRI,6019
186
186
  machineconfig/scripts/python/helpers_devops/cli_utils.py,sha256=KGIU1uTWC4g3kvBBkGrM-TtmcR8V1jTxVMGKXDSLnLA,10183
@@ -219,9 +219,10 @@ machineconfig/scripts/python/helpers_navigator/command_tree.py,sha256=Kw673rk7Qb
219
219
  machineconfig/scripts/python/helpers_navigator/data_models.py,sha256=62CIZ01rfCD2mKX_ihEVuhNzZ8FDnRSEIIQuyKOtmOg,533
220
220
  machineconfig/scripts/python/helpers_navigator/main_app.py,sha256=R1vOBMUKaiFHOg0D4SzTcu48Wsc8lO0LKAzrZxCsCtg,8849
221
221
  machineconfig/scripts/python/helpers_navigator/search_bar.py,sha256=kDi8Jhxap8wdm7YpDBtfhwcPnSqDPFrV2LqbcSBWMT4,414
222
- machineconfig/scripts/python/helpers_repos/action.py,sha256=9AxWy8mB9HFeV5t11-qD_l-KA5jkUmm0pXVKT1L6-Qk,14894
222
+ machineconfig/scripts/python/helpers_repos/action.py,sha256=8je051kpGZ7A_GRsQyWKhPZ8xVW7tSm4bnPu6VjxaXk,9755
223
+ machineconfig/scripts/python/helpers_repos/action_helper.py,sha256=XRCtkGkNrxauqUd9qkxtfJt02Mx2gejSYDLL0jyWn24,6176
223
224
  machineconfig/scripts/python/helpers_repos/clone.py,sha256=UULEG5xJuXlPGU0nqXH6U45jA9DOFqLw8B4iPytCwOQ,5471
224
- machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py,sha256=y3FC57KBKY0w2MwYb6P8uJus_S0ZYalTHvTWsdu6I34,10450
225
+ machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py,sha256=B1vZC587lRYvAWxWKfZqm2URZUUuMB3AuCtvYo4MicI,10450
225
226
  machineconfig/scripts/python/helpers_repos/count_lines.py,sha256=Q5c7b-DxvTlQmljoic7niTuiAVyFlwYvkVQ7uRJHiTo,16009
226
227
  machineconfig/scripts/python/helpers_repos/count_lines_frontend.py,sha256=vSDtrF4829jziwp6WZmGt9G8MJ9jY4hfXqtf0vhkYSE,607
227
228
  machineconfig/scripts/python/helpers_repos/entrypoint.py,sha256=WYEFGUJp9HWImlFjbs_hiFZrUqM_KEYm5VvSUjWd04I,2810
@@ -237,7 +238,7 @@ machineconfig/scripts/python/nw/add_ssh_key.py,sha256=9JLmWu8pE7PAL5VuCFd19iVEdC
237
238
  machineconfig/scripts/python/nw/devops_add_identity.py,sha256=aPjcHbTLhxYwWYcandyAHdwuO15ZBu3fB82u6bI0tMQ,3773
238
239
  machineconfig/scripts/python/nw/devops_add_ssh_key.py,sha256=CkIl85hZLtG9k7yXLSzqi88YrilHV4hIUWHAPBwxWjw,8922
239
240
  machineconfig/scripts/python/nw/mount_drive,sha256=zemKofv7hOmRN_V3qK0q580GkfWw3VdikyVVQyiu8j8,3514
240
- machineconfig/scripts/python/nw/mount_nfs,sha256=bIddaHflyhKg0ONjGD3bKZX9nV2iWyUiYdFk5B8Djvs,1855
241
+ machineconfig/scripts/python/nw/mount_nfs,sha256=TBTU0sFK2d_v-A-XBsZG3gTrsHYj8MbpMsrM9LySXX4,1855
241
242
  machineconfig/scripts/python/nw/mount_nfs.py,sha256=lOMDY4RS7tx8gsCazVR5tNNwFbaRyO2PJlnwBCDQgCM,3573
242
243
  machineconfig/scripts/python/nw/mount_nw_drive,sha256=BqjGBCbwe5ZAsZDO3L0zHhh_gJfZy1CYOcqXA4Y-WkQ,2262
243
244
  machineconfig/scripts/python/nw/mount_nw_drive.py,sha256=iru6AtnTyvyuk6WxlK5R4lDkuliVpPV5_uBTVVhXtjQ,1550
@@ -255,7 +256,7 @@ machineconfig/scripts/windows/mcfgs.ps1,sha256=uuK5pEz38D3_SOjfhbvkDT8Kt4I62YhNz
255
256
  machineconfig/scripts/windows/mounts/mount_nfs.ps1,sha256=XrAdzpxE6a4OccSmWJ7YWHJTnsZK8uXnFE5j9GOPA20,2026
256
257
  machineconfig/scripts/windows/mounts/mount_nw.ps1,sha256=puxcfZc3ZCJerm8pj8OZGVoTYkhzp-h7oV-MrksSqIE,454
257
258
  machineconfig/scripts/windows/mounts/mount_smb.ps1,sha256=PzYWpIO9BpwXjdWlUQL9pnMRnOGNSkxfh4bHukJFme8,69
258
- machineconfig/scripts/windows/mounts/mount_ssh.ps1,sha256=smJZuyHwcS0ZDNJHXD3gYtROQa86MhRgQqmE2EzvGEc,322
259
+ machineconfig/scripts/windows/mounts/mount_ssh.ps1,sha256=TGTSzYfJ8kOx1Anx2CIUpWzRd6E3cQ2rmzkQcm5QwxA,322
259
260
  machineconfig/scripts/windows/mounts/share_cloud.cmd,sha256=exD7JCdxw2LqVjw2MKCYHbVZlEqmelXtwnATng-dhJ4,1028
260
261
  machineconfig/scripts/windows/mounts/share_smb.ps1,sha256=U7x8ULYSjbgzTtiHNSKQuTaZ_apilDvkGV5Xm5hXk5M,384
261
262
  machineconfig/scripts/windows/mounts/unlock_bitlocker.ps1,sha256=Wv-SLscdckV-1mG3p82VXKPY9zW3hgkRmcLUXIZ1daE,253
@@ -372,7 +373,7 @@ machineconfig/setup_linux/others/cli_installation.sh,sha256=gVvszYZJgKPRJx2SEaE3
372
373
  machineconfig/setup_linux/others/mint_keyboard_shortcuts.sh,sha256=F5dbg0n9RHsKGPn8fIdZMn3p0RrHEkb8rWBGsdVGbus,1207
373
374
  machineconfig/setup_linux/ssh/openssh_all.sh,sha256=3dg6HEUFbHQOzLfSAtzK_D_GB8rGCCp_aBnxNdnidVc,824
374
375
  machineconfig/setup_linux/ssh/openssh_wsl.sh,sha256=1eeRGrloVB34K5z8yWVUMG5b9pV-WBfHgV9jqXiYgCQ,1398
375
- machineconfig/setup_linux/web_shortcuts/interactive.sh,sha256=6nJEEtNqMg_IRkFxH83RF7rIwKjyqCfsoOQhA4pExWw,464
376
+ machineconfig/setup_linux/web_shortcuts/interactive.sh,sha256=Bkw6JQMZlDqshUjxRBvmf6PPtn_eUtgGRyYdJn2LI5k,464
376
377
  machineconfig/setup_mac/__init__.py,sha256=Q1waupi5vCBroLqc8Rtnw69_7jLnm2Cs7_zH_GSZgMs,616
377
378
  machineconfig/setup_mac/apps.sh,sha256=R0N6fBwLCzwy4qAormyMerXXXrHazibSkY6NrNOpTQU,2772
378
379
  machineconfig/setup_mac/uv.sh,sha256=CSN8oCBKS-LK1vJJqYOhAMcrouTf4Q_F3cpplc_ddMA,1157
@@ -386,7 +387,7 @@ machineconfig/setup_windows/others/power_options.ps1,sha256=c7Hn94jBD5GWF29CxMhm
386
387
  machineconfig/setup_windows/ssh/add-sshkey.ps1,sha256=qfPdqCpd9KP3VhH4ifsUm1Xvec7c0QVl4Wt8JIAm9HQ,1653
387
388
  machineconfig/setup_windows/ssh/add_identity.ps1,sha256=b8ZXpmNUSw3IMYvqSY7ClpdWPG39FS7MefoWnRhWN2U,506
388
389
  machineconfig/setup_windows/ssh/openssh-server.ps1,sha256=OMlYQdvuJQNxF5EILLPizB6BZAT3jAmDsv1WcVVxpFQ,2529
389
- machineconfig/setup_windows/web_shortcuts/interactive.ps1,sha256=c5TXAJ7o5pSD_9YByBSa6emWBlEbJC4pZwVrZc2Sapc,581
390
+ machineconfig/setup_windows/web_shortcuts/interactive.ps1,sha256=tSaANlJUcCi_sYBIp38KXrYqqYj7ambmaSHk6kYQN4E,581
390
391
  machineconfig/setup_windows/wt_and_pwsh/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
391
392
  machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py,sha256=ogxJnwpdcpH7N6dFJu95UCNoGYirZKQho_3X0F_hmXs,6791
392
393
  machineconfig/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -404,7 +405,7 @@ machineconfig/utils/procs.py,sha256=YPA_vEYQGwPd_o_Lc6nOTBo5BrB1tSs8PJ42XiGpenM,
404
405
  machineconfig/utils/scheduler.py,sha256=fguwvINyaupOxdU5Uadyxalh_jXTXDzt0ioEgjEOKcM,14705
405
406
  machineconfig/utils/scheduling.py,sha256=6x5zLA7sY5gohrEtN6zGrXIqNFasMoyBfwLcOjrjiME,11109
406
407
  machineconfig/utils/source_of_truth.py,sha256=ZAnCRltiM07ig--P6g9_6nEAvNFC4X4ERFTVcvpIYsE,764
407
- machineconfig/utils/ssh.py,sha256=eOJFTxzDr_N81xqcEDPDvGiITMxE4m-sO5RZAUkEODs,39009
408
+ machineconfig/utils/ssh.py,sha256=3jsTdPocNGLnJBMmkKBEsRCgE_p9u3ts02FcweqQTxE,39009
408
409
  machineconfig/utils/terminal.py,sha256=VDgsjTjBmMGgZN0YIc0pJ8YksLDrBtiXON1EThy7_is,4264
409
410
  machineconfig/utils/tst.py,sha256=6u1GI49NdcpxH2BYGAusNfY5q9G_ytCGVzFM5b6HYpM,674
410
411
  machineconfig/utils/upgrade_packages.py,sha256=TCohwiwc0btSsInOloxDVuk5i88yc1vBK8RZcoMWoUw,3425
@@ -433,8 +434,8 @@ machineconfig/utils/schemas/installer/installer_types.py,sha256=QClRY61QaduBPJoS
433
434
  machineconfig/utils/schemas/layouts/layout_types.py,sha256=TcqlZdGVoH8htG5fHn1KWXhRdPueAcoyApppZsPAPto,2020
434
435
  machineconfig/utils/schemas/repos/repos_types.py,sha256=ECVr-3IVIo8yjmYmVXX2mnDDN1SLSwvQIhx4KDDQHBQ,405
435
436
  machineconfig/utils/ssh_utils/utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
436
- machineconfig-6.81.dist-info/METADATA,sha256=akyrWPX9TB4A7xBMBUNJOW7CgsRn4W2ra1dNUug_Y88,2928
437
- machineconfig-6.81.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
438
- machineconfig-6.81.dist-info/entry_points.txt,sha256=2OetLXw0yXtfG6MmJXbzZipCQfPueeM3oMgTORSEfYs,465
439
- machineconfig-6.81.dist-info/top_level.txt,sha256=porRtB8qms8fOIUJgK-tO83_FeH6Bpe12oUVC670teA,14
440
- machineconfig-6.81.dist-info/RECORD,,
437
+ machineconfig-6.83.dist-info/METADATA,sha256=av1Q9f0ye-XEKl0wkJXHAVKpL_N1Yxee12RH2ktRdWQ,2928
438
+ machineconfig-6.83.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
439
+ machineconfig-6.83.dist-info/entry_points.txt,sha256=2OetLXw0yXtfG6MmJXbzZipCQfPueeM3oMgTORSEfYs,465
440
+ machineconfig-6.83.dist-info/top_level.txt,sha256=porRtB8qms8fOIUJgK-tO83_FeH6Bpe12oUVC670teA,14
441
+ machineconfig-6.83.dist-info/RECORD,,