@@ -14,6 +14,7 @@ import (
1414 "io"
1515 "os"
1616 "path/filepath"
17+ "sort"
1718 "strconv"
1819 "strings"
1920
@@ -152,14 +153,10 @@ type dirWalkClosure struct {
152153//
153154// Other than the `vendor` and VCS directories mentioned above, the calculated
154155// hash includes the pathname to every discovered file system node, whether it
155- // is an empty directory, a non-empty directory, empty file, non-empty file, or
156- // symbolic link. If a symbolic link, the referent name is included. If a
157- // non-empty file, the file's contents are included. If a non-empty directory,
158- // the contents of the directory are included.
156+ // is an empty directory, a non-empty directory, an empty file, or a non-empty file.
159157//
160- // While filepath.Walk could have been used, that standard library function
161- // skips symbolic links, and for now, we want the hash to include the symbolic
162- // link referents.
158+ // Symbolic links are excluded, as they are not considered valid elements in the
159+ // definition of a Go module.
163160func DigestFromDirectory (osDirname string ) (VersionedDigest , error ) {
164161 osDirname = filepath .Clean (osDirname )
165162
@@ -173,9 +170,14 @@ func DigestFromDirectory(osDirname string) (VersionedDigest, error) {
173170 someHash : sha256 .New (),
174171 }
175172
176- err := DirWalk (osDirname , func (osPathname string , info os.FileInfo , err error ) error {
173+ err := filepath . Walk (osDirname , func (osPathname string , info os.FileInfo , err error ) error {
177174 if err != nil {
178- return err // DirWalk received an error during initial Lstat
175+ return err
176+ }
177+
178+ // Completely ignore symlinks.
179+ if info .Mode ()& os .ModeSymlink != 0 {
180+ return nil
179181 }
180182
181183 var osRelative string
@@ -207,11 +209,9 @@ func DigestFromDirectory(osDirname string) (VersionedDigest, error) {
207209 switch {
208210 case modeType & os .ModeDir > 0 :
209211 mt = os .ModeDir
210- // DirWalkFunc itself does not need to enumerate children, because
211- // DirWalk will do that for us.
212+ // This func does not need to enumerate children, because
213+ // filepath.Walk will do that for us.
212214 shouldSkip = true
213- case modeType & os .ModeSymlink > 0 :
214- mt = os .ModeSymlink
215215 case modeType & os .ModeNamedPipe > 0 :
216216 mt = os .ModeNamedPipe
217217 shouldSkip = true
@@ -225,9 +225,8 @@ func DigestFromDirectory(osDirname string) (VersionedDigest, error) {
225225
226226 // Write the relative pathname to hash because the hash is a function of
227227 // the node names, node types, and node contents. Added benefit is that
228- // empty directories, named pipes, sockets, devices, and symbolic links
229- // will also affect final hash value. Use `filepath.ToSlash` to ensure
230- // relative pathname is os-agnostic.
228+ // empty directories, named pipes, sockets, and devices. Use
229+ // `filepath.ToSlash` to ensure relative pathname is os-agnostic.
231230 writeBytesWithNull (closure .someHash , []byte (filepath .ToSlash (osRelative )))
232231
233232 binary .LittleEndian .PutUint32 (closure .someModeBytes , uint32 (mt )) // encode the type of mode
@@ -237,15 +236,6 @@ func DigestFromDirectory(osDirname string) (VersionedDigest, error) {
237236 return nil // nothing more to do for some of the node types
238237 }
239238
240- if mt == os .ModeSymlink { // okay to check for equivalence because we set to this value
241- osRelative , err = os .Readlink (osPathname ) // read the symlink referent
242- if err != nil {
243- return errors .Wrap (err , "cannot Readlink" )
244- }
245- writeBytesWithNull (closure .someHash , []byte (filepath .ToSlash (osRelative ))) // write referent to hash
246- return nil // proceed to next node in queue
247- }
248-
249239 // If we get here, node is a regular file.
250240 fh , err := os .Open (osPathname )
251241 if err != nil {
@@ -541,3 +531,25 @@ func CheckDepTree(osDirname string, wantDigests map[string]VersionedDigest) (map
541531
542532 return slashStatus , nil
543533}
534+
535+ // sortedChildrenFromDirname returns a lexicographically sorted list of child
536+ // nodes for the specified directory.
537+ func sortedChildrenFromDirname (osDirname string ) ([]string , error ) {
538+ fh , err := os .Open (osDirname )
539+ if err != nil {
540+ return nil , errors .Wrap (err , "cannot Open" )
541+ }
542+
543+ osChildrenNames , err := fh .Readdirnames (0 ) // 0: read names of all children
544+ if err != nil {
545+ return nil , errors .Wrap (err , "cannot Readdirnames" )
546+ }
547+ sort .Strings (osChildrenNames )
548+
549+ // Close the file handle to the open directory without masking possible
550+ // previous error value.
551+ if er := fh .Close (); err == nil {
552+ err = errors .Wrap (er , "cannot Close" )
553+ }
554+ return osChildrenNames , err
555+ }
0 commit comments