134 lines
3.0 KiB
Go
Executable File
134 lines
3.0 KiB
Go
Executable File
package provision
|
|
|
|
import (
|
|
"archive/tar"
|
|
"compress/gzip"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"zlh-agent/internal/state"
|
|
)
|
|
|
|
// InstallJava downloads and extracts the Java runtime, then creates a stable
|
|
// symlink at /opt/zlh/runtime/java → <version>/bin/java
|
|
func InstallJava(cfg state.Config) error {
|
|
if cfg.JavaPath == "" {
|
|
return fmt.Errorf("java_path missing in config")
|
|
}
|
|
|
|
url := BuildArtifactURL(cfg.JavaPath)
|
|
resp, err := http.Get(url)
|
|
if err != nil {
|
|
return fmt.Errorf("download java from %s: %w", url, err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
return fmt.Errorf("download java: status %s", resp.Status)
|
|
}
|
|
|
|
runtimeRoot := JavaDir(cfg)
|
|
if err := os.MkdirAll(runtimeRoot, 0755); err != nil {
|
|
return fmt.Errorf("create java root dir: %w", err)
|
|
}
|
|
|
|
// Extract into temp directory
|
|
tmpDir := filepath.Join(runtimeRoot, "tmp-extract")
|
|
_ = os.RemoveAll(tmpDir)
|
|
if err := os.MkdirAll(tmpDir, 0755); err != nil {
|
|
return fmt.Errorf("create tmp java dir: %w", err)
|
|
}
|
|
|
|
if err := extractTarGz(resp.Body, tmpDir); err != nil {
|
|
return fmt.Errorf("extract java: %w", err)
|
|
}
|
|
|
|
// Detect root folder (JDK name)
|
|
entries, err := os.ReadDir(tmpDir)
|
|
if err != nil {
|
|
return fmt.Errorf("read tmp java dir: %w", err)
|
|
}
|
|
if len(entries) != 1 || !entries[0].IsDir() {
|
|
return fmt.Errorf("java extract: unexpected folder layout in %s", tmpDir)
|
|
}
|
|
|
|
rootFolder := entries[0].Name()
|
|
versionPath := filepath.Join(runtimeRoot, rootFolder)
|
|
|
|
// Move extracted Java dir into runtime/
|
|
_ = os.RemoveAll(versionPath)
|
|
if err := os.Rename(filepath.Join(tmpDir, rootFolder), versionPath); err != nil {
|
|
return fmt.Errorf("move java folder: %w", err)
|
|
}
|
|
|
|
// Cleanup temp
|
|
_ = os.RemoveAll(tmpDir)
|
|
|
|
// Make java binary executable
|
|
javaBin := filepath.Join(versionPath, "bin", "java")
|
|
if err := os.Chmod(javaBin, 0755); err != nil {
|
|
return fmt.Errorf("chmod java binary: %w", err)
|
|
}
|
|
|
|
// Symlink: java → <version>/bin/java
|
|
linkPath := filepath.Join(JavaRoot, "java")
|
|
_ = os.Remove(linkPath)
|
|
if err := os.Symlink(javaBin, linkPath); err != nil {
|
|
return fmt.Errorf("create java symlink: %w", err)
|
|
}
|
|
|
|
fmt.Println("[java] Installed runtime:", versionPath, "->", linkPath)
|
|
return nil
|
|
}
|
|
|
|
// extractTarGz restores the original signature returning only "error"
|
|
func extractTarGz(r io.Reader, dest string) error {
|
|
gz, err := gzip.NewReader(r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer gz.Close()
|
|
|
|
tr := tar.NewReader(gz)
|
|
|
|
for {
|
|
hdr, err := tr.Next()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
target := filepath.Join(dest, hdr.Name)
|
|
|
|
switch hdr.Typeflag {
|
|
|
|
case tar.TypeDir:
|
|
if err := os.MkdirAll(target, 0755); err != nil {
|
|
return err
|
|
}
|
|
|
|
case tar.TypeReg:
|
|
if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil {
|
|
return err
|
|
}
|
|
|
|
f, err := os.Create(target)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if _, err := io.Copy(f, tr); err != nil {
|
|
f.Close()
|
|
return err
|
|
}
|
|
f.Close()
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|