get.porter.sh/porter@v1.3.0/pkg/pkgmgmt/feed/feed.go (about) 1 package feed 2 3 import ( 4 "context" 5 "fmt" 6 "net/url" 7 "strings" 8 "time" 9 10 "get.porter.sh/porter/pkg/portercontext" 11 "get.porter.sh/porter/pkg/tracing" 12 "github.com/Masterminds/semver/v3" 13 ) 14 15 type MixinFeed struct { 16 *portercontext.Context 17 18 // Index of mixin files 19 Index map[string]map[string]*MixinFileset 20 21 // Mixins present in the feed 22 Mixins []string 23 24 // Updated timestamp according to the atom xml feed 25 Updated *time.Time 26 } 27 28 func NewMixinFeed(cxt *portercontext.Context) *MixinFeed { 29 return &MixinFeed{ 30 Index: make(map[string]map[string]*MixinFileset), 31 Context: cxt, 32 } 33 } 34 35 func (feed *MixinFeed) Search(mixin string, version string) *MixinFileset { 36 versions, ok := feed.Index[mixin] 37 if !ok { 38 return nil 39 } 40 41 fileset, ok := versions[version] 42 if ok { 43 return fileset 44 } 45 46 // Return the highest version of the requested mixin according to semver, ignoring pre-releases 47 if version == "latest" { 48 var latestVersion *semver.Version 49 for version := range versions { 50 v, err := semver.NewVersion(version) 51 if err != nil { 52 continue 53 } 54 if v.Prerelease() != "" { 55 continue 56 } 57 if latestVersion == nil || v.GreaterThan(latestVersion) { 58 latestVersion = v 59 } 60 } 61 if latestVersion != nil { 62 return versions[latestVersion.Original()] 63 } 64 } 65 66 return nil 67 } 68 69 type MixinFileset struct { 70 Mixin string 71 Version string 72 Files []*MixinFile 73 } 74 75 func (f *MixinFileset) FindDownloadURL(ctx context.Context, os string, arch string) *url.URL { 76 log := tracing.LoggerFromContext(ctx) 77 78 match := fmt.Sprintf("%s-%s-%s", f.Mixin, os, arch) 79 for _, file := range f.Files { 80 if strings.Contains(file.URL.Path, match) { 81 return file.URL 82 } 83 } 84 85 // Until we have full support for M1 chipsets, rely on rossetta functionality in macos and use the amd64 binary 86 if os == "darwin" && arch == "arm64" { 87 log.Debugf("%s @ %s did not publish a download for darwin/arm64, falling back to darwin/amd64", f.Mixin, f.Version) 88 return f.FindDownloadURL(ctx, "darwin", "amd64") 89 } 90 91 return nil 92 } 93 94 func (f *MixinFileset) Updated() string { 95 return toAtomTimestamp(f.GetLastUpdated()) 96 } 97 98 func (f *MixinFileset) GetLastUpdated() time.Time { 99 var max time.Time 100 for _, f := range f.Files { 101 if f.Updated.After(max) { 102 max = f.Updated 103 } 104 } 105 return max 106 } 107 108 type MixinFile struct { 109 File string 110 URL *url.URL 111 Updated time.Time 112 } 113 114 // MixinEntries is used to sort the entries in a mixin feed by when they were last updated 115 type MixinEntries []*MixinFileset 116 117 func (e MixinEntries) Len() int { 118 return len(e) 119 } 120 121 func (e MixinEntries) Swap(i, j int) { 122 e[i], e[j] = e[j], e[i] 123 } 124 125 func (e MixinEntries) Less(i, j int) bool { 126 // Sort by LastUpdated, Mixin, Version 127 entryI := e[i] 128 entryJ := e[j] 129 if entryI.GetLastUpdated().Equal(entryJ.GetLastUpdated()) { 130 if entryI.Mixin == entryJ.Mixin { 131 return entryI.Version < entryJ.Version 132 } 133 return entryI.Mixin < entryJ.Mixin 134 } 135 return entryI.GetLastUpdated().Before(entryJ.GetLastUpdated()) 136 }