mirror of
https://github.com/arch3rPro/1Panel-Appstore.git
synced 2026-06-12 10:19:38 +08:00
chore: optimize 1panel app builder skill
This commit is contained in:
Regular → Executable
+111
-5
@@ -40,8 +40,20 @@ EOF
|
||||
|
||||
# 日志函数
|
||||
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
|
||||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; ((WARNINGS++)); }
|
||||
log_error() { echo -e "${RED}[ERROR]${NC} $1"; ((ERRORS++)); }
|
||||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; ((WARNINGS+=1)); }
|
||||
log_error() { echo -e "${RED}[ERROR]${NC} $1"; ((ERRORS+=1)); }
|
||||
|
||||
has_yq() {
|
||||
command -v yq >/dev/null 2>&1
|
||||
}
|
||||
|
||||
yq_read() {
|
||||
local file="$1"
|
||||
local expr="$2"
|
||||
if has_yq; then
|
||||
yq -r "$expr" "$file" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查目录结构
|
||||
check_directory_structure() {
|
||||
@@ -66,11 +78,11 @@ check_directory_structure() {
|
||||
|
||||
# 查找版本目录
|
||||
local version_dirs
|
||||
version_dirs=$(find "$app_dir" -maxdepth 1 -type d -name "v*" -o -name "latest" -o -name "[0-9]*" 2>/dev/null || echo "")
|
||||
version_dirs=$(find "$app_dir" -mindepth 1 -maxdepth 1 -type d \( -name "v*" -o -name "latest" -o -name "[0-9]*" \) 2>/dev/null || echo "")
|
||||
|
||||
if [[ -z "$version_dirs" ]]; then
|
||||
log_error "未找到版本目录(如 1.0.0/, v1.0.0/, latest/)"
|
||||
return 1
|
||||
return 0
|
||||
fi
|
||||
|
||||
# 检查每个版本目录
|
||||
@@ -90,6 +102,9 @@ check_directory_structure() {
|
||||
# 验证顶层 data.yml
|
||||
validate_top_data_yml() {
|
||||
local data_file="$1"
|
||||
local app_dir app_name
|
||||
app_dir="$(dirname "$data_file")"
|
||||
app_name="$(basename "$app_dir")"
|
||||
|
||||
log_info "验证顶层 data.yml"
|
||||
|
||||
@@ -115,6 +130,14 @@ validate_top_data_yml() {
|
||||
log_error "data.yml 缺少 additionalProperties.key"
|
||||
fi
|
||||
|
||||
if has_yq; then
|
||||
local key
|
||||
key=$(yq_read "$data_file" '.additionalProperties.key // ""')
|
||||
if [[ -n "$key" && "$key" != "$app_name" ]]; then
|
||||
log_error "additionalProperties.key 必须与应用目录名一致: key=$key dir=$app_name"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 检查 tags
|
||||
if ! grep -q "tags:" "$data_file"; then
|
||||
log_warn "data.yml 缺少 tags(推荐)"
|
||||
@@ -153,6 +176,86 @@ validate_version_data_yml() {
|
||||
fi
|
||||
}
|
||||
|
||||
extract_form_env_keys() {
|
||||
local data_file="$1"
|
||||
|
||||
if [[ ! -f "$data_file" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if has_yq; then
|
||||
yq -r '.additionalProperties.formFields[]?.envKey // empty' "$data_file" 2>/dev/null || true
|
||||
else
|
||||
grep -oE 'envKey:[[:space:]]*PANEL_APP_PORT_[A-Z0-9_]+' "$data_file" | awk '{print $2}' || true
|
||||
fi
|
||||
}
|
||||
|
||||
extract_compose_port_vars() {
|
||||
local compose_file="$1"
|
||||
grep -oE '\$\{PANEL_APP_PORT_[A-Z0-9_]+\}' "$compose_file" | sed -E 's/^\$\{//; s/\}$//' | sort -u || true
|
||||
}
|
||||
|
||||
validate_port_variables() {
|
||||
local data_file="$1"
|
||||
local compose_file="$2"
|
||||
local defined used var
|
||||
|
||||
defined="$(extract_form_env_keys "$data_file" | sort -u)"
|
||||
used="$(extract_compose_port_vars "$compose_file")"
|
||||
|
||||
while IFS= read -r var; do
|
||||
[[ -z "$var" ]] && continue
|
||||
if ! grep -qx "$var" <<< "$defined"; then
|
||||
log_error "端口变量 ${var} 在 docker-compose.yml 中使用,但未在版本 data.yml 中定义"
|
||||
fi
|
||||
done <<< "$used"
|
||||
}
|
||||
|
||||
validate_image_tags() {
|
||||
local version_dir="$1"
|
||||
local compose_file="$2"
|
||||
local version image tag matched_version=false
|
||||
|
||||
version="$(basename "$version_dir")"
|
||||
while IFS= read -r image; do
|
||||
[[ -z "$image" || "$image" == "null" ]] && continue
|
||||
|
||||
if [[ "$image" =~ @sha256: ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$image" =~ :([^/:]+)$ ]]; then
|
||||
tag="${BASH_REMATCH[1]}"
|
||||
else
|
||||
tag="latest"
|
||||
fi
|
||||
|
||||
if [[ "$version" == "latest" && "$tag" != "latest" ]]; then
|
||||
log_error "latest 目录中的镜像必须使用 latest tag: $image"
|
||||
fi
|
||||
|
||||
if [[ "$version" != "latest" && "$tag" == "$version" ]]; then
|
||||
matched_version=true
|
||||
fi
|
||||
done < <(grep -E '^[[:space:]]*image:[[:space:]]*' "$compose_file" | sed -E 's/^[[:space:]]*image:[[:space:]]*"?([^"]*)"?/\1/' || true)
|
||||
|
||||
if [[ "$version" != "latest" && "$matched_version" != "true" ]]; then
|
||||
log_warn "版本目录 ${version} 未检测到与目录名一致的镜像 tag,请确认是否为多服务或特殊版本"
|
||||
fi
|
||||
}
|
||||
|
||||
validate_logo_file() {
|
||||
local logo_file="$1"
|
||||
|
||||
if [[ ! -f "$logo_file" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if head -c 512 "$logo_file" | grep -qiE '<!doctype|<html|<Error>|AccessDenied'; then
|
||||
log_error "logo.png 看起来不是有效图片,可能是下载失败返回的 HTML/XML"
|
||||
fi
|
||||
}
|
||||
|
||||
# 验证 docker-compose.yml
|
||||
validate_docker_compose() {
|
||||
local compose_file="$1"
|
||||
@@ -226,14 +329,17 @@ main() {
|
||||
# 执行检查
|
||||
check_directory_structure "$app_dir"
|
||||
validate_top_data_yml "$app_dir/data.yml"
|
||||
validate_logo_file "$app_dir/logo.png"
|
||||
|
||||
# 查找并验证版本目录
|
||||
local version_dirs
|
||||
version_dirs=$(find "$app_dir" -maxdepth 1 -type d \( -name "v*" -o -name "latest" -o -name "[0-9]*" \) 2>/dev/null || echo "")
|
||||
version_dirs=$(find "$app_dir" -mindepth 1 -maxdepth 1 -type d \( -name "v*" -o -name "latest" -o -name "[0-9]*" \) 2>/dev/null || echo "")
|
||||
|
||||
for version_dir in $version_dirs; do
|
||||
validate_version_data_yml "$version_dir/data.yml"
|
||||
validate_docker_compose "$version_dir/docker-compose.yml"
|
||||
validate_port_variables "$version_dir/data.yml" "$version_dir/docker-compose.yml"
|
||||
validate_image_tags "$version_dir" "$version_dir/docker-compose.yml"
|
||||
done
|
||||
|
||||
# 输出结果
|
||||
|
||||
Reference in New Issue
Block a user