From 2045dd45c0b2507fe18bb449d794a8c216bada68 Mon Sep 17 00:00:00 2001 From: csh Date: Wed, 21 Jan 2026 10:18:48 +0800 Subject: [PATCH] :sparkles: feat(vendor_playbook): add apply-templates option --- scripts/vendor_playbook.bat | 115 ++++++++++++++++++++++++++++++++---- scripts/vendor_playbook.ps1 | 85 +++++++++++++++++++++++++- scripts/vendor_playbook.sh | 114 ++++++++++++++++++++++++++++++++--- 3 files changed, 295 insertions(+), 19 deletions(-) diff --git a/scripts/vendor_playbook.bat b/scripts/vendor_playbook.bat index 7812e9a..881347f 100644 --- a/scripts/vendor_playbook.bat +++ b/scripts/vendor_playbook.bat @@ -2,17 +2,22 @@ setlocal enabledelayedexpansion rem Vendor a trimmed Playbook snapshot into a target project (offline copy), -rem then run sync_standards to materialize rulesets\\ and .gitattributes in +rem then run sync_standards to materialize .agents\\ and .gitattributes in rem the target project root. rem rem Usage: rem scripts\vendor_playbook.bat (default: tsl) rem scripts\vendor_playbook.bat tsl cpp rem scripts\vendor_playbook.bat --langs tsl,cpp +rem scripts\vendor_playbook.bat tsl cpp --apply-templates +rem +rem Options: +rem --apply-templates Apply CI/lang templates to project root (skip if exists) rem rem Notes: rem - Snapshot is written to: \docs\standards\playbook\ rem - Existing snapshot is backed up before overwrite. +rem - With --apply-templates, CI and lang templates are copied to project root. set "SCRIPT_DIR=%~dp0" for %%I in ("%SCRIPT_DIR%..") do set "SRC=%%~fI" @@ -25,13 +30,30 @@ set "DEST_ROOT=%~1" shift /1 set "LANGS=" +set "APPLY_TEMPLATES=0" + +rem Parse arguments +:parse_args +if "%~1"=="" goto args_done if "%~1"=="--langs" ( set "LANGS=%~2" shift /1 shift /1 -) else ( - set "LANGS=%1 %2 %3 %4 %5 %6 %7 %8 %9" + goto parse_args ) +if "%~1"=="--apply-templates" ( + set "APPLY_TEMPLATES=1" + shift /1 + goto parse_args +) +if "%LANGS%"=="" ( + set "LANGS=%~1" +) else ( + set "LANGS=%LANGS% %~1" +) +shift /1 +goto parse_args +:args_done if "%LANGS%"=="" set "LANGS=tsl" set "LANGS=%LANGS:,= %" @@ -191,24 +213,24 @@ set "SOURCE=%DEST_PREFIX%\\SOURCE.md" echo Vendored snapshot -^> %DEST_PREFIX% -set "PROJECT_AGENTS_ROOT=%DEST_ROOT_ABS%\\rulesets" +set "PROJECT_AGENTS_ROOT=%DEST_ROOT_ABS%\\.agents" set "PROJECT_AGENTS_INDEX=%PROJECT_AGENTS_ROOT%\\index.md" if not exist "%PROJECT_AGENTS_ROOT%" mkdir "%PROJECT_AGENTS_ROOT%" if not exist "%PROJECT_AGENTS_INDEX%" ( - > "%PROJECT_AGENTS_INDEX%" echo # rulesets(多语言) + > "%PROJECT_AGENTS_INDEX%" echo # .agents(多语言) >> "%PROJECT_AGENTS_INDEX%" echo. >> "%PROJECT_AGENTS_INDEX%" echo 本目录用于存放仓库级/语言级的代理规则集。 >> "%PROJECT_AGENTS_INDEX%" echo. >> "%PROJECT_AGENTS_INDEX%" echo 本项目已启用的规则集: for %%L in (%LANGS%) do ( - if /I "%%~L"=="tsl" >> "%PROJECT_AGENTS_INDEX%" echo - rulesets/tsl/:TSL 相关规则集(适用于 .tsl/.tsf) - if /I "%%~L"=="cpp" >> "%PROJECT_AGENTS_INDEX%" echo - rulesets/cpp/:C++ 相关规则集(C++23,含 Modules) - if /I "%%~L"=="python" >> "%PROJECT_AGENTS_INDEX%" echo - rulesets/python/:Python 相关规则集 - if /I "%%~L"=="markdown" >> "%PROJECT_AGENTS_INDEX%" echo - rulesets/markdown/:Markdown 相关规则集(仅代码格式化) + if /I "%%~L"=="tsl" >> "%PROJECT_AGENTS_INDEX%" echo - .agents/tsl/:TSL 相关规则集(适用于 .tsl/.tsf) + if /I "%%~L"=="cpp" >> "%PROJECT_AGENTS_INDEX%" echo - .agents/cpp/:C++ 相关规则集(C++23,含 Modules) + if /I "%%~L"=="python" >> "%PROJECT_AGENTS_INDEX%" echo - .agents/python/:Python 相关规则集 + if /I "%%~L"=="markdown" >> "%PROJECT_AGENTS_INDEX%" echo - .agents/markdown/:Markdown 相关规则集(仅代码格式化) ) >> "%PROJECT_AGENTS_INDEX%" echo. >> "%PROJECT_AGENTS_INDEX%" echo 入口建议从: - for %%L in (%LANGS%) do >> "%PROJECT_AGENTS_INDEX%" echo - rulesets/%%~L/index.md + for %%L in (%LANGS%) do >> "%PROJECT_AGENTS_INDEX%" echo - .agents/%%~L/index.md >> "%PROJECT_AGENTS_INDEX%" echo. >> "%PROJECT_AGENTS_INDEX%" echo 标准快照文档入口: >> "%PROJECT_AGENTS_INDEX%" echo. @@ -222,6 +244,62 @@ call "%DEST_PREFIX%\\scripts\\sync_standards.bat" %LANGS% popd set "SYNC_ROOT=%OLD_SYNC_ROOT%" +rem Apply templates to project root if requested +if "%APPLY_TEMPLATES%"=="1" ( + echo. + echo Applying templates to project root... + + rem Apply CI templates ^(Gitea workflows^) + set "CI_SRC=%DEST_PREFIX%\templates\ci\gitea\.gitea" + if exist "!CI_SRC!" ( + if exist "%DEST_ROOT_ABS%\.gitea" ( + echo Skip ^(exists^): .gitea\ + ) else ( + xcopy "!CI_SRC!\*" "%DEST_ROOT_ABS%\.gitea\" /e /i /y >nul 2>nul + echo Applied: .gitea\ + ) + ) + + rem Apply lang-specific templates + for %%L in (%LANGS%) do ( + set "LANG_SRC=%DEST_PREFIX%\templates\%%~L" + if exist "!LANG_SRC!" ( + if /I "%%~L"=="cpp" ( + call :CopyIfNotExists "!LANG_SRC!\.clang-format" "%DEST_ROOT_ABS%\.clang-format" + call :CopyIfNotExists "!LANG_SRC!\.clangd" "%DEST_ROOT_ABS%\.clangd" + call :CopyIfNotExists "!LANG_SRC!\CMakeLists.txt" "%DEST_ROOT_ABS%\CMakeLists.txt" + call :CopyIfNotExists "!LANG_SRC!\CMakeUserPresets.json" "%DEST_ROOT_ABS%\CMakeUserPresets.json" + call :CopyIfNotExists "!LANG_SRC!\conanfile.txt" "%DEST_ROOT_ABS%\conanfile.txt" + if exist "!LANG_SRC!\conan" ( + if exist "%DEST_ROOT_ABS%\conan" ( + echo Skip ^(exists^): conan\ + ) else ( + xcopy "!LANG_SRC!\conan\*" "%DEST_ROOT_ABS%\conan\" /e /i /y >nul 2>nul + echo Applied: conan\ + ) + ) + ) + if /I "%%~L"=="python" ( + call :CopyIfNotExists "!LANG_SRC!\.editorconfig" "%DEST_ROOT_ABS%\.editorconfig" + call :CopyIfNotExists "!LANG_SRC!\.flake8" "%DEST_ROOT_ABS%\.flake8" + call :CopyIfNotExists "!LANG_SRC!\.pre-commit-config.yaml" "%DEST_ROOT_ABS%\.pre-commit-config.yaml" + call :CopyIfNotExists "!LANG_SRC!\.pylintrc" "%DEST_ROOT_ABS%\.pylintrc" + call :CopyIfNotExists "!LANG_SRC!\pyproject.toml" "%DEST_ROOT_ABS%\pyproject.toml" + if exist "!LANG_SRC!\.vscode" ( + if exist "%DEST_ROOT_ABS%\.vscode" ( + echo Skip ^(exists^): .vscode\ + ) else ( + xcopy "!LANG_SRC!\.vscode\*" "%DEST_ROOT_ABS%\.vscode\" /e /i /y >nul 2>nul + echo Applied: .vscode\ + ) + ) + ) + ) + ) + + echo Templates applied. +) + echo Done. endlocal exit /b 0 @@ -263,9 +341,26 @@ if /I "%LANG%"=="markdown" ( ) exit /b 0 +:CopyIfNotExists +set "SRC_FILE=%~1" +set "DST_FILE=%~2" +if exist "%SRC_FILE%" ( + if exist "%DST_FILE%" ( + for %%F in ("%DST_FILE%") do echo Skip ^(exists^): %%~nxF + ) else ( + copy /y "%SRC_FILE%" "%DST_FILE%" >nul + for %%F in ("%DST_FILE%") do echo Applied: %%~nxF + ) +) +exit /b 0 + :Usage echo Usage: echo scripts\vendor_playbook.bat ^ ^(default: tsl^) echo scripts\vendor_playbook.bat ^ tsl cpp echo scripts\vendor_playbook.bat ^ --langs tsl,cpp +echo scripts\vendor_playbook.bat ^ tsl cpp --apply-templates +echo. +echo Options: +echo --apply-templates Apply CI/lang templates to project root ^(skip if exists^) exit /b 1 diff --git a/scripts/vendor_playbook.ps1 b/scripts/vendor_playbook.ps1 index 9fa0cb7..a85cf40 100644 --- a/scripts/vendor_playbook.ps1 +++ b/scripts/vendor_playbook.ps1 @@ -5,11 +5,15 @@ # Usage: # powershell -File scripts/vendor_playbook.ps1 -DestRoot # powershell -File scripts/vendor_playbook.ps1 -DestRoot -Langs tsl,cpp -# powershell -File scripts/vendor_playbook.ps1 -DestRoot -Langs @("tsl","cpp") +# powershell -File scripts/vendor_playbook.ps1 -DestRoot -Langs @("tsl","cpp") -ApplyTemplates +# +# Options: +# -ApplyTemplates Apply CI/lang templates to project root (skip if exists) # # Notes: # - Snapshot is written to: \docs\standards\playbook\ # - Existing snapshot is backed up before overwrite. +# - With -ApplyTemplates, CI and lang templates are copied to project root. [CmdletBinding()] param( @@ -17,7 +21,10 @@ param( [string]$DestRoot, [Parameter(Mandatory = $false)] - [string[]]$Langs + [string[]]$Langs, + + [Parameter(Mandatory = $false)] + [switch]$ApplyTemplates ) $ErrorActionPreference = "Stop" @@ -247,4 +254,78 @@ try { $env:SYNC_ROOT = $oldSyncRoot } +# Apply templates to project root if requested +if ($ApplyTemplates) { + Write-Host "" + Write-Host "Applying templates to project root..." + + # Helper function: copy file if not exists + function Copy-IfNotExists { + param([string]$SrcFile, [string]$DstFile) + if (Test-Path $SrcFile) { + if (Test-Path $DstFile) { + Write-Host " Skip (exists): $(Split-Path -Leaf $DstFile)" + } else { + Copy-Item $SrcFile $DstFile -Force + Write-Host " Applied: $(Split-Path -Leaf $DstFile)" + } + } + } + + # Apply CI templates (Gitea workflows) + $ciSrc = Join-Path $DestPrefix "templates/ci/gitea/.gitea" + if (Test-Path $ciSrc) { + $ciDst = Join-Path $DestRootAbs ".gitea" + if (Test-Path $ciDst) { + Write-Host " Skip (exists): .gitea/" + } else { + Copy-Item $ciSrc $ciDst -Recurse -Force + Write-Host " Applied: .gitea/" + } + } + + # Apply lang-specific templates + foreach ($lang in $Langs) { + $langSrc = Join-Path $DestPrefix "templates/$lang" + if (-not (Test-Path $langSrc)) { continue } + + switch ($lang) { + "cpp" { + Copy-IfNotExists (Join-Path $langSrc ".clang-format") (Join-Path $DestRootAbs ".clang-format") + Copy-IfNotExists (Join-Path $langSrc ".clangd") (Join-Path $DestRootAbs ".clangd") + Copy-IfNotExists (Join-Path $langSrc "CMakeLists.txt") (Join-Path $DestRootAbs "CMakeLists.txt") + Copy-IfNotExists (Join-Path $langSrc "CMakeUserPresets.json") (Join-Path $DestRootAbs "CMakeUserPresets.json") + Copy-IfNotExists (Join-Path $langSrc "conanfile.txt") (Join-Path $DestRootAbs "conanfile.txt") + $conanSrc = Join-Path $langSrc "conan" + $conanDst = Join-Path $DestRootAbs "conan" + if ((Test-Path $conanSrc) -and -not (Test-Path $conanDst)) { + Copy-Item $conanSrc $conanDst -Recurse -Force + Write-Host " Applied: conan/" + } elseif (Test-Path $conanDst) { + Write-Host " Skip (exists): conan/" + } + break + } + "python" { + Copy-IfNotExists (Join-Path $langSrc ".editorconfig") (Join-Path $DestRootAbs ".editorconfig") + Copy-IfNotExists (Join-Path $langSrc ".flake8") (Join-Path $DestRootAbs ".flake8") + Copy-IfNotExists (Join-Path $langSrc ".pre-commit-config.yaml") (Join-Path $DestRootAbs ".pre-commit-config.yaml") + Copy-IfNotExists (Join-Path $langSrc ".pylintrc") (Join-Path $DestRootAbs ".pylintrc") + Copy-IfNotExists (Join-Path $langSrc "pyproject.toml") (Join-Path $DestRootAbs "pyproject.toml") + $vscodeSrc = Join-Path $langSrc ".vscode" + $vscodeDst = Join-Path $DestRootAbs ".vscode" + if ((Test-Path $vscodeSrc) -and -not (Test-Path $vscodeDst)) { + Copy-Item $vscodeSrc $vscodeDst -Recurse -Force + Write-Host " Applied: .vscode/" + } elseif (Test-Path $vscodeDst) { + Write-Host " Skip (exists): .vscode/" + } + break + } + } + } + + Write-Host "Templates applied." +} + Write-Host "Done." diff --git a/scripts/vendor_playbook.sh b/scripts/vendor_playbook.sh index 4c64b1b..f79ba5a 100644 --- a/scripts/vendor_playbook.sh +++ b/scripts/vendor_playbook.sh @@ -9,11 +9,16 @@ set -eu # sh scripts/vendor_playbook.sh # default: tsl # sh scripts/vendor_playbook.sh tsl cpp # sh scripts/vendor_playbook.sh --langs tsl,cpp +# sh scripts/vendor_playbook.sh tsl cpp --apply-templates +# +# Options: +# --apply-templates Apply CI/lang templates to project root (skip if exists) # # Notes: # - Snapshot is written to: /docs/standards/playbook/ # - Existing snapshot is backed up before overwrite. # - Ruleset templates from rulesets/ will be copied to snapshot for sync_standards use. +# - With --apply-templates, CI and lang templates are copied to project root. SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P)" SRC="$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd -P)" @@ -24,6 +29,11 @@ Usage: sh scripts/vendor_playbook.sh # default: tsl sh scripts/vendor_playbook.sh tsl cpp sh scripts/vendor_playbook.sh --langs tsl,cpp + sh scripts/vendor_playbook.sh tsl cpp --apply-templates + +Options: + --apply-templates Apply CI/lang templates to project root (skip if exists) + -h, --help Show this help EOF } @@ -41,13 +51,33 @@ PROJECT_ROOT="$1" shift langs="" -if [ "${1:-}" = "--langs" ]; then - langs="${2:-}" - shift 2 || true -fi -if [ -z "${langs:-}" ] && [ "$#" -gt 0 ]; then - langs="$*" -fi +APPLY_TEMPLATES=0 + +# Parse arguments +while [ $# -gt 0 ]; do + case "$1" in + --langs) + langs="${2:-}" + shift 2 || true + ;; + --apply-templates) + APPLY_TEMPLATES=1 + shift + ;; + -*) + echo "ERROR: Unknown option: $1" >&2 + exit 1 + ;; + *) + if [ -z "$langs" ]; then + langs="$1" + else + langs="$langs $1" + fi + shift + ;; + esac +done if [ -z "${langs:-}" ]; then langs="tsl" @@ -278,4 +308,74 @@ EOF fi SYNC_ROOT="$PROJECT_ROOT_ABS" sh "$DEST_PREFIX/scripts/sync_standards.sh" "$@" + +# Apply templates to project root if requested +if [ "$APPLY_TEMPLATES" -eq 1 ]; then + echo "" + echo "Applying templates to project root..." + + # Helper function: copy file if not exists + copy_if_not_exists() { + src_file="$1" + dst_file="$2" + if [ -f "$src_file" ]; then + if [ -f "$dst_file" ]; then + echo " Skip (exists): $(basename "$dst_file")" + else + cp "$src_file" "$dst_file" + echo " Applied: $(basename "$dst_file")" + fi + fi + } + + # Apply CI templates (Gitea workflows) + CI_SRC="$DEST_PREFIX/templates/ci/gitea" + if [ -d "$CI_SRC/.gitea" ]; then + if [ -d "$PROJECT_ROOT_ABS/.gitea" ]; then + echo " Skip (exists): .gitea/" + else + cp -R "$CI_SRC/.gitea" "$PROJECT_ROOT_ABS/" + echo " Applied: .gitea/" + fi + fi + + # Apply lang-specific templates + for lang in "$@"; do + [ -n "$lang" ] || continue + LANG_SRC="$DEST_PREFIX/templates/$lang" + [ -d "$LANG_SRC" ] || continue + + case "$lang" in + cpp) + copy_if_not_exists "$LANG_SRC/.clang-format" "$PROJECT_ROOT_ABS/.clang-format" + copy_if_not_exists "$LANG_SRC/.clangd" "$PROJECT_ROOT_ABS/.clangd" + copy_if_not_exists "$LANG_SRC/CMakeLists.txt" "$PROJECT_ROOT_ABS/CMakeLists.txt" + copy_if_not_exists "$LANG_SRC/CMakeUserPresets.json" "$PROJECT_ROOT_ABS/CMakeUserPresets.json" + copy_if_not_exists "$LANG_SRC/conanfile.txt" "$PROJECT_ROOT_ABS/conanfile.txt" + if [ -d "$LANG_SRC/conan" ] && [ ! -d "$PROJECT_ROOT_ABS/conan" ]; then + cp -R "$LANG_SRC/conan" "$PROJECT_ROOT_ABS/" + echo " Applied: conan/" + elif [ -d "$PROJECT_ROOT_ABS/conan" ]; then + echo " Skip (exists): conan/" + fi + ;; + python) + copy_if_not_exists "$LANG_SRC/.editorconfig" "$PROJECT_ROOT_ABS/.editorconfig" + copy_if_not_exists "$LANG_SRC/.flake8" "$PROJECT_ROOT_ABS/.flake8" + copy_if_not_exists "$LANG_SRC/.pre-commit-config.yaml" "$PROJECT_ROOT_ABS/.pre-commit-config.yaml" + copy_if_not_exists "$LANG_SRC/.pylintrc" "$PROJECT_ROOT_ABS/.pylintrc" + copy_if_not_exists "$LANG_SRC/pyproject.toml" "$PROJECT_ROOT_ABS/pyproject.toml" + if [ -d "$LANG_SRC/.vscode" ] && [ ! -d "$PROJECT_ROOT_ABS/.vscode" ]; then + cp -R "$LANG_SRC/.vscode" "$PROJECT_ROOT_ABS/" + echo " Applied: .vscode/" + elif [ -d "$PROJECT_ROOT_ABS/.vscode" ]; then + echo " Skip (exists): .vscode/" + fi + ;; + esac + done + + echo "Templates applied." +fi + echo "Done."