-142
cmd/install.go
-142
cmd/install.go
···
1
-
package cmd
2
-
3
-
import (
4
-
"fmt"
5
-
"os"
6
-
"os/exec"
7
-
"path/filepath"
8
-
"regexp"
9
-
"slices"
10
-
"strings"
11
-
12
-
"github.com/spf13/cobra"
13
-
)
14
-
15
-
var ghRepoRegexp = regexp.MustCompile(`^[a-z\d](?:[a-z\d-]{0,38}[a-z\d])?/[a-zA-Z0-9_.-]+$`)
16
-
17
-
func NewCmdInstall() *cobra.Command {
18
-
cmd := &cobra.Command{
19
-
Use: "install <repo> [app]",
20
-
Args: cobra.RangeArgs(1, 2),
21
-
Short: "Install an app",
22
-
PreRunE: func(cmd *cobra.Command, args []string) error {
23
-
if _, err := exec.LookPath("git"); err != nil {
24
-
return fmt.Errorf("git is not installed: %w", err)
25
-
}
26
-
27
-
return nil
28
-
},
29
-
RunE: func(cmd *cobra.Command, args []string) error {
30
-
repoUrl := args[0]
31
-
// check if repo is <user>/<repo>
32
-
if ghRepoRegexp.MatchString(repoUrl) {
33
-
repoUrl = fmt.Sprintf("https://github.com/%s.git", repoUrl)
34
-
}
35
-
36
-
var appName string
37
-
if len(args) > 1 {
38
-
appName = args[1]
39
-
} else {
40
-
parts := strings.Split(repoUrl, "/")
41
-
if len(parts) < 2 {
42
-
return fmt.Errorf("invalid repository URL: %s", repoUrl)
43
-
}
44
-
45
-
repoName := strings.TrimSuffix(parts[len(parts)-1], ".git")
46
-
appName = strings.TrimPrefix(repoName, "smallweb-")
47
-
}
48
-
appDir := filepath.Join(k.String("dir"), appName)
49
-
if _, err := exec.LookPath(appDir); err == nil {
50
-
return fmt.Errorf("directory already exists: %s", appDir)
51
-
}
52
-
53
-
branches, err := listBranches(repoUrl)
54
-
if err != nil {
55
-
return fmt.Errorf("failed to list branches: %w", err)
56
-
}
57
-
58
-
if len(branches) == 0 {
59
-
return fmt.Errorf("no branches found in the repository")
60
-
}
61
-
62
-
if _, err := os.Stat(filepath.Join(k.String("dir"), ".git")); err == nil {
63
-
if slices.Contains(branches, "smallweb") {
64
-
addCmd := exec.Command("git", "submodule", "add", "--branch", "smallweb", repoUrl, appDir)
65
-
addCmd.Stdout = cmd.OutOrStdout()
66
-
addCmd.Stderr = cmd.ErrOrStderr()
67
-
if err := addCmd.Run(); err != nil {
68
-
return fmt.Errorf("failed to add submodule: %w", err)
69
-
}
70
-
71
-
cmd.PrintErrf("App %s available at https://%s.%s\n", appName, appName, k.String("domain"))
72
-
return nil
73
-
}
74
-
75
-
addCmd := exec.Command("git", "submodule", "add", repoUrl, appDir)
76
-
addCmd.Stdout = cmd.OutOrStdout()
77
-
addCmd.Stderr = cmd.ErrOrStderr()
78
-
if err := addCmd.Run(); err != nil {
79
-
return fmt.Errorf("failed to add submodule: %w", err)
80
-
}
81
-
82
-
cmd.PrintErrf("App %s available at https://%s.%s\n", appName, appName, k.String("domain"))
83
-
return nil
84
-
}
85
-
86
-
if slices.Contains(branches, "smallweb") {
87
-
cmd.PrintErrf("Cloning branch 'smallweb' from %s to %s...\n", repoUrl, appDir)
88
-
cloneCmd := exec.Command("git", "clone", "--single-branch", "--branch", "smallweb", repoUrl, appDir)
89
-
cloneCmd.Stdout = cmd.OutOrStdout()
90
-
cloneCmd.Stderr = cmd.ErrOrStderr()
91
-
if err := cloneCmd.Run(); err != nil {
92
-
return fmt.Errorf("failed to clone branch: %w", err)
93
-
}
94
-
95
-
cmd.PrintErrf("App %s available at https://%s.%s\n", appName, appName, k.String("domain"))
96
-
return nil
97
-
}
98
-
99
-
cmd.PrintErrf("Cloning %s to %s...\n", repoUrl, appDir)
100
-
cloneCmd := exec.Command("git", "clone", "--single-branch", repoUrl, appDir)
101
-
cloneCmd.Stdout = cmd.OutOrStdout()
102
-
cloneCmd.Stderr = cmd.ErrOrStderr()
103
-
if err := cloneCmd.Run(); err != nil {
104
-
return fmt.Errorf("failed to clone repository: %w", err)
105
-
}
106
-
107
-
cmd.Printf("App %s available at https://%s.%s\n", appName, appName, k.String("domain"))
108
-
return nil
109
-
},
110
-
}
111
-
112
-
cmd.Flags().StringP("url", "u", "", "URL of the app to install")
113
-
cmd.Flags().StringP("dir", "d", "", "Directory to install the app in")
114
-
115
-
return cmd
116
-
}
117
-
118
-
func listBranches(remote string) ([]string, error) {
119
-
out, err := exec.Command("git", "ls-remote", "--heads", remote).Output()
120
-
if err != nil {
121
-
return nil, fmt.Errorf("failed to list branches: %w", err)
122
-
}
123
-
124
-
lines := strings.Split(string(out), "\n")
125
-
branches := make([]string, 0, len(lines))
126
-
127
-
for _, line := range lines {
128
-
if !strings.Contains(line, "refs/heads/") {
129
-
continue
130
-
}
131
-
132
-
parts := strings.Fields(line)
133
-
if len(parts) < 2 {
134
-
continue
135
-
}
136
-
137
-
branch := strings.TrimPrefix(parts[1], "refs/heads/")
138
-
branches = append(branches, branch)
139
-
}
140
-
141
-
return branches, nil
142
-
}
-1
cmd/root.go
-1
cmd/root.go
···
151
151
rootCmd.AddCommand(NewCmdSecrets())
152
152
rootCmd.AddCommand(NewCmdGitReceivePack())
153
153
rootCmd.AddCommand(NewCmdGitUploadPack())
154
-
rootCmd.AddCommand(NewCmdInstall())
155
154
156
155
if _, ok := os.LookupEnv("SMALLWEB_DISABLE_COMPLETIONS"); ok {
157
156
rootCmd.CompletionOptions.DisableDefaultCmd = true