diff --git a/build/build.go b/build/build.go index 612e2d189..622f0f897 100644 --- a/build/build.go +++ b/build/build.go @@ -295,12 +295,11 @@ type PackageData struct { IsTest bool // IsTest is true if the package is being built for running tests. SrcModTime time.Time UpToDate bool - Archive *compiler.Archive } type Session struct { options *Options - Packages map[string]*PackageData + Archives map[string]*compiler.Archive Types map[string]*types.Package Watcher *fsnotify.Watcher } @@ -316,7 +315,7 @@ func NewSession(options *Options) *Session { s := &Session{ options: options, - Packages: make(map[string]*PackageData), + Archives: make(map[string]*compiler.Archive), } s.Types = make(map[string]*types.Package) if options.Watch { @@ -356,14 +355,17 @@ func (s *Session) BuildDir(packagePath string, importPath string, pkgObj string) return err } pkg.JSFiles = jsFiles - if err := s.BuildPackage(pkg); err != nil { + archive, err := s.BuildPackage(pkg) + if err != nil { return err } if pkgObj == "" { pkgObj = filepath.Base(packagePath) + ".js" } - if err := s.WriteCommandPackage(pkg, pkgObj); err != nil { - return err + if pkg.IsCommand() && !pkg.UpToDate { + if err := s.WriteCommandPackage(archive, pkgObj); err != nil { + return err + } } return nil } @@ -385,42 +387,41 @@ func (s *Session) BuildFiles(filenames []string, pkgObj string, packagePath stri pkg.GoFiles = append(pkg.GoFiles, file) } - if err := s.BuildPackage(pkg); err != nil { + archive, err := s.BuildPackage(pkg) + if err != nil { return err } if s.Types["main"].Name() != "main" { return fmt.Errorf("cannot build/run non-main package") } - return s.WriteCommandPackage(pkg, pkgObj) + return s.WriteCommandPackage(archive, pkgObj) } func (s *Session) BuildImportPath(path string) (*compiler.Archive, error) { - return s.buildImportPathWithSrcDir(path, "") + _, archive, err := s.buildImportPathWithSrcDir(path, "") + return archive, err } -func (s *Session) buildImportPathWithSrcDir(path string, srcDir string) (*compiler.Archive, error) { - if pkg, found := s.Packages[path]; found { - return pkg.Archive, nil - } - +func (s *Session) buildImportPathWithSrcDir(path string, srcDir string) (*PackageData, *compiler.Archive, error) { pkg, err := importWithSrcDir(path, srcDir, 0, s.InstallSuffix(), s.options.BuildTags) if s.Watcher != nil && pkg != nil { // add watch even on error s.Watcher.Add(pkg.Dir) } if err != nil { - return nil, err + return nil, nil, err } - if err := s.BuildPackage(pkg); err != nil { - return nil, err + archive, err := s.BuildPackage(pkg) + if err != nil { + return nil, nil, err } - return pkg.Archive, nil + + return pkg, archive, nil } -func (s *Session) BuildPackage(pkg *PackageData) error { - s.Packages[pkg.ImportPath] = pkg - if pkg.ImportPath == "unsafe" { - return nil +func (s *Session) BuildPackage(pkg *PackageData) (*compiler.Archive, error) { + if archive, ok := s.Archives[pkg.ImportPath]; ok { + return archive, nil } if pkg.PkgObj != "" { @@ -454,11 +455,11 @@ func (s *Session) BuildPackage(pkg *PackageData) error { if importedPkgPath == "unsafe" || ignored { continue } - _, err := s.BuildImportPath(importedPkgPath) + pkg, _, err := s.buildImportPathWithSrcDir(importedPkgPath, "") if err != nil { - return err + return nil, err } - impModeTime := s.Packages[importedPkgPath].SrcModTime + impModeTime := pkg.SrcModTime if impModeTime.After(pkg.SrcModTime) { pkg.SrcModTime = impModeTime } @@ -467,7 +468,7 @@ func (s *Session) BuildPackage(pkg *PackageData) error { for _, name := range append(pkg.GoFiles, pkg.JSFiles...) { fileInfo, err := os.Stat(filepath.Join(pkg.Dir, name)) if err != nil { - return err + return nil, err } if fileInfo.ModTime().After(pkg.SrcModTime) { pkg.SrcModTime = fileInfo.ModTime() @@ -479,75 +480,79 @@ func (s *Session) BuildPackage(pkg *PackageData) error { // package object is up to date, load from disk if library pkg.UpToDate = true if pkg.IsCommand() { - return nil + return nil, nil } objFile, err := os.Open(pkg.PkgObj) if err != nil { - return err + return nil, err } defer objFile.Close() - pkg.Archive, err = compiler.ReadArchive(pkg.PkgObj, pkg.ImportPath, objFile, s.Types) + archive, err := compiler.ReadArchive(pkg.PkgObj, pkg.ImportPath, objFile, s.Types) if err != nil { - return err + return nil, err } - return nil + s.Archives[pkg.ImportPath] = archive + return archive, err } } fileSet := token.NewFileSet() files, err := parse(pkg.Package, pkg.IsTest, fileSet) if err != nil { - return err + return nil, err } importContext := &compiler.ImportContext{ Packages: s.Types, Import: func(path string) (*compiler.Archive, error) { - return s.buildImportPathWithSrcDir(path, pkg.Dir) + _, archive, err := s.buildImportPathWithSrcDir(path, pkg.Dir) + return archive, err }, } - pkg.Archive, err = compiler.Compile(pkg.ImportPath, files, fileSet, importContext, s.options.Minify) + archive, err := compiler.Compile(pkg.ImportPath, files, fileSet, importContext, s.options.Minify) if err != nil { - return err + return nil, err } for _, jsFile := range pkg.JSFiles { code, err := ioutil.ReadFile(filepath.Join(pkg.Dir, jsFile)) if err != nil { - return err + return nil, err } - pkg.Archive.IncJSCode = append(pkg.Archive.IncJSCode, []byte("\t(function() {\n")...) - pkg.Archive.IncJSCode = append(pkg.Archive.IncJSCode, code...) - pkg.Archive.IncJSCode = append(pkg.Archive.IncJSCode, []byte("\n\t}).call($global);\n")...) + archive.IncJSCode = append(archive.IncJSCode, []byte("\t(function() {\n")...) + archive.IncJSCode = append(archive.IncJSCode, code...) + archive.IncJSCode = append(archive.IncJSCode, []byte("\n\t}).call($global);\n")...) } if s.options.Verbose { fmt.Println(pkg.ImportPath) } + s.Archives[pkg.ImportPath] = archive + if pkg.PkgObj == "" || pkg.IsCommand() { - return nil + return archive, nil } - if err := s.writeLibraryPackage(pkg, pkg.PkgObj); err != nil { + if err := s.writeLibraryPackage(archive, pkg.PkgObj); err != nil { if strings.HasPrefix(pkg.PkgObj, s.options.GOROOT) { // fall back to first GOPATH workspace firstGopathWorkspace := filepath.SplitList(s.options.GOPATH)[0] - if err := s.writeLibraryPackage(pkg, filepath.Join(firstGopathWorkspace, pkg.PkgObj[len(s.options.GOROOT):])); err != nil { - return err + if err := s.writeLibraryPackage(archive, filepath.Join(firstGopathWorkspace, pkg.PkgObj[len(s.options.GOROOT):])); err != nil { + return nil, err } - return nil + return archive, nil } - return err + return nil, err } - return nil + return archive, nil } -func (s *Session) writeLibraryPackage(pkg *PackageData, pkgObj string) error { +func (s *Session) writeLibraryPackage(archive *compiler.Archive, pkgObj string) error { if err := os.MkdirAll(filepath.Dir(pkgObj), 0777); err != nil { return err } @@ -558,14 +563,10 @@ func (s *Session) writeLibraryPackage(pkg *PackageData, pkgObj string) error { } defer objFile.Close() - return compiler.WriteArchive(pkg.Archive, objFile) + return compiler.WriteArchive(archive, objFile) } -func (s *Session) WriteCommandPackage(pkg *PackageData, pkgObj string) error { - if !pkg.IsCommand() || pkg.UpToDate { - return nil - } - +func (s *Session) WriteCommandPackage(archive *compiler.Archive, pkgObj string) error { if err := os.MkdirAll(filepath.Dir(pkgObj), 0777); err != nil { return err } @@ -592,7 +593,13 @@ func (s *Session) WriteCommandPackage(pkg *PackageData, pkgObj string) error { sourceMapFilter.MappingCallback = NewMappingCallback(m, s.options.GOROOT, s.options.GOPATH) } - deps, err := compiler.ImportDependencies(pkg.Archive, s.BuildImportPath) + deps, err := compiler.ImportDependencies(archive, func(path string) (*compiler.Archive, error) { + if archive, ok := s.Archives[path]; ok { + return archive, nil + } + _, archive, err := s.buildImportPathWithSrcDir(path, "") + return archive, err + }) if err != nil { return err } diff --git a/compiler/compiler.go b/compiler/compiler.go index bdbf2fc0f..3ae154d21 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -40,8 +40,6 @@ type Archive struct { IncJSCode []byte FileSet []byte Minified bool - - types *types.Package } type Decl struct { @@ -241,11 +239,10 @@ func ReadArchive(filename, path string, r io.Reader, packages map[string]*types. } var err error - _, a.types, err = importer.ImportData(packages, a.ExportData) + _, packages[path], err = importer.ImportData(packages, a.ExportData) if err != nil { return nil, err } - packages[path] = a.types return &a, nil } diff --git a/compiler/package.go b/compiler/package.go index 9a31f2b59..5b63bac5e 100644 --- a/compiler/package.go +++ b/compiler/package.go @@ -114,7 +114,7 @@ func (pi packageImporter) Import(path string) (*types.Package, error) { return nil, err } - return a.types, nil + return pi.importContext.Packages[a.ImportPath], nil } func Compile(importPath string, files []*ast.File, fileSet *token.FileSet, importContext *ImportContext, minify bool) (*Archive, error) { @@ -530,7 +530,6 @@ func Compile(importPath string, files []*ast.File, fileSet *token.FileSet, impor Declarations: allDecls, FileSet: encodedFileSet.Bytes(), Minified: minify, - types: typesPkg, }, nil } diff --git a/tool.go b/tool.go index 5a7ef389e..581f71463 100644 --- a/tool.go +++ b/tool.go @@ -124,14 +124,17 @@ func main() { if err != nil { return err } - if err := s.BuildPackage(pkg); err != nil { + archive, err := s.BuildPackage(pkg) + if err != nil { return err } if pkgObj == "" { pkgObj = filepath.Base(args[0]) + ".js" } - if err := s.WriteCommandPackage(pkg, pkgObj); err != nil { - return err + if pkg.IsCommand() && !pkg.UpToDate { + if err := s.WriteCommandPackage(archive, pkgObj); err != nil { + return err + } } } return nil @@ -186,13 +189,25 @@ func main() { } for _, pkgPath := range pkgs { pkgPath = filepath.ToSlash(pkgPath) - if _, err := s.BuildImportPath(pkgPath); err != nil { + + pkg, err := gbuild.Import(pkgPath, 0, s.InstallSuffix(), options.BuildTags) + if s.Watcher != nil && pkg != nil { // add watch even on error + s.Watcher.Add(pkg.Dir) + } + if err != nil { return err } - pkg := s.Packages[pkgPath] - if err := s.WriteCommandPackage(pkg, pkg.PkgObj); err != nil { + + archive, err := s.BuildPackage(pkg) + if err != nil { return err } + + if pkg.IsCommand() && !pkg.UpToDate { + if err := s.WriteCommandPackage(archive, pkg.PkgObj); err != nil { + return err + } + } } return nil }, options, nil) @@ -314,11 +329,12 @@ func main() { s := gbuild.NewSession(options) tests := &testFuncs{Package: pkg.Package} collectTests := func(testPkg *gbuild.PackageData, testPkgName string, needVar *bool) error { - if err := s.BuildPackage(testPkg); err != nil { + archive, err := s.BuildPackage(testPkg) + if err != nil { return err } - for _, decl := range testPkg.Archive.Declarations { + for _, decl := range archive.Declarations { if strings.HasPrefix(decl.FullName, testPkg.ImportPath+".Test") { tests.Tests = append(tests.Tests, testFunc{Package: testPkgName, Name: decl.FullName[len(testPkg.ImportPath)+1:]}) *needVar = true @@ -367,17 +383,16 @@ func main() { return err } - mainPkg := &gbuild.PackageData{ - Package: &build.Package{ - Name: "main", - ImportPath: "main", - }, - } importContext := &compiler.ImportContext{ Packages: s.Types, - Import: s.BuildImportPath, + Import: func(path string) (*compiler.Archive, error) { + if path == pkg.ImportPath || path == pkg.ImportPath+"_test" { + return s.Archives[path], nil + } + return s.BuildImportPath(path) + }, } - mainPkg.Archive, err = compiler.Compile("main", []*ast.File{mainFile}, fset, importContext, options.Minify) + mainPkgArchive, err := compiler.Compile("main", []*ast.File{mainFile}, fset, importContext, options.Minify) if err != nil { return err } @@ -406,7 +421,7 @@ func main() { } }() - if err := s.WriteCommandPackage(mainPkg, outfile.Name()); err != nil { + if err := s.WriteCommandPackage(mainPkgArchive, outfile.Name()); err != nil { return err } @@ -552,7 +567,8 @@ func (fs serveCommandFileSystem) Open(name string) (http.File, error) { buf := bytes.NewBuffer(nil) browserErrors := bytes.NewBuffer(nil) exitCode := handleError(func() error { - if err := s.BuildPackage(pkg); err != nil { + archive, err := s.BuildPackage(pkg) + if err != nil { return err } @@ -560,7 +576,7 @@ func (fs serveCommandFileSystem) Open(name string) (http.File, error) { m := &sourcemap.Map{File: base + ".js"} sourceMapFilter.MappingCallback = gbuild.NewMappingCallback(m, fs.options.GOROOT, fs.options.GOPATH) - deps, err := compiler.ImportDependencies(pkg.Archive, s.BuildImportPath) + deps, err := compiler.ImportDependencies(archive, s.BuildImportPath) if err != nil { return err }