Skip to content

Commit

Permalink
Adds functionality to krew to download a binary and reference a link …
Browse files Browse the repository at this point in the history
…to a LICENSE file
  • Loading branch information
joshbrgs committed Aug 18, 2023
1 parent d2e660d commit a27046e
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 3 deletions.
24 changes: 22 additions & 2 deletions internal/download/downloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import (
func download(url string, verifier Verifier, fetcher Fetcher) (io.ReaderAt, int64, error) {
body, err := fetcher.Get(url)
if err != nil {
return nil, 0, errors.Wrapf(err, "failed to obtain plugin archive")
return nil, 0, errors.Wrapf(err, "failed to obtain plugin")
}
defer body.Close()

Expand Down Expand Up @@ -161,6 +161,25 @@ func extractTARGZ(targetDir string, at io.ReaderAt, size int64) error {
return nil
}

// Dowloads the given binary to the target directory
func downloadBinary(targetDir string, read io.ReaderAt, size int64) error {
klog.V(4).Infof("Downloading binary to %q", targetDir)

in := io.NewSectionReader(read, 0, size)
buf := make([]byte, size)

if _, err := in.Read(buf); err != nil {
return errors.Wrap(err, "failed to read binary")
}

if err := os.WriteFile(filepath.Join(targetDir, "binary"), buf, 0o755); err != nil {
return errors.Wrap(err, "failed to write binary")
}

klog.V(4).Infof("download of binary complete to %s complete", targetDir)
return nil
}

func suspiciousPath(path string) error {
if strings.Contains(path, "..") {
return errors.Errorf("refusing to unpack archive with suspicious entry %q", path)
Expand Down Expand Up @@ -193,6 +212,7 @@ type extractor func(targetDir string, read io.ReaderAt, size int64) error
var defaultExtractors = map[string]extractor{
"application/zip": extractZIP,
"application/x-gzip": extractTARGZ,
"application/octet-stream": downloadBinary,
}

func extractArchive(dst string, at io.ReaderAt, size int64) error {
Expand All @@ -203,7 +223,7 @@ func extractArchive(dst string, at io.ReaderAt, size int64) error {
klog.V(4).Infof("detected %q file type", t)
exf, ok := defaultExtractors[t]
if !ok {
return errors.Errorf("mime type %q for archive file is not a supported archive format", t)
return errors.Errorf("mime type %q for file is not a supported format", t)
}
return errors.Wrap(exf(dst, at, size), "failed to extract file")
}
Expand Down
40 changes: 39 additions & 1 deletion internal/installation/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package installation

import (
"io"
"os"
"path/filepath"
"runtime"
Expand Down Expand Up @@ -108,6 +109,16 @@ func install(op installOperation, opts InstallOpts) error {
return errors.Wrap(err, "failed to unpack into staging dir")
}

// Download Liscense file from given URI and rename downloaded binary to plugin name
if op.platform.License != "" {
if err:= downloadLicenseFile(downloadStagingDir, op.platform.License); err != nil {
return errors.Wrap(err, "failed downloading license file to installation directory")
}
if err := renameBinary(downloadStagingDir, op.platform.Bin); err != nil {
return errors.Wrap(err, "failed renaming binary in installation directory")
}
}

applyDefaults(&op.platform)
if err := moveToInstallDir(downloadStagingDir, op.installDir, op.platform.Files); err != nil {
return errors.Wrap(err, "failed while moving files to the installation directory")
Expand Down Expand Up @@ -137,7 +148,7 @@ func applyDefaults(platform *index.Platform) {
}

// downloadAndExtract downloads the specified archive uri (or uses the provided overrideFile, if a non-empty value)
// while validating its checksum with the provided sha256sum, and extracts its contents to extractDir that must be.
// while validating its checksum with the provided sha256sum, and extracts its contents to extractDir that must be
// created.
func downloadAndExtract(extractDir, uri, sha256sum, overrideFile string) error {
var fetcher download.Fetcher = download.HTTPFetcher{}
Expand All @@ -150,6 +161,33 @@ func downloadAndExtract(extractDir, uri, sha256sum, overrideFile string) error {
return errors.Wrap(err, "failed to unpack the plugin archive")
}

// downloadLicenseFile will download the license file from the given URI and save it to the installation directory
// of the plugin.
func downloadLicenseFile(extractDir, uri string) error {
var fetcher download.Fetcher = download.HTTPFetcher{}

body, err := fetcher.Get(uri)
if err != nil {
return errors.Wrap(err, "failed to download the license file")
}
defer body.Close()

out, err := os.Create(filepath.Join(extractDir, "LICENSE"))
if err != nil {
return errors.Wrap(err, "failed to create LICENSE file")
}
defer out.Close()

_, err = io.Copy(out, body)

return err
}

// renames the binary in the installation directory to the plugin name if the binary is given temporary "binary" name
func renameBinary(extractDir, plugin string) error {
return os.Rename(filepath.Join(extractDir, "binary"), filepath.Join(extractDir, plugin))
}

// Uninstall will uninstall a plugin.
func Uninstall(p environment.Paths, name string) error {
if name == constants.KrewPluginName {
Expand Down
2 changes: 2 additions & 0 deletions pkg/index/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ type Platform struct {
Selector *metav1.LabelSelector `json:"selector,omitempty"`
Files []FileOperation `json:"files"`

License string `json:"license,omitempty"`

// Bin specifies the path to the plugin executable.
// The path is relative to the root of the installation folder.
// The binary will be linked after all FileOperations are executed.
Expand Down

0 comments on commit a27046e

Please sign in to comment.