feat: complete 2.0.7.12 platform overhaul
This commit is contained in:
@@ -11,7 +11,10 @@ import (
|
||||
|
||||
const DefaultListen = ":33550"
|
||||
|
||||
var Version = "0.1.0"
|
||||
var (
|
||||
Version = "0.1.0"
|
||||
AdminBuildID = "dev"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
BaseDir string `json:"base_dir"`
|
||||
@@ -26,6 +29,7 @@ type Config struct {
|
||||
UpdateNoticeDir string `json:"update_notice_dir"`
|
||||
DownloadsDir string `json:"downloads_dir"`
|
||||
AdminWebDir string `json:"admin_web_dir"`
|
||||
AdminAssetMode string `json:"admin_asset_mode"`
|
||||
PortalWebDir string `json:"portal_web_dir"`
|
||||
SetupWebDir string `json:"setup_web_dir"`
|
||||
LegacyUpdateDir string `json:"legacy_update_dir"`
|
||||
@@ -140,6 +144,7 @@ func defaults(root string) *Config {
|
||||
UpdateNoticeDir: filepath.Join(root, "data", "update-notice"),
|
||||
DownloadsDir: filepath.Join(root, "data", "update", "public", "downloads"),
|
||||
AdminWebDir: filepath.Join(root, "web", "admin", "dist"),
|
||||
AdminAssetMode: defaultAdminAssetMode(),
|
||||
PortalWebDir: filepath.Join(root, "web", "portal", "dist"),
|
||||
SetupWebDir: filepath.Join(root, "web", "setup", "dist"),
|
||||
LegacyUpdateDir: filepath.Clean(filepath.Join(root, "..", "update")),
|
||||
@@ -225,6 +230,9 @@ func applyEnv(cfg *Config) {
|
||||
if value := os.Getenv("YMHUT_DOWNLOADS_DIR"); value != "" {
|
||||
cfg.DownloadsDir = value
|
||||
}
|
||||
if value := os.Getenv("YMHUT_ADMIN_ASSET_MODE"); value != "" {
|
||||
cfg.AdminAssetMode = value
|
||||
}
|
||||
if value := os.Getenv("YMHUT_LEGACY_UPDATE_DIR"); value != "" {
|
||||
cfg.LegacyUpdateDir = value
|
||||
}
|
||||
@@ -386,6 +394,10 @@ func normalize(root string, cfg *Config) {
|
||||
cfg.AdminWebDir = filepath.Join(cfg.BaseDir, "web", "admin", "dist")
|
||||
}
|
||||
cfg.AdminWebDir = absPath(cfg.BaseDir, cfg.AdminWebDir)
|
||||
cfg.AdminAssetMode = strings.ToLower(strings.TrimSpace(cfg.AdminAssetMode))
|
||||
if cfg.AdminAssetMode != "embedded" && cfg.AdminAssetMode != "disk" {
|
||||
cfg.AdminAssetMode = defaultAdminAssetMode()
|
||||
}
|
||||
if cfg.PortalWebDir == "" {
|
||||
cfg.PortalWebDir = filepath.Join(cfg.BaseDir, "web", "portal", "dist")
|
||||
}
|
||||
|
||||
@@ -111,9 +111,27 @@ func TestReleaseUploadLimitCanBeConfiguredFromEnvironment(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdminAssetModeCanBeConfiguredFromEnvironment(t *testing.T) {
|
||||
t.Setenv("YMHUT_ADMIN_ASSET_MODE", "embedded")
|
||||
cfg := defaults(t.TempDir())
|
||||
applyEnv(cfg)
|
||||
normalize(cfg.BaseDir, cfg)
|
||||
if cfg.AdminAssetMode != "embedded" {
|
||||
t.Fatalf("AdminAssetMode = %q, want embedded", cfg.AdminAssetMode)
|
||||
}
|
||||
|
||||
t.Setenv("YMHUT_ADMIN_ASSET_MODE", "invalid")
|
||||
applyEnv(cfg)
|
||||
normalize(cfg.BaseDir, cfg)
|
||||
if cfg.AdminAssetMode != defaultAdminAssetMode() {
|
||||
t.Fatalf("invalid AdminAssetMode normalized to %q, want %q", cfg.AdminAssetMode, defaultAdminAssetMode())
|
||||
}
|
||||
}
|
||||
|
||||
func TestPreflightReportsMissingAdminAssetName(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
cfg := defaults(root)
|
||||
cfg.AdminAssetMode = "disk"
|
||||
if err := os.MkdirAll(filepath.Join(cfg.AdminWebDir, "assets"), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -123,6 +141,12 @@ func TestPreflightReportsMissingAdminAssetName(t *testing.T) {
|
||||
0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(cfg.AdminWebDir, "admin-build.json"), []byte(`{"buildId":"dev"}`), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(cfg.AdminWebDir, "asset-manifest.json"), []byte(`{"src/main.ts":{"file":"assets/missing.js","isEntry":true}}`), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
checks := Preflight(cfg)
|
||||
admin := checks[0]
|
||||
|
||||
@@ -4,9 +4,9 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"ymhut-box/server/unified-management/internal/adminassets"
|
||||
webassets "ymhut-box/server/unified-management/web"
|
||||
)
|
||||
|
||||
@@ -46,45 +46,37 @@ func Preflight(cfg *Config) []Check {
|
||||
checkSeedFile("legacy update-info", filepath.Join(cfg.UpdatePublicDir, "update-info.json"), []byte(defaultUpdateInfoJSON)),
|
||||
checkSeedFile("legacy media-types", filepath.Join(cfg.UpdatePublicDir, "media-types.json"), []byte(defaultMediaTypesJSON)),
|
||||
checkNoticeIndex("version notice index", filepath.Join(cfg.UpdateNoticeDir, "total.json")),
|
||||
checkAdminWebBuild("admin web dist", cfg.AdminWebDir, "admin/dist"),
|
||||
checkAdminWebBuild("admin web dist", cfg),
|
||||
checkWebBuild("portal web dist", cfg.PortalWebDir, "portal/dist"),
|
||||
checkWebBuild("setup web dist", cfg.SetupWebDir, "setup/dist"),
|
||||
}
|
||||
return checks
|
||||
}
|
||||
|
||||
var adminPreflightAssetPattern = regexp.MustCompile(`(?:src|href)=["'](/admin/assets/[^"'?#]+)`)
|
||||
func checkAdminWebBuild(name string, cfg *Config) Check {
|
||||
var status adminassets.Diagnostics
|
||||
path := cfg.AdminWebDir
|
||||
if cfg.AdminAssetMode == adminassets.ModeEmbedded {
|
||||
status = adminassets.ValidateEmbedded(AdminBuildID)
|
||||
path = "embedded:admin/dist"
|
||||
} else {
|
||||
status = adminassets.ValidateDisk(cfg.AdminWebDir, AdminBuildID)
|
||||
}
|
||||
if !status.Ready {
|
||||
message := status.ValidationError
|
||||
if cfg.AdminAssetMode == adminassets.ModeDisk {
|
||||
message = strings.ReplaceAll(message, cfg.AdminWebDir, ".")
|
||||
}
|
||||
return Check{Name: name, Status: "error", Path: path, Message: message}
|
||||
}
|
||||
return Check{
|
||||
Name: name, Status: "ok", Path: path,
|
||||
Message: fmt.Sprintf("%s assets; build %s; %d manifest entries", status.Mode, status.BuildID, status.ManifestEntries),
|
||||
}
|
||||
}
|
||||
|
||||
func checkAdminWebBuild(name, path, embedRoot string) Check {
|
||||
check := checkWebBuild(name, path, embedRoot)
|
||||
if check.Status != "ok" || strings.Contains(check.Message, "embedded frontend assets") {
|
||||
return check
|
||||
}
|
||||
index := filepath.Join(path, "index.html")
|
||||
data, err := os.ReadFile(index)
|
||||
if err != nil {
|
||||
return check
|
||||
}
|
||||
matches := adminPreflightAssetPattern.FindAllSubmatch(data, -1)
|
||||
if len(matches) == 0 {
|
||||
return Check{Name: name, Status: "error", Path: index, Message: "index.html does not reference any /admin/assets files"}
|
||||
}
|
||||
for _, match := range matches {
|
||||
assetPath := strings.TrimPrefix(string(match[1]), "/admin/")
|
||||
if strings.Contains(assetPath, "..") || strings.ContainsAny(assetPath, `\`) {
|
||||
return Check{Name: name, Status: "error", Path: index, Message: fmt.Sprintf("invalid admin asset reference %s", assetPath)}
|
||||
}
|
||||
info, statErr := os.Stat(filepath.Join(path, filepath.FromSlash(assetPath)))
|
||||
if statErr == nil && !info.IsDir() {
|
||||
continue
|
||||
}
|
||||
message := fmt.Sprintf("disk asset %s is missing", assetPath)
|
||||
if embeddedWebBuildOK(embedRoot) {
|
||||
return Check{Name: name, Status: "ok", Path: path, Message: message + "; using embedded frontend assets"}
|
||||
}
|
||||
return Check{Name: name, Status: "error", Path: filepath.Join(path, filepath.FromSlash(assetPath)), Message: message}
|
||||
}
|
||||
return check
|
||||
func defaultAdminAssetMode() string {
|
||||
return adminassets.DefaultMode()
|
||||
}
|
||||
|
||||
func checkDir(name, path string, create bool) Check {
|
||||
|
||||
Reference in New Issue
Block a user