diff --git a/go.mod b/go.mod index 5f091355..f7036505 100644 --- a/go.mod +++ b/go.mod @@ -32,6 +32,7 @@ require ( github.com/kyokomi/emoji v2.1.0+incompatible github.com/logrusorgru/aurora v0.0.0-20190417123914-21d75270181e github.com/marcsauter/single v0.0.0-20181104081128-f8bf46f26ec0 + github.com/mitchellh/hashstructure/v2 v2.0.1 github.com/moby/buildkit v0.7.2 github.com/moby/sys/mount v0.2.0 // indirect github.com/mudler/cobra-extensions v0.0.0-20200612154940-31a47105fe3d diff --git a/go.sum b/go.sum index cc914e30..7ce6f9af 100644 --- a/go.sum +++ b/go.sum @@ -728,6 +728,8 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= github.com/mitchellh/hashstructure v1.0.0 h1:ZkRJX1CyOoTkar7p/mLS5TZU4nJ1Rn/F8u9dGS02Q3Y= github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= +github.com/mitchellh/hashstructure/v2 v2.0.1 h1:L60q1+q7cXE4JeEJJKMnh2brFIe3rZxCihYAB61ypAY= +github.com/mitchellh/hashstructure/v2 v2.0.1/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20150613213606-2caf8efc9366/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= diff --git a/pkg/compiler/imagehashtree.go b/pkg/compiler/imagehashtree.go index 6e885e08..c1683ff5 100644 --- a/pkg/compiler/imagehashtree.go +++ b/pkg/compiler/imagehashtree.go @@ -109,13 +109,29 @@ func (ht *ImageHashTree) resolve(cs *LuetCompiler, p *compilerspec.LuetCompilati return nil, errors.Wrap(err, "While computing a solution for "+p.GetPackage().HumanReadableString()) } + // Get hash from buildpsecs + salts := map[string]string{} + for _, assertion := range dependencies { //highly dependent on the order + if assertion.Value { + spec, err := cs.FromPackage(assertion.Package) + if err != nil { + return nil, errors.Wrap(err, "while computing hash buildspecs") + } + hash, err := spec.Hash() + if err != nil { + return nil, errors.Wrap(err, "failed computing hash") + } + salts[assertion.Package.GetFingerPrint()] = hash + } + } + assertions := solver.PackagesAssertions{} for _, assertion := range dependencies { //highly dependent on the order if assertion.Value { nthsolution := dependencies.Cut(assertion.Package) assertion.Hash = solver.PackageHash{ - BuildHash: nthsolution.HashFrom(assertion.Package), - PackageHash: nthsolution.AssertionHash(), + BuildHash: nthsolution.SaltedHashFrom(assertion.Package, salts), + PackageHash: nthsolution.SaltedAssertionHash(salts), } assertion.Package.SetTreeDir(p.Package.GetTreeDir()) assertions = append(assertions, assertion) diff --git a/pkg/compiler/imagehashtree_test.go b/pkg/compiler/imagehashtree_test.go index 25781984..accf0367 100644 --- a/pkg/compiler/imagehashtree_test.go +++ b/pkg/compiler/imagehashtree_test.go @@ -46,12 +46,15 @@ var _ = Describe("ImageHashTree", func() { packageHash, err := hashtree.Query(compiler, spec) Expect(err).ToNot(HaveOccurred()) - Expect(packageHash.Target.Hash.BuildHash).To(Equal("6490e800fe443b99328fc363529aee74bda513930fb27ce6ab814d692bba068e")) - Expect(packageHash.Target.Hash.PackageHash).To(Equal("79d7107d13d578b362e6a7bf10ec850efce26316405b8d732ce8f9e004d64281")) - Expect(packageHash.BuilderImageHash).To(Equal("builder-79462b60bf899ad79db63f194a3c9c2a")) + + Expect(packageHash.Target.Hash.BuildHash).To(Equal("ec62e3e2cfb4c520c8b2561797c005d248c2659295f3660fa1a66582fc4dc280")) + Expect(packageHash.Target.Hash.PackageHash).To(Equal("5fa15a0eb0534eaa78ef1b4e32fe72704effaa5e54399b7cab6d630aa0aeac5c")) + Expect(packageHash.BuilderImageHash).To(Equal("builder-96e0c42b5741376ebcf0a47c8ec1c481")) }) }) + expectedPackageHash := "bc6d354e8b9480b70c6f17eafa34cef387b8443ad150b7c9528fb7e94b764e90" + Context("complex package definition", func() { BeforeEach(func() { generalRecipe = tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false)) @@ -69,25 +72,75 @@ var _ = Describe("ImageHashTree", func() { packageHash, err := hashtree.Query(compiler, spec) Expect(err).ToNot(HaveOccurred()) - Expect(packageHash.Dependencies[len(packageHash.Dependencies)-1].Hash.PackageHash).To(Equal("c46e653125d71ee3fd696b3941ec1ed6e8a0268f896204c7a222a5aa03eb9982")) - Expect(packageHash.SourceHash).To(Equal("c46e653125d71ee3fd696b3941ec1ed6e8a0268f896204c7a222a5aa03eb9982")) - Expect(packageHash.BuilderImageHash).To(Equal("builder-37f4d05ba8a39525742ca364f69b4090")) + Expect(packageHash.Dependencies[len(packageHash.Dependencies)-1].Hash.PackageHash).To(Equal(expectedPackageHash)) + Expect(packageHash.SourceHash).To(Equal(expectedPackageHash)) + Expect(packageHash.BuilderImageHash).To(Equal("builder-9b2bc16985446c41eca8f7922ec98078")) //Expect(packageHash.Target.Hash.BuildHash).To(Equal("79d7107d13d578b362e6a7bf10ec850efce26316405b8d732ce8f9e004d64281")) - Expect(packageHash.Target.Hash.PackageHash).To(Equal("bb1d9a99c0c309a297c75b436504e664a42121fadbb4e035bda403cd418117aa")) + Expect(packageHash.Target.Hash.PackageHash).To(Equal("bb84a30ced857725fcb575e87fe33d4aefe911abfdd5f9063bbaeb9e4b94e9e2")) a := &pkg.DefaultPackage{Name: "a", Category: "test", Version: "1.1"} hash, err := packageHash.DependencyBuildImage(a) Expect(err).ToNot(HaveOccurred()) - Expect(hash).To(Equal("79d7107d13d578b362e6a7bf10ec850efce26316405b8d732ce8f9e004d64281")) + + Expect(hash).To(Equal("484f14294d96fd3b51cec1f2db37a269b7b903f3516b74b0cb0771b65d85b799")) assertionA := packageHash.Dependencies.Search(a.GetFingerPrint()) - Expect(assertionA.Hash.PackageHash).To(Equal("c46e653125d71ee3fd696b3941ec1ed6e8a0268f896204c7a222a5aa03eb9982")) + Expect(assertionA.Hash.PackageHash).To(Equal(expectedPackageHash)) b := &pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"} assertionB := packageHash.Dependencies.Search(b.GetFingerPrint()) - Expect(assertionB.Hash.PackageHash).To(Equal("79d7107d13d578b362e6a7bf10ec850efce26316405b8d732ce8f9e004d64281")) + Expect(assertionB.Hash.PackageHash).To(Equal("484f14294d96fd3b51cec1f2db37a269b7b903f3516b74b0cb0771b65d85b799")) hashB, err := packageHash.DependencyBuildImage(b) Expect(err).ToNot(HaveOccurred()) - Expect(hashB).To(Equal("6490e800fe443b99328fc363529aee74bda513930fb27ce6ab814d692bba068e")) + Expect(hashB).To(Equal("828c983e755353190540565a29e71c9eb4c48d6303e1fd2c523235b7c2339c73")) + }) + }) + + Context("complex package definition, with small change in build.yaml", func() { + BeforeEach(func() { + generalRecipe = tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false)) + + //Definition of A here is slightly changed in the steps build.yaml file (1 character only) + err := generalRecipe.Load("../../tests/fixtures/upgrade_old_repo_revision_content_changed") + Expect(err).ToNot(HaveOccurred()) + compiler = NewLuetCompiler(sd.NewSimpleDockerBackend(), generalRecipe.GetDatabase(), options.Concurrency(2)) + hashtree = NewHashTree(generalRecipe.GetDatabase()) + + }) + It("Calculates the hash correctly", func() { + spec, err := compiler.FromPackage(&pkg.DefaultPackage{Name: "c", Category: "test", Version: "1.0"}) + Expect(err).ToNot(HaveOccurred()) + + packageHash, err := hashtree.Query(compiler, spec) + Expect(err).ToNot(HaveOccurred()) + + Expect(packageHash.Dependencies[len(packageHash.Dependencies)-1].Hash.PackageHash).ToNot(Equal(expectedPackageHash)) + sourceHash := "ed1bd90e696904982a1f51998646a335067329e1a262994b5ae15c579106ac81" + Expect(packageHash.Dependencies[len(packageHash.Dependencies)-1].Hash.PackageHash).To(Equal(sourceHash)) + Expect(packageHash.SourceHash).To(Equal(sourceHash)) + Expect(packageHash.SourceHash).ToNot(Equal(expectedPackageHash)) + + Expect(packageHash.BuilderImageHash).To(Equal("builder-f4b0e366e0a42774428fbdc9aa325648")) + + //Expect(packageHash.Target.Hash.BuildHash).To(Equal("79d7107d13d578b362e6a7bf10ec850efce26316405b8d732ce8f9e004d64281")) + Expect(packageHash.Target.Hash.PackageHash).To(Equal("2618f12851a596f6801e2665e07147da98a0a151f44500a54ca8b76b869e378d")) + a := &pkg.DefaultPackage{Name: "a", Category: "test", Version: "1.1"} + hash, err := packageHash.DependencyBuildImage(a) + Expect(err).ToNot(HaveOccurred()) + Expect(hash).To(Equal("484f14294d96fd3b51cec1f2db37a269b7b903f3516b74b0cb0771b65d85b799")) + + assertionA := packageHash.Dependencies.Search(a.GetFingerPrint()) + + Expect(assertionA.Hash.PackageHash).To(Equal("ed1bd90e696904982a1f51998646a335067329e1a262994b5ae15c579106ac81")) + Expect(assertionA.Hash.PackageHash).ToNot(Equal(expectedPackageHash)) + + b := &pkg.DefaultPackage{Name: "b", Category: "test", Version: "1.0"} + assertionB := packageHash.Dependencies.Search(b.GetFingerPrint()) + + Expect(assertionB.Hash.PackageHash).To(Equal("484f14294d96fd3b51cec1f2db37a269b7b903f3516b74b0cb0771b65d85b799")) + hashB, err := packageHash.DependencyBuildImage(b) + Expect(err).ToNot(HaveOccurred()) + + Expect(hashB).To(Equal("828c983e755353190540565a29e71c9eb4c48d6303e1fd2c523235b7c2339c73")) }) }) diff --git a/pkg/compiler/types/spec/spec.go b/pkg/compiler/types/spec/spec.go index d1b07cb1..6778acc4 100644 --- a/pkg/compiler/types/spec/spec.go +++ b/pkg/compiler/types/spec/spec.go @@ -20,6 +20,7 @@ import ( "io/ioutil" "path/filepath" + "github.com/mitchellh/hashstructure/v2" options "github.com/mudler/luet/pkg/compiler/types/options" pkg "github.com/mudler/luet/pkg/package" @@ -226,6 +227,44 @@ func (cs *LuetCompilationSpec) HasImageSource() bool { return (cs.Package != nil && len(cs.GetPackage().GetRequires()) != 0) || cs.GetImage() != "" } +// Signature is a portion of the spec that yields a signature for the hash +type Signature struct { + Image string + Steps []string + PackageDir string + Prelude []string + Seed string + Env []string + Retrieve []string + Unpack bool + Includes []string + Excludes []string + Copy []CopyField +} + +func (cs *LuetCompilationSpec) signature() Signature { + return Signature{ + Image: cs.Image, + Steps: cs.Steps, + PackageDir: cs.PackageDir, + Prelude: cs.Prelude, + Seed: cs.Seed, + Env: cs.Env, + Retrieve: cs.Retrieve, + Unpack: cs.Unpack, + Includes: cs.Includes, + Excludes: cs.Excludes, + Copy: cs.Copy, + } +} + +func (cs *LuetCompilationSpec) Hash() (string, error) { + // build a signature, we want to be part of the hash only the fields that are relevant for build purposes + signature := cs.signature() + h, err := hashstructure.Hash(signature, hashstructure.FormatV2, nil) + return fmt.Sprint(h), err +} + func (cs *LuetCompilationSpec) CopyRetrieves(dest string) error { var err error if len(cs.Retrieve) > 0 { diff --git a/pkg/compiler/types/spec/spec_test.go b/pkg/compiler/types/spec/spec_test.go index 2b5588ad..526ef4d5 100644 --- a/pkg/compiler/types/spec/spec_test.go +++ b/pkg/compiler/types/spec/spec_test.go @@ -20,6 +20,7 @@ import ( "os" "path/filepath" + options "github.com/mudler/luet/pkg/compiler/types/options" compilerspec "github.com/mudler/luet/pkg/compiler/types/spec" . "github.com/mudler/luet/pkg/compiler" @@ -74,6 +75,62 @@ var _ = Describe("Spec", func() { }) }) + Context("Image hashing", func() { + It("is stable", func() { + spec1 := &compilerspec.LuetCompilationSpec{ + Image: "foo", + BuildOptions: &options.Compiler{BuildValues: []map[string]interface{}{{"foo": "bar", "baz": true}}}, + + Package: &pkg.DefaultPackage{ + Name: "foo", + Category: "Bar", + Labels: map[string]string{ + "foo": "bar", + "baz": "foo", + }, + }, + } + spec2 := &compilerspec.LuetCompilationSpec{ + Image: "foo", + BuildOptions: &options.Compiler{BuildValues: []map[string]interface{}{{"foo": "bar", "baz": true}}}, + Package: &pkg.DefaultPackage{ + Name: "foo", + Category: "Bar", + Labels: map[string]string{ + "foo": "bar", + "baz": "foo", + }, + }, + } + spec3 := &compilerspec.LuetCompilationSpec{ + Image: "foo", + Steps: []string{"foo"}, + Package: &pkg.DefaultPackage{ + Name: "foo", + Category: "Bar", + Labels: map[string]string{ + "foo": "bar", + "baz": "foo", + }, + }, + } + hash, err := spec1.Hash() + Expect(err).ToNot(HaveOccurred()) + + hash2, err := spec2.Hash() + Expect(err).ToNot(HaveOccurred()) + + hash3, err := spec3.Hash() + Expect(err).ToNot(HaveOccurred()) + + Expect(hash).To(Equal(hash2)) + hashagain, err := spec2.Hash() + Expect(err).ToNot(HaveOccurred()) + Expect(hash).ToNot(Equal(hash3)) + Expect(hash).To(Equal(hashagain)) + }) + }) + Context("Simple package build definition", func() { It("Loads it correctly", func() { generalRecipe := tree.NewGeneralRecipe(pkg.NewInMemoryDatabase(false)) diff --git a/pkg/package/package.go b/pkg/package/package.go index 2f9eca0b..0067caf6 100644 --- a/pkg/package/package.go +++ b/pkg/package/package.go @@ -118,6 +118,8 @@ type Package interface { SetTreeDir(s string) GetTreeDir() string + Mark() Package + JSON() ([]byte, error) } @@ -492,6 +494,12 @@ func (p *DefaultPackage) Matches(m Package) bool { return false } +func (p *DefaultPackage) Mark() Package { + marked := p.Clone() + marked.SetName("@@" + marked.GetName()) + return marked +} + func (p *DefaultPackage) Expand(definitiondb PackageDatabase) (Packages, error) { var versionsInWorld Packages diff --git a/pkg/solver/decoder.go b/pkg/solver/decoder.go index 93c4d5a9..00cd947c 100644 --- a/pkg/solver/decoder.go +++ b/pkg/solver/decoder.go @@ -260,24 +260,42 @@ func (a PackagesAssertions) TrueLen() int { // and checks it's not the only one. if it's unique it marks it specially - so the hash // which is generated is unique for the selected package func (assertions PackagesAssertions) HashFrom(p pkg.Package) string { + return assertions.SaltedHashFrom(p, map[string]string{}) +} +func (assertions PackagesAssertions) AssertionHash() string { + return assertions.SaltedAssertionHash(map[string]string{}) +} + +func (assertions PackagesAssertions) SaltedHashFrom(p pkg.Package, salts map[string]string) string { var assertionhash string // When we don't have any solution to hash for, we need to generate an UUID by ourselves latestsolution := assertions.Drop(p) if latestsolution.TrueLen() == 0 { - assertionhash = assertions.Mark(p).AssertionHash() + // Preserve the hash if supplied of marked packages + marked := p.Mark() + if markedHash, exists := salts[p.GetFingerPrint()]; exists { + salts[marked.GetFingerPrint()] = markedHash + } + assertionhash = assertions.Mark(p).SaltedAssertionHash(salts) } else { - assertionhash = latestsolution.AssertionHash() + assertionhash = latestsolution.SaltedAssertionHash(salts) } return assertionhash } -func (assertions PackagesAssertions) AssertionHash() string { +func (assertions PackagesAssertions) SaltedAssertionHash(salts map[string]string) string { var fingerprint string for _, assertion := range assertions { // Note: Always order them first! if assertion.Value { // Tke into account only dependencies installed (get fingerprint of subgraph) - fingerprint += assertion.ToString() + "\n" + salt, exists := salts[assertion.Package.GetFingerPrint()] + if exists { + fingerprint += assertion.ToString() + salt + "\n" + + } else { + fingerprint += assertion.ToString() + "\n" + } } } hash := sha256.Sum256([]byte(fingerprint)) @@ -316,8 +334,7 @@ func (assertions PackagesAssertions) Mark(p pkg.Package) PackagesAssertions { for _, a := range assertions { if a.Package.Matches(p) { - marked := a.Package.Clone() - marked.SetName("@@" + marked.GetName()) + marked := a.Package.Mark() a = PackageAssert{Package: marked.(*pkg.DefaultPackage), Value: a.Value, Hash: a.Hash} } ass = append(ass, a) diff --git a/pkg/solver/decoder_test.go b/pkg/solver/decoder_test.go index 793bf0b5..204d598f 100644 --- a/pkg/solver/decoder_test.go +++ b/pkg/solver/decoder_test.go @@ -382,6 +382,9 @@ var _ = Describe("Decoder", func() { Expect(solution.HashFrom(X)).ToNot(Equal(solution2.HashFrom(F))) Expect(solution3.HashFrom(D)).To(Equal(solution.HashFrom(X))) + Expect(solution3.SaltedHashFrom(D, map[string]string{D.GetFingerPrint(): "foo"})).ToNot(Equal(solution3.HashFrom(D))) + + Expect(solution4.SaltedHashFrom(Y, map[string]string{X.GetFingerPrint(): "foo"})).ToNot(Equal(solution4.HashFrom(Y))) Expect(empty.AssertionHash()).ToNot(Equal(solution3.HashFrom(D))) Expect(empty.AssertionHash()).ToNot(Equal(solution2.HashFrom(F))) diff --git a/tests/fixtures/upgrade_old_repo_revision_content_changed/c/build.yaml b/tests/fixtures/upgrade_old_repo_revision_content_changed/c/build.yaml new file mode 100644 index 00000000..dc3fba0a --- /dev/null +++ b/tests/fixtures/upgrade_old_repo_revision_content_changed/c/build.yaml @@ -0,0 +1,10 @@ +prelude: + - echo foo > /test + - echo bar > /test2 +steps: + - echo c > /c + - echo c > /cd +requires: +- category: "test" + name: "a" + version: ">=1.0" diff --git a/tests/fixtures/upgrade_old_repo_revision_content_changed/c/definition.yaml b/tests/fixtures/upgrade_old_repo_revision_content_changed/c/definition.yaml new file mode 100644 index 00000000..348454f7 --- /dev/null +++ b/tests/fixtures/upgrade_old_repo_revision_content_changed/c/definition.yaml @@ -0,0 +1,3 @@ +category: "test" +name: "c" +version: "1.0" diff --git a/tests/fixtures/upgrade_old_repo_revision_content_changed/cat/a/a/build.yaml b/tests/fixtures/upgrade_old_repo_revision_content_changed/cat/a/a/build.yaml new file mode 100644 index 00000000..f2bfb878 --- /dev/null +++ b/tests/fixtures/upgrade_old_repo_revision_content_changed/cat/a/a/build.yaml @@ -0,0 +1,11 @@ +image: "alpine" +prelude: + - echo fozo > /test + - echo bar > /test2 +steps: + - echo artifact3 > /test3 + - echo artifact4 > /test4 +requires: +- category: "test" + name: "b" + version: "1.0" diff --git a/tests/fixtures/upgrade_old_repo_revision_content_changed/cat/a/a/definition.yaml b/tests/fixtures/upgrade_old_repo_revision_content_changed/cat/a/a/definition.yaml new file mode 100644 index 00000000..a419363d --- /dev/null +++ b/tests/fixtures/upgrade_old_repo_revision_content_changed/cat/a/a/definition.yaml @@ -0,0 +1,8 @@ +category: "test" +name: "a" +version: "1.1" +requires: +- category: "test2" + name: "b" + version: "1.0" + diff --git a/tests/fixtures/upgrade_old_repo_revision_content_changed/cat/b-1.1/build.yaml b/tests/fixtures/upgrade_old_repo_revision_content_changed/cat/b-1.1/build.yaml new file mode 100644 index 00000000..d906104d --- /dev/null +++ b/tests/fixtures/upgrade_old_repo_revision_content_changed/cat/b-1.1/build.yaml @@ -0,0 +1,9 @@ +image: "alpine" +prelude: + - echo foo > /test + - echo bar > /test2 +steps: + - echo artifact5 > /newc + - echo artifact6 > /newnewc + - chmod +x generate.sh + - ./generate.sh diff --git a/tests/fixtures/upgrade_old_repo_revision_content_changed/cat/b-1.1/definition.yaml b/tests/fixtures/upgrade_old_repo_revision_content_changed/cat/b-1.1/definition.yaml new file mode 100644 index 00000000..b02a44e8 --- /dev/null +++ b/tests/fixtures/upgrade_old_repo_revision_content_changed/cat/b-1.1/definition.yaml @@ -0,0 +1,3 @@ +category: "test" +name: "b" +version: "1.0" diff --git a/tests/fixtures/upgrade_old_repo_revision_content_changed/cat/b-1.1/generate.sh b/tests/fixtures/upgrade_old_repo_revision_content_changed/cat/b-1.1/generate.sh new file mode 100644 index 00000000..3b2dc1b2 --- /dev/null +++ b/tests/fixtures/upgrade_old_repo_revision_content_changed/cat/b-1.1/generate.sh @@ -0,0 +1 @@ +echo generated > /sonewc diff --git a/tests/integration/28_nobuildtreedocker.sh b/tests/integration/28_nobuildtreedocker.sh index 136a993b..0ddc292f 100755 --- a/tests/integration/28_nobuildtreedocker.sh +++ b/tests/integration/28_nobuildtreedocker.sh @@ -51,9 +51,9 @@ testBuild() { assertTrue 'create package' "[ -e '$tmpdir/testbuild/c-test-1.0.package.tar.zst' ]" assertTrue 'create package Z' "[ -e '$tmpdir/testbuild/z-test-1.0+2.package.tar.zst' ]" assertTrue 'create package interpolated' "[ -e '$tmpdir/testbuild/interpolated-test-1.0+2.package.tar.zst' ]" - assertContains 'Does use the upstream cache without specifying it test/c' "$build_output" "Images available for test/c-1.0 generating artifact from remote images: quay.io/mocaccinoos/integration-test-cache:d620e573c81eab36a9dc5cc314e80fd7b6e04aeff26127de4225bf24fe1f8e71" - assertContains 'Does use the upstream cache without specifying it test/z' "$build_output" "Images available for test/z-1.0+2 generating artifact from remote images: quay.io/mocaccinoos/integration-test-cache:b0f34b0d2d271f0f2619324476b2857b3b39ca895bddc2474a741f3c8c1acbbc" - assertContains 'Does use the upstream cache without specifying it test/interpolated' "$build_output" "Images available for test/interpolated-1.0+2 generating artifact from remote images: quay.io/mocaccinoos/integration-test-cache:c1f11f48113cd71d8795a06c7b49e1558bd7211d2aa88f5d79a3334f0393c64d" + assertContains 'Does use the upstream cache without specifying it test/c' "$build_output" "Images available for test/c-1.0 generating artifact from remote images: quay.io/mocaccinoos/integration-test-cache:7dd6062f45e78c1fe36d0f48fc21bc8c8219edfc9759f117527677a15ae42717" + assertContains 'Does use the upstream cache without specifying it test/z' "$build_output" "Images available for test/z-1.0+2 generating artifact from remote images: quay.io/mocaccinoos/integration-test-cache:2338dc4dc4b3d9657eb26597ad79569fe60f5529dd05676df266ad982ba2b1ba" + assertContains 'Does use the upstream cache without specifying it test/interpolated' "$build_output" "Images available for test/interpolated-1.0+2 generating artifact from remote images: quay.io/mocaccinoos/integration-test-cache:2edc4b6f8fc08a0fc958132dfcf2813e1ab220c2bbf60b988f1039082d61ff3e" } testRepo() { diff --git a/tests/integration/29_nobuildtreeinheritvalues.sh b/tests/integration/29_nobuildtreeinheritvalues.sh index ca166e1d..4f85452c 100755 --- a/tests/integration/29_nobuildtreeinheritvalues.sh +++ b/tests/integration/29_nobuildtreeinheritvalues.sh @@ -45,7 +45,7 @@ EOF mkdir $tmpdir/testbuild mkdir $tmpdir/empty - # With --rebuild, the package gets ignored + # Without --rebuild, the package gets ignored build_output=$(luet build --pull --tree "$tmpdir/empty" \ --config $tmpdir/luet.yaml --values $tmpdir/default.yaml --concurrency 1 \ --from-repositories --destination $tmpdir/testbuild --compression zstd test/c@1.0 test/z test/interpolated) @@ -56,7 +56,8 @@ EOF assertTrue 'create package' "[ -e '$tmpdir/testbuild/c-test-1.0.package.tar.zst' ]" assertTrue 'create package Z' "[ -e '$tmpdir/testbuild/z-test-1.0+2.package.tar.zst' ]" assertTrue 'create package interpolated' "[ -e '$tmpdir/testbuild/interpolated-test-1.0+2.package.tar.zst' ]" - assertContains 'Does use the upstream cache without specifying it' "$build_output" "Images available for test/interpolated-1.0+2 generating artifact from remote images: quay.io/mocaccinoos/integration-test-cache:c1f11f48113cd71d8795a06c7b49e1558bd7211d2aa88f5d79a3334f0393c64d" + assertNotContains 'Does NOT use the upstream cache without specifying it' "$build_output" "Images available for test/interpolated-1.0+2 generating artifact from remote images: quay.io/mocaccinoos/integration-test-cache:2edc4b6f8fc08a0fc958132dfcf2813e1ab220c2bbf60b988f1039082d61ff3e" + assertContains 'Does generate a new hash as values changed build.yaml' "$build_output" "Building image luet/cache:a249d16764168baf32b592dc05c33e499fa3685edda72dfb188a51191709de5a done" } testRepo() { @@ -113,7 +114,7 @@ testInstall() { assertTrue 'package installed' "[ -e '$tmpdir/testrootfs/c' ]" assertTrue 'package Z installed' "[ -e '$tmpdir/testrootfs/z' ]" ls -liah $tmpdir/testrootfs/ - assertTrue 'package interpolated installed' "[ -e '$tmpdir/testrootfs/interpolated-baz-bar' ]" + assertTrue 'package interpolated installed' "[ -e '$tmpdir/testrootfs/interpolated-baz-an' ]" } testReInstall() { diff --git a/tests/integration/29_nobuildtreeinheritvalues_noignored.sh b/tests/integration/29_nobuildtreeinheritvalues_noignored.sh index 46551eee..e1a3c77c 100755 --- a/tests/integration/29_nobuildtreeinheritvalues_noignored.sh +++ b/tests/integration/29_nobuildtreeinheritvalues_noignored.sh @@ -56,7 +56,7 @@ EOF assertTrue 'create package' "[ -e '$tmpdir/testbuild/c-test-1.0.package.tar.zst' ]" assertTrue 'create package Z' "[ -e '$tmpdir/testbuild/z-test-1.0+2.package.tar.zst' ]" assertTrue 'create package interpolated' "[ -e '$tmpdir/testbuild/interpolated-test-1.0+2.package.tar.zst' ]" - assertContains 'Does use the upstream cache without specifying it' "$build_output" "Downloading image quay.io/mocaccinoos/integration-test-cache:6490e800fe443b99328fc363529aee74bda513930fb27ce6ab814d692bba068e" + assertContains 'Does use the upstream cache without specifying it' "$build_output" "Downloading image quay.io/mocaccinoos/integration-test-cache:ec62e3e2cfb4c520c8b2561797c005d248c2659295f3660fa1a66582fc4dc280" } testRepo() { diff --git a/tests/integration/run.sh b/tests/integration/run.sh index 87495f78..f526d7b7 100755 --- a/tests/integration/run.sh +++ b/tests/integration/run.sh @@ -1,6 +1,6 @@ #!/bin/bash set -e - +export LUET_NO_SPINNER=true export LUET_YES=true export ROOT_DIR="$(git rev-parse --show-toplevel)" diff --git a/vendor/modules.txt b/vendor/modules.txt index 0397a5be..cc79038c 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -376,6 +376,9 @@ github.com/mitchellh/colorstring github.com/mitchellh/copystructure # github.com/mitchellh/hashstructure v1.0.0 github.com/mitchellh/hashstructure +# github.com/mitchellh/hashstructure/v2 v2.0.1 +## explicit +github.com/mitchellh/hashstructure/v2 # github.com/mitchellh/mapstructure v1.1.2 github.com/mitchellh/mapstructure # github.com/mitchellh/reflectwalk v1.0.0