package main import ( "bufio" "fmt" "io" "os" "os/exec" "path/filepath" "sort" "strings" ) func getScriptMetadata(scriptPath string) (string, bool) { file, err := os.Open(scriptPath) if err != nil { return "No description", false } defer file.Close() var desc string var requiresSudo bool scanner := bufio.NewScanner(file) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if strings.HasPrefix(line, "# NAME:") { desc = strings.TrimSpace(strings.TrimPrefix(line, "# NAME:")) } if strings.HasPrefix(line, "# REQUIRES: sudo") || strings.HasPrefix(line, "# REQUIRES:sudo") || strings.HasPrefix(line, "# ELEVATED: true") || strings.HasPrefix(line, "# ELEVATED:true") || strings.HasPrefix(line, "# SUDO: true") || strings.HasPrefix(line, "# SUDO:true") { requiresSudo = true } } if desc == "" { desc = "No description" } return desc, requiresSudo } func findScripts(filters []string) ([]Script, error) { var scripts []Script err := filepath.Walk(config.RunsDir, func(path string, info os.FileInfo, err error) error { if err != nil { return err } if info.Mode().IsRegular() && (info.Mode()&0o111) != 0 { // Get relative path from runs directory relPath, err := filepath.Rel(config.RunsDir, path) if err != nil { return err } // Skip hidden files and directories if strings.HasPrefix(filepath.Base(path), ".") { return nil } scriptName := filepath.Base(path) if len(filters) == 0 || matchesFilters(relPath, scriptName, filters) { desc, requiresSudo := getScriptMetadata(path) scripts = append(scripts, Script{ Path: path, Name: scriptName, RelPath: relPath, Desc: desc, RequiresSudo: requiresSudo, }) } } return nil }) sort.Slice(scripts, func(i, j int) bool { return scripts[i].RelPath < scripts[j].RelPath }) return scripts, err } func matchesFilters(relPath, scriptName string, filters []string) bool { for _, filter := range filters { // Normalize paths for comparison (remove .sh extension from filter if present) normalizedFilter := strings.TrimSuffix(filter, ".sh") normalizedRelPath := strings.TrimSuffix(relPath, ".sh") normalizedScriptName := strings.TrimSuffix(scriptName, ".sh") // Check exact matches if normalizedRelPath == normalizedFilter || normalizedScriptName == normalizedFilter { return true } // Check if filter matches the relative path or script name (case insensitive) filterLower := strings.ToLower(normalizedFilter) relPathLower := strings.ToLower(normalizedRelPath) scriptNameLower := strings.ToLower(normalizedScriptName) if strings.Contains(relPathLower, filterLower) || strings.Contains(scriptNameLower, filterLower) { return true } // Check directory match (e.g., "tools" matches "tools/install.sh") if strings.HasPrefix(relPathLower, filterLower+"/") { return true } } return false } func executeScript(script Script, args []string, verbose bool) error { logFile := filepath.Join(config.LogsDir, strings.TrimSuffix(script.Name, filepath.Ext(script.Name))+".log") var cmd *exec.Cmd if script.RequiresSudo { sudoLog("Script requires elevated privileges: %s", script.RelPath) if !commandExists("sudo") { errorLog("sudo command not found - cannot run elevated script") return fmt.Errorf("sudo not available") } fullArgs := append([]string{script.Path}, args...) cmd = exec.Command("sudo", fullArgs...) sudoLog("Running with sudo: %s", strings.Join(append([]string{script.Path}, args...), " ")) } else { cmd = exec.Command(script.Path, args...) } if config.Interactive { cmd.Stdin = os.Stdin } logFileHandle, err := os.Create(logFile) if err != nil { return err } defer logFileHandle.Close() showOutput := verbose || config.Interactive if showOutput { cmd.Stdout = io.MultiWriter(os.Stdout, logFileHandle) cmd.Stderr = io.MultiWriter(os.Stderr, logFileHandle) } else { cmd.Stdout = logFileHandle cmd.Stderr = logFileHandle } return cmd.Run() } func createNewScript(scriptName string) error { scriptPath := filepath.Join(config.RunsDir, scriptName) dirPath := filepath.Dir(scriptPath) if err := os.MkdirAll(dirPath, 0o755); err != nil { return err } if !strings.HasSuffix(scriptName, ".sh") { scriptName += ".sh" } if _, err := os.Stat(scriptPath); err == nil { return fmt.Errorf("script %s already exists", scriptName) } template := fmt.Sprintf(`#!/usr/bin/env bash # NAME: %s script # REQUIRES: sudo set -euo pipefail echo "Running %s script..." echo "✅ %s completed successfully" `, strings.TrimSuffix(scriptName, ".sh"), scriptName, strings.TrimSuffix(scriptName, ".sh")) err := os.WriteFile(scriptPath, []byte(template), 0o755) if err != nil { return err } log("✅ Created script: %s", scriptPath) return nil } func ensureRunsDir() error { if _, err := os.Stat(config.RunsDir); os.IsNotExist(err) { log("Creating runs directory at: %s", config.RunsDir) if err := os.MkdirAll(config.RunsDir, 0o755); err != nil { return err } exampleScript := filepath.Join(config.RunsDir, "example.sh") content := `#!/usr/bin/env bash # NAME: Example script echo "Hello from runs/example.sh!" echo "Edit this script or add your own to runs/" ` if err := os.WriteFile(exampleScript, []byte(content), 0o755); err != nil { return err } sudoExampleScript := filepath.Join(config.RunsDir, "system-info.sh") sudoContent := `#!/usr/bin/env bash # NAME: System information collector # REQUIRES: sudo set -euo pipefail echo "Collecting system information (requires elevated privileges)..." echo "=== Disk Usage ===" df -h echo "=== Memory Info ===" free -h echo "=== System Logs (last 10 lines) ===" tail -n 10 /var/log/syslog 2>/dev/null || tail -n 10 /var/log/messages 2>/dev/null || echo "No accessible system logs" echo "✅ System info collection completed" ` if err := os.WriteFile(sudoExampleScript, []byte(sudoContent), 0o755); err != nil { return err } log("✅ Created runs/ directory with example scripts") return nil } return nil }