Skip to content

Commit

Permalink
Bootstrap fileio package (#40)
Browse files Browse the repository at this point in the history
* Drop receiver from writeFile

Signed-off-by: Atanas Dinov <[email protected]>

* Extract writeFile to fileio package

Signed-off-by: Atanas Dinov <[email protected]>

* Restructure file writing

Signed-off-by: Atanas Dinov <[email protected]>

* Test file writing

Signed-off-by: Atanas Dinov <[email protected]>

* Extract copyFile to fileio package

Signed-off-by: Atanas Dinov <[email protected]>

* Test file copying

Signed-off-by: Atanas Dinov <[email protected]>

* Drop unused copy function

Signed-off-by: Atanas Dinov <[email protected]>

* Use temporary dir in tests

Signed-off-by: Atanas Dinov <[email protected]>

---------

Signed-off-by: Atanas Dinov <[email protected]>
  • Loading branch information
atanasdinov authored Nov 14, 2023
1 parent 57878ba commit d9780ce
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 105 deletions.
76 changes: 3 additions & 73 deletions pkg/build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,12 @@ package build
import (
_ "embed"
"fmt"
"io"
"os"
"path/filepath"
"slices"
"text/template"

"github.com/suse-edge/edge-image-builder/pkg/config"
)

const (
// nolint: unused
embeddedScriptsBaseDir = "scripts"
"github.com/suse-edge/edge-image-builder/pkg/fileio"
)

//go:embed scripts/script_base.sh
Expand Down Expand Up @@ -149,55 +143,12 @@ func (b *Builder) generateCombustionScript() error {

func (b *Builder) writeBuildDirFile(filename string, contents string, templateData any) (string, error) {
destFilename := filepath.Join(b.eibBuildDir, filename)
return destFilename, b.writeFile(destFilename, contents, templateData)
return destFilename, fileio.WriteFile(destFilename, contents, templateData)
}

func (b *Builder) writeCombustionFile(filename string, contents string, templateData any) (string, error) {
destFilename := filepath.Join(b.combustionDir, filename)
return destFilename, b.writeFile(destFilename, contents, templateData)
}

func (b *Builder) writeFile(filename string, contents string, templateData any) error {
if templateData != nil {
tmpl, err := template.New(filename).Parse(contents)
if err != nil {
return fmt.Errorf("creating template for file %s: %w", filename, err)
}

file, err := os.Create(filename)
if err != nil {
return fmt.Errorf("creating file %s: %w", filename, err)
}
defer file.Close()

err = tmpl.Execute(file, templateData)
if err != nil {
return fmt.Errorf("applying the template at %s: %w", filename, err)
}
} else {
err := os.WriteFile(filename, []byte(contents), os.ModePerm)
if err != nil {
return fmt.Errorf("writing file %s: %w", filename, err)
}
}
return nil
}

// nolint: unused
func (b *Builder) copyCombustionFile(scriptSubDir string, scriptName string) error {
sourcePath := filepath.Join(embeddedScriptsBaseDir, scriptSubDir, scriptName)
src, err := os.ReadFile(sourcePath)
if err != nil {
return fmt.Errorf("reading file: %w", err)
}

destFilename := filepath.Join(b.combustionDir, filepath.Base(sourcePath))
err = os.WriteFile(destFilename, src, os.ModePerm)
if err != nil {
return fmt.Errorf("writing file: %w", err)
}

return nil
return destFilename, fileio.WriteFile(destFilename, contents, templateData)
}

func (b *Builder) registerCombustionScript(scriptName string) {
Expand All @@ -217,24 +168,3 @@ func (b *Builder) generateBaseImageFilename() string {
filename := filepath.Join(b.buildConfig.ImageConfigDir, "images", b.imageConfig.Image.BaseImage)
return filename
}

func copyFile(sourcePath string, destPath string) error {
sourceFile, err := os.Open(sourcePath)
if err != nil {
return fmt.Errorf("opening file from source path: %w", err)
}
defer sourceFile.Close()

destFile, err := os.Create(destPath)
if err != nil {
return fmt.Errorf("creating file at dest path: %w", err)
}
defer destFile.Close()

_, err = io.Copy(destFile, sourceFile)
if err != nil {
return fmt.Errorf("copying file from source path to dest path: %w", err)
}

return nil
}
30 changes: 0 additions & 30 deletions pkg/build/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,33 +164,3 @@ func TestWriteBuildDirFile(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, testData, string(foundData))
}

func TestWriteFileWithTemplate(t *testing.T) {
// Setup
builder := New(nil, &config.BuildConfig{})

tmpDir, err := os.MkdirTemp("", "eib-test-")
require.NoError(t, err)
defer os.RemoveAll(tmpDir)

testData := "{{.Foo}} and {{.Bar}}"
values := struct {
Foo string
Bar string
}{
Foo: "ooF",
Bar: "raB",
}
testFilename := filepath.Join(tmpDir, "write-file-with-template.sh")

// Test
err = builder.writeFile(testFilename, testData, &values)

// Verify
require.NoError(t, err)

expectedFilename := filepath.Join(builder.eibBuildDir, testFilename)
foundData, err := os.ReadFile(expectedFilename)
require.NoError(t, err)
assert.Equal(t, "ooF and raB", string(foundData))
}
4 changes: 3 additions & 1 deletion pkg/build/rpm.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"fmt"
"os"
"path/filepath"

"github.com/suse-edge/edge-image-builder/pkg/fileio"
)

func (b *Builder) getRPMFileNames(rpmSourceDir string) ([]string, error) {
Expand Down Expand Up @@ -48,7 +50,7 @@ func (b *Builder) copyRPMs() error {
sourcePath := filepath.Join(rpmSourceDir, rpm)
destPath := filepath.Join(rpmDestDir, rpm)

err = copyFile(sourcePath, destPath)
err = fileio.CopyFile(sourcePath, destPath)
if err != nil {
return fmt.Errorf("copying file %s: %w", sourcePath, err)
}
Expand Down
4 changes: 3 additions & 1 deletion pkg/build/scripts.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"fmt"
"os"
"path/filepath"

"github.com/suse-edge/edge-image-builder/pkg/fileio"
)

const (
Expand Down Expand Up @@ -37,7 +39,7 @@ func (b *Builder) configureScripts() error {
copyMe := filepath.Join(fullScriptsDir, scriptEntry.Name())
copyTo := filepath.Join(b.combustionDir, scriptEntry.Name())

err = copyFile(copyMe, copyTo)
err = fileio.CopyFile(copyMe, copyTo)
if err != nil {
return fmt.Errorf("copying script to %s: %w", copyTo, err)
}
Expand Down
61 changes: 61 additions & 0 deletions pkg/fileio/file_io.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package fileio

import (
"fmt"
"io"
"os"
"text/template"
)

func WriteFile(filename string, contents string, templateData any) error {
if templateData == nil {
if err := os.WriteFile(filename, []byte(contents), os.ModePerm); err != nil {
return fmt.Errorf("writing file: %w", err)
}

return nil
}

tmpl, err := template.New(filename).Parse(contents)
if err != nil {
return fmt.Errorf("parsing template: %w", err)
}

file, err := os.Create(filename)
if err != nil {
return fmt.Errorf("creating file: %w", err)
}
defer func() {
_ = file.Close()
}()

if err = tmpl.Execute(file, templateData); err != nil {
return fmt.Errorf("applying template: %w", err)
}

return nil
}

func CopyFile(src string, dest string) error {
sourceFile, err := os.Open(src)
if err != nil {
return fmt.Errorf("opening source file: %w", err)
}
defer func() {
_ = sourceFile.Close()
}()

destFile, err := os.Create(dest)
if err != nil {
return fmt.Errorf("creating destination file: %w", err)
}
defer func() {
_ = destFile.Close()
}()

if _, err = io.Copy(destFile, sourceFile); err != nil {
return fmt.Errorf("copying file: %w", err)
}

return nil
}
147 changes: 147 additions & 0 deletions pkg/fileio/file_io_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package fileio

import (
"fmt"
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestWriteFile(t *testing.T) {
const tmpDirPrefix = "eib-write-file-test-"

tmpDir, err := os.MkdirTemp("", tmpDirPrefix)
require.NoError(t, err)
defer os.RemoveAll(tmpDir)

tests := []struct {
name string
filename string
contents string
templateData any
expectedContents string
expectedErr string
}{
{
name: "Standard file is successfully written",
filename: "standard",
contents: "this is a non-templated file",
expectedContents: "this is a non-templated file",
},
{
name: "Templated file is successfully written",
filename: "template",
contents: "{{.Foo}} and {{.Bar}}",
templateData: struct {
Foo string
Bar string
}{
Foo: "ooF",
Bar: "raB",
},
expectedContents: "ooF and raB",
},
{
name: "Templated file is not written due to invalid syntax",
filename: "invalid-syntax",
contents: "{{.Foo and ",
templateData: struct{}{},
expectedErr: fmt.Sprintf("parsing template: template: %s/invalid-syntax:1: unclosed action", tmpDir),
},
{
name: "Templated file is not written due to missing field",
filename: "invalid-data",
contents: "{{.Foo}} and {{.Bar}}",
templateData: struct {
Foo string
}{
Foo: "ooF",
},
expectedErr: fmt.Sprintf("applying template: template: %[1]s/invalid-data:1:15: "+
"executing \"%[1]s/invalid-data\" at <.Bar>: can't evaluate field Bar in type struct { Foo string }", tmpDir),
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
filename := filepath.Join(tmpDir, test.filename)

err := WriteFile(filename, test.contents, test.templateData)

if test.expectedErr != "" {
assert.EqualError(t, err, test.expectedErr)
} else {
require.Nil(t, err)

contents, err := os.ReadFile(filename)
require.NoError(t, err)

assert.Equal(t, test.expectedContents, string(contents))
}
})
}
}

func TestCopyFile(t *testing.T) {
const (
source = "file_io.go" // use the source code file as a valid input
destDirPrefix = "eib-copy-file-test-"
)

tmpDir, err := os.MkdirTemp("", destDirPrefix)
require.NoError(t, err)
defer os.RemoveAll(tmpDir)

tests := []struct {
name string
source string
destination string
expectedErr string
}{
{
name: "Source file does not exist",
source: "<missing>",
expectedErr: "opening source file: open <missing>: no such file or directory",
},
{
name: "Destination is an empty file",
source: source,
destination: "",
expectedErr: "creating destination file: open : no such file or directory",
},
{
name: "Destination is a directory",
source: source,
destination: tmpDir,
expectedErr: fmt.Sprintf("creating destination file: open %s: is a directory", tmpDir),
},
{
name: "File is successfully copied",
source: source,
destination: fmt.Sprintf("%s/copy.go", tmpDir),
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
err := CopyFile(test.source, test.destination)

if test.expectedErr != "" {
assert.EqualError(t, err, test.expectedErr)
} else {
require.Nil(t, err)

src, err := os.ReadFile(test.source)
require.NoError(t, err)

dest, err := os.ReadFile(test.destination)
require.NoError(t, err)

assert.Equal(t, src, dest)
}
})
}
}

0 comments on commit d9780ce

Please sign in to comment.