Skip to content

Commit aebb4ea

Browse files
committed
build: Load js, nosync packages from gopherjspkg rather than GOPATH.
The Go stdlib overrides (i.e., compiler/natives package) are already embedded into the GopherJS build system. This makes it possible for the gopherjs binary to access them even if the gopherjs repository is not present in GOPATH (e.g., because it was deleted, or because it's vendored). Doing that for natives but not the js, nosync packages makes little sense, since the gopherjs repository still needs to exist in GOPATH. This change fixes that. By embedding the core GopherJS packages analogously to natives, the gopherjs binary becomes more standalone. Now, it only requires GOROOT/src to contain the matching version of Go source code. Non-core GopherJS packages are not embedded (e.g., the GopherJS compiler itself). That means it needs to exist in GOPATH to be buildable (otherwise, the user gets a "cannot find package" error). This is expected just like with any other normal Go package. Fixes #462. Helps #415.
1 parent 1b676f7 commit aebb4ea

File tree

2 files changed

+65
-14
lines changed

2 files changed

+65
-14
lines changed

build/build.go

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,11 @@ import (
2121

2222
"github.com/fsnotify/fsnotify"
2323
"github.com/gopherjs/gopherjs/compiler"
24+
"github.com/gopherjs/gopherjs/compiler/gopherjspkg"
2425
"github.com/gopherjs/gopherjs/compiler/natives"
2526
"github.com/neelance/sourcemap"
27+
"github.com/shurcooL/httpfs/vfsutil"
28+
"golang.org/x/tools/go/buildutil"
2629
)
2730

2831
type ImportCError struct {
@@ -35,7 +38,11 @@ func (e *ImportCError) Error() string {
3538

3639
// NewBuildContext creates a build context for building Go packages
3740
// with GopherJS compiler.
41+
//
42+
// Core GopherJS packages (i.e., "github.com/gopherjs/gopherjs/js", "github.com/gopherjs/gopherjs/nosync")
43+
// are loaded from gopherjspkg.FS virtual filesystem rather than GOPATH.
3844
func NewBuildContext(installSuffix string, buildTags []string) *build.Context {
45+
gopherJSRoot := filepath.Join(build.Default.GOROOT, "src", "github.com", "gopherjs", "gopherjs")
3946
return &build.Context{
4047
GOROOT: build.Default.GOROOT,
4148
GOPATH: build.Default.GOPATH,
@@ -49,7 +56,50 @@ func NewBuildContext(installSuffix string, buildTags []string) *build.Context {
4956
),
5057
ReleaseTags: build.Default.ReleaseTags,
5158
CgoEnabled: true, // detect `import "C"` to throw proper error
59+
60+
IsDir: func(path string) bool {
61+
if strings.HasPrefix(path, gopherJSRoot+string(filepath.Separator)) {
62+
path = filepath.ToSlash(path[len(gopherJSRoot):])
63+
if fi, err := vfsutil.Stat(gopherjspkg.FS, path); err == nil {
64+
return fi.IsDir()
65+
}
66+
}
67+
fi, err := os.Stat(path)
68+
return err == nil && fi.IsDir()
69+
},
70+
ReadDir: func(path string) ([]os.FileInfo, error) {
71+
if strings.HasPrefix(path, gopherJSRoot+string(filepath.Separator)) {
72+
path = filepath.ToSlash(path[len(gopherJSRoot):])
73+
if fis, err := vfsutil.ReadDir(gopherjspkg.FS, path); err == nil {
74+
return fis, nil
75+
}
76+
}
77+
return ioutil.ReadDir(path)
78+
},
79+
OpenFile: func(path string) (io.ReadCloser, error) {
80+
if strings.HasPrefix(path, gopherJSRoot+string(filepath.Separator)) {
81+
path = filepath.ToSlash(path[len(gopherJSRoot):])
82+
if f, err := gopherjspkg.FS.Open(path); err == nil {
83+
return f, nil
84+
}
85+
}
86+
return os.Open(path)
87+
},
88+
}
89+
}
90+
91+
// statFile returns an os.FileInfo describing the named file.
92+
// For files in "$GOROOT/src/github.com/gopherjs/gopherjs" directory,
93+
// gopherjspkg.FS is consulted first.
94+
func statFile(path string) (os.FileInfo, error) {
95+
gopherJSRoot := filepath.Join(build.Default.GOROOT, "src", "github.com", "gopherjs", "gopherjs")
96+
if strings.HasPrefix(path, gopherJSRoot+string(filepath.Separator)) {
97+
path = filepath.ToSlash(path[len(gopherJSRoot):])
98+
if fi, err := vfsutil.Stat(gopherjspkg.FS, path); err == nil {
99+
return fi, nil
100+
}
52101
}
102+
return os.Stat(path)
53103
}
54104

55105
// Import returns details about the Go package named by the import path. If the
@@ -137,7 +187,7 @@ func importWithSrcDir(bctx *build.Context, path string, srcDir string, mode buil
137187
}
138188
}
139189

140-
jsFiles, err := jsFilesFromDir(pkg.Dir)
190+
jsFiles, err := jsFilesFromDir(bctx, pkg.Dir)
141191
if err != nil {
142192
return nil, err
143193
}
@@ -176,12 +226,13 @@ Outer:
176226
// ImportDir is like Import but processes the Go package found in the named
177227
// directory.
178228
func ImportDir(dir string, mode build.ImportMode, installSuffix string, buildTags []string) (*PackageData, error) {
179-
pkg, err := NewBuildContext(installSuffix, buildTags).ImportDir(dir, mode)
229+
bctx := NewBuildContext(installSuffix, buildTags)
230+
pkg, err := bctx.ImportDir(dir, mode)
180231
if err != nil {
181232
return nil, err
182233
}
183234

184-
jsFiles, err := jsFilesFromDir(pkg.Dir)
235+
jsFiles, err := jsFilesFromDir(bctx, pkg.Dir)
185236
if err != nil {
186237
return nil, err
187238
}
@@ -200,7 +251,7 @@ func ImportDir(dir string, mode build.ImportMode, installSuffix string, buildTag
200251
// as an existing file from the standard library). For all identifiers that exist
201252
// in the original AND the overrides, the original identifier in the AST gets
202253
// replaced by `_`. New identifiers that don't exist in original package get added.
203-
func parseAndAugment(pkg *build.Package, isTest bool, fileSet *token.FileSet) ([]*ast.File, error) {
254+
func parseAndAugment(bctx *build.Context, pkg *build.Package, isTest bool, fileSet *token.FileSet) ([]*ast.File, error) {
204255
var files []*ast.File
205256
replacedDeclNames := make(map[string]bool)
206257
funcName := func(d *ast.FuncDecl) string {
@@ -304,10 +355,10 @@ func parseAndAugment(pkg *build.Package, isTest bool, fileSet *token.FileSet) ([
304355

305356
var errList compiler.ErrorList
306357
for _, name := range pkg.GoFiles {
307-
if !filepath.IsAbs(name) {
358+
if !filepath.IsAbs(name) { // name might be absolute if specified directly. E.g., `gopherjs build /abs/file.go`.
308359
name = filepath.Join(pkg.Dir, name)
309360
}
310-
r, err := os.Open(name)
361+
r, err := buildutil.OpenFile(bctx, name)
311362
if err != nil {
312363
return nil, err
313364
}
@@ -465,7 +516,7 @@ func (s *Session) BuildDir(packagePath string, importPath string, pkgObj string)
465516
return err
466517
}
467518
pkg := &PackageData{Package: buildPkg}
468-
jsFiles, err := jsFilesFromDir(pkg.Dir)
519+
jsFiles, err := jsFilesFromDir(s.bctx, pkg.Dir)
469520
if err != nil {
470521
return err
471522
}
@@ -584,7 +635,7 @@ func (s *Session) BuildPackage(pkg *PackageData) (*compiler.Archive, error) {
584635
}
585636

586637
for _, name := range append(pkg.GoFiles, pkg.JSFiles...) {
587-
fileInfo, err := os.Stat(filepath.Join(pkg.Dir, name))
638+
fileInfo, err := statFile(filepath.Join(pkg.Dir, name))
588639
if err != nil {
589640
return nil, err
590641
}
@@ -618,7 +669,7 @@ func (s *Session) BuildPackage(pkg *PackageData) (*compiler.Archive, error) {
618669
}
619670

620671
fileSet := token.NewFileSet()
621-
files, err := parseAndAugment(pkg.Package, pkg.IsTest, fileSet)
672+
files, err := parseAndAugment(s.bctx, pkg.Package, pkg.IsTest, fileSet)
622673
if err != nil {
623674
return nil, err
624675
}
@@ -756,8 +807,8 @@ func NewMappingCallback(m *sourcemap.Map, goroot, gopath string, localMap bool)
756807
}
757808
}
758809

759-
func jsFilesFromDir(dir string) ([]string, error) {
760-
files, err := ioutil.ReadDir(dir)
810+
func jsFilesFromDir(bctx *build.Context, dir string) ([]string, error) {
811+
files, err := buildutil.ReadDir(bctx, dir)
761812
if err != nil {
762813
return nil, err
763814
}

build/build_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func TestNativesDontImportExtraPackages(t *testing.T) {
7777

7878
// Use parseAndAugment to get a list of augmented AST files.
7979
fset := token.NewFileSet()
80-
files, err := parseAndAugment(bpkg, false, fset)
80+
files, err := parseAndAugment(NewBuildContext("", nil), bpkg, false, fset)
8181
if err != nil {
8282
t.Fatalf("github.com/gopherjs/gopherjs/build.parseAndAugment: %v", err)
8383
}
@@ -116,7 +116,7 @@ func TestNativesDontImportExtraPackages(t *testing.T) {
116116

117117
// Use parseAndAugment to get a list of augmented AST files.
118118
fset := token.NewFileSet()
119-
files, err := parseAndAugment(bpkg, true, fset)
119+
files, err := parseAndAugment(NewBuildContext("", nil), bpkg, true, fset)
120120
if err != nil {
121121
t.Fatalf("github.com/gopherjs/gopherjs/build.parseAndAugment: %v", err)
122122
}
@@ -158,7 +158,7 @@ func TestNativesDontImportExtraPackages(t *testing.T) {
158158

159159
// Use parseAndAugment to get a list of augmented AST files, then check only the external test files.
160160
fset := token.NewFileSet()
161-
files, err := parseAndAugment(bpkg, true, fset)
161+
files, err := parseAndAugment(NewBuildContext("", nil), bpkg, true, fset)
162162
if err != nil {
163163
t.Fatalf("github.com/gopherjs/gopherjs/build.parseAndAugment: %v", err)
164164
}

0 commit comments

Comments
 (0)