package main import ( "archive/tar" "bytes" "compress/gzip" _ "embed" "encoding/json" "fmt" "io" "mime/multipart" "net/http" "os" "path/filepath" "time" "github.com/briandowns/spinner" ) //go:embed config.json var config []byte var configPath = filepath.Join(os.Getenv("HOME"), "/.config/flux") type Config struct { DeamonURL string `json:"deamon_url"` } func compressDirectory() ([]byte, error) { var buf bytes.Buffer gzWriter := gzip.NewWriter(&buf) tarWriter := tar.NewWriter(gzWriter) err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error { if err != nil { return err } if path == "flux.json" || info.IsDir() { return nil } header, err := tar.FileInfoHeader(info, "") if err != nil { return err } header.Name = path if err := tarWriter.WriteHeader(header); err != nil { return err } if !info.IsDir() { file, err := os.Open(path) if err != nil { return err } defer file.Close() if _, err := io.Copy(tarWriter, file); err != nil { return err } } return nil }) if err != nil { return nil, err } if err := tarWriter.Close(); err != nil { return nil, err } if err := gzWriter.Close(); err != nil { return nil, err } return buf.Bytes(), nil } func main() { if len(os.Args) < 2 { fmt.Println("Usage: flux ") os.Exit(1) } command := os.Args[1] if _, err := os.Stat(filepath.Join(configPath, "config.json")); err != nil { if err := os.MkdirAll(configPath, 0755); err != nil { fmt.Printf("Failed to create config directory: %v\n", err) os.Exit(1) } if err = os.WriteFile(filepath.Join(configPath, "config.json"), config, 0644); err != nil { fmt.Printf("Failed to write config file: %v\n", err) os.Exit(1) } } var config Config configBytes, err := os.ReadFile(filepath.Join(configPath, "config.json")) if err != nil { fmt.Printf("Failed to read config file: %v\n", err) os.Exit(1) } if err := json.Unmarshal(configBytes, &config); err != nil { fmt.Printf("Failed to parse config file: %v\n", err) os.Exit(1) } switch command { case "deploy": loadingSpinner := spinner.New(spinner.CharSets[14], 100*time.Millisecond) loadingSpinner.Suffix = " Deploying" loadingSpinner.Start() buf, err := compressDirectory() if err != nil { loadingSpinner.Stop() fmt.Printf("Failed to compress directory: %v\n", err) os.Exit(1) } body := &bytes.Buffer{} writer := multipart.NewWriter(body) configPart, err := writer.CreateFormFile("config", "flux.json") if err != nil { loadingSpinner.Stop() fmt.Printf("Failed to create config part: %v\n", err) os.Exit(1) } fluxConfigFile, err := os.Open("flux.json") if err != nil { loadingSpinner.Stop() fmt.Printf("Failed to open flux.json: %v\n", err) os.Exit(1) } defer fluxConfigFile.Close() if _, err := io.Copy(configPart, fluxConfigFile); err != nil { loadingSpinner.Stop() fmt.Printf("Failed to write config part: %v\n", err) os.Exit(1) } codePart, err := writer.CreateFormFile("code", "code.tar.gz") if err != nil { loadingSpinner.Stop() fmt.Printf("Failed to create code part: %v\n", err) os.Exit(1) } if _, err := codePart.Write(buf); err != nil { loadingSpinner.Stop() fmt.Printf("Failed to write code part: %v\n", err) os.Exit(1) } if err := writer.Close(); err != nil { loadingSpinner.Stop() fmt.Printf("Failed to close writer: %v\n", err) os.Exit(1) } resp, err := http.Post(config.DeamonURL+"/deploy", "multipart/form-data; boundary="+writer.Boundary(), body) if err != nil { loadingSpinner.Stop() fmt.Printf("Failed to send request: %v\n", err) os.Exit(1) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { loadingSpinner.Stop() responseBody, err := io.ReadAll(resp.Body) if err != nil { fmt.Printf("error reading response body: %v\n", err) os.Exit(1) } if len(responseBody) > 0 && responseBody[len(responseBody)-1] == '\n' { responseBody = responseBody[:len(responseBody)-1] } fmt.Printf("Deploy failed: %s\n", responseBody) os.Exit(1) } loadingSpinner.Stop() fmt.Println("Deployed successfully!") default: fmt.Println("Unknown command:", command) } }