|
1 | 1 | import argparse |
2 | | -from pathlib import Path |
| 2 | +import json |
| 3 | +import subprocess |
3 | 4 | import sys |
| 5 | +from pathlib import Path |
4 | 6 |
|
5 | 7 | if not getattr(sys, 'frozen', False) and __package__ is None: |
6 | 8 | sys.path.insert(0, str(Path(__file__).resolve().parents[2])) |
7 | 9 |
|
8 | 10 | from src.utils.log import Log |
| 11 | +from src.utils.const import AppPath, Key |
| 12 | +from src.extend.auto_linux_plan import create_crontab_task, delete_crontab_task |
9 | 13 | from src.runner.executor import run_task_by_id |
10 | 14 |
|
11 | | - |
12 | 15 | def main(argv: list[str] | None = None) -> int: |
13 | 16 | parser = argparse.ArgumentParser(description="Auto-Clock Runner") |
14 | | - parser.add_argument("--task_id", required=True, help="Task ID") |
15 | | - parser.add_argument("--headless", action="store_true", help="Run in headless mode") |
| 17 | + subparsers = parser.add_subparsers(dest="command") |
| 18 | + |
| 19 | + run_parser = subparsers.add_parser("run", help="Run a task by task_id") |
| 20 | + run_parser.add_argument("--task_id", required=True, help="Task ID") |
| 21 | + run_parser.add_argument("--headless", action="store_true", help="Run in headless mode") |
| 22 | + |
| 23 | + cron_create_parser = subparsers.add_parser("cron_create", help="Create a Linux crontab entry for a task") |
| 24 | + cron_create_parser.add_argument("--task_json_path", required=True, help="Path to task json file on Linux") |
| 25 | + |
| 26 | + cron_delete_parser = subparsers.add_parser("cron_delete", help="Delete a Linux crontab entry by task name") |
| 27 | + cron_delete_parser.add_argument("--task_name", required=True, help="System plan name") |
| 28 | + |
| 29 | + set_current_parser = subparsers.add_parser("set_current", help="Set servers/current to a version directory") |
| 30 | + set_current_parser.add_argument("--version", required=True, help="Version string") |
| 31 | + set_current_parser.add_argument( |
| 32 | + "--servers_root", |
| 33 | + default=str(Path(AppPath.AppRoot) / "servers"), |
| 34 | + help="Servers root directory (default: ~/.local/share/auto-clock/servers)", |
| 35 | + ) |
16 | 36 |
|
17 | 37 | args = parser.parse_args(argv) |
18 | 38 |
|
| 39 | + # Backward compatible flags: auto-clock-runner --task_id=xxx [--headless] |
| 40 | + if args.command is None: |
| 41 | + legacy_parser = argparse.ArgumentParser(add_help=False) |
| 42 | + legacy_parser.add_argument("--task_id") |
| 43 | + legacy_parser.add_argument("--headless", action="store_true") |
| 44 | + legacy_args, _ = legacy_parser.parse_known_args(argv) |
| 45 | + if legacy_args.task_id: |
| 46 | + args.command = "run" |
| 47 | + args.task_id = legacy_args.task_id |
| 48 | + args.headless = legacy_args.headless |
| 49 | + else: |
| 50 | + parser.print_help() |
| 51 | + return 1 |
| 52 | + |
19 | 53 | Log.open() |
20 | 54 | try: |
21 | | - ok, error = run_task_by_id(task_id=args.task_id, headless=args.headless) |
22 | | - if ok: |
| 55 | + if args.command == "run": |
| 56 | + ok, error = run_task_by_id(task_id=args.task_id, headless=args.headless) |
| 57 | + if ok: |
| 58 | + return 0 |
| 59 | + return 2 |
| 60 | + |
| 61 | + if args.command == "cron_create": |
| 62 | + task_path = Path(args.task_json_path) |
| 63 | + if not task_path.exists(): |
| 64 | + Log.error(f"Task json not found: {task_path}") |
| 65 | + return 1 |
| 66 | + task = json.loads(task_path.read_text(encoding="utf-8")) |
| 67 | + ok, error = create_crontab_task(task) |
| 68 | + if ok: |
| 69 | + return 0 |
| 70 | + Log.error(error or "Create crontab task failed") |
| 71 | + return 2 |
| 72 | + |
| 73 | + if args.command == "cron_delete": |
| 74 | + ok, error = delete_crontab_task(args.task_name) |
| 75 | + if ok: |
| 76 | + return 0 |
| 77 | + Log.error(error or "Delete crontab task failed") |
| 78 | + return 2 |
| 79 | + |
| 80 | + if args.command == "set_current": |
| 81 | + servers_root = Path(args.servers_root).expanduser().resolve() |
| 82 | + target_dir = (servers_root / args.version).resolve() |
| 83 | + link_path = servers_root / "current" |
| 84 | + servers_root.mkdir(parents=True, exist_ok=True) |
| 85 | + if not target_dir.exists(): |
| 86 | + Log.error(f"Version directory not found: {target_dir}") |
| 87 | + return 1 |
| 88 | + # Use ln -sfn to update atomically |
| 89 | + result = subprocess.run(["ln", "-sfn", str(target_dir), str(link_path)], capture_output=True, text=True) |
| 90 | + if result.returncode != 0: |
| 91 | + Log.error(result.stderr.strip() or f"ln failed with code {result.returncode}") |
| 92 | + return 2 |
23 | 93 | return 0 |
24 | | - return 2 |
| 94 | + |
| 95 | + Log.error(f"Unknown command: {args.command}") |
| 96 | + return 1 |
25 | 97 | except Exception as e: |
26 | 98 | Log.error(str(e)) |
27 | 99 | return 1 |
|
0 commit comments