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  }