diff --git a/cmd/ghDownload.go b/cmd/ghDownload.go index efc13fe..0924e5c 100644 --- a/cmd/ghDownload.go +++ b/cmd/ghDownload.go @@ -15,7 +15,7 @@ var ghDownloadCmd = &cobra.Command{ Short: "Downloads assets from Github", Long: `This command can be used to download assets from Github.`, Run: func(cmd *cobra.Command, args []string) { - gh.DownloadAssets(ReadGithubConfiguration(), false) + gh.DownloadAssets(ReadGithubConfiguration(), ".", false, "") }, } diff --git a/cmd/root.go b/cmd/root.go index 89248fe..eea197f 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -32,7 +32,7 @@ var rootCmd = &cobra.Command{ Short: "Application to retrieve artifacts from github.", Long: `This application by default retrieves zap artifacts, with the right arguments, it can be used to retrieve assets from any public github repo.`, Run: func(cmd *cobra.Command, args []string) { - gh.DefaultAction(ReadGithubConfiguration()) + gh.DefaultAction(ReadGithubConfiguration(), ReadArtifactoryConfiguration()) }, } diff --git a/cmd/rtDelete.go b/cmd/rtDelete.go new file mode 100644 index 0000000..7d82bfe --- /dev/null +++ b/cmd/rtDelete.go @@ -0,0 +1,27 @@ +/* +Copyright © 2024 Silicon Labs +*/ +package cmd + +import ( + "silabs/get-zap/jf" + + "github.com/spf13/cobra" +) + +var rtDeleteCmd = &cobra.Command{ + Use: "delete", + Short: "Deletes a file on artifactory", + Long: `Performs a file delete of a given pattern.`, + Run: func(cmd *cobra.Command, args []string) { + file, err := cmd.Flags().GetString("file") + cobra.CheckErr(err) + jf.ArtifactoryDelete(ReadArtifactoryConfiguration(), file) + }, +} + +func init() { + rtCmd.AddCommand(rtDeleteCmd) + rtDeleteCmd.Flags().StringP("file", "f", "", "File to upload") + rtDeleteCmd.MarkFlagRequired("file") +} diff --git a/cmd/rtDownload.go b/cmd/rtDownload.go index f9a8948..9214f67 100644 --- a/cmd/rtDownload.go +++ b/cmd/rtDownload.go @@ -14,10 +14,14 @@ var rtDownloadCmd = &cobra.Command{ Short: "Downloads a file from Artifactory", Long: `Performs a download of one or more files from Artifactory.`, Run: func(cmd *cobra.Command, args []string) { - jf.ArtifactoryDownload(ReadArtifactoryConfiguration()) + file, err := cmd.Flags().GetString("file") + cobra.CheckErr(err) + jf.ArtifactoryDownload(ReadArtifactoryConfiguration(), file) }, } func init() { rtCmd.AddCommand(rtDownloadCmd) + rtDownloadCmd.Flags().StringP("file", "f", "", "File to upload") + rtDownloadCmd.MarkFlagRequired("file") } diff --git a/cmd/rtUpload.go b/cmd/rtUpload.go index caa4de6..2633216 100644 --- a/cmd/rtUpload.go +++ b/cmd/rtUpload.go @@ -4,7 +4,7 @@ Copyright © 2024 Silicon Labs package cmd import ( - "fmt" + "silabs/get-zap/jf" "github.com/spf13/cobra" ) @@ -14,10 +14,14 @@ var rtUploadCmd = &cobra.Command{ Short: "Uploads a file to artifactory", Long: `Performs an upload of specified files to artifactory.`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println("upload called") + file, err := cmd.Flags().GetString("file") + cobra.CheckErr(err) + jf.ArtifactoryUpload(ReadArtifactoryConfiguration(), file) }, } func init() { rtCmd.AddCommand(rtUploadCmd) + rtUploadCmd.Flags().StringP("file", "f", "", "File to upload") + rtUploadCmd.MarkFlagRequired("file") } diff --git a/gh/download.go b/gh/download.go index 8f92c62..f34de4f 100644 --- a/gh/download.go +++ b/gh/download.go @@ -4,13 +4,17 @@ Copyright © 2024 Silicon Labs package gh import ( + "context" "crypto/tls" - "errors" "fmt" "io" "net/http" "net/url" "os" + "strings" + + "github.com/google/go-github/github" + "github.com/spf13/cobra" ) type DownloadOptions struct { @@ -52,9 +56,73 @@ func DefaultSecurityOptions() *DownloadOptions { return &s } +// If local only is true, then only assets matching the local platform will be downloaded +func DownloadAssets(cfg *GithubConfiguration, destinationDirectory string, localOnly bool, suffixOnly string) { + + client := CreateGithubClient(cfg) + var release *github.RepositoryRelease + // Get latest release + if cfg.Release == "latest" { + r, _, err := client.Repositories.GetLatestRelease(context.Background(), cfg.Owner, cfg.Repo) + cobra.CheckErr(err) + release = r + } else if cfg.Release == "all" { + fmt.Println("Downloading assets for all releases is not supported. Please use 'latest' or specific release.") + return + } else { + release = findRelease(client, cfg.Owner, cfg.Repo, cfg.Release) + if release == nil { + fmt.Printf("Could not find release '%v'\n", cfg.Release) + return + } + } + fmt.Printf("Downloading assets for release '%v' of repo '%v/%v':\n", release.GetTagName(), cfg.Owner, cfg.Repo) + printRelease(client, cfg.Owner, cfg.Repo, release) + assets, _, err := client.Repositories.ListReleaseAssets(context.Background(), cfg.Owner, cfg.Repo, release.GetID(), &github.ListOptions{}) + cobra.CheckErr(err) + for _, asset := range assets { + + if localOnly { + assetOs, assetArch := DetermineAssetPlatform(asset.GetName()) + if !IsLocalAsset(assetOs, assetArch) { + fmt.Printf("Skipping asset '%v' [os='%v', arch='%v'] as it does not match the local platform.\n", asset.GetName(), assetOs, assetArch) + continue + } + } + + if suffixOnly != "" && !strings.HasSuffix(asset.GetName(), suffixOnly) { + fmt.Printf("Skipping asset '%v' as it does not have the suffix '%v'.\n", asset.GetName(), suffixOnly) + continue + } + + rc, redirect, err := client.Repositories.DownloadReleaseAsset(context.Background(), cfg.Owner, cfg.Repo, asset.GetID()) + cobra.CheckErr(err) + err = os.MkdirAll(release.GetName(), 0775) + cobra.CheckErr(err) + if rc != nil { + err = downloadFileFromReadCloser(rc, release.GetName(), asset.GetName()) + cobra.CheckErr(err) + } else { + err = downloadFileFromUrl(redirect, release.GetName(), asset.GetName(), DefaultSecurityOptions()) + cobra.CheckErr(err) + } + } +} + +func downloadFileFromReadCloser(rc io.ReadCloser, destinationDirectory string, destinationPath string) error { + defer rc.Close() + output, err := os.Create(destinationDirectory + "/" + destinationPath) + if err != nil { + return err + } + defer output.Close() + _, err = io.Copy(output, rc) + return err +} + // This function downloads a file from a given URL and puts it into the // destination path. -func DownloadFileFromUrl(urlAsString string, destinationPath string, sec *DownloadOptions) error { +func downloadFileFromUrl(urlAsString string, destinationDirectory string, destinationPath string, sec *DownloadOptions) error { tlsConfig := &tls.Config{} if sec.skipCertCheck { @@ -76,7 +144,7 @@ func DownloadFileFromUrl(urlAsString string, destinationPath string, sec *Downlo } if !sec.allowHttp && u.Scheme == "http" { - return fmt.Errorf("Only secure encrypted HTTPS protocol is allowed. Downloads via HTTP are blocked: %v", urlAsString) + return fmt.Errorf("only secure encrypted HTTPS protocol is allowed, downloads via HTTP are blocked: %v", urlAsString) } // Security alert: Let's do an actual get now @@ -85,7 +153,7 @@ func DownloadFileFromUrl(urlAsString string, destinationPath string, sec *Downlo return err } if response.StatusCode != http.StatusOK { - return errors.New(fmt.Sprintf("HTTP error: %v", response.StatusCode)) + return fmt.Errorf("HTTP error: %v", response.StatusCode) } defer response.Body.Close() @@ -93,7 +161,7 @@ func DownloadFileFromUrl(urlAsString string, destinationPath string, sec *Downlo len := response.ContentLength fmt.Printf("Downloading %v bytes to %v ...\n", len, destinationPath) - output, err := os.Create(destinationPath) + output, err := os.Create(destinationDirectory + "/" + destinationPath) if err != nil { return err } diff --git a/gh/general.go b/gh/general.go index aee7e1f..ec899fc 100644 --- a/gh/general.go +++ b/gh/general.go @@ -6,8 +6,8 @@ package gh import ( "context" "fmt" - "io" "runtime" + "silabs/get-zap/jf" "strings" "github.com/google/go-github/github" @@ -38,9 +38,9 @@ func CreateGithubClient(cfg *GithubConfiguration) *github.Client { return client } -func DefaultAction(cfg *GithubConfiguration) { - fmt.Printf("Downloading release '%v' of repo '%v/%v' for the platform '%v/%v'...\n", cfg.Release, cfg.Owner, cfg.Repo, runtime.GOOS, runtime.GOARCH) - DownloadAssets(cfg, true) +func DefaultAction(ghCfg *GithubConfiguration, rtCfg *jf.ArtifactoryConfiguration) { + fmt.Printf("Downloading release '%v' of repo '%v/%v' for the platform '%v/%v'...\n", ghCfg.Release, ghCfg.Owner, ghCfg.Repo, runtime.GOOS, runtime.GOARCH) + DownloadAssets(ghCfg, ".", true, ".zip") } func DetermineAssetPlatform(assetName string) (os string, arch string) { @@ -74,63 +74,6 @@ func IsLocalAsset(assetOs string, assetArch string) bool { return true } -// If local only is true, then only assets matching the local platform will be downloaded -func DownloadAssets(cfg *GithubConfiguration, localOnly bool) { - - client := CreateGithubClient(cfg) - var release *github.RepositoryRelease - // Get latest release - if cfg.Release == "latest" { - r, _, err := client.Repositories.GetLatestRelease(context.Background(), cfg.Owner, cfg.Repo) - cobra.CheckErr(err) - release = r - } else if cfg.Release == "all" { - fmt.Println("Downloading assets for all releases is not supported. Please use 'latest' or specific release.") - return - } else { - release = findRelease(client, cfg.Owner, cfg.Repo, cfg.Release) - if release == nil { - fmt.Printf("Could not find release '%v'\n", cfg.Release) - return - } - } - fmt.Printf("Downloading assets for release '%v' of repo '%v/%v':\n", release.GetTagName(), cfg.Owner, cfg.Repo) - printRelease(client, cfg.Owner, cfg.Repo, release) - assets, _, err := client.Repositories.ListReleaseAssets(context.Background(), cfg.Owner, cfg.Repo, release.GetID(), &github.ListOptions{}) - cobra.CheckErr(err) - for _, asset := range assets { - - if localOnly { - assetOs, assetArch := DetermineAssetPlatform(asset.GetName()) - if !IsLocalAsset(assetOs, assetArch) { - fmt.Printf("Skipping asset '%v' [os='%v', arch='%v'] as it does not match the local platform.\n", asset.GetName(), assetOs, assetArch) - continue - } - } - - rc, redirect, err := client.Repositories.DownloadReleaseAsset(context.Background(), cfg.Owner, cfg.Repo, asset.GetID()) - cobra.CheckErr(err) - if rc != nil { - fmt.Printf("Not redirected.\n") - buff := make([]byte, 10*1024) - n, err := rc.Read(buff) - fmt.Printf("Read %d bytes\n", n) - if n > 0 { - fmt.Printf("Read %d bytes\n", n) - } else { - if err == io.EOF { - rc.Close() - fmt.Println("Eof") - } else { - cobra.CheckErr(err) - } - } - } else { - DownloadFileFromUrl(redirect, asset.GetName(), DefaultSecurityOptions()) - } - } -} - func findRelease(client *github.Client, owner string, repo string, tag string) *github.RepositoryRelease { allReleases, _, err := client.Repositories.ListReleases(context.Background(), owner, repo, &github.ListOptions{}) cobra.CheckErr(err) diff --git a/jf/artifactory.go b/jf/artifactory.go index dd5d958..efd8259 100644 --- a/jf/artifactory.go +++ b/jf/artifactory.go @@ -28,7 +28,7 @@ func (cfg *ArtifactoryConfiguration) IsValid() bool { func (cfg *ArtifactoryConfiguration) CreateDetails() *auth.ServiceDetails { if !cfg.IsValid() { - cobra.CheckErr(fmt.Errorf("Invalid artifactory configuration. You need to provide url, api key and user either via command line, environment variables, or configuration file.")) + cobra.CheckErr(fmt.Errorf("invalid artifactory configuration, you need to provide url, api key and user either via command line, environment variables, or configuration file")) } rtDetails := rtAuth.NewArtifactoryDetails() rtDetails.SetUrl(cfg.Url) @@ -37,7 +37,28 @@ func (cfg *ArtifactoryConfiguration) CreateDetails() *auth.ServiceDetails { return &rtDetails } -func ArtifactoryDownload(cfg *ArtifactoryConfiguration) { +func ArtifactoryDelete(cfg *ArtifactoryConfiguration, pattern string) { + rtDetails := cfg.CreateDetails() + + s, err := config.NewConfigBuilder().SetServiceDetails(*rtDetails).Build() + cobra.CheckErr(err) + + m, err := artifactory.New(s) + cobra.CheckErr(err) + + params := services.NewDeleteParams() + params.Pattern = cfg.Repo + "/" + pattern + fmt.Printf("Deleting files from %v/%v: %v\n", cfg.Url, cfg.Repo, params.Pattern) + + pathsToDelete, err := m.GetPathsToDelete(params) + cobra.CheckErr(err) + defer pathsToDelete.Close() + cnt, err := m.DeleteFiles(pathsToDelete) + cobra.CheckErr(err) + fmt.Printf("Deleted files: %v\n", cnt) +} + +func ArtifactoryDownload(cfg *ArtifactoryConfiguration, pattern string) { rtDetails := cfg.CreateDetails() @@ -48,15 +69,15 @@ func ArtifactoryDownload(cfg *ArtifactoryConfiguration) { cobra.CheckErr(err) params := services.NewDownloadParams() - params.Pattern = cfg.Repo + "/" + cfg.Path - fmt.Println("Downloading files from", cfg.Url, "with pattern", params.Pattern) + params.Pattern = cfg.Repo + "/" + pattern + fmt.Printf("Downloading files from %v/%v: %v\n", cfg.Url, cfg.Repo, params.Pattern) success, failures, err := m.DownloadFiles(params) cobra.CheckErr(err) - fmt.Printf("Download files: success %v, failure %v\n", success, failures) + fmt.Printf("Downloaded files: success %v, failure %v\n", success, failures) } -func ArtifactoryUpload(cfg *ArtifactoryConfiguration) { +func ArtifactoryUpload(cfg *ArtifactoryConfiguration, pattern string) { rtDetails := cfg.CreateDetails() s, err := config.NewConfigBuilder().SetServiceDetails(*rtDetails).Build() @@ -66,8 +87,11 @@ func ArtifactoryUpload(cfg *ArtifactoryConfiguration) { cobra.CheckErr(err) params := services.NewUploadParams() + params.Pattern = pattern + fmt.Printf("Uploading files to %v/%v: %v\n", cfg.Url, cfg.Repo, params.Pattern) + params.Target = cfg.Repo + "/" success, failures, err := m.UploadFiles(params) cobra.CheckErr(err) - fmt.Printf("Upload files: success %v, failure %v\n", success, failures) + fmt.Printf("Uploaded files: success %v, failure %v\n", success, failures) }