get.porter.sh/porter@v1.3.0/pkg/porter/cnab.go (about) 1 package porter 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "path/filepath" 8 9 "get.porter.sh/porter/pkg/build" 10 cnabprovider "get.porter.sh/porter/pkg/cnab/provider" 11 "get.porter.sh/porter/pkg/config" 12 "get.porter.sh/porter/pkg/portercontext" 13 ) 14 15 const ( 16 // DockerDriver is the name of the Docker driver. 17 DockerDriver = cnabprovider.DriverNameDocker 18 19 // DebugDriver is the name of the Debug driver. 20 DebugDriver = cnabprovider.DriverNameDebug 21 22 // DefaultDriver is the name of the default driver (Docker). 23 DefaultDriver = DockerDriver 24 ) 25 26 type BundleDefinitionOptions struct { 27 // File path to the porter manifest. Defaults to the bundle in the current directory. 28 File string 29 30 // CNABFile is the path to the bundle.json file. Cannot be specified at the same time as the porter manifest or a tag. 31 CNABFile string 32 33 // RelocationMapping is the path to the relocation-mapping.json file, if one exists. Populated only for published bundles 34 RelocationMapping string 35 36 // ReferenceSet indicates whether a bundle reference is present, to determine whether or not to default bundle files 37 ReferenceSet bool 38 39 // Dir represents the build context directory containing bundle assets 40 Dir string 41 42 // AutoBuildDisabled indicates that Porter should not check if the bundle 43 // definition has changed since it was last built and automatically build before 44 // executing the requested command. 45 AutoBuildDisabled bool 46 47 // PreserveTags keep the original tag name on referenced images. 48 PreserveTags bool 49 } 50 51 func (o *BundleDefinitionOptions) Validate(cxt *portercontext.Context) error { 52 var err error 53 54 if o.ReferenceSet { 55 return nil 56 } 57 58 // Resolve the proper build context directory 59 if o.Dir != "" { 60 _, err = cxt.FileSystem.IsDir(o.Dir) 61 if err != nil { 62 return fmt.Errorf("%q is not a valid directory: %w", o.Dir, err) 63 } 64 o.Dir = cxt.FileSystem.Abs(o.Dir) 65 } else { 66 // default to current working directory 67 o.Dir = cxt.Getwd() 68 } 69 70 if o.File != "" { 71 if !filepath.IsAbs(o.File) { 72 o.File = cxt.FileSystem.Abs(filepath.Join(o.Dir, o.File)) 73 } else { 74 o.File = cxt.FileSystem.Abs(o.File) 75 } 76 } 77 78 err = o.validateBundleFiles(cxt) 79 if err != nil { 80 return err 81 } 82 83 err = o.defaultBundleFiles(cxt) 84 if err != nil { 85 return err 86 } 87 88 // Enter the resolved build context directory after all defaults 89 // have been populated 90 cxt.Chdir(o.Dir) 91 return nil 92 } 93 94 // installationOptions are common options that apply to commands that use an installation 95 type installationOptions struct { 96 BundleDefinitionOptions 97 98 // Namespace of the installation. 99 Namespace string 100 101 // Name of the installation. Defaults to the name of the bundle. 102 Name string 103 } 104 105 // Validate prepares for an action and validates the options. 106 // For example, relative paths are converted to full paths and then checked that 107 // they exist and are accessible. 108 func (o *installationOptions) Validate(ctx context.Context, args []string, p *Porter) error { 109 err := o.validateInstallationName(args) 110 if err != nil { 111 return err 112 } 113 114 err = o.BundleDefinitionOptions.Validate(p.Context) 115 if err != nil { 116 return err 117 } 118 119 err = p.applyDefaultOptions(ctx, o) 120 if err != nil { 121 return err 122 } 123 124 return nil 125 } 126 127 // validateInstallationName grabs the installation name from the first positional argument. 128 func (o *installationOptions) validateInstallationName(args []string) error { 129 if len(args) == 1 { 130 o.Name = args[0] 131 } else if len(args) > 1 { 132 return fmt.Errorf("only one positional argument may be specified, the installation name, but multiple were received: %s", args) 133 } 134 135 return nil 136 } 137 138 // defaultBundleFiles defaults the porter manifest and the bundle.json files. 139 func (o *BundleDefinitionOptions) defaultBundleFiles(cxt *portercontext.Context) error { 140 if o.File != "" { // --file 141 o.defaultCNABFile() 142 } else if o.CNABFile != "" { // --cnab-file 143 // Nothing to default 144 } else { 145 defaultPath := filepath.Join(o.Dir, config.Name) 146 manifestExists, err := cxt.FileSystem.Exists(defaultPath) 147 if err != nil { 148 return fmt.Errorf("could not find a porter manifest at %s: %w", defaultPath, err) 149 } else if !manifestExists { 150 return nil 151 } 152 153 o.File = defaultPath 154 o.defaultCNABFile() 155 } 156 157 return nil 158 } 159 160 func (o *BundleDefinitionOptions) defaultCNABFile() { 161 o.CNABFile = filepath.Join(o.Dir, build.LOCAL_BUNDLE) 162 } 163 164 func (o *BundleDefinitionOptions) validateBundleFiles(cxt *portercontext.Context) error { 165 if o.File != "" && o.CNABFile != "" { 166 return errors.New("cannot specify both --file and --cnab-file") 167 } 168 169 err := o.validateFile(cxt) 170 if err != nil { 171 return err 172 } 173 174 err = o.validateCNABFile(cxt) 175 if err != nil { 176 return err 177 } 178 179 return nil 180 } 181 182 func (o *BundleDefinitionOptions) validateFile(cxt *portercontext.Context) error { 183 if o.File == "" { 184 return nil 185 } 186 187 // Verify the file can be accessed 188 if _, err := cxt.FileSystem.Stat(o.File); err != nil { 189 return fmt.Errorf("unable to access --file %s: %w", o.File, err) 190 } 191 192 return nil 193 } 194 195 // validateCNABFile converts the bundle file path to an absolute filepath and verifies that it exists. 196 func (o *BundleDefinitionOptions) validateCNABFile(cxt *portercontext.Context) error { 197 if o.CNABFile == "" { 198 return nil 199 } 200 201 originalPath := o.CNABFile 202 if !filepath.IsAbs(o.CNABFile) { 203 // Convert to an absolute filepath because runtime needs it that way 204 o.CNABFile = filepath.Join(cxt.Getwd(), o.CNABFile) 205 } 206 207 // Verify the file can be accessed 208 if _, err := cxt.FileSystem.Stat(o.CNABFile); err != nil { 209 // warn about the original relative path 210 return fmt.Errorf("unable to access --cnab-file %s: %w", originalPath, err) 211 } 212 213 return nil 214 }