kcl-lang.io/kpm@v0.8.7-0.20240520061008-9fc4c5efc8c7/pkg/opt/opt.go (about) 1 // Copyright 2023 The KCL Authors. All rights reserved. 2 3 package opt 4 5 import ( 6 "io" 7 "net/url" 8 "os" 9 "path/filepath" 10 11 "github.com/hashicorp/go-version" 12 "kcl-lang.io/kcl-go/pkg/kcl" 13 "kcl-lang.io/kpm/pkg/errors" 14 "kcl-lang.io/kpm/pkg/path" 15 "kcl-lang.io/kpm/pkg/reporter" 16 "oras.land/oras-go/v2" 17 ) 18 19 // CompileOptions is the input options of 'kpm run'. 20 type CompileOptions struct { 21 isVendor bool 22 hasSettingsYaml bool 23 entries []string 24 noSumCheck bool 25 // Add a writer to control the output of the compiler. 26 writer io.Writer 27 *kcl.Option 28 } 29 30 type Option func(*CompileOptions) 31 32 // WithKclOption will add a kcl option to the compiler. 33 func WithKclOption(opt kcl.Option) Option { 34 return func(opts *CompileOptions) { 35 opts.Merge(opt) 36 } 37 } 38 39 // WithEntries will add entries to the compiler. 40 func WithEntries(entries []string) Option { 41 return func(opts *CompileOptions) { 42 opts.entries = append(opts.entries, entries...) 43 } 44 } 45 46 // WithEntry will add an entry to the compiler. 47 func WithVendor(isVendor bool) Option { 48 return func(opts *CompileOptions) { 49 opts.isVendor = isVendor 50 } 51 } 52 53 // WithNoSumCheck will set the 'no_sum_check' flag. 54 func WithNoSumCheck(is bool) Option { 55 return func(opts *CompileOptions) { 56 opts.noSumCheck = is 57 } 58 } 59 60 // WithLogWriter will set the log writer of the compiler. 61 func WithLogWriter(writer io.Writer) Option { 62 return func(opts *CompileOptions) { 63 opts.writer = writer 64 } 65 } 66 67 // DefaultCompileOptions returns a default CompileOptions. 68 func DefaultCompileOptions() *CompileOptions { 69 return &CompileOptions{ 70 writer: os.Stdout, 71 Option: kcl.NewOption(), 72 } 73 } 74 75 // SetNoSumCheck will set the 'no_sum_check' flag. 76 func (opts *CompileOptions) SetNoSumCheck(noSumCheck bool) { 77 opts.noSumCheck = noSumCheck 78 } 79 80 // NoSumCheck will return the 'no_sum_check' flag. 81 func (opts *CompileOptions) NoSumCheck() bool { 82 return opts.noSumCheck 83 } 84 85 // AddEntry will add a compile entry file to the compiler. 86 func (opts *CompileOptions) AddEntry(entry string) { 87 opts.entries = append(opts.entries, entry) 88 } 89 90 // SetLogWriter will set the log writer of the compiler. 91 func (opts *CompileOptions) SetLogWriter(writer io.Writer) { 92 opts.writer = writer 93 } 94 95 // Entrirs will return the entries of the compiler. 96 func (opts *CompileOptions) Entries() []string { 97 return opts.entries 98 } 99 100 // ExtendEntries will extend the entries of the compiler. 101 func (opts *CompileOptions) ExtendEntries(entries []string) { 102 opts.entries = append(opts.entries, entries...) 103 } 104 105 // SetEntries will set the entries of the compiler. 106 func (opts *CompileOptions) SetEntries(entries []string) { 107 opts.entries = entries 108 } 109 110 // SetHasSettingsYaml will set the 'hasSettingsYaml' flag. 111 func (opts *CompileOptions) SetHasSettingsYaml(hasSettingsYaml bool) { 112 opts.hasSettingsYaml = hasSettingsYaml 113 } 114 115 // HasSettingsYaml will return the 'hasSettingsYaml' flag. 116 func (opts *CompileOptions) HasSettingsYaml() bool { 117 return opts.hasSettingsYaml 118 } 119 120 // SetVendor will set the 'isVendor' flag. 121 func (opts *CompileOptions) SetVendor(isVendor bool) { 122 opts.isVendor = isVendor 123 } 124 125 // IsVendor will return the 'isVendor' flag. 126 func (opts *CompileOptions) IsVendor() bool { 127 return opts.isVendor 128 } 129 130 // PkgPath will return the home path for a kcl package during compilation 131 func (opts *CompileOptions) PkgPath() string { 132 return opts.WorkDir 133 } 134 135 // SetPkgPath will set the home path for a kcl package during compilation 136 func (opts *CompileOptions) SetPkgPath(pkgPath string) { 137 opts.Merge(kcl.WithWorkDir(pkgPath)) 138 } 139 140 // LogWriter will return the log writer of the compiler. 141 func (opts *CompileOptions) LogWriter() io.Writer { 142 return opts.writer 143 } 144 145 // Input options of 'kpm init'. 146 type InitOptions struct { 147 Name string 148 InitPath string 149 Version string 150 } 151 152 func (opts *InitOptions) Validate() error { 153 if len(opts.Name) == 0 { 154 return errors.InvalidInitOptions 155 } else if len(opts.InitPath) == 0 { 156 return errors.InternalBug 157 } 158 if opts.Version != "" { 159 if _, err := version.NewSemver(opts.Version); err != nil { 160 return errors.InvalidVersionFormat 161 } 162 } 163 164 return nil 165 } 166 167 type AddOptions struct { 168 LocalPath string 169 NewPkgName string 170 RegistryOpts RegistryOptions 171 NoSumCheck bool 172 } 173 174 func (opts *AddOptions) Validate() error { 175 if len(opts.LocalPath) == 0 { 176 return errors.InternalBug 177 } else if opts.RegistryOpts.Git != nil { 178 return opts.RegistryOpts.Git.Validate() 179 } else if opts.RegistryOpts.Oci != nil { 180 return opts.RegistryOpts.Oci.Validate() 181 } else if opts.RegistryOpts.Local != nil { 182 return opts.RegistryOpts.Local.Validate() 183 } 184 return nil 185 } 186 187 type RegistryOptions struct { 188 Git *GitOptions 189 Oci *OciOptions 190 Local *LocalOptions 191 } 192 193 type GitOptions struct { 194 Url string 195 Branch string 196 Commit string 197 Tag string 198 } 199 200 func (opts *GitOptions) Validate() error { 201 if len(opts.Url) == 0 { 202 return reporter.NewErrorEvent(reporter.InvalidGitUrl, errors.InvalidAddOptionsInvalidGitUrl) 203 } 204 return nil 205 } 206 207 // OciOptions for download oci packages. 208 // kpm will download packages from oci registry by '{Reg}/{Repo}/{PkgName}:{Tag}'. 209 type OciOptions struct { 210 Reg string 211 Repo string 212 Tag string 213 PkgName string 214 Annotations map[string]string 215 } 216 217 func (opts *OciOptions) Validate() error { 218 if len(opts.Repo) == 0 { 219 return reporter.NewErrorEvent(reporter.InvalidRepo, errors.InvalidAddOptionsInvalidOciRepo) 220 } 221 return nil 222 } 223 224 // LocalOptions for local packages. 225 // kpm will find packages from local path. 226 type LocalOptions struct { 227 Path string 228 } 229 230 func (opts *LocalOptions) Validate() error { 231 if len(opts.Path) == 0 { 232 return errors.PathIsEmpty 233 } 234 if _, err := os.Stat(opts.Path); err != nil { 235 return err 236 } 237 return nil 238 } 239 240 // ParseOciOptionFromOciUrl will parse oci url into an 'OciOptions'. 241 // If the 'tag' is empty, ParseOciOptionFromOciUrl will take 'latest' as the default tag. 242 func ParseOciOptionFromOciUrl(url, tag string) (*OciOptions, *reporter.KpmEvent) { 243 ociOpt, err := ParseOciUrl(url) 244 if err != nil { 245 return nil, err 246 } 247 ociOpt.Tag = tag 248 return ociOpt, nil 249 } 250 251 // ParseOciUrl will parse 'oci://hostName/repoName:repoTag' into OciOptions without tag. 252 func ParseOciUrl(ociUrl string) (*OciOptions, *reporter.KpmEvent) { 253 u, err := url.Parse(ociUrl) 254 if err != nil { 255 return nil, reporter.NewEvent(reporter.IsNotUrl) 256 } 257 258 if u.Scheme != "oci" { 259 return nil, reporter.NewEvent(reporter.UrlSchemeNotOci) 260 } 261 262 return &OciOptions{ 263 Reg: u.Host, 264 Repo: u.Path, 265 }, nil 266 } 267 268 // AddStoragePathSuffix will take 'Registry/Repo/Tag' as a path suffix. 269 // e.g. Take '/usr/test' as input, 270 // and oci options is 271 // 272 // OciOptions { 273 // Reg: 'docker.io', 274 // Repo: 'test/testRepo', 275 // Tag: 'v0.0.1' 276 // } 277 // 278 // You will get a path '/usr/test/docker.io/test/testRepo/v0.0.1'. 279 // Deprecated: This function will be deprecated, use 'SanitizePathWithSuffix' instead. 280 func (oci *OciOptions) AddStoragePathSuffix(pathPrefix string) string { 281 return filepath.Join(filepath.Join(filepath.Join(pathPrefix, oci.Reg), oci.Repo), oci.Tag) 282 } 283 284 // SanitizePathSuffix will take 'Registry/Repo/Tag' as a path suffix and sanitize it. 285 func (oci *OciOptions) SanitizePathWithSuffix(pathPrefix string) string { 286 return path.SanitizePath(filepath.Join(filepath.Join(filepath.Join(pathPrefix, oci.Reg), oci.Repo), oci.Tag)) 287 } 288 289 type OciManifestOptions struct { 290 Annotations map[string]string 291 } 292 293 // OciFetchOptions is the input options of the api to fetch oci manifest. 294 type OciFetchOptions struct { 295 oras.FetchBytesOptions 296 OciOptions 297 }