-
Notifications
You must be signed in to change notification settings - Fork 64
feat: abstract interactions with archive/store #311
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 5 commits
c5d397c
f79521e
a2e22f2
2eb85d0
3004a6e
ed0e070
268501e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -41,6 +41,15 @@ type contentChecker struct { | |
| knownPaths map[string]pathData | ||
| } | ||
|
|
||
| // pkgSource holds the resolved source for a package: its architecture and a | ||
| // fetch function returning the package reader and metadata. The fetch | ||
| // function is bound at resolution time, so callers are agnostic to whether | ||
| // the package comes from an archive or a store. | ||
| type pkgSource struct { | ||
| arch string | ||
| fetch func() (io.ReadSeekCloser, *archive.PackageInfo, error) | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Note to reviewer]: If we adopt this approach,
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See #316
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not completely sure it makes sense to have PackageInfo itself to be extracted to a different package, because by the end of the day an apt package archive has package info data, and this needs to be concretely somewhere. The alternative is that we create a common ground type, but these often end up very messy because the become the union of all needs of all backends. It seems better to extend the approach that we are already pursuing here: interfaces that encapsulate only what actually needs to be common across them. I'll take this comment to continue into a more general direction: this PR as a whole is playing with the right ideas and going into the right direction, but it's not yet nailing a proper encapsulation and abstraction approach to implement what we must. It doesn't make sense for the slider to be the one defining how to fetch packages and how to fetch stores, by injecting a lambda with custom code for either. The slider is precisely the thing that shouldn't care about the detais, and should instead be calling out in a single way towards multiple implementations. So again, you're probably in the right ground, but needs some tuning still.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This is what I experimented on in #316. Today I think it looks reasonable and not too messy thanks to the introduction of the I also tried using an interface and keeping 2 separate concrete types in #320 (the one for bins will be added in the PR fetching bins from the store). It seems more consistent with the overall approach. The main drawback is that as this time the added
I have reworked the approach following your suggestion. It can be further adapted if we proceed with #320. |
||
| } | ||
|
|
||
| func (cc *contentChecker) checkMutable(path string) error { | ||
| if !cc.knownPaths[path].mutable { | ||
| return fmt.Errorf("cannot write file which is not mutable: %s", path) | ||
|
|
@@ -90,7 +99,7 @@ func Run(options *RunOptions) error { | |
| targetDir = filepath.Join(dir, targetDir) | ||
| } | ||
|
|
||
| pkgArchive, err := selectPkgArchives(options.Archives, options.Selection) | ||
| pkgSources, err := resolvePkgSources(options.Archives, options.Selection) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
@@ -108,7 +117,7 @@ func Run(options *RunOptions) error { | |
| extractPackage = make(map[string][]tarball.ExtractInfo) | ||
| extract[slice.Package] = extractPackage | ||
| } | ||
| arch := pkgArchive[slice.Package].Options().Arch | ||
| arch := pkgSources[slice.Package].arch | ||
| for targetPath, pathInfo := range slice.Contents { | ||
| if targetPath == "" { | ||
| continue | ||
|
|
@@ -153,7 +162,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 := pkgSources[pkg.Name].fetch() | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
@@ -270,7 +279,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 := pkgSources[slice.Package].arch | ||
| for relPath, pathInfo := range slice.Contents { | ||
| if len(pathInfo.Arch) > 0 && !slices.Contains(pathInfo.Arch, arch) { | ||
| continue | ||
|
|
@@ -490,10 +499,13 @@ 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) { | ||
| // resolvePkgSources determines the source for each package in the selection. | ||
| // For archive packages it selects the highest priority archive containing the | ||
| // package unless a particular archive is pinned within the slice definition | ||
| // file. For store packages it records a fetch function that returns an error | ||
| // until store support is implemented. It returns a map of pkgSource indexed by | ||
| // package names. | ||
| func resolvePkgSources(archives map[string]archive.Archive, selection *setup.Selection) (map[string]pkgSource, error) { | ||
| sortedArchives := make([]*setup.Archive, 0, len(selection.Release.Archives)) | ||
| for _, archive := range selection.Release.Archives { | ||
| if archive.Priority < 0 { | ||
|
|
@@ -507,15 +519,20 @@ func selectPkgArchives(archives map[string]archive.Archive, selection *setup.Sel | |
| return b.Priority - a.Priority | ||
| }) | ||
|
|
||
| pkgArchive := make(map[string]archive.Archive) | ||
| pkgSources := make(map[string]pkgSource) | ||
| for _, s := range selection.Slices { | ||
| if _, ok := pkgArchive[s.Package]; ok { | ||
| if _, ok := pkgSources[s.Package]; ok { | ||
| continue | ||
| } | ||
| pkg := selection.Release.Packages[s.Package] | ||
|
|
||
| if pkg.Store != "" { | ||
| return nil, fmt.Errorf("cannot fetch package %q from store %q: not implemented", pkg.Name, pkg.Store) | ||
| pkgSources[pkg.Name] = pkgSource{ | ||
| // TODO: set the arch when implementing fetching from the store. | ||
| fetch: func() (io.ReadSeekCloser, *archive.PackageInfo, error) { | ||
| return nil, nil, fmt.Errorf("cannot fetch package %q from store %q: not implemented", pkg.Name, pkg.Store) | ||
| }, | ||
| } | ||
| continue | ||
| } | ||
|
|
||
| var candidates []*setup.Archive | ||
|
|
@@ -538,7 +555,12 @@ 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 | ||
| pkgSources[pkg.Name] = pkgSource{ | ||
| arch: chosen.Options().Arch, | ||
| fetch: func() (io.ReadSeekCloser, *archive.PackageInfo, error) { | ||
| return chosen.Fetch(pkg.RealName) | ||
| }, | ||
| } | ||
| } | ||
| return pkgArchive, nil | ||
| return pkgSources, nil | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Note to reviewer]: This struct could be extracted to a dedicated package and exported since in the future this abstraction might be useful in other packages, such as
cmd_debug_check_release_archives.go.