222 lines
5.6 KiB
Go
222 lines
5.6 KiB
Go
|
package cmd
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"context"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"io/fs"
|
||
|
"log"
|
||
|
"net/http"
|
||
|
"os"
|
||
|
"os/exec"
|
||
|
"path/filepath"
|
||
|
"runtime"
|
||
|
"strings"
|
||
|
"sync"
|
||
|
)
|
||
|
|
||
|
var processes []*exec.Cmd
|
||
|
var mu sync.Mutex
|
||
|
|
||
|
// walkFolder starts processes for files starting with "az" in the given folder
|
||
|
func walkFolder(folderPath string, ctx context.Context, wg *sync.WaitGroup) {
|
||
|
os.Chdir(folderPath)
|
||
|
files, err := os.ReadDir(".")
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
|
||
|
for _, file := range files {
|
||
|
// Check if filename starts with "oc-"
|
||
|
if strings.HasPrefix(file.Name(), "oc-") {
|
||
|
// Prepare the command to start the process
|
||
|
|
||
|
wg.Add(1)
|
||
|
go startProcess(ctx, file.Name(), wg)
|
||
|
}
|
||
|
// find
|
||
|
if strings.HasPrefix(strings.ToLower(file.Name()), "caddy") && strings.ToLower(file.Name()) != "caddyfile" {
|
||
|
runtime := findCaddyRuntime(".")
|
||
|
if runtime != "" {
|
||
|
// Prepare the command to start the process
|
||
|
wg.Add(1)
|
||
|
go startProcess(ctx, "./"+runtime, wg, "run")
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// startProcess runs the given program and stores a reference to it for later control
|
||
|
func startProcess(ctx context.Context, program string, wg *sync.WaitGroup, args ...string) {
|
||
|
defer wg.Done()
|
||
|
|
||
|
cmd := exec.CommandContext(ctx, program, args...)
|
||
|
|
||
|
mu.Lock()
|
||
|
processes = append(processes, cmd)
|
||
|
mu.Unlock()
|
||
|
|
||
|
var outBuf, errBuf bytes.Buffer
|
||
|
cmd.Stdout = &outBuf
|
||
|
cmd.Stderr = &errBuf
|
||
|
err := cmd.Start()
|
||
|
if err != nil {
|
||
|
log.Printf("Failed to start process: %s", program)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
log.Printf("Started process: %s", program)
|
||
|
|
||
|
fmt.Print(outBuf.String())
|
||
|
fmt.Print(errBuf.String())
|
||
|
|
||
|
err = cmd.Wait()
|
||
|
if err != nil {
|
||
|
log.Printf("Process finished with error: %v", err)
|
||
|
} else {
|
||
|
log.Printf("Process finished successfully: %s", program)
|
||
|
}
|
||
|
fmt.Print(outBuf.String())
|
||
|
fmt.Print(errBuf.String())
|
||
|
}
|
||
|
|
||
|
// stopAllProcesses stops all the started processes
|
||
|
func stopAllProcesses() {
|
||
|
mu.Lock()
|
||
|
defer mu.Unlock()
|
||
|
|
||
|
for _, cmd := range processes {
|
||
|
if cmd.Process != nil {
|
||
|
log.Printf("Killing process with PID %d", cmd.Process.Pid)
|
||
|
err := cmd.Process.Kill()
|
||
|
if err != nil {
|
||
|
log.Printf("Failed to kill process with PID %d: %v", cmd.Process.Pid, err)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
processes = []*exec.Cmd{}
|
||
|
}
|
||
|
|
||
|
func findCaddyRuntime(folder string) string {
|
||
|
var foundFile string
|
||
|
|
||
|
err := filepath.WalkDir(folder, func(path string, d fs.DirEntry, err error) error {
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
// Check if it's a file (not a directory)
|
||
|
if !d.IsDir() {
|
||
|
filename := d.Name()
|
||
|
// Check if the filename starts with "caddy" (case-insensitive) and is not "CaddyFile"
|
||
|
if strings.HasPrefix(strings.ToLower(filename), "caddy") && strings.ToLower(filename) != "caddyfile" {
|
||
|
foundFile = filename
|
||
|
return filepath.SkipDir // Skip further traversal once we find a match
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
})
|
||
|
|
||
|
if err != nil {
|
||
|
fmt.Println("Error:", err)
|
||
|
return ""
|
||
|
}
|
||
|
|
||
|
return foundFile
|
||
|
}
|
||
|
|
||
|
func downloadLatestCaddy(outputFolder string) error {
|
||
|
// Define the GitHub API URL for the latest Caddy release
|
||
|
apiURL := "https://api.github.com/repos/caddyserver/caddy/releases/latest"
|
||
|
|
||
|
// Get the system's OS and architecture
|
||
|
osName := runtime.GOOS
|
||
|
archName := runtime.GOARCH
|
||
|
|
||
|
// Make an HTTP GET request to the GitHub API
|
||
|
resp, err := http.Get(apiURL)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to get latest Caddy release: %v", err)
|
||
|
}
|
||
|
defer resp.Body.Close()
|
||
|
|
||
|
// Read the response body
|
||
|
body, err := io.ReadAll(resp.Body)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to read GitHub API response: %v", err)
|
||
|
}
|
||
|
|
||
|
// Find the download URL for the current platform (OS + architecture)
|
||
|
downloadURL := ""
|
||
|
urlPrefix := fmt.Sprintf("%s_%s", osName, archName)
|
||
|
lines := strings.Split(string(body), "\n")
|
||
|
for _, line := range lines {
|
||
|
if strings.Contains(line, "browser_download_url") && strings.Contains(line, urlPrefix) {
|
||
|
// Extract the URL
|
||
|
parts := strings.Split(line, "\"")
|
||
|
for _, part := range parts {
|
||
|
if strings.HasPrefix(part, "https://") && strings.Contains(part, urlPrefix) && (strings.HasSuffix(part, ".tar.gz") || strings.HasSuffix(part, ".zip")) {
|
||
|
downloadURL = part
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
if downloadURL != "" {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if downloadURL == "" {
|
||
|
return fmt.Errorf("failed to find a suitable Caddy binary for %s_%s", osName, archName)
|
||
|
}
|
||
|
|
||
|
// Make an HTTP GET request to download the file
|
||
|
resp, err = http.Get(downloadURL)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to download Caddy executable: %v", err)
|
||
|
}
|
||
|
defer resp.Body.Close()
|
||
|
suffix := ""
|
||
|
if strings.Contains(downloadURL, ".tar.gz") {
|
||
|
suffix = ".tar.gz"
|
||
|
} else if strings.Contains(downloadURL, ".zip") {
|
||
|
suffix = ".zip"
|
||
|
}
|
||
|
|
||
|
// Create the output file
|
||
|
outputPath := fmt.Sprintf("%s/caddy"+suffix, strings.TrimRight(outputFolder, "/"))
|
||
|
outFile, err := os.Create(outputPath)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to create output file: %v", err)
|
||
|
}
|
||
|
defer outFile.Close()
|
||
|
|
||
|
// Write the response body to the output file
|
||
|
_, err = io.Copy(outFile, resp.Body)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to write to output file: %v", err)
|
||
|
}
|
||
|
|
||
|
// Extract the downloaded file
|
||
|
if strings.Contains(downloadURL, ".tar.gz") {
|
||
|
err = exec.Command("tar", "-xzf", outputPath, "-C", outputFolder).Run()
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to extract tar.gz file: %v", err)
|
||
|
}
|
||
|
} else if strings.Contains(downloadURL, ".zip") {
|
||
|
err = exec.Command("unzip", outputPath, "-d", outputFolder).Run()
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to extract zip file: %v", err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Remove the downloaded file
|
||
|
err = os.Remove(outputPath)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to remove: %v", err)
|
||
|
}
|
||
|
|
||
|
fmt.Printf("Caddy downloaded successfully to %s\n", outputPath)
|
||
|
return nil
|
||
|
}
|