196 lines
5.8 KiB
Go
196 lines
5.8 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
// "github.com/adrg/xdg"
|
|
)
|
|
|
|
// Installer verwaltet die Installation von LSP-Servern
|
|
type Installer struct {
|
|
installDir string
|
|
binDir string
|
|
}
|
|
|
|
// NewInstaller erstellt einen XDG-konformen Installer
|
|
func NewInstaller(baseDir string) *Installer {
|
|
installDir := filepath.Join(baseDir, "servers")
|
|
binDir := filepath.Join(baseDir, "bin")
|
|
|
|
// Verzeichnisse erstellen
|
|
os.MkdirAll(installDir, 0755)
|
|
os.MkdirAll(binDir, 0755)
|
|
|
|
return &Installer{
|
|
installDir: installDir,
|
|
binDir: binDir,
|
|
}
|
|
}
|
|
|
|
// PrintPathInstructions zeigt dem Benutzer, wie der PATH gesetzt wird
|
|
func (i *Installer) PrintPathInstructions() {
|
|
fmt.Println("\n📁 LSP-Server werden installiert in:")
|
|
fmt.Printf(" Binaries: %s\n", i.binDir)
|
|
fmt.Printf(" Data: %s\n\n", i.installDir)
|
|
|
|
// Prüfen ob bereits im PATH
|
|
pathEnv := os.Getenv("PATH")
|
|
pathList := filepath.SplitList(pathEnv)
|
|
inPath := false
|
|
for _, p := range pathList {
|
|
if p == i.binDir {
|
|
inPath = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !inPath {
|
|
fmt.Println("⚠️ Das Binary-Verzeichnis ist noch nicht im PATH!")
|
|
fmt.Println("\nFüge folgende Zeile zu deiner Shell-Konfiguration hinzu:")
|
|
fmt.Printf("\n # Für Bash (~/.bashrc):\n")
|
|
fmt.Printf(" export PATH=\"%s:$PATH\"\n\n", i.binDir)
|
|
fmt.Printf(" # Für Zsh (~/.zshrc):\n")
|
|
fmt.Printf(" export PATH=\"%s:$PATH\"\n\n", i.binDir)
|
|
fmt.Printf(" # Für Fish (~/.config/fish/config.fish):\n")
|
|
fmt.Printf(" set -x PATH %s $PATH\n\n", i.binDir)
|
|
} else {
|
|
fmt.Println("✅ Binary-Verzeichnis ist bereits im PATH!")
|
|
}
|
|
}
|
|
|
|
// Install installiert einen LSP-Server basierend auf dem Typ
|
|
func (i *Installer) Install(server LSPServer) error {
|
|
switch server.InstallType {
|
|
case "go", "golang":
|
|
return i.installGo(server)
|
|
case "npm":
|
|
return i.installNpm(server)
|
|
case "github":
|
|
return i.installGithub(server)
|
|
case "cargo":
|
|
return i.installCargo(server)
|
|
default:
|
|
return fmt.Errorf("unsupported install type: %s (für %s)", server.InstallType, server.Name)
|
|
}
|
|
}
|
|
|
|
// installGo installiert einen LSP-Server via go install
|
|
func (i *Installer) installGo(server LSPServer) error {
|
|
// Mason Source format: "golang.org/x/tools/gopls" oder ähnlich
|
|
source := server.Source
|
|
if !strings.Contains(source, "@") {
|
|
source = source + "@" + server.Version
|
|
}
|
|
|
|
cmd := exec.Command("go", "install", source)
|
|
cmd.Env = append(os.Environ(),
|
|
"GOBIN="+i.binDir,
|
|
)
|
|
|
|
output, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return fmt.Errorf("go install failed: %v\nOutput: %s", err, output)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// installNpm installiert einen LSP-Server via npm
|
|
func (i *Installer) installNpm(server LSPServer) error {
|
|
serverDir := filepath.Join(i.installDir, server.Name)
|
|
os.MkdirAll(serverDir, 0755)
|
|
|
|
// Mason Source format: "package-name" (einfacher npm Package-Name)
|
|
cmd := exec.Command("npm", "install", "-g", "--prefix", serverDir, server.Source)
|
|
output, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return fmt.Errorf("npm install failed: %v\nOutput: %s", err, output)
|
|
}
|
|
|
|
// Symlink zum bin-Verzeichnis erstellen
|
|
// npm installiert in serverDir/lib/node_modules/.bin/
|
|
binPath := filepath.Join(serverDir, "lib", "node_modules", ".bin", server.Executable)
|
|
linkPath := filepath.Join(i.binDir, server.Executable)
|
|
|
|
os.Remove(linkPath) // Alten Link entfernen
|
|
return os.Symlink(binPath, linkPath)
|
|
}
|
|
|
|
// installGithub lädt ein Binary von GitHub Releases herunter
|
|
func (i *Installer) installGithub(server LSPServer) error {
|
|
// Mason Source format: "owner/repo"
|
|
// Wir müssen die Download-URL konstruieren (vereinfacht)
|
|
downloadURL := fmt.Sprintf("https://github.com/%s/releases/latest/download/%s",
|
|
server.Source, server.Executable)
|
|
|
|
resp, err := http.Get(downloadURL)
|
|
if err != nil {
|
|
return fmt.Errorf("download failed: %w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
return fmt.Errorf("download failed with status: %d", resp.StatusCode)
|
|
}
|
|
|
|
targetPath := filepath.Join(i.binDir, server.Executable)
|
|
file, err := os.Create(targetPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
|
|
_, err = io.Copy(file, resp.Body)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Executable-Rechte setzen
|
|
return os.Chmod(targetPath, 0755)
|
|
}
|
|
|
|
// installCargo installiert einen LSP-Server via cargo
|
|
func (i *Installer) installCargo(server LSPServer) error {
|
|
serverDir := filepath.Join(i.installDir, server.Name)
|
|
|
|
// Mason Source format: "crate-name"
|
|
cmd := exec.Command("cargo", "install",
|
|
server.Source,
|
|
"--root", serverDir)
|
|
|
|
output, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return fmt.Errorf("cargo install failed: %v\nOutput: %s", err, output)
|
|
}
|
|
|
|
// Symlink erstellen
|
|
binPath := filepath.Join(serverDir, "bin", server.Executable)
|
|
linkPath := filepath.Join(i.binDir, server.Executable)
|
|
|
|
os.Remove(linkPath)
|
|
return os.Symlink(binPath, linkPath)
|
|
}
|
|
|
|
// IsInstalled prüft, ob ein Server installiert ist
|
|
func (i *Installer) IsInstalled(server LSPServer) bool {
|
|
binPath := filepath.Join(i.binDir, server.Executable)
|
|
_, err := os.Stat(binPath)
|
|
return err == nil
|
|
}
|
|
|
|
// Uninstall entfernt einen installierten LSP-Server
|
|
func (i *Installer) Uninstall(server LSPServer) error {
|
|
binPath := filepath.Join(i.binDir, server.Executable)
|
|
serverDir := filepath.Join(i.installDir, server.Name)
|
|
|
|
os.Remove(binPath)
|
|
os.RemoveAll(serverDir)
|
|
|
|
return nil
|
|
}
|