github.com/kubevela/workflow@v0.6.0/pkg/stdlib/packages.go (about)

     1  /*
     2  Copyright 2022 The KubeVela Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package stdlib
    18  
    19  import (
    20  	"embed"
    21  	"fmt"
    22  	"os"
    23  	"path/filepath"
    24  	"strings"
    25  
    26  	"cuelang.org/go/cue/ast"
    27  	"cuelang.org/go/cue/build"
    28  	"cuelang.org/go/cue/parser"
    29  	"k8s.io/klog/v2"
    30  )
    31  
    32  func init() {
    33  	var err error
    34  	pkgs, err := GetPackages()
    35  	if err != nil {
    36  		klog.ErrorS(err, "Unable to init builtin packages for imports")
    37  		os.Exit(1)
    38  	}
    39  	builtinImport, err = InitBuiltinImports(pkgs)
    40  	if err != nil {
    41  		klog.ErrorS(err, "Unable to init builtin imports")
    42  		os.Exit(1)
    43  	}
    44  }
    45  
    46  var (
    47  	//go:embed actions
    48  	fs embed.FS
    49  	// builtinImport is the builtin import for cue
    50  	builtinImport []*build.Instance
    51  )
    52  
    53  const (
    54  	builtinPackageName = "vela/op"
    55  	builtinActionPath  = "actions"
    56  	packagePath        = "pkgs"
    57  	defaultVersion     = "v1"
    58  )
    59  
    60  // SetupBuiltinImports setup builtin imports
    61  func SetupBuiltinImports(pkgs map[string]string) error {
    62  	builtin, err := GetPackages()
    63  	if err != nil {
    64  		return err
    65  	}
    66  	for k, v := range pkgs {
    67  		file, err := parser.ParseFile("-", v, parser.ParseComments)
    68  		if err != nil {
    69  			return err
    70  		}
    71  		if original, ok := builtin[k]; ok {
    72  			builtin[k] = mergeFiles(original, file)
    73  		} else {
    74  			builtin[k] = file
    75  		}
    76  	}
    77  	builtinImport, err = InitBuiltinImports(builtin)
    78  	if err != nil {
    79  		return err
    80  	}
    81  	return nil
    82  }
    83  
    84  // GetPackages Get Stdlib packages
    85  func GetPackages() (map[string]*ast.File, error) {
    86  	versions, err := fs.ReadDir(builtinActionPath)
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  	ret := make(map[string]*ast.File)
    91  
    92  	for _, dirs := range versions {
    93  		pathPrefix := fmt.Sprintf("%s/%s", builtinActionPath, dirs.Name())
    94  		files, err := fs.ReadDir(fmt.Sprintf("%s/%s", pathPrefix, packagePath))
    95  		if err != nil {
    96  			return nil, err
    97  		}
    98  		opBytes, err := fs.ReadFile(fmt.Sprintf("%s/%s", pathPrefix, "op.cue"))
    99  		if err != nil {
   100  			return nil, err
   101  		}
   102  		opContent := string(opBytes) + "\n"
   103  		for _, file := range files {
   104  			body, err := fs.ReadFile(fmt.Sprintf("%s/%s/%s", pathPrefix, packagePath, file.Name()))
   105  			if err != nil {
   106  				return nil, err
   107  			}
   108  			pkgContent := fmt.Sprintf("%s: {\n%s\n}\n", strings.TrimSuffix(file.Name(), ".cue"), string(body))
   109  			opContent += pkgContent
   110  		}
   111  		f, err := parser.ParseFile("-", opContent, parser.ParseComments)
   112  		if err != nil {
   113  			return nil, err
   114  		}
   115  		if dirs.Name() == defaultVersion {
   116  			ret[builtinPackageName] = f
   117  		}
   118  		ret[filepath.Join(builtinPackageName, dirs.Name())] = f
   119  	}
   120  	return ret, nil
   121  }
   122  
   123  // AddImportsFor install imports for build.Instance.
   124  func AddImportsFor(inst *build.Instance, tagTempl string) error {
   125  	inst.Imports = append(inst.Imports, builtinImport...)
   126  	if tagTempl != "" {
   127  		p := &build.Instance{
   128  			PkgName:    filepath.Base("vela/custom"),
   129  			ImportPath: "vela/custom",
   130  		}
   131  		file, err := parser.ParseFile("-", tagTempl, parser.ParseComments)
   132  		if err != nil {
   133  			return err
   134  		}
   135  		if err := p.AddSyntax(file); err != nil {
   136  			return err
   137  		}
   138  		inst.Imports = append(inst.Imports, p)
   139  	}
   140  	return nil
   141  }
   142  
   143  // InitBuiltinImports init built in imports
   144  func InitBuiltinImports(pkgs map[string]*ast.File) ([]*build.Instance, error) {
   145  	imports := make([]*build.Instance, 0)
   146  	for path, content := range pkgs {
   147  		p := &build.Instance{
   148  			PkgName:    filepath.Base(path),
   149  			ImportPath: path,
   150  		}
   151  		if err := p.AddSyntax(content); err != nil {
   152  			return nil, err
   153  		}
   154  		imports = append(imports, p)
   155  	}
   156  	return imports, nil
   157  }
   158  
   159  func mergeFiles(base, file *ast.File) *ast.File {
   160  	base.Decls = append(base.Decls, file.Decls...)
   161  	return base
   162  }