From 15e33897247b1b5ea517a3724f07b0a36a110559 Mon Sep 17 00:00:00 2001 From: ramonskie Date: Tue, 22 Nov 2022 13:37:19 +0100 Subject: [PATCH] add the ability to set a prefix for vendored packages this is a solution to solve #2400 --- cmd/opts/opts.go | 1 + cmd/vendor_package.go | 2 +- release/pkg/package.go | 10 ++++- release/resource/interfaces.go | 1 + release/resource/resource.go | 20 +++++++--- .../resource/resourcefakes/fake_resource.go | 39 +++++++++++++++++++ releasedir/fs_release_dir.go | 5 ++- releasedir/fs_release_dir_test.go | 22 ++++++++--- releasedir/interfaces.go | 2 +- .../releasedirfakes/fake_release_dir.go | 18 +++++---- 10 files changed, 96 insertions(+), 24 deletions(-) diff --git a/cmd/opts/opts.go b/cmd/opts/opts.go index 82052434e..3a1f9bb91 100644 --- a/cmd/opts/opts.go +++ b/cmd/opts/opts.go @@ -1019,6 +1019,7 @@ type VendorPackageOpts struct { Args VendorPackageArgs `positional-args:"true" required:"true"` Directory DirOrCWDArg `long:"dir" description:"Release directory path if not current working directory" default:"."` + Prefix string `long:"prefix" description:"Prefix to add to the package name" default:""` cmd } diff --git a/cmd/vendor_package.go b/cmd/vendor_package.go index cba9ba83f..8d24f7e6c 100644 --- a/cmd/vendor_package.go +++ b/cmd/vendor_package.go @@ -33,7 +33,7 @@ func (c VendorPackageCmd) Run(opts VendorPackageOpts) error { for _, pkg := range srcRelease.Packages() { if pkg.Name() == opts.Args.PackageName { - return dstReleaseDir.VendorPackage(pkg) + return dstReleaseDir.VendorPackage(pkg, opts.Prefix) } } diff --git a/release/pkg/package.go b/release/pkg/package.go index 2c16a7293..81ae3f46a 100644 --- a/release/pkg/package.go +++ b/release/pkg/package.go @@ -17,6 +17,7 @@ func (a ByName) Less(i, j int) bool { return a[i].Name() < a[j].Name() } type Package struct { resource Resource + prefix string Dependencies []*Package dependencyNames []string @@ -63,7 +64,10 @@ func (p *Package) RehashWithCalculator(calculator crypto.DigestCalculator, archi } func (p *Package) Build(dev, final ArchiveIndex) error { return p.resource.Build(dev, final) } -func (p *Package) Finalize(final ArchiveIndex) error { return p.resource.Finalize(final) } +func (p *Package) Finalize(final ArchiveIndex) error { + p.resource.Prefix(p.prefix) + return p.resource.Finalize(final) +} func (p *Package) AttachDependencies(packages []*Package) error { for _, pkgName := range p.dependencyNames { @@ -99,7 +103,9 @@ func (p *Package) Deps() []Compilable { func (p *Package) IsCompiled() bool { return false } func (p *Package) ExtractedPath() string { return p.extractedPath } - +func (p *Package) Prefix(prefix string) { + p.prefix = prefix +} func (p *Package) CleanUp() error { if p.fs != nil && len(p.extractedPath) > 0 { return p.fs.RemoveAll(p.extractedPath) diff --git a/release/resource/interfaces.go b/release/resource/interfaces.go index 3740e3780..4d6111735 100644 --- a/release/resource/interfaces.go +++ b/release/resource/interfaces.go @@ -36,6 +36,7 @@ type ArchiveIndex interface { type Resource interface { Name() string + Prefix(prefix string) Fingerprint() string ArchivePath() string diff --git a/release/resource/resource.go b/release/resource/resource.go index 32d811898..777bd186e 100644 --- a/release/resource/resource.go +++ b/release/resource/resource.go @@ -12,6 +12,7 @@ import ( type ResourceImpl struct { name string + prefix string fingerprint string archivePath string @@ -52,13 +53,21 @@ func NewResourceWithBuiltArchive(name, fp, path, sha1 string) *ResourceImpl { } } -func (r *ResourceImpl) Name() string { return r.name } +func (r *ResourceImpl) Name() string { + if r.prefix != "" { + return fmt.Sprintf("%s-%s", r.prefix, r.name) + } + return r.name +} +func (r *ResourceImpl) Prefix(prefix string) { + r.prefix = prefix +} func (r *ResourceImpl) Fingerprint() string { return r.fingerprint } func (r *ResourceImpl) ArchivePath() string { if len(r.archivePath) == 0 { errMsg := "Internal inconsistency: Resource '%s/%s' must be found or built before getting its archive path" - panic(fmt.Sprintf(errMsg, r.name, r.fingerprint)) + panic(fmt.Sprintf(errMsg, r.Name(), r.fingerprint)) } return r.archivePath } @@ -66,7 +75,7 @@ func (r *ResourceImpl) ArchivePath() string { func (r *ResourceImpl) ArchiveDigest() string { if len(r.archiveDigest) == 0 { errMsg := "Internal inconsistency: Resource '%s/%s' must be found or built before getting its archive SHA1" - panic(fmt.Sprintf(errMsg, r.name, r.fingerprint)) + panic(fmt.Sprintf(errMsg, r.Name(), r.fingerprint)) } return r.archiveDigest } @@ -107,15 +116,16 @@ func (r *ResourceImpl) Build(devIndex, finalIndex ArchiveIndex) error { } func (r *ResourceImpl) Finalize(finalIndex ArchiveIndex) error { - finalPath, finalSHA1, err := finalIndex.Find(r.name, r.fingerprint) + finalPath, finalSHA1, err := finalIndex.Find(r.Name(), r.fingerprint) if err != nil { return err } else if len(finalPath) > 0 { + r.attachArchive(finalPath, finalSHA1) return nil } - _, _, err = finalIndex.Add(r.name, r.fingerprint, r.ArchivePath(), r.ArchiveDigest()) + _, _, err = finalIndex.Add(r.Name(), r.fingerprint, r.ArchivePath(), r.ArchiveDigest()) de, ok := err.(duplicateError) if ok && de.IsDuplicate() { return r.Finalize(finalIndex) diff --git a/release/resource/resourcefakes/fake_resource.go b/release/resource/resourcefakes/fake_resource.go index d42812ed6..857bc1777 100644 --- a/release/resource/resourcefakes/fake_resource.go +++ b/release/resource/resourcefakes/fake_resource.go @@ -73,6 +73,11 @@ type FakeResource struct { nameReturnsOnCall map[int]struct { result1 string } + PrefixStub func(string) + prefixMutex sync.RWMutex + prefixArgsForCall []struct { + arg1 string + } RehashWithCalculatorStub func(crypto.DigestCalculator, cryptoa.ArchiveDigestFilePathReader) (resource.Resource, error) rehashWithCalculatorMutex sync.RWMutex rehashWithCalculatorArgsForCall []struct { @@ -426,6 +431,38 @@ func (fake *FakeResource) NameReturnsOnCall(i int, result1 string) { }{result1} } +func (fake *FakeResource) Prefix(arg1 string) { + fake.prefixMutex.Lock() + fake.prefixArgsForCall = append(fake.prefixArgsForCall, struct { + arg1 string + }{arg1}) + stub := fake.PrefixStub + fake.recordInvocation("Prefix", []interface{}{arg1}) + fake.prefixMutex.Unlock() + if stub != nil { + fake.PrefixStub(arg1) + } +} + +func (fake *FakeResource) PrefixCallCount() int { + fake.prefixMutex.RLock() + defer fake.prefixMutex.RUnlock() + return len(fake.prefixArgsForCall) +} + +func (fake *FakeResource) PrefixCalls(stub func(string)) { + fake.prefixMutex.Lock() + defer fake.prefixMutex.Unlock() + fake.PrefixStub = stub +} + +func (fake *FakeResource) PrefixArgsForCall(i int) string { + fake.prefixMutex.RLock() + defer fake.prefixMutex.RUnlock() + argsForCall := fake.prefixArgsForCall[i] + return argsForCall.arg1 +} + func (fake *FakeResource) RehashWithCalculator(arg1 crypto.DigestCalculator, arg2 cryptoa.ArchiveDigestFilePathReader) (resource.Resource, error) { fake.rehashWithCalculatorMutex.Lock() ret, specificReturn := fake.rehashWithCalculatorReturnsOnCall[len(fake.rehashWithCalculatorArgsForCall)] @@ -506,6 +543,8 @@ func (fake *FakeResource) Invocations() map[string][][]interface{} { defer fake.fingerprintMutex.RUnlock() fake.nameMutex.RLock() defer fake.nameMutex.RUnlock() + fake.prefixMutex.RLock() + defer fake.prefixMutex.RUnlock() fake.rehashWithCalculatorMutex.RLock() defer fake.rehashWithCalculatorMutex.RUnlock() copiedInvocations := map[string][][]interface{}{} diff --git a/releasedir/fs_release_dir.go b/releasedir/fs_release_dir.go index aaec18f8a..01d44603e 100644 --- a/releasedir/fs_release_dir.go +++ b/releasedir/fs_release_dir.go @@ -236,13 +236,14 @@ func (d FSReleaseDir) BuildRelease(name string, version semver.Version, force bo return release, nil } -func (d FSReleaseDir) VendorPackage(pkg *boshpkg.Package) error { +func (d FSReleaseDir) VendorPackage(pkg *boshpkg.Package, prefix string) error { allInterestingPkgs := map[*boshpkg.Package]struct{}{} - d.collectDependentPackages(pkg, allInterestingPkgs) for pkg2 := range allInterestingPkgs { + pkg2.Prefix(prefix) err := pkg2.Finalize(d.finalIndicies.Packages) + if err != nil { return bosherr.WrapErrorf(err, "Finalizing vendored package") } diff --git a/releasedir/fs_release_dir_test.go b/releasedir/fs_release_dir_test.go index bb8a2463d..f63bb230b 100644 --- a/releasedir/fs_release_dir_test.go +++ b/releasedir/fs_release_dir_test.go @@ -15,6 +15,7 @@ import ( boshman "github.com/cloudfoundry/bosh-cli/v7/release/manifest" boshpkg "github.com/cloudfoundry/bosh-cli/v7/release/pkg" fakerel "github.com/cloudfoundry/bosh-cli/v7/release/releasefakes" + "github.com/cloudfoundry/bosh-cli/v7/release/resource" fakeres "github.com/cloudfoundry/bosh-cli/v7/release/resource/resourcefakes" . "github.com/cloudfoundry/bosh-cli/v7/releasedir" fakereldir "github.com/cloudfoundry/bosh-cli/v7/releasedir/releasedirfakes" @@ -662,7 +663,7 @@ var _ = Describe("FSGenerator", func() { Expect(fs.WriteFileString("/dir/packages/pkg1-name/packaging", "old-packaging")).ToNot(HaveOccurred()) Expect(fs.WriteFileString("/dir/packages/pkg2-name/spec.lock", "old-spec-lock")).ToNot(HaveOccurred()) - err = releaseDir.VendorPackage(pkg1) + err = releaseDir.VendorPackage(pkg1, "") Expect(err).ToNot(HaveOccurred()) // recorded files @@ -707,6 +708,17 @@ fingerprint: pkg4-fp Expect(pkg4Res.FinalizeArgsForCall(0) == finalIndicies.Packages).To(BeTrue()) }) + It("finalize given package with prefix", func() { + pkg1Res := resource.NewResourceWithBuiltArchive("pkg1-name", "pkg1-fp", "/test/something", "something") + pkg1 := boshpkg.NewPackage(pkg1Res, nil) + + err := releaseDir.VendorPackage(pkg1, "prefix") + Expect(err).ToNot(HaveOccurred()) + Expect(fs.ReadFileString("/dir/packages/prefix-pkg1-name/spec.lock")).To(Equal(`name: prefix-pkg1-name +fingerprint: pkg1-fp +`)) + }) + It("returns error if package finalize fails", func() { pkg1Res := &fakeres.FakeResource{ NameStub: func() string { return "pkg1-name" }, @@ -716,7 +728,7 @@ fingerprint: pkg4-fp pkg1Res.FinalizeReturns(errors.New("fake-err")) - err := releaseDir.VendorPackage(pkg1) + err := releaseDir.VendorPackage(pkg1, "") Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-err")) }) @@ -730,7 +742,7 @@ fingerprint: pkg4-fp fs.RemoveAllStub = func(path string) error { return errors.New("fake-err") } - err := releaseDir.VendorPackage(pkg1) + err := releaseDir.VendorPackage(pkg1, "") Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-err")) }) @@ -741,7 +753,7 @@ fingerprint: pkg4-fp } pkg1 := boshpkg.NewPackage(pkg1Res, nil) - err := releaseDir.VendorPackage(pkg1) + err := releaseDir.VendorPackage(pkg1, "") Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Marshaling vendored package 'pkg1-name' spec lock")) }) @@ -755,7 +767,7 @@ fingerprint: pkg4-fp fs.WriteFileErrors["/dir/packages/pkg1-name/spec.lock"] = errors.New("fake-err") - err := releaseDir.VendorPackage(pkg1) + err := releaseDir.VendorPackage(pkg1, "") Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-err")) }) diff --git a/releasedir/interfaces.go b/releasedir/interfaces.go index 179fcbf98..0de1522c9 100644 --- a/releasedir/interfaces.go +++ b/releasedir/interfaces.go @@ -38,7 +38,7 @@ type ReleaseDir interface { // BuildRelease builds a new version of the Release // from the release directory by looking at jobs, packages, etc. directories. BuildRelease(name string, version semver.Version, force bool) (boshrel.Release, error) - VendorPackage(*boshpkg.Package) error + VendorPackage(pkg *boshpkg.Package, prefix string) error // FinalizeRelease adds the Release to the final list so that it's consumable by others. FinalizeRelease(release boshrel.Release, force bool) error diff --git a/releasedir/releasedirfakes/fake_release_dir.go b/releasedir/releasedirfakes/fake_release_dir.go index dd70ef93d..fe882383f 100644 --- a/releasedir/releasedirfakes/fake_release_dir.go +++ b/releasedir/releasedirfakes/fake_release_dir.go @@ -134,10 +134,11 @@ type FakeReleaseDir struct { resetReturnsOnCall map[int]struct { result1 error } - VendorPackageStub func(*pkg.Package) error + VendorPackageStub func(*pkg.Package, string) error vendorPackageMutex sync.RWMutex vendorPackageArgsForCall []struct { arg1 *pkg.Package + arg2 string } vendorPackageReturns struct { result1 error @@ -763,18 +764,19 @@ func (fake *FakeReleaseDir) ResetReturnsOnCall(i int, result1 error) { }{result1} } -func (fake *FakeReleaseDir) VendorPackage(arg1 *pkg.Package) error { +func (fake *FakeReleaseDir) VendorPackage(arg1 *pkg.Package, arg2 string) error { fake.vendorPackageMutex.Lock() ret, specificReturn := fake.vendorPackageReturnsOnCall[len(fake.vendorPackageArgsForCall)] fake.vendorPackageArgsForCall = append(fake.vendorPackageArgsForCall, struct { arg1 *pkg.Package - }{arg1}) + arg2 string + }{arg1, arg2}) stub := fake.VendorPackageStub fakeReturns := fake.vendorPackageReturns - fake.recordInvocation("VendorPackage", []interface{}{arg1}) + fake.recordInvocation("VendorPackage", []interface{}{arg1, arg2}) fake.vendorPackageMutex.Unlock() if stub != nil { - return stub(arg1) + return stub(arg1, arg2) } if specificReturn { return ret.result1 @@ -788,17 +790,17 @@ func (fake *FakeReleaseDir) VendorPackageCallCount() int { return len(fake.vendorPackageArgsForCall) } -func (fake *FakeReleaseDir) VendorPackageCalls(stub func(*pkg.Package) error) { +func (fake *FakeReleaseDir) VendorPackageCalls(stub func(*pkg.Package, string) error) { fake.vendorPackageMutex.Lock() defer fake.vendorPackageMutex.Unlock() fake.VendorPackageStub = stub } -func (fake *FakeReleaseDir) VendorPackageArgsForCall(i int) *pkg.Package { +func (fake *FakeReleaseDir) VendorPackageArgsForCall(i int) (*pkg.Package, string) { fake.vendorPackageMutex.RLock() defer fake.vendorPackageMutex.RUnlock() argsForCall := fake.vendorPackageArgsForCall[i] - return argsForCall.arg1 + return argsForCall.arg1, argsForCall.arg2 } func (fake *FakeReleaseDir) VendorPackageReturns(result1 error) {