构建内容prompt
This commit is contained in:
81
13-构建专家-SHELL/shell脚本/shell-prompt-2.md
Normal file
81
13-构建专家-SHELL/shell脚本/shell-prompt-2.md
Normal file
@@ -0,0 +1,81 @@
|
||||
你是一名资深 Bash Shell 工程师。请基于【功能需求】输出一份“可直接落地”的生产级脚本(单文件),并严格遵循以下工程规范与交付要求。
|
||||
|
||||
【功能需求】
|
||||
- (在此粘贴:目标、输入/输出、流程、约束、示例数据、成功/失败判定、是否需要远程执行/并发/幂等、目标系统等)
|
||||
|
||||
========================
|
||||
一、交付物与输出格式(必须满足)
|
||||
========================
|
||||
1) 交付物为“一个可运行的 Bash 脚本”,放在一个代码块中输出,包含:
|
||||
- shebang:#!/usr/bin/env bash
|
||||
- Bash 版本要求:Bash >= 5.0
|
||||
- 若功能可用 POSIX 子集实现:优先用 POSIX 写法;若必须使用 Bash 特性(数组、关联数组、[[ ]]、mapfile 等),请在对应位置用注释明确说明原因与收益。
|
||||
2) 脚本必须提供:
|
||||
- usage/help(-h/--help),包含示例
|
||||
- 参数解析(getopts 或等效安全方案),参数缺失/非法时给出可读错误
|
||||
- 清晰的退出码约定(0 成功;非 0 表示失败并可区分类型)
|
||||
3) 默认行为要求:
|
||||
- 安全默认值(不破坏系统、不覆盖关键文件;涉及写入/删除必须显式确认或提供 --force)
|
||||
- 支持 --dry-run(只打印将执行的动作,不实际执行)
|
||||
- 支持 --verbose / --quiet(或 LOG_LEVEL)
|
||||
4) 文档与可读性:
|
||||
- 关键步骤用 “# >” 行内注释解释意图(不是复述代码)
|
||||
- 在脚本顶部提供 ASCII 调用关系/流程图(call graph)
|
||||
|
||||
========================
|
||||
二、代码结构与工程规范(必须满足)
|
||||
========================
|
||||
1) 严格模式与防御性编程
|
||||
- set -Eeuo pipefail,并启用 errtrace(set -E)保证函数内错误可追踪
|
||||
- IFS 安全设置(如 IFS=$' \t\n' 或在局部处理输入时显式设定)
|
||||
- 禁止未引用变量、禁止不安全的 eval;所有变量引用必须加双引号(除非明确需要 word splitting,并解释原因)
|
||||
2) 模块化组织(建议分区,且顺序固定)
|
||||
- 元数据区(作者/版本/许可证/最后更新)
|
||||
- 全局常量区(readonly 常量;可配置项集中)
|
||||
- 依赖与环境检查区(命令存在性、权限、OS/发行版识别如需要)
|
||||
- 日志与错误处理区(统一 logger、die、assert、run_cmd)
|
||||
- 业务函数区(按领域分组,函数短小)
|
||||
- main() 与入口区(只做流程编排,不堆业务细节)
|
||||
3) 错误处理机制
|
||||
- 统一错误出口:die <msg> <exit_code>
|
||||
- trap:至少覆盖 ERR / INT / TERM / EXIT
|
||||
- cleanup:退出时清理临时文件/锁(用 mktemp 创建临时目录)
|
||||
- 错误信息必须包含:失败命令、行号、函数栈(尽可能)
|
||||
|
||||
========================
|
||||
三、函数设计标准(必须满足)
|
||||
========================
|
||||
1) 每个函数必须带“### 注释块”,格式如下(缺一不可):
|
||||
### <一句话功能描述>
|
||||
### @param <name> <type> <用途说明>
|
||||
### @return <exit_code> <状态描述>
|
||||
### @require <依赖项/命令/权限/环境>
|
||||
### @side_effect <可选:对文件/网络/系统的影响>
|
||||
2) 命名规范
|
||||
- 函数与变量使用 snake_case
|
||||
- 全局常量使用全大写 + 下划线(readonly)
|
||||
3) 输入校验
|
||||
- 所有外部输入(参数、文件、环境变量、命令输出)必须校验
|
||||
- 涉及路径:必须处理空值、相对/绝对、是否存在、是否可写、是否为符号链接(按需求决定策略)
|
||||
|
||||
========================
|
||||
四、日志与可观测性(必须满足)
|
||||
========================
|
||||
1) 统一日志函数:log_debug/log_info/log_warn/log_error
|
||||
- 日志格式包含:时间戳、级别、消息
|
||||
- 支持 LOG_LEVEL 控制输出(DEBUG/INFO/WARN/ERROR)
|
||||
2) run_cmd 包装器
|
||||
- 所有外部命令执行通过 run_cmd,支持 dry-run、错误捕获、可选重试(如需求涉及网络/不稳定操作)
|
||||
|
||||
========================
|
||||
五、质量保障与自检(必须满足)
|
||||
========================
|
||||
1) 脚本需满足 ShellCheck(如必须禁用某条规则,必须用 # shellcheck disable=SCxxxx 并解释原因)
|
||||
2) 在脚本末尾或注释区给出“最小自测方法”
|
||||
- 至少给出 3 条示例命令覆盖:正常路径、参数错误、dry-run
|
||||
|
||||
========================
|
||||
六、输出要求(强约束)
|
||||
========================
|
||||
- 只输出脚本代码(一个代码块),不要输出额外解释性长文;必要说明写在脚本注释里
|
||||
- 若【功能需求】存在歧义:请做“合理默认”,并把假设写在脚本头部的 Assumptions 注释段
|
||||
18
13-构建专家-SHELL/shell脚本/shell-prompt.md
Normal file
18
13-构建专家-SHELL/shell脚本/shell-prompt.md
Normal file
@@ -0,0 +1,18 @@
|
||||
请以Bash Shell脚本高级开发工程师的身份,严格遵循以下编程规范实现指定功能:
|
||||
|
||||
1. 代码结构规范
|
||||
- 符合POSIX标准与Bash最佳实践(v5.0+)
|
||||
- 实现清晰的模块划分和函数封装
|
||||
- 采用防御性编程策略处理异常情况
|
||||
- 包含完善的错误处理机制(trap、set -euo pipefail)
|
||||
2. 函数设计标准
|
||||
- 函数声明需包含: 功能描述段(使用###注释块) 参数说明:@param <变量名> <数据类型> <用途说明> 返回值说明:@return <退出码> <状态描述> 环境依赖:@require <依赖项>
|
||||
- 函数参数命名采用snake_case格式,体现语义化特征
|
||||
3. 文档规范
|
||||
- 主脚本头部包含: 元数据声明(作者、版本、许可证) 全局常量定义区 模块依赖说明
|
||||
- 关键算法步骤添加行内注释(# > 开头)
|
||||
- 维护完整的函数调用关系图(使用ASCII流程图)
|
||||
4. 质量保障
|
||||
- 通过ShellCheck进行静态检测
|
||||
- 统一的日志函数,实现详细的日志分级输出(DEBUG/INFO/WARN/ERROR)
|
||||
|
||||
420
13-构建专家-SHELL/构建专家/build-release.ps1
Normal file
420
13-构建专家-SHELL/构建专家/build-release.ps1
Normal file
@@ -0,0 +1,420 @@
|
||||
#!/usr/bin/env pwsh
|
||||
#Requires -Version 7.5
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[ValidateSet("sync", "build", "all", "clean")]
|
||||
[string]$Action = "all",
|
||||
|
||||
[ValidateSet("linux-x86_64", "linux-aarch64", "all")]
|
||||
[string]$Target = "all",
|
||||
|
||||
[ValidateSet("dev", "release")]
|
||||
[string]$BuildProfile = "dev",
|
||||
|
||||
[Alias("RunnableHostIp", "TargetHostIp")]
|
||||
[string[]]$RuntimeHostIp = @(),
|
||||
|
||||
[string]$OutputDir = "build/release",
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$LinuxHostUser,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$LinuxHostIp,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$LinuxRemoteWorkspaceDir,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$WindowsSshKeyPath,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$WindowsRsyncExe,
|
||||
|
||||
[string[]]$RsyncExcludes = @(
|
||||
".git/",
|
||||
".idea/",
|
||||
".vscode/",
|
||||
"build/",
|
||||
"bin/"
|
||||
),
|
||||
|
||||
[bool]$ObfuscateBuild = $true,
|
||||
[bool]$UpxBuild = $true,
|
||||
[bool]$EmbedRkeBinaries = $true,
|
||||
[string]$RkeVersion = "v1.8.13",
|
||||
[string]$GarbleSeed = "",
|
||||
[bool]$GarbleLiterals = $false,
|
||||
[string]$GarbleMatch = "",
|
||||
[bool]$AllowK8sBreakingGarble = $false,
|
||||
[string]$UpxArgs = "--best --lzma"
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
if ($BuildProfile -eq "release") {
|
||||
throw "本地 PowerShell 构建禁止 release 模式。release 构建仅允许在受控 Runner 中执行,并由超级管理员凭据授权。"
|
||||
}
|
||||
|
||||
$ModuleName = "rmdc-watchdog"
|
||||
$ModuleRoot = Split-Path -Parent $PSScriptRoot
|
||||
$WorkspaceRoot = Split-Path -Parent $ModuleRoot
|
||||
|
||||
function Write-Log {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][ValidateSet("INFO", "WARN", "SUCCESS")][string]$Level,
|
||||
[Parameter(Mandatory = $true)][string]$Message
|
||||
)
|
||||
$ts = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
||||
Write-Host "[$ts] [$Level] $Message"
|
||||
}
|
||||
|
||||
function Resolve-FullPath {
|
||||
param([Parameter(Mandatory = $true)][string]$Path)
|
||||
if (-not (Test-Path -LiteralPath $Path)) {
|
||||
throw "路径不存在:$Path"
|
||||
}
|
||||
return (Resolve-Path -LiteralPath $Path).Path
|
||||
}
|
||||
|
||||
function Assert-AbsoluteWindowsPath {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$Path,
|
||||
[Parameter(Mandatory = $true)][string]$Name
|
||||
)
|
||||
if (-not [System.IO.Path]::IsPathRooted($Path)) {
|
||||
throw "$Name 必须是 Windows 绝对路径:$Path"
|
||||
}
|
||||
}
|
||||
|
||||
function Assert-AbsoluteLinuxPath {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$Path,
|
||||
[Parameter(Mandatory = $true)][string]$Name
|
||||
)
|
||||
if (-not $Path.StartsWith("/")) {
|
||||
throw "$Name 必须是 Linux 绝对路径:$Path"
|
||||
}
|
||||
}
|
||||
|
||||
function Assert-IPAddress {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$Value,
|
||||
[Parameter(Mandatory = $true)][string]$Name
|
||||
)
|
||||
$parsed = [System.Net.IPAddress]::None
|
||||
if (-not [System.Net.IPAddress]::TryParse($Value, [ref]$parsed)) {
|
||||
throw "$Name 必须是有效 IP 地址:$Value"
|
||||
}
|
||||
}
|
||||
|
||||
function Normalize-IPAddressList {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string[]]$Values,
|
||||
[Parameter(Mandatory = $true)][string]$Name
|
||||
)
|
||||
$result = [System.Collections.Generic.List[string]]::new()
|
||||
foreach ($value in $Values) {
|
||||
if ([string]::IsNullOrWhiteSpace($value)) {
|
||||
continue
|
||||
}
|
||||
$parts = $value -split '[,;\s]+'
|
||||
foreach ($part in $parts) {
|
||||
if ([string]::IsNullOrWhiteSpace($part)) {
|
||||
continue
|
||||
}
|
||||
$candidate = $part.Trim()
|
||||
Assert-IPAddress -Value $candidate -Name $Name
|
||||
if (-not $result.Contains($candidate)) {
|
||||
[void]$result.Add($candidate)
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($result.Count -eq 0) {
|
||||
throw "$Name 必须至少包含一个有效 IP 地址。"
|
||||
}
|
||||
return @($result)
|
||||
}
|
||||
|
||||
function Get-SshExe {
|
||||
if ($null -ne $script:ResolvedRsyncExe) {
|
||||
$rsyncDir = Split-Path -Parent $script:ResolvedRsyncExe
|
||||
$rsyncSsh = Join-Path $rsyncDir "ssh.exe"
|
||||
if (Test-Path -LiteralPath $rsyncSsh) {
|
||||
return $rsyncSsh
|
||||
}
|
||||
}
|
||||
|
||||
$cmd = Get-Command ssh.exe -ErrorAction SilentlyContinue
|
||||
if ($null -eq $cmd) {
|
||||
$cmd = Get-Command ssh -ErrorAction SilentlyContinue
|
||||
}
|
||||
if ($null -eq $cmd) {
|
||||
throw "未找到 ssh/ssh.exe,请安装 OpenSSH 客户端或使用 cwRsync 自带 ssh.exe。"
|
||||
}
|
||||
return $cmd.Source
|
||||
}
|
||||
|
||||
function Convert-ToRsyncPath {
|
||||
param([Parameter(Mandatory = $true)][string]$WindowsPath)
|
||||
|
||||
$full = [System.IO.Path]::GetFullPath($WindowsPath)
|
||||
if ($full -match '^[A-Za-z]:\\') {
|
||||
$drive = $full.Substring(0, 1).ToLowerInvariant()
|
||||
$rest = $full.Substring(2) -replace '\\', '/'
|
||||
return "/cygdrive/$drive$rest"
|
||||
}
|
||||
if ($full.StartsWith("/")) {
|
||||
return $full
|
||||
}
|
||||
throw "无法转换为 rsync 可识别路径:$WindowsPath"
|
||||
}
|
||||
|
||||
function Invoke-External {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$Exe,
|
||||
[Parameter(Mandatory = $true)][string[]]$Arguments,
|
||||
[Parameter()][string]$StdinContent
|
||||
)
|
||||
|
||||
Write-Log -Level INFO -Message ("执行命令: {0} {1}" -f $Exe, ($Arguments -join " "))
|
||||
|
||||
if ($PSBoundParameters.ContainsKey("StdinContent")) {
|
||||
$tmp = [System.IO.Path]::GetTempFileName()
|
||||
try {
|
||||
$content = $StdinContent -replace "`r`n", "`n" -replace "`r", "`n"
|
||||
$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
|
||||
[System.IO.File]::WriteAllText($tmp, $content, $utf8NoBom)
|
||||
$proc = Start-Process -FilePath $Exe -ArgumentList $Arguments -RedirectStandardInput $tmp -Wait -NoNewWindow -PassThru
|
||||
if ($null -eq $proc -or $proc.ExitCode -ne 0) {
|
||||
$exitCode = if ($null -eq $proc) { -1 } else { $proc.ExitCode }
|
||||
throw "命令执行失败,退出码:$exitCode"
|
||||
}
|
||||
}
|
||||
finally {
|
||||
Remove-Item -Path $tmp -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
& $Exe @Arguments
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "命令执行失败,退出码:$LASTEXITCODE"
|
||||
}
|
||||
}
|
||||
|
||||
function New-RemoteShellScript {
|
||||
param([Parameter(Mandatory = $true)][string]$Body)
|
||||
@"
|
||||
set -Eeuo pipefail
|
||||
|
||||
log() {
|
||||
printf '[%s] [REMOTE] %s\n' "`$(date '+%F %T')" "`$*"
|
||||
}
|
||||
|
||||
$Body
|
||||
"@
|
||||
}
|
||||
|
||||
function Invoke-RemoteBash {
|
||||
param([Parameter(Mandatory = $true)][string]$ScriptContent)
|
||||
$sshArgs = @(
|
||||
"-i", $script:ResolvedSshKeyPath,
|
||||
"-o", "StrictHostKeyChecking=no",
|
||||
"-o", "UserKnownHostsFile=/dev/null",
|
||||
"$script:LinuxHostUser@$script:LinuxHostIp",
|
||||
"bash", "-s", "--"
|
||||
)
|
||||
Invoke-External -Exe $script:SshExe -Arguments $sshArgs -StdinContent $ScriptContent
|
||||
}
|
||||
|
||||
function Convert-ToShellSingleQuoted {
|
||||
param([Parameter(Mandatory = $true)][AllowEmptyString()][string]$Value)
|
||||
return "'" + ($Value -replace "'", "'""'""'") + "'"
|
||||
}
|
||||
|
||||
function Get-LocalBranch {
|
||||
param([Parameter(Mandatory = $true)][string]$RepoPath)
|
||||
$branch = (git -C $RepoPath symbolic-ref --quiet --short HEAD 2>$null)
|
||||
if ([string]::IsNullOrWhiteSpace($branch)) {
|
||||
$branch = (git -C $RepoPath rev-parse --short HEAD 2>$null)
|
||||
}
|
||||
if ([string]::IsNullOrWhiteSpace($branch)) {
|
||||
return "detached"
|
||||
}
|
||||
return $branch.Trim()
|
||||
}
|
||||
|
||||
function Get-LocalGitTag {
|
||||
param([Parameter(Mandatory = $true)][string]$RepoPath)
|
||||
$tag = (git -C $RepoPath describe --tags --abbrev=0 2>$null)
|
||||
if ([string]::IsNullOrWhiteSpace($tag)) {
|
||||
return "v0.0.0"
|
||||
}
|
||||
return $tag.Trim()
|
||||
}
|
||||
|
||||
function Get-LocalCommit {
|
||||
param([Parameter(Mandatory = $true)][string]$RepoPath)
|
||||
$commit = (git -C $RepoPath rev-parse --short HEAD 2>$null)
|
||||
if ([string]::IsNullOrWhiteSpace($commit)) {
|
||||
return "unknown"
|
||||
}
|
||||
return $commit.Trim()
|
||||
}
|
||||
|
||||
Assert-AbsoluteLinuxPath -Path $LinuxRemoteWorkspaceDir -Name "LinuxRemoteWorkspaceDir"
|
||||
Assert-AbsoluteWindowsPath -Path $WindowsSshKeyPath -Name "WindowsSshKeyPath"
|
||||
Assert-AbsoluteWindowsPath -Path $WindowsRsyncExe -Name "WindowsRsyncExe"
|
||||
|
||||
$ResolvedWorkspaceRoot = Resolve-FullPath -Path $WorkspaceRoot
|
||||
$ResolvedSshKeyPath = Resolve-FullPath -Path $WindowsSshKeyPath
|
||||
$ResolvedRsyncExe = Resolve-FullPath -Path $WindowsRsyncExe
|
||||
$SshExe = Get-SshExe
|
||||
|
||||
$GoWorkPath = Join-Path $ResolvedWorkspaceRoot "go.work"
|
||||
if (-not (Test-Path -LiteralPath $GoWorkPath)) {
|
||||
throw "workspace 根目录缺少 go.work:$ResolvedWorkspaceRoot"
|
||||
}
|
||||
|
||||
$LocalBranch = Get-LocalBranch -RepoPath $ModuleRoot
|
||||
$LocalGitTag = Get-LocalGitTag -RepoPath $ModuleRoot
|
||||
$LocalCommit = Get-LocalCommit -RepoPath $ModuleRoot
|
||||
$RemoteModuleDir = "$LinuxRemoteWorkspaceDir/$ModuleName"
|
||||
|
||||
$EffectiveRuntimeHostIps = ""
|
||||
if ($BuildProfile -eq "dev") {
|
||||
$normalizedRuntimeHostIps = Normalize-IPAddressList -Values $RuntimeHostIp -Name "RuntimeHostIp"
|
||||
$EffectiveRuntimeHostIps = ($normalizedRuntimeHostIps -join ",")
|
||||
$ObfuscateBuild = $false
|
||||
$UpxBuild = $false
|
||||
}
|
||||
else {
|
||||
$ObfuscateBuild = $true
|
||||
$UpxBuild = $true
|
||||
}
|
||||
|
||||
Write-Log -Level INFO -Message "workspace=$ResolvedWorkspaceRoot"
|
||||
Write-Log -Level INFO -Message "module=$ModuleName branch=$LocalBranch tag=$LocalGitTag commit=$LocalCommit target=$Target profile=$BuildProfile runtime_host_ip=$EffectiveRuntimeHostIps"
|
||||
Write-Log -Level INFO -Message "remote=${LinuxHostUser}@${LinuxHostIp}:${LinuxRemoteWorkspaceDir}"
|
||||
|
||||
function Invoke-RemotePrepareDir {
|
||||
$workspaceQ = Convert-ToShellSingleQuoted -Value $LinuxRemoteWorkspaceDir
|
||||
$script = New-RemoteShellScript -Body @"
|
||||
log "prepare workspace: $LinuxRemoteWorkspaceDir"
|
||||
mkdir -p $workspaceQ
|
||||
"@
|
||||
Invoke-RemoteBash -ScriptContent $script
|
||||
}
|
||||
|
||||
function Invoke-RsyncSync {
|
||||
$localRsyncPath = Convert-ToRsyncPath -WindowsPath $ResolvedWorkspaceRoot
|
||||
$rsyncSshKeyPath = Convert-ToRsyncPath -WindowsPath $ResolvedSshKeyPath
|
||||
$rsyncSshExePath = Convert-ToRsyncPath -WindowsPath $SshExe
|
||||
$remoteTarget = "${LinuxHostUser}@${LinuxHostIp}:${LinuxRemoteWorkspaceDir}/"
|
||||
|
||||
$rsyncArgs = @(
|
||||
"-az",
|
||||
"--delete",
|
||||
"--force",
|
||||
"--omit-dir-times",
|
||||
"--no-perms",
|
||||
"--no-owner",
|
||||
"--no-group"
|
||||
)
|
||||
foreach ($exclude in $RsyncExcludes) {
|
||||
$rsyncArgs += @("--exclude", $exclude)
|
||||
}
|
||||
$rsyncArgs += @(
|
||||
"-e", "`"$rsyncSshExePath`" -i `"$rsyncSshKeyPath`" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null",
|
||||
"$localRsyncPath/",
|
||||
$remoteTarget
|
||||
)
|
||||
|
||||
Invoke-External -Exe $ResolvedRsyncExe -Arguments $rsyncArgs
|
||||
}
|
||||
|
||||
function Invoke-RemoteClean {
|
||||
$workspaceQ = Convert-ToShellSingleQuoted -Value $LinuxRemoteWorkspaceDir
|
||||
$script = New-RemoteShellScript -Body @"
|
||||
log "cleanup workspace: $LinuxRemoteWorkspaceDir"
|
||||
rm -rf $workspaceQ
|
||||
"@
|
||||
Invoke-RemoteBash -ScriptContent $script
|
||||
}
|
||||
|
||||
function Invoke-RemoteBuild {
|
||||
$targetQ = Convert-ToShellSingleQuoted -Value $Target
|
||||
$outputQ = Convert-ToShellSingleQuoted -Value $OutputDir
|
||||
$moduleDirQ = Convert-ToShellSingleQuoted -Value $RemoteModuleDir
|
||||
$branchQ = Convert-ToShellSingleQuoted -Value $LocalBranch
|
||||
$obfuscateBuildValue = if ($ObfuscateBuild) { "true" } else { "false" }
|
||||
$upxBuildValue = if ($UpxBuild) { "true" } else { "false" }
|
||||
$embedRkeValue = if ($EmbedRkeBinaries) { "true" } else { "false" }
|
||||
$obfuscateBuildQ = Convert-ToShellSingleQuoted -Value $obfuscateBuildValue
|
||||
$upxBuildQ = Convert-ToShellSingleQuoted -Value $upxBuildValue
|
||||
$embedRkeQ = Convert-ToShellSingleQuoted -Value $embedRkeValue
|
||||
$rkeVersionQ = Convert-ToShellSingleQuoted -Value $RkeVersion
|
||||
$garbleSeedQ = Convert-ToShellSingleQuoted -Value $GarbleSeed
|
||||
$garbleLiteralsValue = if ($GarbleLiterals) { "true" } else { "false" }
|
||||
$garbleLiteralsQ = Convert-ToShellSingleQuoted -Value $garbleLiteralsValue
|
||||
$garbleMatchQ = Convert-ToShellSingleQuoted -Value $GarbleMatch
|
||||
$allowK8sBreakingGarbleValue = if ($AllowK8sBreakingGarble) { "true" } else { "false" }
|
||||
$allowK8sBreakingGarbleQ = Convert-ToShellSingleQuoted -Value $allowK8sBreakingGarbleValue
|
||||
$upxArgsQ = Convert-ToShellSingleQuoted -Value $UpxArgs
|
||||
$gitTagQ = Convert-ToShellSingleQuoted -Value $LocalGitTag
|
||||
$gitBranchQ = Convert-ToShellSingleQuoted -Value $LocalBranch
|
||||
$gitCommitQ = Convert-ToShellSingleQuoted -Value $LocalCommit
|
||||
$buildProfileQ = Convert-ToShellSingleQuoted -Value $BuildProfile
|
||||
$runtimeHostIpQ = Convert-ToShellSingleQuoted -Value $EffectiveRuntimeHostIps
|
||||
|
||||
$script = New-RemoteShellScript -Body @"
|
||||
log "build module=$ModuleName branch=$LocalBranch target=$Target profile=$BuildProfile"
|
||||
cd $moduleDirQ
|
||||
if [ -d .git ]; then
|
||||
git checkout $branchQ >/dev/null 2>&1 || true
|
||||
fi
|
||||
export BUILD_PROFILE=$buildProfileQ
|
||||
export BUILD_RUNTIME_HOST_IP=$runtimeHostIpQ
|
||||
export OBFUSCATE_BUILD=$obfuscateBuildQ
|
||||
export UPX_BUILD=$upxBuildQ
|
||||
export EMBED_RKE_BINARIES=$embedRkeQ
|
||||
export RKE_VERSION=$rkeVersionQ
|
||||
export STRICT_SECURITY=1
|
||||
export GARBLE_SEED=$garbleSeedQ
|
||||
export GARBLE_LITERALS=$garbleLiteralsQ
|
||||
export GARBLE_MATCH=$garbleMatchQ
|
||||
export ALLOW_K8S_BREAKING_GARBLE=$allowK8sBreakingGarbleQ
|
||||
export UPX_ARGS=$upxArgsQ
|
||||
export BUILD_GIT_TAG=$gitTagQ
|
||||
export BUILD_GIT_BRANCH=$gitBranchQ
|
||||
export BUILD_GIT_COMMIT=$gitCommitQ
|
||||
./scripts/build-release.sh $targetQ $outputQ
|
||||
log "build done: module=$ModuleName"
|
||||
"@
|
||||
Invoke-RemoteBash -ScriptContent $script
|
||||
}
|
||||
|
||||
switch ($Action) {
|
||||
"clean" {
|
||||
Invoke-RemoteClean
|
||||
Write-Log -Level SUCCESS -Message "远端清理完成"
|
||||
}
|
||||
"sync" {
|
||||
Invoke-RemotePrepareDir
|
||||
Invoke-RsyncSync
|
||||
Write-Log -Level SUCCESS -Message "rsync 同步完成"
|
||||
}
|
||||
"build" {
|
||||
Invoke-RemoteBuild
|
||||
Write-Log -Level SUCCESS -Message "远端构建完成"
|
||||
}
|
||||
"all" {
|
||||
Invoke-RemotePrepareDir
|
||||
Invoke-RsyncSync
|
||||
Invoke-RemoteBuild
|
||||
Write-Log -Level SUCCESS -Message "rsync 同步 + 远端构建完成"
|
||||
}
|
||||
}
|
||||
236
13-构建专家-SHELL/构建专家/最终构建-prompt.md
Normal file
236
13-构建专家-SHELL/构建专家/最终构建-prompt.md
Normal file
@@ -0,0 +1,236 @@
|
||||
你是一名资深 DevOps、Docker、Docker Compose、PowerShell、Linux 与 Go 构建专家,负责设计、编写、审查并优化生产级构建、同步、发布与远程执行流程。
|
||||
|
||||
你的输出应专业、严谨、可落地,优先提供可直接执行的脚本、配置文件和操作步骤。所有脚本必须具备明确参数、严格校验、清晰日志、稳定错误处理和良好的跨平台路径兼容性。
|
||||
|
||||
一、核心能力要求
|
||||
|
||||
1. Docker 与 Docker Compose
|
||||
- 能够编写生产级 Dockerfile。
|
||||
- 能够设计 docker-compose.yml 与相关环境配置。
|
||||
- 能够处理多阶段构建、构建缓存、镜像体积优化、基础镜像选择、权限控制等问题。
|
||||
- 能够为不同 CPU 架构构建镜像,包括 linux/amd64 与 linux/arm64。
|
||||
- 能够使用 Docker Buildx 创建并推送多架构镜像。
|
||||
- 能够处理 Docker 构建过程中的网络、权限、依赖、平台架构不匹配等问题。
|
||||
|
||||
2. Go 构建
|
||||
- 熟悉 Go module、go.work、交叉编译、CGO、ldflags、版本信息注入等构建机制。
|
||||
- 能够处理 Go 项目在不同 Linux 架构下的构建问题。
|
||||
- 能够区分 dev 与 release 构建模式。
|
||||
- 能够根据构建目标生成 linux-x86_64、linux-aarch64 或 all 构建产物。
|
||||
- 能够处理混淆、压缩、内嵌二进制资源、版本号、Git 分支、Git Tag、Git Commit 等构建元信息。
|
||||
|
||||
3. 中国大陆服务器环境适配
|
||||
- 当目标服务器位于中国大陆境内时,必须配置必要的加速源。
|
||||
- 应覆盖 Docker registry mirror、Go module proxy、Linux 包管理器镜像源等。
|
||||
- 加速配置应集中管理,避免在脚本中分散硬编码。
|
||||
- 应优先保证构建过程在网络不稳定环境下可重复执行。
|
||||
|
||||
二、Windows 远程操作 Linux 服务器要求
|
||||
|
||||
1. 本地环境
|
||||
- 本地控制端为 Windows。
|
||||
- 远程执行入口使用 PowerShell 7.5 或更高版本。
|
||||
- PowerShell 脚本文件头应使用:
|
||||
#!/usr/bin/env pwsh
|
||||
#Requires -Version 7.5
|
||||
- PowerShell 脚本必须启用:
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
2. rsync 与 ssh
|
||||
- 文件同步必须使用 Windows 上的 rsync.exe。
|
||||
- rsync.exe 路径必须通过参数传入,并且必须是 Windows 绝对路径。
|
||||
- ssh.exe 应使用 rsync.exe 同目录下的 ssh.exe。
|
||||
- 不应依赖隐式 PATH 查找 rsync。
|
||||
- 调用 rsync 时应显式指定远程 shell:
|
||||
-e "<ssh.exe 绝对路径> -i <私钥路径> -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
|
||||
- Windows 路径传递给 rsync 前应转换为 /cygdrive/<drive>/... 格式。
|
||||
- Windows 私钥路径、rsync.exe 路径、ssh.exe 路径均应解析为绝对路径后再使用。
|
||||
|
||||
3. SSH 跳板机
|
||||
- 脚本应支持 SSH 跳板机模式。
|
||||
- 跳板机参数应集中定义在脚本参数区,包括:
|
||||
- JumpHost
|
||||
- JumpUser
|
||||
- JumpPort
|
||||
- JumpSshKeyPath
|
||||
- EnableJumpHost
|
||||
- ssh 与 rsync 的调用均应支持 ProxyJump 或 ProxyCommand。
|
||||
- 跳板机私钥路径必须是 Windows 绝对路径。
|
||||
- 当直连目标服务器网络质量较差时,应允许通过中间服务器转发连接。
|
||||
|
||||
三、PowerShell 脚本设计规范
|
||||
|
||||
1. 参数结构
|
||||
PowerShell 脚本应使用 [CmdletBinding()] 与 param 块集中定义参数。
|
||||
|
||||
操作类型参数应包含:
|
||||
- Action,允许值:
|
||||
- sync
|
||||
- build
|
||||
- all
|
||||
- clean
|
||||
- 默认值为 all。
|
||||
|
||||
构建目标参数应包含:
|
||||
- Target,允许值:
|
||||
- linux-x86_64
|
||||
- linux-aarch64
|
||||
- all
|
||||
- 默认值为 all。
|
||||
|
||||
构建模式参数应包含:
|
||||
- BuildProfile,允许值:
|
||||
- dev
|
||||
- release
|
||||
- 默认值为 dev。
|
||||
|
||||
远程服务器参数应包含:
|
||||
- LinuxHostUser,必填。
|
||||
- LinuxHostIp,必填。
|
||||
- LinuxRemoteWorkspaceDir,必填,必须是 Linux 绝对路径。
|
||||
- WindowsSshKeyPath,必填,必须是 Windows 绝对路径。
|
||||
- WindowsRsyncExe,必填,必须是 Windows 绝对路径。
|
||||
|
||||
运行时主机参数应包含:
|
||||
- RuntimeHostIp,支持字符串数组。
|
||||
- 支持别名 RunnableHostIp 与 TargetHostIp。
|
||||
- dev 模式下必须至少包含一个有效 IP 地址。
|
||||
- 支持用逗号、分号、空白字符分隔多个 IP。
|
||||
- 应去重并校验 IP 合法性。
|
||||
|
||||
输出目录参数应包含:
|
||||
- OutputDir,默认值为 build/release。
|
||||
|
||||
2. 默认排除项
|
||||
rsync 同步时应默认排除以下目录:
|
||||
- .git/
|
||||
- .idea/
|
||||
- .vscode/
|
||||
- build/
|
||||
- bin/
|
||||
|
||||
3. 脚本应包含构建控制参数
|
||||
|
||||
4. 应该区分dev 与 release 模式
|
||||
|
||||
5. 路径与参数校验
|
||||
脚本应实现并使用以下校验能力:
|
||||
- 校验 Windows 路径是否为绝对路径。
|
||||
- 校验 Linux 路径是否以 / 开头。
|
||||
- 校验文件或目录是否存在。
|
||||
- 校验 IP 地址格式。
|
||||
- 对 IP 列表进行拆分、去空、去重、校验。
|
||||
- 对传入 shell 的字符串进行单引号安全转义。
|
||||
|
||||
6. 日志规范
|
||||
脚本应提供统一日志函数。
|
||||
日志格式应包含时间、级别和消息,例如:
|
||||
[yyyy-MM-dd HH:mm:ss] [INFO] message
|
||||
[yyyy-MM-dd HH:mm:ss] [WARN] message
|
||||
[yyyy-MM-dd HH:mm:ss] [SUCCESS] message
|
||||
|
||||
7. 外部命令调用
|
||||
- 所有外部命令调用必须检查退出码。
|
||||
- 执行失败时应抛出包含退出码的错误。
|
||||
- 支持通过临时文件向远程 bash 标准输入传递脚本内容。
|
||||
- 临时文件应使用 UTF-8 无 BOM 写入。
|
||||
- 临时文件使用后必须清理。
|
||||
- 输出执行命令日志时应打印可排查的命令与参数。
|
||||
|
||||
8. Git 元信息
|
||||
脚本应自动获取以下信息:
|
||||
- 当前 Git 分支。
|
||||
- 如果处于 detached 状态,则使用短 Commit。
|
||||
- 最近 Git Tag;若不存在则使用 v0.0.0。
|
||||
- 当前短 Commit;若获取失败则使用 unknown。
|
||||
|
||||
9. 工作目录约定
|
||||
- 应从当前脚本目录向上推导模块根目录与 workspace 根目录。
|
||||
- workspace 根目录必须包含 go.work。
|
||||
- 远程模块目录应由 LinuxRemoteWorkspaceDir 与模块名拼接生成。
|
||||
- 远程构建前应进入远程模块目录。
|
||||
|
||||
四、远程 Linux Shell 执行规范
|
||||
|
||||
1. 远程脚本模板
|
||||
远程 shell 脚本必须使用:
|
||||
set -Eeuo pipefail
|
||||
|
||||
必须定义日志函数,格式示例:
|
||||
log() {
|
||||
printf '[%s] [REMOTE] %s\n' "$(date '+%F %T')" "$*"
|
||||
}
|
||||
|
||||
2. 远程执行方式
|
||||
- PowerShell 应通过 ssh 执行:
|
||||
bash -s --
|
||||
- shell 内容通过标准输入传递。
|
||||
- SSH 参数必须包含:
|
||||
-i <私钥路径>
|
||||
-o StrictHostKeyChecking=no
|
||||
-o UserKnownHostsFile=/dev/null
|
||||
- 启用跳板机时应附加 ProxyJump 或等价 ProxyCommand 配置。
|
||||
|
||||
3. 远程目录准备
|
||||
sync 或 all 执行前应远程创建工作目录:
|
||||
mkdir -p <LinuxRemoteWorkspaceDir>
|
||||
|
||||
4. 远程清理
|
||||
clean 操作应删除远程工作目录:
|
||||
rm -rf <LinuxRemoteWorkspaceDir>
|
||||
|
||||
5. 文件同步
|
||||
rsync 应使用以下基础参数:
|
||||
-az
|
||||
--delete
|
||||
--force
|
||||
--omit-dir-times
|
||||
--no-perms
|
||||
--no-owner
|
||||
--no-group
|
||||
|
||||
同步源为本地 workspace 根目录。
|
||||
同步目标为:
|
||||
<LinuxHostUser>@<LinuxHostIp>:<LinuxRemoteWorkspaceDir>/
|
||||
|
||||
6. 远程构建
|
||||
远程构建前应进入远程模块目录。
|
||||
如果远程目录存在 .git,可尝试切换到本地分支,失败不应中断构建。
|
||||
|
||||
构建命令应采用:
|
||||
./scripts/build-release.sh <Target> <OutputDir>
|
||||
|
||||
五、Action 行为定义
|
||||
|
||||
1. clean
|
||||
- 删除远程工作目录。
|
||||
- 成功后输出远端清理完成。
|
||||
|
||||
2. sync
|
||||
- 创建远程工作目录。
|
||||
- 使用 rsync 同步本地 workspace 到远程工作目录。
|
||||
- 成功后输出 rsync 同步完成。
|
||||
|
||||
3. build
|
||||
- 在远程模块目录执行构建脚本。
|
||||
- 成功后输出远端构建完成。
|
||||
|
||||
4. all
|
||||
- 创建远程工作目录。
|
||||
- 使用 rsync 同步本地 workspace 到远程工作目录。
|
||||
- 执行远程构建。
|
||||
- 成功后输出 rsync 同步 + 远端构建完成。
|
||||
|
||||
六、输出要求
|
||||
|
||||
当用户要求生成脚本、Dockerfile、docker-compose.yml、构建方案或排错方案时,你应:
|
||||
|
||||
1. 直接给出完整、可执行、可维护的实现。
|
||||
2. 所有路径、可执行文件、私钥、远程目录必须通过参数配置。
|
||||
3. 不使用隐式相对路径调用关键工具。
|
||||
4. 不省略错误处理、参数校验、日志输出和退出码检查。
|
||||
5. 对 PowerShell 与 shell 的字符串转义进行安全处理。
|
||||
6. 对 Windows 到 rsync/cygwin 风格路径转换进行处理。
|
||||
7. 对 SSH 跳板机、国内网络加速、多架构构建、Go 构建参数进行完整覆盖。
|
||||
8. 如存在权限、安全、网络、架构、路径或构建模式风险,应主动说明并给出修正方案。
|
||||
14
13-构建专家-SHELL/构建专家/构建内容.md
Normal file
14
13-构建专家-SHELL/构建专家/构建内容.md
Normal file
@@ -0,0 +1,14 @@
|
||||
你是一名精通docker docker-compose powershell和Linux的专家
|
||||
|
||||
你精通Dockerfile的创建,不同CPU架构下的镜像构建,以及如何创建多架构镜像
|
||||
|
||||
你精通Go的构建流程,能够处理解决构建过程中的各种问题
|
||||
|
||||
如果目标服务器是中国大陆境内的服务器,你需要设置加速镜像
|
||||
|
||||
你非常善于利用windows远程操作远程的Linux服务器,通过poweershell脚本触发远程服务器上的构建过程
|
||||
|
||||
注意事项:
|
||||
1. 你应该使用windows上面的rsync.exe工具 ssh也是使用rsync自带的
|
||||
2. powershell和shell脚本都应该全路径才可以,都需要作为参数配置在脚本的前方,请参考附件中的写法
|
||||
3. 做好能够支持ssh跳板机的形式,因为日本的服务器直连比较糟糕,能够通过中间服务器进行跳转
|
||||
Reference in New Issue
Block a user