Skip to content

Commit

Permalink
Introduce Context type (#42)
Browse files Browse the repository at this point in the history
* Add DirStructure type

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

* Decouple dir structure handling from Builder

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

* Remove BuildConfig type

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

* Rename DirStructure type to Context

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

* Move CleanUpBuildDir out of the Context type

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

---------

Signed-off-by: Atanas Dinov <[email protected]>
  • Loading branch information
atanasdinov committed Nov 15, 2023
1 parent 5cf336d commit 52147f3
Show file tree
Hide file tree
Showing 15 changed files with 259 additions and 241 deletions.
23 changes: 13 additions & 10 deletions cmd/eib/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const (
argVerbose = "verbose"
)

func processArgs() (*config.ImageConfig, *config.BuildConfig, error) {
func processArgs() (*config.ImageConfig, *build.Context, error) {
var (
configFile string
configDir string
Expand Down Expand Up @@ -48,13 +48,13 @@ func processArgs() (*config.ImageConfig, *config.BuildConfig, error) {
if err != nil {
return nil, nil, fmt.Errorf("validating the config dir %s: %w", configDir, err)
}
buildConfig := config.BuildConfig{
ImageConfigDir: configDir,
BuildDir: buildDir,
DeleteBuildDir: deleteBuildDir,

context, err := build.NewContext(configDir, buildDir, deleteBuildDir)
if err != nil {
return nil, nil, fmt.Errorf("building dir structure: %w", err)
}

return imageConfig, &buildConfig, err
return imageConfig, context, err
}

func setupLogging(verbose bool) {
Expand Down Expand Up @@ -111,14 +111,17 @@ func validateImageConfigDir(configDir string) error {
}

func main() {
imageConfig, buildConfig, err := processArgs()
imageConfig, context, err := processArgs()
if err != nil {
zap.L().Fatal("CLI arguments could not be parsed", zap.Error(err))
}

builder := build.New(imageConfig, buildConfig)
err = builder.Build()
if err != nil {
builder := build.New(imageConfig, context)
if err = builder.Build(); err != nil {
zap.L().Fatal("An error occurred building the image", zap.Error(err))
}

if err = build.CleanUpBuildDir(context); err != nil {
zap.L().Error("Failed to clean up build directory", zap.Error(err))
}
}
76 changes: 12 additions & 64 deletions pkg/build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,20 @@ var combustionScriptBaseCode string

type Builder struct {
imageConfig *config.ImageConfig
buildConfig *config.BuildConfig
context *Context

eibBuildDir string
combustionDir string
combustionScripts []string
}

func New(imageConfig *config.ImageConfig, buildConfig *config.BuildConfig) *Builder {
func New(imageConfig *config.ImageConfig, context *Context) *Builder {
return &Builder{
imageConfig: imageConfig,
buildConfig: buildConfig,
context: context,
}
}

func (b *Builder) Build() error {
err := b.prepareBuildDir()
if err != nil {
return fmt.Errorf("preparing the build directory: %w", err)
}

err = b.configureMessage()
err := b.configureMessage()
if err != nil {
return fmt.Errorf("configuring the welcome message: %w", err)
}
Expand All @@ -58,63 +51,18 @@ func (b *Builder) Build() error {

switch b.imageConfig.Image.ImageType {
case config.ImageTypeISO:
err = b.buildIsoImage()
return b.buildIsoImage()
case config.ImageTypeRAW:
err = b.buildRawImage()
return b.buildRawImage()
default:
err = fmt.Errorf("invalid imageType value specified, must be either \"%s\" or \"%s\"",
return fmt.Errorf("invalid imageType value specified, must be either \"%s\" or \"%s\"",
config.ImageTypeISO, config.ImageTypeRAW)
}

if err != nil {
return err
}

err = b.cleanUpBuildDir()
if err != nil {
return fmt.Errorf("cleaning up the build directory: %w", err)
}

return nil
}

func (b *Builder) prepareBuildDir() error {
// Combustion works by creating a volume with a subdirectory named "combustion"
// and a file named "script". This function builds out that structure and updates
// the Builder so that the other functions can populate it as necessary.

if b.buildConfig.BuildDir == "" {
tmpDir, err := os.MkdirTemp("", "eib-")
if err != nil {
return fmt.Errorf("creating a temporary build directory: %w", err)
}
b.eibBuildDir = tmpDir
} else {
b.eibBuildDir = b.buildConfig.BuildDir
}
b.combustionDir = filepath.Join(b.eibBuildDir, "combustion")

err := os.MkdirAll(b.combustionDir, os.ModePerm)
if err != nil {
return fmt.Errorf("creating the build directory structure: %w", err)
}

return nil
}

func (b *Builder) cleanUpBuildDir() error {
if b.buildConfig.DeleteBuildDir {
err := os.RemoveAll(b.eibBuildDir)
if err != nil {
return fmt.Errorf("deleting build directory: %w", err)
}
}
return nil
}

func (b *Builder) generateCombustionScript() error {
// The file must be located at "combustion/script"
scriptFilename := filepath.Join(b.combustionDir, "script")
scriptFilename := filepath.Join(b.context.CombustionDir, "script")
scriptFile, err := os.Create(scriptFilename)
if err != nil {
return fmt.Errorf("creating the combustion \"script\" file: %w", err)
Expand Down Expand Up @@ -142,12 +90,12 @@ func (b *Builder) generateCombustionScript() error {
}

func (b *Builder) writeBuildDirFile(filename string, contents string, templateData any) (string, error) {
destFilename := filepath.Join(b.eibBuildDir, filename)
destFilename := filepath.Join(b.context.BuildDir, filename)
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)
destFilename := filepath.Join(b.context.CombustionDir, filename)
return destFilename, fileio.WriteFile(destFilename, contents, templateData)
}

Expand All @@ -160,11 +108,11 @@ func (b *Builder) registerCombustionScript(scriptName string) {
}

func (b *Builder) generateOutputImageFilename() string {
filename := filepath.Join(b.buildConfig.ImageConfigDir, b.imageConfig.Image.OutputImageName)
filename := filepath.Join(b.context.ImageConfigDir, b.imageConfig.Image.OutputImageName)
return filename
}

func (b *Builder) generateBaseImageFilename() string {
filename := filepath.Join(b.buildConfig.ImageConfigDir, "images", b.imageConfig.Image.BaseImage)
filename := filepath.Join(b.context.ImageConfigDir, "images", b.imageConfig.Image.BaseImage)
return filename
}
116 changes: 26 additions & 90 deletions pkg/build/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,93 +7,19 @@ import (

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/suse-edge/edge-image-builder/pkg/config"
)

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

// Test
err := builder.prepareBuildDir()
defer os.RemoveAll(builder.eibBuildDir)

// Verify
require.NoError(t, err)
_, err = os.Stat(builder.eibBuildDir)
require.NoError(t, err)
}

func TestPrepareBuildDirExistingDir(t *testing.T) {
// Setup
tmpDir, err := os.MkdirTemp("", "eib-test-")
require.NoError(t, err)
defer os.RemoveAll(tmpDir)

bc := config.BuildConfig{BuildDir: tmpDir}
builder := New(nil, &bc)

// Test
err = builder.prepareBuildDir()

// Verify
require.NoError(t, err)
require.Equal(t, tmpDir, builder.eibBuildDir)
}

func TestCleanUpBuildDirTrue(t *testing.T) {
// Setup
tmpDir, err := os.MkdirTemp("", "eib-test-")
require.NoError(t, err)
defer os.RemoveAll(tmpDir)

bc := config.BuildConfig{
BuildDir: tmpDir,
DeleteBuildDir: true,
}
builder := New(nil, &bc)
require.NoError(t, builder.prepareBuildDir())

// Test
err = builder.cleanUpBuildDir()

// Verify
require.NoError(t, err)
_, err = os.Stat(tmpDir)
require.Error(t, err)
assert.True(t, os.IsNotExist(err))
}

func TestCleanUpBuildDirFalse(t *testing.T) {
func TestGenerateCombustionScript(t *testing.T) {
// Setup
tmpDir, err := os.MkdirTemp("", "eib-test-")
context, err := NewContext("", "", true)
require.NoError(t, err)
defer os.RemoveAll(tmpDir)
defer func() {
assert.NoError(t, CleanUpBuildDir(context))
}()

bc := config.BuildConfig{
BuildDir: tmpDir,
DeleteBuildDir: false,
builder := Builder{
context: context,
}
builder := New(nil, &bc)
require.NoError(t, builder.prepareBuildDir())

// Test
err = builder.cleanUpBuildDir()

// Verify
require.NoError(t, err)
_, err = os.Stat(tmpDir)
require.NoError(t, err)
}

func TestGenerateCombustionScript(t *testing.T) {
// Setup
bc := config.BuildConfig{}
builder := New(nil, &bc)
err := builder.prepareBuildDir()
require.NoError(t, err)
defer os.RemoveAll(builder.eibBuildDir)

builder.combustionScripts = append(builder.combustionScripts, "foo.sh", "bar.sh")

Expand All @@ -104,7 +30,7 @@ func TestGenerateCombustionScript(t *testing.T) {
require.NoError(t, err)

// - check the script contents itself
scriptBytes, err := os.ReadFile(filepath.Join(builder.combustionDir, "script"))
scriptBytes, err := os.ReadFile(filepath.Join(context.CombustionDir, "script"))
require.NoError(t, err)
scriptData := string(scriptBytes)
assert.Contains(t, scriptData, "#!/bin/bash")
Expand All @@ -118,10 +44,15 @@ func TestGenerateCombustionScript(t *testing.T) {

func TestWriteCombustionFile(t *testing.T) {
// Setup
builder := New(nil, &config.BuildConfig{})
err := builder.prepareBuildDir()
context, err := NewContext("", "", true)
require.NoError(t, err)
defer os.RemoveAll(builder.eibBuildDir)
defer func() {
assert.NoError(t, CleanUpBuildDir(context))
}()

builder := Builder{
context: context,
}

testData := "Edge Image Builder"
testFilename := "combustion-file.sh"
Expand All @@ -132,7 +63,7 @@ func TestWriteCombustionFile(t *testing.T) {
// Verify
require.NoError(t, err)

expectedFilename := filepath.Join(builder.combustionDir, testFilename)
expectedFilename := filepath.Join(context.CombustionDir, testFilename)
foundData, err := os.ReadFile(expectedFilename)
require.NoError(t, err)
assert.Equal(t, expectedFilename, writtenFilename)
Expand All @@ -144,10 +75,15 @@ func TestWriteCombustionFile(t *testing.T) {

func TestWriteBuildDirFile(t *testing.T) {
// Setup
builder := New(nil, &config.BuildConfig{})
err := builder.prepareBuildDir()
context, err := NewContext("", "", true)
require.NoError(t, err)
defer os.RemoveAll(builder.eibBuildDir)
defer func() {
assert.NoError(t, CleanUpBuildDir(context))
}()

builder := Builder{
context: context,
}

testData := "Edge Image Builder"
testFilename := "build-dir-file.sh"
Expand All @@ -158,7 +94,7 @@ func TestWriteBuildDirFile(t *testing.T) {
// Verify
require.NoError(t, err)

expectedFilename := filepath.Join(builder.eibBuildDir, testFilename)
expectedFilename := filepath.Join(context.BuildDir, testFilename)
require.Equal(t, expectedFilename, writtenFilename)
foundData, err := os.ReadFile(expectedFilename)
require.NoError(t, err)
Expand Down
50 changes: 50 additions & 0 deletions pkg/build/context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package build

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

type Context struct {
// ImageConfigDir is the root directory storing all configuration files.
ImageConfigDir string
// BuildDir is the directory used for assembling the different components used in a build.
BuildDir string
// CombustionDir is a subdirectory under BuildDir containing the Combustion script and all related files.
CombustionDir string
// DeleteBuildDir indicates whether the BuildDir should be cleaned up after the image is built.
DeleteBuildDir bool
}

func NewContext(imageConfigDir, buildDir string, deleteBuildDir bool) (*Context, error) {
if buildDir == "" {
tmpDir, err := os.MkdirTemp("", "eib-")
if err != nil {
return nil, fmt.Errorf("creating a temporary build directory: %w", err)
}
buildDir = tmpDir
}
combustionDir := filepath.Join(buildDir, "combustion")

if err := os.MkdirAll(combustionDir, os.ModePerm); err != nil {
return nil, fmt.Errorf("creating the combustion directory: %w", err)
}

return &Context{
ImageConfigDir: imageConfigDir,
BuildDir: buildDir,
CombustionDir: combustionDir,
DeleteBuildDir: deleteBuildDir,
}, nil
}

func CleanUpBuildDir(c *Context) error {
if c.DeleteBuildDir {
err := os.RemoveAll(c.BuildDir)
if err != nil {
return fmt.Errorf("deleting build directory: %w", err)
}
}
return nil
}
Loading

0 comments on commit 52147f3

Please sign in to comment.