Skip to content

Commit b8cb75b

Browse files
myitcvflimzy
authored andcommitted
compiler: use hash calculation for determining staleness
1 parent 103facb commit b8cb75b

File tree

2 files changed

+52
-45
lines changed

2 files changed

+52
-45
lines changed

build/build.go

Lines changed: 51 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,23 @@
66
package build
77

88
import (
9+
"bytes"
10+
"crypto/sha256"
911
"fmt"
1012
"go/ast"
1113
"go/build"
1214
"go/parser"
1315
"go/scanner"
1416
"go/token"
1517
"go/types"
18+
"io"
1619
"io/ioutil"
1720
"os"
1821
"os/exec"
1922
"path"
2023
"path/filepath"
2124
"strconv"
2225
"strings"
23-
"time"
2426

2527
"github.com/fsnotify/fsnotify"
2628
"github.com/gopherjs/gopherjs/compiler"
@@ -409,11 +411,10 @@ func (o *Options) PrintSuccess(format string, a ...interface{}) {
409411
// GopherJS requires.
410412
type PackageData struct {
411413
*build.Package
412-
JSFiles []string
413-
IsTest bool // IsTest is true if the package is being built for running tests.
414-
SrcModTime time.Time
415-
UpToDate bool
416-
IsVirtual bool // If true, the package does not have a corresponding physical directory on disk.
414+
JSFiles []string
415+
IsTest bool // IsTest is true if the package is being built for running tests.
416+
UpToDate bool
417+
IsVirtual bool // If true, the package does not have a corresponding physical directory on disk.
417418

418419
bctx *build.Context // The original build context this package came from.
419420
}
@@ -593,19 +594,19 @@ func (s *Session) BuildPackage(pkg *PackageData) (*compiler.Archive, error) {
593594
return archive, nil
594595
}
595596

597+
pkgHash := sha256.New()
598+
596599
if pkg.PkgObj != "" {
597-
var fileInfo os.FileInfo
598-
gopherjsBinary, err := os.Executable()
599-
if err == nil {
600-
fileInfo, err = os.Stat(gopherjsBinary)
601-
if err == nil {
602-
pkg.SrcModTime = fileInfo.ModTime()
603-
}
600+
binPath, err := os.Executable()
601+
if err != nil {
602+
return nil, fmt.Errorf("could not locate GopherJS binary: %v", err)
604603
}
604+
binFile, err := os.Open(binPath)
605605
if err != nil {
606-
os.Stderr.WriteString("Could not get GopherJS binary's modification timestamp. Please report issue.\n")
607-
pkg.SrcModTime = time.Now()
606+
return nil, fmt.Errorf("could not open %v: %v", binPath, err)
608607
}
608+
defer binFile.Close()
609+
io.Copy(pkgHash, binFile)
609610

610611
for _, importedPkgPath := range pkg.Imports {
611612
// Ignore all imports that aren't mentioned in import specs of pkg.
@@ -627,50 +628,57 @@ func (s *Session) BuildPackage(pkg *PackageData) (*compiler.Archive, error) {
627628
if importedPkgPath == "unsafe" || ignored {
628629
continue
629630
}
630-
importedPkg, _, err := s.buildImportPathWithSrcDir(importedPkgPath, pkg.Dir)
631+
_, importedArchive, err := s.buildImportPathWithSrcDir(importedPkgPath, pkg.Dir)
631632
if err != nil {
632633
return nil, err
633634
}
634-
impModTime := importedPkg.SrcModTime
635-
if impModTime.After(pkg.SrcModTime) {
636-
pkg.SrcModTime = impModTime
637-
}
635+
636+
fmt.Fprintf(pkgHash, "import: %v\n", importedPkgPath)
637+
fmt.Fprintf(pkgHash, " hash: %v\n", importedArchive.Hash)
638638
}
639639

640640
for _, name := range append(pkg.GoFiles, pkg.JSFiles...) {
641-
fileInfo, err := statFile(filepath.Join(pkg.Dir, name))
641+
fp := filepath.Join(pkg.Dir, name)
642+
file, err := s.bctx.OpenFile(fp)
642643
if err != nil {
643-
return nil, err
644-
}
645-
if fileInfo.ModTime().After(pkg.SrcModTime) {
646-
pkg.SrcModTime = fileInfo.ModTime()
644+
return nil, fmt.Errorf("failed to open %v: %v", fp, err)
647645
}
646+
fmt.Fprintf(pkgHash, "file: %v\n", fp)
647+
n, _ := io.Copy(pkgHash, file)
648+
fmt.Fprintf(pkgHash, "%d bytes\n", n)
648649
}
649650

650-
pkgObjFileInfo, err := os.Stat(pkg.PkgObj)
651-
if err == nil && !pkg.SrcModTime.After(pkgObjFileInfo.ModTime()) {
652-
// package object is up to date, load from disk if library
653-
pkg.UpToDate = true
654-
if pkg.IsCommand() {
655-
return nil, nil
656-
}
651+
// no commands are archived
652+
if pkg.IsCommand() {
653+
goto CacheMiss
654+
}
657655

658-
objFile, err := os.Open(pkg.PkgObj)
659-
if err != nil {
660-
return nil, err
656+
objFile, err := os.Open(pkg.PkgObj)
657+
if err != nil {
658+
if os.IsNotExist(err) {
659+
goto CacheMiss
661660
}
662-
defer objFile.Close()
661+
return nil, err
662+
}
663+
defer objFile.Close()
663664

664-
archive, err := compiler.ReadArchive(pkg.PkgObj, pkg.ImportPath, objFile, s.Types)
665-
if err != nil {
666-
return nil, err
667-
}
665+
archive, err := compiler.ReadArchive(pkg.PkgObj, pkg.ImportPath, objFile, s.Types)
666+
if err != nil {
667+
return nil, err
668+
}
668669

670+
if bytes.Equal(archive.Hash, pkgHash.Sum(nil)) {
669671
s.Archives[pkg.ImportPath] = archive
670-
return archive, err
672+
return archive, nil
671673
}
672674
}
673675

676+
CacheMiss:
677+
678+
if s.options.Verbose {
679+
fmt.Printf("Cache miss for %v\n", pkg.ImportPath)
680+
}
681+
674682
fileSet := token.NewFileSet()
675683
files, err := parseAndAugment(s.xctx, pkg, pkg.IsTest, fileSet)
676684
if err != nil {
@@ -697,6 +705,8 @@ func (s *Session) BuildPackage(pkg *PackageData) (*compiler.Archive, error) {
697705
return nil, err
698706
}
699707

708+
archive.Hash = pkgHash.Sum(nil)
709+
700710
for _, jsFile := range pkg.JSFiles {
701711
code, err := ioutil.ReadFile(filepath.Join(pkg.Dir, jsFile))
702712
if err != nil {
@@ -707,10 +717,6 @@ func (s *Session) BuildPackage(pkg *PackageData) (*compiler.Archive, error) {
707717
archive.IncJSCode = append(archive.IncJSCode, []byte("\n\t}).call($global);\n")...)
708718
}
709719

710-
if s.options.Verbose {
711-
fmt.Println(pkg.ImportPath)
712-
}
713-
714720
s.Archives[pkg.ImportPath] = archive
715721

716722
if pkg.PkgObj == "" || pkg.IsCommand() {

compiler/compiler.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ func (err ErrorList) Normalize() error {
4949
//
5050
// This is a logical equivalent of an object file in traditional compilers.
5151
type Archive struct {
52+
Hash []byte
5253
// Package's full import path, e.g. "some/package/name".
5354
ImportPath string
5455
// Package's name as per "package" statement at the top of a source file.

0 commit comments

Comments
 (0)