feat(vendor_playbook): add apply-templates option

This commit is contained in:
csh 2026-01-21 10:18:48 +08:00
parent 872d8cf98b
commit 2045dd45c0
3 changed files with 295 additions and 19 deletions

View File

@ -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\<lang>\ and .gitattributes in
rem then run sync_standards to materialize .agents\<lang>\ and .gitattributes in
rem the target project root.
rem
rem Usage:
rem scripts\vendor_playbook.bat <project-root> (default: tsl)
rem scripts\vendor_playbook.bat <project-root> tsl cpp
rem scripts\vendor_playbook.bat <project-root> --langs tsl,cpp
rem scripts\vendor_playbook.bat <project-root> 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: <project-root>\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 ^<project-root^> ^(default: tsl^)
echo scripts\vendor_playbook.bat ^<project-root^> tsl cpp
echo scripts\vendor_playbook.bat ^<project-root^> --langs tsl,cpp
echo scripts\vendor_playbook.bat ^<project-root^> tsl cpp --apply-templates
echo.
echo Options:
echo --apply-templates Apply CI/lang templates to project root ^(skip if exists^)
exit /b 1

View File

@ -5,11 +5,15 @@
# Usage:
# powershell -File scripts/vendor_playbook.ps1 -DestRoot <project-root>
# powershell -File scripts/vendor_playbook.ps1 -DestRoot <project-root> -Langs tsl,cpp
# powershell -File scripts/vendor_playbook.ps1 -DestRoot <project-root> -Langs @("tsl","cpp")
# powershell -File scripts/vendor_playbook.ps1 -DestRoot <project-root> -Langs @("tsl","cpp") -ApplyTemplates
#
# Options:
# -ApplyTemplates Apply CI/lang templates to project root (skip if exists)
#
# Notes:
# - Snapshot is written to: <project-root>\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."

View File

@ -9,11 +9,16 @@ set -eu
# sh scripts/vendor_playbook.sh <project-root> # default: tsl
# sh scripts/vendor_playbook.sh <project-root> tsl cpp
# sh scripts/vendor_playbook.sh <project-root> --langs tsl,cpp
# sh scripts/vendor_playbook.sh <project-root> tsl cpp --apply-templates
#
# Options:
# --apply-templates Apply CI/lang templates to project root (skip if exists)
#
# Notes:
# - Snapshot is written to: <project-root>/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 <project-root> # default: tsl
sh scripts/vendor_playbook.sh <project-root> tsl cpp
sh scripts/vendor_playbook.sh <project-root> --langs tsl,cpp
sh scripts/vendor_playbook.sh <project-root> 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."