github.com/Racer159/jackal@v0.32.7-0.20240401174413-0bd2339e4f2e/src/pkg/packager/sources/utils.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // SPDX-FileCopyrightText: 2021-Present The Jackal Authors 3 4 // Package sources contains core implementations of the PackageSource interface. 5 package sources 6 7 import ( 8 "fmt" 9 "io" 10 "os" 11 "path/filepath" 12 "strings" 13 14 "github.com/Racer159/jackal/src/config" 15 "github.com/Racer159/jackal/src/pkg/layout" 16 "github.com/Racer159/jackal/src/pkg/zoci" 17 "github.com/Racer159/jackal/src/types" 18 "github.com/defenseunicorns/pkg/helpers" 19 goyaml "github.com/goccy/go-yaml" 20 "github.com/mholt/archiver/v3" 21 ) 22 23 // GetValidPackageExtensions returns the valid package extensions. 24 func GetValidPackageExtensions() [2]string { 25 return [...]string{".tar.zst", ".tar"} 26 } 27 28 // IsValidFileExtension returns true if the filename has a valid package extension. 29 func IsValidFileExtension(filename string) bool { 30 for _, extension := range GetValidPackageExtensions() { 31 if strings.HasSuffix(filename, extension) { 32 return true 33 } 34 } 35 36 return false 37 } 38 39 func identifyUnknownTarball(path string) (string, error) { 40 if helpers.InvalidPath(path) { 41 return "", &os.PathError{Op: "open", Path: path, Err: os.ErrNotExist} 42 } 43 if filepath.Ext(path) != "" && IsValidFileExtension(path) { 44 return path, nil 45 } else if filepath.Ext(path) != "" && !IsValidFileExtension(path) { 46 return "", fmt.Errorf("%s is not a supported tarball format (%+v)", path, GetValidPackageExtensions()) 47 } 48 49 // rename to .tar.zst and check if it's a valid tar.zst 50 tzst := fmt.Sprintf("%s.tar.zst", path) 51 if err := os.Rename(path, tzst); err != nil { 52 return "", err 53 } 54 format, err := archiver.ByExtension(tzst) 55 if err != nil { 56 return "", err 57 } 58 _, ok := format.(*archiver.TarZstd) 59 if ok { 60 return tzst, nil 61 } 62 63 // rename to .tar and check if it's a valid tar 64 tb := fmt.Sprintf("%s.tar", path) 65 if err := os.Rename(tzst, tb); err != nil { 66 return "", err 67 } 68 format, err = archiver.ByExtension(tb) 69 if err != nil { 70 return "", err 71 } 72 _, ok = format.(*archiver.Tar) 73 if ok { 74 return tb, nil 75 } 76 77 return "", fmt.Errorf("%s is not a supported tarball format (%+v)", path, GetValidPackageExtensions()) 78 } 79 80 // RenameFromMetadata renames a tarball based on its metadata. 81 func RenameFromMetadata(path string) (string, error) { 82 var pkg types.JackalPackage 83 84 ext := filepath.Ext(path) 85 if ext == "" { 86 pathWithExt, err := identifyUnknownTarball(path) 87 if err != nil { 88 return "", err 89 } 90 path = pathWithExt 91 ext = filepath.Ext(path) 92 } 93 if ext == ".zst" { 94 ext = ".tar.zst" 95 } 96 97 if err := archiver.Walk(path, func(f archiver.File) error { 98 if f.Name() == layout.JackalYAML { 99 b, err := io.ReadAll(f) 100 if err != nil { 101 return err 102 } 103 if err := goyaml.Unmarshal(b, &pkg); err != nil { 104 return err 105 } 106 } 107 return nil 108 }); err != nil { 109 return "", err 110 } 111 112 if pkg.Metadata.Name == "" { 113 return "", fmt.Errorf("%q does not contain a jackal.yaml", path) 114 } 115 116 name := NameFromMetadata(&pkg, false) 117 118 name = fmt.Sprintf("%s%s", name, ext) 119 120 tb := filepath.Join(filepath.Dir(path), name) 121 122 return tb, os.Rename(path, tb) 123 } 124 125 // NameFromMetadata generates a name from a package's metadata. 126 func NameFromMetadata(pkg *types.JackalPackage, isSkeleton bool) string { 127 var name string 128 129 arch := config.GetArch(pkg.Metadata.Architecture, pkg.Build.Architecture) 130 131 if isSkeleton { 132 arch = zoci.SkeletonArch 133 } 134 135 switch pkg.Kind { 136 case types.JackalInitConfig: 137 name = fmt.Sprintf("jackal-init-%s", arch) 138 case types.JackalPackageConfig: 139 name = fmt.Sprintf("jackal-package-%s-%s", pkg.Metadata.Name, arch) 140 default: 141 name = fmt.Sprintf("jackal-%s-%s", strings.ToLower(string(pkg.Kind)), arch) 142 } 143 144 if pkg.Build.Differential { 145 name = fmt.Sprintf("%s-%s-differential-%s", name, pkg.Build.DifferentialPackageVersion, pkg.Metadata.Version) 146 } else if pkg.Metadata.Version != "" { 147 name = fmt.Sprintf("%s-%s", name, pkg.Metadata.Version) 148 } 149 150 return name 151 } 152 153 // GetInitPackageName returns the formatted name of the init package. 154 func GetInitPackageName() string { 155 // No package has been loaded yet so lookup GetArch() with no package info 156 arch := config.GetArch() 157 return fmt.Sprintf("jackal-init-%s-%s.tar.zst", arch, config.CLIVersion) 158 } 159 160 // PkgSuffix returns a package suffix based on whether it is uncompressed or not. 161 func PkgSuffix(uncompressed bool) (suffix string) { 162 suffix = ".tar.zst" 163 if uncompressed { 164 suffix = ".tar" 165 } 166 return suffix 167 }