kcl-lang.io/kpm@v0.8.7-0.20240520061008-9fc4c5efc8c7/pkg/api/kpm_pkg.go (about)

     1  package api
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  
     8  	"kcl-lang.io/kcl-go/pkg/kcl"
     9  	"kcl-lang.io/kcl-go/pkg/spec/gpyrpc"
    10  	"kcl-lang.io/kpm/pkg/client"
    11  	"kcl-lang.io/kpm/pkg/constants"
    12  	"kcl-lang.io/kpm/pkg/errors"
    13  	pkg "kcl-lang.io/kpm/pkg/package"
    14  )
    15  
    16  // The KCL Package
    17  type KclPackage struct {
    18  	pkg *pkg.KclPkg
    19  }
    20  
    21  // The KCL Type
    22  
    23  // An additional field 'Name' is added to the original 'KclType'.
    24  //
    25  // 'Name' is the name of the kcl type.
    26  //
    27  // 'RelPath' is the relative path to the package home path.
    28  type KclType struct {
    29  	Name    string
    30  	RelPath string
    31  	*gpyrpc.KclType
    32  }
    33  
    34  // NewKclTypes returns a new KclType.
    35  func NewKclTypes(name, path string, tys *gpyrpc.KclType) *KclType {
    36  	return &KclType{
    37  		Name:    name,
    38  		RelPath: path,
    39  		KclType: tys,
    40  	}
    41  }
    42  
    43  // GetKclPackage returns the kcl package infomation.
    44  //
    45  // 'pkgPath' is the root path of the package where the 'kcl.mod' is located in.
    46  //
    47  // 'kcl_pkg_path' is the path of dependencies download by kpm.
    48  func GetKclPackage(pkgPath string) (*KclPackage, error) {
    49  	kclPkg, err := pkg.LoadKclPkg(pkgPath)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  
    54  	return &KclPackage{
    55  		pkg: kclPkg,
    56  	}, nil
    57  }
    58  
    59  // UpdateDependencyInPath updates the dependencies in the path.
    60  //
    61  // 'pkg_path' is the path of dependencies download by kpm.
    62  func (pkg *KclPackage) UpdateDependencyInPath(pkg_path string) error {
    63  	kpmcli, err := client.NewKpmClient()
    64  	if err != nil {
    65  		return err
    66  	}
    67  	return kpmcli.ResolvePkgDepsMetadata(pkg.pkg, true)
    68  }
    69  
    70  // GetPkgName returns the name of the package.
    71  func (pkg *KclPackage) GetPkgName() string {
    72  	return pkg.pkg.GetPkgName()
    73  }
    74  
    75  // GetPkgVersion returns the version of the package.
    76  func (pkg *KclPackage) GetVersion() string {
    77  	return pkg.pkg.GetPkgTag()
    78  }
    79  
    80  // GetPkgEdition returns the kcl compiler edition of the package.
    81  func (pkg *KclPackage) GetEdition() string {
    82  	return pkg.pkg.GetPkgEdition()
    83  }
    84  
    85  // GetDependencies returns the dependencies of the package.
    86  func (pkg *KclPackage) GetDependencies() pkg.Dependencies {
    87  	return pkg.pkg.Dependencies
    88  }
    89  
    90  // GetDependenciesInModFile returns the mod file of the package.
    91  func (pkg *KclPackage) GetDependenciesInModFile() *pkg.Dependencies {
    92  	return &pkg.pkg.ModFile.Dependencies
    93  }
    94  
    95  // GetPkgHomePath returns the home path of the package.
    96  func (pkg *KclPackage) GetPkgHomePath() string {
    97  	return pkg.pkg.HomePath
    98  }
    99  
   100  // GetPkgProfile returns the profile of the package.
   101  func (pkg *KclPackage) GetPkgProfile() *pkg.Profile {
   102  	return pkg.pkg.GetPkgProfile()
   103  }
   104  
   105  // GetAllSchemaTypeMapping returns all the schema types of the package.
   106  //
   107  // It will return a map of schema types, the key is the relative path to the package home path.
   108  //
   109  // And, the value is a map of schema types, the key is the schema name, the value is the schema type.
   110  func (pkg *KclPackage) GetAllSchemaTypeMapping() (map[string]map[string]*KclType, error) {
   111  	cli, err := client.NewKpmClient()
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  	return pkg.GetFullSchemaTypeMappingWithFilters(cli, []KclTypeFilterFunc{IsSchemaType})
   116  }
   117  
   118  // GetSchemaTypeMappingNamed returns the schema type filtered by schema name.
   119  //
   120  // If 'schemaName' is empty, it will return all the schema types.
   121  func (pkg *KclPackage) GetSchemaTypeMappingNamed(schemaName string) (map[string]map[string]*KclType, error) {
   122  	namedFilterFunc := func(kt *KclType) bool {
   123  		return IsSchemaNamed(kt, schemaName)
   124  	}
   125  	return pkg.GetSchemaTypeMappingWithFilters([]KclTypeFilterFunc{IsSchemaType, namedFilterFunc})
   126  }
   127  
   128  // GetFullSchemaTypeMappingWithFilters returns the full schema type filtered by the filter functions.
   129  func (pkg *KclPackage) GetFullSchemaTypeMappingWithFilters(kpmcli *client.KpmClient, fileterFuncs []KclTypeFilterFunc) (map[string]map[string]*KclType, error) {
   130  	schemaTypes := make(map[string]map[string]*KclType)
   131  	err := filepath.Walk(pkg.GetPkgHomePath(), func(path string, info os.FileInfo, err error) error {
   132  		if err != nil {
   133  			return err
   134  		}
   135  
   136  		if info.IsDir() {
   137  			fileteredKtypeMap := make(map[string]*KclType)
   138  
   139  			depsMap, err := kpmcli.ResolveDepsIntoMap(pkg.pkg)
   140  			if err != nil {
   141  				return err
   142  			}
   143  
   144  			opts := kcl.NewOption()
   145  			for depName, depPath := range depsMap {
   146  				opts.Merge(kcl.WithExternalPkgs(fmt.Sprintf(constants.EXTERNAL_PKGS_ARG_PATTERN, depName, depPath)))
   147  			}
   148  
   149  			schemaTypeList, err := kcl.GetFullSchemaType([]string{path}, "", *opts)
   150  			if err != nil && err.Error() != errors.NoKclFiles.Error() {
   151  				return err
   152  			}
   153  
   154  			schemaTypeMap := make(map[string]*gpyrpc.KclType)
   155  			for _, schemaType := range schemaTypeList {
   156  				schemaTypeMap[schemaType.SchemaName] = schemaType
   157  			}
   158  
   159  			relPath, err := filepath.Rel(pkg.GetPkgHomePath(), path)
   160  			if err != nil {
   161  				return err
   162  			}
   163  			if len(schemaTypeMap) != 0 && schemaTypeMap != nil {
   164  				for kName, kType := range schemaTypeMap {
   165  					kTy := NewKclTypes(kName, relPath, kType)
   166  					filterPassed := true
   167  					for _, filterFunc := range fileterFuncs {
   168  						if !filterFunc(kTy) {
   169  							filterPassed = false
   170  							break
   171  						}
   172  					}
   173  					if filterPassed {
   174  						fileteredKtypeMap[kName] = kTy
   175  					}
   176  				}
   177  				if len(fileteredKtypeMap) > 0 {
   178  					schemaTypes[relPath] = fileteredKtypeMap
   179  				}
   180  			}
   181  		}
   182  
   183  		return nil
   184  	})
   185  
   186  	if err != nil {
   187  		return nil, err
   188  	}
   189  
   190  	return schemaTypes, nil
   191  }
   192  
   193  // GetSchemaTypeMappingWithFilters returns the schema type filtered by the filter functions.
   194  func (pkg *KclPackage) GetSchemaTypeMappingWithFilters(fileterFuncs []KclTypeFilterFunc) (map[string]map[string]*KclType, error) {
   195  	schemaTypes := make(map[string]map[string]*KclType)
   196  	err := filepath.Walk(pkg.GetPkgHomePath(), func(path string, info os.FileInfo, err error) error {
   197  		if err != nil {
   198  			return err
   199  		}
   200  
   201  		if info.IsDir() {
   202  			fileteredKtypeMap := make(map[string]*KclType)
   203  			schemaTypeMap, err := kcl.GetSchemaTypeMapping(path, "", "")
   204  			if err != nil && err.Error() != errors.NoKclFiles.Error() {
   205  				return err
   206  			}
   207  
   208  			relPath, err := filepath.Rel(pkg.GetPkgHomePath(), path)
   209  			if err != nil {
   210  				return err
   211  			}
   212  			if schemaTypeMap != nil {
   213  				for kName, kType := range schemaTypeMap {
   214  					kTy := NewKclTypes(kName, relPath, kType)
   215  					filterPassed := true
   216  					for _, filterFunc := range fileterFuncs {
   217  						if !filterFunc(kTy) {
   218  							filterPassed = false
   219  							break
   220  						}
   221  					}
   222  					if filterPassed {
   223  						fileteredKtypeMap[kName] = kTy
   224  					}
   225  				}
   226  				if len(fileteredKtypeMap) > 0 {
   227  					schemaTypes[relPath] = fileteredKtypeMap
   228  				}
   229  			}
   230  		}
   231  
   232  		return nil
   233  	})
   234  
   235  	if err != nil {
   236  		return nil, err
   237  	}
   238  
   239  	return schemaTypes, nil
   240  }
   241  
   242  type KclTypeFilterFunc func(kt *KclType) bool
   243  
   244  // IsSchema returns true if the type is schema.
   245  func IsSchema(kt *KclType) bool {
   246  	return kt.Type == "schema"
   247  }
   248  
   249  // IsSchemaType returns true if the type is schema type.
   250  func IsSchemaType(kt *KclType) bool {
   251  	return IsSchema(kt) && kt.SchemaName == kt.Name
   252  }
   253  
   254  // IsSchemaInstance returns true if the type is schema instance.
   255  func IsSchemaInstance(kt *KclType) bool {
   256  	return IsSchema(kt) && kt.SchemaName != kt.Name
   257  }
   258  
   259  // IsSchemaNamed returns true if the type is schema and the name is equal to the given name.
   260  func IsSchemaNamed(kt *KclType, name string) bool {
   261  	return IsSchema(kt) && kt.Name == name
   262  }