@@ -2,6 +2,7 @@ package installer
22
33import (
44 "fmt"
5+ "path"
56 "path/filepath"
67 "runtime"
78 "strings"
@@ -42,6 +43,10 @@ func (i *Installer) buildAssetURLForPlatform(tool *registry.Tool, version, goos,
4243 return i .buildHTTPAssetURLForPlatform (tool , version , goos , goarch )
4344 case "github_release" :
4445 return i .buildGitHubReleaseURLForPlatform (tool , version , goos , goarch )
46+ case "github_archive" :
47+ return i .buildGitHubArchiveURL (tool , version )
48+ case "github_content" :
49+ return i .buildGitHubContentURL (tool , version )
4550 default :
4651 return "" , fmt .Errorf ("%w: unsupported tool type: %s" , ErrInvalidToolSpec , tool .Type )
4752 }
@@ -100,6 +105,61 @@ func (i *Installer) buildGitHubReleaseURLForPlatform(tool *registry.Tool, versio
100105 return url , nil
101106}
102107
108+ // buildGitHubArchiveURL builds an asset URL for github_archive type tools.
109+ // Matches upstream aquaproj/aqua behavior: always uses GitHub's tag archive endpoint
110+ // with .tar.gz format. The Asset, URL, Format, and FormatOverrides fields are
111+ // intentionally ignored (Aqua's GetFormat() hardcodes "tar.gz" for github_archive).
112+ // See: https://github.com/aquaproj/aqua/blob/main/pkg/download/github_archive.go.
113+ func (i * Installer ) buildGitHubArchiveURL (tool * registry.Tool , version string ) (string , error ) {
114+ defer perf .Track (nil , "Installer.buildGitHubArchiveURL" )()
115+
116+ if tool .RepoOwner == "" || tool .RepoName == "" {
117+ return "" , fmt .Errorf ("%w: RepoOwner and RepoName must be set for github_archive type (got RepoOwner=%q, RepoName=%q)" ,
118+ ErrInvalidToolSpec , tool .RepoOwner , tool .RepoName )
119+ }
120+
121+ data := buildTemplateData (tool , version )
122+ return fmt .Sprintf ("https://github.com/%s/%s/archive/refs/tags/%s.tar.gz" ,
123+ tool .RepoOwner , tool .RepoName , data .Version ), nil
124+ }
125+
126+ // buildGitHubContentURL builds an asset URL for github_content type tools.
127+ // Matches upstream aquaproj/aqua behavior: downloads a single file from a repo
128+ // at a tag via raw.githubusercontent.com. The Asset, URL, Format, and
129+ // FormatOverrides fields are intentionally ignored for this type.
130+ // See: https://github.com/aquaproj/aqua/blob/main/pkg/download/github_content.go.
131+ func (i * Installer ) buildGitHubContentURL (tool * registry.Tool , version string ) (string , error ) {
132+ defer perf .Track (nil , "Installer.buildGitHubContentURL" )()
133+
134+ if err := validateGitHubContentFields (tool ); err != nil {
135+ return "" , err
136+ }
137+ data := buildTemplateData (tool , version )
138+ return formatGitHubContentURL (tool .RepoOwner , tool .RepoName , data .Version , tool .Path ), nil
139+ }
140+
141+ // validateGitHubContentFields verifies that a github_content tool has the
142+ // required RepoOwner, RepoName, and Path fields. Pure function: no I/O, no state.
143+ func validateGitHubContentFields (tool * registry.Tool ) error {
144+ if tool .RepoOwner == "" || tool .RepoName == "" || tool .Path == "" {
145+ return fmt .Errorf ("%w: RepoOwner, RepoName, and Path must be set for github_content type (got RepoOwner=%q, RepoName=%q, Path=%q)" ,
146+ ErrInvalidToolSpec , tool .RepoOwner , tool .RepoName , tool .Path )
147+ }
148+ // Path is a repo-relative URL segment (always forward-slash, regardless of
149+ // host OS), so use the "path" package rather than "path/filepath" here.
150+ if path .IsAbs (tool .Path ) || strings .Contains (tool .Path , ".." ) {
151+ return fmt .Errorf ("%w: Path must be a relative repository path for github_content type (got Path=%q)" ,
152+ ErrInvalidToolSpec , tool .Path )
153+ }
154+ return nil
155+ }
156+
157+ // formatGitHubContentURL formats a raw.githubusercontent.com URL from its
158+ // component parts. Pure function: no inputs beyond the parameters.
159+ func formatGitHubContentURL (owner , repo , version , path string ) string {
160+ return fmt .Sprintf ("https://raw.githubusercontent.com/%s/%s/%s/%s" , owner , repo , version , path )
161+ }
162+
103163// archiveExtensions contains known archive file extensions.
104164var archiveExtensions = []string {
105165 ".tar.gz" , ".tgz" , ".zip" , ".gz" ,
0 commit comments