From ae43c236c4fac926f2daa4afa2ccf879b98ac33d Mon Sep 17 00:00:00 2001 From: xplshn <114888778+xplshn@users.noreply.github.com> Date: Sat, 11 May 2024 02:09:53 -0300 Subject: [PATCH] Delete baks directory --- baks/.helperFunctions.go | 433 --------------------------------------- baks/.info.go | 134 ------------ baks/.install.go | 67 ------ baks/.main.go | 297 --------------------------- baks/.run.go | 236 --------------------- 5 files changed, 1167 deletions(-) delete mode 100644 baks/.helperFunctions.go delete mode 100644 baks/.info.go delete mode 100644 baks/.install.go delete mode 100644 baks/.main.go delete mode 100644 baks/.run.go diff --git a/baks/.helperFunctions.go b/baks/.helperFunctions.go deleted file mode 100644 index 251f10f..0000000 --- a/baks/.helperFunctions.go +++ /dev/null @@ -1,433 +0,0 @@ -// helperFunctions.go // This file contains commonly used functions //> -package main - -import ( - "context" - "fmt" - "io" - "net/http" - "os" - "os/exec" - "os/signal" - "path/filepath" - "sort" - "strconv" - "strings" - "syscall" - - "github.com/schollz/progressbar/v3" -) - -// TODO: Add *PROPER* error handling in the truncate functions. Ensure escape sequences are correctly handled? - -// signalHandler sets up a channel to listen for interrupt signals and returns a function -// that can be called to check if an interrupt has been received. -func signalHandler(ctx context.Context, cancel context.CancelFunc) (func() bool, error) { - sigChan := make(chan os.Signal, 1) - signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM) - - go func() { - <-sigChan - cancel() // Call the cancel function when an interrupt is received - }() - - return func() bool { - select { - case <-ctx.Done(): - return true - default: - return false - } - }, nil -} - -// fetchBinaryFromURL fetches a binary from the given URL and saves it to the specified destination. -func fetchBinaryFromURL(url, destination string) error { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() // Ensure the cancel function is called when the function returns - - // Set up signal handling - interrupted, err := signalHandler(ctx, cancel) - if err != nil { - return fmt.Errorf("failed to set up signal handler: %v", err) - } - - // Create a temporary directory if it doesn't exist - if err := os.MkdirAll(TEMP_DIR, 0755); err != nil { - return fmt.Errorf("failed to create temporary directory: %v", err) - } - - // Create a temporary file to download the binary - tempFile := filepath.Join(TEMP_DIR, filepath.Base(destination)+".tmp") - out, err := os.Create(tempFile) - if err != nil { - return fmt.Errorf("failed to create temporary file: %v", err) - } - defer out.Close() - - // Schedule the deletion of the temporary file - defer func() { - if err := os.Remove(tempFile); err != nil && !os.IsNotExist(err) { - fmt.Printf("\r\033[Kfailed to remove temporary file: %v\n", err) - } - }() - - // Fetch the binary from the given URL - req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) - if err != nil { - return fmt.Errorf("error creating request: %v", err) - } - - // Ensure that redirects are followed - client := &http.Client{ - CheckRedirect: func(_ *http.Request, _ []*http.Request) error { - return nil - }, - } - - resp, err := client.Do(req) - if err != nil { - return fmt.Errorf("failed to fetch binary from %s: %v", url, err) - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("failed to fetch binary from %s. HTTP status code: %d", url, resp.StatusCode) - } - - bar := spawnProgressBar(resp.ContentLength) - - // Write the binary to the temporary file with progress bar - _, err = io.Copy(io.MultiWriter(out, bar), resp.Body) - if err != nil { - return fmt.Errorf("failed to write to temporary file: %v", err) - } - - // Close the file before setting executable bit - if err := out.Close(); err != nil { - return fmt.Errorf("failed to close temporary file: %v", err) - } - - // Use copyFile to move the binary to its destination - if err := copyFile(tempFile, destination); err != nil { - return fmt.Errorf("failed to move binary to destination: %v", err) - } - - // Set executable bit immediately after copying - if err := os.Chmod(destination, 0755); err != nil { - return fmt.Errorf("failed to set executable bit: %v", err) - } - - // Check if the operation was interrupted - if interrupted() { - fmt.Println("\r\033[KDownload interrupted. Cleaning up...") - // Ensure the temporary file is removed if the operation was interrupted - if err := os.Remove(tempFile); err != nil && !os.IsNotExist(err) { - fmt.Printf("failed to remove temporary file: %v\n", err) - } - } - fmt.Print("\033[2K\r") // Clean the line - return nil -} - -// copyFile copies(removes original after copy) a file from src to dst -func copyFile(src, dst string) error { - // Check if the destination file already exists - if fileExists(dst) { - if err := os.Remove(dst); err != nil { - return fmt.Errorf("%v", err) - } - } - - sourceFile, err := os.Open(src) - if err != nil { - return fmt.Errorf("failed to open source file: %v", err) - } - defer sourceFile.Close() - - destFile, err := os.Create(dst) - if err != nil { - return fmt.Errorf("failed to create destination file: %v", err) - } - - _, err = io.Copy(destFile, sourceFile) - if err != nil { - destFile.Close() // Ensure the destination file is closed - return fmt.Errorf("failed to copy file: %v", err) - } - - if err := destFile.Close(); err != nil { - return fmt.Errorf("failed to close destination file: %v", err) - } - - // Remove the temporary file after copying - if err := os.Remove(src); err != nil { - return fmt.Errorf("failed to remove source file: %v", err) - } - - return nil -} - -// removeDuplicates removes duplicate elements from the input slice. -func removeDuplicates(input []string) []string { - seen := make(map[string]bool) - unique := []string{} - if input != nil { - for _, entry := range input { - if _, value := seen[entry]; !value { - seen[entry] = true - unique = append(unique, entry) - } - } - } else { - unique = input - } - return unique -} - -// sortBinaries sorts the input slice of binaries. -func sortBinaries(binaries []string) []string { - sort.Strings(binaries) - return binaries -} - -// fileExists checks if a file exists. -func fileExists(filePath string) bool { - _, err := os.Stat(filePath) - return !os.IsNotExist(err) -} - -// appendLineToFile appends a line to the end of a file. -func appendLineToFile(filePath, line string) error { - file, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644) - if err != nil { - return err - } - defer file.Close() - _, err = fmt.Fprintln(file, line) - return err -} - -// fileSize returns the size of the file at the specified path. -func fileSize(filePath string) int64 { - file, err := os.Open(filePath) - if err != nil { - return 0 - } - defer file.Close() - - stat, err := file.Stat() - if err != nil { - return 0 - } - - return stat.Size() -} - -// isExecutable checks if the file at the specified path is executable. -func isExecutable(filePath string) bool { - info, err := os.Stat(filePath) - if err != nil { - return false - } - return info.Mode().IsRegular() && (info.Mode().Perm()&0111) != 0 -} - -// listFilesInDir lists all files in a directory -func listFilesInDir(dir string) ([]string, error) { - var files []string - entries, err := os.ReadDir(dir) - if err != nil { - return nil, err - } - for _, entry := range entries { - if !entry.IsDir() { - files = append(files, dir+"/"+entry.Name()) - } - } - return files, nil -} - -func spawnProgressBar(contentLength int64) *progressbar.ProgressBar { - if useProgressBar { - return progressbar.NewOptions(int(contentLength), - progressbar.OptionClearOnFinish(), - progressbar.OptionFullWidth(), - progressbar.OptionShowBytes(true), - progressbar.OptionSetTheme(progressbar.Theme{ - Saucer: "=", - SaucerHead: ">", - SaucerPadding: " ", - BarStart: "[", - BarEnd: "]", - }), - ) - } - return progressbar.NewOptions(0, progressbar.OptionClearOnFinish()) // A dummy -} - -// sanitizeString removes certain punctuation from the end of the string and converts it to lower case. -func sanitizeString(s string) string { - // Define the punctuation to remove - punctuation := []string{".", " ", ",", "!", "?"} - - // Convert string to lower case - s = strings.ToLower(s) - - // Remove specified punctuation from the end of the string - for _, p := range punctuation { - if strings.HasSuffix(s, p) { - s = s[:len(s)-len(p)] - } - } - - return s -} - -// errorEncoder generates a unique error code based on the sum of ASCII values of the error message. -func errorEncoder(format string, args ...interface{}) int { - formattedErrorMessage := fmt.Sprintf(format, args...) - - var sum int - for _, char := range formattedErrorMessage { - sum += int(char) - } - errorCode := sum % 256 - fmt.Fprint(os.Stderr, formattedErrorMessage) - return errorCode -} - -// errorOut prints the error message to stderr and exits the program with the error code generated by errorEncoder. -func errorOut(format string, args ...interface{}) { - os.Exit(errorEncoder(format, args...)) -} - -// GetTerminalWidth attempts to determine the width of the terminal. -// It first tries using "stty size", then "tput cols", and finally falls back to 80 columns. -func getTerminalWidth() int { - // Try using stty size - cmd := exec.Command("stty", "size") - cmd.Stdin = os.Stdin - out, err := cmd.Output() - if err == nil { - // stty size returns rows and columns - parts := strings.Split(strings.TrimSpace(string(out)), " ") - if len(parts) == 2 { - width, err := strconv.Atoi(parts[1]) - if err == nil { - return width - } - } - } - - // Fallback to tput cols - cmd = exec.Command("tput", "cols") - cmd.Stdin = os.Stdin - out, err = cmd.Output() - if err == nil { - width, err := strconv.Atoi(strings.TrimSpace(string(out))) - if err == nil { - return width - } - } - - // Fallback to 80 columns - return 80 -} - -// truncateSprintf formats the string and truncates it if it exceeds the terminal width. -func truncateSprintf(format string, a ...interface{}) string { - // Format the string first - formatted := fmt.Sprintf(format, a...) - - // Determine the truncation length & truncate the formatted string if it exceeds the available space - availableSpace := getTerminalWidth() - len(indicator) - if len(formatted) > availableSpace { - formatted = fmt.Sprintf("%s", formatted[:availableSpace]) - for strings.HasSuffix(formatted, ",") || strings.HasSuffix(formatted, ".") || strings.HasSuffix(formatted, " ") { - formatted = formatted[:len(formatted)-1] - } - formatted = fmt.Sprintf("%s%s", formatted, indicator) // Add the dots. - } - - return formatted -} - -// truncatePrintf is a drop-in replacement for fmt.Printf that truncates the input string if it exceeds a certain length. -func truncatePrintf(format string, a ...interface{}) (n int, err error) { - if disableTruncation { - return fmt.Print(fmt.Sprintf(format, a...)) - } - return fmt.Print(truncateSprintf(format, a...)) -} // NOTE: Both truncate functions will remove the escape sequences of truncated lines, and sometimes break them in half because of the truncation. Avoid using escape sequences with truncate functions, as it is UNSAFE. - -// validateProgramsFrom validates programs against the files in the specified directory against the remote binaries. -// It returns the validated programs based on the last element of the received list of programs. -func validateProgramsFrom(InstallDir string, programsToValidate []string) ([]string, error) { - // Fetch the list of binaries from the remote source once - remotePrograms, err := listBinaries() - if err != nil { - return nil, fmt.Errorf("failed to list remote binaries: %w", err) - } - - // List files from the specified directory - files, err := listFilesInDir(InstallDir) - if err != nil { - return nil, fmt.Errorf("failed to list files in %s: %w", InstallDir, err) - } - - validPrograms := make([]string, 0) - invalidPrograms := make([]string, 0) - - programsToValidate = removeDuplicates(programsToValidate) - - // If programsToValidate is nil, validate all programs in the install directory - if programsToValidate == nil { - for _, file := range files { - // Extract the file name from the full path - fileName := filepath.Base(file) - if contains(remotePrograms, fileName) { - validPrograms = append(validPrograms, fileName) - } else { - invalidPrograms = append(invalidPrograms, fileName) - } - } - } else { - // Only check the ones specified in programsToValidate - for _, program := range programsToValidate { - if contains(remotePrograms, program) { - validPrograms = append(validPrograms, program) - } else { - invalidPrograms = append(invalidPrograms, program) - } - } - } - - // Handle the list of programs received based on the last element - // If programsToValidate is not nil, handle based on the last element - if len(programsToValidate) != 0 { - lastElement := programsToValidate[len(programsToValidate)-1] - switch lastElement { - case "_2_": - return invalidPrograms, nil - case "_3_": - return append(validPrograms, invalidPrograms...), nil - default: - return validPrograms, nil - } - } - return validPrograms, nil -} - -// isBinaryInPath checks if the binary is in the user's PATH, and it returns the path to it if so -func isBinaryInPath(binaryName string) (string, error) { - pathEnv := os.Getenv("PATH") - paths := strings.Split(pathEnv, string(os.PathListSeparator)) - for _, path := range paths { - binaryPath := filepath.Join(path, binaryName) - if fileExists(binaryPath) && isExecutable(binaryPath) { - return binaryPath, nil // Return the path to the binary if found - } - } - return "", nil // Return an empty string and no error if the binary is not found -} diff --git a/baks/.info.go b/baks/.info.go deleted file mode 100644 index 9a85b8a..0000000 --- a/baks/.info.go +++ /dev/null @@ -1,134 +0,0 @@ -// info.go // this file implements the functionality of 'info' //> -package main - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "net/http" -) - -// BinaryInfo represents the structure of binary information including description, updated, and version. -type BinaryInfo struct { - Name string `json:"Name"` - Description string `json:"Description"` - Repo string `json:"Repo"` - ModTime string `json:"ModTime"` - Version string `json:"Version"` - Updated string `json:"Updated"` - Size string `json:"Size"` - SHA256 string `json:"SHA256"` - B3SUM string `json:"B3SUM"` - Source string `json:"Source"` -} - -// getBinaryInfo fetches a binary's information from RNMetadataURL and RMetadataURL and returns it as a BinaryInfo struct. -func getBinaryInfo(binaryName string) (*BinaryInfo, error) { - // Fetch a binary's details from RNMetadataURL - response, err := http.Get(RNMetadataURL) - if err != nil { - return nil, fmt.Errorf("error fetching metadata from %s: %v", RNMetadataURL, err) - } - defer response.Body.Close() - - body, err := ioutil.ReadAll(response.Body) - if err != nil { - return nil, fmt.Errorf("error reading metadata from %s: %v", RNMetadataURL, err) - } - - var metadata [][]map[string]interface{} - if err := json.Unmarshal(body, &metadata); err != nil { - return nil, fmt.Errorf("error decoding metadata from %s: %v", RNMetadataURL, err) - } - - var binInfo BinaryInfo - var found bool - - for _, hostInfoArray := range metadata { - for _, hostInfo := range hostInfoArray { - if hostInfo["host"].(string) == validatedArch[2] { - mainBins, ok := hostInfo["Main"].([]interface{}) - if !ok { - return nil, fmt.Errorf("error decoding Main field from %s: %v", RNMetadataURL, err) - } - for _, bin := range mainBins { - binMap, ok := bin.(map[string]interface{}) - if !ok { - return nil, fmt.Errorf("error decoding binary details from %s: %v", RNMetadataURL, err) - } - if binMap["Name"].(string) == binaryName { - binInfo = BinaryInfo{ - Name: binMap["Name"].(string), - Size: binMap["Size"].(string), - ModTime: binMap["ModTime"].(string), - Source: binMap["Source"].(string), - B3SUM: binMap["B3SUM"].(string), - SHA256: binMap["SHA256"].(string), - Repo: binMap["Repo"].(string), - } - found = true - break - } - } - if found { - break - } - } - } - if found { - break - } - } - - if !found { - return nil, fmt.Errorf("info for the requested binary ('%s') not found in the metadata.json file for architecture '%s'", binaryName, validatedArch[2]) - } - - // Fetch binary description, updated, and version from RMetadataURL - response, err = http.Get(RMetadataURL) - if err != nil { - return nil, fmt.Errorf("error fetching description from %s: %v", RMetadataURL, err) - } - defer response.Body.Close() - - body, err = ioutil.ReadAll(response.Body) - if err != nil { - return nil, fmt.Errorf("error reading description from %s: %v", RMetadataURL, err) - } - - var rMetadata map[string][]BinaryInfo - if err := json.Unmarshal(body, &rMetadata); err != nil { - return nil, fmt.Errorf("error decoding description from %s: %v", RMetadataURL, err) - } - - binaries, exists := rMetadata["packages"] - if !exists { - return nil, fmt.Errorf("invalid description metadata format. No 'packages' field found.") - } - - var description, updated, version string - for _, binInfo := range binaries { - if binInfo.Name == binaryName { - description = binInfo.Description - updated = binInfo.Updated - version = binInfo.Version - break - } - } - - // Combine the technical details and description into a single BinaryInfo struct - combinedInfo := BinaryInfo{ - Name: binInfo.Name, - Description: description, - Repo: binInfo.Repo, - ModTime: binInfo.ModTime, - Version: version, - Updated: updated, - Size: binInfo.Size, - SHA256: binInfo.SHA256, - B3SUM: binInfo.B3SUM, - Source: binInfo.Source, - } - - return &combinedInfo, nil -} diff --git a/baks/.install.go b/baks/.install.go deleted file mode 100644 index 7c60715..0000000 --- a/baks/.install.go +++ /dev/null @@ -1,67 +0,0 @@ -// install.go // This file implements the install functionality // -package main - -import ( - "fmt" - "os" - "path/filepath" -) - -func installCommand(binaryName string, installMessage ...string) error { - installPath := filepath.Join(InstallDir, binaryName) - - // Use ReturnCachedFile to check for a cached file - if installUseCache { - cachedFile, err := ReturnCachedFile(binaryName) - if err == 0 { - // If the cached file exists, use it - fmt.Printf("\r\033[KUsing cached file: %s\n", cachedFile) - // Copy the cached file to the install path - if err := copyFile(cachedFile, installPath); err != nil { - return fmt.Errorf("Error: Could not copy cached file: %v", err) - } - - // Set executable bit immediately after copying - if err := os.Chmod(installPath, 0755); err != nil { - return fmt.Errorf("failed to set executable bit: %v", err) - } - - return nil - } - } - - // If the cached file does not exist, download the binary - url, err := findURL(binaryName) - if err != nil { - errorOut("%v\n", err) - } - if err := fetchBinaryFromURL(url, installPath); err != nil { - return fmt.Errorf("Error: Could not install binary: %v", err) - } - - // Check if the user provided a custom installMessage and If so, print it as per his requirements. - if len(installMessage) != 0 { - if installMessage[0] == "--fancy" { - if installMessage[1] == "--truncate" { - truncatePrintf(installMessage[2], binaryName) - } else { - fmt.Printf(installMessage[1], binaryName) - } - if len(installMessage) > 2 && installMessage[2] == "--newline" || len(installMessage) > 3 && installMessage[3] == "--newline" { - fmt.Println() - } - } else { - if installMessage[0] == "--truncate" { - fmt.Println(truncateSprintf("%s", installMessage[1])) - } else { - if installMessage[0] == "--silent" { - } else { - fmt.Println(installMessage[0]) - } - } - } - } else { - fmt.Printf("Installation complete: %s\n", installPath) - } - return nil -} diff --git a/baks/.main.go b/baks/.main.go deleted file mode 100644 index ddd29e2..0000000 --- a/baks/.main.go +++ /dev/null @@ -1,297 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "os" - "path/filepath" - "runtime" - "strconv" -) - -var ( - Repositories []string - MetadataURLs []string - validatedArch = [3]string{} - InstallDir = os.Getenv("INSTALL_DIR") - installUseCache = true - useProgressBar = true - disableTruncation = false -) - -const ( - RMetadataURL = "https://raw.githubusercontent.com/metis-os/hysp-pkgs/main/data/metadata.json" // This is the file from which we extract descriptions for different binaries //unreliable mirror: "https://raw.githubusercontent.com/Azathothas/Toolpacks/main/metadata.json" - RNMetadataURL = "https://bin.ajam.dev/METADATA.json" // This is the file which contains a concatenation of all metadata in the different repos, this one also contains sha256 checksums. - VERSION = "1.6" - usagePage = " [-v|-h] [list|install|remove|update|run|info|search|tldr] <{args}>" - // Truncation indicator - indicator = "...>" - // Cache size limit & handling. - MaxCacheSize = 10 - BinariesToDelete = 5 // Once the cache is filled - The programs populate the list of binaries to be removed in order of least used. - TEMP_DIR = "/tmp/bigdl_cached" -) - -// Exclude specified file types and file names, these shall not appear in Lists nor in the Search Results -var excludedFileTypes = map[string]struct{}{ - ".7z": {}, - ".bz2": {}, - ".json": {}, - ".gz": {}, - ".md": {}, - ".txt": {}, - ".tar": {}, - ".zip": {}, - ".exe": {}, - ".cfg": {}, -} - -var excludedFileNames = map[string]struct{}{ - "TEST": {}, - "LICENSE": {}, - "experimentalBinaries_dir": {}, - "robotstxt": {}, - "bdl.sh": {}, - // Because the repo contains duplicated files. And I do not manage the repo: - "uroot": {}, - "uroot-busybox": {}, - "gobusybox": {}, - "sysinfo-collector": {}, - "neofetch": {}, -} - -func init() { - if InstallDir == "" { - homeDir, err := os.UserHomeDir() - if err != nil { - fmt.Fprintf(os.Stderr, "Error: Failed to get user's Home directory. %v\n", err) - os.Exit(1) - } - InstallDir = filepath.Join(homeDir, ".local", "bin") - } - - if os.Getenv("DISABLE_TRUNCATION") == "true" || os.Getenv("DISABLE_TRUNCATION") == "1" { - disableTruncation = true - } - - if os.Getenv("DISABLE_PRBAR") == "true" || os.Getenv("DISABLE_PRBAR") == "1" { - useProgressBar = false - } - - switch runtime.GOARCH { - case "amd64": - validatedArch = [3]string{"x86_64_Linux", "x86_64", "x86_64-Linux"} - case "arm64": - validatedArch = [3]string{"aarch64_arm64_Linux", "aarch64_arm64", "aarch64-Linux"} - default: - fmt.Println("Unsupported architecture:", runtime.GOARCH) - os.Exit(1) - } - arch := validatedArch[0] - Repositories = append(Repositories, "https://bin.ajam.dev/"+arch+"/") - Repositories = append(Repositories, "https://bin.ajam.dev/"+arch+"/Baseutils/") - Repositories = append(Repositories, "https://raw.githubusercontent.com/xplshn/Handyscripts/master/") - // These are used for listing the binaries themselves - MetadataURLs = append(MetadataURLs, "https://bin.ajam.dev/"+arch+"/METADATA.json") - MetadataURLs = append(MetadataURLs, "https://bin.ajam.dev/"+arch+"/Baseutils/METADATA.json") - MetadataURLs = append(MetadataURLs, "https://api.github.com/repos/xplshn/Handyscripts/contents") // You may add other repos if need be? bigdl is customizable, feel free to open a PR, ask questions, etc. -} - -func printHelp() { - helpMessage := "Usage:\n" + usagePage + ` - -Options: - -h, --help Show this help message - -v, --version Show the version number - -Commands: - list List all available binaries - install, add Install a binary - remove, del Remove a binary - update Update binaries, by checking their SHA against the repo's SHA - run Run a binary - info Show information about a specific binary - search Search for a binary - (not all binaries have metadata. Use list to see all binaries) - tldr Show a brief description & usage examples for a given program/command. This is an alias equivalent to using "run" with "tlrc" as argument. - -Examples: - bigdl search editor - bigdl install micro - bigdl install lux --fancy "%s was installed to $INSTALL_DIR." --newline - bigdl install bed --fancy --truncate "%s was installed to $INSTALL_DIR." --newline - bigdl install orbiton --truncate "installed Orbiton to $INSTALL_DIR." - bigdl remove bed - bigdl remove orbiton tgpt lux - bigdl info jq - bigdl tldr gum - bigdl run --verbose curl -qsfSL "https://raw.githubusercontent.com/xplshn/bigdl/master/stubdl" | sh - - bigdl run --silent elinks -no-home "https://fatbuffalo.neocities.org/def" - bigdl run --transparent --silent micro ~/.profile - bigdl run btop - -Version: ` + VERSION - - fmt.Println(helpMessage) -} - -func main() { - errorOutInsufficientArgs := func() { errorOut("Error: Insufficient parameters\n") } - version := flag.Bool("v", false, "Show the version number") - versionLong := flag.Bool("version", false, "Show the version number") - - flag.Usage = printHelp - flag.Parse() - - if *version || *versionLong { - errorOut("bigdl %s\n", VERSION) - } - - if flag.NArg() < 1 { - errorOut(" bigdl:%s\n", usagePage) - } - - // From now on, things happen. - if err := os.MkdirAll(InstallDir, os.ModePerm); err != nil { - fmt.Fprintf(os.Stderr, "Error: Failed to get user's Home directory. %v\n", err) - os.Exit(1) - } - - switch flag.Arg(0) { - case "find_url": - binaryName := flag.Arg(1) - if binaryName == "" { - fmt.Println("Usage: bigdl find_url [binary]") - errorOutInsufficientArgs() - } - findURLCommand(binaryName) - case "list": - if len(os.Args) == 3 { - if os.Args[2] == "--described" || os.Args[2] == "-d" { - fSearch("", 99999) // Call fSearch with an empty query and a large limit to list all described binaries - } else { - errorOut("bigdl: Unknown command.\n") - } - } else { - binaries, err := listBinaries() - if err != nil { - fmt.Println("Error listing binaries:", err) - os.Exit(1) - } - for _, binary := range binaries { - fmt.Println(binary) - } - } - case "install", "add": - // Check if the binary name is provided - if flag.NArg() < 2 { - fmt.Printf("Usage: bigdl %s [binary] \n", flag.Arg(0)) - fmt.Println("Options:") - fmt.Println(" --fancy <--truncate> : Will replace exactly ONE '%s' with the name of the requested binary in the install message <--newline>") - fmt.Println(" --truncate: Truncates the message to fit into the terminal") - errorOutInsufficientArgs() - } - - binaryName := os.Args[2] - installMessage := os.Args[3:] - - installCommand(binaryName, installMessage...) - case "remove", "del": - if flag.NArg() < 2 { - fmt.Printf("Usage: bigdl %s [binar|y|ies]\n", flag.Arg(0)) - errorOutInsufficientArgs() - } - remove(flag.Args()[1:]) - case "run": - if flag.NArg() < 2 { - fmt.Println("Usage: bigdl run <--verbose, --silent, --transparent> [binary] ") - errorOutInsufficientArgs() - } - RunFromCache(flag.Arg(1), flag.Args()[2:]) - case "tldr": - if flag.NArg() < 2 { - fmt.Println("Usage: bigdl tldr [page]") - errorOutInsufficientArgs() - } - RunFromCache("tlrc", flag.Args()[1:]) - case "info": - binaryName := flag.Arg(1) - - if len(os.Args) > 3 { - fmt.Fprintln(os.Stderr, "Warning: The command contains more arguments than expected. Part of the input unused.") - } - - if len(os.Args) < 3 { - installedPrograms, err := validateProgramsFrom(InstallDir, nil) - if err != nil { - fmt.Println("Error validating programs:", err) - return - } - for _, program := range installedPrograms { - fmt.Println(program) - } - } else { - - binaryInfo, err := getBinaryInfo(binaryName) - if err != nil { - errorOut("%v\n", err) - } - fmt.Printf("Name: %s\n", binaryInfo.Name) - if binaryInfo.Description != "" { - fmt.Printf("Description: %s\n", binaryInfo.Description) - } - if binaryInfo.Repo != "" { - fmt.Printf("Repo: %s\n", binaryInfo.Repo) - } - if binaryInfo.Updated != "" { - fmt.Printf("Updated: %s\n", binaryInfo.Updated) - } - if binaryInfo.Version != "" { - fmt.Printf("Version: %s\n", binaryInfo.Version) - } - if binaryInfo.Size != "" { - fmt.Printf("Size: %s\n", binaryInfo.Size) - } - if binaryInfo.SHA256 != "" { - fmt.Printf("SHA256: %s\n", binaryInfo.SHA256) - } - if binaryInfo.B3SUM != "" { - fmt.Printf("B3SUM: %s\n", binaryInfo.B3SUM) - } - if binaryInfo.Source != "" { - fmt.Printf("Source: %s\n", binaryInfo.Source) - } - } - case "search": - limit := 90 - queryIndex := 2 - - if len(os.Args) < queryIndex+1 { - fmt.Println("Usage: bigdl search <--limit||-l [int]> [query]") - os.Exit(1) - } - - if len(os.Args) > 2 && os.Args[queryIndex] == "--limit" || os.Args[queryIndex] == "-l" { - if len(os.Args) > queryIndex+1 { - var err error - limit, err = strconv.Atoi(os.Args[queryIndex+1]) - if err != nil { - errorOut("Error: 'limit' value is not an int.\n") - } - queryIndex += 2 - } else { - errorOut("Error: Missing 'limit' value.\n") - } - } - - query := os.Args[queryIndex] - fSearch(query, limit) - case "update": - var programsToUpdate []string - if len(os.Args) > 2 { - programsToUpdate = os.Args[2:] - } - update(programsToUpdate) - default: - errorOut("bigdl: Unknown command.\n") - } -} diff --git a/baks/.run.go b/baks/.run.go deleted file mode 100644 index 3a83737..0000000 --- a/baks/.run.go +++ /dev/null @@ -1,236 +0,0 @@ -// run.go // This file implements the "run" functionality //> -package main - -import ( - "flag" - "fmt" - "os" - "os/exec" - "path/filepath" - "sort" - "strings" - "syscall" - "time" -) - -var verboseMode bool -var silentMode bool -var transparentMode bool - -// ReturnCachedFile retrieves the cached file location. Returns an empty string and error code 1 if not found. -func ReturnCachedFile(binaryName string) (string, int) { - // Construct the expected cached file pattern - expectedCachedFile := filepath.Join(TEMP_DIR, fmt.Sprintf("%s.bin", binaryName)) - - // Check if the file exists using the fileExists function - if fileExists(expectedCachedFile) { - return expectedCachedFile, 0 - } - - // If the file does not exist, return an error - return "", 1 -} - -// RunFromCache runs the binary from cache or fetches it if not found. -func RunFromCache(binaryName string, args []string) { - - // purifyVars is a function to purify binaryName and args. - purifyVars := func() { - if len(args) > 0 { - binaryName = (args)[0] // Purify binaryName - args = (args)[1:] // Appropriately set args to exclude any of the flags - } else { - errorOut("Error: Binary name not provided after flag.\n") - } - } - - // Process flags - verbose := flag.Bool("verbose", false, "Enable verbose mode") - silent := flag.Bool("silent", false, "Enable silent mode") - transparent := flag.Bool("transparent", false, "Enable transparent mode") - - flags_AndBinaryName := append(strings.Fields(binaryName), args...) - flag.CommandLine.Parse(flags_AndBinaryName) - - if *verbose && *silent { - errorOut("Error: --verbose and --silent are mutually exclusive\n") - } - - if *verbose { - verboseMode = true - purifyVars() - } - - if *silent { - silentMode = true - purifyVars() - } - - if *transparent { - transparentMode = true - - purifyVars() - binaryPath, err := isBinaryInPath(binaryName) - if err != nil { - errorOut("Error checking if binary is in PATH: %s\n", err) - } - - if binaryPath != "" { - if !silentMode { - fmt.Printf("Running '%s' from PATH...\n", binaryName) - } - runBinary(binaryPath, args, verboseMode) - } - } - - if binaryName == "" { - errorOut("Error: Binary name not provided\n") - } - - cachedFile := filepath.Join(TEMP_DIR, binaryName+".bin") - if fileExists(cachedFile) && isExecutable(cachedFile) { - if !silentMode { - fmt.Printf("Running '%s' from cache...\n", binaryName) - } - runBinary(cachedFile, args, verboseMode) - cleanCache() - } else { - if verboseMode { - fmt.Printf("Couldn't find '%s' in the cache. Fetching a new one...\n", binaryName) - } - err := fetchBinary(binaryName) - if err != nil { - fmt.Fprintf(os.Stderr, "Error fetching binary for '%s'\n", binaryName) - errorOut("Error: %s\n", err) - } - cleanCache() - runBinary(cachedFile, args, verboseMode) - } -} - -// runBinary executes the binary with the given arguments, handling .bin files as needed. -func runBinary(binaryPath string, args []string, verboseMode bool) { - var programExitCode = 1 - executeBinary := func(rbinaryPath string, args []string, verboseMode bool) { - cmd := exec.Command(rbinaryPath, args...) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - cmd.Stdin = os.Stdin - if err := cmd.Run(); err != nil { - if exitError, ok := err.(*exec.ExitError); ok { - if status, ok := exitError.Sys().(syscall.WaitStatus); ok { - if verboseMode { - fmt.Printf("The program (%s) errored out with a non-zero exit code (%d).\n", binaryPath, status.ExitStatus()) - } - programExitCode = status.ExitStatus() - } - } else { - programExitCode = 1 - } - } else { - programExitCode = 0 - } - } - // If the file ends with .bin, remove the suffix and proceed to run it, afterwards, set the same suffix again. - if strings.HasSuffix(binaryPath, ".bin") { - tempFile := filepath.Join(filepath.Dir(binaryPath), strings.TrimSuffix(filepath.Base(binaryPath), ".bin")) - if err := copyFile(binaryPath, tempFile); err != nil { - fmt.Printf("failed to move binary to temporary location: %v\n", err) - return - } - if err := os.Chmod(tempFile, 0755); err != nil { - fmt.Printf("failed to set executable bit: %v\n", err) - return - } - - executeBinary(tempFile, args, verboseMode) - if err := os.Rename(tempFile, binaryPath); err != nil { - fmt.Printf("failed to move temporary binary back to original name: %v\n", err) - return - } - } else { - executeBinary(binaryPath, args, verboseMode) - } - // Exit the program with the exit code from the executed binary or 1 if we couldn't even get to the execution - os.Exit(programExitCode) -} - -// fetchBinary downloads the binary and caches it. -func fetchBinary(binaryName string) error { - if silentMode { - useProgressBar = false - } - - url, err := findURL(binaryName) - if err != nil { - return err - } - - cachedFile := filepath.Join(TEMP_DIR, binaryName+".bin") - - // Fetch the binary from the internet and save it to the cache - err = fetchBinaryFromURL(url, cachedFile) - if err != nil { - return fmt.Errorf("error fetching binary for %s: %v", binaryName, err) - } - - cleanCache() - return nil -} - -// cleanCache removes the oldest binaries when the cache size exceeds MaxCacheSize. -func cleanCache() { - // Get a list of all binaries in the cache directory - files, err := os.ReadDir(TEMP_DIR) - if err != nil { - fmt.Printf("Error reading cache directory: %v\n", err) - return - } - - // Check if the cache size has exceeded the limit - if len(files) <= MaxCacheSize { - return - } - - // Use a custom struct to hold file info and atime - type fileWithAtime struct { - info os.FileInfo - atime time.Time - } - - // Convert os.DirEntry to fileWithAtime and track the last accessed time - var filesWithAtime []fileWithAtime - for _, entry := range files { - fileInfo, err := entry.Info() - if err != nil { - fmt.Printf("Error getting file info: %v\n", err) - continue - } - - // Use syscall to get atime - var stat syscall.Stat_t - err = syscall.Stat(filepath.Join(TEMP_DIR, entry.Name()), &stat) - if err != nil { - fmt.Printf("Error getting file stat: %v\n", err) - continue - } - - atime := time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec)) - filesWithAtime = append(filesWithAtime, fileWithAtime{info: fileInfo, atime: atime}) - } - - // Sort files by last accessed time - sort.Slice(filesWithAtime, func(i, j int) bool { - return filesWithAtime[i].atime.Before(filesWithAtime[j].atime) - }) - - // Delete the oldest binaries - for i := 0; i < BinariesToDelete; i++ { - err := os.Remove(filepath.Join(TEMP_DIR, filesWithAtime[i].info.Name())) - if err != nil { - if !silentMode { // Check if not in silent mode before printing - fmt.Printf("Error removing file: %v\n", err) - } - } - } -}