forked from golang/dep
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Karrick S. McDermott
committed
Jul 15, 2017
1 parent
911cd22
commit 9449c59
Showing
8 changed files
with
138 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package fs | ||
|
||
import ( | ||
"crypto/sha256" | ||
"fmt" | ||
"io" | ||
"os" | ||
"strconv" | ||
|
||
"github.com/pkg/errors" | ||
) | ||
|
||
// HashFromPathname returns a hash of the specified file or directory, ignoring | ||
// all file system objects named, `vendor` and their descendants. This function | ||
// follows symbolic links. | ||
func HashFromPathname(pathname string) (hash string, err error) { | ||
fi, err := os.Stat(pathname) | ||
if err != nil { | ||
return "", errors.Wrap(err, "could not stat") | ||
} | ||
if fi.IsDir() { | ||
return hashFromDirectory(pathname, fi) | ||
} | ||
return hashFromFile(pathname, fi) | ||
} | ||
|
||
func hashFromFile(pathname string, fi os.FileInfo) (hash string, err error) { | ||
fh, err := os.Open(pathname) | ||
if err != nil { | ||
return "", errors.Wrap(err, "could not open") | ||
} | ||
defer func() { | ||
err = errors.Wrap(fh.Close(), "could not close") | ||
}() | ||
|
||
h := sha256.New() | ||
_, _ = h.Write([]byte(strconv.FormatInt(fi.Size(), 10))) | ||
|
||
if _, err = io.Copy(h, fh); err != nil { | ||
err = errors.Wrap(err, "could not read file") | ||
return | ||
} | ||
|
||
hash = fmt.Sprintf("%x", h.Sum(nil)) | ||
return | ||
} | ||
|
||
func hashFromDirectory(pathname string, fi os.FileInfo) (hash string, err error) { | ||
const maxFileInfos = 32 | ||
|
||
fh, err := os.Open(pathname) | ||
if err != nil { | ||
return hash, errors.Wrap(err, "could not open") | ||
} | ||
defer func() { | ||
err = errors.Wrap(fh.Close(), "could not close") | ||
}() | ||
|
||
h := sha256.New() | ||
|
||
// NOTE: Chunk through file system objects to prevent allocating too much | ||
// memory for directories with tens of thousands of child objects. | ||
for { | ||
var children []os.FileInfo | ||
var childHash string | ||
|
||
children, err = fh.Readdir(maxFileInfos) | ||
if err != nil { | ||
if err == io.EOF { | ||
err = nil | ||
break | ||
} | ||
return hash, errors.Wrap(err, "could not read directory") | ||
} | ||
for _, child := range children { | ||
switch child.Name() { | ||
case ".", "..", "vendor": | ||
// skip | ||
default: | ||
childPathname := pathname + string(os.PathSeparator) + child.Name() | ||
if childHash, err = HashFromPathname(childPathname); err != nil { | ||
err = errors.Wrap(err, "could not compute hash from pathname") | ||
return | ||
} | ||
_, _ = h.Write([]byte(childPathname)) | ||
_, _ = h.Write([]byte(childHash)) | ||
} | ||
} | ||
} | ||
|
||
hash = fmt.Sprintf("%x", h.Sum(nil)) | ||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package fs | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
func TestHashFromPathnameWithFile(t *testing.T) { | ||
actual, err := HashFromPathname("testdata/blob") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
expected := "825dc11fe41d8f604ab48a8cd6cecf304005bd82fd0228a6e411e992d4d03a08" | ||
if actual != expected { | ||
t.Errorf("Actual:\n\t%#q\nExpected:\n\t%#q", actual, expected) | ||
} | ||
} | ||
|
||
func TestHashFromPathnameWithDirectory(t *testing.T) { | ||
actual, err := HashFromPathname("testdata/recursive") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
expected := "9b3a1f1f63c0c54860799cc5464a3c380a697a3ec49ca103a62d9c09ad9fedf8" | ||
if actual != expected { | ||
t.Errorf("Actual:\n\t%#q\nExpected:\n\t%#q", actual, expected) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
fjdkal;fdjskc | ||
xzc | ||
axc | ||
fdsf | ||
adsf | ||
das | ||
fd |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
fjdkal;fdjskc | ||
xzc | ||
axc | ||
fdsf | ||
adsf | ||
das | ||
fd |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
fjdsakl;fd | ||
vcafcds | ||
vca |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
this file ought to be skipped |
Empty file.
9449c59
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make a PR for this, so we can discuss? π π