mirror of
https://github.com/DeBrosOfficial/orama.git
synced 2026-03-17 13:36:57 +00:00
- Deleted redeploy.sh, which handled redeployment to nodes in devnet/testnet environments. - Removed upgrade-nodes.sh, responsible for rolling upgrades of nodes. - Eliminated upload-source-fanout.sh, which uploaded source archives to nodes in parallel. - Removed upload-source.sh, used for uploading and extracting source archives to VPS nodes.
270 lines
5.9 KiB
Go
270 lines
5.9 KiB
Go
package build
|
|
|
|
import (
|
|
"archive/tar"
|
|
"compress/gzip"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// Manifest describes the contents of a binary archive.
|
|
type Manifest struct {
|
|
Version string `json:"version"`
|
|
Commit string `json:"commit"`
|
|
Date string `json:"date"`
|
|
Arch string `json:"arch"`
|
|
Checksums map[string]string `json:"checksums"` // filename -> sha256
|
|
}
|
|
|
|
// generateManifest creates the manifest with SHA256 checksums of all binaries.
|
|
func (b *Builder) generateManifest() (*Manifest, error) {
|
|
m := &Manifest{
|
|
Version: b.version,
|
|
Commit: b.commit,
|
|
Date: b.date,
|
|
Arch: b.flags.Arch,
|
|
Checksums: make(map[string]string),
|
|
}
|
|
|
|
entries, err := os.ReadDir(b.binDir)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, entry := range entries {
|
|
if entry.IsDir() {
|
|
continue
|
|
}
|
|
path := filepath.Join(b.binDir, entry.Name())
|
|
hash, err := sha256File(path)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to hash %s: %w", entry.Name(), err)
|
|
}
|
|
m.Checksums[entry.Name()] = hash
|
|
}
|
|
|
|
return m, nil
|
|
}
|
|
|
|
// createArchive creates the tar.gz archive from the build directory.
|
|
func (b *Builder) createArchive(outputPath string, manifest *Manifest) error {
|
|
fmt.Printf("\nCreating archive: %s\n", outputPath)
|
|
|
|
// Write manifest.json to tmpDir
|
|
manifestData, err := json.MarshalIndent(manifest, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := os.WriteFile(filepath.Join(b.tmpDir, "manifest.json"), manifestData, 0644); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Create output file
|
|
f, err := os.Create(outputPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
gw := gzip.NewWriter(f)
|
|
defer gw.Close()
|
|
|
|
tw := tar.NewWriter(gw)
|
|
defer tw.Close()
|
|
|
|
// Add bin/ directory
|
|
if err := addDirToTar(tw, b.binDir, "bin"); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Add systemd/ directory
|
|
systemdDir := filepath.Join(b.tmpDir, "systemd")
|
|
if _, err := os.Stat(systemdDir); err == nil {
|
|
if err := addDirToTar(tw, systemdDir, "systemd"); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Add packages/ directory if it exists
|
|
packagesDir := filepath.Join(b.tmpDir, "packages")
|
|
if _, err := os.Stat(packagesDir); err == nil {
|
|
if err := addDirToTar(tw, packagesDir, "packages"); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Add manifest.json
|
|
if err := addFileToTar(tw, filepath.Join(b.tmpDir, "manifest.json"), "manifest.json"); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Print summary
|
|
fmt.Printf(" bin/: %d binaries\n", len(manifest.Checksums))
|
|
fmt.Printf(" systemd/: namespace templates\n")
|
|
fmt.Printf(" manifest: v%s (%s) linux/%s\n", manifest.Version, manifest.Commit, manifest.Arch)
|
|
|
|
info, err := f.Stat()
|
|
if err == nil {
|
|
fmt.Printf(" size: %s\n", formatBytes(info.Size()))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// addDirToTar adds all files in a directory to the tar archive under the given prefix.
|
|
func addDirToTar(tw *tar.Writer, srcDir, prefix string) error {
|
|
return filepath.Walk(srcDir, func(path string, info os.FileInfo, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Calculate relative path
|
|
relPath, err := filepath.Rel(srcDir, path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
tarPath := filepath.Join(prefix, relPath)
|
|
|
|
if info.IsDir() {
|
|
header := &tar.Header{
|
|
Name: tarPath + "/",
|
|
Mode: 0755,
|
|
Typeflag: tar.TypeDir,
|
|
}
|
|
return tw.WriteHeader(header)
|
|
}
|
|
|
|
return addFileToTar(tw, path, tarPath)
|
|
})
|
|
}
|
|
|
|
// addFileToTar adds a single file to the tar archive.
|
|
func addFileToTar(tw *tar.Writer, srcPath, tarPath string) error {
|
|
f, err := os.Open(srcPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
info, err := f.Stat()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
header := &tar.Header{
|
|
Name: tarPath,
|
|
Size: info.Size(),
|
|
Mode: int64(info.Mode()),
|
|
}
|
|
|
|
if err := tw.WriteHeader(header); err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = io.Copy(tw, f)
|
|
return err
|
|
}
|
|
|
|
// sha256File computes the SHA256 hash of a file.
|
|
func sha256File(path string) (string, error) {
|
|
f, err := os.Open(path)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer f.Close()
|
|
|
|
h := sha256.New()
|
|
if _, err := io.Copy(h, f); err != nil {
|
|
return "", err
|
|
}
|
|
return hex.EncodeToString(h.Sum(nil)), nil
|
|
}
|
|
|
|
// downloadFile downloads a URL to a local file path.
|
|
func downloadFile(url, destPath string) error {
|
|
client := &http.Client{Timeout: 5 * time.Minute}
|
|
resp, err := client.Get(url)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to download %s: %w", url, err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
return fmt.Errorf("download %s returned status %d", url, resp.StatusCode)
|
|
}
|
|
|
|
f, err := os.Create(destPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
_, err = io.Copy(f, resp.Body)
|
|
return err
|
|
}
|
|
|
|
// extractFileFromTarball extracts a single file from a tar.gz archive.
|
|
func extractFileFromTarball(tarPath, targetFile, destPath string) error {
|
|
f, err := os.Open(tarPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
gr, err := gzip.NewReader(f)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer gr.Close()
|
|
|
|
tr := tar.NewReader(gr)
|
|
for {
|
|
header, err := tr.Next()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Match the target file (strip leading ./ if present)
|
|
name := strings.TrimPrefix(header.Name, "./")
|
|
if name == targetFile {
|
|
out, err := os.OpenFile(destPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0755)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer out.Close()
|
|
|
|
if _, err := io.Copy(out, tr); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
return fmt.Errorf("file %s not found in archive %s", targetFile, tarPath)
|
|
}
|
|
|
|
// formatBytes formats bytes into a human-readable string.
|
|
func formatBytes(b int64) string {
|
|
const unit = 1024
|
|
if b < unit {
|
|
return fmt.Sprintf("%d B", b)
|
|
}
|
|
div, exp := int64(unit), 0
|
|
for n := b / unit; n >= unit; n /= unit {
|
|
div *= unit
|
|
exp++
|
|
}
|
|
return fmt.Sprintf("%.1f %cB", float64(b)/float64(div), "KMGTPE"[exp])
|
|
}
|