From c17024ba5a1b085e6ce48913b1f70d979153a87b Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 4 Oct 2025 17:22:06 +0800 Subject: [PATCH 01/17] Add .docs to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b18037c69..e3259780b 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ __Snapshots__ Example/ReferenceImages/**/*.png .claude +.docs From 64319c2878d6d9406c8d9c6cc3bad88120f6a21c Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 4 Oct 2025 17:23:59 +0800 Subject: [PATCH 02/17] Add DocC GitHub Pages documentation script - Generates symbol graphs and builds documentation using docc - --preview: Local preview server with configurable port - --port: Specify preview server port (default: 8000) - --clean: Force rebuild of symbol graphs - --minimum-access-level: Control symbol visibility (public/internal/private) - --target: Specify module to document - Automatic port conflict detection with user prompt - Reuses existing build artifacts for fast preview iterations - GitHub Pages deployment via gh-pages branch --- Scripts/update-gh-pages-documentation.sh | 376 +++++++++++++++++++++++ 1 file changed, 376 insertions(+) create mode 100755 Scripts/update-gh-pages-documentation.sh diff --git a/Scripts/update-gh-pages-documentation.sh b/Scripts/update-gh-pages-documentation.sh new file mode 100755 index 000000000..4fdc3b718 --- /dev/null +++ b/Scripts/update-gh-pages-documentation.sh @@ -0,0 +1,376 @@ +#!/bin/bash + +##===----------------------------------------------------------------------===## +## +## This source file is part of the OpenSwiftUI open source project +## +## Copyright (c) 2025 the OpenSwiftUI project authors +## Licensed under Apache License v2.0 +## +## See LICENSE.txt for license information +## +## SPDX-License-Identifier: Apache-2.0 +## +##===----------------------------------------------------------------------===## + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +DOCS_DIR="$REPO_ROOT/.docs" +BUILD_DIR="$DOCS_DIR/build" +SYMBOL_GRAPH_DIR="$BUILD_DIR/symbol-graphs" +DOCC_OUTPUT_DIR="$BUILD_DIR/docc-output" + +# Default configuration +PREVIEW_MODE=false +MINIMUM_ACCESS_LEVEL="public" +TARGET_NAME="OpenSwiftUI" +HOSTING_BASE_PATH="" +CLEAN_BUILD=false +PREVIEW_PORT=8000 + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +usage() { + cat << EOF +Usage: $(basename "$0") [OPTIONS] + +Build and publish Swift documentation to GitHub Pages using DocC. + +OPTIONS: + --preview Preview documentation locally instead of publishing + --minimum-access-level Set minimum access level (public, internal, private) + Default: public + --target TARGET Target to document (default: OpenSwiftUI) + --hosting-base-path PATH Base path for hosting (e.g., /OpenSwiftUI) + --port PORT Port for preview server (default: 8000) + --clean Clean build artifacts and force rebuild + -h, --help Show this help message + +EXAMPLES: + # Build and publish to GitHub Pages + $(basename "$0") + + # Preview documentation locally + $(basename "$0") --preview + + # Include internal symbols + $(basename "$0") --minimum-access-level internal --preview + + # Document a specific target + $(basename "$0") --target OpenSwiftUICore --preview + +EOF + exit 0 +} + +log_info() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Function to run docc command +rundocc() { + if command -v xcrun >/dev/null 2>&1; then + xcrun docc "$@" + else + docc "$@" + fi +} + +# Parse command line arguments +while [[ $# -gt 0 ]]; do + case $1 in + --preview) + PREVIEW_MODE=true + shift + ;; + --minimum-access-level) + MINIMUM_ACCESS_LEVEL="$2" + shift 2 + ;; + --target) + TARGET_NAME="$2" + shift 2 + ;; + --hosting-base-path) + HOSTING_BASE_PATH="$2" + shift 2 + ;; + --port) + PREVIEW_PORT="$2" + shift 2 + ;; + --clean) + CLEAN_BUILD=true + shift + ;; + -h|--help) + usage + ;; + *) + log_error "Unknown option: $1" + usage + ;; + esac +done + +# Validate minimum access level +case "$MINIMUM_ACCESS_LEVEL" in + public|internal|private|fileprivate) + ;; + *) + log_error "Invalid minimum access level: $MINIMUM_ACCESS_LEVEL" + log_error "Valid values: public, internal, private, fileprivate" + exit 1 + ;; +esac + +log_info "Configuration:" +log_info " Target: $TARGET_NAME" +log_info " Minimum Access Level: $MINIMUM_ACCESS_LEVEL" +log_info " Preview Mode: $PREVIEW_MODE" +if [[ -n "$HOSTING_BASE_PATH" ]]; then + log_info " Hosting Base Path: $HOSTING_BASE_PATH" +fi + +# Check for required tools +command -v swift >/dev/null 2>&1 || { + log_error "swift is required but not installed. Aborting." + exit 1 +} + +# Check for docc +if ! command -v docc >/dev/null 2>&1 && ! command -v xcrun >/dev/null 2>&1; then + log_error "docc is required but not found. Please install Swift-DocC." + exit 1 +fi + +# Clean build if requested +if [[ "$CLEAN_BUILD" == true ]]; then + log_info "Cleaning build artifacts..." + swift package clean + rm -rf "$DOCS_DIR" +fi + +# Create build directories +log_info "Preparing build directories..." +mkdir -p "$SYMBOL_GRAPH_DIR" +mkdir -p "$DOCC_OUTPUT_DIR" + +# Step 1: Generate symbol graphs +cd "$REPO_ROOT" + +# Use default .build directory for symbol graphs (reuses existing build) +SWIFT_BUILD_DIR=".build" +DEFAULT_SYMBOL_GRAPH_DIR="$SWIFT_BUILD_DIR/symbol-graphs" + +# Check if symbol graphs already exist with correct access level +REBUILD_NEEDED=false +if [[ ! -d "$DEFAULT_SYMBOL_GRAPH_DIR" ]] || [[ -z "$(ls -A "$DEFAULT_SYMBOL_GRAPH_DIR" 2>/dev/null)" ]]; then + REBUILD_NEEDED=true + log_info "No existing symbol graphs found, building..." +else + log_info "Found existing symbol graphs, reusing them (use --clean to rebuild)" +fi + +if [[ "$REBUILD_NEEDED" == true ]] || [[ "$CLEAN_BUILD" == true ]]; then + log_info "Generating symbol graphs..." + swift build \ + -Xswiftc -emit-symbol-graph \ + -Xswiftc -emit-symbol-graph-dir \ + -Xswiftc "$DEFAULT_SYMBOL_GRAPH_DIR" \ + -Xswiftc -symbol-graph-minimum-access-level \ + -Xswiftc "$MINIMUM_ACCESS_LEVEL" + + if [[ ! -d "$DEFAULT_SYMBOL_GRAPH_DIR" ]] || [[ -z "$(ls -A "$DEFAULT_SYMBOL_GRAPH_DIR")" ]]; then + log_error "Symbol graph generation failed or produced no output" + exit 1 + fi +fi + +# Filter symbol graphs for the target module +log_info "Filtering symbol graphs for $TARGET_NAME..." +if ls "$DEFAULT_SYMBOL_GRAPH_DIR/${TARGET_NAME}"*.symbols.json >/dev/null 2>&1; then + cp "$DEFAULT_SYMBOL_GRAPH_DIR/${TARGET_NAME}"*.symbols.json "$SYMBOL_GRAPH_DIR/" + log_info "Symbol graphs for $TARGET_NAME copied successfully" +else + log_warning "No symbol graphs found for $TARGET_NAME, using all available symbol graphs" + cp "$DEFAULT_SYMBOL_GRAPH_DIR"/*.symbols.json "$SYMBOL_GRAPH_DIR/" +fi + +# Step 2: Find or create documentation catalog +DOCC_CATALOG="" +if [[ -d "Sources/$TARGET_NAME/${TARGET_NAME}.docc" ]]; then + DOCC_CATALOG="Sources/$TARGET_NAME/${TARGET_NAME}.docc" + log_info "Using documentation catalog: $DOCC_CATALOG" +else + log_warning "No .docc catalog found for $TARGET_NAME" + log_info "DocC will generate documentation from symbol graphs only" +fi + +# Step 3: Build documentation +log_info "Building documentation archive..." + +if [[ -n "$DOCC_CATALOG" ]]; then + # We have a .docc catalog + DOCC_ARGS=( + "$DOCC_CATALOG" + --output-path "$DOCC_OUTPUT_DIR" + --emit-digest + --transform-for-static-hosting + ) + + if [[ -n "$HOSTING_BASE_PATH" ]]; then + DOCC_ARGS+=(--hosting-base-path "$HOSTING_BASE_PATH") + fi + + # Add symbol graph directory if we have symbol graphs + if [[ -d "$SYMBOL_GRAPH_DIR" ]] && [[ -n "$(ls -A "$SYMBOL_GRAPH_DIR")" ]]; then + DOCC_ARGS+=(--additional-symbol-graph-dir "$SYMBOL_GRAPH_DIR") + fi + + rundocc convert "${DOCC_ARGS[@]}" +else + # No .docc catalog, create one from symbol graphs + TEMP_DOCC_CATALOG="$BUILD_DIR/${TARGET_NAME}.docc" + mkdir -p "$TEMP_DOCC_CATALOG" + + # Copy symbol graphs into the catalog + if [[ -d "$SYMBOL_GRAPH_DIR" ]] && [[ -n "$(ls -A "$SYMBOL_GRAPH_DIR")" ]]; then + cp "$SYMBOL_GRAPH_DIR"/*.symbols.json "$TEMP_DOCC_CATALOG/" + fi + + DOCC_ARGS=( + "$TEMP_DOCC_CATALOG" + --output-path "$DOCC_OUTPUT_DIR" + --emit-digest + --transform-for-static-hosting + ) + + if [[ -n "$HOSTING_BASE_PATH" ]]; then + DOCC_ARGS+=(--hosting-base-path "$HOSTING_BASE_PATH") + fi + + rundocc convert "${DOCC_ARGS[@]}" +fi + +log_info "Documentation built successfully" + +# Step 4: Preview or publish +if [[ "$PREVIEW_MODE" == true ]]; then + # Check if port is already in use + if lsof -Pi :$PREVIEW_PORT -sTCP:LISTEN -t >/dev/null 2>&1; then + log_warning "Port $PREVIEW_PORT is already in use" + + # Find the process using the port + PORT_PID=$(lsof -Pi :$PREVIEW_PORT -sTCP:LISTEN -t) + PORT_PROCESS=$(ps -p $PORT_PID -o command= 2>/dev/null || echo "Unknown process") + + log_info "Process using port $PREVIEW_PORT (PID $PORT_PID): $PORT_PROCESS" + + # Ask user if they want to kill it + read -p "Do you want to kill this process and start the preview server? (y/N): " -n 1 -r + echo + + if [[ $REPLY =~ ^[Yy]$ ]]; then + log_info "Killing process $PORT_PID..." + kill $PORT_PID + sleep 1 + + # Verify it's killed + if lsof -Pi :$PREVIEW_PORT -sTCP:LISTEN -t >/dev/null 2>&1; then + log_error "Failed to kill process on port $PREVIEW_PORT" + exit 1 + fi + log_info "Process killed successfully" + else + log_error "Cannot start preview server. Please free port $PREVIEW_PORT or use --port option" + exit 1 + fi + fi + + log_info "Starting preview server on port $PREVIEW_PORT..." + log_info "Documentation will be available at: http://localhost:$PREVIEW_PORT/documentation/$TARGET_NAME" + log_info "Press Ctrl+C to stop the server" + + cd "$DOCC_OUTPUT_DIR" + python3 -m http.server $PREVIEW_PORT +else + # Prepare for GitHub Pages deployment + GH_PAGES_DIR="$DOCS_DIR/gh-pages" + + log_info "Preparing GitHub Pages deployment..." + + # Check if we're in a git repository + if ! git rev-parse --git-dir > /dev/null 2>&1; then + log_error "Not in a git repository. Cannot deploy to GitHub Pages." + exit 1 + fi + + # Store current branch + CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) + + # Check if gh-pages branch exists + if git show-ref --verify --quiet refs/heads/gh-pages; then + log_info "Using existing gh-pages branch" + git fetch origin gh-pages + git worktree add "$GH_PAGES_DIR" gh-pages || { + log_warning "Worktree already exists, removing and recreating..." + git worktree remove "$GH_PAGES_DIR" --force + git worktree add "$GH_PAGES_DIR" gh-pages + } + else + log_info "Creating new gh-pages branch" + git worktree add --detach "$GH_PAGES_DIR" + cd "$GH_PAGES_DIR" + git checkout --orphan gh-pages + git rm -rf . 2>/dev/null || true + cd "$REPO_ROOT" + fi + + # Copy documentation to gh-pages worktree + log_info "Copying documentation files..." + rsync -av --delete "$DOCC_OUTPUT_DIR/" "$GH_PAGES_DIR/" + + # Add .nojekyll to prevent GitHub Pages from processing with Jekyll + touch "$GH_PAGES_DIR/.nojekyll" + + # Commit and push + cd "$GH_PAGES_DIR" + git add -A + + if git diff --cached --quiet; then + log_info "No changes to documentation" + else + log_info "Committing documentation changes..." + git commit -m "Update documentation (generated from $CURRENT_BRANCH@$(git -C "$REPO_ROOT" rev-parse --short HEAD))" + + log_info "Pushing to gh-pages branch..." + git push origin gh-pages + + log_info "${GREEN}✓${NC} Documentation published successfully!" + log_info "GitHub Pages will be updated shortly at your repository's GitHub Pages URL" + fi + + # Cleanup + cd "$REPO_ROOT" + git worktree remove "$GH_PAGES_DIR" + + log_info "Cleaning up build artifacts..." + rm -rf "$DOCS_DIR" +fi + +log_info "Done!" From 6ce6a347144f3048e735b9f75a4fd144a394b843 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 4 Oct 2025 17:32:24 +0800 Subject: [PATCH 03/17] Split documentation scripts and add source service support - Create build-documentation.sh for building and previewing documentation - Refactor update-gh-pages-documentation.sh to focus only on GitHub Pages deployment - Add --source-service and --source-service-base-url options to enable source code links - update-gh-pages-documentation.sh now calls build-documentation.sh internally - Support --no-build option to deploy pre-built documentation --- Scripts/build-documentation.sh | 364 +++++++++++++++++++++++ Scripts/update-gh-pages-documentation.sh | 350 +++++++--------------- 2 files changed, 476 insertions(+), 238 deletions(-) create mode 100755 Scripts/build-documentation.sh diff --git a/Scripts/build-documentation.sh b/Scripts/build-documentation.sh new file mode 100755 index 000000000..f950a1d40 --- /dev/null +++ b/Scripts/build-documentation.sh @@ -0,0 +1,364 @@ +#!/bin/bash + +##===----------------------------------------------------------------------===## +## +## This source file is part of the OpenSwiftUI open source project +## +## Copyright (c) 2025 the OpenSwiftUI project authors +## Licensed under Apache License v2.0 +## +## See LICENSE.txt for license information +## +## SPDX-License-Identifier: Apache-2.0 +## +##===----------------------------------------------------------------------===## + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +DOCS_DIR="$REPO_ROOT/.docs" +BUILD_DIR="$DOCS_DIR/build" +SYMBOL_GRAPH_DIR="$BUILD_DIR/symbol-graphs" +DOCC_OUTPUT_DIR="$BUILD_DIR/docc-output" + +# Default configuration +PREVIEW_MODE=false +MINIMUM_ACCESS_LEVEL="public" +TARGET_NAME="OpenSwiftUI" +HOSTING_BASE_PATH="" +CLEAN_BUILD=false +PREVIEW_PORT=8000 +SOURCE_SERVICE="" +SOURCE_SERVICE_BASE_URL="" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +usage() { + cat << EOF +Usage: $(basename "$0") [OPTIONS] + +Build Swift documentation using DocC with optional local preview. + +OPTIONS: + --preview Preview documentation locally with HTTP server + --minimum-access-level LEVEL Set minimum access level (public, internal, private) + Default: public + --target TARGET Target to document (default: OpenSwiftUI) + --hosting-base-path PATH Base path for hosting (e.g., /OpenSwiftUI) + --port PORT Port for preview server (default: 8000) + --source-service SERVICE Source service (github, gitlab, bitbucket) + --source-service-base-url URL Base URL for source service + (e.g., https://github.com/user/repo/blob/main) + --clean Clean build artifacts and force rebuild + -h, --help Show this help message + +EXAMPLES: + # Build and preview documentation + $(basename "$0") --preview + + # Preview with internal symbols on port 8080 + $(basename "$0") --preview --minimum-access-level internal --port 8080 + + # Clean rebuild + $(basename "$0") --preview --clean + + # Build for specific target + $(basename "$0") --target OpenSwiftUICore --preview + + # Build with source links to GitHub + $(basename "$0") --preview \\ + --source-service github \\ + --source-service-base-url https://github.com/OpenSwiftUIProject/OpenSwiftUI/blob/main + +EOF + exit 0 +} + +log_info() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Function to run docc command +rundocc() { + if command -v xcrun >/dev/null 2>&1; then + xcrun docc "$@" + else + docc "$@" + fi +} + +# Parse command line arguments +while [[ $# -gt 0 ]]; do + case $1 in + --preview) + PREVIEW_MODE=true + shift + ;; + --minimum-access-level) + MINIMUM_ACCESS_LEVEL="$2" + shift 2 + ;; + --target) + TARGET_NAME="$2" + shift 2 + ;; + --hosting-base-path) + HOSTING_BASE_PATH="$2" + shift 2 + ;; + --port) + PREVIEW_PORT="$2" + shift 2 + ;; + --source-service) + SOURCE_SERVICE="$2" + shift 2 + ;; + --source-service-base-url) + SOURCE_SERVICE_BASE_URL="$2" + shift 2 + ;; + --clean) + CLEAN_BUILD=true + shift + ;; + -h|--help) + usage + ;; + *) + log_error "Unknown option: $1" + usage + ;; + esac +done + +# Validate minimum access level +case "$MINIMUM_ACCESS_LEVEL" in + public|internal|private|fileprivate) + ;; + *) + log_error "Invalid minimum access level: $MINIMUM_ACCESS_LEVEL" + log_error "Valid values: public, internal, private, fileprivate" + exit 1 + ;; +esac + +log_info "Configuration:" +log_info " Target: $TARGET_NAME" +log_info " Minimum Access Level: $MINIMUM_ACCESS_LEVEL" +log_info " Preview Mode: $PREVIEW_MODE" +if [[ "$PREVIEW_MODE" == true ]]; then + log_info " Preview Port: $PREVIEW_PORT" +fi +if [[ -n "$HOSTING_BASE_PATH" ]]; then + log_info " Hosting Base Path: $HOSTING_BASE_PATH" +fi +if [[ -n "$SOURCE_SERVICE" ]]; then + log_info " Source Service: $SOURCE_SERVICE" + log_info " Source Service Base URL: $SOURCE_SERVICE_BASE_URL" +fi + +# Validate source service configuration +if [[ -n "$SOURCE_SERVICE" ]] && [[ -z "$SOURCE_SERVICE_BASE_URL" ]]; then + log_error "--source-service requires --source-service-base-url" + exit 1 +fi + +if [[ -z "$SOURCE_SERVICE" ]] && [[ -n "$SOURCE_SERVICE_BASE_URL" ]]; then + log_error "--source-service-base-url requires --source-service" + exit 1 +fi + +# Check for required tools +command -v swift >/dev/null 2>&1 || { + log_error "swift is required but not installed. Aborting." + exit 1 +} + +# Check for docc +if ! command -v docc >/dev/null 2>&1 && ! command -v xcrun >/dev/null 2>&1; then + log_error "docc is required but not found. Please install Swift-DocC." + exit 1 +fi + +# Clean build if requested +if [[ "$CLEAN_BUILD" == true ]]; then + log_info "Cleaning build artifacts..." + swift package clean + rm -rf "$DOCS_DIR" +fi + +# Create build directories +log_info "Preparing build directories..." +mkdir -p "$SYMBOL_GRAPH_DIR" +mkdir -p "$DOCC_OUTPUT_DIR" + +# Step 1: Generate symbol graphs +cd "$REPO_ROOT" + +# Use default .build directory for symbol graphs (reuses existing build) +SWIFT_BUILD_DIR=".build" +DEFAULT_SYMBOL_GRAPH_DIR="$SWIFT_BUILD_DIR/symbol-graphs" + +# Check if symbol graphs already exist with correct access level +REBUILD_NEEDED=false +if [[ ! -d "$DEFAULT_SYMBOL_GRAPH_DIR" ]] || [[ -z "$(ls -A "$DEFAULT_SYMBOL_GRAPH_DIR" 2>/dev/null)" ]]; then + REBUILD_NEEDED=true + log_info "No existing symbol graphs found, building..." +else + log_info "Found existing symbol graphs, reusing them (use --clean to rebuild)" +fi + +if [[ "$REBUILD_NEEDED" == true ]] || [[ "$CLEAN_BUILD" == true ]]; then + log_info "Generating symbol graphs..." + swift build \ + -Xswiftc -emit-symbol-graph \ + -Xswiftc -emit-symbol-graph-dir \ + -Xswiftc "$DEFAULT_SYMBOL_GRAPH_DIR" \ + -Xswiftc -symbol-graph-minimum-access-level \ + -Xswiftc "$MINIMUM_ACCESS_LEVEL" + + if [[ ! -d "$DEFAULT_SYMBOL_GRAPH_DIR" ]] || [[ -z "$(ls -A "$DEFAULT_SYMBOL_GRAPH_DIR")" ]]; then + log_error "Symbol graph generation failed or produced no output" + exit 1 + fi +fi + +# Filter symbol graphs for the target module +log_info "Filtering symbol graphs for $TARGET_NAME..." +if ls "$DEFAULT_SYMBOL_GRAPH_DIR/${TARGET_NAME}"*.symbols.json >/dev/null 2>&1; then + cp "$DEFAULT_SYMBOL_GRAPH_DIR/${TARGET_NAME}"*.symbols.json "$SYMBOL_GRAPH_DIR/" + log_info "Symbol graphs for $TARGET_NAME copied successfully" +else + log_warning "No symbol graphs found for $TARGET_NAME, using all available symbol graphs" + cp "$DEFAULT_SYMBOL_GRAPH_DIR"/*.symbols.json "$SYMBOL_GRAPH_DIR/" +fi + +# Step 2: Find or create documentation catalog +DOCC_CATALOG="" +if [[ -d "Sources/$TARGET_NAME/${TARGET_NAME}.docc" ]]; then + DOCC_CATALOG="Sources/$TARGET_NAME/${TARGET_NAME}.docc" + log_info "Using documentation catalog: $DOCC_CATALOG" +else + log_warning "No .docc catalog found for $TARGET_NAME" + log_info "DocC will generate documentation from symbol graphs only" +fi + +# Step 3: Build documentation +log_info "Building documentation archive..." + +if [[ -n "$DOCC_CATALOG" ]]; then + # We have a .docc catalog + DOCC_ARGS=( + "$DOCC_CATALOG" + --output-path "$DOCC_OUTPUT_DIR" + --emit-digest + --transform-for-static-hosting + ) + + if [[ -n "$HOSTING_BASE_PATH" ]]; then + DOCC_ARGS+=(--hosting-base-path "$HOSTING_BASE_PATH") + fi + + # Add source service configuration + if [[ -n "$SOURCE_SERVICE" ]]; then + DOCC_ARGS+=(--source-service "$SOURCE_SERVICE") + DOCC_ARGS+=(--source-service-base-url "$SOURCE_SERVICE_BASE_URL") + DOCC_ARGS+=(--checkout-path "$REPO_ROOT") + fi + + # Add symbol graph directory if we have symbol graphs + if [[ -d "$SYMBOL_GRAPH_DIR" ]] && [[ -n "$(ls -A "$SYMBOL_GRAPH_DIR")" ]]; then + DOCC_ARGS+=(--additional-symbol-graph-dir "$SYMBOL_GRAPH_DIR") + fi + + rundocc convert "${DOCC_ARGS[@]}" +else + # No .docc catalog, create one from symbol graphs + TEMP_DOCC_CATALOG="$BUILD_DIR/${TARGET_NAME}.docc" + mkdir -p "$TEMP_DOCC_CATALOG" + + # Copy symbol graphs into the catalog + if [[ -d "$SYMBOL_GRAPH_DIR" ]] && [[ -n "$(ls -A "$SYMBOL_GRAPH_DIR")" ]]; then + cp "$SYMBOL_GRAPH_DIR"/*.symbols.json "$TEMP_DOCC_CATALOG/" + fi + + DOCC_ARGS=( + "$TEMP_DOCC_CATALOG" + --output-path "$DOCC_OUTPUT_DIR" + --emit-digest + --transform-for-static-hosting + ) + + if [[ -n "$HOSTING_BASE_PATH" ]]; then + DOCC_ARGS+=(--hosting-base-path "$HOSTING_BASE_PATH") + fi + + # Add source service configuration + if [[ -n "$SOURCE_SERVICE" ]]; then + DOCC_ARGS+=(--source-service "$SOURCE_SERVICE") + DOCC_ARGS+=(--source-service-base-url "$SOURCE_SERVICE_BASE_URL") + DOCC_ARGS+=(--checkout-path "$REPO_ROOT") + fi + + rundocc convert "${DOCC_ARGS[@]}" +fi + +log_info "Documentation built successfully" +log_info "Documentation output: $DOCC_OUTPUT_DIR" + +# Step 4: Preview if requested +if [[ "$PREVIEW_MODE" == true ]]; then + # Check if port is already in use + if lsof -Pi :$PREVIEW_PORT -sTCP:LISTEN -t >/dev/null 2>&1; then + log_warning "Port $PREVIEW_PORT is already in use" + + # Find the process using the port + PORT_PID=$(lsof -Pi :$PREVIEW_PORT -sTCP:LISTEN -t) + PORT_PROCESS=$(ps -p $PORT_PID -o command= 2>/dev/null || echo "Unknown process") + + log_info "Process using port $PREVIEW_PORT (PID $PORT_PID): $PORT_PROCESS" + + # Ask user if they want to kill it + read -p "Do you want to kill this process and start the preview server? (y/N): " -n 1 -r + echo + + if [[ $REPLY =~ ^[Yy]$ ]]; then + log_info "Killing process $PORT_PID..." + kill $PORT_PID + sleep 1 + + # Verify it's killed + if lsof -Pi :$PREVIEW_PORT -sTCP:LISTEN -t >/dev/null 2>&1; then + log_error "Failed to kill process on port $PREVIEW_PORT" + exit 1 + fi + log_info "Process killed successfully" + else + log_error "Cannot start preview server. Please free port $PREVIEW_PORT or use --port option" + exit 1 + fi + fi + + log_info "Starting preview server on port $PREVIEW_PORT..." + log_info "Documentation will be available at: http://localhost:$PREVIEW_PORT/documentation/$TARGET_NAME" + log_info "Press Ctrl+C to stop the server" + + cd "$DOCC_OUTPUT_DIR" + python3 -m http.server $PREVIEW_PORT +fi + +log_info "Done!" diff --git a/Scripts/update-gh-pages-documentation.sh b/Scripts/update-gh-pages-documentation.sh index 4fdc3b718..e96c76945 100755 --- a/Scripts/update-gh-pages-documentation.sh +++ b/Scripts/update-gh-pages-documentation.sh @@ -19,16 +19,16 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" DOCS_DIR="$REPO_ROOT/.docs" BUILD_DIR="$DOCS_DIR/build" -SYMBOL_GRAPH_DIR="$BUILD_DIR/symbol-graphs" DOCC_OUTPUT_DIR="$BUILD_DIR/docc-output" # Default configuration -PREVIEW_MODE=false +BUILD_DOCS=true MINIMUM_ACCESS_LEVEL="public" TARGET_NAME="OpenSwiftUI" HOSTING_BASE_PATH="" CLEAN_BUILD=false -PREVIEW_PORT=8000 +SOURCE_SERVICE="" +SOURCE_SERVICE_BASE_URL="" # Colors for output RED='\033[0;31m' @@ -40,30 +40,40 @@ usage() { cat << EOF Usage: $(basename "$0") [OPTIONS] -Build and publish Swift documentation to GitHub Pages using DocC. +Publish Swift documentation to GitHub Pages using DocC. + +This script will build documentation (or use existing build) and deploy it +to the gh-pages branch for GitHub Pages hosting. OPTIONS: - --preview Preview documentation locally instead of publishing - --minimum-access-level Set minimum access level (public, internal, private) - Default: public - --target TARGET Target to document (default: OpenSwiftUI) - --hosting-base-path PATH Base path for hosting (e.g., /OpenSwiftUI) - --port PORT Port for preview server (default: 8000) - --clean Clean build artifacts and force rebuild - -h, --help Show this help message + --no-build Skip building documentation (use existing output) + --minimum-access-level LEVEL Set minimum access level (public, internal, private) + Default: public + --target TARGET Target to document (default: OpenSwiftUI) + --hosting-base-path PATH Base path for hosting (e.g., /OpenSwiftUI) + --source-service SERVICE Source service (github, gitlab, bitbucket) + --source-service-base-url URL Base URL for source service + (e.g., https://github.com/user/repo/blob/main) + --clean Clean build artifacts and force rebuild + -h, --help Show this help message EXAMPLES: # Build and publish to GitHub Pages $(basename "$0") - # Preview documentation locally - $(basename "$0") --preview + # Publish using existing documentation build + $(basename "$0") --no-build - # Include internal symbols - $(basename "$0") --minimum-access-level internal --preview + # Build with internal symbols and publish + $(basename "$0") --minimum-access-level internal # Document a specific target - $(basename "$0") --target OpenSwiftUICore --preview + $(basename "$0") --target OpenSwiftUICore + + # Build and publish with source links to GitHub + $(basename "$0") \\ + --source-service github \\ + --source-service-base-url https://github.com/OpenSwiftUIProject/OpenSwiftUI/blob/main EOF exit 0 @@ -81,20 +91,11 @@ log_error() { echo -e "${RED}[ERROR]${NC} $1" } -# Function to run docc command -rundocc() { - if command -v xcrun >/dev/null 2>&1; then - xcrun docc "$@" - else - docc "$@" - fi -} - # Parse command line arguments while [[ $# -gt 0 ]]; do case $1 in - --preview) - PREVIEW_MODE=true + --no-build) + BUILD_DOCS=false shift ;; --minimum-access-level) @@ -109,8 +110,12 @@ while [[ $# -gt 0 ]]; do HOSTING_BASE_PATH="$2" shift 2 ;; - --port) - PREVIEW_PORT="$2" + --source-service) + SOURCE_SERVICE="$2" + shift 2 + ;; + --source-service-base-url) + SOURCE_SERVICE_BASE_URL="$2" shift 2 ;; --clean) @@ -127,250 +132,119 @@ while [[ $# -gt 0 ]]; do esac done -# Validate minimum access level -case "$MINIMUM_ACCESS_LEVEL" in - public|internal|private|fileprivate) - ;; - *) - log_error "Invalid minimum access level: $MINIMUM_ACCESS_LEVEL" - log_error "Valid values: public, internal, private, fileprivate" - exit 1 - ;; -esac - log_info "Configuration:" log_info " Target: $TARGET_NAME" -log_info " Minimum Access Level: $MINIMUM_ACCESS_LEVEL" -log_info " Preview Mode: $PREVIEW_MODE" +log_info " Build Documentation: $BUILD_DOCS" if [[ -n "$HOSTING_BASE_PATH" ]]; then log_info " Hosting Base Path: $HOSTING_BASE_PATH" fi # Check for required tools -command -v swift >/dev/null 2>&1 || { - log_error "swift is required but not installed. Aborting." +command -v git >/dev/null 2>&1 || { + log_error "git is required but not installed. Aborting." exit 1 } -# Check for docc -if ! command -v docc >/dev/null 2>&1 && ! command -v xcrun >/dev/null 2>&1; then - log_error "docc is required but not found. Please install Swift-DocC." - exit 1 -fi - -# Clean build if requested -if [[ "$CLEAN_BUILD" == true ]]; then - log_info "Cleaning build artifacts..." - swift package clean - rm -rf "$DOCS_DIR" -fi - -# Create build directories -log_info "Preparing build directories..." -mkdir -p "$SYMBOL_GRAPH_DIR" -mkdir -p "$DOCC_OUTPUT_DIR" +# Build documentation if requested +if [[ "$BUILD_DOCS" == true ]]; then + log_info "Building documentation..." -# Step 1: Generate symbol graphs -cd "$REPO_ROOT" - -# Use default .build directory for symbol graphs (reuses existing build) -SWIFT_BUILD_DIR=".build" -DEFAULT_SYMBOL_GRAPH_DIR="$SWIFT_BUILD_DIR/symbol-graphs" - -# Check if symbol graphs already exist with correct access level -REBUILD_NEEDED=false -if [[ ! -d "$DEFAULT_SYMBOL_GRAPH_DIR" ]] || [[ -z "$(ls -A "$DEFAULT_SYMBOL_GRAPH_DIR" 2>/dev/null)" ]]; then - REBUILD_NEEDED=true - log_info "No existing symbol graphs found, building..." -else - log_info "Found existing symbol graphs, reusing them (use --clean to rebuild)" -fi - -if [[ "$REBUILD_NEEDED" == true ]] || [[ "$CLEAN_BUILD" == true ]]; then - log_info "Generating symbol graphs..." - swift build \ - -Xswiftc -emit-symbol-graph \ - -Xswiftc -emit-symbol-graph-dir \ - -Xswiftc "$DEFAULT_SYMBOL_GRAPH_DIR" \ - -Xswiftc -symbol-graph-minimum-access-level \ - -Xswiftc "$MINIMUM_ACCESS_LEVEL" - - if [[ ! -d "$DEFAULT_SYMBOL_GRAPH_DIR" ]] || [[ -z "$(ls -A "$DEFAULT_SYMBOL_GRAPH_DIR")" ]]; then - log_error "Symbol graph generation failed or produced no output" + BUILD_SCRIPT="$SCRIPT_DIR/build-documentation.sh" + if [[ ! -f "$BUILD_SCRIPT" ]]; then + log_error "Build script not found: $BUILD_SCRIPT" exit 1 fi -fi - -# Filter symbol graphs for the target module -log_info "Filtering symbol graphs for $TARGET_NAME..." -if ls "$DEFAULT_SYMBOL_GRAPH_DIR/${TARGET_NAME}"*.symbols.json >/dev/null 2>&1; then - cp "$DEFAULT_SYMBOL_GRAPH_DIR/${TARGET_NAME}"*.symbols.json "$SYMBOL_GRAPH_DIR/" - log_info "Symbol graphs for $TARGET_NAME copied successfully" -else - log_warning "No symbol graphs found for $TARGET_NAME, using all available symbol graphs" - cp "$DEFAULT_SYMBOL_GRAPH_DIR"/*.symbols.json "$SYMBOL_GRAPH_DIR/" -fi - -# Step 2: Find or create documentation catalog -DOCC_CATALOG="" -if [[ -d "Sources/$TARGET_NAME/${TARGET_NAME}.docc" ]]; then - DOCC_CATALOG="Sources/$TARGET_NAME/${TARGET_NAME}.docc" - log_info "Using documentation catalog: $DOCC_CATALOG" -else - log_warning "No .docc catalog found for $TARGET_NAME" - log_info "DocC will generate documentation from symbol graphs only" -fi -# Step 3: Build documentation -log_info "Building documentation archive..." - -if [[ -n "$DOCC_CATALOG" ]]; then - # We have a .docc catalog - DOCC_ARGS=( - "$DOCC_CATALOG" - --output-path "$DOCC_OUTPUT_DIR" - --emit-digest - --transform-for-static-hosting - ) + BUILD_ARGS=() + BUILD_ARGS+=(--target "$TARGET_NAME") + BUILD_ARGS+=(--minimum-access-level "$MINIMUM_ACCESS_LEVEL") if [[ -n "$HOSTING_BASE_PATH" ]]; then - DOCC_ARGS+=(--hosting-base-path "$HOSTING_BASE_PATH") + BUILD_ARGS+=(--hosting-base-path "$HOSTING_BASE_PATH") fi - # Add symbol graph directory if we have symbol graphs - if [[ -d "$SYMBOL_GRAPH_DIR" ]] && [[ -n "$(ls -A "$SYMBOL_GRAPH_DIR")" ]]; then - DOCC_ARGS+=(--additional-symbol-graph-dir "$SYMBOL_GRAPH_DIR") + if [[ -n "$SOURCE_SERVICE" ]]; then + BUILD_ARGS+=(--source-service "$SOURCE_SERVICE") + BUILD_ARGS+=(--source-service-base-url "$SOURCE_SERVICE_BASE_URL") fi - rundocc convert "${DOCC_ARGS[@]}" -else - # No .docc catalog, create one from symbol graphs - TEMP_DOCC_CATALOG="$BUILD_DIR/${TARGET_NAME}.docc" - mkdir -p "$TEMP_DOCC_CATALOG" - - # Copy symbol graphs into the catalog - if [[ -d "$SYMBOL_GRAPH_DIR" ]] && [[ -n "$(ls -A "$SYMBOL_GRAPH_DIR")" ]]; then - cp "$SYMBOL_GRAPH_DIR"/*.symbols.json "$TEMP_DOCC_CATALOG/" - fi - - DOCC_ARGS=( - "$TEMP_DOCC_CATALOG" - --output-path "$DOCC_OUTPUT_DIR" - --emit-digest - --transform-for-static-hosting - ) - - if [[ -n "$HOSTING_BASE_PATH" ]]; then - DOCC_ARGS+=(--hosting-base-path "$HOSTING_BASE_PATH") + if [[ "$CLEAN_BUILD" == true ]]; then + BUILD_ARGS+=(--clean) fi - rundocc convert "${DOCC_ARGS[@]}" + "$BUILD_SCRIPT" "${BUILD_ARGS[@]}" fi -log_info "Documentation built successfully" - -# Step 4: Preview or publish -if [[ "$PREVIEW_MODE" == true ]]; then - # Check if port is already in use - if lsof -Pi :$PREVIEW_PORT -sTCP:LISTEN -t >/dev/null 2>&1; then - log_warning "Port $PREVIEW_PORT is already in use" - - # Find the process using the port - PORT_PID=$(lsof -Pi :$PREVIEW_PORT -sTCP:LISTEN -t) - PORT_PROCESS=$(ps -p $PORT_PID -o command= 2>/dev/null || echo "Unknown process") - - log_info "Process using port $PREVIEW_PORT (PID $PORT_PID): $PORT_PROCESS" - - # Ask user if they want to kill it - read -p "Do you want to kill this process and start the preview server? (y/N): " -n 1 -r - echo - - if [[ $REPLY =~ ^[Yy]$ ]]; then - log_info "Killing process $PORT_PID..." - kill $PORT_PID - sleep 1 - - # Verify it's killed - if lsof -Pi :$PREVIEW_PORT -sTCP:LISTEN -t >/dev/null 2>&1; then - log_error "Failed to kill process on port $PREVIEW_PORT" - exit 1 - fi - log_info "Process killed successfully" - else - log_error "Cannot start preview server. Please free port $PREVIEW_PORT or use --port option" - exit 1 - fi - fi +# Verify documentation output exists +if [[ ! -d "$DOCC_OUTPUT_DIR" ]] || [[ -z "$(ls -A "$DOCC_OUTPUT_DIR" 2>/dev/null)" ]]; then + log_error "Documentation output not found at: $DOCC_OUTPUT_DIR" + log_error "Please build documentation first or run without --no-build" + exit 1 +fi - log_info "Starting preview server on port $PREVIEW_PORT..." - log_info "Documentation will be available at: http://localhost:$PREVIEW_PORT/documentation/$TARGET_NAME" - log_info "Press Ctrl+C to stop the server" +log_info "Using documentation from: $DOCC_OUTPUT_DIR" - cd "$DOCC_OUTPUT_DIR" - python3 -m http.server $PREVIEW_PORT -else - # Prepare for GitHub Pages deployment - GH_PAGES_DIR="$DOCS_DIR/gh-pages" +# Deploy to GitHub Pages +GH_PAGES_DIR="$DOCS_DIR/gh-pages" - log_info "Preparing GitHub Pages deployment..." +log_info "Preparing GitHub Pages deployment..." - # Check if we're in a git repository - if ! git rev-parse --git-dir > /dev/null 2>&1; then - log_error "Not in a git repository. Cannot deploy to GitHub Pages." - exit 1 - fi +# Check if we're in a git repository +if ! git rev-parse --git-dir > /dev/null 2>&1; then + log_error "Not in a git repository. Cannot deploy to GitHub Pages." + exit 1 +fi - # Store current branch - CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) - - # Check if gh-pages branch exists - if git show-ref --verify --quiet refs/heads/gh-pages; then - log_info "Using existing gh-pages branch" - git fetch origin gh-pages - git worktree add "$GH_PAGES_DIR" gh-pages || { - log_warning "Worktree already exists, removing and recreating..." - git worktree remove "$GH_PAGES_DIR" --force - git worktree add "$GH_PAGES_DIR" gh-pages - } - else - log_info "Creating new gh-pages branch" - git worktree add --detach "$GH_PAGES_DIR" - cd "$GH_PAGES_DIR" - git checkout --orphan gh-pages - git rm -rf . 2>/dev/null || true - cd "$REPO_ROOT" - fi +# Store current branch +CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) + +# Check if gh-pages branch exists +if git show-ref --verify --quiet refs/heads/gh-pages; then + log_info "Using existing gh-pages branch" + git fetch origin gh-pages 2>/dev/null || true + git worktree add "$GH_PAGES_DIR" gh-pages || { + log_warning "Worktree already exists, removing and recreating..." + git worktree remove "$GH_PAGES_DIR" --force + git worktree add "$GH_PAGES_DIR" gh-pages + } +else + log_info "Creating new gh-pages branch" + git worktree add --detach "$GH_PAGES_DIR" + cd "$GH_PAGES_DIR" + git checkout --orphan gh-pages + git rm -rf . 2>/dev/null || true + cd "$REPO_ROOT" +fi - # Copy documentation to gh-pages worktree - log_info "Copying documentation files..." - rsync -av --delete "$DOCC_OUTPUT_DIR/" "$GH_PAGES_DIR/" +# Copy documentation to gh-pages worktree +log_info "Copying documentation files..." +rsync -av --delete "$DOCC_OUTPUT_DIR/" "$GH_PAGES_DIR/" - # Add .nojekyll to prevent GitHub Pages from processing with Jekyll - touch "$GH_PAGES_DIR/.nojekyll" +# Add .nojekyll to prevent GitHub Pages from processing with Jekyll +touch "$GH_PAGES_DIR/.nojekyll" - # Commit and push - cd "$GH_PAGES_DIR" - git add -A +# Commit and push +cd "$GH_PAGES_DIR" +git add -A - if git diff --cached --quiet; then - log_info "No changes to documentation" - else - log_info "Committing documentation changes..." - git commit -m "Update documentation (generated from $CURRENT_BRANCH@$(git -C "$REPO_ROOT" rev-parse --short HEAD))" +if git diff --cached --quiet; then + log_info "No changes to documentation" +else + log_info "Committing documentation changes..." + git commit -m "Update documentation (generated from $CURRENT_BRANCH@$(git -C "$REPO_ROOT" rev-parse --short HEAD))" - log_info "Pushing to gh-pages branch..." - git push origin gh-pages + log_info "Pushing to gh-pages branch..." + git push origin gh-pages - log_info "${GREEN}✓${NC} Documentation published successfully!" - log_info "GitHub Pages will be updated shortly at your repository's GitHub Pages URL" - fi + log_info "${GREEN}✓${NC} Documentation published successfully!" + log_info "GitHub Pages will be updated shortly at your repository's GitHub Pages URL" +fi - # Cleanup - cd "$REPO_ROOT" - git worktree remove "$GH_PAGES_DIR" +# Cleanup +cd "$REPO_ROOT" +git worktree remove "$GH_PAGES_DIR" - log_info "Cleaning up build artifacts..." - rm -rf "$DOCS_DIR" -fi +log_info "Cleaning up build artifacts..." +rm -rf "$DOCS_DIR" log_info "Done!" From 97d4d9525e02bcd90c0c6943af495f097a7ea0c5 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 4 Oct 2025 17:50:33 +0800 Subject: [PATCH 04/17] Set default source service to GitHub for OpenSwiftUI repo - Default --source-service to 'github' - Default --source-service-base-url to OpenSwiftUI main branch - Source links are now enabled by default - Can still be overridden for forks or custom branches --- Scripts/build-documentation.sh | 10 +++++----- Scripts/update-gh-pages-documentation.sh | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Scripts/build-documentation.sh b/Scripts/build-documentation.sh index f950a1d40..4bc816902 100755 --- a/Scripts/build-documentation.sh +++ b/Scripts/build-documentation.sh @@ -29,8 +29,8 @@ TARGET_NAME="OpenSwiftUI" HOSTING_BASE_PATH="" CLEAN_BUILD=false PREVIEW_PORT=8000 -SOURCE_SERVICE="" -SOURCE_SERVICE_BASE_URL="" +SOURCE_SERVICE="github" +SOURCE_SERVICE_BASE_URL="https://github.com/OpenSwiftUIProject/OpenSwiftUI/blob/main" # Colors for output RED='\033[0;31m' @@ -58,7 +58,7 @@ OPTIONS: -h, --help Show this help message EXAMPLES: - # Build and preview documentation + # Build and preview documentation (source links enabled by default) $(basename "$0") --preview # Preview with internal symbols on port 8080 @@ -70,10 +70,10 @@ EXAMPLES: # Build for specific target $(basename "$0") --target OpenSwiftUICore --preview - # Build with source links to GitHub + # Build with custom source service (e.g., for a fork) $(basename "$0") --preview \\ --source-service github \\ - --source-service-base-url https://github.com/OpenSwiftUIProject/OpenSwiftUI/blob/main + --source-service-base-url https://github.com/yourname/OpenSwiftUI/blob/custom-branch EOF exit 0 diff --git a/Scripts/update-gh-pages-documentation.sh b/Scripts/update-gh-pages-documentation.sh index e96c76945..6401822fc 100755 --- a/Scripts/update-gh-pages-documentation.sh +++ b/Scripts/update-gh-pages-documentation.sh @@ -27,8 +27,8 @@ MINIMUM_ACCESS_LEVEL="public" TARGET_NAME="OpenSwiftUI" HOSTING_BASE_PATH="" CLEAN_BUILD=false -SOURCE_SERVICE="" -SOURCE_SERVICE_BASE_URL="" +SOURCE_SERVICE="github" +SOURCE_SERVICE_BASE_URL="https://github.com/OpenSwiftUIProject/OpenSwiftUI/blob/main" # Colors for output RED='\033[0;31m' @@ -58,7 +58,7 @@ OPTIONS: -h, --help Show this help message EXAMPLES: - # Build and publish to GitHub Pages + # Build and publish to GitHub Pages (source links enabled by default) $(basename "$0") # Publish using existing documentation build @@ -70,10 +70,10 @@ EXAMPLES: # Document a specific target $(basename "$0") --target OpenSwiftUICore - # Build and publish with source links to GitHub + # Build and publish with custom source service (e.g., for a fork) $(basename "$0") \\ --source-service github \\ - --source-service-base-url https://github.com/OpenSwiftUIProject/OpenSwiftUI/blob/main + --source-service-base-url https://github.com/yourname/OpenSwiftUI/blob/custom-branch EOF exit 0 From 9ce451455ce5546a56334fe0e08573b1b8227507 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 4 Oct 2025 17:54:05 +0800 Subject: [PATCH 05/17] Fix preview URL to use actual module name from generated docs - Detect module name from data/documentation/*.json files - Use lowercase module name for preview URL (e.g., openswiftuicore) - Fixes 404 errors when accessing documentation preview --- Scripts/build-documentation.sh | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Scripts/build-documentation.sh b/Scripts/build-documentation.sh index 4bc816902..acba9c58d 100755 --- a/Scripts/build-documentation.sh +++ b/Scripts/build-documentation.sh @@ -353,8 +353,19 @@ if [[ "$PREVIEW_MODE" == true ]]; then fi fi + # Detect the actual module name from the generated documentation + ACTUAL_MODULE="" + if [[ -d "$DOCC_OUTPUT_DIR/data/documentation" ]]; then + # Find the first .json file in data/documentation directory + ACTUAL_MODULE=$(ls "$DOCC_OUTPUT_DIR/data/documentation"/*.json 2>/dev/null | head -1 | xargs basename -s .json) + fi + log_info "Starting preview server on port $PREVIEW_PORT..." - log_info "Documentation will be available at: http://localhost:$PREVIEW_PORT/documentation/$TARGET_NAME" + if [[ -n "$ACTUAL_MODULE" ]]; then + log_info "Documentation will be available at: http://localhost:$PREVIEW_PORT/documentation/$ACTUAL_MODULE" + else + log_info "Documentation will be available at: http://localhost:$PREVIEW_PORT/" + fi log_info "Press Ctrl+C to stop the server" cd "$DOCC_OUTPUT_DIR" From 14335068d75f4f8ff31fcbcce1e32761da10533f Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 4 Oct 2025 18:02:32 +0800 Subject: [PATCH 06/17] Build documentation for OpenSwiftUI target only - Use --target OpenSwiftUI when generating symbol graphs - Only include OpenSwiftUI and OpenSwiftUICore symbol graphs - Exclude re-exported system modules (Foundation, CoreFoundation, etc.) - Documentation now shows OpenSwiftUI as main entry point --- Scripts/build-documentation.sh | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Scripts/build-documentation.sh b/Scripts/build-documentation.sh index acba9c58d..d0cfe5dcb 100755 --- a/Scripts/build-documentation.sh +++ b/Scripts/build-documentation.sh @@ -225,6 +225,7 @@ fi if [[ "$REBUILD_NEEDED" == true ]] || [[ "$CLEAN_BUILD" == true ]]; then log_info "Generating symbol graphs..." swift build \ + --target "$TARGET_NAME" \ -Xswiftc -emit-symbol-graph \ -Xswiftc -emit-symbol-graph-dir \ -Xswiftc "$DEFAULT_SYMBOL_GRAPH_DIR" \ @@ -238,13 +239,18 @@ if [[ "$REBUILD_NEEDED" == true ]] || [[ "$CLEAN_BUILD" == true ]]; then fi # Filter symbol graphs for the target module +# Only include the target itself and OpenSwiftUICore, excluding re-exported system modules log_info "Filtering symbol graphs for $TARGET_NAME..." -if ls "$DEFAULT_SYMBOL_GRAPH_DIR/${TARGET_NAME}"*.symbols.json >/dev/null 2>&1; then - cp "$DEFAULT_SYMBOL_GRAPH_DIR/${TARGET_NAME}"*.symbols.json "$SYMBOL_GRAPH_DIR/" +if ls "$DEFAULT_SYMBOL_GRAPH_DIR/${TARGET_NAME}.symbols.json" >/dev/null 2>&1; then + # Copy the main target and OpenSwiftUICore symbol graphs + cp "$DEFAULT_SYMBOL_GRAPH_DIR/${TARGET_NAME}"*.symbols.json "$SYMBOL_GRAPH_DIR/" 2>/dev/null || true + cp "$DEFAULT_SYMBOL_GRAPH_DIR/OpenSwiftUICore"*.symbols.json "$SYMBOL_GRAPH_DIR/" 2>/dev/null || true log_info "Symbol graphs for $TARGET_NAME copied successfully" else - log_warning "No symbol graphs found for $TARGET_NAME, using all available symbol graphs" - cp "$DEFAULT_SYMBOL_GRAPH_DIR"/*.symbols.json "$SYMBOL_GRAPH_DIR/" + log_error "No symbol graphs found for $TARGET_NAME" + log_error "Available symbol graphs:" + ls "$DEFAULT_SYMBOL_GRAPH_DIR"/*.symbols.json 2>/dev/null || echo " (none)" + exit 1 fi # Step 2: Find or create documentation catalog From cd5b0e99220dd484d0f9c66282c15a3e1677efdb Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 4 Oct 2025 18:25:31 +0800 Subject: [PATCH 07/17] Add force push option to save git repo size - Force push to gh-pages by default to avoid accumulating large binary files - Add --no-force flag to preserve history if needed - Prevents repo from growing rapidly with each documentation update - Reference: https://github.com/uxlfoundation/oneAPI-spec/issues/334 --- Scripts/update-gh-pages-documentation.sh | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Scripts/update-gh-pages-documentation.sh b/Scripts/update-gh-pages-documentation.sh index 6401822fc..e06a1573c 100755 --- a/Scripts/update-gh-pages-documentation.sh +++ b/Scripts/update-gh-pages-documentation.sh @@ -29,6 +29,7 @@ HOSTING_BASE_PATH="" CLEAN_BUILD=false SOURCE_SERVICE="github" SOURCE_SERVICE_BASE_URL="https://github.com/OpenSwiftUIProject/OpenSwiftUI/blob/main" +FORCE_PUSH=true # Force push to save git repo size (avoids accumulating large binary files) # Colors for output RED='\033[0;31m' @@ -54,6 +55,8 @@ OPTIONS: --source-service SERVICE Source service (github, gitlab, bitbucket) --source-service-base-url URL Base URL for source service (e.g., https://github.com/user/repo/blob/main) + --no-force Don't force push (preserves gh-pages history) + Default: force push to save repo size --clean Clean build artifacts and force rebuild -h, --help Show this help message @@ -118,6 +121,10 @@ while [[ $# -gt 0 ]]; do SOURCE_SERVICE_BASE_URL="$2" shift 2 ;; + --no-force) + FORCE_PUSH=false + shift + ;; --clean) CLEAN_BUILD=true shift @@ -135,6 +142,7 @@ done log_info "Configuration:" log_info " Target: $TARGET_NAME" log_info " Build Documentation: $BUILD_DOCS" +log_info " Force Push: $FORCE_PUSH" if [[ -n "$HOSTING_BASE_PATH" ]]; then log_info " Hosting Base Path: $HOSTING_BASE_PATH" fi @@ -234,7 +242,12 @@ else git commit -m "Update documentation (generated from $CURRENT_BRANCH@$(git -C "$REPO_ROOT" rev-parse --short HEAD))" log_info "Pushing to gh-pages branch..." - git push origin gh-pages + if [[ "$FORCE_PUSH" == true ]]; then + log_info "Using --force to save git repo size (avoids accumulating large binary files)" + git push --force origin gh-pages + else + git push origin gh-pages + fi log_info "${GREEN}✓${NC} Documentation published successfully!" log_info "GitHub Pages will be updated shortly at your repository's GitHub Pages URL" From 09a2ad2ac97adb7c59acbc746622209a906dbbbc Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 4 Oct 2025 18:36:17 +0800 Subject: [PATCH 08/17] Filter out re-exported system framework symbols from documentation - Add Python script to filter symbol graph JSON files - Extract module names from Swift mangled identifiers - Only keep OpenSwiftUI and OpenSwiftUICore symbols - Remove CoreFoundation, CoreGraphics, and other system framework symbols - Reduces symbol count from 10,185 to 4,298 (OpenSwiftUI + OpenSwiftUICore only) --- Scripts/build-documentation.sh | 59 ++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/Scripts/build-documentation.sh b/Scripts/build-documentation.sh index d0cfe5dcb..f2eb6e898 100755 --- a/Scripts/build-documentation.sh +++ b/Scripts/build-documentation.sh @@ -246,6 +246,65 @@ if ls "$DEFAULT_SYMBOL_GRAPH_DIR/${TARGET_NAME}.symbols.json" >/dev/null 2>&1; t cp "$DEFAULT_SYMBOL_GRAPH_DIR/${TARGET_NAME}"*.symbols.json "$SYMBOL_GRAPH_DIR/" 2>/dev/null || true cp "$DEFAULT_SYMBOL_GRAPH_DIR/OpenSwiftUICore"*.symbols.json "$SYMBOL_GRAPH_DIR/" 2>/dev/null || true log_info "Symbol graphs for $TARGET_NAME copied successfully" + + # Filter out symbols from unwanted modules (CoreFoundation, CoreGraphics, etc.) + log_info "Removing re-exported system framework symbols..." + python3 << EOF +import json +import sys +import os + +def filter_symbol_graph(file_path, allowed_modules): + """Filter symbol graph to only include symbols from allowed modules.""" + try: + with open(file_path, 'r') as f: + data = json.load(f) + + if 'symbols' in data and isinstance(data['symbols'], list): + original_count = len(data['symbols']) + # Filter symbols by extracting module from precise identifier + filtered_symbols = [] + for symbol in data['symbols']: + precise = symbol.get('identifier', {}).get('precise', '') + module = None + + # Extract module from mangled Swift names + if precise.startswith('s:'): + rest = precise[2:] + if rest and rest[0].isdigit(): + i = 0 + while i < len(rest) and rest[i].isdigit(): + i += 1 + if i > 0: + mod_len = int(rest[:i]) + module = rest[i:i+mod_len] + + # Keep if it's from an allowed module + if module and module in allowed_modules: + filtered_symbols.append(symbol) + + data['symbols'] = filtered_symbols + filtered_count = len(filtered_symbols) + + # Write back + with open(file_path, 'w') as f: + json.dump(data, f) + + print(f" {os.path.basename(file_path)}: {original_count} -> {filtered_count} symbols", file=sys.stderr) + return True + return False + except Exception as e: + print(f" Error filtering {file_path}: {e}", file=sys.stderr) + return False + +# List of allowed modules (OpenSwiftUI and OpenSwiftUICore only) +allowed_modules = {'OpenSwiftUI', 'OpenSwiftUICore', '$TARGET_NAME'} + +# Filter the main OpenSwiftUI symbol graph +symbol_file = '$SYMBOL_GRAPH_DIR/OpenSwiftUI.symbols.json' +if os.path.exists(symbol_file): + filter_symbol_graph(symbol_file, allowed_modules) +EOF else log_error "No symbol graphs found for $TARGET_NAME" log_error "Available symbol graphs:" From bc501c118685914ff586331578891a58012ca4f4 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 4 Oct 2025 18:52:01 +0800 Subject: [PATCH 09/17] Auto-clean build when symbol graphs are missing - Automatically run swift package clean when no symbol graphs exist - Ensures symbol graphs are always generated on first run - Prevents 'Symbol graph generation failed' error when build is up-to-date - Subsequent runs reuse existing symbol graphs for fast iterations --- Scripts/build-documentation.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Scripts/build-documentation.sh b/Scripts/build-documentation.sh index f2eb6e898..a437822df 100755 --- a/Scripts/build-documentation.sh +++ b/Scripts/build-documentation.sh @@ -217,12 +217,18 @@ DEFAULT_SYMBOL_GRAPH_DIR="$SWIFT_BUILD_DIR/symbol-graphs" REBUILD_NEEDED=false if [[ ! -d "$DEFAULT_SYMBOL_GRAPH_DIR" ]] || [[ -z "$(ls -A "$DEFAULT_SYMBOL_GRAPH_DIR" 2>/dev/null)" ]]; then REBUILD_NEEDED=true - log_info "No existing symbol graphs found, building..." + log_info "No existing symbol graphs found, will perform clean build..." else log_info "Found existing symbol graphs, reusing them (use --clean to rebuild)" fi if [[ "$REBUILD_NEEDED" == true ]] || [[ "$CLEAN_BUILD" == true ]]; then + # Clean build to ensure symbol graphs are generated + if [[ "$REBUILD_NEEDED" == true ]]; then + log_info "Cleaning build to ensure symbol graph generation..." + swift package clean + fi + log_info "Generating symbol graphs..." swift build \ --target "$TARGET_NAME" \ From 2b9ee0bede2e124a2f71a945da756e1de164d9be Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 4 Oct 2025 18:58:31 +0800 Subject: [PATCH 10/17] Check for target-specific symbol graph file - Check for TARGET_NAME.symbols.json instead of just the directory - Prevents false positive when only dependency symbol graphs exist - Ensures OpenSwiftUI symbol graphs are always generated --- Scripts/build-documentation.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Scripts/build-documentation.sh b/Scripts/build-documentation.sh index a437822df..ab72dbf9a 100755 --- a/Scripts/build-documentation.sh +++ b/Scripts/build-documentation.sh @@ -213,13 +213,13 @@ cd "$REPO_ROOT" SWIFT_BUILD_DIR=".build" DEFAULT_SYMBOL_GRAPH_DIR="$SWIFT_BUILD_DIR/symbol-graphs" -# Check if symbol graphs already exist with correct access level +# Check if symbol graphs already exist for the target REBUILD_NEEDED=false -if [[ ! -d "$DEFAULT_SYMBOL_GRAPH_DIR" ]] || [[ -z "$(ls -A "$DEFAULT_SYMBOL_GRAPH_DIR" 2>/dev/null)" ]]; then +if [[ ! -f "$DEFAULT_SYMBOL_GRAPH_DIR/${TARGET_NAME}.symbols.json" ]]; then REBUILD_NEEDED=true - log_info "No existing symbol graphs found, will perform clean build..." + log_info "No existing symbol graphs found for $TARGET_NAME, will perform clean build..." else - log_info "Found existing symbol graphs, reusing them (use --clean to rebuild)" + log_info "Found existing symbol graphs for $TARGET_NAME, reusing them (use --clean to rebuild)" fi if [[ "$REBUILD_NEEDED" == true ]] || [[ "$CLEAN_BUILD" == true ]]; then From 6db8d3f8e3608514ec348cbafb9469cecc9de4a3 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 4 Oct 2025 20:09:56 +0800 Subject: [PATCH 11/17] Fix: Only include OpenSwiftUI symbol graphs in documentation Only copy OpenSwiftUI*.symbols.json files, not OpenSwiftUICore*.symbols.json. Since OpenSwiftUI uses @_exported import OpenSwiftUICore, the OpenSwiftUI symbol graph already contains all re-exported OpenSwiftUICore symbols. This ensures only one documentation module (openswiftui) is generated, with all OpenSwiftUICore symbols appearing under openswiftui instead of a separate openswiftuicore module. --- Scripts/build-documentation.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Scripts/build-documentation.sh b/Scripts/build-documentation.sh index ab72dbf9a..efb0b540d 100755 --- a/Scripts/build-documentation.sh +++ b/Scripts/build-documentation.sh @@ -245,12 +245,12 @@ if [[ "$REBUILD_NEEDED" == true ]] || [[ "$CLEAN_BUILD" == true ]]; then fi # Filter symbol graphs for the target module -# Only include the target itself and OpenSwiftUICore, excluding re-exported system modules +# Only include the target itself (which already includes re-exported OpenSwiftUICore symbols) log_info "Filtering symbol graphs for $TARGET_NAME..." if ls "$DEFAULT_SYMBOL_GRAPH_DIR/${TARGET_NAME}.symbols.json" >/dev/null 2>&1; then - # Copy the main target and OpenSwiftUICore symbol graphs + # Copy only the main target symbol graphs + # OpenSwiftUI already includes OpenSwiftUICore symbols via @_exported import cp "$DEFAULT_SYMBOL_GRAPH_DIR/${TARGET_NAME}"*.symbols.json "$SYMBOL_GRAPH_DIR/" 2>/dev/null || true - cp "$DEFAULT_SYMBOL_GRAPH_DIR/OpenSwiftUICore"*.symbols.json "$SYMBOL_GRAPH_DIR/" 2>/dev/null || true log_info "Symbol graphs for $TARGET_NAME copied successfully" # Filter out symbols from unwanted modules (CoreFoundation, CoreGraphics, etc.) From e6e26824bd4945333b47aa42439c6ec96c1cb1e9 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 4 Oct 2025 21:11:37 +0800 Subject: [PATCH 12/17] Fix: Use specific glob patterns to exclude OpenSwiftUICore symbol graphs The previous pattern OpenSwiftUI*.symbols.json incorrectly matched OpenSwiftUICore.symbols.json because 'OpenSwiftUICore' starts with 'OpenSwiftUI'. Changed to use two explicit copy commands: 1. OpenSwiftUI.symbols.json (exact match) 2. OpenSwiftUI@*.symbols.json (extension symbol graphs like @AppKit, @Swift) This ensures only OpenSwiftUI's own symbol graphs are included, not OpenSwiftUICore's. Since OpenSwiftUI uses @_exported import OpenSwiftUICore, all OpenSwiftUICore symbols are already included in OpenSwiftUI.symbols.json. --- Scripts/build-documentation.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Scripts/build-documentation.sh b/Scripts/build-documentation.sh index efb0b540d..1a9021231 100755 --- a/Scripts/build-documentation.sh +++ b/Scripts/build-documentation.sh @@ -250,7 +250,9 @@ log_info "Filtering symbol graphs for $TARGET_NAME..." if ls "$DEFAULT_SYMBOL_GRAPH_DIR/${TARGET_NAME}.symbols.json" >/dev/null 2>&1; then # Copy only the main target symbol graphs # OpenSwiftUI already includes OpenSwiftUICore symbols via @_exported import - cp "$DEFAULT_SYMBOL_GRAPH_DIR/${TARGET_NAME}"*.symbols.json "$SYMBOL_GRAPH_DIR/" 2>/dev/null || true + # Use explicit patterns to avoid matching OpenSwiftUICore*.symbols.json + cp "$DEFAULT_SYMBOL_GRAPH_DIR/${TARGET_NAME}.symbols.json" "$SYMBOL_GRAPH_DIR/" 2>/dev/null || true + cp "$DEFAULT_SYMBOL_GRAPH_DIR/${TARGET_NAME}@"*.symbols.json "$SYMBOL_GRAPH_DIR/" 2>/dev/null || true log_info "Symbol graphs for $TARGET_NAME copied successfully" # Filter out symbols from unwanted modules (CoreFoundation, CoreGraphics, etc.) From 19ad40470b00e228e911b8ba387ee6306eb381f3 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 4 Oct 2025 22:36:26 +0800 Subject: [PATCH 13/17] Fix: Force-add files in gh-pages worktree and improve orphan branch creation - Use 'git add -Af .' to override .gitignore rules that prevent tracking files in the .docs directory - Create orphan branch in main working tree before creating worktree to ensure the branch exists properly - This fixes deployment failures where files were ignored and the gh-pages branch wasn't created --- Scripts/update-gh-pages-documentation.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Scripts/update-gh-pages-documentation.sh b/Scripts/update-gh-pages-documentation.sh index e06a1573c..73ca99a2a 100755 --- a/Scripts/update-gh-pages-documentation.sh +++ b/Scripts/update-gh-pages-documentation.sh @@ -217,11 +217,14 @@ if git show-ref --verify --quiet refs/heads/gh-pages; then } else log_info "Creating new gh-pages branch" - git worktree add --detach "$GH_PAGES_DIR" - cd "$GH_PAGES_DIR" + # Create an empty orphan branch first git checkout --orphan gh-pages git rm -rf . 2>/dev/null || true - cd "$REPO_ROOT" + git commit --allow-empty -m "Initialize gh-pages branch" + git checkout "$CURRENT_BRANCH" + + # Now create worktree from the new branch + git worktree add "$GH_PAGES_DIR" gh-pages fi # Copy documentation to gh-pages worktree @@ -233,7 +236,7 @@ touch "$GH_PAGES_DIR/.nojekyll" # Commit and push cd "$GH_PAGES_DIR" -git add -A +git add -Af . if git diff --cached --quiet; then log_info "No changes to documentation" From 398c8f6a0f5a624ad553b96c4c0d932c058d4c2a Mon Sep 17 00:00:00 2001 From: Kyle Date: Sat, 4 Oct 2025 23:53:41 +0800 Subject: [PATCH 14/17] Add --echo-without-push option and fix gh-pages deployment structure - Add git_push() function to support --echo-without-push for testing - Add --echo-without-push CLI option to echo push commands without executing - Change gh-pages worktree location from .docs/gh-pages to gh-pages/ - Copy documentation files to gh-pages/docs/ subdirectory instead of root - Add gh-pages to .gitignore to exclude worktree from main branch - This fixes the issue where .docs, Example, and .swiftpm folders were incorrectly included in gh-pages branch --- .gitignore | 1 + Scripts/update-gh-pages-documentation.sh | 25 +++++++++++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index e3259780b..43e4312c6 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ Example/ReferenceImages/**/*.png .claude .docs +gh-pages diff --git a/Scripts/update-gh-pages-documentation.sh b/Scripts/update-gh-pages-documentation.sh index 73ca99a2a..a76906c46 100755 --- a/Scripts/update-gh-pages-documentation.sh +++ b/Scripts/update-gh-pages-documentation.sh @@ -30,6 +30,7 @@ CLEAN_BUILD=false SOURCE_SERVICE="github" SOURCE_SERVICE_BASE_URL="https://github.com/OpenSwiftUIProject/OpenSwiftUI/blob/main" FORCE_PUSH=true # Force push to save git repo size (avoids accumulating large binary files) +ECHO_WITHOUT_PUSH=false # Echo push command without actually pushing # Colors for output RED='\033[0;31m' @@ -58,6 +59,7 @@ OPTIONS: --no-force Don't force push (preserves gh-pages history) Default: force push to save repo size --clean Clean build artifacts and force rebuild + --echo-without-push Echo push command without actually pushing (for testing) -h, --help Show this help message EXAMPLES: @@ -94,6 +96,14 @@ log_error() { echo -e "${RED}[ERROR]${NC} $1" } +git_push() { + if [[ "$ECHO_WITHOUT_PUSH" == true ]]; then + echo "[echo without push]: git push $*" + else + git push "$@" + fi +} + # Parse command line arguments while [[ $# -gt 0 ]]; do case $1 in @@ -129,6 +139,10 @@ while [[ $# -gt 0 ]]; do CLEAN_BUILD=true shift ;; + --echo-without-push) + ECHO_WITHOUT_PUSH=true + shift + ;; -h|--help) usage ;; @@ -193,7 +207,7 @@ fi log_info "Using documentation from: $DOCC_OUTPUT_DIR" # Deploy to GitHub Pages -GH_PAGES_DIR="$DOCS_DIR/gh-pages" +GH_PAGES_DIR="$REPO_ROOT/gh-pages" log_info "Preparing GitHub Pages deployment..." @@ -227,9 +241,10 @@ else git worktree add "$GH_PAGES_DIR" gh-pages fi -# Copy documentation to gh-pages worktree +# Copy documentation to gh-pages worktree docs folder log_info "Copying documentation files..." -rsync -av --delete "$DOCC_OUTPUT_DIR/" "$GH_PAGES_DIR/" +mkdir -p "$GH_PAGES_DIR/docs" +rsync -av --delete "$DOCC_OUTPUT_DIR/" "$GH_PAGES_DIR/docs/" # Add .nojekyll to prevent GitHub Pages from processing with Jekyll touch "$GH_PAGES_DIR/.nojekyll" @@ -247,9 +262,9 @@ else log_info "Pushing to gh-pages branch..." if [[ "$FORCE_PUSH" == true ]]; then log_info "Using --force to save git repo size (avoids accumulating large binary files)" - git push --force origin gh-pages + git_push --force origin gh-pages else - git push origin gh-pages + git_push origin gh-pages fi log_info "${GREEN}✓${NC} Documentation published successfully!" From 29080abc99de39e2afac433a1539620e9bcfa5e2 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 5 Oct 2025 00:21:51 +0800 Subject: [PATCH 15/17] Add documentation for GitHub Pages setup and deployment scripts - Explain documentation architecture and hosting setup - Provide usage instructions for build-documentation.sh script - Provide usage instructions for update-gh-pages-documentation.sh script - Document why self-hosted was chosen over Swift Package Index - Include troubleshooting guide and advanced usage examples - Explain technical details of symbol filtering and deployment process --- Docs/Documentation.md | 265 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 Docs/Documentation.md diff --git a/Docs/Documentation.md b/Docs/Documentation.md new file mode 100644 index 000000000..d51064f75 --- /dev/null +++ b/Docs/Documentation.md @@ -0,0 +1,265 @@ +# Documentation + +This document explains how OpenSwiftUI's documentation is built and hosted. + +## Overview + +OpenSwiftUI uses Swift-DocC to generate API documentation, which is hosted on GitHub Pages at: + +**https://openswiftuiproject.github.io/OpenSwiftUI/documentation/openswiftui/** + +The documentation is built from the `OpenSwiftUI` target and includes symbols from `OpenSwiftUICore` via `@_exported import`. System framework symbols (CoreFoundation, CoreGraphics, etc.) are filtered out to keep the documentation focused on OpenSwiftUI's own APIs. + +## Documentation Scripts + +Two scripts are provided for documentation management: + +### `Scripts/build-documentation.sh` + +Builds documentation locally with optional preview server. + +**Usage:** +```bash +# Build and preview documentation locally +./Scripts/build-documentation.sh --preview + +# Build with internal symbols visible +./Scripts/build-documentation.sh --minimum-access-level internal + +# Preview on a different port +./Scripts/build-documentation.sh --preview --port 8080 + +# Clean build (force regenerate symbol graphs) +./Scripts/build-documentation.sh --clean +``` + +**Options:** +- `--preview` - Start a local HTTP server to preview documentation +- `--port PORT` - Port for preview server (default: 8000) +- `--minimum-access-level LEVEL` - Symbol visibility: public, internal, private, fileprivate (default: public) +- `--target TARGET` - Documentation target (default: OpenSwiftUI) +- `--hosting-base-path PATH` - Base path for hosting (e.g., /OpenSwiftUI) +- `--source-service SERVICE` - Source service (github, gitlab, bitbucket) +- `--source-service-base-url URL` - Base URL for source links +- `--clean` - Clean build artifacts and force rebuild + +**Example workflow:** +```bash +# Preview documentation locally before deploying +./Scripts/build-documentation.sh --preview + +# Open http://localhost:8000/documentation/openswiftui in your browser +# Make changes to documentation comments in source code +# Re-run the script to see updates (uses incremental builds) +``` + +### `Scripts/update-gh-pages-documentation.sh` + +Builds and deploys documentation to GitHub Pages. + +**Usage:** +```bash +# Build and deploy documentation to GitHub Pages +./Scripts/update-gh-pages-documentation.sh --hosting-base-path /OpenSwiftUI + +# Test deployment without pushing (dry-run) +./Scripts/update-gh-pages-documentation.sh --hosting-base-path /OpenSwiftUI --echo-without-push + +# Deploy using existing build (skip building) +./Scripts/update-gh-pages-documentation.sh --no-build --hosting-base-path /OpenSwiftUI + +# Deploy with internal symbols +./Scripts/update-gh-pages-documentation.sh --minimum-access-level internal --hosting-base-path /OpenSwiftUI +``` + +**Important:** Always use `--hosting-base-path /OpenSwiftUI` when deploying to GitHub Pages, as the site is served from a subdirectory. Without this flag, CSS/JS resources will fail to load. + +**Options:** +- `--hosting-base-path PATH` - **Required** for GitHub Pages deployment (use `/OpenSwiftUI`) +- `--no-build` - Skip building, use existing documentation output +- `--echo-without-push` - Show push command without executing (for testing) +- `--minimum-access-level LEVEL` - Symbol visibility (default: public) +- `--clean` - Clean build artifacts and force rebuild +- `--no-force` - Don't force push (preserves gh-pages history, increases repo size) + +**How it works:** +1. Builds documentation using `build-documentation.sh` +2. Creates or updates the `gh-pages` branch as a git worktree at `gh-pages/` +3. Copies documentation files to `gh-pages/docs/` +4. Commits and force-pushes to `origin/gh-pages` +5. Cleans up the worktree + +**Note:** Force push is used by default to keep the repository size small by avoiding accumulation of large binary files (CSS, JS, images) in git history. Each deployment completely replaces the previous one. + +## GitHub Pages Configuration + +The documentation is deployed to the `gh-pages` branch with the following structure: + +``` +gh-pages/ +├── .nojekyll # Prevents Jekyll processing +└── docs/ # Documentation root (configured in GitHub Pages settings) + ├── index.html + ├── css/ + ├── js/ + ├── data/ + ├── documentation/ + └── ... +``` + +**GitHub Pages settings:** +- **Source:** Deploy from branch +- **Branch:** `gh-pages` +- **Folder:** `/docs` + +## Why Self-Hosted Instead of Swift Package Index? + +We initially used [Swift Package Index (SPI)](https://swiftpackageindex.com) for documentation hosting, which worked well and provided excellent features like multi-version documentation picker. However, we encountered several limitations that led us to switch to self-hosted GitHub Pages: + +### Limitations of SPI Documentation + +SPI's documentation system is built on `swift-docc-plugin` and SwiftPM, which currently has some constraints: + +1. **Binary Target Limitations** - SwiftPM has issues with binary targets in documentation builds ([swiftlang/swift-package-manager#7580](https://github.com/swiftlang/swift-package-manager/issues/7580)). We had to add `isSPIDocGenerationBuild` workarounds in `Package.swift` to exclude certain dependencies during SPI builds. + +2. **Exported Symbol Handling** - SwiftPM's symbol graph generation doesn't properly handle `@_exported import` declarations ([swiftlang/swift-package-manager#9101](https://github.com/swiftlang/swift-package-manager/issues/9101)), which is essential for OpenSwiftUI's re-export architecture where `OpenSwiftUI` re-exports `OpenSwiftUICore`. + +3. **Limited Customization** - The plugin-based approach doesn't provide fine-grained control over symbol filtering, documentation generation parameters, or output customization that we need for a complex project like OpenSwiftUI. + +### Benefits of Self-Hosted Documentation + +By self-hosting, we gain: + +- **Full Control** - Direct access to Swift-DocC compiler flags and symbol graph filtering +- **Flexible Deployment** - Custom scripts tailored to OpenSwiftUI's specific needs +- **Faster Iteration** - No dependency on external service processing times +- **Symbol Filtering** - Ability to filter out re-exported system framework symbols (CoreFoundation, CoreGraphics) that would otherwise clutter the documentation +- **Custom Build Workflow** - Support for local preview, incremental builds, and testing before deployment + +We appreciate the Swift Package Index team's efforts in providing documentation hosting for the Swift community. The decision to self-host is purely technical, driven by OpenSwiftUI's specific requirements and architectural constraints rather than any shortcomings of SPI itself. + +## Updating Documentation + +### For regular updates: + +```bash +# 1. Make changes to documentation comments in source code + +# 2. Preview locally +./Scripts/build-documentation.sh --preview + +# 3. Verify changes at http://localhost:8000/documentation/openswiftui + +# 4. Deploy to GitHub Pages +./Scripts/update-gh-pages-documentation.sh --hosting-base-path /OpenSwiftUI + +# 5. Wait 1-2 minutes for GitHub Pages to rebuild +# 6. Verify at https://openswiftuiproject.github.io/OpenSwiftUI/documentation/openswiftui/ +``` + +### For major API changes: + +If you've added new public APIs or significantly changed the module structure, use `--clean` to force regeneration of symbol graphs: + +```bash +./Scripts/update-gh-pages-documentation.sh --clean --hosting-base-path /OpenSwiftUI +``` + +## Troubleshooting + +### CSS/JS files not loading (404 errors) + +**Symptom:** Documentation page loads but appears unstyled, browser console shows 404 errors for CSS/JS files. + +**Cause:** Documentation was built without `--hosting-base-path /OpenSwiftUI` flag. + +**Solution:** Rebuild and redeploy with the correct flag: +```bash +./Scripts/update-gh-pages-documentation.sh --hosting-base-path /OpenSwiftUI +``` + +### Symbol graphs are stale + +**Symptom:** New APIs don't appear in documentation. + +**Cause:** Symbol graphs weren't regenerated. + +**Solution:** Use `--clean` flag to force regeneration: +```bash +./Scripts/build-documentation.sh --clean +``` + +### Documentation includes system framework symbols + +**Symptom:** Documentation shows CoreFoundation, CoreGraphics symbols. + +**Cause:** Symbol filtering failed or was disabled. + +**Solution:** The filtering is automatic. If you see system symbols, check the build output for filtering errors and ensure the Python JSON filtering step completed successfully. + +### Port already in use (preview) + +**Symptom:** `Address already in use` error when running preview. + +**Solution:** The script will detect this and prompt you to kill the existing process, or use a different port: +```bash +./Scripts/build-documentation.sh --preview --port 8001 +``` + +## Advanced Usage + +### Building documentation for OpenSwiftUICore + +```bash +./Scripts/build-documentation.sh --target OpenSwiftUICore --preview +``` + +### Internal documentation for contributors + +```bash +./Scripts/build-documentation.sh \ + --minimum-access-level internal \ + --preview +``` + +### Testing deployment without pushing + +```bash +./Scripts/update-gh-pages-documentation.sh \ + --hosting-base-path /OpenSwiftUI \ + --echo-without-push +``` + +This creates the gh-pages branch locally and shows what would be pushed without actually pushing to the remote. + +## Technical Details + +### Symbol Graph Filtering + +The build process filters symbol graphs to remove re-exported system framework symbols: + +1. Swift compiler generates symbol graphs with `-emit-symbol-graph` +2. Symbol graphs include all accessible symbols, including re-exports from CoreFoundation, CoreGraphics, etc. +3. Python script parses Swift mangled identifiers (format: `s:MODULE_LEN+MODULE_NAME...`) to extract module names +4. Only symbols from `OpenSwiftUI` and `OpenSwiftUICore` modules are kept +5. Typical reduction: ~10,000 → ~4,300 symbols + +### Git Worktree Approach + +The deployment script uses git worktree to manage the gh-pages branch: + +- Main working tree: feature branch with source code +- Worktree at `gh-pages/`: checked out to gh-pages branch +- This allows deploying documentation without switching branches in the main working tree +- Worktree is automatically cleaned up after deployment + +### Force Push Strategy + +By default, deployments use `git push --force` to prevent repository size growth: + +- Documentation includes large binary files (CSS, JS, images, data) +- Preserving history would accumulate these files with each deployment +- Force push keeps only the latest version in git history +- Trade-off: No documentation version history in git (use git tags on main branch for versioning instead) + +To preserve history: `./Scripts/update-gh-pages-documentation.sh --no-force --hosting-base-path /OpenSwiftUI` From ce289b18f6554c070497433baa801f3b911c3490 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 5 Oct 2025 00:27:26 +0800 Subject: [PATCH 16/17] Add future improvements section to documentation - Add TODO for removing default implementations from docs - Add TODO for migrating to GitHub Actions for automated deployment --- Docs/Documentation.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Docs/Documentation.md b/Docs/Documentation.md index d51064f75..011530cc2 100644 --- a/Docs/Documentation.md +++ b/Docs/Documentation.md @@ -263,3 +263,18 @@ By default, deployments use `git push --force` to prevent repository size growth - Trade-off: No documentation version history in git (use git tags on main branch for versioning instead) To preserve history: `./Scripts/update-gh-pages-documentation.sh --no-force --hosting-base-path /OpenSwiftUI` + +## Future Improvements + +The following improvements are planned for the documentation system: + +- [ ] **Remove default implementation** - Currently, the documentation includes default implementations from protocol extensions. These can clutter the documentation and make it harder to find the primary API declarations. Future work will add filtering to hide default implementations while keeping protocol requirements visible. + +- [ ] **Migrate to GitHub Actions** - The current deployment process uses a local `gh-pages` branch and manual script execution. Migrating to GitHub Actions would provide: + - Automatic documentation updates on every push to main + - Consistent build environment (no local machine dependencies) + - Build artifacts and logs available in GitHub UI + - Easier collaboration (no need to run deployment scripts locally) + - Integration with PR previews (optional) + + This would replace the manual `./Scripts/update-gh-pages-documentation.sh` workflow with an automated CI/CD pipeline. From 9430cdea24a36cdfe1abd76540f88d6adbfac9d4 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 5 Oct 2025 00:43:52 +0800 Subject: [PATCH 17/17] Update README with GitHub Pages documentation link - Add link to new GitHub Pages documentation as primary source - Mention legacy SwiftPackageIndex version with OpenSwiftUICore limitation - Use concise link labels for better readability --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 46b78dca7..7d74628ba 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,9 @@ And the API design and documentation is to stay as compatible with the original Currently, this project is in early development. -You can find the API [documentation](https://swiftpackageindex.com/OpenSwiftUIProject/OpenSwiftUI/main/documentation/openswiftui) here. +The full API [documentation](https://openswiftuiproject.github.io/OpenSwiftUI/documentation/openswiftui/) is hosted on GitHub Pages. + +A legacy version is available on [SwiftPackageIndex](https://swiftpackageindex.com/OpenSwiftUIProject/OpenSwiftUI/main/documentation/openswiftui), but it does not include OpenSwiftUICore APIs. ## Notes