feat(client): 迁移Hub更新客户端实现

This commit is contained in:
2026-09-08 17:08:58 +08:00
parent 0c500024e6
commit 8dfef45bc4
34 changed files with 2032 additions and 2903 deletions
+17 -43
View File
@@ -1,59 +1,33 @@
客户端脚本说明
==============
SimCAE Hub 客户端脚本说明
==========================
本目录保存 update-client 的辅助脚本。项目根目录只保留源码、CMake 入口、Docs 和配置模板,脚本统一放在这里。
本目录保存 Qt/C++ 客户端更新链路的辅助脚本。客户端仍然由
Launcher、Updater、Bootstrap 和业务主程序组成,服务端接口使用当前
SimCAE Hub 的 Go API。
脚本列表:
1. package-sdk.ps1
在 Windows 上生成给其他软件接入用的 UpdateClientSDK 包。
注意:SDK 包只面向运行接入,不包含 config/server_config.json 和 config/server_config.qrc。
服务端地址必须在打包前写入源码目录 config/server_config.json,并重新编译进 Launcher/Updater。
在 Windows 上生成给业务软件接入用的客户端更新运行时包。
2. package-client.ps1
Windows 上生成某个具体产品的最终客户端发布包
Windows 本地调试用的客户包脚本,需要手工提供 app_config.json
新流程建议上传完整软件 ZIP 到 SimCAE Hub,由服务端生成最终配置。
3. install-sdk.ps1
将 SDK 运行时复制到业务软件 Release 目录。
把客户端更新运行时复制到业务软件 Release 目录。
4. package-sdk.sh
在 Linux 上生成给其他软件接入用的 UpdateClientSDK 包,输出 tar.gz。
在 Linux 上生成客户端更新运行时包,输出 tar.gz。
5. package-client.sh
Linux 上生成某个具体产品的最终客户端发布包,输出 tar.gz
Linux 本地调试用的客户包脚本,需要手工提供 app_config.json
推荐在 update-client 根目录执行
SDK 打包命令、两种打包模式、参数含义和输出位置,统一看
```powershell
.\scripts\package-sdk.ps1 `
-SourceDir .\out\bin\Release `
-OutputDir .\dist\UpdateClientSDK `
-ZipFile .\dist\UpdateClientSDK.zip `
-SdkVersion 0.1.0
```
../Docs/01-客户端接入打包部署指南.md
```powershell
.\scripts\package-client.ps1 `
-SourceDir .\out\bin\Release `
-ConfigFile .\config\app_config.json `
-OutputDir .\dist\UpdateClient `
-ZipFile .\dist\UpdateClient.zip
```
Linux 示例:
```bash
bash ./scripts/package-sdk.sh \
--source-dir ./out/linux/bin \
--output-dir ./dist/UpdateClientSDK-linux \
--archive ./dist/UpdateClientSDK-linux.tar.gz \
--sdk-version 0.1.0
```
```bash
bash ./scripts/package-client.sh \
--source-dir /path/to/SimCAE \
--config-file /path/to/SimCAE/bin/config/app_config.json \
--output-dir ./dist/UpdateClient-linux \
--archive ./dist/UpdateClient-linux.tar.gz
```
生成 SDK 后,把 Launcher、Updater、Bootstrap 和必要运行库放进业务软件
根目录或 bin 目录,再把完整软件目录压缩上传到 SimCAE Hub 管理后台的
发布包页面。服务端会生成 config/app_config.json,并在启用 Manifest 签名
时生成 config/manifest_public_key.pem。
+18 -32
View File
@@ -1,28 +1,23 @@
param(
[Parameter(Mandatory=$true)]
[string]$SdkRoot,
[string]$ReleaseDir = (Get-Location).Path,
[switch]$OverwriteConfig,
[switch]$IncludeQtRuntime
)
[Parameter(Mandatory=$true)]
[string]$SdkRoot,
[string]$ReleaseDir = (Get-Location).Path,
[switch]$IncludeQtRuntime
)
$ErrorActionPreference = "Stop"
$sdk = (Resolve-Path $SdkRoot).Path
$release = (Resolve-Path $ReleaseDir).Path
$binDir = Join-Path $sdk "bin"
$configDir = Join-Path $sdk "config"
$appConfig = Join-Path $configDir "app_config.json"
$publicKey = Join-Path $configDir "manifest_public_key.pem"
foreach ($path in @($binDir, $appConfig, $publicKey)) {
if (-not (Test-Path $path)) {
throw "SDK file is missing: $path"
}
$binDir = Join-Path $sdk "bin"
foreach ($path in @($binDir)) {
if (-not (Test-Path $path)) {
throw "SDK file is missing: $path"
}
}
function Test-IsQtRuntimeItem {
@@ -58,17 +53,8 @@ Get-ChildItem $binDir -Force | Where-Object {
-not (Test-IsQtRuntimeItem $_)
} | Copy-Item -Destination $release -Recurse -Force
$targetConfigDir = Join-Path $release "config"
New-Item $targetConfigDir -ItemType Directory -Force | Out-Null
$targetAppConfig = Join-Path $targetConfigDir "app_config.json"
if ((-not (Test-Path $targetAppConfig)) -or $OverwriteConfig) {
Copy-Item $appConfig $targetAppConfig -Force
} else {
Write-Host "Keep existing config/app_config.json. Use -OverwriteConfig to replace it."
}
Copy-Item $publicKey (Join-Path $targetConfigDir "manifest_public_key.pem") -Force
Write-Host "SDK files installed to: $release"
Write-Host "Next: edit config/app_config.json, then start Launcher.exe."
$targetConfigDir = Join-Path $release "config"
New-Item $targetConfigDir -ItemType Directory -Force | Out-Null
Write-Host "SDK files installed to: $release"
Write-Host "Next: package the whole application directory and upload it in SimCAE Hub. The server will generate config/app_config.json and config/manifest_public_key.pem when needed."
+15 -13
View File
@@ -3,7 +3,8 @@ param(
[Parameter(Mandatory = $true)]
[string]$ConfigFile,
[string]$OutputDir = "",
[string]$ZipFile = ""
[string]$ZipFile = "",
[switch]$SkipManifestCheck
)
$ErrorActionPreference = "Stop"
@@ -13,10 +14,10 @@ if ([string]::IsNullOrWhiteSpace($SourceDir)) {
$SourceDir = Join-Path $RepoRoot "out/bin/Release"
}
if ([string]::IsNullOrWhiteSpace($OutputDir)) {
$OutputDir = Join-Path $RepoRoot "dist/UpdateClient"
$OutputDir = Join-Path $RepoRoot "dist/SimCAEUpdateClient"
}
if ([string]::IsNullOrWhiteSpace($ZipFile)) {
$ZipFile = Join-Path $RepoRoot "dist/UpdateClient.zip"
$ZipFile = Join-Path $RepoRoot "dist/SimCAEUpdateClient.zip"
}
$source = (Resolve-Path $SourceDir).Path
@@ -64,12 +65,11 @@ function Get-UserDataManifestCandidate([string]$RuntimeDir, [string]$ManifestNam
$localData = [Environment]::GetFolderPath("LocalApplicationData")
if ([string]::IsNullOrWhiteSpace($localData)) { return "" }
$installId = Get-InstallDirectoryId $RuntimeDir
return Join-Path $localData "Marsco\UpdateClientSDK\installations\$installId\update\manifest_cache\$ManifestName"
return Join-Path $localData "SimCAE\HubUpdateClient\installations\$installId\update\manifest_cache\$ManifestName"
}
$requiredFields = @(
"app_id", "channel", "current_version",
"client_token", "launch_token", "license_key",
"product_code", "channel", "current_version", "launch_token",
"main_executable", "launcher_executable", "updater_executable", "bootstrap_executable"
)
foreach ($field in $requiredFields) {
@@ -127,9 +127,9 @@ $manifestCandidates = @(
(Join-Path $source "update/manifest_cache/$manifestName")
) | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }
$sourceManifest = $manifestCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1
if (-not $sourceManifest -or -not (Test-Path $sourceManifest)) {
if (-not $SkipManifestCheck -and (-not $sourceManifest -or -not (Test-Path $sourceManifest))) {
$searched = ($manifestCandidates | ForEach-Object { " - $_" }) -join [Environment]::NewLine
throw "Missing signed Manifest cache for current version: $manifestName. Complete online update/verification for this version before packaging. Searched paths:$([Environment]::NewLine)$searched"
throw "Missing Manifest cache for current version: $manifestName. Complete online update/verification for this version before packaging, or pass -SkipManifestCheck for a first-time test package. Searched paths:$([Environment]::NewLine)$searched"
}
if (Test-Path $OutputDir) {
@@ -155,14 +155,16 @@ $outputConfigDir = Split-Path $outputConfigPath -Parent
New-Item $outputConfigDir -ItemType Directory -Force | Out-Null
Copy-Item $config $outputConfigPath -Force
@("client_identity.dat", "local_state.json", "version_policy.dat") | ForEach-Object {
@("client_identity.dat", "local_state.json", "version_policy.dat") | ForEach-Object {
$runtimeFile = Join-Path $outputConfigDir $_
if (Test-Path $runtimeFile) { Remove-Item $runtimeFile -Force }
}
$manifestDir = Join-Path $OutputDir ((Join-RelativePath $runtimeDirRelative "update/manifest_cache") -replace '/', [IO.Path]::DirectorySeparatorChar)
New-Item $manifestDir -ItemType Directory -Force | Out-Null
Copy-Item $sourceManifest (Join-Path $manifestDir $manifestName) -Force
$manifestDir = Join-Path $OutputDir ((Join-RelativePath $runtimeDirRelative "update/manifest_cache") -replace '/', [IO.Path]::DirectorySeparatorChar)
if ($sourceManifest -and (Test-Path $sourceManifest)) {
New-Item $manifestDir -ItemType Directory -Force | Out-Null
Copy-Item $sourceManifest (Join-Path $manifestDir $manifestName) -Force
}
$zipParent = Split-Path $ZipFile -Parent
New-Item $zipParent -ItemType Directory -Force | Out-Null
+8 -8
View File
@@ -6,8 +6,8 @@ REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
SOURCE_DIR="$REPO_ROOT/out/linux/bin"
CONFIG_FILE=""
OUTPUT_DIR="$REPO_ROOT/dist/UpdateClient-linux"
ARCHIVE_FILE="$REPO_ROOT/dist/UpdateClient-linux.tar.gz"
OUTPUT_DIR="$REPO_ROOT/dist/SimCAEUpdateClient-linux"
ARCHIVE_FILE="$REPO_ROOT/dist/SimCAEUpdateClient-linux.tar.gz"
SKIP_MANIFEST_CHECK=0
usage() {
@@ -17,8 +17,8 @@ Usage: package-client.sh --config-file FILE [options]
Options:
--source-dir DIR Release/install root to package. Default: ./out/linux/bin
--config-file FILE app_config.json used by this client package. Required.
--output-dir DIR Output directory. Default: ./dist/UpdateClient-linux
--archive FILE Output tar.gz. Default: ./dist/UpdateClient-linux.tar.gz
--output-dir DIR Output directory. Default: ./dist/SimCAEUpdateClient-linux
--archive FILE Output tar.gz. Default: ./dist/SimCAEUpdateClient-linux.tar.gz
--skip-manifest-check Skip current-version manifest cache check.
-h, --help Show this help.
EOF
@@ -89,7 +89,7 @@ user_data_manifest_candidate() {
local data_home="${XDG_DATA_HOME:-$HOME/.local/share}"
local install_id
install_id="$(install_directory_id "$runtime_dir")"
printf '%s/Marsco/UpdateClientSDK/installations/%s/update/manifest_cache/%s' \
printf '%s/SimCAE/HubUpdateClient/installations/%s/update/manifest_cache/%s' \
"$data_home" "$install_id" "$manifest_name"
}
@@ -116,7 +116,7 @@ CONFIG_FILE="$(realpath "$CONFIG_FILE")"
OUTPUT_DIR="$(realpath -m "$OUTPUT_DIR")"
ARCHIVE_FILE="$(realpath -m "$ARCHIVE_FILE")"
for field in app_id channel current_version client_token launch_token license_key main_executable launcher_executable updater_executable bootstrap_executable; do
for field in product_code channel current_version launch_token main_executable launcher_executable updater_executable bootstrap_executable; do
if [[ -z "$(json_value "$field")" ]]; then
echo "Config file is missing required field: $field" >&2
exit 1
@@ -187,8 +187,8 @@ for candidate in "${MANIFEST_CANDIDATES[@]}"; do
fi
done
if [[ "$SKIP_MANIFEST_CHECK" -eq 0 && ! -f "$SOURCE_MANIFEST" ]]; then
echo "Missing signed Manifest cache for current version: $MANIFEST_NAME." >&2
echo "Complete online update/verification for this version before packaging. Searched paths:" >&2
echo "Missing Manifest cache for current version: $MANIFEST_NAME." >&2
echo "Complete online update/verification for this version before packaging, or pass --skip-manifest-check for a first-time test package. Searched paths:" >&2
printf ' - %s\n' "${MANIFEST_CANDIDATES[@]}" >&2
exit 1
fi
+28 -35
View File
@@ -3,7 +3,6 @@ param(
[string]$OutputDir = "",
[string]$ZipFile = "",
[string]$SdkVersion = "0.1.0",
[string]$ExampleConfig = "",
[switch]$IncludeDemoMainApp,
[switch]$IncludeQtRuntime
)
@@ -15,38 +14,24 @@ if ([string]::IsNullOrWhiteSpace($SourceDir)) {
$SourceDir = Join-Path $RepoRoot "out/bin/Release"
}
if ([string]::IsNullOrWhiteSpace($OutputDir)) {
$OutputDir = Join-Path $RepoRoot "dist/UpdateClientSDK"
$OutputDir = Join-Path $RepoRoot "dist/SimCAEHubUpdateClientSDK"
}
if ([string]::IsNullOrWhiteSpace($ZipFile)) {
$ZipFile = Join-Path $RepoRoot "dist/UpdateClientSDK.zip"
}
if ([string]::IsNullOrWhiteSpace($ExampleConfig)) {
$ExampleConfig = Join-Path $RepoRoot "config/app_config.example.json"
$ZipFile = Join-Path $RepoRoot "dist/SimCAEHubUpdateClientSDK.zip"
}
$source = (Resolve-Path $SourceDir).Path
$exampleConfigPath = (Resolve-Path $ExampleConfig).Path
$requiredFiles = @("Launcher.exe", "Updater.exe", "Bootstrap.exe")
foreach ($name in $requiredFiles) {
$requiredFiles = @("Launcher.exe", "Updater.exe", "Bootstrap.exe")
foreach ($name in $requiredFiles) {
$path = Join-Path $source $name
if (-not (Test-Path $path)) {
throw "SDK source directory is missing required file: $path"
}
}
$publicKeyCandidates = @(
(Join-Path $source "config/manifest_public_key.pem"),
(Join-Path $source "manifest_public_key.pem"),
(Join-Path $RepoRoot "config/manifest_public_key.pem")
)
$publicKey = $publicKeyCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1
if (-not $publicKey) {
throw "manifest_public_key.pem is missing. Prepare the public key that matches the server signing private key."
}
$debugArtifacts = Get-ChildItem $source -Recurse -File | Where-Object {
$_.Name -match '^(Qt5.*d|qwindowsd|libEGLd|libGLESv2d|msvcp.*d|vcruntime.*d)\.dll$' -or
}
}
$debugArtifacts = Get-ChildItem $source -Recurse -File | Where-Object {
$_.Name -match '^(Qt5.*d|qwindowsd|libEGLd|libGLESv2d|msvcp.*d|vcruntime.*d)\.dll$' -or
$_.Extension -in @('.pdb', '.ilk')
}
if ($debugArtifacts) {
@@ -85,9 +70,14 @@ function Test-IsQtRuntimeFile {
}
return (
$Item.Name -match '^Qt5.*\.dll$' -or
$Item.Name -in @(
"libEGL.dll",
$Item.Name -match '^Qt5.*\.dll$' -or
$Item.Name -match '^vc_redist.*\.exe$' -or
$Item.Name -match '^vcredist.*\.exe$' -or
$Item.Name -match '^vcruntime.*\.dll$' -or
$Item.Name -match '^msvcp.*\.dll$' -or
$Item.Name -match '^concrt.*\.dll$' -or
$Item.Name -in @(
"libEGL.dll",
"libGLESv2.dll",
"opengl32sw.dll",
"d3dcompiler_47.dll"
@@ -95,19 +85,20 @@ function Test-IsQtRuntimeFile {
)
}
Get-ChildItem $source -Force | Where-Object {
$_.Name -notin $excludedTopLevel -and -not (Test-IsQtRuntimeFile $_)
} | Copy-Item -Destination $binDir -Recurse -Force
Copy-Item $exampleConfigPath (Join-Path $configDir "app_config.json") -Force
Copy-Item $publicKey (Join-Path $configDir "manifest_public_key.pem") -Force
Get-ChildItem $source -Force | Where-Object {
$_.Name -notin $excludedTopLevel -and -not (Test-IsQtRuntimeFile $_)
} | Copy-Item -Destination $binDir -Recurse -Force
$commonSourceDir = Join-Path $RepoRoot "Common"
$commonSourceFiles = @(
"ConfigHelper.h",
"ConfigHelper.cpp",
"IntegrityHelper.h",
"IntegrityHelper.cpp",
"TicketHelper.h",
"TicketHelper.cpp"
"TicketHelper.cpp",
"UpdatePathPolicy.h",
"UpdatePathPolicy.cpp"
)
foreach ($commonFile in $commonSourceFiles) {
$commonPath = Join-Path $commonSourceDir $commonFile
@@ -144,6 +135,8 @@ Copy-Item (Join-Path $PSScriptRoot "install-sdk.ps1") (Join-Path $scriptsDir "in
sdk_type = "external-updater-runtime"
required_entry = "Launcher.exe"
contains_demo_main_app = [bool]$IncludeDemoMainApp
contains_qt_runtime = [bool]$IncludeQtRuntime
contains_final_config = $false
docs_entry = "Docs/01-客户端接入打包部署指南.md"
word_guide_included = [bool]$wordGuideSource
integration_sources = $commonSourceFiles
+33 -28
View File
@@ -5,11 +5,11 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
SOURCE_DIR="$REPO_ROOT/out/linux/bin"
OUTPUT_DIR="$REPO_ROOT/dist/UpdateClientSDK-linux"
ARCHIVE_FILE="$REPO_ROOT/dist/UpdateClientSDK-linux.tar.gz"
OUTPUT_DIR="$REPO_ROOT/dist/SimCAEHubUpdateClientSDK-linux"
ARCHIVE_FILE="$REPO_ROOT/dist/SimCAEHubUpdateClientSDK-linux.tar.gz"
SDK_VERSION="0.1.0"
EXAMPLE_CONFIG="$REPO_ROOT/config/app_config.linux.example.json"
INCLUDE_DEMO_MAIN_APP=0
INCLUDE_QT_RUNTIME=0
usage() {
cat <<'EOF'
@@ -17,11 +17,11 @@ Usage: package-sdk.sh [options]
Options:
--source-dir DIR Linux Release output directory. Default: ./out/linux/bin
--output-dir DIR SDK directory to generate. Default: ./dist/UpdateClientSDK-linux
--archive FILE SDK tar.gz path. Default: ./dist/UpdateClientSDK-linux.tar.gz
--output-dir DIR SDK directory to generate. Default: ./dist/SimCAEHubUpdateClientSDK-linux
--archive FILE SDK tar.gz path. Default: ./dist/SimCAEHubUpdateClientSDK-linux.tar.gz
--sdk-version VERSION SDK version. Default: 0.1.0
--example-config FILE app_config template. Default: ./config/app_config.linux.example.json
--include-demo-mainapp Include MainApp demo executable in SDK bin.
--include-qt-runtime Include Qt runtime files from the Release output directory.
-h, --help Show this help.
EOF
}
@@ -32,15 +32,14 @@ while [[ $# -gt 0 ]]; do
--output-dir) OUTPUT_DIR="$2"; shift 2 ;;
--archive|--tar-file|--zip-file) ARCHIVE_FILE="$2"; shift 2 ;;
--sdk-version) SDK_VERSION="$2"; shift 2 ;;
--example-config) EXAMPLE_CONFIG="$2"; shift 2 ;;
--include-demo-mainapp) INCLUDE_DEMO_MAIN_APP=1; shift ;;
--include-qt-runtime) INCLUDE_QT_RUNTIME=1; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "Unknown option: $1" >&2; usage >&2; exit 2 ;;
esac
done
SOURCE_DIR="$(realpath "$SOURCE_DIR")"
EXAMPLE_CONFIG="$(realpath "$EXAMPLE_CONFIG")"
OUTPUT_DIR="$(realpath -m "$OUTPUT_DIR")"
ARCHIVE_FILE="$(realpath -m "$ARCHIVE_FILE")"
@@ -51,21 +50,6 @@ for name in Launcher Updater Bootstrap; do
fi
done
PUBLIC_KEY=""
for candidate in \
"$SOURCE_DIR/config/manifest_public_key.pem" \
"$SOURCE_DIR/manifest_public_key.pem" \
"$REPO_ROOT/config/manifest_public_key.pem"; do
if [[ -f "$candidate" ]]; then
PUBLIC_KEY="$candidate"
break
fi
done
if [[ -z "$PUBLIC_KEY" ]]; then
echo "manifest_public_key.pem is missing. Prepare the public key that matches the server signing private key." >&2
exit 1
fi
DEBUG_ARTIFACT="$(find "$SOURCE_DIR" -type f \( -name '*.pdb' -o -name '*.ilk' -o -name '*d.dll' \) -print -quit)"
if [[ -n "$DEBUG_ARTIFACT" ]]; then
echo "SDK source directory contains Debug artifacts. Use a clean Release output directory." >&2
@@ -76,6 +60,21 @@ fi
rm -rf "$OUTPUT_DIR"
mkdir -p "$OUTPUT_DIR/bin" "$OUTPUT_DIR/config" "$OUTPUT_DIR/scripts" "$OUTPUT_DIR/Common" "$OUTPUT_DIR/Docs"
is_qt_runtime_item() {
local base="$1"
case "$base" in
bearer|iconengines|imageformats|platforms|styles|translations)
return 0
;;
libQt5*.so*|libEGL.so*|libGLESv2.so*|libqxcb.so*|libxcb*.so*|libstdc++.so*|libgcc_s.so*|libssl.so*|libcrypto.so*|opengl32sw.dll|d3dcompiler_47.dll)
return 0
;;
*)
return 1
;;
esac
}
shopt -s dotglob nullglob
for item in "$SOURCE_DIR"/*; do
base="$(basename "$item")"
@@ -86,16 +85,16 @@ for item in "$SOURCE_DIR"/*; do
fi
;;
*)
if [[ "$INCLUDE_QT_RUNTIME" -eq 0 ]] && is_qt_runtime_item "$base"; then
continue
fi
cp -a "$item" "$OUTPUT_DIR/bin/"
;;
esac
done
shopt -u dotglob nullglob
cp "$EXAMPLE_CONFIG" "$OUTPUT_DIR/config/app_config.json"
cp "$PUBLIC_KEY" "$OUTPUT_DIR/config/manifest_public_key.pem"
for common_file in ConfigHelper.h ConfigHelper.cpp TicketHelper.h TicketHelper.cpp; do
for common_file in ConfigHelper.h ConfigHelper.cpp IntegrityHelper.h IntegrityHelper.cpp TicketHelper.h TicketHelper.cpp UpdatePathPolicy.h UpdatePathPolicy.cpp; do
common_path="$REPO_ROOT/Common/$common_file"
if [[ ! -f "$common_path" ]]; then
echo "SDK Common integration source is missing: $common_path" >&2
@@ -134,13 +133,19 @@ cat > "$OUTPUT_DIR/sdk_manifest.json" <<EOF
"platform": "linux",
"required_entry": "Launcher",
"contains_demo_main_app": $([[ "$INCLUDE_DEMO_MAIN_APP" -eq 1 ]] && echo true || echo false),
"contains_qt_runtime": $([[ "$INCLUDE_QT_RUNTIME" -eq 1 ]] && echo true || echo false),
"contains_final_config": false,
"docs_entry": "Docs/01-客户端接入打包部署指南.md",
"word_guide_included": $WORD_GUIDE_INCLUDED,
"integration_sources": [
"ConfigHelper.h",
"ConfigHelper.cpp",
"IntegrityHelper.h",
"IntegrityHelper.cpp",
"TicketHelper.h",
"TicketHelper.cpp"
"TicketHelper.cpp",
"UpdatePathPolicy.h",
"UpdatePathPolicy.cpp"
]
}
EOF