Commit 0b3adb9d authored by Daniel Martí's avatar Daniel Martí

schema/gen/go: cache genned code in os.TempDir

This means we no longer clutter the repository with lots of files, even
if they are git-ignored. It's always a bit of a red flag when you run
"go test ./..." and the result is a bunch of leftover files.

We still want to keep the files around, for the sake of Go's build
cache. And we still want their paths to be static between "go test"
runs. So put them in a static dir under os.TempDir.

This does mean that concurrent runs of these tests will likely not work
well. I don't imagine that's going to be a problem anytime soon, though.
If it really becomes a problem in the future, we could figure something
out like grabbing a file lock for the directory.

The idea behind using os.TempDir is that it will likely remain in place
between a number of "go test" runs within a hacking session, but it will
be eventually cleaned up by the system, such as when rebooting.

Note that we need to use globbing since one can't build "proper
packages" located outside a module. The only exception is building an
ad-hoc set of explicit Go files. While at it, use filepath.Join, to be
nice.
parent c0829bcd
......@@ -17,14 +17,20 @@ func buildGennedCode(t *testing.T, prefix string, pkgName string) {
// so 'pkgName' in practice is almost always "main").
// I dunno, friend. I didn't write the rules.
if pkgName == "main" {
withFile("./_test/"+prefix+"/main.go", func(w io.Writer) {
withFile(filepath.Join(tmpGenBuildDir, prefix, "main.go"), func(w io.Writer) {
fmt.Fprintf(w, "package %s\n\n", pkgName)
fmt.Fprintf(w, "func main() {}\n")
})
}
// Invoke 'go build' -- nothing fancy.
cmd := exec.Command("go", "build", "./_test/"+prefix)
files, err := filepath.Glob(filepath.Join(tmpGenBuildDir, prefix, "*.go"))
if err != nil {
t.Fatal(err)
}
args := []string{"build"}
args = append(args, files...)
cmd := exec.Command("go", args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
......
......@@ -32,14 +32,20 @@ func buildGennedCode(t *testing.T, prefix string, pkgName string) {
// so 'pkgName' in practice is almost always "main").
// I dunno, friend. I didn't write the rules.
if pkgName == "main" {
withFile("./_test/"+prefix+"/main.go", func(w io.Writer) {
withFile(filepath.Join(tmpGenBuildDir, prefix, "main.go"), func(w io.Writer) {
fmt.Fprintf(w, "package %s\n\n", pkgName)
fmt.Fprintf(w, "func main() {}\n")
})
}
// Invoke 'go build' -- nothing fancy.
cmd := exec.Command("go", "build", "./_test/"+prefix)
files, err := filepath.Glob(filepath.Join(tmpGenBuildDir, prefix, "*.go"))
if err != nil {
t.Fatal(err)
}
args := []string{"build"}
args = append(args, files...)
cmd := exec.Command("go", args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
......
......@@ -5,26 +5,37 @@ package gengo
import (
"os"
"os/exec"
"path/filepath"
"plugin"
"testing"
"github.com/ipld/go-ipld-prime"
)
func objPath(prefix string) string {
return filepath.Join(tmpGenBuildDir, prefix, "obj.so")
}
func buildGennedCode(t *testing.T, prefix string, _ string) {
// Invoke `go build` with flags to create a plugin -- we'll be able to
// load into this plugin into this selfsame process momentarily.
cmd := exec.Command("go", "build", "-o=./_test/"+prefix+"/obj.so", "-buildmode=plugin", "./_test/"+prefix)
// Use globbing, because these are files outside our module.
files, err := filepath.Glob(filepath.Join(tmpGenBuildDir, prefix, "*.go"))
if err != nil {
t.Fatal(err)
}
args := []string{"build", "-o=" + objPath(prefix), "-buildmode=plugin"}
args = append(args, files...)
cmd := exec.Command("go", args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
if err := cmd.Run(); err != nil {
t.Fatalf("genned code failed to compile: %s", err)
}
}
func runBehavioralTests(t *testing.T, prefix string, testsFn behavioralTests) {
plg, err := plugin.Open("./_test/" + prefix + "/obj.so")
plg, err := plugin.Open(objPath(prefix))
if err != nil {
panic(err) // Panic because if this was going to flunk, we expected it to flunk earlier when we ran 'go build'.
}
......
......@@ -3,6 +3,7 @@ package gengo
import (
"io"
"os"
"path/filepath"
"testing"
"github.com/ipld/go-ipld-prime"
......@@ -21,6 +22,8 @@ import (
// their representation prototypes can be obtained by appending ".Repr".
type behavioralTests func(t *testing.T, getPrototypeByName func(string) ipld.NodePrototype)
var tmpGenBuildDir = filepath.Join(os.TempDir(), "go-ipld-prime-gengo")
func genAndCompileAndTest(
t *testing.T,
prefix string,
......@@ -30,23 +33,25 @@ func genAndCompileAndTest(
testsFn behavioralTests,
) {
// Make directories for the package we're about to generate.
// Everything will be prefixed with "./_test".
// You can rm-rf the whole "./_test" dir at your leisure.
// We don't by default because it's nicer to let go's builds of things cache.
// If you change the names of types, though, you'll have garbage files leftover,
// and that's currently a manual cleanup problem. Sorry.
os.Mkdir("./_test/", 0755)
os.Mkdir("./_test/"+prefix, 0755)
// They will live in a temporary directory, usually
// /tmp/go-ipld-prime-gengo on Linux. It can be removed at any time.
// We don't by default because it's nicer to let go's builds of things cache.
// If you change the names of types, though, you'll have garbage files leftover,
// and that's currently a manual cleanup problem. Sorry.
dir := filepath.Join(tmpGenBuildDir, prefix)
if err := os.MkdirAll(dir, 0755); err != nil {
t.Fatal(err)
}
// Generate... everything, really.
Generate("./_test/"+prefix, pkgName, ts, adjCfg)
Generate(dir, pkgName, ts, adjCfg)
// Emit an exported top level function for getting NodePrototype.
// This part isn't necessary except for a special need we have with this plugin trick;
// normally, user code uses the `{pkgname}.Prototype.{TypeName}` constant (so-to-speak, anyway) to get a hold of NodePrototypes...
// but for plugins, we need a top-level exported symbol to grab ahold of, and we can't easily look through the `Prototype` value
// without an interface... so we generate this function to fit the bill instead.
withFile("./_test/"+prefix+"/prototypeGetter.go", func(w io.Writer) {
withFile(filepath.Join(dir, "prototypeGetter.go"), func(w io.Writer) {
doTemplate(`
package `+pkgName+`
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment