kcl-lang.io/kpm@v0.8.7-0.20240520061008-9fc4c5efc8c7/pkg/package/package.go (about) 1 package pkg 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 "strings" 8 9 "kcl-lang.io/kcl-go/pkg/kcl" 10 "kcl-lang.io/kpm/pkg/constants" 11 errors "kcl-lang.io/kpm/pkg/errors" 12 "kcl-lang.io/kpm/pkg/opt" 13 "kcl-lang.io/kpm/pkg/reporter" 14 "kcl-lang.io/kpm/pkg/utils" 15 ) 16 17 type KclPkg struct { 18 ModFile ModFile 19 HomePath string 20 // The dependencies in the current kcl package are the dependencies of kcl.mod.lock, 21 // not the dependencies in kcl.mod. 22 Dependencies 23 // The flag 'NoSumCheck' is true if the checksum of the current kcl package is not checked. 24 NoSumCheck bool 25 } 26 27 func (p *KclPkg) GetDepsMetadata() (*Dependencies, error) { 28 return p.Dependencies.ToDepMetadata() 29 } 30 31 func NewKclPkg(opts *opt.InitOptions) KclPkg { 32 return KclPkg{ 33 ModFile: *NewModFile(opts), 34 HomePath: opts.InitPath, 35 Dependencies: Dependencies{Deps: make(map[string]Dependency)}, 36 } 37 } 38 39 func LoadKclPkg(pkgPath string) (*KclPkg, error) { 40 modFile, err := LoadModFile(pkgPath) 41 if err != nil { 42 return nil, reporter.NewErrorEvent(reporter.FailedLoadKclMod, err, fmt.Sprintf("could not load 'kcl.mod' in '%s'", pkgPath)) 43 } 44 45 // Get dependencies from kcl.mod.lock. 46 deps, err := LoadLockDeps(pkgPath) 47 48 if err != nil { 49 return nil, reporter.NewErrorEvent(reporter.FailedLoadKclMod, err, fmt.Sprintf("could not load 'kcl.mod.lock' in '%s'", pkgPath)) 50 } 51 52 // Align the dependencies between kcl.mod and kcl.mod.lock. 53 for name, dep := range modFile.Dependencies.Deps { 54 if dep.Local != nil { 55 if ldep, ok := deps.Deps[name]; ok { 56 abs, err := filepath.Abs(filepath.Join(pkgPath, dep.Local.Path)) 57 if err != nil { 58 return nil, reporter.NewErrorEvent(reporter.Bug, err, "internal bugs, please contact us to fix it.") 59 } 60 ldep.LocalFullPath = abs 61 dep.LocalFullPath = abs 62 ldep.Source = dep.Source 63 deps.Deps[name] = ldep 64 modFile.Dependencies.Deps[name] = dep 65 } 66 } 67 } 68 69 return &KclPkg{ 70 ModFile: *modFile, 71 HomePath: pkgPath, 72 Dependencies: *deps, 73 }, nil 74 } 75 76 func FindFirstKclPkgFrom(path string) (*KclPkg, error) { 77 matches, _ := filepath.Glob(filepath.Join(path, "*.tar")) 78 if matches == nil || len(matches) != 1 { 79 // then try to glob tgz file 80 matches, _ = filepath.Glob(filepath.Join(path, "*.tgz")) 81 if matches == nil || len(matches) != 1 { 82 pkg, err := LoadKclPkg(path) 83 if err != nil { 84 return nil, reporter.NewErrorEvent( 85 reporter.InvalidKclPkg, 86 err, 87 fmt.Sprintf("failed to find the kcl package tar from '%s'.", path), 88 ) 89 } 90 91 return pkg, nil 92 } 93 } 94 95 tarPath := matches[0] 96 unTarPath := filepath.Dir(tarPath) 97 var err error 98 if utils.IsTar(tarPath) { 99 err = utils.UnTarDir(tarPath, unTarPath) 100 } else { 101 err = utils.ExtractTarball(tarPath, unTarPath) 102 } 103 if err != nil { 104 return nil, reporter.NewErrorEvent( 105 reporter.FailedUntarKclPkg, 106 err, 107 fmt.Sprintf("failed to untar the kcl package tar from '%s' into '%s'.", tarPath, unTarPath), 108 ) 109 } 110 111 // After untar the downloaded kcl package tar file, remove the tar file. 112 if utils.DirExists(tarPath) { 113 rmErr := os.Remove(tarPath) 114 if rmErr != nil { 115 return nil, reporter.NewErrorEvent( 116 reporter.FailedUntarKclPkg, 117 err, 118 fmt.Sprintf("failed to untar the kcl package tar from '%s' into '%s'.", tarPath, unTarPath), 119 ) 120 } 121 } 122 123 pkg, err := LoadKclPkg(unTarPath) 124 if err != nil { 125 return nil, reporter.NewErrorEvent( 126 reporter.InvalidKclPkg, 127 err, 128 fmt.Sprintf("failed to find the kcl package tar from '%s'.", path), 129 ) 130 } 131 132 return pkg, nil 133 } 134 135 func LoadKclPkgFromTar(pkgTarPath string) (*KclPkg, error) { 136 destDir := strings.TrimSuffix(pkgTarPath, filepath.Ext(pkgTarPath)) 137 err := utils.UnTarDir(pkgTarPath, destDir) 138 if err != nil { 139 return nil, err 140 } 141 return LoadKclPkg(destDir) 142 } 143 144 // GetKclOpts will return the kcl options from kcl.mod. 145 func (kclPkg *KclPkg) GetKclOpts() *kcl.Option { 146 if kclPkg.ModFile.Profiles == nil { 147 return kcl.NewOption() 148 } 149 return kclPkg.ModFile.Profiles.IntoKclOptions() 150 } 151 152 // GetEntryKclFilesFromModFile will return the entry kcl files from kcl.mod. 153 func (kclPkg *KclPkg) GetEntryKclFilesFromModFile() []string { 154 return kclPkg.ModFile.GetEntries() 155 } 156 157 // HasProfile will return true if the current kcl package has the profile. 158 func (kclPkg *KclPkg) HasProfile() bool { 159 return kclPkg.ModFile.Profiles != nil 160 } 161 162 func (kclPkg *KclPkg) IsVendorMode() bool { 163 return kclPkg.ModFile.VendorMode 164 } 165 166 func (kclPkg *KclPkg) SetVendorMode(vendorMode bool) { 167 kclPkg.ModFile.VendorMode = vendorMode 168 } 169 170 // Return the full vendor path. 171 func (kclPkg *KclPkg) LocalVendorPath() string { 172 return filepath.Join(kclPkg.HomePath, "vendor") 173 } 174 175 // updateModAndLockFile will update kcl.mod and kcl.mod.lock 176 func (kclPkg *KclPkg) UpdateModAndLockFile() error { 177 // Generate file kcl.mod. 178 err := kclPkg.ModFile.StoreModFile() 179 if err != nil { 180 return err 181 } 182 183 // Generate file kcl.mod.lock. 184 if !kclPkg.NoSumCheck { 185 err := kclPkg.LockDepsVersion() 186 if err != nil { 187 return err 188 } 189 } 190 191 return nil 192 } 193 194 // LockDepsVersion locks the dependencies of the current kcl package into kcl.mod.lock. 195 func (kclPkg *KclPkg) LockDepsVersion() error { 196 fullPath := filepath.Join(kclPkg.HomePath, MOD_LOCK_FILE) 197 lockToml, err := kclPkg.Dependencies.MarshalLockTOML() 198 if err != nil { 199 return err 200 } 201 202 return utils.StoreToFile(fullPath, lockToml) 203 } 204 205 // CreateDefauleMain will create a default main.k file in the current kcl package. 206 func (kclPkg *KclPkg) CreateDefauleMain() error { 207 mainKPath := filepath.Join(kclPkg.HomePath, constants.DEFAULT_KCL_FILE_NAME) 208 return utils.StoreToFile(mainKPath, constants.DEFAULT_KCL_FILE_CONTENT) 209 } 210 211 // check sum for a Dependency. 212 func check(dep Dependency, newDepPath string) bool { 213 if dep.Sum == "" { 214 return false 215 } 216 217 sum, err := utils.HashDir(newDepPath) 218 219 if err != nil { 220 return false 221 } 222 223 return dep.Sum == sum 224 } 225 226 const TAR_SUFFIX = ".tar" 227 228 // DefaultTarPath will return "<kcl_package_path>/<package_name>-<package_version>.tar" 229 func (kclPkg *KclPkg) DefaultTarPath() string { 230 return filepath.Join(kclPkg.HomePath, kclPkg.GetPkgTarName()) 231 } 232 233 // Verify that the environment variable KPM HOME is set correctly 234 func (kclPkg *KclPkg) ValidateKpmHome(kpmHome string) *reporter.KpmEvent { 235 if kclPkg.HomePath == kpmHome { 236 return reporter.NewErrorEvent(reporter.InvalidKpmHomeInCurrentPkg, errors.InvalidKpmHomeInCurrentPkg) 237 } 238 return nil 239 } 240 241 // GetPkgFullName returns the full name of package. 242 // The full name is "<pkg_name>-<pkg_version>", 243 // <pkg_name> is the name of package. 244 // <pkg_version> is the version of package 245 func (kclPkg *KclPkg) GetPkgFullName() string { 246 return fmt.Sprintf(PKG_NAME_PATTERN, kclPkg.ModFile.Pkg.Name, kclPkg.ModFile.Pkg.Version) 247 } 248 249 // GetPkgName returns name of package. 250 func (kclPkg *KclPkg) GetPkgName() string { 251 return kclPkg.ModFile.Pkg.Name 252 } 253 254 // GetPkgTag returns version of package. 255 func (kclPkg *KclPkg) GetPkgTag() string { 256 return kclPkg.ModFile.Pkg.Version 257 } 258 259 // GetPkgEdition returns compile edition of package. 260 func (kclPkg *KclPkg) GetPkgEdition() string { 261 return kclPkg.ModFile.Pkg.Edition 262 } 263 264 // GetPkgProfile returns the profile of package. 265 func (kclPkg *KclPkg) GetPkgProfile() *Profile { 266 return kclPkg.ModFile.Profiles 267 } 268 269 // GetPkgTarName returns the kcl package tar name "<package_name>-v<package_version>.tar" 270 func (kclPkg *KclPkg) GetPkgTarName() string { 271 return kclPkg.GetPkgFullName() + TAR_SUFFIX 272 } 273 274 const LOCK_FILE_NAME = "kcl.mod.lock" 275 276 // GetLockFilePath returns the abs path of kcl.mod.lock. 277 func (kclPkg *KclPkg) GetLockFilePath() string { 278 return filepath.Join(kclPkg.HomePath, LOCK_FILE_NAME) 279 } 280 281 // GetPkgVersion returns the version of package. 282 func (KclPkg *KclPkg) GetPkgVersion() string { 283 return KclPkg.ModFile.Pkg.Version 284 } 285 286 // GetPkgDescription returns the description of package. 287 func (KclPkg *KclPkg) GetPkgDescription() string { 288 return KclPkg.ModFile.Pkg.Description 289 } 290 291 // GetPkgInclude returns the include of package. 292 func (KclPkg *KclPkg) GetPkgInclude() []string { 293 return KclPkg.ModFile.Pkg.Include 294 } 295 296 // GetPkgExclude returns the exclude of package. 297 func (KclPkg *KclPkg) GetPkgExclude() []string { 298 return KclPkg.ModFile.Pkg.Exclude 299 } 300 301 // GenCheckSum generates the checksum of the current kcl package. 302 func (KclPkg *KclPkg) GenCheckSum() (string, error) { 303 return utils.HashDir(KclPkg.HomePath) 304 }