Skip to content

Commit ed63216

Browse files
committed
support running plugins when smallweb is invoked with --dir
1 parent 58ac2bf commit ed63216

File tree

1 file changed

+86
-52
lines changed

1 file changed

+86
-52
lines changed

cmd/root.go

Lines changed: 86 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,62 @@ func NewCmdRoot(changelog string) *cobra.Command {
7777
_ = k.Load(fileProvider, utils.ConfigParser())
7878
})
7979
},
80-
SilenceUsage: true,
80+
ValidArgsFunction: completePlugins,
81+
Args: cobra.MinimumNArgs(1),
82+
SilenceUsage: true,
83+
RunE: func(cmd *cobra.Command, args []string) error {
84+
if env, ok := os.LookupEnv("SMALLWEB_DISABLE_PLUGINS"); ok {
85+
if disablePlugins, _ := strconv.ParseBool(env); disablePlugins {
86+
return cmd.Help()
87+
}
88+
}
89+
90+
for _, pluginDir := range []string{
91+
filepath.Join(k.String("dir"), ".smallweb", "plugins"),
92+
filepath.Join(xdg.DataHome, "smallweb", "plugins"),
93+
} {
94+
entries, err := os.ReadDir(pluginDir)
95+
if err != nil {
96+
continue
97+
}
98+
99+
for _, entry := range entries {
100+
if entry.IsDir() {
101+
continue
102+
}
103+
104+
plugin := strings.TrimSuffix(entry.Name(), filepath.Ext(entry.Name()))
105+
if plugin != args[0] {
106+
continue
107+
}
108+
109+
entrypoint := filepath.Join(pluginDir, entry.Name())
110+
111+
if ok, err := isExecutable(entrypoint); err != nil {
112+
return fmt.Errorf("failed to check if plugin is executable: %w", err)
113+
} else if !ok {
114+
if err := os.Chmod(entrypoint, 0755); err != nil {
115+
return fmt.Errorf("failed to make plugin executable: %w", err)
116+
}
117+
}
118+
119+
command := exec.Command(entrypoint, args...)
120+
command.Env = os.Environ()
121+
command.Env = append(command.Env, fmt.Sprintf("SMALLWEB_VERSION=%s", build.Version))
122+
command.Env = append(command.Env, fmt.Sprintf("SMALLWEB_DIR=%s", k.String("dir")))
123+
command.Env = append(command.Env, fmt.Sprintf("SMALLWEB_DOMAIN=%s", k.String("domain")))
124+
125+
command.Stdin = os.Stdin
126+
command.Stdout = os.Stdout
127+
command.Stderr = os.Stderr
128+
129+
cmd.SilenceErrors = true
130+
return command.Run()
131+
}
132+
}
133+
134+
return fmt.Errorf("unknown command \"%s\" for \"smallweb\"", args[0])
135+
},
81136
}
82137

83138
rootCmd.PersistentFlags().String("dir", "", "The root directory for smallweb")
@@ -127,16 +182,41 @@ func NewCmdRoot(changelog string) *cobra.Command {
127182
}
128183
}
129184

130-
if env, ok := os.LookupEnv("SMALLWEB_DISABLE_PLUGINS"); ok {
131-
if disablePlugins, _ := strconv.ParseBool(env); disablePlugins {
132-
return rootCmd
185+
return rootCmd
186+
}
187+
188+
func GetCommand(cmd *cobra.Command, name string) (*cobra.Command, bool) {
189+
for _, c := range cmd.Commands() {
190+
if c.Name() == name {
191+
return c, true
133192
}
134193
}
135194

195+
return nil, false
196+
}
197+
198+
func isExecutable(path string) (bool, error) {
199+
fileInfo, err := os.Stat(path)
200+
if err != nil {
201+
return false, err
202+
}
203+
return fileInfo.Mode().Perm()&0111 != 0, nil
204+
}
205+
206+
func completePlugins(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
207+
flagProvider := posflag.Provider(cmd.Root().PersistentFlags(), ".", k)
208+
_ = k.Load(flagProvider, nil)
209+
210+
if len(args) > 0 {
211+
return nil, cobra.ShellCompDirectiveDefault
212+
}
213+
214+
var plugins []string
136215
for _, pluginDir := range []string{
137216
filepath.Join(k.String("dir"), ".smallweb", "plugins"),
138217
filepath.Join(xdg.DataHome, "smallweb", "plugins"),
139218
} {
219+
140220
entries, err := os.ReadDir(pluginDir)
141221
if err != nil {
142222
continue
@@ -148,57 +228,11 @@ func NewCmdRoot(changelog string) *cobra.Command {
148228
}
149229

150230
plugin := strings.TrimSuffix(entry.Name(), filepath.Ext(entry.Name()))
151-
rootCmd.AddCommand(&cobra.Command{
152-
Use: strings.TrimSuffix(entry.Name(), filepath.Ext(entry.Name())),
153-
Short: fmt.Sprintf("Run the %s plugin", plugin),
154-
RunE: func(cmd *cobra.Command, args []string) error {
155-
entrypoint := filepath.Join(pluginDir, entry.Name())
156-
157-
if ok, err := isExecutable(entrypoint); err != nil {
158-
return fmt.Errorf("failed to check if plugin is executable: %w", err)
159-
} else if !ok {
160-
if err := os.Chmod(entrypoint, 0755); err != nil {
161-
return fmt.Errorf("failed to make plugin executable: %w", err)
162-
}
163-
}
164-
165-
command := exec.Command(entrypoint, args...)
166-
command.Env = os.Environ()
167-
command.Env = append(command.Env, fmt.Sprintf("SMALLWEB_VERSION=%s", build.Version))
168-
command.Env = append(command.Env, fmt.Sprintf("SMALLWEB_DIR=%s", k.String("dir")))
169-
command.Env = append(command.Env, fmt.Sprintf("SMALLWEB_DOMAIN=%s", k.String("domain")))
170-
171-
command.Stdin = os.Stdin
172-
command.Stdout = os.Stdout
173-
command.Stderr = os.Stderr
174-
175-
cmd.SilenceErrors = true
176-
return command.Run()
177-
},
178-
})
179-
180-
}
181-
}
182-
183-
return rootCmd
184-
}
185-
186-
func GetCommand(cmd *cobra.Command, name string) (*cobra.Command, bool) {
187-
for _, c := range cmd.Commands() {
188-
if c.Name() == name {
189-
return c, true
231+
plugins = append(plugins, plugin)
190232
}
191233
}
192234

193-
return nil, false
194-
}
195-
196-
func isExecutable(path string) (bool, error) {
197-
fileInfo, err := os.Stat(path)
198-
if err != nil {
199-
return false, err
200-
}
201-
return fileInfo.Mode().Perm()&0111 != 0, nil
235+
return plugins, cobra.ShellCompDirectiveDefault
202236
}
203237

204238
func completeApp(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {

0 commit comments

Comments
 (0)