133 lines
5.4 KiB
Go
133 lines
5.4 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"net/url"
|
|
"os"
|
|
"os/signal"
|
|
|
|
"browser.local/run/api"
|
|
"browser.local/run/config"
|
|
runruntime "browser.local/run/runtime"
|
|
"browser.local/run/spool"
|
|
)
|
|
|
|
func main() {
|
|
if handled, exitCode := runruntime.RunManagedProcessHelper(os.Args); handled {
|
|
os.Exit(exitCode)
|
|
}
|
|
cfg := config.Load()
|
|
configSource := "environment-or-build-defaults"
|
|
if cfg.Mode == "self-update-helper" {
|
|
log.Printf("RUN phase=self_update_helper status=starting manifestPresent=%t", os.Getenv("RUN_UPDATE_MANIFEST") != "")
|
|
if err := runruntime.ApplySelfUpdateManifest(os.Getenv("RUN_UPDATE_MANIFEST")); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Run self-update helper failed: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
log.Printf("RUN phase=self_update_helper status=complete")
|
|
return
|
|
}
|
|
if packageConfig, ok, err := config.LoadPackageConfigFromEnv(); err != nil {
|
|
fmt.Fprintf(os.Stderr, "invalid run package config: %v\n", err)
|
|
os.Exit(1)
|
|
} else if ok {
|
|
cfg = config.ApplyPackageConfig(cfg, packageConfig)
|
|
configSource = "RUN_PACKAGE_CONFIG"
|
|
} else if packageConfig, ok, err := config.LoadPackageConfigBesideExecutable(); err != nil {
|
|
fmt.Fprintf(os.Stderr, "invalid bundled run package config: %v\n", err)
|
|
os.Exit(1)
|
|
} else if ok {
|
|
cfg = config.ApplyPackageConfig(cfg, packageConfig)
|
|
configSource = "package-config-beside-executable"
|
|
}
|
|
logWorkerPhases := cfg.Mode == "worker"
|
|
if logWorkerPhases {
|
|
log.Printf("RUN phase=bootstrap status=starting pid=%d args=%d", os.Getpid(), len(os.Args))
|
|
log.Printf("RUN phase=config status=loaded source=%s mode=%s platform=%s endpoint=%s server=%s plugin=%s component=%s componentKey=%s version=%s", configSource, cfg.Mode, diagnosticPlatformAddress(cfg.PlatformURL), diagnosticValue(cfg.RunEndpointID), diagnosticValue(cfg.ServerInstanceID), diagnosticValue(cfg.PluginID), diagnosticValue(cfg.ComponentKind), diagnosticValue(cfg.ComponentKey), diagnosticValue(cfg.Version))
|
|
log.Printf("RUN phase=platform_client status=building platform=%s", diagnosticPlatformAddress(cfg.PlatformURL))
|
|
}
|
|
client, err := api.NewPlatformClient(cfg.PlatformURL)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "invalid platform URL: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
if logWorkerPhases {
|
|
log.Printf("RUN phase=platform_client status=ready base=%s", client.BaseURL())
|
|
}
|
|
|
|
if cfg.Mode == "worker" {
|
|
log.Printf("RUN phase=startup status=worker platform=%s endpoint=%s server=%s plugin=%s workspace=%s artifactQueue=%s maxJobs=%d", diagnosticPlatformAddress(cfg.PlatformURL), diagnosticValue(cfg.RunEndpointID), diagnosticValue(cfg.ServerInstanceID), diagnosticValue(cfg.PluginID), diagnosticValue(cfg.WorkspaceRoot), diagnosticValue(cfg.SpoolRoot), cfg.MaxJobs)
|
|
log.Printf("RUN phase=workspace_seed status=materializing present=%t workspace=%s componentKey=%s", cfg.WorkspaceSeed != "", diagnosticValue(cfg.WorkspaceRoot), diagnosticValue(cfg.ComponentKey))
|
|
if err := runruntime.MaterializeWorkspaceSeed(cfg); err != nil {
|
|
fmt.Fprintf(os.Stderr, "initialize plugin workspace assets: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
log.Printf("RUN phase=workspace_seed status=ready workspace=%s", diagnosticValue(cfg.WorkspaceRoot))
|
|
log.Printf("RUN phase=artifact_queue status=opening path=%s", diagnosticValue(cfg.SpoolRoot))
|
|
artifactQueue, err := spool.NewArtifactQueue(cfg.SpoolRoot)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "initialize artifact queue: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
log.Printf("RUN phase=artifact_queue status=ready path=%s", diagnosticValue(cfg.SpoolRoot))
|
|
log.Printf("RUN phase=log_spool status=opening path=%s", diagnosticValue(cfg.SpoolRoot))
|
|
logSpool, err := spool.NewLogSpool(cfg.SpoolRoot)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "initialize log spool: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
log.Printf("RUN phase=log_spool status=ready path=%s", diagnosticValue(cfg.SpoolRoot))
|
|
log.Printf("RUN phase=worker_init status=starting endpoint=%s", diagnosticValue(cfg.RunEndpointID))
|
|
worker, err := runruntime.NewWorker(
|
|
cfg,
|
|
client,
|
|
runruntime.WithProcessLogSink(&runruntime.SpoolLogSink{Spool: logSpool}),
|
|
runruntime.WithLifecycleArtifactHook(&runruntime.QueueArtifactHook{Queue: artifactQueue}),
|
|
)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "initialize worker: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
log.Printf("RUN phase=worker_init status=ready endpoint=%s", diagnosticValue(cfg.RunEndpointID))
|
|
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
|
|
defer stop()
|
|
log.Printf("RUN phase=worker_loop status=entering endpoint=%s", diagnosticValue(cfg.RunEndpointID))
|
|
if err := worker.Run(ctx); err != nil && err != context.Canceled && err != runruntime.ErrSelfUpdateRestartRequested {
|
|
fmt.Fprintf(os.Stderr, "run worker stopped: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
log.Printf("RUN phase=worker_loop status=stopped endpoint=%s", diagnosticValue(cfg.RunEndpointID))
|
|
return
|
|
}
|
|
|
|
summary := runruntime.SmokeSummary(cfg)
|
|
summary.PlatformURL = client.BaseURL()
|
|
|
|
if err := json.NewEncoder(os.Stdout).Encode(summary); err != nil {
|
|
fmt.Fprintf(os.Stderr, "encode smoke summary: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func diagnosticValue(value string) string {
|
|
if value == "" {
|
|
return "-"
|
|
}
|
|
return value
|
|
}
|
|
|
|
func diagnosticPlatformAddress(rawURL string) string {
|
|
parsed, err := url.Parse(rawURL)
|
|
if err != nil || parsed.Scheme == "" || parsed.Host == "" {
|
|
return "invalid"
|
|
}
|
|
address := parsed.Scheme + "://" + parsed.Host
|
|
if path := parsed.EscapedPath(); path != "" && path != "/" {
|
|
address += path
|
|
}
|
|
return address
|
|
}
|