|
6 | 6 | import sys |
7 | 7 |
|
8 | 8 | from .commands.generate import run_generate |
| 9 | +from .commands.migrate import run_migrate |
9 | 10 | from .output import output |
10 | 11 |
|
11 | 12 |
|
@@ -47,45 +48,91 @@ def create_cli() -> argparse.ArgumentParser: |
47 | 48 | generate_cmd.add_argument("--json", action="store_true") |
48 | 49 | generate_cmd.add_argument("-o", "--output-dir") |
49 | 50 |
|
| 51 | + migrate_cmd = sub.add_parser("migrate", help="Migrate Tinybird .datasource/.pipe files to Python resources") |
| 52 | + migrate_cmd.add_argument("patterns", nargs="+", help="Files, directories, or glob patterns to migrate") |
| 53 | + migrate_cmd.add_argument("--cwd", help="Working directory to resolve patterns from") |
| 54 | + migrate_cmd.add_argument("-o", "--out", help="Output file path for the generated migration module") |
| 55 | + migrate_cmd.add_argument("--dry-run", action="store_true", help="Generate output without writing files") |
| 56 | + migrate_cmd.add_argument("--force", action="store_true", help="Overwrite existing output file when needed") |
| 57 | + migrate_cmd.add_argument( |
| 58 | + "--strict", |
| 59 | + action=argparse.BooleanOptionalAction, |
| 60 | + default=True, |
| 61 | + help="Fail on migration issues (disable with --no-strict)", |
| 62 | + ) |
| 63 | + migrate_cmd.add_argument("--json", action="store_true", help="Print migration result as JSON") |
| 64 | + |
50 | 65 | return parser |
51 | 66 |
|
52 | 67 |
|
53 | 68 | def main(argv: list[str] | None = None) -> int: |
54 | 69 | normalized_argv = list(argv) if argv is not None else list(sys.argv[1:]) |
55 | 70 |
|
56 | | - # `generate` is owned by the SDK; all other commands are delegated to Tinybird CLI. |
57 | | - if not normalized_argv or normalized_argv[0] != "generate": |
| 71 | + # SDK-owned commands stay local; all other commands are delegated to Tinybird CLI. |
| 72 | + if not normalized_argv or normalized_argv[0] not in {"generate", "migrate"}: |
58 | 73 | return _run_installed_tinybird_cli(normalized_argv) |
59 | 74 |
|
60 | 75 | parser = create_cli() |
61 | 76 | args = parser.parse_args(normalized_argv) |
62 | 77 |
|
63 | | - result = run_generate({"output_dir": args.output_dir}) |
64 | | - if not result.success: |
65 | | - output.error(result.error or "Generate failed") |
66 | | - return 1 |
| 78 | + if args.command == "generate": |
| 79 | + result = run_generate({"output_dir": args.output_dir}) |
| 80 | + if not result.success: |
| 81 | + output.error(result.error or "Generate failed") |
| 82 | + return 1 |
| 83 | + |
| 84 | + if args.json: |
| 85 | + _print_json(asdict(result)) |
| 86 | + return 0 |
| 87 | + |
| 88 | + stats = result.stats or { |
| 89 | + "datasource_count": 0, |
| 90 | + "pipe_count": 0, |
| 91 | + "connection_count": 0, |
| 92 | + "total_count": 0, |
| 93 | + } |
| 94 | + print( |
| 95 | + "Generated " |
| 96 | + f"{stats['total_count']} resources " |
| 97 | + f"({stats['datasource_count']} datasources, " |
| 98 | + f"{stats['pipe_count']} pipes, " |
| 99 | + f"{stats['connection_count']} connections)" |
| 100 | + ) |
| 101 | + if result.output_dir: |
| 102 | + print(f"Written to: {result.output_dir}") |
| 103 | + print(f"Completed in {output.format_duration(result.duration_ms)}") |
| 104 | + return 0 |
| 105 | + |
| 106 | + result = run_migrate( |
| 107 | + { |
| 108 | + "cwd": args.cwd, |
| 109 | + "patterns": args.patterns, |
| 110 | + "out": args.out, |
| 111 | + "strict": args.strict, |
| 112 | + "dry_run": args.dry_run, |
| 113 | + "force": args.force, |
| 114 | + } |
| 115 | + ) |
67 | 116 |
|
68 | 117 | if args.json: |
69 | | - _print_json(asdict(result)) |
| 118 | + _print_json(result) |
| 119 | + return 0 if result["success"] else 1 |
| 120 | + |
| 121 | + if result["success"]: |
| 122 | + migrated_count = len(result.get("migrated") or []) |
| 123 | + print(f"Migrated {migrated_count} resources") |
| 124 | + if result.get("output_path"): |
| 125 | + print(f"Written to: {result['output_path']}") |
70 | 126 | return 0 |
71 | 127 |
|
72 | | - stats = result.stats or { |
73 | | - "datasource_count": 0, |
74 | | - "pipe_count": 0, |
75 | | - "connection_count": 0, |
76 | | - "total_count": 0, |
77 | | - } |
78 | | - print( |
79 | | - "Generated " |
80 | | - f"{stats['total_count']} resources " |
81 | | - f"({stats['datasource_count']} datasources, " |
82 | | - f"{stats['pipe_count']} pipes, " |
83 | | - f"{stats['connection_count']} connections)" |
84 | | - ) |
85 | | - if result.output_dir: |
86 | | - print(f"Written to: {result.output_dir}") |
87 | | - print(f"Completed in {output.format_duration(result.duration_ms)}") |
88 | | - return 0 |
| 128 | + errors = result.get("errors") or [] |
| 129 | + if errors: |
| 130 | + output.error(f"Migrate failed with {len(errors)} error(s)") |
| 131 | + for error in errors: |
| 132 | + output.error(str(error)) |
| 133 | + else: |
| 134 | + output.error("Migrate failed") |
| 135 | + return 1 |
89 | 136 |
|
90 | 137 |
|
91 | 138 | if __name__ == "__main__": |
|
0 commit comments