github.com/operator-framework/operator-lifecycle-manager@v0.30.0/util/cpb/main.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 8 "github.com/operator-framework/operator-registry/pkg/lib/bundle" 9 "github.com/otiai10/copy" 10 "github.com/spf13/cobra" 11 "gopkg.in/yaml.v2" 12 ) 13 14 func main() { 15 if err := rootCmd.Execute(); err != nil { 16 fmt.Println(err) 17 os.Exit(1) 18 } 19 } 20 21 var rootCmd = &cobra.Command{ 22 Use: "cpb [output directory]", 23 Short: "Copy bundle content", 24 Long: `Copy bundle metadata and manifests into an output directory. 25 Copy traverses the filesystem from the current directory down 26 until it finds an annotations.yaml representing the bundle's metadata. 27 From there, it copies the annotations.yaml file and manifests into the 28 specified output directory`, 29 Run: func(cmd *cobra.Command, args []string) { 30 dest := "./bundle" 31 if len(args) > 1 { 32 // Get the destination position argument 33 dest = args[0] 34 } 35 36 if err := copyBundle(dest); err != nil { 37 fmt.Println(err) 38 os.Exit(1) 39 } 40 }, 41 } 42 43 func copyBundle(dest string) error { 44 // Find the manifest directory 45 m, err := getMetadata() 46 if err != nil { 47 return fmt.Errorf("error finding metadata directory: %s", err) 48 } 49 50 fmt.Printf("%v\n", m) 51 52 return m.copy(dest) 53 } 54 55 type metadata struct { 56 annotationsFile string 57 manifestDir string 58 } 59 60 func (m *metadata) copy(dest string) error { 61 // Copy the annotations file 62 path := filepath.Join(dest, "metadata/annotations.yaml") 63 if err := copy.Copy(m.annotationsFile, path); err != nil { 64 return err 65 } 66 67 // Copy manifest dir 68 path = filepath.Join(dest, "manifests") 69 if err := os.MkdirAll(path, os.ModePerm); err != nil { 70 return err 71 } 72 if err := copy.Copy(m.manifestDir, path); err != nil { 73 return err 74 } 75 76 return nil 77 } 78 79 func getMetadata() (m *metadata, err error) { 80 // Create default metadata 81 m = &metadata{ 82 annotationsFile: "/metadata/annotations.yaml", 83 manifestDir: "/manifests", 84 } 85 86 // Exclude device filesystems and pseudo filesystems from filesystems looking for metadata 87 excludeDir := []string{ 88 "/dev", 89 "/proc", 90 "/sys", 91 } 92 93 // Traverse the filesystem looking for metadata 94 err = filepath.Walk(".", func(path string, info os.FileInfo, err error) error { 95 if err != nil { 96 fmt.Printf("prevent panic by handling failure accessing a path %q: %v\n", path, err) 97 return nil 98 } 99 if info.IsDir() { 100 absPath, err := filepath.Abs(path) 101 if err != nil { 102 fmt.Printf("couldn't get the absolute path %q: %v\n", path, err) 103 return nil 104 } 105 for _, v := range excludeDir { 106 if v == absPath { 107 fmt.Printf("skipping all files in the dir: %+v \n", absPath) 108 return filepath.SkipDir 109 } 110 } 111 fmt.Printf("skipping a dir without errors: %+v \n", absPath) 112 return nil 113 } 114 if info.Name() != bundle.AnnotationsFile { 115 return nil 116 } 117 m.annotationsFile = path 118 119 // Unmarshal metadata 120 content, err := os.ReadFile(path) 121 if err != nil { 122 return fmt.Errorf("couldn't get content of annotations.yaml file: %s", path) 123 } 124 125 annotations := bundle.AnnotationMetadata{} 126 if err := yaml.Unmarshal(content, &annotations); err != nil { 127 return err 128 } 129 130 if annotations.Annotations == nil { 131 return fmt.Errorf("annotations.yaml file unmarshalling failed: %s", path) 132 } 133 134 if manifestDir, ok := annotations.Annotations[bundle.ManifestsLabel]; ok { 135 m.manifestDir = manifestDir 136 } 137 138 // Skip the remainder of files in the directory 139 return filepath.SkipDir 140 }) 141 142 if err != nil { 143 m = nil 144 } 145 146 return 147 }