From 59ea6caf9f476efe6110c7dca5bda644c289c2c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Virtus?= Date: Fri, 5 May 2023 00:44:51 +0200 Subject: [PATCH] Support archive priorities If a package to be downloaded exists in archive A and archive B, and archive A has higher priority than archive B, the package is downloaded from archive A even if archive B has a newer version. If two or more archives have the same priority, the most recent version of the package from all of them is selected, if any. Otherwise, lower priority archives are tried, if any. --- cmd/chisel/cmd_cut.go | 1 + internal/archive/archive.go | 1 + internal/setup/setup.go | 3 ++ internal/slicer/slicer.go | 39 ++++++++++++++- internal/slicer/slicer_test.go | 87 ++++++++++++++++++++++++++++++++++ 5 files changed, 130 insertions(+), 1 deletion(-) diff --git a/cmd/chisel/cmd_cut.go b/cmd/chisel/cmd_cut.go index 2a00b718..02fc9eda 100644 --- a/cmd/chisel/cmd_cut.go +++ b/cmd/chisel/cmd_cut.go @@ -91,6 +91,7 @@ func (cmd *cmdCut) Execute(args []string) error { Suites: archiveInfo.Suites, Components: archiveInfo.Components, CacheDir: cache.DefaultDir("chisel"), + Priority: archiveInfo.Priority, }) if err != nil { return err diff --git a/internal/archive/archive.go b/internal/archive/archive.go index 48777606..97ee208f 100644 --- a/internal/archive/archive.go +++ b/internal/archive/archive.go @@ -34,6 +34,7 @@ type Options struct { Suites []string Components []string CacheDir string + Priority int } func Open(options *Options) (Archive, error) { diff --git a/internal/setup/setup.go b/internal/setup/setup.go index 6f5ffda8..6bc3c2cc 100644 --- a/internal/setup/setup.go +++ b/internal/setup/setup.go @@ -29,6 +29,7 @@ type Archive struct { Version string Suites []string Components []string + Priority int } // Package holds a collection of slices that represent parts of themselves. @@ -321,6 +322,7 @@ type yamlArchive struct { Version string `yaml:"version"` Suites []string `yaml:"suites"` Components []string `yaml:"components"` + Priority int `yaml:"priority"` } type yamlPackage struct { @@ -427,6 +429,7 @@ func parseRelease(baseDir, filePath string, data []byte) (*Release, error) { Version: details.Version, Suites: details.Suites, Components: details.Components, + Priority: details.Priority, } } diff --git a/internal/slicer/slicer.go b/internal/slicer/slicer.go index fd4f1f4c..70c49e08 100644 --- a/internal/slicer/slicer.go +++ b/internal/slicer/slicer.go @@ -5,8 +5,10 @@ import ( "bytes" "fmt" "io" + "math" "os" "path/filepath" + "sort" "strings" "syscall" @@ -69,13 +71,48 @@ func Run(options *RunOptions) error { targetDirAbs = filepath.Join(dir, targetDir) } + // Archives are ordered in descending order by priority. The + // default priority is 0 and the maximum allowed priority is + // the upper limit of int. + // + // If a package to be downloaded exists in archive A and + // archive B, and archive A has higher priority than archive + // B, the package is downloaded from archive A even if archive + // B has a newer version. + // + // If two or more archives have the same priority, the most + // recent version of the package from all of them is selected, + // if any. Otherwise, archives with lower priority are tried, + // if any. + // + // If two or more archives with the same priority contain the + // package with the same version, the first archive from the + // options.Archives iterator is used. In effect, the choice is + // random. + orderedArchives := make([]archive.Archive, 0, len(options.Archives)) + for _, archive := range options.Archives { + orderedArchives = append(orderedArchives, archive) + } + sort.Slice(orderedArchives, func(a, b int) bool { + prioA := orderedArchives[a].Options().Priority + prioB := orderedArchives[b].Options().Priority + return prioA > prioB + }) + // Build information to process the selection. for _, slice := range options.Selection.Slices { extractPackage := extract[slice.Package] if extractPackage == nil { var selectedVersion string var selectedArchive archive.Archive - for _, currentArchive := range options.Archives { + currentPrio := math.MaxInt + for _, currentArchive := range orderedArchives { + if prio := currentArchive.Options().Priority; prio < currentPrio { + if selectedVersion != "" { + break + } + currentPrio = prio + } pkgInfo := currentArchive.Info(slice.Package) if pkgInfo == nil { continue diff --git a/internal/slicer/slicer_test.go b/internal/slicer/slicer_test.go index acc4a093..2cb611f3 100644 --- a/internal/slicer/slicer_test.go +++ b/internal/slicer/slicer_test.go @@ -687,6 +687,92 @@ var slicerTests = []slicerTest{{ "/speed/cheetah": "file 0644 e98b0879", "/speed/ostrich": "file 0644 c8fa2806", }, +}, { + summary: "Pick package from archive with highest priority", + pkgs: map[string]map[string]testPackage{ + "edge": { + "hello": testPackage{ + info: map[string]string{ + "Version": "2.0-beta", + }, + content: testutil.MakeTestDeb([]testutil.TarEntry{ + DIR(0755, "./"), + REG(0644, "./hello", "Hello, The Edge\n"), + }), + }, + }, + "candidate": { + "hello": testPackage{ + info: map[string]string{ + "Version": "1.8", + }, + content: testutil.MakeTestDeb([]testutil.TarEntry{ + DIR(0755, "./"), + REG(0644, "./hello", "Hello, The Candidate\n"), + }), + }, + }, + "stable": { + "hello": testPackage{ + info: map[string]string{ + "Version": "1.2", + }, + content: testutil.MakeTestDeb([]testutil.TarEntry{ + DIR(0755, "./"), + REG(0644, "./hello", "Hello, The Stable\n"), + }), + }, + }, + "obsolete": { + "hello": testPackage{ + info: map[string]string{ + "Version": "1.0", + }, + content: testutil.MakeTestDeb([]testutil.TarEntry{ + DIR(0755, "./"), + REG(0644, "./hello", "Hello, The Obsolete\n"), + }), + }, + }, + }, + release: map[string]string{ + "chisel.yaml": ` + format: chisel-v1 + archives: + edge: + version: 1 + suites: [main] + components: [main] + candidate: + version: 1 + suites: [main] + components: [main] + priority: 5 + stable: + version: 1 + suites: [main] + components: [main] + priority: 10 + obsolete: + version: 1 + suites: [main] + components: [main] + priority: 10 + `, + "slices/mydir/hello.yaml": ` + package: hello + slices: + all: + contents: + /hello: + `, + }, + slices: []setup.SliceKey{ + {"hello", "all"}, + }, + result: map[string]string{ + "/hello": "file 0644 b5621b65", + }, }} const defaultChiselYaml = ` @@ -792,6 +878,7 @@ func (s *S) TestRun(c *C) { Version: setupArchive.Version, Suites: setupArchive.Suites, Components: setupArchive.Components, + Priority: setupArchive.Priority, Arch: test.arch, }, pkgs: archivePkgs,