smallweb
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232package cmd
import ( "fmt" "os" "os/exec" "path/filepath" "strconv" "strings"
"github.com/adrg/xdg" "github.com/knadh/koanf/providers/env" "github.com/knadh/koanf/providers/file" "github.com/knadh/koanf/providers/posflag" "github.com/knadh/koanf/v2"
"github.com/pomdtr/smallweb/internal/app" "github.com/pomdtr/smallweb/internal/build" "github.com/pomdtr/smallweb/internal/utils" "github.com/spf13/cobra")
var ( k = koanf.New("."))
func findSmallwebDir() string { currentDir, err := os.Getwd() if err != nil { return "" }
for filepath.Dir(currentDir) != currentDir { if _, err := os.Stat(filepath.Join(currentDir, ".smallweb")); err == nil { return currentDir }
currentDir = filepath.Dir(currentDir) }
return ""}
var envProvider = env.ProviderWithValue("SMALLWEB_", ".", func(s string, v string) (string, interface{}) { switch s { case "SMALLWEB_DIR": return "dir", v }
return "", nil})
func NewCmdRoot() *cobra.Command { _ = k.Load(envProvider, nil) rootCmd := &cobra.Command{ Use: "smallweb", Short: "Host websites from your internet folder", Version: build.Version, PersistentPreRunE: func(cmd *cobra.Command, args []string) error { flagProvider := posflag.Provider(cmd.Root().PersistentFlags(), ".", k) _ = k.Load(flagProvider, nil)
configPath := utils.FindConfigPath(k.String("dir")) fileProvider := file.Provider(configPath) _ = k.Load(fileProvider, utils.ConfigParser()) _ = k.Load(envProvider, nil) _ = k.Load(flagProvider, nil)
return nil }, ValidArgsFunction: completePlugins, SilenceUsage: true, Args: cobra.ArbitraryArgs, RunE: func(cmd *cobra.Command, args []string) error { if len(args) == 0 { return cmd.Help() }
if env, ok := os.LookupEnv("SMALLWEB_DISABLE_PLUGINS"); ok { if disablePlugins, _ := strconv.ParseBool(env); disablePlugins { return fmt.Errorf("unknown command \"%s\" for \"smallweb\"", args[0]) } }
for _, pluginDir := range []string{ filepath.Join(k.String("dir"), ".smallweb", "plugins"), filepath.Join(xdg.DataHome, "smallweb", "plugins"), } { entries, err := os.ReadDir(pluginDir) if err != nil { continue }
for _, entry := range entries { if entry.IsDir() { continue }
plugin := strings.TrimSuffix(entry.Name(), filepath.Ext(entry.Name())) if plugin != args[0] { continue }
entrypoint := filepath.Join(pluginDir, entry.Name())
if ok, err := isExecutable(entrypoint); err != nil { return fmt.Errorf("failed to check if plugin is executable: %w", err) } else if !ok { if err := os.Chmod(entrypoint, 0755); err != nil { return fmt.Errorf("failed to make plugin executable: %w", err) } }
command := exec.Command(entrypoint, args[1:]...) command.Env = os.Environ() command.Env = append(command.Env, fmt.Sprintf("SMALLWEB_VERSION=%s", build.Version)) command.Env = append(command.Env, fmt.Sprintf("SMALLWEB_DIR=%s", k.String("dir"))) command.Env = append(command.Env, fmt.Sprintf("SMALLWEB_DOMAIN=%s", k.String("domain")))
command.Stdin = os.Stdin command.Stdout = cmd.OutOrStdout() command.Stderr = cmd.ErrOrStderr()
cmd.SilenceErrors = true return command.Run() } }
return fmt.Errorf("unknown command \"%s\" for \"smallweb\"", args[0]) }, }
rootCmd.PersistentFlags().String("dir", findSmallwebDir(), "The root directory for smallweb") rootCmd.PersistentFlags().String("domain", "", "The domain for smallweb") rootCmd.Flags().SetInterspersed(false)
rootCmd.AddCommand(NewCmdRun()) rootCmd.AddCommand(NewCmdOpen()) rootCmd.AddCommand(NewCmdDocs()) rootCmd.AddCommand(NewCmdUp()) rootCmd.AddCommand(NewCmdDoctor()) rootCmd.AddCommand(NewCmdList()) rootCmd.AddCommand(NewCmdCrons()) rootCmd.AddCommand(NewCmdInit()) rootCmd.AddCommand(NewCmdLink()) rootCmd.AddCommand(NewCmdConfig()) rootCmd.AddCommand(NewCmdSecrets()) rootCmd.AddCommand(NewCmdGitReceivePack()) rootCmd.AddCommand(NewCmdGitUploadPack())
if _, ok := os.LookupEnv("SMALLWEB_DISABLE_COMPLETIONS"); ok { rootCmd.CompletionOptions.DisableDefaultCmd = true }
if env, ok := os.LookupEnv("SMALLWEB_DISABLED_COMMANDS"); ok { disabledCommands := strings.Split(env, ",") for _, commandName := range disabledCommands { if command, ok := GetCommand(rootCmd, commandName); ok { rootCmd.RemoveCommand(command) } } }
return rootCmd}
func GetCommand(cmd *cobra.Command, name string) (*cobra.Command, bool) { for _, c := range cmd.Commands() { if c.Name() == name { return c, true } }
return nil, false}
func isExecutable(path string) (bool, error) { fileInfo, err := os.Stat(path) if err != nil { return false, err } return fileInfo.Mode().Perm()&0111 != 0, nil}
func completePlugins(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { flagProvider := posflag.Provider(cmd.Root().PersistentFlags(), ".", k) _ = k.Load(flagProvider, nil)
if len(args) > 0 { return nil, cobra.ShellCompDirectiveDefault }
var plugins []string for _, pluginDir := range []string{ filepath.Join(k.String("dir"), ".smallweb", "plugins"), filepath.Join(xdg.DataHome, "smallweb", "plugins"), } {
entries, err := os.ReadDir(pluginDir) if err != nil { continue }
for _, entry := range entries { if entry.IsDir() { continue }
plugin := strings.TrimSuffix(entry.Name(), filepath.Ext(entry.Name())) plugins = append(plugins, fmt.Sprintf("%s\tPlugin %s", plugin, plugin)) } }
return plugins, cobra.ShellCompDirectiveDefault}
func completeApp(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { flagProvider := posflag.Provider(cmd.Root().PersistentFlags(), ".", k) _ = k.Load(flagProvider, nil)
if len(args) > 0 { return nil, cobra.ShellCompDirectiveDefault }
apps, err := app.ListApps(k.String("dir")) if err != nil { return nil, cobra.ShellCompDirectiveDefault }
return apps, cobra.ShellCompDirectiveDefault}