chore(repo): replace app symlink/submodule with in-repo app directory; enable committing app/Dockerfile and tooling\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

This commit is contained in:
torsten committed 2026-07-17 13:13:02 +02:00
1 parent a12270ad01
commit ae2c674b81
25 files changed
+3417 -1

No files matched your search

+143
View File
@@ -0,0 +1,143 @@
#!/usr/bin/env python3
"""CLI entry point for the Qt5→Qt6 migration pipeline.
Usage examples
--------------
# Run the Q1 pilot batch on both tracks:
python run_migration.py \\
--batch-id q1_pilot \\
--file-list ./q1_files.txt \\
--repo-root . \\
--source-root ./src
# Dry-run: show files and chunk info without migrating:
python run_migration.py --batch-id q1_pilot --file-list ./q1_files.txt --dry-run
"""
from __future__ import annotations
import argparse
import asyncio
import logging
import sys
from pathlib import Path
def _configure_logging(verbose: bool) -> None:
level = logging.DEBUG if verbose else logging.INFO
logging.basicConfig(
level=level,
format="%(asctime)s %(levelname)-8s %(name)s – %(message)s",
datefmt="%H:%M:%S",
)
def _dry_run(file_list_path: Path, source_root: Path) -> None:
"""Print file list with chunk estimates without calling any API."""
from migration_pipeline.chunker import split_semantic
from migration_pipeline.config import CHUNK_SIZE_LINES
files = _load_plain_list(file_list_path, source_root)
print(f"\nDry-run: {len(files)} files in {file_list_path.name}\n")
print(f"{'#':<4} {'File':<60} {'Lines':>6} {'Chunks':>6}")
print("-" * 82)
for i, fp in enumerate(files, 1):
p = Path(fp)
if not p.exists():
print(f"{i:<4} {fp:<60} {'NOT FOUND':>6}")
continue
code = p.read_text(errors="ignore")
lines = len(code.splitlines())
chunks = split_semantic(code, CHUNK_SIZE_LINES)
print(f"{i:<4} {str(p.name):<60} {lines:>6} {len(chunks):>6}")
print()
def _load_plain_list(list_path: Path, source_root: Path) -> list[str]:
base = source_root.resolve()
result = []
for raw in list_path.read_text().splitlines():
s = raw.strip()
if not s or s.startswith("#"):
continue
p = Path(s)
result.append(str((base / p).resolve() if not p.is_absolute() else p))
return result
def _parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Qt5→Qt6 async migration pipeline",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=__doc__,
)
parser.add_argument(
"--batch-id",
required=True,
help="Unique identifier for this batch (e.g. q1_pilot)",
)
parser.add_argument(
"--file-list",
required=True,
type=Path,
help="Path to the prioritised file list (one path per line)",
)
parser.add_argument(
"--repo-root",
default=".",
type=Path,
help="Root of the git repository (default: current directory)",
)
parser.add_argument(
"--source-root",
default=".",
type=Path,
help="Root of the C++ source tree (default: current directory)",
)
parser.add_argument(
"--dry-run",
action="store_true",
help="Print file list and chunk estimates; do not call any API",
)
parser.add_argument(
"--model",
choices=("glm", "qwen"),
default="glm",
help="Model family for API calls (default: glm)",
)
parser.add_argument(
"--verbose", "-v",
action="store_true",
help="Enable DEBUG logging",
)
return parser.parse_args()
def main() -> None:
args = _parse_args()
_configure_logging(args.verbose)
if not args.file_list.exists():
print(f"ERROR: File list not found: {args.file_list}", file=sys.stderr)
sys.exit(1)
if args.dry_run:
_dry_run(args.file_list, args.source_root.resolve())
return
from migration_pipeline.api_client import set_model_family
from migration_pipeline.orchestrator import run_batch
set_model_family(args.model)
asyncio.run(
run_batch(
batch_id=args.batch_id,
file_list_path=args.file_list,
repo_root=args.repo_root.resolve(),
source_root=args.source_root.resolve(),
)
)
if __name__ == "__main__":
main()