Files
Tosone 2cc50352ce refactor(clients): propagate request context through registry clients
Thread the caller context through ClientsFactory.New and
Clients.AuthToken so proxied blob and manifest requests keep
cancellation and trace propagation instead of starting from
context.Background(). Regenerate the mock and update callers and tests.
Document the intentionally background contexts in the one-shot builder
CLI.

Verification:
- go generate ./pkg/distribution/clients/... (no diff)
- go vet ./...
2026-10-03 16:20:36 +08:00

140 lines
4.2 KiB
Go

// Copyright 2023 sigma
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package builder
import (
"context"
"errors"
"fmt"
"io"
"log/slog"
"math/big"
"os"
"os/exec"
"path"
"github.com/dustin/go-humanize"
"github.com/go-sigma/sigma/pkg/utils"
)
const (
cache = "/opt/cache"
cacheIn = "/opt/cache_in"
cacheOut = "/opt/cache_out"
compressedCache = "cache.tgz"
)
// osOpen wraps os.Open for testability
var osOpen = os.Open
// osOpenFile wraps os.OpenFile for testability
var osOpenFile = os.OpenFile
// osErrNotExist wraps os.ErrNotExist for testability
var osErrNotExist = os.ErrNotExist
// initCache 下载并解压构建缓存
func (f *BuildFlow) initCache() error {
reader, err := f.api.getCache(context.Background(), f.BuilderID) // one-shot CLI: no caller context to propagate
if err != nil && !errors.Is(err, osErrNotExist) {
return err
}
if reader != nil {
file, err := osOpenFile(path.Join(cache, compressedCache), os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
_, err = io.Copy(file, reader)
if err != nil {
return err
}
err = file.Close()
if err != nil {
slog.Error("cache file close failed", "err", err)
}
}
if utils.IsFile(path.Join(cache, compressedCache)) {
slog.Info("start to decompress cache")
cmd := exec.Command("zstd", "-d", path.Join(cache, compressedCache), "-o", path.Join(home, "cache.tar")) // #nosec G204 -- command is fixed and paths are constrained to builder cache directories
err := cmd.Run()
if err != nil {
return fmt.Errorf("decompress cache failed: %v", err)
}
cmd = exec.Command("tar", "-xf", path.Join(home, "cache.tar"), "-C", home) // #nosec G204 -- command is fixed and paths are constrained to builder cache directories
err = cmd.Run()
if err != nil {
return fmt.Errorf("untar cache failed: %v", err)
}
_ = os.Remove(path.Join(home, "cache.tar"))
fileInfo, err := os.Stat(path.Join(cache, compressedCache))
if err != nil {
return fmt.Errorf("read compressed file failed: %v", err)
}
err = os.Rename(cacheOut, cacheIn)
if err != nil {
return fmt.Errorf("rename cache_out to cache_in failed: %v", err)
}
slog.Info("decompress cache success", "size", humanize.BigIBytes(big.NewInt(fileInfo.Size())))
}
var dirs = []string{cacheOut, cacheIn}
for _, dir := range dirs {
if !utils.IsDir(dir) {
err := os.MkdirAll(dir, 0755)
if err != nil {
return err
}
}
}
return nil
}
// exportCache 压缩并上传构建缓存
func (f *BuildFlow) exportCache() error {
slog.Info("start to compress cache")
cmd := exec.Command("tar", "-cf", path.Join("/tmp", "cache.tar"), "-C", cacheOut, ".") // #nosec G204 -- command is fixed and paths are constrained to builder cache directories
err := cmd.Run()
if err != nil {
return fmt.Errorf("tar cache failed: %v", err)
}
cmd = exec.Command("zstd", path.Join("/tmp", "cache.tar"), "-o", path.Join("/tmp", compressedCache)) // #nosec G204 -- command is fixed and paths are constrained to builder cache directories
err = cmd.Run()
if err != nil {
return fmt.Errorf("compress cache failed: %v", err)
}
_ = os.Remove(path.Join("/tmp", "cache.tar"))
err = os.Rename(path.Join("/tmp", compressedCache), path.Join(cache, compressedCache))
if err != nil {
return fmt.Errorf("move compressed file to dir failed: %v", err)
}
fileInfo, err := os.Stat(path.Join(cache, compressedCache))
if err != nil {
return fmt.Errorf("read compressed file failed: %v", err)
}
err = f.api.createCache(context.Background(), f.BuilderID, path.Join(cache, compressedCache)) // one-shot CLI: no caller context to propagate
if err != nil {
return fmt.Errorf("export cache to server failed: %v", err)
}
slog.Info("export cache success", "size", humanize.BigIBytes(big.NewInt(fileInfo.Size())))
return nil
}