machineconfig 3.83__py3-none-any.whl → 3.86__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/zellij_local.py +2 -2
- machineconfig/cluster/sessions_managers/zellij_remote.py +2 -2
- machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +2 -2
- machineconfig/jobs/python/vscode/api.py +8 -7
- machineconfig/scripts/python/ai/initai.py +1 -11
- machineconfig/scripts/python/cloud_copy.py +33 -27
- machineconfig/scripts/python/cloud_manager.py +0 -2
- machineconfig/scripts/python/cloud_mount.py +13 -10
- machineconfig/scripts/python/cloud_sync.py +30 -28
- machineconfig/scripts/python/croshell.py +46 -53
- machineconfig/scripts/python/dotfile.py +16 -16
- machineconfig/scripts/python/fire_agents.py +4 -5
- machineconfig/scripts/python/fire_jobs.py +30 -14
- machineconfig/scripts/python/fire_jobs_args_helper.py +43 -15
- machineconfig/scripts/python/fire_jobs_layout_helper.py +24 -16
- machineconfig/scripts/python/helpers/helpers4.py +0 -2
- machineconfig/scripts/python/repos.py +10 -88
- machineconfig/scripts/python/repos_helper_action.py +335 -0
- machineconfig/scripts/python/scheduler.py +0 -1
- machineconfig/scripts/python/share_terminal.py +41 -0
- machineconfig/scripts/python/start_slidev.py +15 -13
- machineconfig/scripts/python/start_terminals.py +19 -19
- machineconfig/scripts/python/t4.py +17 -0
- machineconfig/scripts/python/wifi_conn.py +16 -14
- machineconfig/scripts/python/wsl_windows_transfer.py +23 -29
- machineconfig/utils/accessories.py +45 -7
- machineconfig/utils/ai/generate_file_checklist.py +17 -17
- {machineconfig-3.83.dist-info → machineconfig-3.86.dist-info}/METADATA +1 -1
- {machineconfig-3.83.dist-info → machineconfig-3.86.dist-info}/RECORD +32 -32
- {machineconfig-3.83.dist-info → machineconfig-3.86.dist-info}/entry_points.txt +5 -5
- machineconfig/cluster/templates/cli_gooey.py +0 -115
- machineconfig/jobs/python/vscode/link_ve.py +0 -63
- machineconfig/jobs/python/vscode/select_interpreter.py +0 -87
- {machineconfig-3.83.dist-info → machineconfig-3.86.dist-info}/WHEEL +0 -0
- {machineconfig-3.83.dist-info → machineconfig-3.86.dist-info}/top_level.txt +0 -0
|
@@ -8,7 +8,6 @@ fire
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
from machineconfig.scripts.python.helpers.helpers4 import search_for_files_of_interest
|
|
11
|
-
from machineconfig.scripts.python.helpers.helpers4 import convert_kwargs_to_fire_kwargs_str
|
|
12
11
|
from machineconfig.scripts.python.helpers.helpers4 import parse_pyfile
|
|
13
12
|
from machineconfig.scripts.python.helpers.helpers4 import get_import_module_code
|
|
14
13
|
from machineconfig.utils.ve import get_ve_activate_line, get_ve_path_and_ipython_profile
|
|
@@ -17,7 +16,7 @@ from machineconfig.utils.path_helper import match_file_name, sanitize_path
|
|
|
17
16
|
|
|
18
17
|
from machineconfig.utils.path_extended import PathExtended as PathExtended
|
|
19
18
|
from machineconfig.utils.accessories import get_repo_root, randstr
|
|
20
|
-
from machineconfig.scripts.python.fire_jobs_args_helper import FireJobArgs, extract_kwargs
|
|
19
|
+
from machineconfig.scripts.python.fire_jobs_args_helper import FireJobArgs, extract_kwargs, parse_fire_args_from_context
|
|
21
20
|
import platform
|
|
22
21
|
from typing import Optional, Annotated
|
|
23
22
|
from pathlib import Path
|
|
@@ -26,7 +25,7 @@ import typer
|
|
|
26
25
|
# import os
|
|
27
26
|
|
|
28
27
|
|
|
29
|
-
def route(args: FireJobArgs) -> None:
|
|
28
|
+
def route(args: FireJobArgs, fire_args: str = "") -> None:
|
|
30
29
|
if args.layout:
|
|
31
30
|
from machineconfig.scripts.python.fire_jobs_layout_helper import handle_layout_args
|
|
32
31
|
|
|
@@ -51,7 +50,7 @@ def route(args: FireJobArgs) -> None:
|
|
|
51
50
|
ipy_profile = "default"
|
|
52
51
|
|
|
53
52
|
if choice_file.suffix == ".py":
|
|
54
|
-
kwargs = extract_kwargs(args)
|
|
53
|
+
kwargs = extract_kwargs(args) # This now returns empty dict, but kept for compatibility
|
|
55
54
|
activate_ve_line = get_ve_activate_line(ve_root=args.ve or ve_root_from_file or "$HOME/code/machineconfig/.venv")
|
|
56
55
|
else:
|
|
57
56
|
activate_ve_line = ""
|
|
@@ -217,8 +216,7 @@ except ImportError as _ex:
|
|
|
217
216
|
# both selected function and kwargs are mentioned in the made up script, therefore no need for fire module.
|
|
218
217
|
command = f"{exe} {choice_file} "
|
|
219
218
|
elif choice_function is not None:
|
|
220
|
-
|
|
221
|
-
command = f"{exe} -m fire {choice_file} {choice_function} {kwargs_str}"
|
|
219
|
+
command = f"{exe} -m fire {choice_file} {choice_function} {fire_args}"
|
|
222
220
|
elif args.streamlit:
|
|
223
221
|
# for .streamlit config to work, it needs to be in the current directory.
|
|
224
222
|
if args.holdDirectory:
|
|
@@ -230,8 +228,7 @@ except ImportError as _ex:
|
|
|
230
228
|
command = rf""" cd /d {choice_file.parent} & {exe} {choice_file.name} """
|
|
231
229
|
else:
|
|
232
230
|
if choice_file.suffix == "":
|
|
233
|
-
|
|
234
|
-
command = f"{exe} {choice_file} {kwargs_raw}"
|
|
231
|
+
command = f"{exe} {choice_file} {fire_args}"
|
|
235
232
|
else:
|
|
236
233
|
# command = f"cd {choice_file.parent}\n{exe} {choice_file.name}\ncd {PathExtended.cwd()}"
|
|
237
234
|
command = f"{exe} {choice_file} "
|
|
@@ -330,7 +327,8 @@ python -m machineconfig.cluster.templates.cli_click --file {choice_file} """
|
|
|
330
327
|
|
|
331
328
|
|
|
332
329
|
def main(
|
|
333
|
-
|
|
330
|
+
ctx: typer.Context,
|
|
331
|
+
path: Annotated[str, typer.Argument(help="Path to the Python file to run")] = ".",
|
|
334
332
|
function: Annotated[Optional[str], typer.Argument(help="Function to run")] = None,
|
|
335
333
|
ve: Annotated[str, typer.Option("--ve", "-v", help="Virtual environment name")] = "",
|
|
336
334
|
cmd: Annotated[bool, typer.Option("--cmd", "-B", help="Create a cmd fire command to launch the job asynchronously")] = False,
|
|
@@ -351,10 +349,13 @@ def main(
|
|
|
351
349
|
Nprocess: Annotated[int, typer.Option("--Nprocess", "-p", help="Number of processes to use")] = 1,
|
|
352
350
|
zellij_tab: Annotated[Optional[str], typer.Option("--zellij_tab", "-z", help="Open in a new zellij tab")] = None,
|
|
353
351
|
watch: Annotated[bool, typer.Option("--watch", "-w", help="Watch the file for changes")] = False,
|
|
354
|
-
kw: Annotated[Optional[list[str]], typer.Option("--kw", help="Keyword arguments to pass to the function in the form of k1 v1 k2 v2 ... (meaning k1=v1, k2=v2, etc)")] = None,
|
|
355
352
|
layout: Annotated[bool, typer.Option("--layout", "-L", help="Use layout configuration (Zellij Or WindowsTerminal)")] = False,
|
|
356
353
|
) -> None:
|
|
357
354
|
"""Main function to process fire jobs arguments."""
|
|
355
|
+
|
|
356
|
+
# Get Fire arguments from context
|
|
357
|
+
fire_args = parse_fire_args_from_context(ctx)
|
|
358
|
+
|
|
358
359
|
args = FireJobArgs(
|
|
359
360
|
path=path,
|
|
360
361
|
function=function,
|
|
@@ -377,16 +378,31 @@ def main(
|
|
|
377
378
|
Nprocess=Nprocess,
|
|
378
379
|
zellij_tab=zellij_tab,
|
|
379
380
|
watch=watch,
|
|
380
|
-
kw=kw,
|
|
381
381
|
layout=layout,
|
|
382
382
|
)
|
|
383
|
-
|
|
383
|
+
try:
|
|
384
|
+
route(args, fire_args)
|
|
385
|
+
except SystemExit:
|
|
386
|
+
# Re-raise SystemExit to preserve exit codes and allow clean exits
|
|
387
|
+
raise
|
|
388
|
+
except Exception as e:
|
|
389
|
+
# For other exceptions, print clean error message and exit
|
|
390
|
+
import sys
|
|
391
|
+
print(f"❌ Error: {e}", file=sys.stderr)
|
|
392
|
+
sys.exit(1)
|
|
384
393
|
|
|
385
394
|
|
|
386
395
|
def main_from_parser():
|
|
387
|
-
typer
|
|
396
|
+
# from trogon.typer import init_tui
|
|
397
|
+
# from trogon.typer import init_tui
|
|
398
|
+
from typer import Typer
|
|
399
|
+
app = Typer(add_completion=False)
|
|
400
|
+
app.command(context_settings={"allow_extra_args": True, "allow_interspersed_args": False})(main)
|
|
401
|
+
# typer.run(main)
|
|
402
|
+
# init_tui(app)
|
|
403
|
+
app()
|
|
388
404
|
|
|
389
405
|
|
|
390
406
|
if __name__ == "__main__":
|
|
391
407
|
# options, func_args = parse_pyfile(file_path="C:/Users/aalsaf01/code/machineconfig/myresources/crocodile/core.py")
|
|
392
|
-
|
|
408
|
+
main_from_parser()
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
|
-
from typing import Optional
|
|
2
|
+
from typing import Optional, Any
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
@dataclass
|
|
@@ -27,21 +27,49 @@ class FireJobArgs:
|
|
|
27
27
|
Nprocess: int = 1
|
|
28
28
|
zellij_tab: Optional[str] = None
|
|
29
29
|
watch: bool = False
|
|
30
|
-
kw: Optional[list[str]] = None
|
|
31
30
|
layout: bool = False
|
|
32
31
|
|
|
33
32
|
|
|
34
33
|
def extract_kwargs(args: FireJobArgs) -> dict[str, object]:
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
34
|
+
"""Extract kwargs from command line using -- separator.
|
|
35
|
+
|
|
36
|
+
Returns empty dict since kwargs are now parsed directly from sys.argv
|
|
37
|
+
using the -- separator pattern in the main function.
|
|
38
|
+
"""
|
|
39
|
+
return {}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def parse_fire_args_from_argv() -> str:
|
|
43
|
+
"""Parse arguments after -- separator for Fire compatibility.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
String of Fire-compatible arguments to append to command
|
|
47
|
+
"""
|
|
48
|
+
import sys
|
|
49
|
+
|
|
50
|
+
if '--' in sys.argv:
|
|
51
|
+
separator_index = sys.argv.index('--')
|
|
52
|
+
fire_args = sys.argv[separator_index + 1:]
|
|
53
|
+
# Join all Fire arguments - they should already be in Fire format
|
|
54
|
+
return ' '.join(fire_args) if fire_args else ''
|
|
55
|
+
|
|
56
|
+
return ''
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def parse_fire_args_from_context(ctx: Any) -> str:
|
|
60
|
+
"""Parse Fire arguments from typer context.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
ctx: Typer context containing raw arguments
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
String of Fire-compatible arguments to append to command
|
|
67
|
+
"""
|
|
68
|
+
# Get remaining args that weren't consumed by typer
|
|
69
|
+
if hasattr(ctx, 'args') and ctx.args:
|
|
70
|
+
args = ctx.args
|
|
71
|
+
# Filter out the -- separator if present
|
|
72
|
+
if args and args[0] == '--':
|
|
73
|
+
args = args[1:]
|
|
74
|
+
return ' '.join(args)
|
|
75
|
+
return ''
|
|
@@ -10,34 +10,39 @@ if TYPE_CHECKING:
|
|
|
10
10
|
from machineconfig.scripts.python.fire_jobs_args_helper import FireJobArgs
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
def select_layout(layouts_json_file: Path,
|
|
13
|
+
def select_layout(layouts_json_file: Path, layouts_name: Optional[list[str]]) -> list[LayoutConfig]:
|
|
14
14
|
import json
|
|
15
|
-
|
|
16
15
|
layout_file: LayoutsFile = json.loads(layouts_json_file.read_text(encoding="utf-8"))
|
|
17
16
|
if len(layout_file["layouts"]) == 0:
|
|
18
17
|
raise ValueError(f"No layouts found in {layouts_json_file}")
|
|
19
|
-
if
|
|
18
|
+
if layouts_name is None:
|
|
20
19
|
options = [layout["layoutName"] for layout in layout_file["layouts"]]
|
|
21
20
|
from machineconfig.utils.options import choose_from_options
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
21
|
+
layouts_name = choose_from_options(multi=True, options=options, prompt="Choose a layout configuration:", fzf=True, msg="Choose one option")
|
|
22
|
+
print(f"Selected layout(s): {layouts_name}")
|
|
23
|
+
# layout_chosen = next((layout for layout in layout_file["layouts"] if layout["layoutName"] == layouts_name), None)
|
|
24
|
+
# if layout_chosen is None:
|
|
25
|
+
# layout_chosen = next((layout for layout in layout_file["layouts"] if layout["layoutName"].lower() == layouts_name.lower()), None)
|
|
26
|
+
# if layout_chosen is None:
|
|
27
|
+
# available_layouts = [layout["layoutName"] for layout in layout_file["layouts"]]
|
|
28
|
+
# raise ValueError(f"Layout '{layouts_name}' not found. Available layouts: {available_layouts}")
|
|
29
|
+
layouts_chosen: list[LayoutConfig] = []
|
|
30
|
+
for name in layouts_name:
|
|
31
|
+
layout_chosen = next((layout for layout in layout_file["layouts"] if layout["layoutName"] == name), None)
|
|
32
|
+
if layout_chosen is None:
|
|
33
|
+
layout_chosen = next((layout for layout in layout_file["layouts"] if layout["layoutName"].lower() == name.lower()), None)
|
|
34
|
+
if layout_chosen is None:
|
|
35
|
+
available_layouts = [layout["layoutName"] for layout in layout_file["layouts"]]
|
|
36
|
+
raise ValueError(f"Layout '{name}' not found. Available layouts: {available_layouts}")
|
|
37
|
+
layouts_chosen.append(layout_chosen)
|
|
38
|
+
return layouts_chosen
|
|
32
39
|
|
|
33
40
|
|
|
34
41
|
def launch_layout(layout_config: LayoutConfig) -> Optional[Exception]:
|
|
35
42
|
import platform
|
|
36
|
-
|
|
37
43
|
if platform.system() == "Linux" or platform.system() == "Darwin":
|
|
38
44
|
print("🧑💻 Launching layout using Zellij terminal multiplexer...")
|
|
39
45
|
from machineconfig.cluster.sessions_managers.zellij_local import run_zellij_layout
|
|
40
|
-
|
|
41
46
|
run_zellij_layout(layout_config=layout_config)
|
|
42
47
|
elif platform.system() == "Windows":
|
|
43
48
|
print("🧑💻 Launching layout using Windows Terminal...")
|
|
@@ -63,4 +68,7 @@ def handle_layout_args(args: "FireJobArgs") -> None:
|
|
|
63
68
|
choice_file = PathExtended(choice_file)
|
|
64
69
|
else:
|
|
65
70
|
choice_file = path_obj
|
|
66
|
-
|
|
71
|
+
if args.function is None: layouts_name = None
|
|
72
|
+
else: layouts_name = args.function.split(",")
|
|
73
|
+
for a_layout_config in select_layout(layouts_json_file=choice_file, layouts_name=layouts_name):
|
|
74
|
+
launch_layout(layout_config=a_layout_config)
|
|
@@ -2,9 +2,7 @@ from typing import Any, Callable, Optional
|
|
|
2
2
|
import inspect
|
|
3
3
|
import os
|
|
4
4
|
|
|
5
|
-
# import argparse
|
|
6
5
|
from machineconfig.utils.path_extended import PathExtended as PathExtended
|
|
7
|
-
# from machineconfig.utils.utils import choose_ssh_host
|
|
8
6
|
|
|
9
7
|
|
|
10
8
|
def search_for_files_of_interest(path_obj: PathExtended):
|
|
@@ -8,80 +8,13 @@ in the event that username@github.com is not mentioned in the remote url.
|
|
|
8
8
|
from machineconfig.utils.io import read_ini
|
|
9
9
|
from machineconfig.utils.source_of_truth import CONFIG_PATH, DEFAULTS_PATH
|
|
10
10
|
from machineconfig.utils.path_extended import PathExtended as PathExtended
|
|
11
|
-
from machineconfig.utils.accessories import randstr
|
|
12
|
-
from machineconfig.scripts.python.repos_helper_update import update_repository
|
|
13
11
|
from machineconfig.scripts.python.repos_helper_record import main as record_repos
|
|
14
12
|
from machineconfig.scripts.python.repos_helper_clone import clone_repos
|
|
13
|
+
from machineconfig.scripts.python.repos_helper_action import perform_git_operations
|
|
15
14
|
|
|
16
15
|
import typer
|
|
17
|
-
from enum import Enum
|
|
18
16
|
from typing import Annotated, Optional
|
|
19
17
|
|
|
20
|
-
from rich import print as pprint
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
class GitAction(Enum):
|
|
24
|
-
commit = "commit"
|
|
25
|
-
push = "push"
|
|
26
|
-
pull = "pull"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def git_action(path: PathExtended, action: GitAction, mess: Optional[str] = None, r: bool = False, auto_sync: bool = True) -> bool:
|
|
30
|
-
"""Perform git actions using Python instead of shell scripts. Returns True if successful."""
|
|
31
|
-
from git.exc import InvalidGitRepositoryError
|
|
32
|
-
from git.repo import Repo
|
|
33
|
-
|
|
34
|
-
try:
|
|
35
|
-
repo = Repo(str(path), search_parent_directories=False)
|
|
36
|
-
except InvalidGitRepositoryError:
|
|
37
|
-
pprint(f"⚠️ Skipping {path} because it is not a git repository.")
|
|
38
|
-
if r:
|
|
39
|
-
results = [git_action(path=sub_path, action=action, mess=mess, r=r, auto_sync=auto_sync) for sub_path in path.search()]
|
|
40
|
-
return all(results) # Return True only if all recursive operations succeeded
|
|
41
|
-
else:
|
|
42
|
-
return False
|
|
43
|
-
|
|
44
|
-
print(f">>>>>>>>> 🔧{action} - {path}")
|
|
45
|
-
|
|
46
|
-
try:
|
|
47
|
-
if action == GitAction.commit:
|
|
48
|
-
if mess is None:
|
|
49
|
-
mess = "auto_commit_" + randstr()
|
|
50
|
-
|
|
51
|
-
# Check if there are changes to commit
|
|
52
|
-
if repo.is_dirty() or repo.untracked_files:
|
|
53
|
-
repo.git.add(A=True) # Stage all changes
|
|
54
|
-
repo.index.commit(mess)
|
|
55
|
-
print(f"✅ Committed changes with message: {mess}")
|
|
56
|
-
return True
|
|
57
|
-
else:
|
|
58
|
-
print("ℹ️ No changes to commit")
|
|
59
|
-
return True
|
|
60
|
-
|
|
61
|
-
elif action == GitAction.push:
|
|
62
|
-
success = True
|
|
63
|
-
for remote in repo.remotes:
|
|
64
|
-
try:
|
|
65
|
-
print(f"🚀 Pushing to {remote.url}")
|
|
66
|
-
remote.push(repo.active_branch.name)
|
|
67
|
-
print(f"✅ Pushed to {remote.name}")
|
|
68
|
-
except Exception as e:
|
|
69
|
-
print(f"❌ Failed to push to {remote.name}: {e}")
|
|
70
|
-
success = False
|
|
71
|
-
return success
|
|
72
|
-
|
|
73
|
-
elif action == GitAction.pull:
|
|
74
|
-
# Use the enhanced update function with uv sync support
|
|
75
|
-
update_repository(repo, auto_sync=auto_sync, allow_password_prompt=False)
|
|
76
|
-
print("✅ Pull completed")
|
|
77
|
-
return True
|
|
78
|
-
|
|
79
|
-
except Exception as e:
|
|
80
|
-
print(f"❌ Error performing {action} on {path}: {e}")
|
|
81
|
-
return False
|
|
82
|
-
|
|
83
|
-
return True
|
|
84
|
-
|
|
85
18
|
|
|
86
19
|
def main(
|
|
87
20
|
directory: Annotated[str, typer.Argument(help="📁 Folder containing repos to record or a specs JSON file to follow.")] = "",
|
|
@@ -105,9 +38,7 @@ def main(
|
|
|
105
38
|
repos_root = PathExtended.home().joinpath("code") # it is a positional argument, can never be empty.
|
|
106
39
|
else:
|
|
107
40
|
repos_root = PathExtended(directory).expanduser().absolute()
|
|
108
|
-
|
|
109
41
|
auto_sync = not no_sync # Enable auto sync by default, disable with --no-sync
|
|
110
|
-
|
|
111
42
|
if record:
|
|
112
43
|
save_path = record_repos(repos_root=repos_root)
|
|
113
44
|
if cloud is not None:
|
|
@@ -115,7 +46,6 @@ def main(
|
|
|
115
46
|
|
|
116
47
|
elif clone or checkout or checkout_to_branch:
|
|
117
48
|
print("\n📥 Cloning or checking out repositories...")
|
|
118
|
-
print(">>>>>>>>> Cloning Repos")
|
|
119
49
|
if not repos_root.exists() or repos_root.name != "repos.json":
|
|
120
50
|
repos_root = PathExtended(CONFIG_PATH).joinpath("repos").joinpath(repos_root.rel2home()).joinpath("repos.json")
|
|
121
51
|
if not repos_root.exists():
|
|
@@ -130,23 +60,15 @@ def main(
|
|
|
130
60
|
clone_repos(spec_path=repos_root, preferred_remote=None, checkout_branch_flag=checkout_to_branch, checkout_commit_flag=checkout)
|
|
131
61
|
|
|
132
62
|
elif all or commit or pull or push:
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if push or all:
|
|
143
|
-
path_success = git_action(a_path, action=GitAction.push, r=recursive, auto_sync=auto_sync) and path_success
|
|
144
|
-
overall_success = overall_success and path_success
|
|
145
|
-
|
|
146
|
-
if overall_success:
|
|
147
|
-
print("✅ All git operations completed successfully")
|
|
148
|
-
else:
|
|
149
|
-
print("⚠️ Some git operations encountered issues")
|
|
63
|
+
# Use the new helper function for git operations
|
|
64
|
+
perform_git_operations(
|
|
65
|
+
repos_root=repos_root,
|
|
66
|
+
pull=pull or all,
|
|
67
|
+
commit=commit or all,
|
|
68
|
+
push=push or all,
|
|
69
|
+
recursive=recursive,
|
|
70
|
+
auto_sync=auto_sync
|
|
71
|
+
)
|
|
150
72
|
else:
|
|
151
73
|
print("❌ No action specified. Try passing --push, --pull, --commit, or --all.")
|
|
152
74
|
|