install.go

 1package cli
 2
 3import (
 4	"fmt"
 5	"io"
 6	"net/http"
 7	"os"
 8	"path/filepath"
 9	"strings"
10	"time"
11)
12
13// RunInstall handles `matcha install <url_or_file>`.
14func RunInstall(args []string) error {
15	if len(args) == 0 {
16		return fmt.Errorf("usage: matcha install <url_or_file>")
17	}
18
19	source := args[0]
20	var data []byte
21	var filename string
22
23	if strings.HasPrefix(source, "http://") || strings.HasPrefix(source, "https://") {
24		// Download from URL
25		client := &http.Client{Timeout: 30 * time.Second}
26		resp, err := client.Get(source)
27		if err != nil {
28			return fmt.Errorf("failed to download: %w", err)
29		}
30		defer resp.Body.Close()
31
32		if resp.StatusCode != http.StatusOK {
33			return fmt.Errorf("download returned status %d", resp.StatusCode)
34		}
35
36		data, err = io.ReadAll(resp.Body)
37		if err != nil {
38			return fmt.Errorf("failed to read response: %w", err)
39		}
40
41		// Extract filename from URL path
42		parts := strings.Split(strings.TrimRight(source, "/"), "/")
43		filename = parts[len(parts)-1]
44	} else {
45		// Read from local file
46		var err error
47		data, err = os.ReadFile(source)
48		if err != nil {
49			return fmt.Errorf("failed to read file: %w", err)
50		}
51		filename = filepath.Base(source)
52	}
53
54	if !strings.HasSuffix(filename, ".lua") {
55		return fmt.Errorf("plugin file must have a .lua extension")
56	}
57
58	pluginsDir, err := pluginsDir()
59	if err != nil {
60		return err
61	}
62
63	dest := filepath.Join(pluginsDir, filename)
64	if err := os.WriteFile(dest, data, 0644); err != nil {
65		return fmt.Errorf("failed to write plugin: %w", err)
66	}
67
68	fmt.Printf("Installed %s to %s\n", filename, dest)
69	return nil
70}
71
72func pluginsDir() (string, error) {
73	home, err := os.UserHomeDir()
74	if err != nil {
75		return "", fmt.Errorf("cannot find home directory: %w", err)
76	}
77	dir := filepath.Join(home, ".config", "matcha", "plugins")
78	if err := os.MkdirAll(dir, 0755); err != nil {
79		return "", fmt.Errorf("cannot create plugins directory: %w", err)
80	}
81	return dir, nil
82}