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  }