-
Notifications
You must be signed in to change notification settings - Fork 570
Embed core GopherJS packages into build system; enable vendoring of GopherJS. #787
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
I'd be happy if you could tell me the steps to test this. |
// | ||
package gopherjspkg | ||
|
||
//go:generate vfsgendev -source="github.com/gopherjs/gopherjs/compiler/gopherjspkg".FS -tag=gopherjsdev |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where does vfgendev
come from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please can we make this go:generate
directive not rely on vfsgendev
being in PATH
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's out of scope for this PR. This gopherjspkg
package is the same in structure as natives
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. This would be better solved in any case by golang/go#22726
The way I tested was:
You can also see #678 (comment) for more ideas. |
NEWGOPATH=/tmp/gopherjs
rm -rf $NEWGOPATH
GOPATH=$NEWGOPATH go get github.com/gopherjs/gopherjs
(cd $NEWGOPATH/src/github.com/gopherjs/gopherjs; git checkout origin/embed-core-pkgs)
mkdir -p $NEWGOPATH/src/github.com/hajimehoshi/gopherjstest
echo 'package main
import "github.com/gopherjs/gopherjs/js"
func main() {
js.Global.Get("console").Call("log", "Hello")
}' > $NEWGOPATH/src/github.com/hajimehoshi/gopherjstest/main.go
mkdir -p $NEWGOPATH/src/github.com/hajimehoshi/gopherjstest/vendor/github.com/gopherjs
# vendering
cp -r $NEWGOPATH/src/github.com/gopherjs/gopherjs $NEWGOPATH/src/github.com/hajimehoshi/gopherjstest/vendor/github.com/gopherjs
rm -rf $NEWGOPATH/src/github.com/gopherjs/gopherjs
GOPATH=$NEWGOPATH go build github.com/hajimehoshi/gopherjstest
GOPATH=$NEWGOPATH $NEWGOPATH/bin/gopherjs run $NEWGOPATH/src/github.com/hajimehoshi/gopherjstest/main.go failed with the message
Am I missing something? (Without vendering, it succeeded to say 'Hello'.) EDIT: Ah, gopherjs command itself relies on GOPATH/src/github.com/gohperjs/gopherjs, not vendered one. EDIT2: Hmm, reinstalling gopherjs command doesn't change the situation 🤔 NEWGOPATH=/tmp/gopherjs
rm -rf $NEWGOPATH
GOPATH=$NEWGOPATH go get github.com/gopherjs/gopherjs
(cd $NEWGOPATH/src/github.com/gopherjs/gopherjs; git checkout origin/embed-core-pkgs)
# Create the main package
mkdir -p $NEWGOPATH/src/foobarbaz/hajimehoshi/gopherjstest
echo 'package main
import "github.com/gopherjs/gopherjs/js"
func main() {
js.Global.Get("console").Call("log", "Hello")
}' > $NEWGOPATH/src/foobarbaz/hajimehoshi/gopherjstest/main.go
mkdir -p $NEWGOPATH/src/foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/gopherjs
# Vendering
cp -r $NEWGOPATH/src/github.com $NEWGOPATH/src/foobarbaz/hajimehoshi/gopherjstest/vendor
cp -r $NEWGOPATH/src/golang.org $NEWGOPATH/src/foobarbaz/hajimehoshi/gopherjstest/vendor
rm -rf $NEWGOPATH/src/github.com/gopherjs/gopherjs
GOPATH=$NEWGOPATH go install foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/gopherjs/gopherjs
GOPATH=$NEWGOPATH go build foobarbaz/hajimehoshi/gopherjstest
GOPATH=$NEWGOPATH $NEWGOPATH/bin/gopherjs run $NEWGOPATH/src/foobarbaz/hajimehoshi/gopherjstest/main.go |
Should we be getting tests like the ones you describe in a script (or similar) as part of the repo? Automates the process of verifying that the behaviour is as described, makes it easier for you to test that the vendored version works with any subsequent commits/changes submitted to this PR, but also makes it easier for anyone else making future (unrelated) changes to verify that their changes haven't broken the vendor behaviour. |
@hajimehoshi I think you were forgetting to install the checked out PR branch in the first script. Instead of doing -GOPATH=$NEWGOPATH go get github.com/gopherjs/gopherjs
+GOPATH=$NEWGOPATH go get -d github.com/gopherjs/gopherjs
(cd $NEWGOPATH/src/github.com/gopherjs/gopherjs; git checkout origin/embed-core-pkgs)
+GOPATH=$NEWGOPATH go get github.com/shurcooL/httpfs/vfsutil
+GOPATH=$NEWGOPATH go install github.com/gopherjs/gopherjs You can also do The second one looks like it should've worked. Let me try it and see if I can reproduce.
Yes, adding a test for this would be nice. |
@hajimehoshi I followed your edited instructions and got a different outcome. Notably, I think you made a mistake somewhere, and ended up using the See the log from my terminal for reference: Last login: Sun Apr 8 13:11:18 on ttys000
~ $ cd /tmp/
tmp $ ls
com.apple.launchd.0q00aXw85q powerlog
com.apple.launchd.v3Mhw42Gmb
tmp $ NEWGOPATH=/tmp/go2
tmp $ ls $NEWGOPATH
ls: /tmp/go2: No such file or directory
tmp $ rm -rf $NEWGOPATH
tmp $ GOPATH=$NEWGOPATH go get github.com/gopherjs/gopherjs
tmp $ tree $NEWGOPATH | head
/tmp/go2
├── bin
│ └── gopherjs
└── src
├── github.com
│ ├── fsnotify
│ │ └── fsnotify
│ │ ├── AUTHORS
│ │ ├── CHANGELOG.md
│ │ ├── CONTRIBUTING.md
tmp $ (cd $NEWGOPATH/src/github.com/gopherjs/gopherjs; git checkout origin/embed-core-pkgs)
Note: checking out 'origin/embed-core-pkgs'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b <new-branch-name>
HEAD is now at 9b293ec... README: Remove note saying vendoring GopherJS is unsupported.
tmp $ mkdir -p $NEWGOPATH/src/foobarbaz/hajimehoshi/gopherjstest
tmp $ echo 'package main
>
> import "github.com/gopherjs/gopherjs/js"
>
> func main() {
> js.Global.Get("console").Call("log", "Hello")
> }' > $NEWGOPATH/src/foobarbaz/hajimehoshi/gopherjstest/main.go
tmp $ tree /tmp/go2/src/foobarbaz/
/tmp/go2/src/foobarbaz/
└── hajimehoshi
└── gopherjstest
└── main.go
2 directories, 1 file
tmp $ mkdir -p $NEWGOPATH/src/foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/gopherjs
tmp $ ls go2/src/
foobarbaz github.com golang.org
tmp $ cp -r $NEWGOPATH/src/github.com $NEWGOPATH/src/foobarbaz/hajimehoshi/gopherjstest/vendor
tmp $ cp -r $NEWGOPATH/src/golang.org $NEWGOPATH/src/foobarbaz/hajimehoshi/gopherjstest/vendor
tmp $ cd go2
go2 $ ls
bin src
go2 $ ls src/
foobarbaz/ github.com/ golang.org/
go2 $ ls src/foobarbaz/hajimehoshi/gopherjstest/vendor/
github.com golang.org
go2 $ rm -rf $NEWGOPATH/src/github.com/gopherjs/gopherjs
go2 $ ls -la bin/gopherjs
-rwxr-xr-x 1 Dmitri staff 12955388 Apr 8 13:24 bin/gopherjs
go2 $ GOPATH=$NEWGOPATH go install -v foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/gopherjs/gopherjs
src/foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/gopherjs/gopherjs/build/build.go:27:2: cannot find package "github.com/shurcooL/httpfs/vfsutil" in any of:
/tmp/go2/src/foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/shurcooL/httpfs/vfsutil (vendor tree)
/usr/local/go/src/github.com/shurcooL/httpfs/vfsutil (from $GOROOT)
/tmp/go2/src/github.com/shurcooL/httpfs/vfsutil (from $GOPATH)
go2 $ (mkdir /tmp/go2/src/foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/shurcooL; cd /tmp/go2/src/foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/shurcooL; git clone https://github.com/shurcooL/httpfs)
Cloning into 'httpfs'...
remote: Counting objects: 197, done.
remote: Total 197 (delta 0), reused 0 (delta 0), pack-reused 197
Receiving objects: 100% (197/197), 32.35 KiB | 1.08 MiB/s, done.
Resolving deltas: 100% (82/82), done.
go2 $ GOPATH=$NEWGOPATH go install -v foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/gopherjs/gopherjs
foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/gopherjs/gopherjs/compiler/prelude
foobarbaz/hajimehoshi/gopherjstest/vendor/golang.org/x/sys/unix
foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/neelance/sourcemap
foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/kisielk/gotool/internal/load
foobarbaz/hajimehoshi/gopherjstest/vendor/golang.org/x/tools/go/buildutil
foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/gopherjs/gopherjs/compiler/astutil
foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/gopherjs/gopherjs/compiler/typesutil
foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/spf13/pflag
foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/gopherjs/gopherjs/compiler/vendor/github.com/neelance/astrewrite
foobarbaz/hajimehoshi/gopherjstest/vendor/golang.org/x/tools/go/gcimporter15
foobarbaz/hajimehoshi/gopherjstest/vendor/golang.org/x/tools/go/types/typeutil
foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/gopherjs/gopherjs/compiler/filter
foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/gopherjs/gopherjs/compiler/analysis
foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/gopherjs/gopherjs/compiler/gopherjspkg
foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/gopherjs/gopherjs/compiler/natives
foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/shurcooL/httpfs/vfsutil
foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/kisielk/gotool
foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/gopherjs/gopherjs/compiler
foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/gopherjs/gopherjs/internal/sysutil
foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/fsnotify/fsnotify
foobarbaz/hajimehoshi/gopherjstest/vendor/golang.org/x/crypto/ssh/terminal
foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/spf13/cobra
foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/gopherjs/gopherjs/build
foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/gopherjs/gopherjs
go2 $ GOPATH=$NEWGOPATH go build foobarbaz/hajimehoshi/gopherjstest
go2 $ GOPATH=$NEWGOPATH $NEWGOPATH/bin/gopherjs run $NEWGOPATH/src/foobarbaz/hajimehoshi/gopherjstest/main.go
Hello
go2 $ I'm going to bump the GopherJS version in this PR, so it'll be easier to tell it apart from previous versions (that did not support vendoring). |
@shurcooL OK, I've succeeded to say 'hello' with your fix, thank you! NEWGOPATH=/tmp/gopherjs
rm -rf $NEWGOPATH
GOPATH=$NEWGOPATH go get -d github.com/gopherjs/gopherjs
(cd $NEWGOPATH/src/github.com/gopherjs/gopherjs; git checkout origin/embed-core-pkgs)
GOPATH=$NEWGOPATH go get github.com/shurcooL/httpfs/vfsutil
GOPATH=$NEWGOPATH go install github.com/gopherjs/gopherjs
# Create the main package
mkdir -p $NEWGOPATH/src/foobarbaz/hajimehoshi/gopherjstest
echo 'package main
import "github.com/gopherjs/gopherjs/js"
func main() {
js.Global.Get("console").Call("log", "Hello")
}' > $NEWGOPATH/src/foobarbaz/hajimehoshi/gopherjstest/main.go
mkdir -p $NEWGOPATH/src/foobarbaz/hajimehoshi/gopherjstest/vendor/github.com/gopherjs
# Vendering
cp -r $NEWGOPATH/src/github.com $NEWGOPATH/src/foobarbaz/hajimehoshi/gopherjstest/vendor
cp -r $NEWGOPATH/src/golang.org $NEWGOPATH/src/foobarbaz/hajimehoshi/gopherjstest/vendor
rm -rf $NEWGOPATH/src/github.com/gopherjs/gopherjs
GOPATH=$NEWGOPATH go build foobarbaz/hajimehoshi/gopherjstest
GOPATH=$NEWGOPATH $NEWGOPATH/bin/gopherjs run $NEWGOPATH/src/foobarbaz/hajimehoshi/gopherjstest/main.go |
build/build.go
Outdated
IsDir: func(path string) bool { | ||
if strings.HasPrefix(path, gopherJSRoot+string(filepath.Separator)) { | ||
path = filepath.ToSlash(path[len(gopherJSRoot):]) | ||
if fi, err := vfsutil.Stat(gopherjspkg.FS, path); err == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This condition is repeated four times, so how about creating a function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which condition, exactly? I don't see a way of making this code simpler, can you show what you had in mind?
Note that these funcs return different signatures (bool
, ([]os.FileInfo, error)
, (io.ReadCloser, error)
, (os.FileInfo, error)
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry but I meant strings.HasPrefix(path, gopherJSRoot+string(filepath.Separator)
or path = filepath.ToSlash(path[len(gopherJSRoot):])
. Aren't they repeated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, thanks for clarifying.
I've considered it, but I think keeping it as is is more readable and simpler. The duplication is locally contained in the same place. Factoring it out into a helper moves the relevant code further away from where it's being used, and there's just too little code here to factor out efficiently.
@@ -91,17 +145,17 @@ func importWithSrcDir(path string, srcDir string, mode build.ImportMode, install | |||
case "crypto/x509", "os/user": | |||
// These stdlib packages have cgo and non-cgo versions (via build tags); we want the latter. | |||
bctx.CgoEnabled = false | |||
case "github.com/gopherjs/gopherjs/js", "github.com/gopherjs/gopherjs/nosync": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't it ok to check in the above way like strings.HasPrefix(path, gopherJSRoot+string(filepath.Separator)
for consistency?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, because this needs to be those 2 packages only. We don't want github.com/gopherjs/gopherjs/compiler
or others to be included.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, thanks. I feel like this set is duplicated with FS
definition in fs.go
. Would it be possible to unify these sets into one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "core" GopherJS packages are enumerated and documented in the package comment of ./compiler/gopherjspkg
package (see compiler/gopherjspkg/doc.go
file).
Here, the ./build
package implements that. It uses import paths.
In gopherjspkg.FS
, the code picks up those packages via relative directory paths.
I don't think anything more needs to be done, this is very simple, and trying to make it more DRY isn't worth the effort (I'm usually all for it, but it needs to be worthwhile).
compiler/gopherjspkg/fs.go
Outdated
func(path string, fi os.FileInfo) bool { | ||
return path == "/" || | ||
path == "/js" || strings.HasPrefix(path, "/js/") || | ||
path == "/nosync" || strings.HasPrefix(path, "/nosync/") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not only github.com/gopherjs/js
, but also github.com/gopherjs/js/foobar
would be a special path?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we add a new package under js
or nosync
, yes, it would get included here. The chances of that are very low, so we can deal with it when/if it happens. We might want to include it as "core" or exclude it (by making the filter above more picky).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made the filter more precise in 2ad4a5b, so it won't pick up any subdirectories now.
And as @myitcv suggests, we should have a test for this. |
@shurcooL I haven't looked at the code at all, but with this PR it seems I was able to build Perkeep without our temp GOPATH hackery, so LGTM as far as I'm concerned. thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should have a test for this.
I'll try to make one. It needs to be simple and be able to run offline, so go get
isn't allowed. It should be doable by copying the gopherjs
repo itself into a temporary folder and making that the GOPATH
.
I was able to build Perkeep without our temp GOPATH hackery
Good to hear, thanks for trying it!
compiler/gopherjspkg/fs.go
Outdated
func(path string, fi os.FileInfo) bool { | ||
return path == "/" || | ||
path == "/js" || strings.HasPrefix(path, "/js/") || | ||
path == "/nosync" || strings.HasPrefix(path, "/nosync/") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we add a new package under js
or nosync
, yes, it would get included here. The chances of that are very low, so we can deal with it when/if it happens. We might want to include it as "core" or exclude it (by making the filter above more picky).
@@ -91,17 +145,17 @@ func importWithSrcDir(path string, srcDir string, mode build.ImportMode, install | |||
case "crypto/x509", "os/user": | |||
// These stdlib packages have cgo and non-cgo versions (via build tags); we want the latter. | |||
bctx.CgoEnabled = false | |||
case "github.com/gopherjs/gopherjs/js", "github.com/gopherjs/gopherjs/nosync": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, because this needs to be those 2 packages only. We don't want github.com/gopherjs/gopherjs/compiler
or others to be included.
build/build.go
Outdated
IsDir: func(path string) bool { | ||
if strings.HasPrefix(path, gopherJSRoot+string(filepath.Separator)) { | ||
path = filepath.ToSlash(path[len(gopherJSRoot):]) | ||
if fi, err := vfsutil.Stat(gopherjspkg.FS, path); err == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which condition, exactly? I don't see a way of making this code simpler, can you show what you had in mind?
Note that these funcs return different signatures (bool
, ([]os.FileInfo, error)
, (io.ReadCloser, error)
, (os.FileInfo, error)
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I'll wait for you adding tests :-)
build/build.go
Outdated
IsDir: func(path string) bool { | ||
if strings.HasPrefix(path, gopherJSRoot+string(filepath.Separator)) { | ||
path = filepath.ToSlash(path[len(gopherJSRoot):]) | ||
if fi, err := vfsutil.Stat(gopherjspkg.FS, path); err == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry but I meant strings.HasPrefix(path, gopherJSRoot+string(filepath.Separator)
or path = filepath.ToSlash(path[len(gopherJSRoot):])
. Aren't they repeated?
@@ -91,17 +145,17 @@ func importWithSrcDir(path string, srcDir string, mode build.ImportMode, install | |||
case "crypto/x509", "os/user": | |||
// These stdlib packages have cgo and non-cgo versions (via build tags); we want the latter. | |||
bctx.CgoEnabled = false | |||
case "github.com/gopherjs/gopherjs/js", "github.com/gopherjs/gopherjs/nosync": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, thanks. I feel like this set is duplicated with FS
definition in fs.go
. Would it be possible to unify these sets into one?
c934767
to
50a9ce5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haven't read all the code but this branch is working for me when vendoring gopherjs/gopherjs.
The only change I had to make was to include a dummy go file with import _ "github.com/gopherjs/gopherjs"
so that the dep tool will pull in everything instead of just the libraries directory.
163f6c0
to
49f2b5c
Compare
I've added a test that GopherJS can be vendored in commit 49f2b5c. It's passing CI. I've cherry-picked the same commit onto latest
That means the test is working as expected. PTAL. I'll deal with the remaining minor comments next. |
Improved failing test output in commit 8a9d21b:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for review comments and suggestions @hajimehoshi. I've considered and addressed them all. This is ready from my side now. PTAL.
compiler/gopherjspkg/fs.go
Outdated
func(path string, fi os.FileInfo) bool { | ||
return path == "/" || | ||
path == "/js" || strings.HasPrefix(path, "/js/") || | ||
path == "/nosync" || strings.HasPrefix(path, "/nosync/") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made the filter more precise in 2ad4a5b, so it won't pick up any subdirectories now.
@@ -91,17 +145,17 @@ func importWithSrcDir(path string, srcDir string, mode build.ImportMode, install | |||
case "crypto/x509", "os/user": | |||
// These stdlib packages have cgo and non-cgo versions (via build tags); we want the latter. | |||
bctx.CgoEnabled = false | |||
case "github.com/gopherjs/gopherjs/js", "github.com/gopherjs/gopherjs/nosync": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "core" GopherJS packages are enumerated and documented in the package comment of ./compiler/gopherjspkg
package (see compiler/gopherjspkg/doc.go
file).
Here, the ./build
package implements that. It uses import paths.
In gopherjspkg.FS
, the code picks up those packages via relative directory paths.
I don't think anything more needs to be done, this is very simple, and trying to make it more DRY isn't worth the effort (I'm usually all for it, but it needs to be worthwhile).
build/build.go
Outdated
IsDir: func(path string) bool { | ||
if strings.HasPrefix(path, gopherJSRoot+string(filepath.Separator)) { | ||
path = filepath.ToSlash(path[len(gopherJSRoot):]) | ||
if fi, err := vfsutil.Stat(gopherjspkg.FS, path); err == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, thanks for clarifying.
I've considered it, but I think keeping it as is is more readable and simpler. The duplication is locally contained in the same place. Factoring it out into a helper moves the relevant code further away from where it's being used, and there's just too little code here to factor out efficiently.
I filed issue #792 for some potential followup work. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost lgtm
tests/gorepo_test.go
Outdated
t.Fatal(err) | ||
} | ||
if want := "hello using js pkg\n"; string(got) != want { | ||
t.Errorf("got != want:\ngot:\n%s\nwant:\n%s", got, want) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd write the message mentioning the script like gopherjsvendored_test.js failed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The failure output is:
$ go test -v -run=TestGopherJSCanBeVendored
=== RUN TestGopherJSCanBeVendored
--- FAIL: TestGopherJSCanBeVendored (17.78s)
gorepo_test.go:43: got != want:
got:
unexpected output 123
want:
hello using js pkg
FAIL
exit status 1
FAIL github.com/gopherjs/gopherjs/tests 17.787s
There's only one got != want
check in the test. It seems okay as is, isn't it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, as I am not sure GopherJS's test policy, I don't have a strong opinion on it. Then, that's fine :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can make it something like this, hope it's more clear:
unexpected stdout from gopherjsvendored_test.sh:
got:
unexpected output 123
want:
hello using js pkg
tests/gorepo_test.go
Outdated
} | ||
|
||
cmd := exec.Command("bash", "gopherjsvendored_test.sh") | ||
cmd.Stderr = os.Stdout |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not catching the stderr and dumping it as an error message?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test is considered failed if the exit code is non-zero, or if the stdout output is not exactly the expected "hello using js pkg\n" value.
Stderr can be anything, it shouldn't fail the test. It's just information.
For example, if you run the test without the sourcemap module, it'll print "gopherjs: Source maps disabled. Install source-map-support module for ..." message to stderr.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense.
tests/gopherjsvendored_test.sh
Outdated
cp -r $(go list -e -f '{{.Dir}}' github.com/spf13/pflag) "$tmp/src/example.org/hello/vendor/github.com/spf13/pflag" | ||
cp -r $(go list -e -f '{{.Dir}}' golang.org/x/crypto) "$tmp/src/example.org/hello/vendor/golang.org/x/crypto" | ||
cp -r $(go list -e -f '{{.Dir}}' golang.org/x/sys) "$tmp/src/example.org/hello/vendor/golang.org/x/sys" | ||
cp -r $(go list -e -f '{{.Dir}}' golang.org/x/tools) "$tmp/src/example.org/hello/vendor/golang.org/x/tools" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If GopherJS's dependencies are changed, we should update these items, right? At least, should we leave a comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. Perhaps this script can be improved in the future to infer dependencies more automatically (e.g., with go list -f '{{join .Deps "\n"}}' github.com/gopherjs/gopherjs/...
or so).
There's a comment on top saying # Vendor GopherJS and its dependencies into hello project.
, is it not clear?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feels like we should make this change now; it's brittle having these hard-coded, particularly when using go list
is something that we're already doing elsewhere and is easy to make work in this situation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed with @myitcv . This doesn't look so hard.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll take a look through this more closely later. I do have a question about your comments in #792 though - which I will ask there.
tests/gopherjsvendored_test.sh
Outdated
cp -r $(go list -e -f '{{.Dir}}' github.com/spf13/pflag) "$tmp/src/example.org/hello/vendor/github.com/spf13/pflag" | ||
cp -r $(go list -e -f '{{.Dir}}' golang.org/x/crypto) "$tmp/src/example.org/hello/vendor/golang.org/x/crypto" | ||
cp -r $(go list -e -f '{{.Dir}}' golang.org/x/sys) "$tmp/src/example.org/hello/vendor/golang.org/x/sys" | ||
cp -r $(go list -e -f '{{.Dir}}' golang.org/x/tools) "$tmp/src/example.org/hello/vendor/golang.org/x/tools" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feels like we should make this change now; it's brittle having these hard-coded, particularly when using go list
is something that we're already doing elsewhere and is easy to make work in this situation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a few more comments; please also note I added a response over in #792 (comment)
// | ||
package gopherjspkg | ||
|
||
//go:generate vfsgendev -source="github.com/gopherjs/gopherjs/compiler/gopherjspkg".FS -tag=gopherjsdev |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please can we make this go:generate
directive not rely on vfsgendev
being in PATH
?
compiler/version_check.go
Outdated
@@ -6,4 +6,4 @@ package compiler | |||
const ___GOPHERJS_REQUIRES_GO_VERSION_1_10___ = true | |||
|
|||
// Version is the GopherJS compiler version string. | |||
const Version = "1.10-2" | |||
const Version = "1.10-3" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we not do a release separately from this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see a difference, but sure, I can take out this commit and apply it on master
after this PR lands.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The difference being that if this PR needs to be reverted at a later date we don't want to revert the version change. Keeping the release as a separate PR ensures we have that ability.
tests/gorepo_test.go
Outdated
t.Skip("test meant to be run using normal Go compiler (needs os/exec)") | ||
} | ||
|
||
cmd := exec.Command("bash", "gopherjsvendored_test.sh") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sh
should be sufficient here; and more flexible to those who do not use bash
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you see the commit message of 49f2b5c?
However, I think I know what it'll take to make it work with sh
. It might just be a matter of removing the SIG
prefix from the signal names. I'll try it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it not cleaner to just write this test as // +build ignore
-d .go
file in any case? That way we don't need to worry about shells, traps etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I often prefer Go over other tools, but a bash script seemed like a good fit for this task. It was based on the bash script in playground repo, which has been used with success for some years.
It's already done and it works well. I don't see a need to spend much more time on it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will leave it up to you. It might be, however, that addressing https://github.com/gopherjs/gopherjs/pull/787/files/2ad4a5b9a30e5f1f31c643c2a2ac27543a5ddb58#r181624969 would be easier/clearer in a .go
file.
Call NewBuildContext at the top of Import, ImportDir, and inside NewSession. Previously, it was called more often than necessary (instead of being preserved for entire build session). Pass build context by value to importWithSrcDir so it can be safely modified there, without the changes persisisting from one package to the next. The build context will need to be available in more places in an upcoming commit. Storing it in Session helps with that.
This package embeds the core GopherJS packages (js, nosync). It's similar to how native overrides for stdlib are embedded in the compiler/natives package. Pick only files in /fs and /nosync, and no subdirectories (if any are added, they won't get included by default).
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.
…nosync. These core GopherJS packages are already embedded into the GopherJS build system via the gopherjspkg virtual filesystem. The gopherjspkg package can be safely vendored. Therefore, there's no need to try to use vendor directory to resolve those packages. This change makes it possible to use a vendored copy of GopherJS in a project, and use it to build any Go code. Fixes #415.
The _test.go file needs to be accessed via the build context's file system interface. Take into account the fact that the js and nosync packages are now effectively virtual, and don't have a corresponding physical directory. Use current directory when running tests with Node.js, otherwise it would fail with "directory not exist" error.
Rely on runtime.GOARCH and t.Skip to skip tests that shouldn't be run with GopherJS. It's more clear and reliable than a file-wide build tag. Include stderr from gopherjsvendored_test.sh in output of TestGopherJSCanBeVendored. This is only to get get more information when it fails.
2ad4a5b
to
c8e5f7c
Compare
I've rebased this PR on top of latest (Previous PR version was 2ad4a5b.) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
@myitcv, are you happy with this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a couple of minor comments/questions, but nothing blocking.
|
||
# Make a hello project that will vendor GopherJS. | ||
mkdir -p "$tmp/src/example.org/hello" | ||
echo 'package main |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a minor thought, but the heredoc syntax often reads a bit cleaner in these multi-line situations because the redirect is on the same line:
cat <<EOD > "$tmp/src/example.org/hello/main.go"
package main
import "github.com/gopherjs/gopherjs/js"
func main() {
js.Global.Get("console").Call("log", "hello using js pkg")
}
EOD
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the suggestion. I wasn't familiar with this syntax, but I'll consider it next time.
"testing" | ||
) | ||
|
||
// Go repository basic compiler tests, and regression tests for fixed compiler bugs. | ||
func TestGoRepositoryCompilerTests(t *testing.T) { | ||
if runtime.GOARCH == "js" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the thinking behind dropping the // +build !js
build tag here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The motivation is written in the commit message of d0d69c0:
Rely on runtime.GOARCH and t.Skip to skip tests that shouldn't be run
with GopherJS. It's more clear and reliable than a file-wide build tag.
t.Skip
exists per-test (rather than for the entire file) and can offer an individual message for the skip reason. This was better in this context. Build tags were used previously because I didn't get the idea that t.Skip
could be used instead until now.
@@ -15,6 +14,10 @@ import ( | |||
// | |||
// See https://github.com/gopherjs/gopherjs/issues/279. | |||
func TestTimeInternalizationExternalization(t *testing.T) { | |||
if runtime.GOARCH == "js" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same question on why the build tag isn't sufficient in this situation and why you prefer the t.Skip
Thanks for the reviews! I'm going to merge this and bump up the GopherJS compiler version to 1.10-3, the first version to support vendoring GopherJS into other Go projects. |
There isn't a need, that PR is orthogonal. We can bump up to 1.10-4 for it if needed. |
Yes I know it's orthogonal, but I was proposing bundling together a number of fixes into one release. Or would you prefer to have one point release per fix/feature? |
Let's discuss that outside this PR. I've already effectively allocated 1.10-3 for this fix by bumping to 1.10-3 in the earlier version of this PR, so that release has already been decided. We can reconsider the approach for future versions. |
…amd64). The github.com/gopherjs/gopherjs/js and github.com/gopherjs/gopherjs/nosync packages still need to be built and served as separate archives, because the playground uses a custom compiler.ImportContext for loading all packages from the server. The playground doesn't try to build them. Regenerate with: go generate github.com/gopherjs/gopherjs.github.io/playground Follows gopherjs/gopherjs#787.
As a followup step, I've checked that the GopherJS Playground works with the latest version (it does) and updated it in gopherjs/gopherjs.github.io@cbdec89. |
This change brings two major features:
gopherjs
binary to be completely standalone and not require GopherJS source code to be in $GOPATH. Only $GOROOT is required.gopherjs
to be vendored in a Go project, and the vendored copy ofgopherjs
will be able to compile Go code successfully.The approach taken to make these things possible is as follows.
As of commit ab917e0, the natives (GopherJS-specific overrides for the Go standard library packages) are embedded in the GopherJS build system via a virtual filesystem. We re-generate the VFS whenever natives are modified.
Doing that made it possible to compile most parts of the Go standard library with GopherJS without needing the
github.com/gopherjs/gopherjs
repository in $GOPATH. However, without thegithub.com/gopherjs/gopherjs/js
andgithub.com/gopherjs/gopherjs/nosync
packages, compiling the Go standard library is not possible. Those two packages are core to the GopherJS compiler and are needed to buildruntime
, etc.Therefore, since natives are already embedded, it makes a lot of sense to also embed the 2 small additional
github.com/gopherjs/gopherjs/js
andgithub.com/gopherjs/gopherjs/nosync
packages analogously. Then, the VFS is used whenever the source of those two packages is accessed.As a result, a compiled
gopherjs
binary can successfully compile Go code even if the GopherJS repository is not located in $GOPATH.Additionally, the
natives
andgopherjspkg
packages are very friendly towards being vendored. That means the entire GopherJS project can be vendored in another Go project, and then used to compile Go code.Fixes #462.
Fixes #415.