github.com/kubri/kubri@v0.5.1-0.20240317001612-bda2aaef967e/source/source.go (about) 1 package source 2 3 import ( 4 "context" 5 "log" 6 "sort" 7 "time" 8 9 "golang.org/x/mod/semver" 10 11 "github.com/kubri/kubri/pkg/slices" 12 "github.com/kubri/kubri/pkg/version" 13 ) 14 15 type Release struct { 16 Name string 17 Description string 18 Date time.Time 19 Version string 20 Prerelease bool 21 Assets []*Asset 22 } 23 24 type Asset struct { 25 Name string 26 URL string 27 Size int 28 } 29 30 type Driver interface { 31 GetRelease(ctx context.Context, version string) (*Release, error) 32 ListReleases(ctx context.Context) ([]*Release, error) 33 DownloadAsset(ctx context.Context, version, name string) ([]byte, error) 34 UploadAsset(ctx context.Context, version, name string, data []byte) error 35 } 36 37 type Source struct { 38 s Driver 39 } 40 41 func New(driver Driver) *Source { 42 return &Source{s: driver} 43 } 44 45 type ListOptions struct { 46 // Version constraint e.g. 'v1.2.4', 'v1', '>= v1.1.0, < v2.1' 47 Version string 48 49 // Include pre-releases 50 Prerelease bool 51 } 52 53 func (s *Source) ListReleases(ctx context.Context, opt *ListOptions) ([]*Release, error) { 54 if s == nil || s.s == nil { 55 return nil, ErrMissingSource 56 } 57 58 var constraint version.Constraint 59 if opt != nil && opt.Version != "" && opt.Version != "latest" { 60 c, err := version.NewConstraint(opt.Version) 61 if err != nil { 62 return nil, err 63 } 64 constraint = c 65 } 66 67 releases, err := s.s.ListReleases(ctx) 68 if err != nil { 69 return nil, err 70 } 71 72 releases = slices.Filter(releases, func(r *Release) bool { 73 if !semver.IsValid(r.Version) { 74 log.Println("Skipping invalid version:", r.Version) 75 return false 76 } 77 78 if !constraint.Check(r.Version) { 79 log.Println("Skipping excluded version:", r.Version) 80 return false 81 } 82 83 if (opt == nil || !opt.Prerelease) && semver.Prerelease(r.Version) != "" { 84 log.Println("Skipping prerelease:", r.Version) 85 return false 86 } 87 88 processRelease(r) 89 return true 90 }) 91 92 if len(releases) == 0 { 93 return nil, ErrNoReleaseFound 94 } 95 96 sort.Sort(ByVersion(releases)) 97 98 if opt != nil && opt.Version == "latest" { 99 return releases[:1], nil 100 } 101 102 return releases, nil 103 } 104 105 func (s *Source) GetRelease(ctx context.Context, version string) (*Release, error) { 106 if s == nil || s.s == nil { 107 return nil, ErrMissingSource 108 } 109 110 r, err := s.s.GetRelease(ctx, version) 111 if err != nil { 112 return nil, err 113 } 114 115 processRelease(r) 116 117 return r, nil 118 } 119 120 func (s *Source) DownloadAsset(ctx context.Context, version, name string) ([]byte, error) { 121 if s == nil || s.s == nil { 122 return nil, ErrMissingSource 123 } 124 125 return s.s.DownloadAsset(ctx, version, name) 126 } 127 128 func (s *Source) UploadAsset(ctx context.Context, version, name string, data []byte) error { 129 if s == nil || s.s == nil { 130 return ErrMissingSource 131 } 132 133 return s.s.UploadAsset(ctx, version, name, data) 134 } 135 136 func processRelease(r *Release) { 137 if r.Name == "" { 138 r.Name = r.Version 139 } 140 if !r.Prerelease { 141 r.Prerelease = semver.Prerelease(r.Version) != "" 142 } 143 }