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  }