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 }