From 3bc45caf40801482e795add7d9e167c7308d5042 Mon Sep 17 00:00:00 2001 From: dbw7 Date: Thu, 2 Nov 2023 04:36:03 -0400 Subject: [PATCH] Copy local RPMs to image (#28) * added handling for adding rpms to an image as well as the relevant tests * remove rpm dir from combustion * update to loop for linter * updates based on feedback * added .gitkeep * handling for .gitkeep and and reformatting for linter * updates based on feedback copyFile is no longer attached to the build struct. getRPMFileNames now checks for the .rpm extension, to remove the previously unnecessary (and frankly ugly) logic. I also added more abstraction for readability. Finally, cleaned up the tests based on feedback and altered them to match changes. * removed unnecessary filepath.Join * update .gitignore and remove .idea * added handling and tests for when user doesn't add rpms * removing else statement for linter --- .gitignore | 3 + pkg/build/build.go | 27 +++++++ pkg/build/rpm.go | 58 ++++++++++++++ pkg/build/rpm_test.go | 125 ++++++++++++++++++++++++++++++ pkg/config/testdata/rpms/.gitkeep | 0 5 files changed, 213 insertions(+) create mode 100644 pkg/build/rpm.go create mode 100644 pkg/build/rpm_test.go create mode 100644 pkg/config/testdata/rpms/.gitkeep diff --git a/.gitignore b/.gitignore index de67df5e..ed88a340 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,6 @@ # Go workspace file go.work + +# IDE +.idea \ No newline at end of file diff --git a/pkg/build/build.go b/pkg/build/build.go index d1e43a59..1e76cb97 100644 --- a/pkg/build/build.go +++ b/pkg/build/build.go @@ -3,6 +3,7 @@ package build import ( _ "embed" "fmt" + "io" "os" "path/filepath" "text/template" @@ -50,6 +51,11 @@ func (b *Builder) Build() error { return fmt.Errorf("generating combustion script: %w", err) } + err = b.copyRPMs() + if err != nil { + return fmt.Errorf("copying RPMs over: %w", err) + } + switch b.imageConfig.Image.ImageType { case config.ImageTypeISO: err = b.buildIsoImage() @@ -202,3 +208,24 @@ 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 +} diff --git a/pkg/build/rpm.go b/pkg/build/rpm.go new file mode 100644 index 00000000..48e37d44 --- /dev/null +++ b/pkg/build/rpm.go @@ -0,0 +1,58 @@ +package build + +import ( + "fmt" + "os" + "path/filepath" +) + +func (b *Builder) getRPMFileNames(rpmSourceDir string) ([]string, error) { + var rpmFileNames []string + + rpms, err := os.ReadDir(rpmSourceDir) + if err != nil { + return nil, fmt.Errorf("reading rpm source dir: %w", err) + } + + for _, rpmFile := range rpms { + if filepath.Ext(rpmFile.Name()) == ".rpm" { + rpmFileNames = append(rpmFileNames, rpmFile.Name()) + } + } + + if len(rpmFileNames) == 0 { + return nil, fmt.Errorf("no rpms found") + } + + return rpmFileNames, nil +} + +func (b *Builder) copyRPMs() error { + rpmSourceDir := filepath.Join(b.buildConfig.ImageConfigDir, "rpms") + // Only proceed with copying the RPMs if the directory exists + _, err := os.Stat(rpmSourceDir) + if err != nil { + if os.IsNotExist(err) { + return nil + } + return fmt.Errorf("checking for rpm directory at %s: %w", rpmSourceDir, err) + } + rpmDestDir := b.combustionDir + + rpmFileNames, err := b.getRPMFileNames(rpmSourceDir) + if err != nil { + return fmt.Errorf("getting rpm file names: %w", err) + } + + for _, rpm := range rpmFileNames { + sourcePath := filepath.Join(rpmSourceDir, rpm) + destPath := filepath.Join(rpmDestDir, rpm) + + err = copyFile(sourcePath, destPath) + if err != nil { + return fmt.Errorf("copying file %s: %w", sourcePath, err) + } + } + + return nil +} diff --git a/pkg/build/rpm_test.go b/pkg/build/rpm_test.go new file mode 100644 index 00000000..b5420247 --- /dev/null +++ b/pkg/build/rpm_test.go @@ -0,0 +1,125 @@ +package build + +import ( + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/suse-edge/edge-image-builder/pkg/config" +) + +func TestGetRPMFileNames(t *testing.T) { + // Setup + bc := config.BuildConfig{ + ImageConfigDir: "../config/testdata", + } + builder := New(nil, &bc) + err := builder.prepareBuildDir() + require.NoError(t, err) + defer os.Remove(builder.eibBuildDir) + + rpmSourceDir := filepath.Join(builder.buildConfig.ImageConfigDir, "rpms") + + file1Path := filepath.Join(rpmSourceDir, "rpm1.rpm") + defer os.Remove(file1Path) + file1, err := os.Create(file1Path) + require.NoError(t, err) + + file2Path := filepath.Join(rpmSourceDir, "rpm2.rpm") + defer os.Remove(file2Path) + file2, err := os.Create(file2Path) + require.NoError(t, err) + + // Test + rpmFileNames, err := builder.getRPMFileNames(rpmSourceDir) + + // Verify + require.NoError(t, err) + + assert.Contains(t, rpmFileNames, "rpm1.rpm") + assert.Contains(t, rpmFileNames, "rpm2.rpm") + + // Cleanup + assert.NoError(t, file1.Close()) + assert.NoError(t, file2.Close()) +} + +func TestCopyRPMs(t *testing.T) { + // Setup + bc := config.BuildConfig{ + ImageConfigDir: "../config/testdata", + } + builder := New(nil, &bc) + err := builder.prepareBuildDir() + require.NoError(t, err) + defer os.Remove(builder.eibBuildDir) + + rpmSourceDir := filepath.Join(builder.buildConfig.ImageConfigDir, "rpms") + rpmDestDir := builder.combustionDir + + file1Path := filepath.Join(rpmSourceDir, "rpm1.rpm") + defer os.Remove(file1Path) + file1, err := os.Create(file1Path) + require.NoError(t, err) + + file2Path := filepath.Join(rpmSourceDir, "rpm2.rpm") + defer os.Remove(file2Path) + file2, err := os.Create(file2Path) + require.NoError(t, err) + + // Test + err = builder.copyRPMs() + + // Verify + require.NoError(t, err) + + _, err = os.Stat(filepath.Join(rpmDestDir, "rpm1.rpm")) + require.NoError(t, err) + + _, err = os.Stat(filepath.Join(rpmDestDir, "rpm2.rpm")) + require.NoError(t, err) + + // Cleanup + assert.NoError(t, file1.Close()) + assert.NoError(t, file2.Close()) +} + +func TestGetRPMFileNamesNoRPMs(t *testing.T) { + // Setup + bc := config.BuildConfig{ + ImageConfigDir: "../config/testdata", + } + builder := New(nil, &bc) + err := builder.prepareBuildDir() + require.NoError(t, err) + defer os.Remove(builder.eibBuildDir) + + rpmSourceDir := filepath.Join(builder.buildConfig.ImageConfigDir, "rpms") + + // Test + rpmFileNames, err := builder.getRPMFileNames(rpmSourceDir) + + // Verify + require.ErrorContains(t, err, "no rpms found") + + assert.Empty(t, rpmFileNames) +} + +func TestCopyRPMsNoRPMDir(t *testing.T) { + // Setup + bc := config.BuildConfig{ + ImageConfigDir: "../config/ThisDirDoesNotExist", + } + builder := New(nil, &bc) + err := builder.prepareBuildDir() + require.NoError(t, err) + defer os.Remove(builder.eibBuildDir) + + // Test + err = builder.copyRPMs() + + // Verify + require.NoError(t, err) +} diff --git a/pkg/config/testdata/rpms/.gitkeep b/pkg/config/testdata/rpms/.gitkeep new file mode 100644 index 00000000..e69de29b