Skip to content

Commit

Permalink
fix: use ioutil for Go 1.15 and lower (#492)
Browse files Browse the repository at this point in the history
Since Go 1.16 it has been recommended to no longer use ioutil in new
code. We want Gomega to look modern so we removed references to ioutil,
which also removes the chance of outdated code being copied. However we
got feedback that some users were stuck on Go 1.15 and lower and were
broken by this change. We have therefore introduces a "gutil" package
that implements similar functions to ioutil and redirect to the right
functions appropriate to the version of Go. This will hopefully:
- make it look intentional that ioutil is still used (rather than
looking like an omission)
- reduce the chance of ioutil usage being propagated by copying
- limit the possibility of deprecation warnings
  • Loading branch information
blgm committed Jan 17, 2022
1 parent 72e6040 commit c29c1c0
Show file tree
Hide file tree
Showing 16 changed files with 164 additions and 59 deletions.
6 changes: 4 additions & 2 deletions gexec/build.go
Expand Up @@ -13,6 +13,8 @@ import (
"runtime"
"strings"
"sync"

"github.com/onsi/gomega/internal/gutil"
)

var (
Expand Down Expand Up @@ -221,11 +223,11 @@ func temporaryDirectory() (string, error) {
mu.Lock()
defer mu.Unlock()
if tmpDir == "" {
tmpDir, err = os.MkdirTemp("", "gexec_artifacts")
tmpDir, err = gutil.MkdirTemp("", "gexec_artifacts")
if err != nil {
return "", err
}
}

return os.MkdirTemp(tmpDir, "g")
return gutil.MkdirTemp(tmpDir, "g")
}
9 changes: 5 additions & 4 deletions gexec/build_test.go
Expand Up @@ -8,6 +8,7 @@ import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec"
"github.com/onsi/gomega/internal/gutil"
)

var packagePath = "./_fixture/firefly"
Expand Down Expand Up @@ -98,7 +99,7 @@ var _ = Describe(".BuildIn", func() {
BeforeEach(func() {
var err error
original = os.Getenv("GOPATH")
gopath, err = os.MkdirTemp("", "")
gopath, err = gutil.MkdirTemp("", "")
Expect(err).NotTo(HaveOccurred())
copyFile(filepath.Join("_fixture", "firefly", "main.go"), filepath.Join(gopath, "src", target), "main.go")
Expect(os.Setenv("GOPATH", filepath.Join(os.TempDir(), "emptyFakeGopath"))).To(Succeed())
Expand Down Expand Up @@ -234,7 +235,7 @@ var _ = Describe(".CompiledTestIn", func() {
BeforeEach(func() {
var err error
original = os.Getenv("GOPATH")
gopath, err = os.MkdirTemp("", "")
gopath, err = gutil.MkdirTemp("", "")
Expect(err).NotTo(HaveOccurred())
copyFile(filepath.Join("_fixture", "firefly", "main.go"), filepath.Join(gopath, "src", target), "main.go")
Expect(os.Setenv("GOPATH", filepath.Join(os.TempDir(), "emptyFakeGopath"))).To(Succeed())
Expand Down Expand Up @@ -277,7 +278,7 @@ var _ = Describe(".CompiledTestIn", func() {

func copyFile(source, directory, basename string) {
Expect(os.MkdirAll(directory, 0755)).To(Succeed())
content, err := os.ReadFile(source)
content, err := gutil.ReadFile(source)
Expect(err).NotTo(HaveOccurred())
Expect(os.WriteFile(filepath.Join(directory, basename), content, 0644)).To(Succeed())
Expect(gutil.WriteFile(filepath.Join(directory, basename), content)).To(Succeed())
}
8 changes: 4 additions & 4 deletions ghttp/handlers.go
Expand Up @@ -6,7 +6,6 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"reflect"
Expand All @@ -15,6 +14,7 @@ import (
"github.com/golang/protobuf/proto"
"github.com/onsi/gomega"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/internal/gutil"
"github.com/onsi/gomega/types"
)

Expand Down Expand Up @@ -117,7 +117,7 @@ func (g GHTTPWithGomega) VerifyHeaderKV(key string, values ...string) http.Handl
func (g GHTTPWithGomega) VerifyBody(expectedBody []byte) http.HandlerFunc {
return CombineHandlers(
func(w http.ResponseWriter, req *http.Request) {
body, err := io.ReadAll(req.Body)
body, err := gutil.ReadAll(req.Body)
req.Body.Close()
g.gomega.Expect(err).ShouldNot(HaveOccurred())
g.gomega.Expect(body).Should(Equal(expectedBody), "Body Mismatch")
Expand All @@ -133,7 +133,7 @@ func (g GHTTPWithGomega) VerifyJSON(expectedJSON string) http.HandlerFunc {
return CombineHandlers(
g.VerifyMimeType("application/json"),
func(w http.ResponseWriter, req *http.Request) {
body, err := io.ReadAll(req.Body)
body, err := gutil.ReadAll(req.Body)
req.Body.Close()
g.gomega.Expect(err).ShouldNot(HaveOccurred())
g.gomega.Expect(body).Should(MatchJSON(expectedJSON), "JSON Mismatch")
Expand Down Expand Up @@ -182,7 +182,7 @@ func (g GHTTPWithGomega) VerifyProtoRepresenting(expected proto.Message) http.Ha
return CombineHandlers(
g.VerifyContentType("application/x-protobuf"),
func(w http.ResponseWriter, req *http.Request) {
body, err := io.ReadAll(req.Body)
body, err := gutil.ReadAll(req.Body)
g.gomega.Expect(err).ShouldNot(HaveOccurred())
req.Body.Close()

Expand Down
3 changes: 2 additions & 1 deletion ghttp/test_server.go
Expand Up @@ -120,6 +120,7 @@ import (
"sync"

. "github.com/onsi/gomega"
"github.com/onsi/gomega/internal/gutil"
)

func new() *Server {
Expand Down Expand Up @@ -268,7 +269,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
} else {
s.rwMutex.Unlock()
if s.GetAllowUnhandledRequests() {
io.ReadAll(req.Body)
gutil.ReadAll(req.Body)
req.Body.Close()
w.WriteHeader(s.GetUnhandledRequestStatusCode())
} else {
Expand Down
25 changes: 13 additions & 12 deletions ghttp/test_server_test.go
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/golang/protobuf/proto"
"github.com/onsi/gomega/gbytes"
"github.com/onsi/gomega/ghttp/protobuf"
"github.com/onsi/gomega/internal/gutil"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
Expand Down Expand Up @@ -59,7 +60,7 @@ var _ = Describe("TestServer", func() {
Expect(err).ShouldNot(HaveOccurred())
Expect(resp.StatusCode).Should(Equal(200))

body, err := io.ReadAll(resp.Body)
body, err := gutil.ReadAll(resp.Body)
resp.Body.Close()
Expect(err).ShouldNot(HaveOccurred())

Expand All @@ -69,7 +70,7 @@ var _ = Describe("TestServer", func() {
Expect(err).ShouldNot(HaveOccurred())
Expect(resp.StatusCode).Should(Equal(200))

body2, err := io.ReadAll(resp.Body)
body2, err := gutil.ReadAll(resp.Body)
resp.Body.Close()
Expect(err).ShouldNot(HaveOccurred())

Expand Down Expand Up @@ -101,7 +102,7 @@ var _ = Describe("TestServer", func() {
Expect(err).ShouldNot(HaveOccurred())
Expect(resp.StatusCode).Should(Equal(http.StatusForbidden))

data, err := io.ReadAll(resp.Body)
data, err := gutil.ReadAll(resp.Body)
Expect(err).ShouldNot(HaveOccurred())
Expect(data).Should(BeEmpty())
})
Expand Down Expand Up @@ -791,7 +792,7 @@ var _ = Describe("TestServer", func() {

Expect(resp.StatusCode).Should(Equal(http.StatusCreated))

body, err := io.ReadAll(resp.Body)
body, err := gutil.ReadAll(resp.Body)
Expect(err).ShouldNot(HaveOccurred())
Expect(body).Should(Equal([]byte("sweet")))

Expand All @@ -800,7 +801,7 @@ var _ = Describe("TestServer", func() {

Expect(resp.StatusCode).Should(Equal(http.StatusOK))

body, err = io.ReadAll(resp.Body)
body, err = gutil.ReadAll(resp.Body)
Expect(err).ShouldNot(HaveOccurred())
Expect(body).Should(Equal([]byte("sour")))
})
Expand All @@ -819,7 +820,7 @@ var _ = Describe("TestServer", func() {
Expect(err).ShouldNot(HaveOccurred())

Expect(resp.StatusCode).Should(Equal(http.StatusCreated))
Expect(io.ReadAll(resp.Body)).Should(Equal([]byte("sweet")))
Expect(gutil.ReadAll(resp.Body)).Should(Equal([]byte("sweet")))
Expect(resp.Header.Get("X-Custom-Header")).Should(Equal("my header"))
})
})
Expand Down Expand Up @@ -853,7 +854,7 @@ var _ = Describe("TestServer", func() {

Expect(resp.StatusCode).Should(Equal(http.StatusCreated))

body, err := io.ReadAll(resp.Body)
body, err := gutil.ReadAll(resp.Body)
Expect(err).ShouldNot(HaveOccurred())
Expect(body).Should(Equal([]byte("tasty")))

Expand All @@ -862,7 +863,7 @@ var _ = Describe("TestServer", func() {

Expect(resp.StatusCode).Should(Equal(http.StatusCreated))

body, err = io.ReadAll(resp.Body)
body, err = gutil.ReadAll(resp.Body)
Expect(err).ShouldNot(HaveOccurred())
Expect(body).Should(Equal([]byte("treat")))
})
Expand All @@ -880,7 +881,7 @@ var _ = Describe("TestServer", func() {

Expect(err).ShouldNot(HaveOccurred())
Expect(resp.StatusCode).Should(Equal(http.StatusOK))
body, err := io.ReadAll(resp.Body)
body, err := gutil.ReadAll(resp.Body)
Expect(err).ShouldNot(HaveOccurred())
Expect(body).Should(BeEmpty())

Expand All @@ -904,7 +905,7 @@ var _ = Describe("TestServer", func() {

Expect(resp.StatusCode).Should(Equal(http.StatusCreated))

body, err := io.ReadAll(resp.Body)
body, err := gutil.ReadAll(resp.Body)
Expect(err).ShouldNot(HaveOccurred())
Expect(body).Should(MatchJSON("[1,2,3]"))
})
Expand Down Expand Up @@ -989,7 +990,7 @@ var _ = Describe("TestServer", func() {

Expect(resp.StatusCode).Should(Equal(http.StatusCreated))

body, err := io.ReadAll(resp.Body)
body, err := gutil.ReadAll(resp.Body)
Expect(err).ShouldNot(HaveOccurred())
Expect(body).Should(MatchJSON(`{"Key": "Jim", "Value": "Codes"}`))
})
Expand Down Expand Up @@ -1070,7 +1071,7 @@ var _ = Describe("TestServer", func() {
Expect(resp.StatusCode).Should(Equal(http.StatusCreated))

var received protobuf.SimpleMessage
body, err := io.ReadAll(resp.Body)
body, err := gutil.ReadAll(resp.Body)
Expect(err).ShouldNot(HaveOccurred())
err = proto.Unmarshal(body, &received)
Expect(err).ShouldNot(HaveOccurred())
Expand Down
18 changes: 10 additions & 8 deletions gmeasure/cache.go
Expand Up @@ -6,6 +6,8 @@ import (
"fmt"
"os"
"path/filepath"

"github.com/onsi/gomega/internal/gutil"
)

const CACHE_EXT = ".gmeasure-cache"
Expand Down Expand Up @@ -66,15 +68,15 @@ List returns a list of all Cached Experiments found in the cache.
*/
func (cache ExperimentCache) List() ([]CachedExperimentHeader, error) {
var out []CachedExperimentHeader
entries, err := os.ReadDir(cache.Path)
names, err := gutil.ReadDir(cache.Path)
if err != nil {
return out, err
}
for _, entry := range entries {
if filepath.Ext(entry.Name()) != CACHE_EXT {
for _, name := range names {
if filepath.Ext(name) != CACHE_EXT {
continue
}
header, err := cache.readHeader(entry.Name())
header, err := cache.readHeader(name)
if err != nil {
return out, err
}
Expand All @@ -87,15 +89,15 @@ func (cache ExperimentCache) List() ([]CachedExperimentHeader, error) {
Clear empties out the cache - this will delete any and all detected cache files in the cache directory. Use with caution!
*/
func (cache ExperimentCache) Clear() error {
entries, err := os.ReadDir(cache.Path)
names, err := gutil.ReadDir(cache.Path)
if err != nil {
return err
}
for _, entry := range entries {
if filepath.Ext(entry.Name()) != CACHE_EXT {
for _, name := range names {
if filepath.Ext(name) != CACHE_EXT {
continue
}
err := os.Remove(filepath.Join(cache.Path, entry.Name()))
err := os.Remove(filepath.Join(cache.Path, name))
if err != nil {
return err
}
Expand Down
48 changes: 48 additions & 0 deletions internal/gutil/post_ioutil.go
@@ -0,0 +1,48 @@
//go:build go1.16
// +build go1.16

// Package gutil is a replacement for ioutil, which should not be used in new
// code as of Go 1.16. With Go 1.16 and higher, this implementation
// uses the ioutil replacement functions in "io" and "os" with some
// Gomega specifics. This means that we should not get deprecation warnings
// for ioutil when they are added.
package gutil

import (
"io"
"os"
)

func NopCloser(r io.Reader) io.ReadCloser {
return io.NopCloser(r)
}

func ReadAll(r io.Reader) ([]byte, error) {
return io.ReadAll(r)
}

func ReadDir(dirname string) ([]string, error) {
entries, err := os.ReadDir(dirname)
if err != nil {
return nil, err
}

var names []string
for _, entry := range entries {
names = append(names, entry.Name())
}

return names, nil
}

func ReadFile(filename string) ([]byte, error) {
return os.ReadFile(filename)
}

func MkdirTemp(dir, pattern string) (string, error) {
return os.MkdirTemp(dir, pattern)
}

func WriteFile(filename string, data []byte) error {
return os.WriteFile(filename, data, 0644)
}
47 changes: 47 additions & 0 deletions internal/gutil/using_ioutil.go
@@ -0,0 +1,47 @@
//go:build !go1.16
// +build !go1.16

// Package gutil is a replacement for ioutil, which should not be used in new
// code as of Go 1.16. With Go 1.15 and lower, this implementation
// uses the ioutil functions, meaning that although Gomega is not officially
// supported on these versions, it is still likely to work.
package gutil

import (
"io"
"io/ioutil"
)

func NopCloser(r io.Reader) io.ReadCloser {
return ioutil.NopCloser(r)
}

func ReadAll(r io.Reader) ([]byte, error) {
return ioutil.ReadAll(r)
}

func ReadDir(dirname string) ([]string, error) {
files, err := ioutil.ReadDir(dirname)
if err != nil {
return nil, err
}

var names []string
for _, file := range files {
names = append(names, file.Name())
}

return names, nil
}

func ReadFile(filename string) ([]byte, error) {
return ioutil.ReadFile(filename)
}

func MkdirTemp(dir, pattern string) (string, error) {
return ioutil.TempDir(dir, pattern)
}

func WriteFile(filename string, data []byte) error {
return ioutil.WriteFile(filename, data, 0644)
}
3 changes: 2 additions & 1 deletion matchers/be_a_directory_test.go
Expand Up @@ -5,6 +5,7 @@ import (

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/internal/gutil"
. "github.com/onsi/gomega/matchers"
)

Expand All @@ -18,7 +19,7 @@ var _ = Describe("BeADirectoryMatcher", func() {
defer os.Remove(tmpFile.Name())
Expect(tmpFile.Name()).ShouldNot(BeADirectory())

tmpDir, err := os.MkdirTemp("", "gomega-test-tempdir")
tmpDir, err := gutil.MkdirTemp("", "gomega-test-tempdir")
Expect(err).ShouldNot(HaveOccurred())
defer os.Remove(tmpDir)
Expect(tmpDir).Should(BeADirectory())
Expand Down

0 comments on commit c29c1c0

Please sign in to comment.