github.com/criteo/command-launcher@v0.0.0-20230407142452-fb616f546e98/internal/pkg/default-package.go (about) 1 package pkg 2 3 import ( 4 "fmt" 5 "io" 6 "io/fs" 7 "os" 8 "path/filepath" 9 10 "github.com/criteo/command-launcher/internal/command" 11 "gopkg.in/yaml.v3" 12 ) 13 14 type defaultPackageManifest struct { 15 PkgName string `json:"pkgName" yaml:"pkgName"` 16 PkgVersion string `json:"version" yaml:"version"` 17 PkgCommands []*command.DefaultCommand `json:"cmds" yaml:"cmds"` 18 } 19 20 func (mf *defaultPackageManifest) Name() string { 21 return mf.PkgName 22 } 23 24 func (mf *defaultPackageManifest) Version() string { 25 return mf.PkgVersion 26 } 27 28 func (mf *defaultPackageManifest) Commands() []command.Command { 29 cmds := make([]command.Command, 0) 30 for _, cmd := range mf.PkgCommands { 31 //newCmd := cmd 32 cmds = append(cmds, cmd) 33 } 34 return cmds 35 } 36 37 type defaultPackage struct { 38 Manifest command.PackageManifest 39 // store the repository id, indicates which registry/repository that the package belongs to 40 repositoryID string 41 } 42 43 func (pkg *defaultPackage) Name() string { 44 return pkg.Manifest.Name() 45 } 46 47 func (pkg *defaultPackage) Version() string { 48 return pkg.Manifest.Version() 49 } 50 51 func (pkg *defaultPackage) Commands() []command.Command { 52 return pkg.Manifest.Commands() 53 } 54 55 func (pkg *defaultPackage) RepositoryID() string { 56 return pkg.repositoryID 57 } 58 59 func ReadManifest(file fs.File) (command.PackageManifest, error) { 60 stat, err := file.Stat() 61 if err != nil { 62 return nil, fmt.Errorf("cannot read the manifest file handle (%s)", err) 63 } 64 65 var payload = make([]byte, stat.Size()) 66 nb, err := file.Read(payload) 67 if err != nil && err != io.EOF || nb != int(stat.Size()) { 68 return nil, fmt.Errorf("cannot read the manifest (%s)", err) 69 } 70 71 var mf = defaultPackageManifest{} 72 // YAML is super set of json, should work with JSON as well 73 err = yaml.Unmarshal(payload, &mf) 74 if err != nil { 75 return nil, fmt.Errorf("cannot read the manifest content, it is neither a valid JSON nor YAML (%s)", err) 76 } 77 78 return &mf, nil 79 } 80 81 func (pkg *defaultPackage) RunSetup(pkgDir string) error { 82 return ExecSetupHookFromPackage(pkg, pkgDir) 83 } 84 85 func copyFolder(srcFolder string, dstFolder string) error { 86 info, err := os.Stat(srcFolder) 87 if err != nil { 88 return err 89 } 90 91 if err = os.MkdirAll(dstFolder, info.Mode()); err != nil { 92 return err 93 } 94 95 files, err := os.ReadDir(srcFolder) 96 if err != nil { 97 return err 98 } 99 100 for _, fd := range files { 101 src := filepath.Join(srcFolder, fd.Name()) 102 dst := filepath.Join(dstFolder, fd.Name()) 103 104 if fd.IsDir() { 105 if err = copyFolder(src, dst); err != nil { 106 return err 107 } 108 } else { 109 if err = copyFile(src, dst); err != nil { 110 return err 111 } 112 } 113 } 114 115 return nil 116 } 117 118 func copyFile(src string, dst string) error { 119 srcFile, err := os.Open(src) 120 if err != nil { 121 return err 122 } 123 defer srcFile.Close() 124 125 dstFile, err := os.Create(dst) 126 if err != nil { 127 return fmt.Errorf("file extraction failed: %s", err) 128 } 129 defer dstFile.Close() 130 131 if _, err = io.Copy(dstFile, srcFile); err != nil { 132 return err 133 } 134 135 srcInfo, err := os.Stat(src) 136 if err != nil { 137 return err 138 } 139 140 return os.Chmod(dst, srcInfo.Mode()) 141 } 142 143 func ExecSetupHookFromPackage(pkg command.PackageManifest, pkgDir string) error { 144 for _, c := range pkg.Commands() { 145 if c.Name() == "__setup__" && c.Type() == "system" { 146 if pkgDir != "" { 147 c.SetPackageDir(pkgDir) 148 } 149 // Execute the __setup__ hook 150 _, err := c.Execute(os.Environ()) 151 if err != nil { 152 return fmt.Errorf("setup hook of package %s failed to execute: %v", pkg.Name(), err) 153 } 154 return nil 155 } 156 } 157 return fmt.Errorf("no setup hook found in the package") 158 }