From fbee2dc57d5a90b50b96179c1928744072b0cde4 Mon Sep 17 00:00:00 2001 From: Daniel Mikusa Date: Thu, 17 Aug 2023 22:42:12 -0400 Subject: [PATCH 1/6] Updates for layer contributors Signed-off-by: Daniel Mikusa --- layer.go | 115 +++++++++++++++++++++++++++++++------------------- layer_test.go | 103 ++++++++++++++++++++++---------------------- 2 files changed, 124 insertions(+), 94 deletions(-) diff --git a/layer.go b/layer.go index 548b978..bcea074 100644 --- a/layer.go +++ b/layer.go @@ -35,10 +35,41 @@ import ( "github.com/paketo-buildpacks/libpak/v2/bard" ) -// LayerContributor is a helper for implementing a libcnb.LayerContributor in order to get consistent logging and -// avoidance. -type LayerContributor struct { +// ContributableBuildFunc is a standard libcnb.BuildFunc implementation that delegates to a list of Contributables +func ContributableBuildFunc(layerContributors []Contributable) libcnb.BuildFunc { + return func(context libcnb.BuildContext) (libcnb.BuildResult, error) { + result := libcnb.NewBuildResult() + + for _, creator := range layerContributors { + name := creator.Name() + layer, err := context.Layers.Layer(name) + if err != nil { + return libcnb.BuildResult{}, fmt.Errorf("unable to create layer %s\n%w", name, err) + } + + err = creator.Contribute(&layer) + if err != nil { + return libcnb.BuildResult{}, fmt.Errorf("unable to invoke layer creator\n%w", err) + } + + result.Layers = append(result.Layers, layer) + } + + return result, nil + } +} +// Contributable is an interface that is implemented when you want to contribute new layers +type Contributable interface { + // Contribute accepts a new empty layer and transforms it + Contribute(layer *libcnb.Layer) error + + // Name is the name of the layer. + Name() string +} + +// LayerContributor is a helper for implementing Contributable in order to get consistent logging and avoidance. +type LayerContributor struct { // ExpectedMetadata is the metadata to compare against any existing layer metadata. ExpectedMetadata interface{} @@ -53,33 +84,34 @@ type LayerContributor struct { } // NewLayerContributor creates a new instance. -func NewLayerContributor(name string, expectedMetadata interface{}, expectedTypes libcnb.LayerTypes) LayerContributor { +func NewLayerContributor(name string, expectedMetadata interface{}, expectedTypes libcnb.LayerTypes, logger bard.Logger) LayerContributor { return LayerContributor{ ExpectedMetadata: expectedMetadata, - Name: name, ExpectedTypes: expectedTypes, + Logger: logger, + Name: name, } } // LayerFunc is a callback function that is invoked when a layer needs to be contributed. -type LayerFunc func() (libcnb.Layer, error) +type LayerFunc func(*libcnb.Layer) error -// Contribute is the function to call when implementing your libcnb.LayerContributor. -func (l *LayerContributor) Contribute(layer libcnb.Layer, f LayerFunc) (libcnb.Layer, error) { - layerRestored, err := l.checkIfLayerRestored(layer) +// Contribute is the function to call when implementing Contributable. +func (l *LayerContributor) Contribute(layer *libcnb.Layer, f LayerFunc) error { + layerRestored, err := l.checkIfLayerRestored(*layer) if err != nil { - return libcnb.Layer{}, fmt.Errorf("unable to check metadata\n%w", err) + return fmt.Errorf("unable to check metadata\n%w", err) } - expected, cached, err := l.checkIfMetadataMatches(layer) + expected, cached, err := l.checkIfMetadataMatches(*layer) if err != nil { - return libcnb.Layer{}, fmt.Errorf("unable to check metadata\n%w", err) + return fmt.Errorf("unable to check metadata\n%w", err) } if cached && layerRestored { l.Logger.Headerf("%s: %s cached layer", color.BlueString(l.Name), color.GreenString("Reusing")) layer.LayerTypes = l.ExpectedTypes - return layer, nil + return nil } if !layerRestored { @@ -90,18 +122,18 @@ func (l *LayerContributor) Contribute(layer libcnb.Layer, f LayerFunc) (libcnb.L err = l.reset(layer) if err != nil { - return libcnb.Layer{}, fmt.Errorf("unable to reset\n%w", err) + return fmt.Errorf("unable to reset\n%w", err) } - layer, err = f() + err = f(layer) if err != nil { - return libcnb.Layer{}, err + return err } layer.LayerTypes = l.ExpectedTypes layer.Metadata = expected - return layer, nil + return nil } func (l *LayerContributor) checkIfMetadataMatches(layer libcnb.Layer) (map[string]interface{}, bool, error) { @@ -146,7 +178,7 @@ func (l *LayerContributor) checkIfLayerRestored(layer libcnb.Layer) (bool, error return !(tomlExists && (!layerDirExists || len(dirContents) == 0) && (l.ExpectedTypes.Cache || l.ExpectedTypes.Build)), nil } -func (l *LayerContributor) reset(layer libcnb.Layer) error { +func (l *LayerContributor) reset(layer *libcnb.Layer) error { if err := os.RemoveAll(layer.Path); err != nil { return fmt.Errorf("unable to remove existing layer directory %s\n%w", layer.Path, err) } @@ -158,7 +190,7 @@ func (l *LayerContributor) reset(layer libcnb.Layer) error { return nil } -// DependencyLayerContributor is a helper for implementing a libcnb.LayerContributor for a BuildpackDependency in order +// DependencyLayerContributor is a helper for implementing a Contributable for a BuildpackDependency in order // to get consistent logging and avoidance. type DependencyLayerContributor struct { @@ -192,34 +224,33 @@ func NewDependencyLayerContributor(dependency BuildModuleDependency, cache Depen } // DependencyLayerFunc is a callback function that is invoked when a dependency needs to be contributed. -type DependencyLayerFunc func(artifact *os.File) (libcnb.Layer, error) +type DependencyLayerFunc func(layer *libcnb.Layer, artifact *os.File) error -// Contribute is the function to call whe implementing your libcnb.LayerContributor. -func (d *DependencyLayerContributor) Contribute(layer libcnb.Layer, f DependencyLayerFunc) (libcnb.Layer, error) { - lc := NewLayerContributor(d.Name(), d.ExpectedMetadata, d.ExpectedTypes) - lc.Logger = d.Logger +// Contribute is the function to call whe implementing your Contributable. +func (d *DependencyLayerContributor) Contribute(layer *libcnb.Layer, f DependencyLayerFunc) error { + lc := NewLayerContributor(d.Name(), d.ExpectedMetadata, d.ExpectedTypes, d.Logger) - return lc.Contribute(layer, func() (libcnb.Layer, error) { + return lc.Contribute(layer, func(_ *libcnb.Layer) error { artifact, err := d.DependencyCache.Artifact(d.Dependency, d.RequestModifierFuncs...) if err != nil { - return libcnb.Layer{}, fmt.Errorf("unable to get dependency %s\n%w", d.Dependency.ID, err) + return fmt.Errorf("unable to get dependency %s\n%w", d.Dependency.ID, err) } defer artifact.Close() // Only buildpacks can create layers, so source must be buildpack.toml sbomArtifact, err := d.Dependency.AsSyftArtifact("buildpack.toml") if err != nil { - return libcnb.Layer{}, fmt.Errorf("unable to get SBOM artifact %s\n%w", d.Dependency.ID, err) + return fmt.Errorf("unable to get SBOM artifact %s\n%w", d.Dependency.ID, err) } sbomPath := layer.SBOMPath(libcnb.SyftJSON) dep := sbom.NewSyftDependency(layer.Path, []sbom.SyftArtifact{sbomArtifact}) d.Logger.Debugf("Writing Syft SBOM at %s: %+v", sbomPath, dep) if err := dep.WriteTo(sbomPath); err != nil { - return libcnb.Layer{}, fmt.Errorf("unable to write SBOM\n%w", err) + return fmt.Errorf("unable to write SBOM\n%w", err) } - return f(artifact) + return f(layer, artifact) }) } @@ -233,7 +264,7 @@ func (d *DependencyLayerContributor) Name() string { return fmt.Sprintf("%s %s", d.Dependency.Name, d.Dependency.Version) } -// HelperLayerContributor is a helper for implementing a libcnb.LayerContributor for a buildpack helper application in +// HelperLayerContributor is a helper for implementing a Contributable for a buildpack helper application in // order to get consistent logging and avoidance. type HelperLayerContributor struct { @@ -264,25 +295,23 @@ func (h HelperLayerContributor) Name() string { return filepath.Base(h.Path) } -// Contribute is the function to call whe implementing your libcnb.LayerContributor. -func (h HelperLayerContributor) Contribute(layer libcnb.Layer) (libcnb.Layer, error) { +// Contribute is the function to call whe implementing your Contributable. +func (h HelperLayerContributor) Contribute(layer *libcnb.Layer) error { expected := map[string]interface{}{"buildpackInfo": h.BuildpackInfo, "helperNames": h.Names} lc := NewLayerContributor("Launch Helper", expected, libcnb.LayerTypes{ Launch: true, - }) - - lc.Logger = h.Logger + }, h.Logger) - return lc.Contribute(layer, func() (libcnb.Layer, error) { + return lc.Contribute(layer, func(_ *libcnb.Layer) error { in, err := os.Open(h.Path) if err != nil { - return libcnb.Layer{}, fmt.Errorf("unable to open %s\n%w", h.Path, err) + return fmt.Errorf("unable to open %s\n%w", h.Path, err) } defer in.Close() out := filepath.Join(layer.Path, "helper") if err := sherpa.CopyFile(in, out); err != nil { - return libcnb.Layer{}, fmt.Errorf("unable to copy %s to %s", h.Path, out) + return fmt.Errorf("unable to copy %s to %s", h.Path, out) } for _, n := range h.Names { @@ -291,27 +320,27 @@ func (h HelperLayerContributor) Contribute(layer libcnb.Layer) (libcnb.Layer, er f := filepath.Dir(link) if err := os.MkdirAll(f, 0755); err != nil { - return libcnb.Layer{}, fmt.Errorf("unable to create %s\n%w", f, err) + return fmt.Errorf("unable to create %s\n%w", f, err) } if err := os.Symlink(out, link); err != nil { - return libcnb.Layer{}, fmt.Errorf("unable to link %s to %s\n%w", out, link, err) + return fmt.Errorf("unable to link %s to %s\n%w", out, link, err) } } sbomArtifact, err := h.AsSyftArtifact() if err != nil { - return libcnb.Layer{}, fmt.Errorf("unable to get SBOM artifact for helper\n%w", err) + return fmt.Errorf("unable to get SBOM artifact for helper\n%w", err) } sbomPath := layer.SBOMPath(libcnb.SyftJSON) dep := sbom.NewSyftDependency(layer.Path, []sbom.SyftArtifact{sbomArtifact}) h.Logger.Debugf("Writing Syft SBOM at %s: %+v", sbomPath, dep) if err := dep.WriteTo(sbomPath); err != nil { - return libcnb.Layer{}, fmt.Errorf("unable to write SBOM\n%w", err) + return fmt.Errorf("unable to write SBOM\n%w", err) } - return layer, nil + return nil }) } diff --git a/layer_test.go b/layer_test.go index fa87f96..6561b07 100644 --- a/layer_test.go +++ b/layer_test.go @@ -39,11 +39,12 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { Expect = NewWithT(t).Expect layersDir string - layer libcnb.Layer + layer *libcnb.Layer ) it.Before(func() { layersDir = t.TempDir() + layer = &libcnb.Layer{} layer.Path = filepath.Join(layersDir, "test-layer") layer.Exec.Path = layer.Path @@ -74,9 +75,9 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { it("calls function with no existing metadata", func() { var called bool - _, err := lc.Contribute(layer, func() (libcnb.Layer, error) { + err := lc.Contribute(layer, func(layer *libcnb.Layer) error { called = true - return layer, nil + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -89,9 +90,9 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { var called bool - _, err := lc.Contribute(layer, func() (libcnb.Layer, error) { + err := lc.Contribute(layer, func(layer *libcnb.Layer) error { called = true - return layer, nil + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -117,9 +118,9 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { Expect(os.RemoveAll(layer.Path)).To(Succeed()) lc.ExpectedTypes.Cache = true - _, err := lc.Contribute(layer, func() (libcnb.Layer, error) { + err := lc.Contribute(layer, func(layer *libcnb.Layer) error { called = true - return layer, nil + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -131,9 +132,9 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { Expect(os.RemoveAll(layer.Path)).To(Succeed()) lc.ExpectedTypes.Build = true - _, err := lc.Contribute(layer, func() (libcnb.Layer, error) { + err := lc.Contribute(layer, func(layer *libcnb.Layer) error { called = true - return layer, nil + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -145,9 +146,9 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { Expect(os.MkdirAll(layer.Path, 0755)).To(Succeed()) lc.ExpectedTypes.Build = true - _, err := lc.Contribute(layer, func() (libcnb.Layer, error) { + err := lc.Contribute(layer, func(layer *libcnb.Layer) error { called = true - return layer, nil + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -160,9 +161,9 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { Expect(os.WriteFile(filepath.Join(layer.Path, "foo"), []byte{}, 0644)).To(Succeed()) lc.ExpectedTypes.Build = true - _, err := lc.Contribute(layer, func() (libcnb.Layer, error) { + err := lc.Contribute(layer, func(layer *libcnb.Layer) error { called = true - return layer, nil + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -173,9 +174,9 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { Expect(os.MkdirAll(layer.Path, 0755)).To(Succeed()) layer.Build = true - _, err := lc.Contribute(layer, func() (libcnb.Layer, error) { + err := lc.Contribute(layer, func(layer *libcnb.Layer) error { called = true - return layer, nil + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -194,9 +195,9 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { var called bool - _, err := lc.Contribute(layer, func() (libcnb.Layer, error) { + err := lc.Contribute(layer, func(layer *libcnb.Layer) error { called = true - return layer, nil + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -204,15 +205,15 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { }) it("returns function error", func() { - _, err := lc.Contribute(layer, func() (libcnb.Layer, error) { - return libcnb.Layer{}, fmt.Errorf("test-error") + err := lc.Contribute(layer, func(layer *libcnb.Layer) error { + return fmt.Errorf("test-error") }) Expect(err).To(MatchError("test-error")) }) it("adds expected metadata to layer", func() { - layer, err := lc.Contribute(layer, func() (libcnb.Layer, error) { - return layer, nil + err := lc.Contribute(layer, func(layer *libcnb.Layer) error { + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -227,8 +228,8 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { it("sets build layer flag", func() { lc.ExpectedTypes.Build = true - layer, err := lc.Contribute(layer, func() (libcnb.Layer, error) { - return layer, nil + err := lc.Contribute(layer, func(layer *libcnb.Layer) error { + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -237,8 +238,8 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { it("sets cache layer flag", func() { lc.ExpectedTypes.Cache = true - layer, err := lc.Contribute(layer, func() (libcnb.Layer, error) { - return layer, nil + err := lc.Contribute(layer, func(layer *libcnb.Layer) error { + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -247,8 +248,8 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { it("sets launch layer flag", func() { lc.ExpectedTypes.Launch = true - layer, err := lc.Contribute(layer, func() (libcnb.Layer, error) { - return layer, nil + err := lc.Contribute(layer, func(layer *libcnb.Layer) error { + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -270,9 +271,9 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { var called bool - layer, err := lc.Contribute(layer, func() (libcnb.Layer, error) { + err := lc.Contribute(layer, func(layer *libcnb.Layer) error { called = true - return layer, nil + return nil }) Expect(err).NotTo(HaveOccurred()) Expect(called).To(BeFalse()) @@ -333,11 +334,11 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { var called bool - _, err := dlc.Contribute(layer, func(artifact *os.File) (libcnb.Layer, error) { + err := dlc.Contribute(layer, func(layer *libcnb.Layer, artifact *os.File) error { defer artifact.Close() called = true - return layer, nil + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -355,9 +356,9 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { return request, nil }) - _, err := dlc.Contribute(layer, func(artifact *os.File) (libcnb.Layer, error) { + err := dlc.Contribute(layer, func(layer *libcnb.Layer, artifact *os.File) error { defer artifact.Close() - return layer, nil + return nil }) Expect(err).NotTo(HaveOccurred()) }) @@ -369,11 +370,11 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { var called bool - _, err := dlc.Contribute(layer, func(artifact *os.File) (libcnb.Layer, error) { + err := dlc.Contribute(layer, func(layer *libcnb.Layer, artifact *os.File) error { defer artifact.Close() called = true - return layer, nil + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -401,11 +402,11 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { var called bool - _, err := dlc.Contribute(layer, func(artifact *os.File) (libcnb.Layer, error) { + err := dlc.Contribute(layer, func(layer *libcnb.Layer, artifact *os.File) error { defer artifact.Close() called = true - return layer, nil + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -415,10 +416,10 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { it("returns function error", func() { server.AppendHandlers(ghttp.RespondWith(http.StatusOK, "test-fixture")) - _, err := dlc.Contribute(layer, func(artifact *os.File) (libcnb.Layer, error) { + err := dlc.Contribute(layer, func(layer *libcnb.Layer, artifact *os.File) error { defer artifact.Close() - return libcnb.Layer{}, fmt.Errorf("test-error") + return fmt.Errorf("test-error") }) Expect(err).To(MatchError("test-error")) }) @@ -426,9 +427,9 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { it("adds expected metadata to layer", func() { server.AppendHandlers(ghttp.RespondWith(http.StatusOK, "test-fixture")) - layer, err := dlc.Contribute(layer, func(artifact *os.File) (libcnb.Layer, error) { + err := dlc.Contribute(layer, func(layer *libcnb.Layer, artifact *os.File) error { defer artifact.Close() - return layer, nil + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -475,11 +476,11 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { var called bool - layer, err := dlc.Contribute(layer, func(artifact *os.File) (libcnb.Layer, error) { + err := dlc.Contribute(layer, func(layer *libcnb.Layer, artifact *os.File) error { defer artifact.Close() called = true - return layer, nil + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -493,9 +494,9 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { it("adds expected Syft SBOM file", func() { server.AppendHandlers(ghttp.RespondWith(http.StatusOK, "test-fixture")) - layer, err := dlc.Contribute(layer, func(artifact *os.File) (libcnb.Layer, error) { + err := dlc.Contribute(layer, func(layer *libcnb.Layer, artifact *os.File) error { defer artifact.Close() - return layer, nil + return nil }) Expect(err).NotTo(HaveOccurred()) @@ -547,7 +548,7 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { }) it("calls function with no existing metadata", func() { - _, err := hlc.Contribute(layer) + err := hlc.Contribute(layer) Expect(err).NotTo(HaveOccurred()) Expect(filepath.Join(layer.Exec.FilePath("test-name-1"))).To(BeAnExistingFile()) @@ -556,7 +557,7 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { it("calls function with non-matching metadata", func() { layer.Metadata["alpha"] = "other-alpha" - _, err := hlc.Contribute(layer) + err := hlc.Contribute(layer) Expect(err).NotTo(HaveOccurred()) file := filepath.Join(layer.Exec.FilePath("test-name-1")) @@ -580,7 +581,7 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { layer.Metadata["buildpackInfo"] = buildpackInfo layer.Metadata["helperNames"] = []interface{}{hlc.Names[0], hlc.Names[1]} - _, err := hlc.Contribute(layer) + err := hlc.Contribute(layer) Expect(err).NotTo(HaveOccurred()) @@ -589,7 +590,7 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { }) it("adds expected metadata to layer", func() { - layer, err := hlc.Contribute(layer) + err := hlc.Contribute(layer) Expect(err).NotTo(HaveOccurred()) buildpackInfo := map[string]interface{}{ @@ -617,7 +618,7 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { // Launch is the only one set & always true - layer, err := hlc.Contribute(layer) + err := hlc.Contribute(layer) Expect(err).NotTo(HaveOccurred()) Expect(filepath.Join(layer.Exec.FilePath("test-name-1"))).NotTo(BeAnExistingFile()) @@ -631,7 +632,7 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { it("adds expected Syft SBOM file", func() { layer.Metadata = map[string]interface{}{} - _, err := hlc.Contribute(layer) + err := hlc.Contribute(layer) Expect(err).NotTo(HaveOccurred()) Expect(filepath.Join(layer.Exec.FilePath("test-name-1"))).To(BeAnExistingFile()) From b6a8693340831f453243535a0aa66a5c1ac878ce Mon Sep 17 00:00:00 2001 From: Daniel Mikusa Date: Sat, 26 Aug 2023 21:39:40 -0400 Subject: [PATCH 2/6] Rename bard to log This commit renames the bard package to log. This is because while bard is a witty name it is not always the most clear, especially for folks where English is not their primary language. Signed-off-by: Daniel Mikusa --- build.go | 4 ++-- build_test.go | 4 ++-- buildmodule.go | 6 +++--- buildmodule_test.go | 4 ++-- carton/build_image_dependency.go | 6 +++--- carton/buildmodule_dependency.go | 6 +++--- carton/lifecycle_dependency.go | 6 +++--- carton/package.go | 4 ++-- carton/package_dependency.go | 6 +++--- dependency_cache.go | 4 ++-- detect.go | 4 ++-- detect_test.go | 4 ++-- generate.go | 4 ++-- generate_test.go | 4 ++-- internal/environment_writer.go | 10 +++++----- internal/environment_writer_test.go | 4 ++-- internal/exit_handler.go | 12 ++++++------ internal/exit_handler_test.go | 6 +++--- internal/toml_writer.go | 11 +++++------ internal/toml_writer_test.go | 4 ++-- layer.go | 11 +++++------ layer_test.go | 8 ++++---- {bard => log}/formatter.go | 2 +- {bard => log}/formatter_test.go | 9 ++++----- {bard => log}/init_test.go | 4 ++-- {bard => log}/logger.go | 2 +- {bard => log}/logger_test.go | 19 +++++++++---------- {bard => log}/writer.go | 2 +- {bard => log}/writer_test.go | 21 ++++++++++----------- sbom/sbom.go | 6 +++--- sbom/sbom_test.go | 10 +++++----- 31 files changed, 101 insertions(+), 106 deletions(-) rename {bard => log}/formatter.go (98%) rename {bard => log}/formatter_test.go (86%) rename {bard => log}/init_test.go (91%) rename {bard => log}/logger.go (99%) rename {bard => log}/logger_test.go (93%) rename {bard => log}/writer.go (99%) rename {bard => log}/writer_test.go (86%) diff --git a/build.go b/build.go index cc10821..bde2f76 100644 --- a/build.go +++ b/build.go @@ -19,8 +19,8 @@ package libpak import ( "github.com/buildpacks/libcnb/v2" - "github.com/paketo-buildpacks/libpak/v2/bard" "github.com/paketo-buildpacks/libpak/v2/internal" + "github.com/paketo-buildpacks/libpak/v2/log" ) // Build is called by the main function of a buildpack, for build. @@ -40,7 +40,7 @@ type buildDelegate struct { func (b buildDelegate) Build(context libcnb.BuildContext) (libcnb.BuildResult, error) { result, err := b.delegate(context) if err != nil { - err = bard.IdentifiableError{ + err = log.IdentifiableError{ Name: context.Buildpack.Info.Name, Description: context.Buildpack.Info.Version, Err: err, diff --git a/build_test.go b/build_test.go index b52cf38..a988277 100644 --- a/build_test.go +++ b/build_test.go @@ -29,7 +29,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/paketo-buildpacks/libpak/v2" - "github.com/paketo-buildpacks/libpak/v2/bard" + "github.com/paketo-buildpacks/libpak/v2/log" ) func testBuild(t *testing.T, context spec.G, it spec.S) { @@ -132,7 +132,7 @@ version = "test-version"`), libcnb.WithExitHandler(exitHandler), ) - Expect(exitHandler.Calls[0].Arguments.Get(0)).To(MatchError(bard.IdentifiableError{ + Expect(exitHandler.Calls[0].Arguments.Get(0)).To(MatchError(log.IdentifiableError{ Name: "test-name", Description: "test-version", Err: fmt.Errorf("test-error"), diff --git a/buildmodule.go b/buildmodule.go index 03cc725..f1956f6 100644 --- a/buildmodule.go +++ b/buildmodule.go @@ -28,7 +28,7 @@ import ( "github.com/Masterminds/semver/v3" "github.com/heroku/color" - "github.com/paketo-buildpacks/libpak/v2/bard" + "github.com/paketo-buildpacks/libpak/v2/log" "github.com/paketo-buildpacks/libpak/v2/sbom" ) @@ -321,7 +321,7 @@ func (c configurationEntry) String(nameLength int, valueLength int) string { // NewConfigurationResolver creates a new instance from buildmodule metadata. Logs configuration options to the body // level int the form 'Set $Name to configure $Description[. Default $Default.]'. -func NewConfigurationResolver(md BuildModuleMetadata, logger *bard.Logger) (ConfigurationResolver, error) { +func NewConfigurationResolver(md BuildModuleMetadata, logger *log.Logger) (ConfigurationResolver, error) { cr := ConfigurationResolver{Configurations: md.Configurations} @@ -435,7 +435,7 @@ type DependencyResolver struct { StackID string // Logger is the logger used to write to the console. - Logger *bard.Logger + Logger *log.Logger } // NewDependencyResolver creates a new instance from the build module metadata and stack id. diff --git a/buildmodule_test.go b/buildmodule_test.go index a9a9a84..74defb8 100644 --- a/buildmodule_test.go +++ b/buildmodule_test.go @@ -29,8 +29,8 @@ import ( "github.com/sclevine/spec" "github.com/paketo-buildpacks/libpak/v2" - "github.com/paketo-buildpacks/libpak/v2/bard" "github.com/paketo-buildpacks/libpak/v2/internal" + "github.com/paketo-buildpacks/libpak/v2/log" "github.com/paketo-buildpacks/libpak/v2/sbom" ) @@ -601,7 +601,7 @@ func testBuildpack(t *testing.T, context spec.G, it spec.S) { it("prints outdated dependencies", func() { buff := bytes.NewBuffer(nil) - logger := bard.NewLogger(buff) + logger := log.NewLogger(buff) resolver.Logger = &logger soonDeprecated := time.Now().UTC().Add(30 * 24 * time.Hour) notSoSoonDeprecated := time.Now().UTC().Add(60 * 24 * time.Hour) diff --git a/carton/build_image_dependency.go b/carton/build_image_dependency.go index 3611f92..20d14e9 100644 --- a/carton/build_image_dependency.go +++ b/carton/build_image_dependency.go @@ -21,8 +21,8 @@ import ( "os" "regexp" - "github.com/paketo-buildpacks/libpak/v2/bard" "github.com/paketo-buildpacks/libpak/v2/internal" + "github.com/paketo-buildpacks/libpak/v2/log" ) const ( @@ -44,8 +44,8 @@ func (i BuildImageDependency) Update(options ...Option) { config = option(config) } - logger := bard.NewLogger(os.Stdout) - _, _ = fmt.Fprintf(logger.TitleWriter(), "\n%s\n", bard.FormatIdentity("Build Image", i.Version)) + logger := log.NewLogger(os.Stdout) + _, _ = fmt.Fprintf(logger.TitleWriter(), "\n%s\n", log.FormatIdentity("Build Image", i.Version)) c, err := os.ReadFile(i.BuilderPath) if err != nil { diff --git a/carton/buildmodule_dependency.go b/carton/buildmodule_dependency.go index bfbd24f..f684615 100644 --- a/carton/buildmodule_dependency.go +++ b/carton/buildmodule_dependency.go @@ -23,8 +23,8 @@ import ( "regexp" "github.com/BurntSushi/toml" - "github.com/paketo-buildpacks/libpak/v2/bard" "github.com/paketo-buildpacks/libpak/v2/internal" + "github.com/paketo-buildpacks/libpak/v2/log" ) const ( @@ -54,8 +54,8 @@ func (b BuildModuleDependency) Update(options ...Option) { config = option(config) } - logger := bard.NewLogger(os.Stdout) - _, _ = fmt.Fprintf(logger.TitleWriter(), "\n%s\n", bard.FormatIdentity(b.ID, b.VersionPattern)) + logger := log.NewLogger(os.Stdout) + _, _ = fmt.Fprintf(logger.TitleWriter(), "\n%s\n", log.FormatIdentity(b.ID, b.VersionPattern)) logger.Headerf("Version: %s", b.Version) logger.Headerf("PURL: %s", b.PURL) logger.Headerf("CPEs: %s", b.CPE) diff --git a/carton/lifecycle_dependency.go b/carton/lifecycle_dependency.go index 54b503e..d8a0ea1 100644 --- a/carton/lifecycle_dependency.go +++ b/carton/lifecycle_dependency.go @@ -21,8 +21,8 @@ import ( "os" "regexp" - "github.com/paketo-buildpacks/libpak/v2/bard" "github.com/paketo-buildpacks/libpak/v2/internal" + "github.com/paketo-buildpacks/libpak/v2/log" ) const ( @@ -44,8 +44,8 @@ func (l LifecycleDependency) Update(options ...Option) { config = option(config) } - logger := bard.NewLogger(os.Stdout) - _, _ = fmt.Fprintf(logger.TitleWriter(), "\n%s\n", bard.FormatIdentity("Lifecycle", l.Version)) + logger := log.NewLogger(os.Stdout) + _, _ = fmt.Fprintf(logger.TitleWriter(), "\n%s\n", log.FormatIdentity("Lifecycle", l.Version)) c, err := os.ReadFile(l.BuilderPath) if err != nil { diff --git a/carton/package.go b/carton/package.go index 2f96c25..dd7b6ec 100644 --- a/carton/package.go +++ b/carton/package.go @@ -29,9 +29,9 @@ import ( "github.com/heroku/color" "github.com/paketo-buildpacks/libpak/v2" - "github.com/paketo-buildpacks/libpak/v2/bard" "github.com/paketo-buildpacks/libpak/v2/effect" "github.com/paketo-buildpacks/libpak/v2/internal" + "github.com/paketo-buildpacks/libpak/v2/log" ) // Package is an object that contains the configuration for building a package. @@ -76,7 +76,7 @@ func (p Package) Create(options ...Option) { file string ) - logger := bard.NewLogger(os.Stdout) + logger := log.NewLogger(os.Stdout) // Is this a buildpack or an extension? bpfile := filepath.Join(p.Source, "buildpack.toml") diff --git a/carton/package_dependency.go b/carton/package_dependency.go index f1ac3e3..77aca20 100644 --- a/carton/package_dependency.go +++ b/carton/package_dependency.go @@ -23,8 +23,8 @@ import ( "strings" "github.com/BurntSushi/toml" - "github.com/paketo-buildpacks/libpak/v2/bard" "github.com/paketo-buildpacks/libpak/v2/internal" + "github.com/paketo-buildpacks/libpak/v2/log" ) type PackageDependency struct { @@ -44,8 +44,8 @@ func (p PackageDependency) Update(options ...Option) { config = option(config) } - logger := bard.NewLogger(os.Stdout) - _, _ = fmt.Fprintf(logger.TitleWriter(), "\n%s\n", bard.FormatIdentity(p.ID, p.Version)) + logger := log.NewLogger(os.Stdout) + _, _ = fmt.Fprintf(logger.TitleWriter(), "\n%s\n", log.FormatIdentity(p.ID, p.Version)) if p.BuilderPath != "" { if err := updateFile(p.BuilderPath, updateByKey("buildpacks", p.ID, p.Version)); err != nil { diff --git a/dependency_cache.go b/dependency_cache.go index c4898e5..bbdb38b 100644 --- a/dependency_cache.go +++ b/dependency_cache.go @@ -34,7 +34,7 @@ import ( "github.com/buildpacks/libcnb/v2" "github.com/heroku/color" - "github.com/paketo-buildpacks/libpak/v2/bard" + "github.com/paketo-buildpacks/libpak/v2/log" "github.com/paketo-buildpacks/libpak/v2/sherpa" ) @@ -57,7 +57,7 @@ type DependencyCache struct { DownloadPath string // Logger is the logger used to write to the console. - Logger bard.Logger + Logger log.Logger // UserAgent is the User-Agent string to use with requests. UserAgent string diff --git a/detect.go b/detect.go index a1391ca..9d29fb6 100644 --- a/detect.go +++ b/detect.go @@ -19,8 +19,8 @@ package libpak import ( "github.com/buildpacks/libcnb/v2" - "github.com/paketo-buildpacks/libpak/v2/bard" "github.com/paketo-buildpacks/libpak/v2/internal" + "github.com/paketo-buildpacks/libpak/v2/log" ) // Detect is called by the main function of a buildpack, for detection. @@ -39,7 +39,7 @@ type detectDelegate struct { func (d detectDelegate) Detect(context libcnb.DetectContext) (libcnb.DetectResult, error) { result, err := d.delegate(context) if err != nil { - err = bard.IdentifiableError{ + err = log.IdentifiableError{ Name: context.Buildpack.Info.Name, Description: context.Buildpack.Info.Version, Err: err, diff --git a/detect_test.go b/detect_test.go index f846df0..4f23925 100644 --- a/detect_test.go +++ b/detect_test.go @@ -29,7 +29,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/paketo-buildpacks/libpak/v2" - "github.com/paketo-buildpacks/libpak/v2/bard" + "github.com/paketo-buildpacks/libpak/v2/log" ) func testDetect(t *testing.T, context spec.G, it spec.S) { @@ -131,7 +131,7 @@ version = "test-version"`), libcnb.WithExitHandler(exitHandler), ) - Expect(exitHandler.Calls[0].Arguments.Get(0)).To(MatchError(bard.IdentifiableError{ + Expect(exitHandler.Calls[0].Arguments.Get(0)).To(MatchError(log.IdentifiableError{ Name: "test-name", Description: "test-version", Err: fmt.Errorf("test-error"), diff --git a/generate.go b/generate.go index e531718..1fce952 100644 --- a/generate.go +++ b/generate.go @@ -19,8 +19,8 @@ package libpak import ( "github.com/buildpacks/libcnb/v2" - "github.com/paketo-buildpacks/libpak/v2/bard" "github.com/paketo-buildpacks/libpak/v2/internal" + "github.com/paketo-buildpacks/libpak/v2/log" ) // Generate is called by the main function of an extension, for generation. @@ -40,7 +40,7 @@ type generateDelegate struct { func (b generateDelegate) Generate(context libcnb.GenerateContext) (libcnb.GenerateResult, error) { result, err := b.delegate(context) if err != nil { - err = bard.IdentifiableError{ + err = log.IdentifiableError{ Name: context.Extension.Info.Name, Description: context.Extension.Info.Version, Err: err, diff --git a/generate_test.go b/generate_test.go index ee47f35..c201e80 100644 --- a/generate_test.go +++ b/generate_test.go @@ -29,7 +29,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/paketo-buildpacks/libpak/v2" - "github.com/paketo-buildpacks/libpak/v2/bard" + "github.com/paketo-buildpacks/libpak/v2/log" ) func testGenerate(t *testing.T, context spec.G, it spec.S) { @@ -128,7 +128,7 @@ version = "test-version"`), libcnb.WithExitHandler(exitHandler), ) - Expect(exitHandler.Calls[0].Arguments.Get(0)).To(MatchError(bard.IdentifiableError{ + Expect(exitHandler.Calls[0].Arguments.Get(0)).To(MatchError(log.IdentifiableError{ Name: "test-name", Description: "test-version", Err: fmt.Errorf("test-error"), diff --git a/internal/environment_writer.go b/internal/environment_writer.go index f2470d5..0c7f7d3 100644 --- a/internal/environment_writer.go +++ b/internal/environment_writer.go @@ -22,29 +22,29 @@ import ( "path/filepath" "sort" - "github.com/paketo-buildpacks/libpak/v2/bard" + "github.com/paketo-buildpacks/libpak/v2/log" ) // EnvironmentWriter is an implementation of the libcnb.EnvironmentWriter interface. type EnvironmentWriter struct { - logger bard.Logger + logger log.Logger } // EnvironmentWriterOption is a function for configuring a EnvironmentWriter instance. type EnvironmentWriterOption func(writer EnvironmentWriter) EnvironmentWriter // WithEnvironmentWriterLogger creates an EnvironmentWriterOption that configures the logger. -func WithEnvironmentWriterLogger(logger bard.Logger) EnvironmentWriterOption { +func WithEnvironmentWriterLogger(logger log.Logger) EnvironmentWriterOption { return func(writer EnvironmentWriter) EnvironmentWriter { writer.logger = logger return writer } } -// NewEnvironmentWriter creates a new instance that writes to the filesystem and writes to the default bard.Logger. +// NewEnvironmentWriter creates a new instance that writes to the filesystem and writes to the default log.Logger. func NewEnvironmentWriter(options ...EnvironmentWriterOption) EnvironmentWriter { w := EnvironmentWriter{ - logger: bard.NewLogger(os.Stdout), + logger: log.NewLogger(os.Stdout), } for _, option := range options { diff --git a/internal/environment_writer_test.go b/internal/environment_writer_test.go index 973e179..376354d 100644 --- a/internal/environment_writer_test.go +++ b/internal/environment_writer_test.go @@ -25,8 +25,8 @@ import ( . "github.com/onsi/gomega" "github.com/sclevine/spec" - "github.com/paketo-buildpacks/libpak/v2/bard" "github.com/paketo-buildpacks/libpak/v2/internal" + "github.com/paketo-buildpacks/libpak/v2/log" ) func testEnvironmentWriter(t *testing.T, context spec.G, it spec.S) { @@ -85,7 +85,7 @@ func testEnvironmentWriter(t *testing.T, context spec.G, it spec.S) { it.Before(func() { b = bytes.NewBuffer(nil) - writer = internal.NewEnvironmentWriter(internal.WithEnvironmentWriterLogger(bard.NewLogger(b))) + writer = internal.NewEnvironmentWriter(internal.WithEnvironmentWriterLogger(log.NewLogger(b))) }) it("logs environment", func() { diff --git a/internal/exit_handler.go b/internal/exit_handler.go index 13ac366..c6fa401 100644 --- a/internal/exit_handler.go +++ b/internal/exit_handler.go @@ -21,7 +21,7 @@ import ( "io" "os" - "github.com/paketo-buildpacks/libpak/v2/bard" + "github.com/paketo-buildpacks/libpak/v2/log" ) const ( @@ -38,7 +38,7 @@ const ( // ExitHandler is an implementation of the libcnb.ExitHandler interface. type ExitHandler struct { exitFunc func(int) - logger bard.Logger + logger log.Logger writer io.Writer } @@ -54,7 +54,7 @@ func WithExitHandlerExitFunc(exitFunc func(int)) ExitHandlerOption { } // WithExitHandlerLogger creates an ExitHandlerOption that configures the logger. -func WithExitHandlerLogger(logger bard.Logger) ExitHandlerOption { +func WithExitHandlerLogger(logger log.Logger) ExitHandlerOption { return func(handler ExitHandler) ExitHandler { handler.logger = logger return handler @@ -69,11 +69,11 @@ func WithExitHandlerWriter(writer io.Writer) ExitHandlerOption { } } -// NewExitHandler creates a new instance that calls os.Exit and writes to the default bard.Logger and os.stderr. +// NewExitHandler creates a new instance that calls os.Exit and writes to the default log.Logger and os.stderr. func NewExitHandler(options ...ExitHandlerOption) ExitHandler { h := ExitHandler{ exitFunc: os.Exit, - logger: bard.NewLogger(os.Stdout), + logger: log.NewLogger(os.Stdout), writer: os.Stderr, } @@ -85,7 +85,7 @@ func NewExitHandler(options ...ExitHandlerOption) ExitHandler { } func (e ExitHandler) Error(err error) { - if i, ok := err.(bard.IdentifiableError); ok { + if i, ok := err.(log.IdentifiableError); ok { e.logger.TerminalError(i) } else { _, _ = fmt.Fprintln(e.writer, err) diff --git a/internal/exit_handler_test.go b/internal/exit_handler_test.go index 10058d5..0994884 100644 --- a/internal/exit_handler_test.go +++ b/internal/exit_handler_test.go @@ -25,8 +25,8 @@ import ( . "github.com/onsi/gomega" "github.com/sclevine/spec" - "github.com/paketo-buildpacks/libpak/v2/bard" "github.com/paketo-buildpacks/libpak/v2/internal" + "github.com/paketo-buildpacks/libpak/v2/log" ) func testExitHandler(t *testing.T, context spec.G, it spec.S) { @@ -43,7 +43,7 @@ func testExitHandler(t *testing.T, context spec.G, it spec.S) { handler = internal.NewExitHandler( internal.WithExitHandlerExitFunc(func(c int) { exitCode = c }), - internal.WithExitHandlerLogger(bard.NewLogger(b)), + internal.WithExitHandlerLogger(log.NewLogger(b)), internal.WithExitHandlerWriter(b), ) }) @@ -69,7 +69,7 @@ func testExitHandler(t *testing.T, context spec.G, it spec.S) { }) it("writes terminal error", func() { - handler.Error(bard.IdentifiableError{Name: "test-name", Description: "test-description", Err: fmt.Errorf("test-error")}) + handler.Error(log.IdentifiableError{Name: "test-name", Description: "test-description", Err: fmt.Errorf("test-error")}) Expect(b).To(ContainSubstring("\x1b[31m\x1b[0m\n\x1b[31m\x1b[1mtest-name\x1b[0m\x1b[31m test-description\x1b[0m\n\x1b[31;1m test-error\x1b[0m\n")) }) } diff --git a/internal/toml_writer.go b/internal/toml_writer.go index 354dfde..83ec83a 100644 --- a/internal/toml_writer.go +++ b/internal/toml_writer.go @@ -26,30 +26,29 @@ import ( "github.com/BurntSushi/toml" "github.com/buildpacks/libcnb/v2" "github.com/heroku/color" - - "github.com/paketo-buildpacks/libpak/v2/bard" + "github.com/paketo-buildpacks/libpak/v2/log" ) // TOMLWriter is an implementation of the libcnb.TOMLWriter interface. type TOMLWriter struct { - logger bard.Logger + logger log.Logger } // TOMLWriterOption is a function for configuring a TOMLWriter instance. type TOMLWriterOption func(writer TOMLWriter) TOMLWriter // WithTOMLWriterLogger creates an TOMLWriterOption that configures the logger. -func WithTOMLWriterLogger(logger bard.Logger) TOMLWriterOption { +func WithTOMLWriterLogger(logger log.Logger) TOMLWriterOption { return func(writer TOMLWriter) TOMLWriter { writer.logger = logger return writer } } -// NewTOMLWriter creates a new instance that writes to the filesystem and writes to the default bard.Logger. +// NewTOMLWriter creates a new instance that writes to the filesystem and writes to the default log.Logger. func NewTOMLWriter(options ...TOMLWriterOption) TOMLWriter { w := TOMLWriter{ - logger: bard.NewLogger(os.Stdout), + logger: log.NewLogger(os.Stdout), } for _, option := range options { diff --git a/internal/toml_writer_test.go b/internal/toml_writer_test.go index 570c976..c6b17cb 100644 --- a/internal/toml_writer_test.go +++ b/internal/toml_writer_test.go @@ -28,8 +28,8 @@ import ( . "github.com/onsi/gomega" "github.com/sclevine/spec" - "github.com/paketo-buildpacks/libpak/v2/bard" "github.com/paketo-buildpacks/libpak/v2/internal" + "github.com/paketo-buildpacks/libpak/v2/log" ) func testTOMLWriter(t *testing.T, context spec.G, it spec.S) { @@ -65,7 +65,7 @@ other-field = "other-value"`)) it.Before(func() { b = bytes.NewBuffer(nil) - tomlWriter = internal.NewTOMLWriter(internal.WithTOMLWriterLogger(bard.NewLogger(b))) + tomlWriter = internal.NewTOMLWriter(internal.WithTOMLWriterLogger(log.NewLogger(b))) }) it("does not log for uninteresting types", func() { diff --git a/layer.go b/layer.go index bcea074..b0f27ff 100644 --- a/layer.go +++ b/layer.go @@ -29,10 +29,9 @@ import ( "github.com/buildpacks/libcnb/v2" "github.com/paketo-buildpacks/libpak/v2/internal" + "github.com/paketo-buildpacks/libpak/v2/log" "github.com/paketo-buildpacks/libpak/v2/sbom" "github.com/paketo-buildpacks/libpak/v2/sherpa" - - "github.com/paketo-buildpacks/libpak/v2/bard" ) // ContributableBuildFunc is a standard libcnb.BuildFunc implementation that delegates to a list of Contributables @@ -74,7 +73,7 @@ type LayerContributor struct { ExpectedMetadata interface{} // Logger is the logger to use. - Logger bard.Logger + Logger log.Logger // Name is the user readable name of the contribution. Name string @@ -84,7 +83,7 @@ type LayerContributor struct { } // NewLayerContributor creates a new instance. -func NewLayerContributor(name string, expectedMetadata interface{}, expectedTypes libcnb.LayerTypes, logger bard.Logger) LayerContributor { +func NewLayerContributor(name string, expectedMetadata interface{}, expectedTypes libcnb.LayerTypes, logger log.Logger) LayerContributor { return LayerContributor{ ExpectedMetadata: expectedMetadata, ExpectedTypes: expectedTypes, @@ -207,7 +206,7 @@ type DependencyLayerContributor struct { ExpectedMetadata interface{} // Logger is the logger to use. - Logger bard.Logger + Logger log.Logger // RequestModifierFuncs is an optional Request Modifier to use when downloading the dependency. RequestModifierFuncs []RequestModifierFunc @@ -275,7 +274,7 @@ type HelperLayerContributor struct { BuildpackInfo libcnb.BuildpackInfo // Logger is the logger to use. - Logger bard.Logger + Logger log.Logger // Names are the names of the helpers to create Names []string diff --git a/layer_test.go b/layer_test.go index 6561b07..c5a5cc0 100644 --- a/layer_test.go +++ b/layer_test.go @@ -31,7 +31,7 @@ import ( "github.com/sclevine/spec" "github.com/paketo-buildpacks/libpak/v2" - "github.com/paketo-buildpacks/libpak/v2/bard" + "github.com/paketo-buildpacks/libpak/v2/log" ) func testLayer(t *testing.T, context spec.G, it spec.S) { @@ -62,7 +62,7 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { ) it.Before(func() { - lc.Logger = bard.NewLogger(bytes.NewBuffer(nil)) + lc.Logger = log.NewLogger(bytes.NewBuffer(nil)) lc.ExpectedMetadata = map[string]interface{}{ "alpha": "test-alpha", "bravo": map[string]interface{}{ @@ -318,7 +318,7 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { layer.Metadata = map[string]interface{}{} - dlc.Logger = bard.NewLogger(bytes.NewBuffer(nil)) + dlc.Logger = log.NewLogger(bytes.NewBuffer(nil)) dlc.ExpectedMetadata = dependency dlc.Dependency = dependency dlc.DependencyCache.CachePath = layer.Path @@ -538,7 +538,7 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { hlc = libpak.HelperLayerContributor{ Path: file, BuildpackInfo: buildpack.Info, - Logger: bard.NewLogger(bytes.NewBuffer(nil)), + Logger: log.NewLogger(bytes.NewBuffer(nil)), Names: []string{"test-name-1", "test-name-2"}, } }) diff --git a/bard/formatter.go b/log/formatter.go similarity index 98% rename from bard/formatter.go rename to log/formatter.go index d010829..1d7abf7 100644 --- a/bard/formatter.go +++ b/log/formatter.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package bard +package log import ( "fmt" diff --git a/bard/formatter_test.go b/log/formatter_test.go similarity index 86% rename from bard/formatter_test.go rename to log/formatter_test.go index f0c5ffd..ace344b 100644 --- a/bard/formatter_test.go +++ b/log/formatter_test.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package bard_test +package log_test import ( "fmt" @@ -22,9 +22,8 @@ import ( "github.com/heroku/color" . "github.com/onsi/gomega" + "github.com/paketo-buildpacks/libpak/v2/log" "github.com/sclevine/spec" - - "github.com/paketo-buildpacks/libpak/v2/bard" ) func testFormatter(t *testing.T, context spec.G, it spec.S) { @@ -35,12 +34,12 @@ func testFormatter(t *testing.T, context spec.G, it spec.S) { context("FormatIdentity", func() { it("it formats name", func() { - Expect(bard.FormatIdentity("test-name", "")). + Expect(log.FormatIdentity("test-name", "")). To(Equal(color.New(color.Bold).Sprint("test-name"))) }) it("formats name and description", func() { - Expect(bard.FormatIdentity("test-name", "test-description")). + Expect(log.FormatIdentity("test-name", "test-description")). To(Equal(fmt.Sprintf("%s test-description", color.New(color.Bold).Sprint("test-name")))) }) }) diff --git a/bard/init_test.go b/log/init_test.go similarity index 91% rename from bard/init_test.go rename to log/init_test.go index cffb67d..5218e05 100644 --- a/bard/init_test.go +++ b/log/init_test.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package bard_test +package log_test import ( "testing" @@ -24,7 +24,7 @@ import ( ) func TestUnit(t *testing.T) { - suite := spec.New("libpak/bard", spec.Report(report.Terminal{})) + suite := spec.New("libpak/log", spec.Report(report.Terminal{})) suite("Logger", testLogger) suite("Formatter", testFormatter) suite("Writer", testWriter) diff --git a/bard/logger.go b/log/logger.go similarity index 99% rename from bard/logger.go rename to log/logger.go index fa35bd4..a8e5407 100644 --- a/bard/logger.go +++ b/log/logger.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package bard +package log import ( "fmt" diff --git a/bard/logger_test.go b/log/logger_test.go similarity index 93% rename from bard/logger_test.go rename to log/logger_test.go index 9fc763d..005ec10 100644 --- a/bard/logger_test.go +++ b/log/logger_test.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package bard_test +package log_test import ( "bytes" @@ -23,9 +23,8 @@ import ( "testing" . "github.com/onsi/gomega" + "github.com/paketo-buildpacks/libpak/v2/log" "github.com/sclevine/spec" - - "github.com/paketo-buildpacks/libpak/v2/bard" ) func testLogger(t *testing.T, context spec.G, it spec.S) { @@ -33,7 +32,7 @@ func testLogger(t *testing.T, context spec.G, it spec.S) { Expect = NewWithT(t).Expect b *bytes.Buffer - l bard.Logger + l log.Logger ) it.Before(func() { @@ -42,7 +41,7 @@ func testLogger(t *testing.T, context spec.G, it spec.S) { context("without BP_DEBUG", func() { it.Before(func() { - l = bard.NewLogger(b) + l = log.NewLogger(b) }) it("does not configure debug", func() { @@ -55,7 +54,7 @@ func testLogger(t *testing.T, context spec.G, it spec.S) { //libcnb defines BP_DEBUG as enabled if it has _any_ value //this does not include empty string as previously tested here. Expect(os.Setenv("BP_DEBUG", "true")).To(Succeed()) - l = bard.NewLogger(b) + l = log.NewLogger(b) }) it.After(func() { @@ -70,7 +69,7 @@ func testLogger(t *testing.T, context spec.G, it spec.S) { context("with BP_LOG_LEVEL set to DEBUG", func() { it.Before(func() { Expect(os.Setenv("BP_LOG_LEVEL", "DEBUG")).To(Succeed()) - l = bard.NewLogger(b) + l = log.NewLogger(b) }) it.After(func() { @@ -85,7 +84,7 @@ func testLogger(t *testing.T, context spec.G, it spec.S) { context("with debug disabled", func() { it.Before(func() { Expect(os.Unsetenv("BP_LOG_LEVEL")).To(Succeed()) - l = bard.NewLoggerWithOptions(b) + l = log.NewLoggerWithOptions(b) }) it("does not write debug log", func() { @@ -106,7 +105,7 @@ func testLogger(t *testing.T, context spec.G, it spec.S) { context("with debug enabled", func() { it.Before(func() { Expect(os.Setenv("BP_LOG_LEVEL", "debug")).To(Succeed()) - l = bard.NewLogger(b) + l = log.NewLogger(b) }) it.After(func() { Expect(os.Unsetenv("BP_LOG_LEVEL")).To(Succeed()) @@ -163,7 +162,7 @@ func testLogger(t *testing.T, context spec.G, it spec.S) { }) it("writes terminal error", func() { - l.TerminalError(bard.IdentifiableError{Name: "test-name", Description: "test-description", Err: fmt.Errorf("test-error")}) + l.TerminalError(log.IdentifiableError{Name: "test-name", Description: "test-description", Err: fmt.Errorf("test-error")}) Expect(b.String()).To(Equal("\x1b[31m\x1b[0m\n\x1b[31m\x1b[1mtest-name\x1b[0m\x1b[31m test-description\x1b[0m\n\x1b[31;1m test-error\x1b[0m\n")) }) diff --git a/bard/writer.go b/log/writer.go similarity index 99% rename from bard/writer.go rename to log/writer.go index 61f2600..c1df30b 100644 --- a/bard/writer.go +++ b/log/writer.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package bard +package log import ( "bytes" diff --git a/bard/writer_test.go b/log/writer_test.go similarity index 86% rename from bard/writer_test.go rename to log/writer_test.go index 7b8fda5..92b1cbf 100644 --- a/bard/writer_test.go +++ b/log/writer_test.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package bard_test +package log_test import ( "bytes" @@ -22,9 +22,8 @@ import ( "github.com/heroku/color" . "github.com/onsi/gomega" + "github.com/paketo-buildpacks/libpak/v2/log" "github.com/sclevine/spec" - - "github.com/paketo-buildpacks/libpak/v2/bard" ) func testWriter(t *testing.T, context spec.G, it spec.S) { @@ -35,12 +34,12 @@ func testWriter(t *testing.T, context spec.G, it spec.S) { context("Writer", func() { var ( buffer *bytes.Buffer - writer *bard.Writer + writer *log.Writer ) it.Before(func() { buffer = bytes.NewBuffer(nil) - writer = bard.NewWriter(buffer) + writer = log.NewWriter(buffer) }) context("Write", func() { @@ -52,7 +51,7 @@ func testWriter(t *testing.T, context spec.G, it spec.S) { context("when the writer has a color", func() { it.Before(func() { - writer = bard.NewWriter(buffer, bard.WithAttributes(color.FgBlue)) + writer = log.NewWriter(buffer, log.WithAttributes(color.FgBlue)) }) it("prints to the writer with the correct color codes", func() { @@ -64,7 +63,7 @@ func testWriter(t *testing.T, context spec.G, it spec.S) { context("when the writer has an indent", func() { it.Before(func() { - writer = bard.NewWriter(buffer, bard.WithIndent(2)) + writer = log.NewWriter(buffer, log.WithIndent(2)) }) it("prints to the writer with the correct indentation", func() { @@ -76,7 +75,7 @@ func testWriter(t *testing.T, context spec.G, it spec.S) { context("when the writer has a return prefix", func() { it.Before(func() { - writer = bard.NewWriter(buffer, bard.WithAttributes(color.FgRed), bard.WithIndent(2)) + writer = log.NewWriter(buffer, log.WithAttributes(color.FgRed), log.WithIndent(2)) }) it("prints to the writer with the correct indentation", func() { @@ -88,7 +87,7 @@ func testWriter(t *testing.T, context spec.G, it spec.S) { context("when the writer has a newline suffix", func() { it.Before(func() { - writer = bard.NewWriter(buffer, bard.WithAttributes(color.FgRed), bard.WithIndent(2)) + writer = log.NewWriter(buffer, log.WithAttributes(color.FgRed), log.WithIndent(2)) }) it("prints to the writer with the correct indentation", func() { @@ -100,7 +99,7 @@ func testWriter(t *testing.T, context spec.G, it spec.S) { context("when there is multiple input", func() { it.Before(func() { - writer = bard.NewWriter(buffer, bard.WithIndent(2)) + writer = log.NewWriter(buffer, log.WithIndent(2)) }) it("skips indentation if there was not a line break", func() { @@ -126,7 +125,7 @@ func testWriter(t *testing.T, context spec.G, it spec.S) { context("when the input has a percent symbol", func() { it.Before(func() { - writer = bard.NewWriter(buffer, bard.WithAttributes(color.FgMagenta)) + writer = log.NewWriter(buffer, log.WithAttributes(color.FgMagenta)) }) it("prints to the writer with the correct indentation", func() { diff --git a/sbom/sbom.go b/sbom/sbom.go index fb90d35..b42b734 100644 --- a/sbom/sbom.go +++ b/sbom/sbom.go @@ -7,8 +7,8 @@ import ( "github.com/buildpacks/libcnb/v2" "github.com/mitchellh/hashstructure/v2" - "github.com/paketo-buildpacks/libpak/v2/bard" "github.com/paketo-buildpacks/libpak/v2/effect" + "github.com/paketo-buildpacks/libpak/v2/log" ) //go:generate mockery --name SBOMScanner --case=underscore @@ -105,10 +105,10 @@ type SyftSchema struct { type SyftCLISBOMScanner struct { Executor effect.Executor Layers libcnb.Layers - Logger bard.Logger + Logger log.Logger } -func NewSyftCLISBOMScanner(layers libcnb.Layers, executor effect.Executor, logger bard.Logger) SyftCLISBOMScanner { +func NewSyftCLISBOMScanner(layers libcnb.Layers, executor effect.Executor, logger log.Logger) SyftCLISBOMScanner { return SyftCLISBOMScanner{ Executor: executor, Layers: layers, diff --git a/sbom/sbom_test.go b/sbom/sbom_test.go index 1dcaed4..f83996d 100644 --- a/sbom/sbom_test.go +++ b/sbom/sbom_test.go @@ -9,9 +9,9 @@ import ( "github.com/buildpacks/libcnb/v2" . "github.com/onsi/gomega" - "github.com/paketo-buildpacks/libpak/v2/bard" "github.com/paketo-buildpacks/libpak/v2/effect" "github.com/paketo-buildpacks/libpak/v2/effect/mocks" + "github.com/paketo-buildpacks/libpak/v2/log" "github.com/paketo-buildpacks/libpak/v2/sbom" "github.com/sclevine/spec" "github.com/stretchr/testify/mock" @@ -62,7 +62,7 @@ func testSBOM(t *testing.T, context spec.G, it spec.S) { }).Return(nil) // uses interface here intentionally, to force that inteface and implementation match - scanner = sbom.NewSyftCLISBOMScanner(layers, &executor, bard.NewLogger(io.Discard)) + scanner = sbom.NewSyftCLISBOMScanner(layers, &executor, log.NewLogger(io.Discard)) Expect(scanner.ScanBuild("something", format)).To(Succeed()) @@ -105,7 +105,7 @@ func testSBOM(t *testing.T, context spec.G, it spec.S) { }).Return(nil) // uses interface here intentionally, to force that inteface and implementation match - scanner = sbom.NewSyftCLISBOMScanner(layers, &executor, bard.NewLogger(io.Discard)) + scanner = sbom.NewSyftCLISBOMScanner(layers, &executor, log.NewLogger(io.Discard)) Expect(scanner.ScanBuild("something", format)).To(Succeed()) @@ -133,7 +133,7 @@ func testSBOM(t *testing.T, context spec.G, it spec.S) { scanner := sbom.SyftCLISBOMScanner{ Executor: &executor, Layers: layers, - Logger: bard.NewLogger(io.Discard), + Logger: log.NewLogger(io.Discard), } Expect(scanner.ScanLayer(layer, "something", format)).To(Succeed()) @@ -160,7 +160,7 @@ func testSBOM(t *testing.T, context spec.G, it spec.S) { scanner := sbom.SyftCLISBOMScanner{ Executor: &executor, Layers: layers, - Logger: bard.NewLogger(io.Discard), + Logger: log.NewLogger(io.Discard), } Expect(scanner.ScanLaunch("something", libcnb.CycloneDXJSON, libcnb.SyftJSON, libcnb.SPDXJSON)).To(Succeed()) From e63c58ff050a40ed88df730111abb922d93d66d7 Mon Sep 17 00:00:00 2001 From: Daniel Mikusa Date: Tue, 29 Aug 2023 00:16:28 -0400 Subject: [PATCH 3/6] Extend libcnb's log.Logger as Paketo's log.Logger and implement We add a new interface `log.Logger`, which has methods for all of the different log levels that we use in Paketo. It also contains an implementation of PaketoLogger which implements Logger. The implementation uses color and formatting in the way that is consistent with libpak v1. In previous versions, debug and info level logging was done at the libcnb logging level. In libcnb v2, we can now control this and the PaketoLogger sets the debug logger to have cyan colored output. In addition, there is no Info level log. You can use Body in place of Info. Other changes in this commit: - NewConfigurationResolver no longer logs the configuration. You need to manually call `ConfigurationResolver.LogConfiguration` to log the configuration. - ConfigurationResolver and DependencyResolver use the `log.Logger` which is an interface. If you have code that was depending on a default `log.Logger` struct, this will now break. With `log.Logger` being an interface, the default is nil. This may cause panics in your code. - NewDependencyCache requires a logger. Previously, it didn't which was weird because it will log stuff. In general, pass it a logger but if you do not want it to log anything pass it `log.NewDiscardLogger()` - NewDependencyLayerContributor requires a logger. Previously, it didn't which was weird because it will log stuff. In general, pass it a logger but if you do not want it to log anything pass it `log.NewDiscardLogger()` Signed-off-by: Daniel Mikusa --- buildmodule.go | 41 ++++---- buildmodule_test.go | 5 +- carton/build_image_dependency.go | 2 +- carton/buildmodule_dependency.go | 2 +- carton/lifecycle_dependency.go | 2 +- carton/package.go | 8 +- carton/package_dependency.go | 2 +- dependency_cache.go | 7 +- dependency_cache_test.go | 12 ++- internal/environment_writer.go | 2 +- internal/environment_writer_test.go | 4 +- internal/exit_handler.go | 2 +- internal/exit_handler_test.go | 2 +- internal/toml_writer.go | 2 +- internal/toml_writer_test.go | 2 +- layer.go | 6 +- layer_test.go | 7 +- log/logger.go | 141 +++++++++++++++++++++++----- log/logger_test.go | 31 ++---- sbom/sbom_test.go | 9 +- 20 files changed, 182 insertions(+), 107 deletions(-) diff --git a/buildmodule.go b/buildmodule.go index f1956f6..fc51049 100644 --- a/buildmodule.go +++ b/buildmodule.go @@ -284,7 +284,6 @@ func NewBuildModuleMetadata(metadata map[string]interface{}) (BuildModuleMetadat // ConfigurationResolver provides functionality for resolving a configuration value. type ConfigurationResolver struct { - // Configurations are the configurations to resolve against Configurations []BuildModuleConfiguration } @@ -319,16 +318,20 @@ func (c configurationEntry) String(nameLength int, valueLength int) string { return sb.String() } -// NewConfigurationResolver creates a new instance from buildmodule metadata. Logs configuration options to the body -// level int the form 'Set $Name to configure $Description[. Default $Default.]'. -func NewConfigurationResolver(md BuildModuleMetadata, logger *log.Logger) (ConfigurationResolver, error) { - +// NewConfigurationResolver creates a new instance from buildmodule metadata. +func NewConfigurationResolver(md BuildModuleMetadata) (ConfigurationResolver, error) { cr := ConfigurationResolver{Configurations: md.Configurations} - if logger == nil { - return cr, nil - } + sort.Slice(md.Configurations, func(i, j int) bool { + return md.Configurations[i].Name < md.Configurations[j].Name + }) + return cr, nil +} + +// LogConfiguration will write the configuration options to the body level in +// the form 'Set $Name to configure $Description[. Default $Default.]'. +func (c *ConfigurationResolver) LogConfiguration(logger log.Logger) { var ( build []configurationEntry launch []configurationEntry @@ -338,16 +341,12 @@ func NewConfigurationResolver(md BuildModuleMetadata, logger *log.Logger) (Confi valueLength int ) - sort.Slice(md.Configurations, func(i, j int) bool { - return md.Configurations[i].Name < md.Configurations[j].Name - }) - - for _, c := range md.Configurations { - s, _ := cr.Resolve(c.Name) + for _, config := range c.Configurations { + s, _ := c.Resolve(config.Name) e := configurationEntry{ - Name: c.Name, - Description: c.Description, + Name: config.Name, + Description: config.Description, Value: s, } @@ -359,15 +358,15 @@ func NewConfigurationResolver(md BuildModuleMetadata, logger *log.Logger) (Confi valueLength = l } - if c.Build { + if config.Build { build = append(build, e) } - if c.Launch { + if config.Launch { launch = append(launch, e) } - if !c.Build && !c.Launch { + if !config.Build && !config.Launch { unknown = append(unknown, e) } } @@ -394,8 +393,6 @@ func NewConfigurationResolver(md BuildModuleMetadata, logger *log.Logger) (Confi logger.Body(e.String(nameLength, valueLength)) } } - - return cr, nil } // Resolve resolves the value for a configuration option, returning the default value and false if it was not set. @@ -435,7 +432,7 @@ type DependencyResolver struct { StackID string // Logger is the logger used to write to the console. - Logger *log.Logger + Logger log.Logger } // NewDependencyResolver creates a new instance from the build module metadata and stack id. diff --git a/buildmodule_test.go b/buildmodule_test.go index 74defb8..2a70a9d 100644 --- a/buildmodule_test.go +++ b/buildmodule_test.go @@ -284,7 +284,6 @@ func testBuildpack(t *testing.T, context spec.G, it spec.S) { ) context("Resolve", func() { - it("filters by id", func() { resolver.Dependencies = []libpak.BuildModuleDependency{ { @@ -601,8 +600,8 @@ func testBuildpack(t *testing.T, context spec.G, it spec.S) { it("prints outdated dependencies", func() { buff := bytes.NewBuffer(nil) - logger := log.NewLogger(buff) - resolver.Logger = &logger + logger := log.NewPaketoLogger(buff) + resolver.Logger = logger soonDeprecated := time.Now().UTC().Add(30 * 24 * time.Hour) notSoSoonDeprecated := time.Now().UTC().Add(60 * 24 * time.Hour) resolver.Dependencies = []libpak.BuildModuleDependency{ diff --git a/carton/build_image_dependency.go b/carton/build_image_dependency.go index 20d14e9..af3b960 100644 --- a/carton/build_image_dependency.go +++ b/carton/build_image_dependency.go @@ -44,7 +44,7 @@ func (i BuildImageDependency) Update(options ...Option) { config = option(config) } - logger := log.NewLogger(os.Stdout) + logger := log.NewPaketoLogger(os.Stdout) _, _ = fmt.Fprintf(logger.TitleWriter(), "\n%s\n", log.FormatIdentity("Build Image", i.Version)) c, err := os.ReadFile(i.BuilderPath) diff --git a/carton/buildmodule_dependency.go b/carton/buildmodule_dependency.go index f684615..0722c9a 100644 --- a/carton/buildmodule_dependency.go +++ b/carton/buildmodule_dependency.go @@ -54,7 +54,7 @@ func (b BuildModuleDependency) Update(options ...Option) { config = option(config) } - logger := log.NewLogger(os.Stdout) + logger := log.NewPaketoLogger(os.Stdout) _, _ = fmt.Fprintf(logger.TitleWriter(), "\n%s\n", log.FormatIdentity(b.ID, b.VersionPattern)) logger.Headerf("Version: %s", b.Version) logger.Headerf("PURL: %s", b.PURL) diff --git a/carton/lifecycle_dependency.go b/carton/lifecycle_dependency.go index d8a0ea1..d4636c2 100644 --- a/carton/lifecycle_dependency.go +++ b/carton/lifecycle_dependency.go @@ -44,7 +44,7 @@ func (l LifecycleDependency) Update(options ...Option) { config = option(config) } - logger := log.NewLogger(os.Stdout) + logger := log.NewPaketoLogger(os.Stdout) _, _ = fmt.Fprintf(logger.TitleWriter(), "\n%s\n", log.FormatIdentity("Lifecycle", l.Version)) c, err := os.ReadFile(l.BuilderPath) diff --git a/carton/package.go b/carton/package.go index dd7b6ec..56d7e4f 100644 --- a/carton/package.go +++ b/carton/package.go @@ -76,7 +76,7 @@ func (p Package) Create(options ...Option) { file string ) - logger := log.NewLogger(os.Stdout) + logger := log.NewPaketoLogger(os.Stdout) // Is this a buildpack or an extension? bpfile := filepath.Join(p.Source, "buildpack.toml") @@ -103,7 +103,7 @@ func (p Package) Create(options ...Option) { name = b.Info.Name version = b.Info.Version homepage = b.Info.Homepage - logger.Debug("Buildpack: %+v", b) + logger.Debugf("Buildpack: %+v", b) } else if _, err := os.Stat(extnfile); err == nil { s, err := os.ReadFile(extnfile) if err != nil { @@ -121,7 +121,7 @@ func (p Package) Create(options ...Option) { version = e.Info.Version homepage = e.Info.Homepage extension = true - logger.Debug("Extension: %+v", e) + logger.Debugf("Extension: %+v", e) } else { config.exitHandler.Error(fmt.Errorf("unable to read buildpack/extension.toml at %s", p.Source)) return @@ -138,7 +138,7 @@ func (p Package) Create(options ...Option) { for _, i := range metadata.IncludeFiles { entries[i] = filepath.Join(p.Source, i) } - logger.Debug("Include files: %+v", entries) + logger.Debugf("Include files: %+v", entries) if p.Version != "" { version = p.Version diff --git a/carton/package_dependency.go b/carton/package_dependency.go index 77aca20..174de0c 100644 --- a/carton/package_dependency.go +++ b/carton/package_dependency.go @@ -44,7 +44,7 @@ func (p PackageDependency) Update(options ...Option) { config = option(config) } - logger := log.NewLogger(os.Stdout) + logger := log.NewPaketoLogger(os.Stdout) _, _ = fmt.Fprintf(logger.TitleWriter(), "\n%s\n", log.FormatIdentity(p.ID, p.Version)) if p.BuilderPath != "" { diff --git a/dependency_cache.go b/dependency_cache.go index bbdb38b..513367a 100644 --- a/dependency_cache.go +++ b/dependency_cache.go @@ -49,7 +49,6 @@ type HttpClientTimeouts struct { // DependencyCache allows a user to get an artifact either from a buildmodule's cache, a previous download, or to download // directly. type DependencyCache struct { - // CachePath is the location where the buildmodule has cached its dependencies. CachePath string @@ -71,12 +70,13 @@ type DependencyCache struct { // NewDependencyCache creates a new instance setting the default cache path (/dependencies) and user // agent (/). -func NewDependencyCache(buildModuleID string, buildModuleVersion string, buildModulePath string, platformBindings libcnb.Bindings) (DependencyCache, error) { +func NewDependencyCache(buildModuleID string, buildModuleVersion string, buildModulePath string, platformBindings libcnb.Bindings, logger log.Logger) (DependencyCache, error) { cache := DependencyCache{ CachePath: filepath.Join(buildModulePath, "dependencies"), DownloadPath: os.TempDir(), - UserAgent: fmt.Sprintf("%s/%s", buildModuleID, buildModuleVersion), + Logger: logger, Mappings: map[string]string{}, + UserAgent: fmt.Sprintf("%s/%s", buildModuleID, buildModuleVersion), } mappings, err := mappingsFromBindings(platformBindings) if err != nil { @@ -161,7 +161,6 @@ type RequestModifierFunc func(request *http.Request) (*http.Request, error) // If the BuildpackDependency's SHA256 is not set, the download can never be verified to be up to date and will always // download, skipping all the caches. func (d *DependencyCache) Artifact(dependency BuildModuleDependency, mods ...RequestModifierFunc) (*os.File, error) { - var ( artifact string file string diff --git a/dependency_cache_test.go b/dependency_cache_test.go index 02bc10f..697ddc0 100644 --- a/dependency_cache_test.go +++ b/dependency_cache_test.go @@ -32,6 +32,7 @@ import ( "github.com/sclevine/spec" "github.com/paketo-buildpacks/libpak/v2" + "github.com/paketo-buildpacks/libpak/v2/log" ) func testDependencyCache(t *testing.T, context spec.G, it spec.S) { @@ -55,7 +56,7 @@ func testDependencyCache(t *testing.T, context spec.G, it spec.S) { }) it("set default CachePath and UserAgent", func() { - dependencyCache, err := libpak.NewDependencyCache(ctx.Buildpack.Info.ID, ctx.Buildpack.Info.Version, ctx.Buildpack.Path, ctx.Platform.Bindings) + dependencyCache, err := libpak.NewDependencyCache(ctx.Buildpack.Info.ID, ctx.Buildpack.Info.Version, ctx.Buildpack.Path, ctx.Platform.Bindings, log.NewDiscardLogger()) Expect(err).NotTo(HaveOccurred()) Expect(dependencyCache.CachePath).To(Equal(filepath.Join("some/path/dependencies"))) Expect(dependencyCache.UserAgent).To(Equal("some-buildpack-id/some-buildpack-version")) @@ -63,7 +64,7 @@ func testDependencyCache(t *testing.T, context spec.G, it spec.S) { }) it("uses default timeout values", func() { - dependencyCache, err := libpak.NewDependencyCache(ctx.Buildpack.Info.ID, ctx.Buildpack.Info.Version, ctx.Buildpack.Path, ctx.Platform.Bindings) + dependencyCache, err := libpak.NewDependencyCache(ctx.Buildpack.Info.ID, ctx.Buildpack.Info.Version, ctx.Buildpack.Path, ctx.Platform.Bindings, log.NewDiscardLogger()) Expect(err).NotTo(HaveOccurred()) Expect(dependencyCache.HttpClientTimeouts.DialerTimeout).To(Equal(6 * time.Second)) Expect(dependencyCache.HttpClientTimeouts.DialerKeepAlive).To(Equal(60 * time.Second)) @@ -82,7 +83,7 @@ func testDependencyCache(t *testing.T, context spec.G, it spec.S) { }) it("uses custom timeout values", func() { - dependencyCache, err := libpak.NewDependencyCache(ctx.Buildpack.Info.ID, ctx.Buildpack.Info.Version, ctx.Buildpack.Path, ctx.Platform.Bindings) + dependencyCache, err := libpak.NewDependencyCache(ctx.Buildpack.Info.ID, ctx.Buildpack.Info.Version, ctx.Buildpack.Path, ctx.Platform.Bindings, log.NewDiscardLogger()) Expect(err).NotTo(HaveOccurred()) Expect(dependencyCache.HttpClientTimeouts.DialerTimeout).To(Equal(7 * time.Second)) Expect(dependencyCache.HttpClientTimeouts.DialerKeepAlive).To(Equal(50 * time.Second)) @@ -119,7 +120,7 @@ func testDependencyCache(t *testing.T, context spec.G, it spec.S) { }) it("sets Mappings", func() { - dependencyCache, err := libpak.NewDependencyCache(ctx.Buildpack.Info.ID, ctx.Buildpack.Info.Version, ctx.Buildpack.Path, ctx.Platform.Bindings) + dependencyCache, err := libpak.NewDependencyCache(ctx.Buildpack.Info.ID, ctx.Buildpack.Info.Version, ctx.Buildpack.Path, ctx.Platform.Bindings, log.NewDiscardLogger()) Expect(err).NotTo(HaveOccurred()) Expect(dependencyCache.Mappings).To(Equal( map[string]string{ @@ -142,7 +143,7 @@ func testDependencyCache(t *testing.T, context spec.G, it spec.S) { }) it("errors", func() { - _, err := libpak.NewDependencyCache(ctx.Buildpack.Info.ID, ctx.Buildpack.Info.Version, ctx.Buildpack.Path, ctx.Platform.Bindings) + _, err := libpak.NewDependencyCache(ctx.Buildpack.Info.ID, ctx.Buildpack.Info.Version, ctx.Buildpack.Path, ctx.Platform.Bindings, log.NewDiscardLogger()) Expect(err).To(HaveOccurred()) }) }) @@ -191,6 +192,7 @@ func testDependencyCache(t *testing.T, context spec.G, it spec.S) { dependencyCache = libpak.DependencyCache{ CachePath: cachePath, DownloadPath: downloadPath, + Logger: log.NewDiscardLogger(), UserAgent: "test-user-agent", } }) diff --git a/internal/environment_writer.go b/internal/environment_writer.go index 0c7f7d3..68041d6 100644 --- a/internal/environment_writer.go +++ b/internal/environment_writer.go @@ -44,7 +44,7 @@ func WithEnvironmentWriterLogger(logger log.Logger) EnvironmentWriterOption { // NewEnvironmentWriter creates a new instance that writes to the filesystem and writes to the default log.Logger. func NewEnvironmentWriter(options ...EnvironmentWriterOption) EnvironmentWriter { w := EnvironmentWriter{ - logger: log.NewLogger(os.Stdout), + logger: log.NewPaketoLogger(os.Stdout), } for _, option := range options { diff --git a/internal/environment_writer_test.go b/internal/environment_writer_test.go index 376354d..a8e406c 100644 --- a/internal/environment_writer_test.go +++ b/internal/environment_writer_test.go @@ -41,7 +41,7 @@ func testEnvironmentWriter(t *testing.T, context spec.G, it spec.S) { path = t.TempDir() Expect(os.RemoveAll(path)).To(Succeed()) - writer = internal.EnvironmentWriter{} + writer = internal.NewEnvironmentWriter() }) it("writes the given environment to a directory", func() { @@ -85,7 +85,7 @@ func testEnvironmentWriter(t *testing.T, context spec.G, it spec.S) { it.Before(func() { b = bytes.NewBuffer(nil) - writer = internal.NewEnvironmentWriter(internal.WithEnvironmentWriterLogger(log.NewLogger(b))) + writer = internal.NewEnvironmentWriter(internal.WithEnvironmentWriterLogger(log.NewPaketoLogger(b))) }) it("logs environment", func() { diff --git a/internal/exit_handler.go b/internal/exit_handler.go index c6fa401..2024098 100644 --- a/internal/exit_handler.go +++ b/internal/exit_handler.go @@ -73,7 +73,7 @@ func WithExitHandlerWriter(writer io.Writer) ExitHandlerOption { func NewExitHandler(options ...ExitHandlerOption) ExitHandler { h := ExitHandler{ exitFunc: os.Exit, - logger: log.NewLogger(os.Stdout), + logger: log.NewPaketoLogger(os.Stdout), writer: os.Stderr, } diff --git a/internal/exit_handler_test.go b/internal/exit_handler_test.go index 0994884..62e4549 100644 --- a/internal/exit_handler_test.go +++ b/internal/exit_handler_test.go @@ -43,7 +43,7 @@ func testExitHandler(t *testing.T, context spec.G, it spec.S) { handler = internal.NewExitHandler( internal.WithExitHandlerExitFunc(func(c int) { exitCode = c }), - internal.WithExitHandlerLogger(log.NewLogger(b)), + internal.WithExitHandlerLogger(log.NewPaketoLogger(b)), internal.WithExitHandlerWriter(b), ) }) diff --git a/internal/toml_writer.go b/internal/toml_writer.go index 83ec83a..083e70e 100644 --- a/internal/toml_writer.go +++ b/internal/toml_writer.go @@ -48,7 +48,7 @@ func WithTOMLWriterLogger(logger log.Logger) TOMLWriterOption { // NewTOMLWriter creates a new instance that writes to the filesystem and writes to the default log.Logger. func NewTOMLWriter(options ...TOMLWriterOption) TOMLWriter { w := TOMLWriter{ - logger: log.NewLogger(os.Stdout), + logger: log.NewPaketoLogger(os.Stdout), } for _, option := range options { diff --git a/internal/toml_writer_test.go b/internal/toml_writer_test.go index c6b17cb..9c7b134 100644 --- a/internal/toml_writer_test.go +++ b/internal/toml_writer_test.go @@ -65,7 +65,7 @@ other-field = "other-value"`)) it.Before(func() { b = bytes.NewBuffer(nil) - tomlWriter = internal.NewTOMLWriter(internal.WithTOMLWriterLogger(log.NewLogger(b))) + tomlWriter = internal.NewTOMLWriter(internal.WithTOMLWriterLogger(log.NewPaketoLogger(b))) }) it("does not log for uninteresting types", func() { diff --git a/layer.go b/layer.go index b0f27ff..7aa53c6 100644 --- a/layer.go +++ b/layer.go @@ -192,7 +192,6 @@ func (l *LayerContributor) reset(layer *libcnb.Layer) error { // DependencyLayerContributor is a helper for implementing a Contributable for a BuildpackDependency in order // to get consistent logging and avoidance. type DependencyLayerContributor struct { - // Dependency is the dependency being contributed. Dependency BuildModuleDependency @@ -213,12 +212,13 @@ type DependencyLayerContributor struct { } // NewDependencyLayerContributor returns a new DependencyLayerContributor for the given BuildpackDependency -func NewDependencyLayerContributor(dependency BuildModuleDependency, cache DependencyCache, types libcnb.LayerTypes) DependencyLayerContributor { +func NewDependencyLayerContributor(dependency BuildModuleDependency, cache DependencyCache, types libcnb.LayerTypes, logger log.Logger) DependencyLayerContributor { return DependencyLayerContributor{ Dependency: dependency, - ExpectedMetadata: dependency, DependencyCache: cache, + ExpectedMetadata: dependency, ExpectedTypes: types, + Logger: logger, } } diff --git a/layer_test.go b/layer_test.go index c5a5cc0..494f5c8 100644 --- a/layer_test.go +++ b/layer_test.go @@ -62,7 +62,7 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { ) it.Before(func() { - lc.Logger = log.NewLogger(bytes.NewBuffer(nil)) + lc.Logger = log.NewPaketoLogger(bytes.NewBuffer(nil)) lc.ExpectedMetadata = map[string]interface{}{ "alpha": "test-alpha", "bravo": map[string]interface{}{ @@ -318,11 +318,12 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { layer.Metadata = map[string]interface{}{} - dlc.Logger = log.NewLogger(bytes.NewBuffer(nil)) + dlc.Logger = log.NewDiscardLogger() dlc.ExpectedMetadata = dependency dlc.Dependency = dependency dlc.DependencyCache.CachePath = layer.Path dlc.DependencyCache.DownloadPath = layer.Path + dlc.DependencyCache.Logger = log.NewDiscardLogger() }) it.After(func() { @@ -538,7 +539,7 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { hlc = libpak.HelperLayerContributor{ Path: file, BuildpackInfo: buildpack.Info, - Logger: log.NewLogger(bytes.NewBuffer(nil)), + Logger: log.NewPaketoLogger(bytes.NewBuffer(nil)), Names: []string{"test-name-1", "test-name-2"}, } }) diff --git a/log/logger.go b/log/logger.go index a8e5407..35b08a6 100644 --- a/log/logger.go +++ b/log/logger.go @@ -19,6 +19,7 @@ package log import ( "fmt" "io" + "os" "strings" "github.com/buildpacks/libcnb/v2/log" @@ -30,10 +31,32 @@ func init() { color.Enabled() } -// Logger logs message to a writer. -type Logger struct { +type Logger interface { log.Logger + Body(a ...interface{}) + Bodyf(format string, a ...interface{}) + BodyWriter() io.Writer + IsBodyEnabled() bool + + Header(a ...interface{}) + Headerf(format string, a ...interface{}) + HeaderWriter() io.Writer + IsHeaderEnabled() bool + + TerminalError(err IdentifiableError) + TerminalErrorWriter() io.Writer + IsTerminalErrorEnabled() bool + + Title(name string, version string, homepage string) + Titlef(format string, a ...interface{}) + TitleWriter() io.Writer + IsTitleEnabled() bool +} + +// Logger logs message to a writer. +type PaketoLogger struct { + debug io.Writer body io.Writer header io.Writer terminalBody io.Writer @@ -41,18 +64,35 @@ type Logger struct { title io.Writer } -// NewLogger creates a new instance of Logger. It configures debug logging if $BP_DEBUG is set. -func NewLogger(writer io.Writer) Logger { +// NewDiscard creates a new instance of PaketoLogger that discards all log messages. Useful in testing. +func NewDiscardLogger() PaketoLogger { + return PaketoLogger{ + debug: io.Discard, + body: io.Discard, + header: io.Discard, + terminalBody: io.Discard, + terminalHeader: io.Discard, + title: io.Discard, + } +} + +// NewPaketoLogger creates a new instance of PaketoLogger. It configures debug logging if $BP_DEBUG is set. +func NewPaketoLogger(writer io.Writer) PaketoLogger { var options []Option - return NewLoggerWithOptions(writer, options...) + return NewPaketoLoggerWithOptions(writer, options...) } // Option is a function for configuring a Logger instance. -type Option func(logger Logger) Logger +type Option func(logger PaketoLogger) PaketoLogger -func NewLoggerWithOptions(writer io.Writer, options ...Option) Logger { - l := Logger{ - Logger: log.New(writer), +func NewPaketoLoggerWithOptions(writer io.Writer, options ...Option) PaketoLogger { + var debugWriter io.Writer + if strings.ToLower(os.Getenv("BP_LOG_LEVEL")) == "debug" || os.Getenv("BP_DEBUG") != "" { + debugWriter = NewWriter(writer, WithAttributes(color.BgCyan)) + } + + l := PaketoLogger{ + debug: debugWriter, body: NewWriter(writer, WithAttributes(color.Faint), WithIndent(2)), header: NewWriter(writer, WithIndent(1)), terminalBody: NewWriter(writer, WithAttributes(color.FgRed, color.Bold), WithIndent(1)), @@ -69,7 +109,7 @@ func NewLoggerWithOptions(writer io.Writer, options ...Option) Logger { // Body formats using the default formats for its operands and logs a message to the configured body writer. Spaces // are added between operands when neither is a string. -func (l Logger) Body(a ...interface{}) { +func (l PaketoLogger) Body(a ...interface{}) { if !l.IsBodyEnabled() { return } @@ -78,7 +118,7 @@ func (l Logger) Body(a ...interface{}) { } // Bodyf formats according to a format specifier and logs a message to the configured body writer. -func (l Logger) Bodyf(format string, a ...interface{}) { +func (l PaketoLogger) Bodyf(format string, a ...interface{}) { if !l.IsBodyEnabled() { return } @@ -87,18 +127,18 @@ func (l Logger) Bodyf(format string, a ...interface{}) { } // BodyWriter returns the configured body writer. -func (l Logger) BodyWriter() io.Writer { +func (l PaketoLogger) BodyWriter() io.Writer { return l.body } // IsBodyEnabled indicates whether body logging is enabled. -func (l Logger) IsBodyEnabled() bool { +func (l PaketoLogger) IsBodyEnabled() bool { return l.body != nil } // Header formats using the default formats for its operands and logs a message to the configured header writer. Spaces // are added between operands when neither is a string. -func (l Logger) Header(a ...interface{}) { +func (l PaketoLogger) Header(a ...interface{}) { if !l.IsHeaderEnabled() { return } @@ -107,7 +147,7 @@ func (l Logger) Header(a ...interface{}) { } // Headerf formats according to a format specifier and logs a message to the configured header writer. -func (l Logger) Headerf(format string, a ...interface{}) { +func (l PaketoLogger) Headerf(format string, a ...interface{}) { if !l.IsHeaderEnabled() { return } @@ -116,18 +156,17 @@ func (l Logger) Headerf(format string, a ...interface{}) { } // HeaderWriter returns the configured header writer. -func (l Logger) HeaderWriter() io.Writer { +func (l PaketoLogger) HeaderWriter() io.Writer { return l.header } // IsHeaderEnabled indicates whether header logging is enabled. -func (l Logger) IsHeaderEnabled() bool { +func (l PaketoLogger) IsHeaderEnabled() bool { return l.header != nil } // IdentifiableError is an error associated with an Identifiable for logging purposes. type IdentifiableError struct { - // Name is the name of the identified object. Name string @@ -143,7 +182,7 @@ func (i IdentifiableError) Error() string { } // TerminalError logs a message to the configured terminal error writer. -func (l Logger) TerminalError(err IdentifiableError) { +func (l PaketoLogger) TerminalError(err IdentifiableError) { if !l.IsTerminalErrorEnabled() { return } @@ -153,16 +192,16 @@ func (l Logger) TerminalError(err IdentifiableError) { } // TerminalErrorWriter returns the configured terminal error writer. -func (l Logger) TerminalErrorWriter() io.Writer { +func (l PaketoLogger) TerminalErrorWriter() io.Writer { return l.terminalBody } // IsTerminalErrorEnabled indicates whether terminal error logging is enabled. -func (l Logger) IsTerminalErrorEnabled() bool { +func (l PaketoLogger) IsTerminalErrorEnabled() bool { return l.terminalHeader != nil && l.terminalBody != nil } -func (l Logger) Title(name string, version string, homepage string) { +func (l PaketoLogger) Title(name string, version string, homepage string) { if !l.IsTitleEnabled() { return } @@ -171,17 +210,67 @@ func (l Logger) Title(name string, version string, homepage string) { l.Header(color.New(color.FgBlue, color.Faint, color.Italic).Sprint(homepage)) } +func (l PaketoLogger) Titlef(format string, a ...interface{}) { + if !l.IsTitleEnabled() { + return + } + + l.printf(l.title, format, a...) +} + // TitleWriter returns the configured title writer. -func (l Logger) TitleWriter() io.Writer { +func (l PaketoLogger) TitleWriter() io.Writer { return l.title } // IsTitleEnabled indicates whether title logging is enabled. -func (l Logger) IsTitleEnabled() bool { +func (l PaketoLogger) IsTitleEnabled() bool { return l.title != nil } -func (Logger) print(writer io.Writer, a ...interface{}) { +// Debug formats using the default formats for its operands and writes to the configured debug writer. Spaces are added +// between operands when neither is a string. +func (l PaketoLogger) Debug(a ...interface{}) { + if !l.IsDebugEnabled() { + return + } + + s := fmt.Sprint(a...) + + if !strings.HasSuffix(s, "\n") { + s += "\n" + } + + _, _ = fmt.Fprint(l.debug, s) +} + +// Debugf formats according to a format specifier and writes to the configured debug writer. +func (l PaketoLogger) Debugf(format string, a ...interface{}) { + if !l.IsDebugEnabled() { + return + } + + if !strings.HasSuffix(format, "\n") { + format += "\n" + } + + _, _ = fmt.Fprintf(l.debug, format, a...) +} + +// DebugWriter returns the configured debug writer. +func (l PaketoLogger) DebugWriter() io.Writer { + if l.IsDebugEnabled() { + return l.debug + } + return io.Discard +} + +// IsDebugEnabled indicates whether debug logging is enabled. +func (l PaketoLogger) IsDebugEnabled() bool { + return l.debug != nil +} + +func (PaketoLogger) print(writer io.Writer, a ...interface{}) { s := fmt.Sprint(a...) if !strings.HasSuffix(s, "\n") { @@ -191,7 +280,7 @@ func (Logger) print(writer io.Writer, a ...interface{}) { _, _ = fmt.Fprint(writer, s) } -func (Logger) printf(writer io.Writer, format string, a ...interface{}) { +func (PaketoLogger) printf(writer io.Writer, format string, a ...interface{}) { if !strings.HasSuffix(format, "\n") { format = format + "\n" } diff --git a/log/logger_test.go b/log/logger_test.go index 005ec10..fd35374 100644 --- a/log/logger_test.go +++ b/log/logger_test.go @@ -41,7 +41,7 @@ func testLogger(t *testing.T, context spec.G, it spec.S) { context("without BP_DEBUG", func() { it.Before(func() { - l = log.NewLogger(b) + l = log.NewPaketoLogger(b) }) it("does not configure debug", func() { @@ -53,12 +53,8 @@ func testLogger(t *testing.T, context spec.G, it spec.S) { it.Before(func() { //libcnb defines BP_DEBUG as enabled if it has _any_ value //this does not include empty string as previously tested here. - Expect(os.Setenv("BP_DEBUG", "true")).To(Succeed()) - l = log.NewLogger(b) - }) - - it.After(func() { - Expect(os.Unsetenv("BP_DEBUG")).To(Succeed()) + t.Setenv("BP_DEBUG", "true") + l = log.NewPaketoLogger(b) }) it("configures debug", func() { @@ -68,12 +64,8 @@ func testLogger(t *testing.T, context spec.G, it spec.S) { context("with BP_LOG_LEVEL set to DEBUG", func() { it.Before(func() { - Expect(os.Setenv("BP_LOG_LEVEL", "DEBUG")).To(Succeed()) - l = log.NewLogger(b) - }) - - it.After(func() { - Expect(os.Unsetenv("BP_LOG_LEVEL")).To(Succeed()) + t.Setenv("BP_LOG_LEVEL", "DEBUG") + l = log.NewPaketoLogger(b) }) it("configures debug", func() { @@ -84,7 +76,7 @@ func testLogger(t *testing.T, context spec.G, it spec.S) { context("with debug disabled", func() { it.Before(func() { Expect(os.Unsetenv("BP_LOG_LEVEL")).To(Succeed()) - l = log.NewLoggerWithOptions(b) + l = log.NewPaketoLoggerWithOptions(b) }) it("does not write debug log", func() { @@ -104,11 +96,8 @@ func testLogger(t *testing.T, context spec.G, it spec.S) { context("with debug enabled", func() { it.Before(func() { - Expect(os.Setenv("BP_LOG_LEVEL", "debug")).To(Succeed()) - l = log.NewLogger(b) - }) - it.After(func() { - Expect(os.Unsetenv("BP_LOG_LEVEL")).To(Succeed()) + t.Setenv("BP_LOG_LEVEL", "debug") + l = log.NewPaketoLogger(b) }) it("writes body log", func() { @@ -131,12 +120,12 @@ func testLogger(t *testing.T, context spec.G, it spec.S) { it("writes debug log", func() { l.Debug("test-message") - Expect(b.String()).To(Equal("test-message\n")) + Expect(b.String()).To(Equal("\x1b[46mtest-message\x1b[0m\n")) }) it("writes debug formatted log", func() { l.Debugf("test-%s", "message") - Expect(b.String()).To(Equal("test-message\n")) + Expect(b.String()).To(Equal("\x1b[46mtest-message\x1b[0m\n")) }) it("returns debug writer", func() { diff --git a/sbom/sbom_test.go b/sbom/sbom_test.go index f83996d..8a36130 100644 --- a/sbom/sbom_test.go +++ b/sbom/sbom_test.go @@ -1,7 +1,6 @@ package sbom_test import ( - "io" "os" "path/filepath" "strings" @@ -62,7 +61,7 @@ func testSBOM(t *testing.T, context spec.G, it spec.S) { }).Return(nil) // uses interface here intentionally, to force that inteface and implementation match - scanner = sbom.NewSyftCLISBOMScanner(layers, &executor, log.NewLogger(io.Discard)) + scanner = sbom.NewSyftCLISBOMScanner(layers, &executor, log.NewDiscardLogger()) Expect(scanner.ScanBuild("something", format)).To(Succeed()) @@ -105,7 +104,7 @@ func testSBOM(t *testing.T, context spec.G, it spec.S) { }).Return(nil) // uses interface here intentionally, to force that inteface and implementation match - scanner = sbom.NewSyftCLISBOMScanner(layers, &executor, log.NewLogger(io.Discard)) + scanner = sbom.NewSyftCLISBOMScanner(layers, &executor, log.NewDiscardLogger()) Expect(scanner.ScanBuild("something", format)).To(Succeed()) @@ -133,7 +132,7 @@ func testSBOM(t *testing.T, context spec.G, it spec.S) { scanner := sbom.SyftCLISBOMScanner{ Executor: &executor, Layers: layers, - Logger: log.NewLogger(io.Discard), + Logger: log.NewDiscardLogger(), } Expect(scanner.ScanLayer(layer, "something", format)).To(Succeed()) @@ -160,7 +159,7 @@ func testSBOM(t *testing.T, context spec.G, it spec.S) { scanner := sbom.SyftCLISBOMScanner{ Executor: &executor, Layers: layers, - Logger: log.NewLogger(io.Discard), + Logger: log.NewDiscardLogger(), } Expect(scanner.ScanLaunch("something", libcnb.CycloneDXJSON, libcnb.SyftJSON, libcnb.SPDXJSON)).To(Succeed()) From 206540a92c3f1c7f737b91bd5f1b718ba2ea906a Mon Sep 17 00:00:00 2001 From: Daniel Mikusa Date: Wed, 30 Aug 2023 23:34:46 -0400 Subject: [PATCH 4/6] Add logger to the NewHelperLayerContributor method arguments Signed-off-by: Daniel Mikusa --- layer.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/layer.go b/layer.go index 7aa53c6..b38325a 100644 --- a/layer.go +++ b/layer.go @@ -281,11 +281,12 @@ type HelperLayerContributor struct { } // NewHelperLayerContributor returns a new HelperLayerContributor -func NewHelperLayerContributor(buildpack libcnb.Buildpack, names ...string) HelperLayerContributor { +func NewHelperLayerContributor(buildpack libcnb.Buildpack, logger log.Logger, names ...string) HelperLayerContributor { return HelperLayerContributor{ - Path: filepath.Join(buildpack.Path, "bin", "helper"), - Names: names, BuildpackInfo: buildpack.Info, + Logger: logger, + Names: names, + Path: filepath.Join(buildpack.Path, "bin", "helper"), } } From 24484d8befa6ee575122fd1da4b7a2821c3eba37 Mon Sep 17 00:00:00 2001 From: Daniel Mikusa Date: Thu, 31 Aug 2023 00:20:41 -0400 Subject: [PATCH 5/6] Add `ContributeLayersFunc` and reverse flow of `ContributableBuildFunc` Previously, it was on the buildpack author to call `ContributableBuildFunc` which was a little awkward and created some testing issues. You could not mock out this method so it would run your layer contributors even during tests. In libpak v1, the layer contributor was returned from build and converted by libcnb into a layer so when doing tests, we could capture the layer contributors but not execute them. This change flips the flow around so that `ContributableBuildFunc` takes a `ContributeLayersFunc` and the `ContributeLayersFunc` produces a list of layer contributors. Normally, `ContributableBuildFunc` would run and process the layer contributors making layers but in tests you can simply run the `ContributeLayersFunc` directly and check that the list of layer contributors is as expected making it more convenient for testing purposes. Signed-off-by: Daniel Mikusa --- layer.go | 10 +++++++++- layer_test.go | 4 ---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/layer.go b/layer.go index b38325a..a1ed94a 100644 --- a/layer.go +++ b/layer.go @@ -34,11 +34,19 @@ import ( "github.com/paketo-buildpacks/libpak/v2/sherpa" ) +// ContributeLayersFunc takes a context and result pointer returning a list of Contributables, the list of Contributables will be turned into layers automatically +type ContributeLayersFunc func(context libcnb.BuildContext, result *libcnb.BuildResult) ([]Contributable, error) + // ContributableBuildFunc is a standard libcnb.BuildFunc implementation that delegates to a list of Contributables -func ContributableBuildFunc(layerContributors []Contributable) libcnb.BuildFunc { +func ContributableBuildFunc(contributeLayersFunc ContributeLayersFunc) libcnb.BuildFunc { return func(context libcnb.BuildContext) (libcnb.BuildResult, error) { result := libcnb.NewBuildResult() + layerContributors, err := contributeLayersFunc(context, &result) + if err != nil { + return libcnb.BuildResult{}, fmt.Errorf("unable to fetch layer contributors\n%w", err) + } + for _, creator := range layerContributors { name := creator.Name() layer, err := context.Layers.Layer(name) diff --git a/layer_test.go b/layer_test.go index 494f5c8..02ea425 100644 --- a/layer_test.go +++ b/layer_test.go @@ -52,10 +52,6 @@ func testLayer(t *testing.T, context spec.G, it spec.S) { layer.Profile = libcnb.Profile{} }) - it.After(func() { - Expect(os.RemoveAll(layersDir)).To(Succeed()) - }) - context("LayerContributor", func() { var ( lc libpak.LayerContributor From fe3162f0ea11e14578032a32ca3b2af798dccbdc Mon Sep 17 00:00:00 2001 From: Daniel Mikusa Date: Thu, 31 Aug 2023 11:36:34 -0400 Subject: [PATCH 6/6] Update log/logger.go --- log/logger.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/log/logger.go b/log/logger.go index 35b08a6..218a720 100644 --- a/log/logger.go +++ b/log/logger.go @@ -64,7 +64,7 @@ type PaketoLogger struct { title io.Writer } -// NewDiscard creates a new instance of PaketoLogger that discards all log messages. Useful in testing. +// NewDiscardLogger creates a new instance of PaketoLogger that discards all log messages. Useful in testing. func NewDiscardLogger() PaketoLogger { return PaketoLogger{ debug: io.Discard,