Git Repository
Stackyard
Stackyard scannt lokale Entwicklungsordner und bündelt Projekte, Git-Status, TODOs, Toolchains, Docker-Compose-Setups, Datei- und Launcher-Funktionen sowie Operations-Informationen in einer lokalen WebUI.
HTTPS
https://zanvex.de/git/stackyard.gitinternal/project/discovery.go
Zum Verzeichnispackage project
import (
"os"
"path/filepath"
"regexp"
"sort"
"strconv"
"strings"
)
var (
miseLinePattern = regexp.MustCompile(`(?m)^\s*([A-Za-z0-9._-]+)\s*=\s*["']?([^"'\n]+)["']?\s*$`)
portPattern = regexp.MustCompile(`(?m)(\d{2,5})\s*:\s*(\d{2,5})`)
exposedPortPattern = regexp.MustCompile(`(?m)\b(?:PORT|EXPOSE_PORT|VITE_PORT|DEV_PORT)\s*[:=]\s*["']?(\d{2,5})["']?`)
)
func DiscoverMiseTools(projectDir string) []string {
path := filepath.Join(projectDir, ".mise.toml")
data, err := os.ReadFile(path)
if err != nil {
return nil
}
lines := strings.Split(string(data), "\n")
inTools := false
tools := make([]string, 0)
for _, line := range lines {
trimmed := strings.TrimSpace(line)
if trimmed == "" || strings.HasPrefix(trimmed, "#") {
continue
}
if strings.HasPrefix(trimmed, "[") {
inTools = trimmed == "[tools]"
continue
}
if !inTools {
continue
}
matches := miseLinePattern.FindStringSubmatch(trimmed)
if len(matches) != 3 {
continue
}
tools = append(tools, matches[1]+" "+strings.TrimSpace(matches[2]))
}
sort.Strings(tools)
return tools
}
func DiscoverComposeFiles(projectDir string) []string {
candidates := []string{"docker-compose.yml", "compose.yml"}
files := make([]string, 0, len(candidates))
for _, name := range candidates {
if _, err := os.Stat(filepath.Join(projectDir, name)); err == nil {
files = append(files, name)
}
}
return files
}
func DiscoverPorts(projectDir string) []int {
paths := []string{
filepath.Join(projectDir, "docker-compose.yml"),
filepath.Join(projectDir, "compose.yml"),
filepath.Join(projectDir, ".env"),
filepath.Join(projectDir, "README.md"),
}
ports := make(map[int]struct{})
for _, path := range paths {
data, err := os.ReadFile(path)
if err != nil {
continue
}
for _, match := range portPattern.FindAllStringSubmatch(string(data), -1) {
if len(match) < 2 {
continue
}
port, err := strconv.Atoi(match[1])
if err == nil && port > 0 && port <= 65535 {
ports[port] = struct{}{}
}
}
for _, match := range exposedPortPattern.FindAllStringSubmatch(string(data), -1) {
if len(match) < 2 {
continue
}
port, err := strconv.Atoi(match[1])
if err == nil && port > 0 && port <= 65535 {
ports[port] = struct{}{}
}
}
}
values := make([]int, 0, len(ports))
for port := range ports {
values = append(values, port)
}
sort.Ints(values)
return values
}