Skip to content

Commit

Permalink
Update to use GitHub Actions, go.mod, and fix for Go 1.20 (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
benhoyt committed Mar 17, 2023
1 parent bada53c commit d48d634
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 80 deletions.
36 changes: 36 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Tests

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
build-linux:
strategy:
matrix:
go: ['1.20', '1.19']
os: [ubuntu-latest, macos-latest, windows-latest]

name: Go ${{ matrix.go }} on ${{ matrix.os }}

runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go }}

- name: Run tests
run: |
go version
go test -race ./...
- name: Test that binary builds
run: |
go build
./gosnip "fmt.Println(time.Now())"
13 changes: 0 additions & 13 deletions .travis.yml

This file was deleted.

5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# gosnip: run small snippets of Go code from the command line

[![GoDoc](https://godoc.org/github.com/benhoyt/gosnip?status.png)](https://godoc.org/github.com/benhoyt/gosnip)
[![TravisCI Build](https://travis-ci.org/benhoyt/gosnip.svg)](https://travis-ci.org/benhoyt/gosnip)
[![AppVeyor Build](https://ci.appveyor.com/api/projects/status/github/benhoyt/gosnip?branch=master&svg=true)](https://ci.appveyor.com/project/benhoyt/gosnip)
[![Documentation](https://pkg.go.dev/badge/github.com/benhoyt/gosnip)](https://pkg.go.dev/github.com/benhoyt/gosnip)
[![GitHub Actions Build](https://github.com/benhoyt/gosnip/workflows/Tests/badge.svg)](https://github.com/benhoyt/gosnip/actions/workflows/tests.yml)

Package gosnip is a tool that allows you to run small snippets of
Go code from the command line.
Expand Down
13 changes: 0 additions & 13 deletions appveyor.yml

This file was deleted.

10 changes: 10 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module github.com/benhoyt/gosnip

go 1.19

require golang.org/x/tools v0.7.0

require (
golang.org/x/mod v0.9.0 // indirect
golang.org/x/sys v0.6.0 // indirect
)
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
47 changes: 23 additions & 24 deletions gosnip.go
Original file line number Diff line number Diff line change
@@ -1,53 +1,52 @@
// Package gosnip is a tool that allows you to run small snippets of
// Go code from the command line.
//
// usage: gosnip [-d] [-i import ...] statements...
// usage: gosnip [-d] [-i import ...] statements...
//
// For simple uses, just specify one or more Go statements on the
// command line, and gosnip will roll them into a full Go program and
// run the result using "go run". Standard library imports and any
// imports needed for packages in GOPATH are added automatically
// (using the same logic as the "goimports" tool). Some examples:
//
// $ gosnip 'fmt.Println("Hello world")'
// Hello world
// $ gosnip 'fmt.Println("Hello world")'
// Hello world
//
// $ gosnip 'fmt.Println("Current time:")' 'fmt.Println(time.Now())'
// Current time:
// 2018-11-24 16:18:47.101951 -0500 EST m=+0.000419239
// $ gosnip 'fmt.Println("Current time:")' 'fmt.Println(time.Now())'
// Current time:
// 2018-11-24 16:18:47.101951 -0500 EST m=+0.000419239
//
// The -i flag allows you to specify an import explicitly, which may be
// needed to select between ambiguous stdlib imports such as
// "text/template" and "html/template" (multiple -i flags are
// allowed). For example:
//
// $ ./gosnip -i text/template 't, _ := template.New("w").Parse("{{ . }}\n")' \
// 't.Execute(os.Stdout, "<b>")'
// <b>
// $ ./gosnip -i html/template 't, _ := template.New("w").Parse("{{ . }}\n")' \
// 't.Execute(os.Stdout, "<b>")'
// &lt;b&gt;
// $ ./gosnip -i text/template 't, _ := template.New("w").Parse("{{ . }}\n")' \
// 't.Execute(os.Stdout, "<b>")'
// <b>
// $ ./gosnip -i html/template 't, _ := template.New("w").Parse("{{ . }}\n")' \
// 't.Execute(os.Stdout, "<b>")'
// &lt;b&gt;
//
// The -d flag turns on debug mode, which prints the full program on
// stderr before running it. For example:
//
// $ gosnip -d 'fmt.Println(time.Now())'
// package main
// $ gosnip -d 'fmt.Println(time.Now())'
// package main
//
// import (
// "fmt"
// "time"
// )
// import (
// "fmt"
// "time"
// )
//
// func main() {
// fmt.Println(time.Now())
// }
// 2018-11-24 16:33:56.681024 -0500 EST m=+0.000383308
// func main() {
// fmt.Println(time.Now())
// }
// 2018-11-24 16:33:56.681024 -0500 EST m=+0.000383308
//
// The gosnip command-line tool is a thin wrapper around the
// "sniplib" package. To run Go snippets in your Go programs, see the
// sniplib docs.
//
package main

import (
Expand All @@ -59,7 +58,7 @@ import (
)

const (
version = "v1.1.1"
version = "v1.2.0"
)

func main() {
Expand Down
33 changes: 11 additions & 22 deletions sniplib/sniplib.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"os"
"os/exec"
"strings"
"syscall"

importspkg "golang.org/x/tools/imports"
)
Expand Down Expand Up @@ -69,41 +68,31 @@ func Run(source string, stdin io.Reader, stdout, stderr io.Writer) error {
errBuf := &bytes.Buffer{}
cmd.Stderr = errBuf
err = cmd.Run()
if exitStatus(err) == 2 {
// "go run" exit status 2 means compile error, so filter the
// funky temp filename and extraneous "go run" comments
if err != nil {
// Ideally we'd only do this filtering on compile error, not program
// error, but it's hard to tell the difference ("go run" used to
// return exit code 2 for this, but since Go 1.20, it doesn't).
filterStderr(errBuf.Bytes(), stderr)
return err
}
_, _ = errBuf.WriteTo(stderr)
return err
}

// Return exit status from given exec error (there'll be a better way
// to do this in Go 1.12!).
func exitStatus(err error) int {
if err == nil {
return 0
}
if exitErr, ok := err.(*exec.ExitError); ok {
if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
return status.ExitStatus()
}
}
return 1
}

// Filter out extraneous output and temp file name from "go run"
// output in case of compile error. Example "go run" output:
//
// # command-line-arguments
// /var/folders/sz/thh6m7316b3gvvvmjp8qpdrm0000gp/T/gosnip_615300750.go:8:2: undefined: fmt.X
// # command-line-arguments
// /var/folders/sz/thh6m7316b3gvvvmjp8qpdrm0000gp/T/gosnip_615300750.go:8:2: undefined: fmt.X
//
// Output after filtering:
//
// 8:2: undefined: fmt.X
//
// 8:2: undefined: fmt.X
func filterStderr(data []byte, writer io.Writer) {
if !bytes.Contains(data, []byte("# command-line-arguments")) {
writer.Write(data)
return
}
lines := bytes.Split(data, []byte("\n"))
for _, line := range lines {
if bytes.HasPrefix(line, []byte("# ")) {
Expand Down
23 changes: 18 additions & 5 deletions sniplib/sniplib_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"bytes"
"fmt"
"os"
"regexp"
"strings"
"testing"

Expand Down Expand Up @@ -149,8 +150,8 @@ func main() {
}
`,
"",
"8:2: undefined: fmt.X\n",
"exit status 2",
"8:6: undefined: fmt.X\n",
"exit status [12]",
},
{
`package main
Expand Down Expand Up @@ -178,7 +179,7 @@ func main() {
`,
"",
"4:2: undefined: foo\n",
"exit status 2",
"exit status [12]",
},
}
for _, test := range tests {
Expand All @@ -194,14 +195,26 @@ func main() {
t.Errorf("expected stderr %q, got %q", test.stderr, errBuf.String())
}
if err != nil {
if err.Error() != test.err {
t.Errorf("expected error %q, got %q", test.err, err.Error())
if !mustMatch(test.err, err.Error()) {
t.Errorf("expected error to match %q, got %q", test.err, err.Error())
}
} else {
if test.err != "" {
t.Errorf("expected error to match %q, got no error", test.err)
}
}
})
}
}

func mustMatch(pattern, s string) bool {
matched, err := regexp.MatchString(pattern, s)
if err != nil {
panic(err)
}
return matched
}

func ExampleToProgram() {
statements := []string{`fmt.Println("Hello world")`}
source, err := sniplib.ToProgram(statements, nil)
Expand Down

0 comments on commit d48d634

Please sign in to comment.