From 4028e0156b3f439866d5d3d09b05868f0804ec7b Mon Sep 17 00:00:00 2001 From: ben-toogood Date: Fri, 25 Sep 2020 10:02:49 +0100 Subject: [PATCH] runtime: remove builder package (moved to micro) (#2023) --- runtime/builder/builder.go | 9 -- runtime/builder/golang/golang.go | 189 -------------------------- runtime/builder/golang/golang_test.go | 148 -------------------- runtime/builder/options.go | 26 ---- 4 files changed, 372 deletions(-) delete mode 100644 runtime/builder/builder.go delete mode 100644 runtime/builder/golang/golang.go delete mode 100644 runtime/builder/golang/golang_test.go delete mode 100644 runtime/builder/options.go diff --git a/runtime/builder/builder.go b/runtime/builder/builder.go deleted file mode 100644 index 5fbeb207..00000000 --- a/runtime/builder/builder.go +++ /dev/null @@ -1,9 +0,0 @@ -package builder - -import "io" - -// Builder is an interface for building packages -type Builder interface { - // Build a package - Build(src io.Reader, opts ...Option) (io.Reader, error) -} diff --git a/runtime/builder/golang/golang.go b/runtime/builder/golang/golang.go deleted file mode 100644 index e2f6cfa7..00000000 --- a/runtime/builder/golang/golang.go +++ /dev/null @@ -1,189 +0,0 @@ -package golang - -import ( - "archive/tar" - "archive/zip" - "bytes" - "errors" - "fmt" - "io" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - - "github.com/micro/go-micro/v3/runtime/builder" - "github.com/micro/go-micro/v3/runtime/local" -) - -// NewBuilder returns a golang builder which can build a go binary given some source -func NewBuilder() (builder.Builder, error) { - path, err := locateGo() - if err != nil { - return nil, fmt.Errorf("Error locating go binary: %v", err) - } - - return &golang{ - cmdPath: path, - tmpDir: os.TempDir(), - }, nil -} - -type golang struct { - cmdPath string - tmpDir string -} - -// Build a binary using source. If an archive was used, e.g. tar, this should be specified in the -// options. If no archive option is passed, the builder will treat the source as a single file. -func (g *golang) Build(src io.Reader, opts ...builder.Option) (io.Reader, error) { - // parse the options - var options builder.Options - for _, o := range opts { - o(&options) - } - - // create a tmp dir to contain the source - dir, err := ioutil.TempDir(g.tmpDir, "src") - if err != nil { - return nil, err - } - defer os.RemoveAll(dir) - - // decode the source and write to the tmp directory - switch options.Archive { - case "": - err = writeFile(src, dir) - case "tar": - err = unarchiveTar(src, dir) - case "zip": - err = unarchiveZip(src, dir) - default: - return nil, errors.New("Invalid Archive") - } - if err != nil { - return nil, err - } - - // determine the entrypoint if one wasn't provided - if len(options.Entrypoint) == 0 { - ep, err := local.Entrypoint(dir) - if err != nil { - return nil, err - } - options.Entrypoint = ep - } - - // build the binary - cmd := exec.Command(g.cmdPath, "build", "-o", "micro_build", filepath.Dir(options.Entrypoint)) - cmd.Env = append(os.Environ(), "GO111MODULE=auto") - cmd.Dir = dir - if err := cmd.Run(); err != nil { - return nil, err - } - - // read the bytes from the file - dst, err := ioutil.ReadFile(filepath.Join(dir, "micro_build")) - if err != nil { - return nil, err - } - - return bytes.NewBuffer(dst), nil -} - -// writeFile takes a single file to a directory -func writeFile(src io.Reader, dir string) error { - // copy the source to the temp file - bytes, err := ioutil.ReadAll(src) - if err != nil { - return err - } - - // write the file, note: in order for the golang builder to access the file, it cannot be - // os.ModeTemp. This is okay because we delete all the files in the tmp dir at the end of this - // function. - return ioutil.WriteFile(filepath.Join(dir, "main.go"), bytes, os.ModePerm) -} - -// unarchiveTar decodes the source in a tar and writes it to a directory -func unarchiveTar(src io.Reader, dir string) error { - tr := tar.NewReader(src) - for { - hdr, err := tr.Next() - if err == io.EOF { - break - } else if err != nil { - return err - } - - path := filepath.Join(dir, hdr.Name) - bytes, err := ioutil.ReadAll(tr) - if err != nil { - return err - } - - if err := ioutil.WriteFile(path, bytes, os.ModePerm); err != nil { - return err - } - } - return nil -} - -// unarchiveZip decodes the source in a zip and writes it to a directory -func unarchiveZip(src io.Reader, dir string) error { - // create a new buffer with the source, this is required because zip.NewReader takes a io.ReaderAt - // and not an io.Reader - buff := bytes.NewBuffer([]byte{}) - size, err := io.Copy(buff, src) - if err != nil { - return err - } - - // create the zip - reader := bytes.NewReader(buff.Bytes()) - zip, err := zip.NewReader(reader, size) - if err != nil { - return err - } - - // write the files in the zip to our tmp dir - for _, f := range zip.File { - rc, err := f.Open() - if err != nil { - return err - } - - bytes, err := ioutil.ReadAll(rc) - if err != nil { - return err - } - - path := filepath.Join(dir, f.Name) - if err := ioutil.WriteFile(path, bytes, os.ModePerm); err != nil { - return err - } - - if err := rc.Close(); err != nil { - return err - } - } - - return nil -} - -// locateGo locates the go command -func locateGo() (string, error) { - if gr := os.Getenv("GOROOT"); len(gr) > 0 { - return filepath.Join(gr, "bin", "go"), nil - } - - // check path - for _, p := range filepath.SplitList(os.Getenv("PATH")) { - bin := filepath.Join(p, "go") - if _, err := os.Stat(bin); err == nil { - return bin, nil - } - } - - return exec.LookPath("go") -} diff --git a/runtime/builder/golang/golang_test.go b/runtime/builder/golang/golang_test.go deleted file mode 100644 index 771788ea..00000000 --- a/runtime/builder/golang/golang_test.go +++ /dev/null @@ -1,148 +0,0 @@ -package golang - -import ( - "archive/tar" - "archive/zip" - "bytes" - "fmt" - "io" - "io/ioutil" - "os" - "os/exec" - "strings" - "testing" - - "github.com/micro/go-micro/v3/runtime/builder" - "github.com/stretchr/testify/assert" -) - -var ( - testMainGo = "package main; import \"fmt\"; func main() { fmt.Println(\"HelloWorld\") }" - testSecondGo = "package main; import \"fmt\"; func init() { fmt.Println(\"Init\") }" -) - -func TestGolangBuilder(t *testing.T) { - t.Run("NoArchive", func(t *testing.T) { - buf := bytes.NewBuffer([]byte(testMainGo)) - err := testBuilder(t, buf) - assert.Nil(t, err, "No error should be returned") - }) - - t.Run("InvalidArchive", func(t *testing.T) { - buf := bytes.NewBuffer([]byte(testMainGo)) - err := testBuilder(t, buf, builder.Archive("foo")) - assert.Error(t, err, "An error should be returned") - }) - - t.Run("TarArchive", func(t *testing.T) { - // Create a tar writer - tf := bytes.NewBuffer(nil) - tw := tar.NewWriter(tf) - - // Add some files to the archive. - var files = []struct { - Name, Body string - }{ - {"main.go", testMainGo}, - {"second.go", testSecondGo}, - } - for _, file := range files { - hdr := &tar.Header{ - Name: file.Name, - Mode: 0600, - Size: int64(len(file.Body)), - } - if err := tw.WriteHeader(hdr); err != nil { - t.Fatal(err) - } - if _, err := tw.Write([]byte(file.Body)); err != nil { - t.Fatal(err) - } - } - if err := tw.Close(); err != nil { - t.Fatal(err) - } - - err := testBuilder(t, tf, builder.Archive("tar")) - assert.Nil(t, err, "No error should be returned") - }) - - t.Run("ZipArchive", func(t *testing.T) { - // Create a buffer to write our archive to. - buf := new(bytes.Buffer) - - // Create a new zip archive. - w := zip.NewWriter(buf) - defer w.Close() - - // Add some files to the archive. - var files = []struct { - Name, Body string - }{ - {"main.go", testMainGo}, - {"second.go", testSecondGo}, - } - for _, file := range files { - f, err := w.Create(file.Name) - if err != nil { - t.Fatal(err) - } - _, err = f.Write([]byte(file.Body)) - if err != nil { - t.Fatal(err) - } - } - if err := w.Close(); err != nil { - t.Fatal(err) - } - - err := testBuilder(t, buf, builder.Archive("zip")) - assert.Nil(t, err, "No error should be returned") - }) -} - -func testBuilder(t *testing.T, buf io.Reader, opts ...builder.Option) error { - // setup the builder - builder, err := NewBuilder() - if err != nil { - return fmt.Errorf("Error creating the builder: %v", err) - } - - // build the source - res, err := builder.Build(buf, opts...) - if err != nil { - return fmt.Errorf("Error building source: %v", err) - } - - // write the binary to a tmp file and make it executable - file, err := ioutil.TempFile(os.TempDir(), "res") - if err != nil { - return fmt.Errorf("Error creating tmp output file: %v", err) - } - if _, err := io.Copy(file, res); err != nil { - return fmt.Errorf("Error copying binary to tmp file: %v", err) - } - if err := file.Close(); err != nil { - return err - } - if err := os.Chmod(file.Name(), 0111); err != nil { - return err - } - defer os.Remove(file.Name()) - - // execute the binary - cmd := exec.Command(file.Name()) - outp, err := cmd.Output() - if err != nil { - return fmt.Errorf("Error executing binary: %v", err) - } - if !strings.Contains(string(outp), "HelloWorld") { - return fmt.Errorf("Output does not contain HelloWorld") - } - // when an archive is used we also check for the second file to be loaded - if len(opts) > 0 && !strings.Contains(string(outp), "Init") { - return fmt.Errorf("Output does not contain Init") - } - - return nil -} diff --git a/runtime/builder/options.go b/runtime/builder/options.go deleted file mode 100644 index a268dc1b..00000000 --- a/runtime/builder/options.go +++ /dev/null @@ -1,26 +0,0 @@ -package builder - -// Options to use when building source -type Options struct { - // Archive used, e.g. tar - Archive string - // Entrypoint to use, e.g. foo/main.go - Entrypoint string -} - -// Option configures one or more options -type Option func(o *Options) - -// Archive sets the builders archive -func Archive(a string) Option { - return func(o *Options) { - o.Archive = a - } -} - -// Entrypoint sets the builders entrypoint -func Entrypoint(e string) Option { - return func(o *Options) { - o.Entrypoint = e - } -}