mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-09-15 04:12:43 +00:00
Previously, only a single embedded Kubernetes API version could be specified, resulting in a lack of support for certain GVKs. To address this, the goal is to create and utilize a unified scheme that consolidates Kubernetes API definitions. As a preliminary step, the current method of loading API definitions will be improved.
148 lines
4.0 KiB
Go
148 lines
4.0 KiB
Go
// Copyright 2026 The Kubernetes Authors.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
// Package embeddedasset provides helpers that preserve the legacy generated
|
|
// asset API exposed by the OpenAPI packages.
|
|
package embeddedasset
|
|
|
|
import (
|
|
"bytes"
|
|
"compress/gzip"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// File describes one embedded asset.
|
|
type File struct {
|
|
// Path is the full slash-separated virtual path used to look up the asset.
|
|
Path string
|
|
Data []byte
|
|
Compressed bool
|
|
Size int64
|
|
Mode os.FileMode
|
|
ModTime time.Time
|
|
}
|
|
|
|
// Asset returns a fresh copy of the uncompressed asset data.
|
|
func Asset(file File, name string) ([]byte, error) {
|
|
if canonical(name) != file.Path {
|
|
return nil, fmt.Errorf("Asset %s not found", name)
|
|
}
|
|
if !file.Compressed {
|
|
return bytes.Clone(file.Data), nil
|
|
}
|
|
reader, err := gzip.NewReader(bytes.NewReader(file.Data))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("read %q: %w", name, err)
|
|
}
|
|
b, readErr := io.ReadAll(io.LimitReader(reader, file.Size+1))
|
|
closeErr := reader.Close()
|
|
if readErr != nil {
|
|
return nil, fmt.Errorf("read %q: %w", name, readErr)
|
|
}
|
|
if closeErr != nil {
|
|
return nil, fmt.Errorf("read %q: %w", name, closeErr)
|
|
}
|
|
if int64(len(b)) != file.Size {
|
|
return nil, fmt.Errorf("read %q: expected %d bytes, got %d", name, file.Size, len(b))
|
|
}
|
|
return b, nil
|
|
}
|
|
|
|
// MustAsset is like Asset but panics on error.
|
|
func MustAsset(file File, name string) []byte {
|
|
b, err := Asset(file, name)
|
|
if err != nil {
|
|
panic("asset: Asset(" + name + "): " + err.Error())
|
|
}
|
|
return b
|
|
}
|
|
|
|
// AssetInfo returns metadata for an embedded asset.
|
|
func AssetInfo(file File, name string) (os.FileInfo, error) {
|
|
if canonical(name) != file.Path {
|
|
return nil, fmt.Errorf("AssetInfo %s not found", name)
|
|
}
|
|
return fileInfo{file: file}, nil
|
|
}
|
|
|
|
// AssetDir returns the immediate children of a directory in the asset path.
|
|
func AssetDir(file File, name string) ([]string, error) {
|
|
name = canonical(name)
|
|
parts := strings.Split(file.Path, "/")
|
|
if name == "" {
|
|
return []string{parts[0]}, nil
|
|
}
|
|
dirParts := strings.Split(name, "/")
|
|
if len(dirParts) >= len(parts) {
|
|
return nil, fmt.Errorf("Asset %s not found", name)
|
|
}
|
|
for i := range dirParts {
|
|
if dirParts[i] != parts[i] {
|
|
return nil, fmt.Errorf("Asset %s not found", name)
|
|
}
|
|
}
|
|
return []string{parts[len(dirParts)]}, nil
|
|
}
|
|
|
|
// RestoreAsset restores an asset under dir.
|
|
func RestoreAsset(file File, dir, name string) error {
|
|
b, err := Asset(file, name)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
info, err := AssetInfo(file, name)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
target := filePath(dir, name)
|
|
if err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil {
|
|
return fmt.Errorf("create asset directory: %w", err)
|
|
}
|
|
if err := os.WriteFile(target, b, info.Mode()); err != nil {
|
|
return fmt.Errorf("write asset %q: %w", name, err)
|
|
}
|
|
if err := os.Chtimes(target, info.ModTime(), info.ModTime()); err != nil {
|
|
return fmt.Errorf("restore timestamps for asset %q: %w", name, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// RestoreAssets restores an asset or directory recursively under dir.
|
|
func RestoreAssets(file File, dir, name string) error {
|
|
children, err := AssetDir(file, name)
|
|
if err != nil {
|
|
return RestoreAsset(file, dir, name)
|
|
}
|
|
for _, child := range children {
|
|
if err := RestoreAssets(file, dir, filepath.Join(name, child)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type fileInfo struct {
|
|
file File
|
|
}
|
|
|
|
func (info fileInfo) Name() string { return path.Base(info.file.Path) }
|
|
func (info fileInfo) Size() int64 { return info.file.Size }
|
|
func (info fileInfo) Mode() os.FileMode { return info.file.Mode }
|
|
func (info fileInfo) ModTime() time.Time { return info.file.ModTime }
|
|
func (info fileInfo) IsDir() bool { return false }
|
|
func (info fileInfo) Sys() interface{} { return nil }
|
|
|
|
func canonical(name string) string {
|
|
return strings.ReplaceAll(name, "\\", "/")
|
|
}
|
|
|
|
func filePath(dir, name string) string {
|
|
return filepath.Join(append([]string{dir}, strings.Split(canonical(name), "/")...)...)
|
|
}
|