diff --git a/.github/workflows/sync-dev.yml b/.github/workflows/sync-dev.yml index 6cf29db..afbf493 100644 --- a/.github/workflows/sync-dev.yml +++ b/.github/workflows/sync-dev.yml @@ -16,11 +16,19 @@ jobs: wx_branch: "3.2" release_tag: "wx-3.2-latest" always_build: false + mode: full - name: dev wx_branch: "master" release_tag: "wx-dev-latest" always_build: true + mode: full + + - name: interface + wx_branch: "master" + release_tag: "latest-interface" + always_build: true + mode: interface steps: - name: Get upstream version @@ -60,24 +68,35 @@ jobs: python-version: '3.x' - name: Clone wxWidgets (shallow + submodules) - if: steps.check.outputs.skip != 'true' + if: steps.check.outputs.skip != 'true' && matrix.mode == 'full' run: | git clone --depth 1 --recurse-submodules --shallow-submodules \ -b ${{ matrix.wx_branch }} \ https://github.com/wxWidgets/wxWidgets.git /tmp/wxWidgets + - name: Clone wxWidgets (shallow, no submodules) + if: steps.check.outputs.skip != 'true' && matrix.mode == 'interface' + run: | + git clone --depth 1 \ + -b ${{ matrix.wx_branch }} \ + https://github.com/wxWidgets/wxWidgets.git /tmp/wxWidgets + - name: Run sync script - if: steps.check.outputs.skip != 'true' + if: steps.check.outputs.skip != 'true' && matrix.mode == 'full' run: python maintain/sync_wxwidgets.py --source /tmp/wxWidgets --dest . + - name: Run sync script (interface only) + if: steps.check.outputs.skip != 'true' && matrix.mode == 'interface' + run: python maintain/sync_wxwidgets.py --source /tmp/wxWidgets --dest . --interface-only + - name: Install build dependencies - if: steps.check.outputs.skip != 'true' + if: steps.check.outputs.skip != 'true' && matrix.mode == 'full' run: | sudo apt-get update sudo apt-get install -y libgtk-3-dev libgl1-mesa-dev - name: Configure wxWidgets - if: steps.check.outputs.skip != 'true' + if: steps.check.outputs.skip != 'true' && matrix.mode == 'full' run: | cmake -B /tmp/wxbuild -S . -G Ninja \ -DwxBUILD_SHARED=OFF \ @@ -87,7 +106,7 @@ jobs: -DCMAKE_BUILD_TYPE=Release - name: Build wxWidgets core - if: steps.check.outputs.skip != 'true' + if: steps.check.outputs.skip != 'true' && matrix.mode == 'full' run: ninja -C /tmp/wxbuild wxbase wxcore - name: Get current date @@ -96,13 +115,18 @@ jobs: run: echo "today=$(date +%Y-%m-%d)" >> "$GITHUB_OUTPUT" - name: Create source archive - if: steps.check.outputs.skip != 'true' + if: steps.check.outputs.skip != 'true' && matrix.mode == 'full' run: | tar -cJf /tmp/kwxFetch-source.tar.xz \ CMakeLists.txt setup.h.in version-script.in \ wx-config-inplace.in wx-config.in \ 3rdparty/ art/ build/ include/ src/ utils/ + - name: Create interface archive + if: steps.check.outputs.skip != 'true' && matrix.mode == 'interface' + run: | + tar -cJf /tmp/kwxFetch-source.tar.xz interface/ + - name: Publish release if: steps.check.outputs.skip != 'true' env: diff --git a/maintain/sync_wxwidgets.py b/maintain/sync_wxwidgets.py index beddae1..c7f73ff 100644 --- a/maintain/sync_wxwidgets.py +++ b/maintain/sync_wxwidgets.py @@ -319,6 +319,81 @@ def sync_files(source: Path, dest: Path, dry_run: bool = False, verbose: bool = return stats +def sync_interface_only(source: Path, dest: Path, dry_run: bool = False, + verbose: bool = False) -> dict: + """ + Sync only the interface directory from source to destination. + + No filtering rules are applied — everything under interface/ is copied as-is. + """ + stats = {"added": 0, "updated": 0, "skipped": 0, "unchanged": 0} + changes = {"added": [], "updated": []} + + source = source.resolve() + dest = dest.resolve() + + interface_src = source / "interface" + if not interface_src.exists(): + print(f"Error: interface directory not found: {interface_src}", file=sys.stderr) + sys.exit(1) + + print(f"Syncing interface from: {interface_src}") + print(f"Syncing to: {dest / 'interface'}") + print(f"Dry run: {dry_run}") + print() + + for src_file in interface_src.rglob("*"): + if not src_file.is_file(): + continue + + rel_path = src_file.relative_to(source) + rel_path_str = normalize_path(str(rel_path)) + + dest_file = dest / rel_path + + if dest_file.exists(): + if files_are_identical(src_file, dest_file): + stats["unchanged"] += 1 + continue + stats["updated"] += 1 + changes["updated"].append(rel_path_str) + if not dry_run: + dest_file.parent.mkdir(parents=True, exist_ok=True) + dest_file.write_bytes(src_file.read_bytes()) + else: + stats["added"] += 1 + changes["added"].append(rel_path_str) + if not dry_run: + dest_file.parent.mkdir(parents=True, exist_ok=True) + dest_file.write_bytes(src_file.read_bytes()) + + # Print summary + print("=" * 60) + print("Summary (interface only):") + print(f" Added: {stats['added']}") + print(f" Updated: {stats['updated']}") + print(f" Unchanged: {stats['unchanged']}") + print() + + if changes["added"]: + print("Added files:") + for f in sorted(changes["added"])[:50]: + print(f" + {f}") + if len(changes["added"]) > 50: + print(f" ... and {len(changes['added']) - 50} more") + print() + + if changes["updated"]: + print("Updated files:") + for f in sorted(changes["updated"])[:50]: + print(f" ~ {f}") + if len(changes["updated"]) > 50: + print(f" ... and {len(changes['updated']) - 50} more") + print() + + return stats + + def main(): parser = argparse.ArgumentParser( description="Sync wxWidgets source to kwxFetch with filtering", @@ -333,6 +408,9 @@ def main(): # Verbose output (show skipped files) python sync_wxwidgets.py --source /tmp/wxWidgets --dest . --verbose + + # Sync only the interface directory (Doxygen headers) + python sync_wxwidgets.py --source /tmp/wxWidgets --dest . --interface-only """ ) @@ -356,13 +434,21 @@ def main(): action="store_true", help="Show skipped files" ) + parser.add_argument( + "--interface-only", + action="store_true", + help="Sync only the interface directory (no filtering, no build files)" + ) args = parser.parse_args() source = Path(args.source) dest = Path(args.dest) - sync_files(source, dest, dry_run=args.dry_run, verbose=args.verbose) + if args.interface_only: + sync_interface_only(source, dest, dry_run=args.dry_run, verbose=args.verbose) + else: + sync_files(source, dest, dry_run=args.dry_run, verbose=args.verbose) if __name__ == "__main__":