@@ -24,9 +24,14 @@ Usage: go run build/ci.go <command> <command flags/arguments>
2424
2525Available commands are:
2626
27- install [ -arch architecture ] [ -cc compiler ] [ packages... ] -- builds packages and executables
28- test [ -coverage ] [ packages... ] -- runs the tests
29- lint -- runs certain pre-selected linters
27+ lint -- runs certain pre-selected linters
28+ check_tidy -- verifies that everything is 'go mod tidy'-ed
29+ check_generate -- verifies that everything is 'go generate'-ed
30+ check_baddeps -- verifies that certain dependencies are avoided
31+
32+ install [ -arch architecture ] [ -cc compiler ] [ packages... ] -- builds packages and executables
33+ test [ -coverage ] [ packages... ] -- runs the tests
34+
3035 archive [ -arch architecture ] [ -type zip|tar ] [ -signer key-envvar ] [ -signify key-envvar ] [ -upload dest ] -- archives build artifacts
3136 importkeys -- imports signing keys from env
3237 debsrc [ -signer key-id ] [ -upload dest ] -- creates a debian source package
@@ -39,11 +44,9 @@ package main
3944
4045import (
4146 "bytes"
42- "crypto/sha256"
4347 "encoding/base64"
4448 "flag"
4549 "fmt"
46- "io"
4750 "log"
4851 "os"
4952 "os/exec"
@@ -156,6 +159,12 @@ func main() {
156159 doTest (os .Args [2 :])
157160 case "lint" :
158161 doLint (os .Args [2 :])
162+ case "check_tidy" :
163+ doCheckTidy ()
164+ case "check_generate" :
165+ doCheckGenerate ()
166+ case "check_baddeps" :
167+ doCheckBadDeps ()
159168 case "archive" :
160169 doArchive (os .Args [2 :])
161170 case "dockerx" :
@@ -168,8 +177,6 @@ func main() {
168177 doPurge (os .Args [2 :])
169178 case "sanitycheck" :
170179 doSanityCheck ()
171- case "generate" :
172- doGenerate ()
173180 default :
174181 log .Fatal ("unknown command " , os .Args [1 ])
175182 }
@@ -348,130 +355,93 @@ func downloadSpecTestFixtures(csdb *build.ChecksumDB, cachedir string) string {
348355 return filepath .Join (cachedir , base )
349356}
350357
351- // hashAllSourceFiles iterates all files under the top-level project directory
352- // computing the hash of each file (excluding files within the tests
353- // subrepo)
354- func hashAllSourceFiles () (map [string ][32 ]byte , error ) {
355- res := make (map [string ][32 ]byte )
356- err := filepath .WalkDir ("." , func (path string , d os.DirEntry , err error ) error {
357- if strings .HasPrefix (path , filepath .FromSlash ("tests/testdata" )) {
358- return filepath .SkipDir
359- }
360- if ! d .Type ().IsRegular () {
361- return nil
362- }
363- // open the file and hash it
364- f , err := os .OpenFile (path , os .O_RDONLY , 0666 )
365- if err != nil {
366- return err
367- }
368- hasher := sha256 .New ()
369- if _ , err := io .Copy (hasher , f ); err != nil {
370- return err
371- }
372- res [path ] = [32 ]byte (hasher .Sum (nil ))
373- return nil
374- })
375- if err != nil {
376- return nil , err
377- }
378- return res , nil
379- }
358+ // doCheckTidy assets that the Go modules files are tidied already.
359+ func doCheckTidy () {
360+ targets := []string {"go.mod" , "go.sum" }
380361
381- // hashSourceFiles iterates the provided set of filepaths (relative to the top-level geth project directory)
382- // computing the hash of each file.
383- func hashSourceFiles (files []string ) (map [string ][32 ]byte , error ) {
384- res := make (map [string ][32 ]byte )
385- for _ , filePath := range files {
386- f , err := os .OpenFile (filePath , os .O_RDONLY , 0666 )
387- if err != nil {
388- return nil , err
389- }
390- hasher := sha256 .New ()
391- if _ , err := io .Copy (hasher , f ); err != nil {
392- return nil , err
393- }
394- res [filePath ] = [32 ]byte (hasher .Sum (nil ))
395- }
396- return res , nil
397- }
398-
399- // compareHashedFilesets compares two maps (key is relative file path to top-level geth directory, value is its hash)
400- // and returns the list of file paths whose hashes differed.
401- func compareHashedFilesets (preHashes map [string ][32 ]byte , postHashes map [string ][32 ]byte ) []string {
402- updates := []string {}
403- for path , postHash := range postHashes {
404- preHash , ok := preHashes [path ]
405- if ! ok || preHash != postHash {
406- updates = append (updates , path )
407- }
362+ hashes , err := build .HashFiles (targets )
363+ if err != nil {
364+ log .Fatalf ("failed to hash go.mod/go.sum: %v" , err )
408365 }
409- return updates
410- }
366+ build .MustRun (new (build.GoToolchain ).Go ("mod" , "tidy" ))
411367
412- // doGoModTidy runs 'go mod tidy' and asserts that go.sum/go.mod do not change
413- // as a result.
414- func doGoModTidy () {
415- targetFiles := []string {"go.mod" , "go.sum" }
416- preHashes , err := hashSourceFiles (targetFiles )
368+ tidied , err := build .HashFiles (targets )
417369 if err != nil {
418- log .Fatal ("failed to hash go.mod/go.sum" , "err" , err )
419- }
420- tc := new (build.GoToolchain )
421- c := tc .Go ("mod" , "tidy" )
422- build .MustRun (c )
423- postHashes , err := hashSourceFiles (targetFiles )
424- updates := compareHashedFilesets (preHashes , postHashes )
425- for _ , updatedFile := range updates {
426- fmt .Fprintf (os .Stderr , "changed file %s\n " , updatedFile )
370+ log .Fatalf ("failed to rehash go.mod/go.sum: %v" , err )
427371 }
428- if len (updates ) != 0 {
429- log .Fatal ( "go.sum and/or go.mod were updated by running 'go mod tidy'" )
372+ if updates := build . DiffHashes ( hashes , tidied ); len (updates ) > 0 {
373+ log .Fatalf ( "files changed on running 'go mod tidy': %v" , updates )
430374 }
375+ fmt .Println ("No untidy module files detected." )
431376}
432377
433- // doGenerate ensures that re-generating generated files does not cause
434- // any mutations in the source file tree: i.e. all generated files were
435- // updated and committed. Any stale generated files are updated.
436- func doGenerate () {
378+ // doCheckGenerate ensures that re-generating generated files does not cause
379+ // any mutations in the source file tree.
380+ func doCheckGenerate () {
437381 var (
438- tc = new (build.GoToolchain )
439382 cachedir = flag .String ("cachedir" , "./build/cache" , "directory for caching binaries." )
440- verify = flag .Bool ("verify" , false , "check whether any files are changed by go generate" )
441383 )
384+ // Compute the origin hashes of all the files
385+ var hashes map [string ][32 ]byte
442386
443- protocPath := downloadProtoc (* cachedir )
444- protocGenGoPath := downloadProtocGenGo (* cachedir )
445-
446- var preHashes map [string ][32 ]byte
447- if * verify {
448- var err error
449- preHashes , err = hashAllSourceFiles ()
450- if err != nil {
451- log .Fatal ("failed to compute map of source hashes" , "err" , err )
452- }
387+ var err error
388+ hashes , err = build .HashFolder ("." , []string {"tests/testdata" , "build/cache" })
389+ if err != nil {
390+ log .Fatal ("Error computing hashes" , "err" , err )
453391 }
454-
455- c := tc .Go ("generate" , "./..." )
392+ // Run any go generate steps we might be missing
393+ var (
394+ protocPath = downloadProtoc (* cachedir )
395+ protocGenGoPath = downloadProtocGenGo (* cachedir )
396+ )
397+ c := new (build.GoToolchain ).Go ("generate" , "./..." )
456398 pathList := []string {filepath .Join (protocPath , "bin" ), protocGenGoPath , os .Getenv ("PATH" )}
457399 c .Env = append (c .Env , "PATH=" + strings .Join (pathList , string (os .PathListSeparator )))
458400 build .MustRun (c )
459401
460- if ! * verify {
461- return
462- }
463- // Check if files were changed.
464- postHashes , err := hashAllSourceFiles ()
402+ // Check if generate file hashes have changed
403+ generated , err := build .HashFolder ("." , []string {"tests/testdata" , "build/cache" })
465404 if err != nil {
466- log .Fatal ( "error computing source tree file hashes" , "err " , err )
405+ log .Fatalf ( "Error re- computing hashes: %v " , err )
467406 }
468- updates := compareHashedFilesets ( preHashes , postHashes )
469- for _ , updatedFile := range updates {
470- fmt . Fprintf ( os . Stderr , " changed file %s \n " , updatedFile )
407+ updates := build . DiffHashes ( hashes , generated )
408+ for _ , file := range updates {
409+ log . Printf ( "File changed: %s " , file )
471410 }
472411 if len (updates ) != 0 {
473412 log .Fatal ("One or more generated files were updated by running 'go generate ./...'" )
474413 }
414+ fmt .Println ("No stale files detected." )
415+ }
416+
417+ // doCheckBadDeps verifies whether certain unintended dependencies between some
418+ // packages leak into the codebase due to a refactor. This is not an exhaustive
419+ // list, rather something we build up over time at sensitive places.
420+ func doCheckBadDeps () {
421+ baddeps := [][2 ]string {
422+ // Rawdb tends to be a dumping ground for db utils, sometimes leaking the db itself
423+ {"github.com/ethereum/go-ethereum/core/rawdb" , "github.com/ethereum/go-ethereum/ethdb/leveldb" },
424+ {"github.com/ethereum/go-ethereum/core/rawdb" , "github.com/ethereum/go-ethereum/ethdb/pebbledb" },
425+ }
426+ tc := new (build.GoToolchain )
427+
428+ var failed bool
429+ for _ , rule := range baddeps {
430+ out , err := tc .Go ("list" , "-deps" , rule [0 ]).CombinedOutput ()
431+ if err != nil {
432+ log .Fatalf ("Failed to list '%s' dependencies: %v" , rule [0 ], err )
433+ }
434+ for _ , line := range strings .Split (string (out ), "\n " ) {
435+ if strings .TrimSpace (line ) == rule [1 ] {
436+ log .Printf ("Found bad dependency '%s' -> '%s'" , rule [0 ], rule [1 ])
437+ failed = true
438+ }
439+ }
440+ }
441+ if failed {
442+ log .Fatalf ("Bad dependencies detected." )
443+ }
444+ fmt .Println ("No bad dependencies detected." )
475445}
476446
477447// doLint runs golangci-lint on requested packages.
@@ -488,8 +458,6 @@ func doLint(cmdline []string) {
488458 linter := downloadLinter (* cachedir )
489459 lflags := []string {"run" , "--config" , ".golangci.yml" }
490460 build .MustRunCommandWithOutput (linter , append (lflags , packages ... )... )
491-
492- doGoModTidy ()
493461 fmt .Println ("You have achieved perfection." )
494462}
495463
0 commit comments