diff --git a/internal/archive/archive.go b/internal/archive/archive.go index d301494b..1d3f1af6 100644 --- a/internal/archive/archive.go +++ b/internal/archive/archive.go @@ -32,13 +32,6 @@ type PackageInfo struct { SHA256 string } -func (p *PackageInfo) PkgName() string { return p.Name } -func (p *PackageInfo) PkgVersion() string { return p.Version } -func (p *PackageInfo) PkgRevision() int { return 0 } -func (p *PackageInfo) PkgArch() string { return p.Arch } -func (p *PackageInfo) PkgDigestKind() cache.DigestKind { return cache.SHA256 } -func (p *PackageInfo) PkgDigest() string { return p.SHA256 } - type Options struct { Label string Version string diff --git a/internal/manifestutil/manifestutil.go b/internal/manifestutil/manifestutil.go index 3cf4db75..2959ce8a 100644 --- a/internal/manifestutil/manifestutil.go +++ b/internal/manifestutil/manifestutil.go @@ -16,8 +16,6 @@ import ( "github.com/canonical/chisel/public/manifest" ) -// PackageInfo describes a package as obtained from its source, abstracting -// over archives, stores, and any other backend. type PackageInfo interface { PkgName() string PkgVersion() string @@ -26,6 +24,7 @@ type PackageInfo interface { // revisions. PkgRevision() int PkgArch() string + PkgStore() string PkgDigestKind() cache.DigestKind PkgDigest() string } diff --git a/internal/manifestutil/manifestutil_test.go b/internal/manifestutil/manifestutil_test.go index e7e68752..ec9bb339 100644 --- a/internal/manifestutil/manifestutil_test.go +++ b/internal/manifestutil/manifestutil_test.go @@ -12,7 +12,7 @@ import ( . "gopkg.in/check.v1" "github.com/canonical/chisel/internal/apachetestutil" - "github.com/canonical/chisel/internal/archive" + "github.com/canonical/chisel/internal/cache" "github.com/canonical/chisel/internal/manifestutil" "github.com/canonical/chisel/internal/setup" "github.com/canonical/chisel/public/manifest" @@ -119,6 +119,24 @@ var slice2 = &setup.Slice{ Name: "slice2", } +type testPackageInfo struct { + Name string + Version string + Revision int + Arch string + Store string + DigestKind cache.DigestKind + Digest string +} + +func (p *testPackageInfo) PkgName() string { return p.Name } +func (p *testPackageInfo) PkgVersion() string { return p.Version } +func (p *testPackageInfo) PkgRevision() int { return p.Revision } +func (p *testPackageInfo) PkgArch() string { return p.Arch } +func (p *testPackageInfo) PkgStore() string { return p.Store } +func (p *testPackageInfo) PkgDigestKind() cache.DigestKind { return p.DigestKind } +func (p *testPackageInfo) PkgDigest() string { return p.Digest } + var generateManifestTests = []struct { summary string report *manifestutil.Report @@ -149,17 +167,19 @@ var generateManifestTests = []struct { }, }, packageInfo: []manifestutil.PackageInfo{ - &archive.PackageInfo{ - Name: "package1", - Version: "v1", - Arch: "a1", - SHA256: "s1", + &testPackageInfo{ + Name: "package1", + Version: "v1", + Arch: "a1", + DigestKind: cache.SHA256, + Digest: "s1", }, - &archive.PackageInfo{ - Name: "package2", - Version: "v2", - Arch: "a2", - SHA256: "s2", + &testPackageInfo{ + Name: "package2", + Version: "v2", + Arch: "a2", + DigestKind: cache.SHA256, + Digest: "s2", }, }, expected: &apachetestutil.ManifestContents{ @@ -399,11 +419,12 @@ var generateManifestTests = []struct { }, }, packageInfo: []manifestutil.PackageInfo{ - &archive.PackageInfo{ - Name: "package1", - Version: "v1", - Arch: "a1", - SHA256: "s1", + &testPackageInfo{ + Name: "package1", + Version: "v1", + Arch: "a1", + DigestKind: cache.SHA256, + Digest: "s1", }, }, expected: &apachetestutil.ManifestContents{ @@ -500,37 +521,40 @@ var generateManifestTests = []struct { }, { summary: "Invalid package: missing name", packageInfo: []manifestutil.PackageInfo{ - &archive.PackageInfo{ - Version: "v1", - Arch: "a1", - SHA256: "s1", + &testPackageInfo{ + Version: "v1", + Arch: "a1", + DigestKind: cache.SHA256, + Digest: "s1", }, }, error: `internal error: invalid manifest: package name not set`, }, { summary: "Invalid package: missing version", packageInfo: []manifestutil.PackageInfo{ - &archive.PackageInfo{ - Name: "package-1", - Arch: "a1", - SHA256: "s1", + &testPackageInfo{ + Name: "package-1", + Arch: "a1", + DigestKind: cache.SHA256, + Digest: "s1", }, }, error: `internal error: invalid manifest: package "package-1" missing version`, }, { summary: "Invalid package: missing arch", packageInfo: []manifestutil.PackageInfo{ - &archive.PackageInfo{ - Name: "package-1", - Version: "v1", - SHA256: "s1", + &testPackageInfo{ + Name: "package-1", + Version: "v1", + DigestKind: cache.SHA256, + Digest: "s1", }, }, error: `internal error: invalid manifest: package "package-1" missing arch`, }, { summary: "Invalid package: missing sha256", packageInfo: []manifestutil.PackageInfo{ - &archive.PackageInfo{ + &testPackageInfo{ Name: "package-1", Version: "v1", Arch: "a1", @@ -547,11 +571,12 @@ func (s *S) TestGenerateManifests(c *C) { } if test.packageInfo == nil { test.packageInfo = []manifestutil.PackageInfo{ - &archive.PackageInfo{ - Name: "package1", - Version: "v1", - Arch: "a1", - SHA256: "s1", + &testPackageInfo{ + Name: "package1", + Version: "v1", + Arch: "a1", + DigestKind: cache.SHA256, + Digest: "s1", }, } } diff --git a/internal/slicer/package_remote.go b/internal/slicer/package_remote.go new file mode 100644 index 00000000..0306556f --- /dev/null +++ b/internal/slicer/package_remote.go @@ -0,0 +1,62 @@ +package slicer + +import ( + "io" + + "github.com/canonical/chisel/internal/archive" + "github.com/canonical/chisel/internal/cache" +) + +// RemotePackageInfo describes a package as reported by its provider. +type RemotePackageInfo struct { + Name string + Version string + Revision int + Arch string + Store string + DigestKind cache.DigestKind + Digest string +} + +func (p *RemotePackageInfo) PkgName() string { return p.Name } +func (p *RemotePackageInfo) PkgVersion() string { return p.Version } +func (p *RemotePackageInfo) PkgRevision() int { return p.Revision } +func (p *RemotePackageInfo) PkgArch() string { return p.Arch } +func (p *RemotePackageInfo) PkgStore() string { return p.Store } +func (p *RemotePackageInfo) PkgDigestKind() cache.DigestKind { return p.DigestKind } +func (p *RemotePackageInfo) PkgDigest() string { return p.Digest } + +// PackageRemote represents the remote from which a package is obtained. +type PackageRemote interface { + // Arch returns the architecture the remote serves packages for, which is + // the target architecture used to request the package, not the + // architecture of the fetched package itself (which may be "all", for + // example). + Arch() string + Fetch() (io.ReadSeekCloser, *RemotePackageInfo, error) +} + +var _ PackageRemote = (*archiveRemote)(nil) + +type archiveRemote struct { + archive archive.Archive + name string +} + +func (d *archiveRemote) Arch() string { + return d.archive.Options().Arch +} + +func (d *archiveRemote) Fetch() (io.ReadSeekCloser, *RemotePackageInfo, error) { + reader, info, err := d.archive.Fetch(d.name) + if err != nil { + return nil, nil, err + } + return reader, &RemotePackageInfo{ + Name: info.Name, + Version: info.Version, + Arch: info.Arch, + DigestKind: cache.SHA256, + Digest: info.SHA256, + }, nil +} diff --git a/internal/slicer/slicer.go b/internal/slicer/slicer.go index ce791162..7a5e8bf9 100644 --- a/internal/slicer/slicer.go +++ b/internal/slicer/slicer.go @@ -90,7 +90,7 @@ func Run(options *RunOptions) error { targetDir = filepath.Join(dir, targetDir) } - pkgArchive, err := selectPkgArchives(options.Archives, options.Selection) + pkgRemotes, err := selectPkgRemotes(options.Archives, options.Selection) if err != nil { return err } @@ -108,7 +108,7 @@ func Run(options *RunOptions) error { extractPackage = make(map[string][]tarball.ExtractInfo) extract[slice.Package] = extractPackage } - arch := pkgArchive[slice.Package].Options().Arch + arch := pkgRemotes[slice.Package].Arch() for targetPath, pathInfo := range slice.Contents { if targetPath == "" { continue @@ -153,7 +153,7 @@ func Run(options *RunOptions) error { continue } pkg := options.Selection.Release.Packages[slice.Package] - reader, info, err := pkgArchive[slice.Package].Fetch(pkg.RealName) + reader, info, err := pkgRemotes[pkg.Name].Fetch() if err != nil { return err } @@ -270,7 +270,7 @@ func Run(options *RunOptions) error { // them to the appropriate slices. relPaths := map[string][]*setup.Slice{} for _, slice := range options.Selection.Slices { - arch := pkgArchive[slice.Package].Options().Arch + arch := pkgRemotes[slice.Package].Arch() for relPath, pathInfo := range slice.Contents { if len(pathInfo.Arch) > 0 && !slices.Contains(pathInfo.Arch, arch) { continue @@ -490,10 +490,12 @@ func createFile(targetDir, relPath string, pathInfo setup.PathInfo) (*fsutil.Ent }) } -// selectPkgArchives selects the highest priority archive containing the package -// unless a particular archive is pinned within the slice definition file. It -// returns a map of archives indexed by package names. -func selectPkgArchives(archives map[string]archive.Archive, selection *setup.Selection) (map[string]archive.Archive, error) { +// selectPkgRemotes determines the remote for each package in the selection. +// For packages from an archive it selects the highest priority archive +// containing the package unless a particular archive is pinned within the +// package slices file. Packages from a store are not supported yet. +// It returns a map of PackageRemote indexed by package names. +func selectPkgRemotes(archives map[string]archive.Archive, selection *setup.Selection) (map[string]PackageRemote, error) { sortedArchives := make([]*setup.Archive, 0, len(selection.Release.Archives)) for _, archive := range selection.Release.Archives { if archive.Priority < 0 { @@ -507,9 +509,9 @@ func selectPkgArchives(archives map[string]archive.Archive, selection *setup.Sel return b.Priority - a.Priority }) - pkgArchive := make(map[string]archive.Archive) + pkgRemotes := make(map[string]PackageRemote) for _, s := range selection.Slices { - if _, ok := pkgArchive[s.Package]; ok { + if _, ok := pkgRemotes[s.Package]; ok { continue } pkg := selection.Release.Packages[s.Package] @@ -538,7 +540,10 @@ func selectPkgArchives(archives map[string]archive.Archive, selection *setup.Sel if chosen == nil { return nil, fmt.Errorf("cannot find package %q in archive(s)", pkg.RealName) } - pkgArchive[pkg.Name] = chosen + pkgRemotes[pkg.Name] = &archiveRemote{ + archive: chosen, + name: pkg.RealName, + } } - return pkgArchive, nil + return pkgRemotes, nil }