diff --git a/pkg/client/client.go b/pkg/client/client.go index ae00008b..40e36e84 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -264,11 +264,6 @@ func (c *KpmClient) ResolvePkgDepsMetadata(kclPkg *pkg.KclPkg, update bool) erro } else if d.IsFromLocal() && !utils.DirExists(d.GetLocalFullPath(kclPkg.HomePath)) { return reporter.NewErrorEvent(reporter.DependencyNotFound, fmt.Errorf("dependency '%s' not found in '%s'", d.Name, searchFullPath)) } else if d.IsFromLocal() && utils.DirExists(d.GetLocalFullPath(kclPkg.HomePath)) { - sum, err := utils.HashDir(d.GetLocalFullPath(kclPkg.HomePath)) - if err != nil { - return reporter.NewErrorEvent(reporter.CalSumFailed, err, fmt.Sprintf("failed to calculate checksum for '%s' in '%s'", d.Name, searchFullPath)) - } - d.Sum = sum depPkg, err := c.LoadPkgFromPath(d.GetLocalFullPath(kclPkg.HomePath)) if err != nil { return err @@ -718,7 +713,7 @@ func (c *KpmClient) VendorDeps(kclPkg *pkg.KclPkg) error { } vendorFullPath := filepath.Join(vendorPath, d.FullName) // If the package already exists in the 'vendor', do nothing. - if utils.DirExists(vendorFullPath) && check(d, vendorFullPath) { + if depExisted(vendorFullPath, d) { continue } else { // If not in the 'vendor', check the global cache. @@ -729,7 +724,7 @@ func (c *KpmClient) VendorDeps(kclPkg *pkg.KclPkg) error { if err != nil { return err } - } else if utils.DirExists(d.GetLocalFullPath(kclPkg.HomePath)) && check(d, d.GetLocalFullPath(kclPkg.HomePath)) { + } else if depExisted(d.GetLocalFullPath(kclPkg.HomePath), d) { // If there is, copy it into the 'vendor' directory. err := copy.Copy(d.GetLocalFullPath(kclPkg.HomePath), vendorFullPath) if err != nil { @@ -754,6 +749,14 @@ func (c *KpmClient) VendorDeps(kclPkg *pkg.KclPkg) error { return nil } +// depExisted will check whether the dependency exists in the local path. +// If the dep is from local, do not need to check the checksum, so return true directly if it exists. +// If the dep is from git or oci, check the checksum, so return true if the checksum is correct and it exist. +func depExisted(localPath string, dep pkg.Dependency) bool { + return (utils.DirExists(localPath) && check(dep, localPath)) || + (utils.DirExists(localPath) && dep.IsFromLocal()) +} + // FillDepInfo will fill registry information for a dependency. func (c *KpmClient) FillDepInfo(dep *pkg.Dependency, homepath string) error { if dep.Source.Local != nil { @@ -851,14 +854,16 @@ func (c *KpmClient) Download(dep *pkg.Dependency, homePath, localPath string) (* dep.FromKclPkg(kpkg) } - var err error - dep.Sum, err = utils.HashDir(dep.LocalFullPath) - if err != nil { - return nil, reporter.NewErrorEvent( - reporter.FailedHashPkg, - err, - fmt.Sprintf("failed to hash the kcl package '%s' in '%s'.", dep.Name, dep.LocalFullPath), - ) + if dep.Source.Local == nil { + var err error + dep.Sum, err = utils.HashDir(dep.LocalFullPath) + if err != nil { + return nil, reporter.NewErrorEvent( + reporter.FailedHashPkg, + err, + fmt.Sprintf("failed to hash the kcl package '%s' in '%s'.", dep.Name, dep.LocalFullPath), + ) + } } return dep, nil diff --git a/pkg/client/test_data/add_with_local_path/expect/pkg/kcl.mod.lock b/pkg/client/test_data/add_with_local_path/expect/pkg/kcl.mod.lock index e7aa3a93..cf4fb1e7 100644 --- a/pkg/client/test_data/add_with_local_path/expect/pkg/kcl.mod.lock +++ b/pkg/client/test_data/add_with_local_path/expect/pkg/kcl.mod.lock @@ -3,7 +3,6 @@ name = "dep_pkg" full_name = "dep_pkg_0.0.1" version = "0.0.1" - sum = "C3TjaZJVdt4G8TtbiCxTUO/zAlf7fWJTAvs/CDMnlxY=" [dependencies.helloworld] name = "helloworld" full_name = "helloworld_0.1.1" diff --git a/pkg/utils/test_data/test_link/is_link_exist/link_target_not_exist b/pkg/utils/test_data/test_link/is_link_exist/link_target_not_exist new file mode 120000 index 00000000..b5615a26 --- /dev/null +++ b/pkg/utils/test_data/test_link/is_link_exist/link_target_not_exist @@ -0,0 +1 @@ +not_exist \ No newline at end of file diff --git a/pkg/utils/test_data/test_link/is_link_exist/test.txt b/pkg/utils/test_data/test_link/is_link_exist/test.txt new file mode 100644 index 00000000..2cbf0611 --- /dev/null +++ b/pkg/utils/test_data/test_link/is_link_exist/test.txt @@ -0,0 +1 @@ +test for create link \ No newline at end of file diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index ca0c82a1..02fd9c65 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -284,6 +284,45 @@ func DirExists(path string) bool { return err == nil } +// IsSymlinkValidAndExists will check whether the symlink exists and points to a valid target +// return three values: whether the symlink exists, whether it points to a valid target, and any error encountered +// Note: IsSymlinkValidAndExists is only useful on unix-like systems. +func IsSymlinkValidAndExists(symlinkPath string) (bool, bool, error) { + // check if the symlink exists + info, err := os.Lstat(symlinkPath) + if err != nil && os.IsNotExist(err) { + // symlink does not exist + return false, false, nil + } else if err != nil { + // other error + return false, false, err + } + + // check if the file is a symlink + if info.Mode()&os.ModeSymlink == os.ModeSymlink { + // get the target of the symlink + target, err := os.Readlink(symlinkPath) + if err != nil { + // can not read the target + return true, false, err + } + + // check if the target exists + _, err = os.Stat(target) + if err == nil { + // target exists + return true, true, nil + } + if os.IsNotExist(err) { + // target does not exist + return true, false, nil + } + return true, false, err + } + + return false, false, fmt.Errorf("%s exists but is not a symlink", symlinkPath) +} + // DefaultKpmHome create the '.kpm' in the user home and return the path of ".kpm". func CreateSubdirInUserHome(subdir string) (string, error) { homeDir, err := os.UserHomeDir() @@ -304,15 +343,22 @@ func CreateSubdirInUserHome(subdir string) (string, error) { // CreateSymlink will create symbolic link named 'newName' for 'oldName', // and if the symbolic link already exists, it will be deleted and recreated. +// Note: CreateSymlink is only useful on unix-like systems. func CreateSymlink(oldName, newName string) error { - if DirExists(newName) { + symExist, _, err := IsSymlinkValidAndExists(newName) + + if err != nil { + return err + } + + if symExist { err := os.Remove(newName) if err != nil { return err } } - err := os.Symlink(oldName, newName) + err = os.Symlink(oldName, newName) if err != nil { return err } diff --git a/pkg/utils/utils_test.go b/pkg/utils/utils_test.go index 239ebfb3..2ab8a51b 100644 --- a/pkg/utils/utils_test.go +++ b/pkg/utils/utils_test.go @@ -192,3 +192,45 @@ func TestAbsTarPath(t *testing.T) { assert.NotEqual(t, err, nil) assert.Equal(t, abs, "") } + +func TestIsSymlinkExist(t *testing.T) { + testPath := filepath.Join(getTestDir("test_link"), "is_link_exist") + + link_target_not_exist := filepath.Join(testPath, "link_target_not_exist") + + linkExist, targetExist, err := IsSymlinkValidAndExists(link_target_not_exist) + assert.Equal(t, err, nil) + assert.Equal(t, linkExist, true) + assert.Equal(t, targetExist, false) + + linkExist, targetExist, err = IsSymlinkValidAndExists("invalid_link") + assert.Equal(t, err, nil) + assert.Equal(t, linkExist, false) + assert.Equal(t, targetExist, false) + + filename := filepath.Join(testPath, "test.txt") + validLink := filepath.Join(testPath, "valid_link") + err = CreateSymlink(filename, validLink) + assert.Equal(t, err, nil) + + linkExist, targetExist, err = IsSymlinkValidAndExists(validLink) + assert.Equal(t, err, nil) + assert.Equal(t, linkExist, true) + assert.Equal(t, targetExist, true) + + anotherValidLink := filepath.Join(testPath, "another_valid_link") + err = CreateSymlink(filename, anotherValidLink) + assert.Equal(t, err, nil) + + linkExist, targetExist, err = IsSymlinkValidAndExists(anotherValidLink) + assert.Equal(t, err, nil) + assert.Equal(t, linkExist, true) + assert.Equal(t, targetExist, true) + // Defer the removal of the symlink + defer func() { + err := os.Remove(anotherValidLink) + assert.Equal(t, err, nil) + err = os.Remove(validLink) + assert.Equal(t, err, nil) + }() +}