cli(refactor): adjust local release logic for new project structure (#1355)

This commit is contained in:
dkeven 2025-05-28 23:47:16 +08:00 committed by GitHub
parent a034b37239
commit 4e7ba01bcd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 218 additions and 359 deletions

View file

@ -10,7 +10,7 @@ function command_exists() {
if [[ x"$VERSION" == x"" ]]; then
if [[ "$LOCAL_RELEASE" == "1" ]]; then
ts=$(date +%Y%m%d%H%M%S)
export VERSION="0.0.0-local-dev-$ts"
export VERSION="1.12.0-local-$ts"
echo "will build and use a local release of Olares with version: $VERSION"
echo ""
else
@ -79,47 +79,55 @@ if [[ x"$os_type" == x"Darwin" ]]; then
CLI_FILE="olares-cli-v${VERSION}_darwin_${ARCH}.tar.gz"
fi
if command_exists olares-cli && [[ "$(olares-cli -v | awk '{print $3}')" == "$VERSION" ]]; then
if [[ "$LOCAL_RELEASE" == "1" ]]; then
if ! command_exists olares-cli ; then
echo "error: LOCAL_RELEASE specified but olares-cli not found"
exit 1
fi
INSTALL_OLARES_CLI=$(which olares-cli)
echo "olares-cli already installed and is the expected version"
echo ""
else
if [[ ! -f ${CLI_FILE} ]]; then
CLI_URL="${cdn_url}/${CLI_FILE}"
echo "downloading Olares installer from ${CLI_URL} ..."
if command_exists olares-cli && [[ "$(olares-cli -v | awk '{print $3}')" == "$VERSION" ]]; then
INSTALL_OLARES_CLI=$(which olares-cli)
echo "olares-cli already installed and is the expected version"
echo ""
else
if [[ ! -f ${CLI_FILE} ]]; then
CLI_URL="${cdn_url}/${CLI_FILE}"
curl -Lo ${CLI_FILE} ${CLI_URL}
echo "downloading Olares installer from ${CLI_URL} ..."
echo ""
curl -Lo ${CLI_FILE} ${CLI_URL}
if [[ $? -ne 0 ]]; then
echo "error: failed to download Olares installer"
exit 1
else
echo "Olares installer ${VERSION} download complete!"
echo ""
fi
fi
INSTALL_OLARES_CLI="/usr/local/bin/olares-cli"
echo "unpacking Olares installer to $INSTALL_OLARES_CLI..."
echo ""
tar -zxf ${CLI_FILE} olares-cli && chmod +x olares-cli
if [[ x"$os_type" == x"Darwin" ]]; then
if [ ! -f "/usr/local/Cellar/olares" ]; then
current_user=$(whoami)
$sh_c "sudo mkdir -p /usr/local/Cellar/olares && sudo chown ${current_user}:staff /usr/local/Cellar/olares"
fi
$sh_c "mv olares-cli /usr/local/Cellar/olares/olares-cli && \
sudo rm -rf /usr/local/bin/olares-cli && \
sudo ln -s /usr/local/Cellar/olares/olares-cli $INSTALL_OLARES_CLI"
else
$sh_c "mv olares-cli $INSTALL_OLARES_CLI"
fi
if [[ $? -ne 0 ]]; then
echo "error: failed to download Olares installer"
echo "error: failed to unpack Olares installer"
exit 1
else
echo "Olares installer ${VERSION} download complete!"
echo ""
fi
fi
INSTALL_OLARES_CLI="/usr/local/bin/olares-cli"
echo "unpacking Olares installer to $INSTALL_OLARES_CLI..."
echo ""
tar -zxf ${CLI_FILE} olares-cli && chmod +x olares-cli
if [[ x"$os_type" == x"Darwin" ]]; then
if [ ! -f "/usr/local/Cellar/olares" ]; then
current_user=$(whoami)
$sh_c "sudo mkdir -p /usr/local/Cellar/olares && sudo chown ${current_user}:staff /usr/local/Cellar/olares"
fi
$sh_c "mv olares-cli /usr/local/Cellar/olares/olares-cli && \
sudo rm -rf /usr/local/bin/olares-cli && \
sudo ln -s /usr/local/Cellar/olares/olares-cli $INSTALL_OLARES_CLI"
else
$sh_c "mv olares-cli $INSTALL_OLARES_CLI"
fi
if [[ $? -ne 0 ]]; then
echo "error: failed to unpack Olares installer"
exit 1
fi
fi
PARAMS="--version $VERSION --base-dir $BASE_DIR"

View file

@ -48,7 +48,7 @@ func NewCmdRelease() *cobra.Command {
}
if version == "" {
version = fmt.Sprintf("0.0.0-local-dev-%s", time.Now().Format("20060102150405"))
version = fmt.Sprintf("1.12.0-local-%s", time.Now().Format("20060102150405"))
fmt.Printf("--version unspecified, using: %s\n", version)
time.Sleep(1 * time.Second)
}

View file

@ -4,6 +4,7 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"bytetrade.io/web3os/installer/pkg/core/util"
)
@ -21,13 +22,8 @@ func NewManager(olaresRepoRoot, distPath string) *Manager {
}
func (m *Manager) Package() error {
modules := []string{"frameworks", "libs", "apps", "third-party"}
buildTemplate := "build/installer"
// Create dist directory if not exists
if err := os.MkdirAll(m.distPath, 0755); err != nil {
return err
}
modules := []string{"apps", "framework", "daemon", "infrastructure", "platform", "vendor"}
buildTemplate := "build/base-package"
// Copy template files
if err := util.CopyDirectory(buildTemplate, m.distPath); err != nil {
@ -55,46 +51,47 @@ func (m *Manager) Package() error {
func (m *Manager) packageModule(mod string) error {
modPath := filepath.Join(m.olaresRepoRoot, mod)
entries, err := os.ReadDir(modPath)
if err != nil {
return err
}
for _, entry := range entries {
if !entry.IsDir() {
continue
err := filepath.Walk(modPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
if !strings.EqualFold(info.Name(), ".olares") {
return nil
}
app := entry.Name()
fmt.Printf("packaging %s ... \n", app)
fmt.Printf("packaging %s ... \n", path)
// Package user app charts
chartPath := filepath.Join(modPath, app, "config/user/helm-charts")
chartPath := filepath.Join(path, "config/user/helm-charts")
if err := util.CopyDirectoryIfExists(chartPath, filepath.Join(m.distPath, "wizard/config/apps")); err != nil {
return err
}
// Package cluster CRDs
crdPath := filepath.Join(modPath, app, "config/cluster/crds")
crdPath := filepath.Join(path, "config/cluster/crds")
if err := util.CopyDirectoryIfExists(crdPath, filepath.Join(m.distPath, "wizard/config/settings/templates/crds")); err != nil {
return err
}
// Package cluster deployments
deployPath := filepath.Join(modPath, app, "config/cluster/deploy")
deployPath := filepath.Join(path, "config/cluster/deploy")
if err := util.CopyDirectoryIfExists(deployPath, filepath.Join(m.distPath, "wizard/config/system/templates/deploy")); err != nil {
return err
}
}
return nil
return nil
})
return err
}
func (m *Manager) packageLauncher() error {
fmt.Println("packaging launcher ...")
return util.CopyDirectory(
filepath.Join(m.olaresRepoRoot, "frameworks/bfl/config/launcher"),
filepath.Join(m.olaresRepoRoot, "framework/bfl/.olares/config/launcher"),
filepath.Join(m.distPath, "wizard/config/launcher"),
)
}
@ -102,7 +99,7 @@ func (m *Manager) packageLauncher() error {
func (m *Manager) packageGPU() error {
fmt.Println("packaging gpu ...")
return util.CopyDirectory(
filepath.Join(m.olaresRepoRoot, "frameworks/GPU/config/gpu"),
filepath.Join(m.olaresRepoRoot, "framework/gpu/.olares/config/gpu"),
filepath.Join(m.distPath, "wizard/config/gpu"),
)
}

View file

@ -23,62 +23,44 @@ func NewBuilder(olaresRepoRoot, version, cdnURL string, ignoreMissingImages bool
olaresRepoRoot: olaresRepoRoot,
distPath: distPath,
version: version,
manifestManager: manifest.NewManager(olaresRepoRoot, cdnURL, ignoreMissingImages),
manifestManager: manifest.NewManager(olaresRepoRoot, distPath, cdnURL, ignoreMissingImages),
appManager: app.NewManager(olaresRepoRoot, distPath),
}
}
func (b *Builder) Build() (string, error) {
// Clean previous build
if err := os.RemoveAll(filepath.Join(b.olaresRepoRoot, ".dist")); err != nil {
if err := os.RemoveAll(b.distPath); err != nil {
return "", fmt.Errorf("failed to clean previous dist directory: %v", err)
}
// Create dist directory if not exists
if err := os.MkdirAll(b.distPath, 0755); err != nil {
return "", err
}
// Package apps
if err := b.appManager.Package(); err != nil {
return "", fmt.Errorf("package apps failed: %v", err)
}
// Build manifest
if err := b.manifestManager.Build(); err != nil {
return "", fmt.Errorf("manifest build failed: %v", err)
}
// Copy upgrade script, as the current build.sh does
if err := util.CopyFile(
filepath.Join(b.olaresRepoRoot, "scripts/upgrade.sh"),
filepath.Join(b.distPath, "upgrade.sh"),
); err != nil {
return "", fmt.Errorf("failed to copy upgrade script: %v", err)
// Generate manifest
if err := b.manifestManager.Generate(); err != nil {
return "", fmt.Errorf("failed to generate manifest: %v", err)
}
// archive the install-wizard
return b.createFinalPackage()
return b.archive()
}
func (b *Builder) createFinalPackage() (string, error) {
if err := os.RemoveAll(filepath.Join(b.distPath, "images")); err != nil {
return "", err
}
manifestSrc := filepath.Join(b.olaresRepoRoot, ".manifest/installation.manifest")
manifestDst := filepath.Join(b.distPath, "installation.manifest")
if err := util.MoveFile(manifestSrc, manifestDst); err != nil {
return "", err
}
imagesSrc := filepath.Join(b.olaresRepoRoot, ".manifest")
imagesDst := filepath.Join(b.distPath, "images")
if err := util.MoveDirectory(imagesSrc, imagesDst); err != nil {
return "", err
}
func (b *Builder) archive() (string, error) {
versionStr := "v" + b.version
files := []string{
filepath.Join(b.distPath, "wizard/config/settings/templates/terminus_cr.yaml"),
filepath.Join(b.distPath, "install.sh"),
filepath.Join(b.distPath, "install.ps1"),
filepath.Join(b.distPath, "joincluster.sh"),
}
for _, file := range files {

View file

@ -2,7 +2,6 @@ package manifest
import (
"bufio"
"bytetrade.io/web3os/installer/pkg/core/util"
"crypto/md5"
"fmt"
dockerref "github.com/containerd/containerd/reference/docker"
@ -11,127 +10,68 @@ import (
"os"
"path/filepath"
"regexp"
"sigs.k8s.io/kustomize/kyaml/yaml"
"sort"
"strings"
)
type Manager struct {
olaresRepoRoot string
cdnURL string
ignoreMissingImages bool
type OlaresManifest struct {
APIVersion string `yaml:"apiVersion"`
Target string `yaml:"target"`
Output OutputManifest `yaml:"output"`
}
func NewManager(olaresRepoRoot, cdnURL string, ignoreMissingImages bool) *Manager {
type OutputManifest struct {
Binaries []BinaryOutput `yaml:"binaries"`
Containers []ContainerOutput `yaml:"containers"`
}
type BinaryOutput struct {
ID string `yaml:"id"`
Name string `yaml:"name"`
AMD64 string `yaml:"amd64"`
ARM64 string `yaml:"arm64"`
}
type ContainerOutput struct {
Name string `yaml:"name"`
}
type Manager struct {
olaresRepoRoot string
distPath string
cdnURL string
ignoreMissingImages bool
extractedImages []string
extractedComponents []BinaryOutput
}
func NewManager(olaresRepoRoot, distPath, cdnURL string, ignoreMissingImages bool) *Manager {
return &Manager{
olaresRepoRoot: olaresRepoRoot,
distPath: distPath,
cdnURL: cdnURL,
ignoreMissingImages: ignoreMissingImages,
}
}
func (m *Manager) generateImageManifest() error {
manifestDir := filepath.Join(m.olaresRepoRoot, ".manifest")
if err := os.RemoveAll(manifestDir); err != nil {
func (m *Manager) Generate() error {
if err := m.scan(); err != nil {
return fmt.Errorf("failed to scan Olares repository for images and components: %v", err)
}
manifestPath := filepath.Join(m.distPath, "installation.manifest")
f, err := os.OpenFile(manifestPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
if err := os.MkdirAll(manifestDir, 0755); err != nil {
defer f.Close()
if err := m.writeComponents(f); err != nil {
return err
}
imageManifest := filepath.Join(manifestDir, "images.mf")
// Copy default base images
if err := util.CopyFile(
filepath.Join(m.olaresRepoRoot, "build/manifest/images"),
imageManifest,
); err != nil {
return err
}
if err := util.CopyFile(
filepath.Join(m.olaresRepoRoot, "build/manifest/images.node.mf"),
filepath.Join(manifestDir, "images.node.mf"),
); err != nil {
return err
}
// Find images in app modules
modules := []string{"frameworks", "libs", "apps", "third-party"}
tmpManifest := filepath.Join(manifestDir, "tmp.image.manifest")
for _, mod := range modules {
entries, err := os.ReadDir(filepath.Join(m.olaresRepoRoot, mod))
if err != nil {
continue
}
for _, entry := range entries {
if !entry.IsDir() {
continue
}
chartPath := filepath.Join(m.olaresRepoRoot, mod, entry.Name(), "config")
if err := m.findImagesInPath(chartPath, tmpManifest); err != nil {
return err
}
}
}
// Process temporary manifest
return m.processTemporaryManifest(tmpManifest, imageManifest)
}
func (m *Manager) generateDepsManifest() error {
depsDir := filepath.Join(m.olaresRepoRoot, ".dependencies")
if err := os.RemoveAll(depsDir); err != nil {
return err
}
if err := os.MkdirAll(depsDir, 0755); err != nil {
return err
}
// Copy components and pkgs
files := []string{"components", "pkgs"}
for _, file := range files {
if err := util.CopyFile(
filepath.Join(m.olaresRepoRoot, "build/manifest", file),
filepath.Join(depsDir, file),
); err != nil {
return err
}
}
return nil
}
func (m *Manager) Build() error {
if err := m.generateImageManifest(); err != nil {
return fmt.Errorf("image manifest generation failed: %v", err)
}
if err := m.generateDepsManifest(); err != nil {
return fmt.Errorf("deps manifest generation failed: %v", err)
}
// Move dependencies
if err := util.MoveDirectory(
filepath.Join(m.olaresRepoRoot, ".dependencies"),
filepath.Join(m.olaresRepoRoot, ".manifest"),
); err != nil {
return fmt.Errorf("failed to move dependencies: %v", err)
}
manifestFile := filepath.Join(m.olaresRepoRoot, ".manifest/installation.manifest")
// Process components and pkgs
deps := []string{"components", "pkgs"}
for _, dep := range deps {
if err := m.processDependencies(dep, manifestFile); err != nil {
return err
}
}
return m.processImages(manifestFile)
return m.writeImages(f)
}
func (m *Manager) downloadChecksum(name string) (string, error) {
@ -160,39 +100,22 @@ func (m *Manager) downloadChecksum(name string) (string, error) {
return strings.Fields(string(body))[0], nil
}
func (m *Manager) processDependencies(depType, manifestFile string) error {
file, err := os.Open(filepath.Join(m.olaresRepoRoot, ".manifest", depType))
if err != nil {
return err
}
defer file.Close()
manifestOut, err := os.OpenFile(manifestFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer manifestOut.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
if line == "" {
continue
func (m *Manager) writeComponents(out io.Writer) error {
for _, component := range m.extractedComponents {
var fileName, path string
fields := strings.Split(component.Name, ",")
fileName = strings.TrimSpace(fields[0])
if len(fields) > 1 {
path = strings.TrimSpace(fields[1])
} else {
path = "pkg/components"
}
md5Name := fmt.Sprintf("%x", md5.Sum([]byte(fileName)))
fields := strings.Split(line, ",")
if len(fields) < 5 {
return fmt.Errorf("invalid format: %s", line)
}
urlAMD64 := md5Name
urlARM64 := "arm64/" + md5Name
filename := fields[0]
path := fields[1]
name := fmt.Sprintf("%x", md5.Sum([]byte(filename)))
urlAMD64 := name
urlARM64 := "arm64/" + name
fmt.Printf("downloading md5 checksum for dependency %s, object: %s\n", filename, name)
fmt.Printf("downloading md5 checksum for dependency %s, object: %s\n", fileName, md5Name)
checksumAMD64, err := m.downloadChecksum(urlAMD64)
if err != nil {
@ -204,99 +127,100 @@ func (m *Manager) processDependencies(depType, manifestFile string) error {
return err
}
fmt.Fprintf(manifestOut, "%s,%s,%s,%s,%s,%s,%s,%s\n",
filename, path, depType, urlAMD64, checksumAMD64, urlARM64, checksumARM64, fields[4])
_, err = fmt.Fprintf(out, "%s,%s,%s,%s,%s,%s,%s,%s\n",
fileName, path, "", urlAMD64, checksumAMD64, urlARM64, checksumARM64, component.ID)
if err != nil {
return err
}
}
return scanner.Err()
return nil
}
func (m *Manager) processImages(manifestFile string) error {
path := "images"
manifestOut, err := os.OpenFile(manifestFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer manifestOut.Close()
imagesList, err := os.Open(filepath.Join(m.olaresRepoRoot, ".manifest/images.mf"))
if err != nil {
return err
}
defer imagesList.Close()
scanner := bufio.NewScanner(imagesList)
for scanner.Scan() {
line := scanner.Text()
if line == "" {
continue
}
func (m *Manager) writeImages(out io.Writer) error {
for _, image := range m.extractedImages {
// Generate MD5 hash of the image name
name := fmt.Sprintf("%x", md5.Sum([]byte(line)))
md5Name := fmt.Sprintf("%x", md5.Sum([]byte(image)))
// Define URLs for both architectures
urlAMD64 := name + ".tar.gz"
urlARM64 := "arm64/" + name + ".tar.gz"
urlAMD64 := md5Name + ".tar.gz"
urlARM64 := "arm64/" + md5Name + ".tar.gz"
fmt.Printf("downloading checksum for image %s, object: %s\n", line, urlAMD64)
fmt.Printf("downloading checksum for image %s, object: %s\n", image, md5Name)
checksumAMD64, err := m.downloadChecksum(name)
checksumAMD64, err := m.downloadChecksum(md5Name)
if err != nil {
return fmt.Errorf("failed to download AMD64 checksum for %s: %v", line, err)
return fmt.Errorf("failed to download AMD64 checksum for %s: %v", image, err)
}
if checksumAMD64 == "" {
if m.ignoreMissingImages {
fmt.Printf("skipping image %s due to missing checksum\n", line)
fmt.Printf("skipping image %s due to missing checksum\n", image)
continue
}
return fmt.Errorf("got empty checksum for image %s", line)
return fmt.Errorf("got empty checksum for image %s", image)
}
checksumARM64, err := m.downloadChecksum("arm64/" + name)
checksumARM64, err := m.downloadChecksum("arm64/" + md5Name)
if err != nil {
return fmt.Errorf("failed to download ARM64 checksum for %s: %v", line, err)
return fmt.Errorf("failed to download ARM64 checksum for %s: %v", image, err)
}
// Write to manifest file
_, err = fmt.Fprintf(manifestOut, "%s.tar.gz,%s,%s,%s,%s,%s,%s,%s\n",
name, path, "images.mf", urlAMD64, checksumAMD64, urlARM64, checksumARM64, line)
_, err = fmt.Fprintf(out, "%s.tar.gz,%s,%s,%s,%s,%s,%s,%s\n",
md5Name, "images", "images.mf", urlAMD64, checksumAMD64, urlARM64, checksumARM64, image)
if err != nil {
return fmt.Errorf("failed to write to manifest file: %v", err)
}
}
return scanner.Err()
return nil
}
func (m *Manager) findImagesInPath(path string, tmpManifest string) error {
// Open temporary manifest file for appending
tmpFile, err := os.OpenFile(tmpManifest, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer tmpFile.Close()
func (m *Manager) scan() error {
var images []string
uniqueComponents := make(map[string]BinaryOutput)
// Walk through all yaml files in the path
err = filepath.Walk(path, func(filePath string, info os.FileInfo, err error) error {
err := filepath.Walk(m.olaresRepoRoot, func(filePath string, info os.FileInfo, err error) error {
if err != nil {
if os.IsNotExist(err) {
relPath, _ := filepath.Rel(m.olaresRepoRoot, filePath)
fmt.Printf("skipping non existing path: %s\n", relPath)
return nil
}
return err
}
// Only process yaml files
// shortcut to Olares manifest file
if strings.EqualFold(info.Name(), "olares.yaml") {
content, err := os.ReadFile(filePath)
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
olaresManifest := &OlaresManifest{}
err = yaml.Unmarshal(content, olaresManifest)
if err != nil {
return fmt.Errorf("failed to unmarshal olares manifest %s: %v", filePath, err)
}
for _, c := range olaresManifest.Output.Containers {
images = append(images, c.Name)
}
for _, b := range olaresManifest.Output.Binaries {
uniqueComponents[b.ID] = b
}
return nil
}
// extract image from ordinary kubernetes yaml files
if !info.IsDir() && (strings.HasSuffix(filePath, ".yaml") || strings.HasSuffix(filePath, ".yml")) {
targetFile, err := os.Open(filePath)
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
defer targetFile.Close()
relPath, _ := filepath.Rel(m.olaresRepoRoot, filePath)
scanner := bufio.NewScanner(targetFile)
for scanner.Scan() {
line := scanner.Text()
@ -306,97 +230,45 @@ func (m *Manager) findImagesInPath(path string, tmpManifest string) error {
image := strings.TrimSpace(strings.TrimPrefix(strings.TrimSpace(line), "image:"))
image = strings.Trim(image, "'")
image = strings.Trim(image, "\"")
// probably some other config yaml
// instead of a container spec
if image == "" {
fmt.Printf("skipping empty image key in file: %s, line: %s\n", relPath, line)
continue
}
image, err = m.patchImage(image)
if err != nil {
return fmt.Errorf("failed to patch image %s: %v", image, err)
}
if _, err := dockerref.ParseDockerRef(image); err != nil {
fmt.Printf("skipping invalid image key: %s in file: %s, line: %s\n", image, relPath, line)
continue
}
// Skip specific images
if strings.Contains(image, "nitro") || strings.Contains(image, "orion") {
fmt.Printf("skipping image %s in file: %s, line: %s\n", image, relPath, line)
continue
}
fmt.Printf("found image %s in file %s\n", image, relPath)
// Write image to temporary manifest
if _, err := fmt.Fprintln(tmpFile, image); err != nil {
return err
}
images = append(images, image)
}
}
return nil
})
return err
}
func (m *Manager) processTemporaryManifest(tmpManifest, imageManifest string) error {
// Read temporary manifest
tmpContent, err := os.ReadFile(tmpManifest)
if err != nil {
return err
}
// Create a map to store unique images
uniqueImages := make(map[string]struct{})
// remove this logic for now
// to maintain a same order as the one
// built from shell script
// Add existing images from image manifest
//existingContent, err := os.ReadFile(imageManifest)
//if err != nil {
// return err
//}
//for _, line := range strings.Split(string(existingContent), "\n") {
// if line = strings.TrimSpace(line); line != "" {
// uniqueImages[line] = struct{}{}
// }
//}
// Add new images from temporary manifest
for _, line := range strings.Split(string(tmpContent), "\n") {
if line = strings.TrimSpace(line); line != "" {
uniqueImages[line] = struct{}{}
}
}
// Write unique images back to image manifest
manifestFile, err := os.OpenFile(imageManifest, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
return err
}
defer manifestFile.Close()
// Convert map to sorted slice for consistent output
var images []string
for image := range uniqueImages {
images = append(images, image)
}
sort.Strings(images)
// Write sorted images to manifest
for _, image := range images {
if _, err := fmt.Fprintln(manifestFile, image); err != nil {
return err
image = strings.TrimSpace(image)
if image == "" {
continue
}
image, err = m.patchImage(image)
if err != nil {
return fmt.Errorf("failed to patch image %s: %v", image, err)
}
if _, err := dockerref.ParseDockerRef(image); err != nil {
continue
}
uniqueImages[image] = struct{}{}
}
// Clean up temporary manifest
return os.Remove(tmpManifest)
var sortedImages []string
for image := range uniqueImages {
sortedImages = append(sortedImages, image)
}
sort.Strings(sortedImages)
m.extractedImages = sortedImages
for _, component := range uniqueComponents {
m.extractedComponents = append(m.extractedComponents, component)
}
return nil
}
// Helper function to patch extracted image name
@ -407,7 +279,7 @@ func (m *Manager) patchImage(image string) (string, error) {
if !strings.Contains(image, backupServerImageVersionTpl) {
return image, nil
}
backupConfigPath := filepath.Join(m.olaresRepoRoot, "frameworks/backup-server/config/cluster/deploy/backup_server.yaml")
backupConfigPath := filepath.Join(m.olaresRepoRoot, "framework/backup-server/.olares/config/cluster/deploy/backup_server.yaml")
content, err := os.ReadFile(backupConfigPath)
if err != nil {
return "", err