Skip to content
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

Merge newly-rebased lib into main #856

Merged
merged 9 commits into from
Jan 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ results-junit.xml
# E2E customzied env log file.
sgol.txt

# Testing dirs
/artifacts
# E2E testing artifacts dir
e2e_test_artifacts/

Expand Down
37 changes: 37 additions & 0 deletions artifacts/artifacts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Package artifacts provides functionality for writing artifact files in configured
// artifacts directory. This package operators with a singleton directory variable that can be
// changed and reset. It provides simple functionality that can be accessible from
// any calling library.
package artifacts

import (
"context"
"io"
)

const DefaultArtifactsDir = "artifacts"

// ContextWithWriter adds ArtifactWriter w to the context ctx.
func ContextWithWriter(ctx context.Context, w ArtifactWriter) context.Context {
return context.WithValue(ctx, artifactWriterContextKey, w)
}

// WriterFromContext returns the writer from the context, or nil.
func WriterFromContext(ctx context.Context) ArtifactWriter {
w := ctx.Value(artifactWriterContextKey)
if writer, ok := w.(ArtifactWriter); ok {
return writer
}

return nil
}

// contextKey is a key used to store/retrieve ArtifactsWriter in/from context.Context.
type contextKey string

const artifactWriterContextKey contextKey = "ArtifactWriter"

// ArtifactWriter is the functionality required by all implementations.
type ArtifactWriter interface {
WriteFile(filename string, contents io.Reader) (fullpathToFile string, err error)
}
28 changes: 28 additions & 0 deletions artifacts/artifacts_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package artifacts_test

import (
"context"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"github.com/redhat-openshift-ecosystem/openshift-preflight/artifacts"
)

var _ = Describe("Artifacts package context management", func() {
Context("When working with an ArtifactWriter from context", func() {
It("Should be settable and retrievable using helper functions", func() {
aw, err := artifacts.NewMapWriter()
Expect(err).ToNot(HaveOccurred())

ctx := artifacts.ContextWithWriter(context.Background(), aw)
awRetrieved := artifacts.WriterFromContext(ctx)
Expect(awRetrieved).ToNot(BeNil())
Expect(awRetrieved).To(BeEquivalentTo(aw))
})
})
It("Should return nil when there is no ArtifactWriter found in the context", func() {
awRetrieved := artifacts.WriterFromContext(context.Background())
Expect(awRetrieved).To(BeNil())
})
})
58 changes: 58 additions & 0 deletions artifacts/filesystem_writer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package artifacts

import (
"fmt"
"io"
"path/filepath"

"github.com/spf13/afero"
)

// FilesystemWriter is an ArtifactWriter that targets a particular directory on
// the underlying filesystem.
type FilesystemWriter struct {
dir string
fs afero.Fs
}

// NewFilesystemWriter creates an artifact writer which writes to the filesystem.
func NewFilesystemWriter(opts ...FilesystemWriterOption) (*FilesystemWriter, error) {
w := FilesystemWriter{
dir: resolveFullPath(DefaultArtifactsDir),
fs: afero.NewOsFs(),
}

for _, opt := range opts {
opt(&w)
}

return &w, nil
}

// WithDirectory sets the artifacts directory to dir unless it's empty, in which case
// this option is ignored.
func WithDirectory(dir string) FilesystemWriterOption {
return func(w *FilesystemWriter) {
if dir == "" {
return
}
w.dir = resolveFullPath(dir)
}
}

type FilesystemWriterOption = func(*FilesystemWriter)

// WriteFile places contents into dir at filename.
func (w *FilesystemWriter) WriteFile(filename string, contents io.Reader) (string, error) {
fullFilePath := filepath.Join(w.Path(), filename)

if err := afero.SafeWriteReader(w.fs, fullFilePath, contents); err != nil {
return fullFilePath, fmt.Errorf("could not write file to artifacts directory: %v", err)
}
return fullFilePath, nil
}

// Path is the full artifacts path.
func (w *FilesystemWriter) Path() string {
return w.dir
}
50 changes: 50 additions & 0 deletions artifacts/filesystem_writer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package artifacts

import (
"bytes"
"os"
"path/filepath"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = Describe("Filesystem Artifact Writer", func() {
var tempdir string
BeforeEach(func() {
var err error
tempdir, err = os.MkdirTemp(os.TempDir(), "fs-artifact-writer-*")
Expect(err).ToNot(HaveOccurred())
Expect(len(tempdir)).ToNot(BeZero())
})

AfterEach(func() {
Expect(os.RemoveAll(tempdir)).To(Succeed())
})

Context("With a Filesystem Artifact Writer configured with a provided Artifact Directory", func() {
var aw *FilesystemWriter
filename := "testfile.txt"
contents := []byte("testcontents")

BeforeEach(func() {
var err error
aw, err = NewFilesystemWriter(WithDirectory(tempdir))
Expect(err).ToNot(HaveOccurred())
})

It("Should write to the input filename in the configured directory with the provided content", func() {
fullpath, err := aw.WriteFile(filename, bytes.NewBuffer(contents))

Expect(err).ToNot(HaveOccurred())
Expect(fullpath).To(Equal(filepath.Join(tempdir, filename)))

_, err = os.Stat(fullpath)
Expect(err).ToNot(HaveOccurred())

readin, err := os.ReadFile(fullpath)
Expect(err).ToNot(HaveOccurred())
Expect(readin).To(Equal(contents))
})
})
})
34 changes: 34 additions & 0 deletions artifacts/map_writer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package artifacts

import (
"errors"
"io"
)

var ErrFileAlreadyExists = errors.New("file already exists")

// MapWriter implements an ArtifactWriter storing contents in a map.
type MapWriter struct {
files map[string]io.Reader
}

// NewMapWriter creates an artifact writer in memory using a map.
func NewMapWriter() (*MapWriter, error) {
return &MapWriter{
files: map[string]io.Reader{},
}, nil
}

// WriteFile places contents into files at filename.
func (w *MapWriter) WriteFile(filename string, contents io.Reader) (string, error) {
if _, exists := w.files[filename]; exists {
return "", ErrFileAlreadyExists
}

w.files[filename] = contents
return filename, nil
}

func (w *MapWriter) Files() map[string]io.Reader {
return w.files
}
44 changes: 44 additions & 0 deletions artifacts/map_writer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package artifacts

import (
"bytes"
"io"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = Describe("Map Artifact Writer", func() {
Context("With a Map Artifact Writer", func() {
var aw *MapWriter
filename := "testfile.txt"
contents := []byte("testcontents")

BeforeEach(func() {
var err error
aw, err = NewMapWriter()
Expect(err).ToNot(HaveOccurred())
})

It("Should write to the input filename in the map with the provided content", func() {
_, err := aw.WriteFile(filename, bytes.NewBuffer(contents))

Expect(err).ToNot(HaveOccurred())

written := aw.Files()
val, ok := written[filename]
Expect(ok).To(BeTrue())
readin, err := io.ReadAll(val)
Expect(err).ToNot(HaveOccurred())
Expect(readin).To(Equal(contents))
})

It("Should reject subsequent writes to the same file", func() {
_, err := aw.WriteFile(filename, bytes.NewBuffer(contents))
Expect(err).ToNot(HaveOccurred())

_, err = aw.WriteFile(filename, bytes.NewBuffer([]byte("rejected")))
Expect(err).To(Equal(ErrFileAlreadyExists))
})
})
})
13 changes: 13 additions & 0 deletions artifacts/suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package artifacts

import (
"testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

func TestArtifacts(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Artifacts Suite")
}
17 changes: 17 additions & 0 deletions artifacts/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package artifacts

import (
"os"
"path/filepath"
"strings"
)

// resolveFullPath resolves the full path of s if s is a relative path.
func resolveFullPath(s string) string {
fullPath := s
if !strings.HasPrefix(s, "/") {
cwd, _ := os.Getwd()
fullPath = filepath.Join(cwd, s)
}
return fullPath
}
27 changes: 27 additions & 0 deletions artifacts/util_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package artifacts

import (
"os"
"path/filepath"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = Describe("Artifacts Package Utility Functions", func() {
Context("When resolving a path of an input directory", func() {
It("Should return the exact input when it starts with the \"/\" character", func() {
in := "/foo"
actual := resolveFullPath(in)
Expect(actual).To(Equal(in))
})

It("Should return the input relative to the current working directory when the first character is not \"/\"", func() {
in := "foo"
cwd, err := os.Getwd()
Expect(err).ToNot(HaveOccurred())
actual := resolveFullPath(in)
Expect(actual).To(Equal(filepath.Join(cwd, in)))
})
})
})
64 changes: 0 additions & 64 deletions certification/artifacts/artifacts.go

This file was deleted.

Loading