Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cmd/kosli/fingerprint.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ exclude ^zam/file.txt^ which is relative to the DIR-PATH.
The supported glob pattern syntax is what is documented here: https://pkg.go.dev/path/filepath#Match ,
plus the ability to use recursive globs "**"

If the directory structure contains symbolic links to a file the content of the file it points to is included in the
fingerprint calculation. If a symbolic link points to a directory the path it is pointing to is include in the
fingerprint calculation.

` + kosliIgnoreDesc

const fingerprintLongDesc = fingerprintShortDesc + `
Expand Down
12 changes: 12 additions & 0 deletions cmd/kosli/fingerprint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ func (suite *FingerprintTestSuite) TestFingerprintCmd() {
cmd: "fingerprint --artifact-type dir testdata/folder1-with-ignore",
golden: "038897ea5334462098d65125380d58a493671fb3b8bdbbee1e75ec8bd4a65c23\n",
},
{
name: "dir fingerprint with symbolic links 1",
cmd: "fingerprint --artifact-type dir testdata/folder-with-symlinks-1",
golden: "1c0740265b38509fb9ce7babf00d7eb57e7e08b59dad8be66897c1ebb5b36409\n",
},
{
// The two folders contains the same files and folder, but a/b/c/point-to-dir points
// different directories
name: "dir fingerprint with symbolic links 2",
cmd: "fingerprint --artifact-type dir testdata/folder-with-symlinks-2",
golden: "2a5fe76bc616a97b2ff6f30f46380f1230b98a58df8aec6e96c1fb0e03b41fd9\n",
},
{
name: "fails if type is directory but the argument is not a dir",
cmd: "fingerprint --artifact-type dir testdata/file1",
Expand Down
1 change: 1 addition & 0 deletions cmd/kosli/testdata/folder-with-symlinks-1/a/b/bob.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bob
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dorris
1 change: 1 addition & 0 deletions cmd/kosli/testdata/folder-with-symlinks-2/a/b/bob.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bob
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dorris
40 changes: 38 additions & 2 deletions internal/digest/digest.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,14 +131,50 @@ func calculateDirContentSha256(digestsFile *os.File, dirPath, tmpDir string, exc
return nil
}

// If it's a symlink, resolve the target
var stat fs.FileInfo
if info.Type()&os.ModeSymlink != 0 {
resolved, err := os.Stat(path) // follows the symlink
if err != nil {
return err
}
stat = resolved
} else {
// Convert fs.DirEntry to fs.FileInfo for consistency
resolved, err := info.Info()
if err != nil {
return err
}
stat = resolved
}

nameSha256, err := addNameDigest(tmpDir, info.Name(), digestsFile)
if err != nil {
return err
}

if info.IsDir() {
logger.Debug("dir path: %s -- dirname digest: %v", path, nameSha256)
if stat.IsDir() {
if info.Type()&os.ModeSymlink != 0 {
// This is a symlink to a directory
logger.Debug("symlink path: %s -- linkname digest: %v", path, nameSha256)

targetPath, err := os.Readlink(path)
if err != nil {
return err
}

// Calculate fingerprint of what link points to (for this: a -> c/d calculate the fingerprint of c/d)
targetSha256, err := addNameDigest(tmpDir, targetPath, digestsFile)
if err != nil {
return err
}
logger.Debug("symlink: %s (points to %s) -- digest: %v", path, targetPath, targetSha256)
} else {
// Normal directory
logger.Debug("dir path: %s -- dirname digest: %v", path, nameSha256)
}
} else {
// File or symlink -> file
logger.Debug("file path: %s -- filename digest: %s", path, nameSha256)
fileContentSha256, err := FileSha256(path)
if err != nil {
Expand Down