From 1f4844a1d318bb06a769aac995906a89cd0bc567 Mon Sep 17 00:00:00 2001 From: FlUxIuS Date: Sun, 14 Jul 2024 17:31:23 +0200 Subject: [PATCH] Uploading missing files --- go/rfswift/dock/dockerhub.go | 144 ++++++++++++++++++++ go/rfswift/rfutils/githutils.go | 227 ++++++++++++++++++++++++++++++++ 2 files changed, 371 insertions(+) create mode 100644 go/rfswift/dock/dockerhub.go create mode 100644 go/rfswift/rfutils/githutils.go diff --git a/go/rfswift/dock/dockerhub.go b/go/rfswift/dock/dockerhub.go new file mode 100644 index 0000000..2111a99 --- /dev/null +++ b/go/rfswift/dock/dockerhub.go @@ -0,0 +1,144 @@ +package dock + +import ( + "encoding/json" + "fmt" + "log" + "net/http" + "os" + "runtime" + "sort" + "time" + + "github.com/olekukonko/tablewriter" + rfutils "penthertz/rfswift/rfutils" +) + +type Tag struct { + Name string `json:"name"` + Images []Image `json:"images"` + TagLastPushed time.Time `json:"tag_last_pushed"` +} + +type Image struct { + Architecture string `json:"architecture"` + Digest string `json:"digest"` +} + +type TagList struct { + Results []Tag `json:"results"` +} + +func getArchitecture() string { + switch runtime.GOARCH { + case "amd64": + return "amd64" + case "arm64": + return "arm64" + case "arm": + return "arm" + default: + return "" + } +} + +func getLatestDockerHubTags(repo string, architecture string) ([]Tag, error) { + /* + * Get latest Docker images details + * in(1): remote repository string + * in(2): architecture string + * out: tuple status + */ + url := fmt.Sprintf("https://hub.docker.com/v2/repositories/%s/tags/?page_size=100", repo) + + client := &http.Client{Timeout: 10 * time.Second} + resp, err := client.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("failed to get tags: %s", resp.Status) + } + + var tagList TagList + if err := json.NewDecoder(resp.Body).Decode(&tagList); err != nil { + return nil, err + } + + var filteredTags []Tag + for _, tag := range tagList.Results { + for _, image := range tag.Images { + if image.Architecture == architecture { + filteredTags = append(filteredTags, tag) + break + } + } + } + + // Sort tags by pushed date from latest to oldest + sort.Slice(filteredTags, func(i, j int) bool { + return filteredTags[i].TagLastPushed.After(filteredTags[j].TagLastPushed) + }) + + // Remove duplicate tags, keeping only the latest + uniqueTags := make(map[string]Tag) + for _, tag := range filteredTags { + if _, exists := uniqueTags[tag.Name]; !exists { + uniqueTags[tag.Name] = tag + } + } + + // Convert map to slice + var latestTags []Tag + for _, tag := range uniqueTags { + latestTags = append(latestTags, tag) + } + + // Sort the tags again to ensure they are in the correct order after deduplication + sort.Slice(latestTags, func(i, j int) bool { + return latestTags[i].TagLastPushed.After(latestTags[j].TagLastPushed) + }) + + return latestTags, nil +} + +func ListDockerImagesRepo() { + /* + * Prints Latest tags for RF Swift + */ + repo := "penthertz/rfswift" // Change this to the repository you want to check + architecture := getArchitecture() + + if architecture == "" { + log.Fatalf("Unsupported architecture: %s", runtime.GOARCH) + } + + tags, err := getLatestDockerHubTags(repo, architecture) + if err != nil { + log.Fatalf("Error getting tags: %v", err) + } + + rfutils.ClearScreen() + + table := tablewriter.NewWriter(os.Stdout) + table.SetHeader([]string{"Tag", "Pushed Date", "Image", "Architecture", "Digest"}) + + for _, tag := range tags { + for _, image := range tag.Images { + if image.Architecture == architecture { + table.Append([]string{ + tag.Name, + tag.TagLastPushed.Format(time.RFC3339), + fmt.Sprintf("%s:%s", repo, tag.Name), + image.Architecture, + image.Digest, + }) + break + } + } + } + + table.Render() +} \ No newline at end of file diff --git a/go/rfswift/rfutils/githutils.go b/go/rfswift/rfutils/githutils.go new file mode 100644 index 0000000..de02cd4 --- /dev/null +++ b/go/rfswift/rfutils/githutils.go @@ -0,0 +1,227 @@ +package rfutils + +import ( + "encoding/json" + "fmt" + "io" + "log" + "net/http" + "os" + "os/exec" + "path/filepath" + "runtime" + "strconv" + "strings" + + "github.com/cheggaaa/pb/v3" + "github.com/go-resty/resty/v2" +) + +type Release struct { + TagName string `json:"tag_name"` +} + +func getLatestRelease(owner string, repo string) (Release, error) { + /* + * Get Latest Release information + * in(1): owner string + * in(2): repository string + * out: status + */ + client := resty.New() + + resp, err := client.R(). + SetHeader("Accept", "application/vnd.github.v3+json"). + Get(fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/latest", owner, repo)) + + if err != nil { + return Release{}, err + } + + if resp.StatusCode() != http.StatusOK { + return Release{}, fmt.Errorf("failed to get latest release: %s", resp.Status()) + } + + var release Release + if err := json.Unmarshal(resp.Body(), &release); err != nil { + return Release{}, err + } + + return release, nil +} + +func constructDownloadURL(owner, repo, tag, fileName string) string { + /* + * Construct download URL link for RF Swift release + * in(1): owner string + * in(2): repository string + * in(3): tag string + * in(4): filename string + * out: status + */ + return fmt.Sprintf("https://github.com/%s/%s/releases/download/%s/%s", owner, repo, tag, fileName) +} + +func downloadFile(url, dest string) error { + /* + * Download RF swift binary realse + * in(1): string url + * in(2): destinarion string + * out: status + */ + resp, err := http.Get(url) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("failed to download file: %s", resp.Status) + } + + size, err := strconv.Atoi(resp.Header.Get("Content-Length")) + if err != nil { + return err + } + + out, err := os.Create(dest) + if err != nil { + return err + } + defer out.Close() + + bar := pb.Full.Start64(int64(size)) + barReader := bar.NewProxyReader(resp.Body) + _, err = io.Copy(out, barReader) + bar.Finish() + + return err +} + +func makeExecutable(path string) error { + /* + * Making downloaded RF Swift binary executable + * in(1): string path + * out: status + */ + err := os.Chmod(path, 0755) + if err != nil { + return err + } + return nil +} + +func replaceBinary(newBinaryPath, binaryName string) error { + /* + * Replace original RF Swift binary by the latest release + * in(1): latest binary string + * in(2): original binary string + * out: status + */ + // Ensure the new binary is executable + err := makeExecutable(newBinaryPath) + if err != nil { + return err + } + + // Determine the current binary path + currentBinaryPath, err := exec.LookPath(binaryName) + if err != nil { + return err + } + + // Replace the current binary with the new one + err = os.Rename(newBinaryPath, currentBinaryPath) + if err != nil { + return err + } + + return nil +} + +func GetLatestRFSwift() { + /* + * Print latest RF Swift binary from official Penthertz' repository + */ + owner := "PentHertz" + repo := "RF-Swift" + + release, err := getLatestRelease(owner, repo) + if err != nil { + log.Fatalf("Error getting latest release: %v", err) + } + + arch := runtime.GOARCH + goos := runtime.GOOS + + var fileName string + + switch goos { + case "linux": + switch arch { + case "amd64": + fileName = "rfswift_linux_amd64" + case "arm64": + fileName = "rfswift_linux_arm64" + default: + log.Fatalf("Unsupported architecture: %s", arch) + } + case "windows": + switch arch { + case "amd64": + fileName = "rfswift_windows_amd64.exe" + case "arm64": + fileName = "rfswift_windows_arm64.exe" + default: + log.Fatalf("Unsupported architecture: %s", arch) + } + default: + log.Fatalf("Unsupported operating system: %s", goos) + } + + downloadURL := constructDownloadURL(owner, repo, release.TagName, fileName) + fmt.Printf("Latest release download URL: %s\n", downloadURL) + + fmt.Printf("Do you want to replace the existing 'rfswift' binary with this new release? (yes/no): ") + var response string + fmt.Scanln(&response) + + if response == "yes" { + tempDest := filepath.Join(os.TempDir(), fileName) + err = downloadFile(downloadURL, tempDest) + if err != nil { + log.Fatalf("Error downloading file: %v", err) + } + + err = replaceBinary(tempDest, "./rfswift") + if err != nil { + log.Fatalf("Error replacing binary: %v", err) + } + + fmt.Println("File downloaded and replaced successfully.") + } else { + // Get the current binary directory + currentBinaryPath, err := exec.LookPath("./rfswift") + if err != nil { + log.Fatalf("Error locating current binary: %v", err) + } + + var dest string + ext := filepath.Ext(fileName) + name := strings.TrimSuffix(fileName, ext) + dest = filepath.Join(filepath.Dir(currentBinaryPath), fmt.Sprintf("%s_%s%s", name, release.TagName, ext)) + + err = downloadFile(downloadURL, dest) + if err != nil { + log.Fatalf("Error downloading file: %v", err) + } + + // Make the new binary executable + err = makeExecutable(dest) + if err != nil { + log.Fatalf("Error making binary executable: %v", err) + } + + fmt.Printf("File downloaded and saved at %s\n", dest) + } +} \ No newline at end of file