From f5b04fe69d52b255a17ff957e184f42aed3e2e02 Mon Sep 17 00:00:00 2001 From: Nick Goodall Date: Tue, 13 Jan 2026 11:13:11 +0000 Subject: [PATCH] dev command --- main.go | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/main.go b/main.go index 534a017..6c82bdb 100644 --- a/main.go +++ b/main.go @@ -9,8 +9,10 @@ import ( "math/rand" "net/http" "os" + "os/exec" "path/filepath" "runtime" + "sort" "strings" "time" @@ -27,6 +29,11 @@ func main() { Usage: "start a new PocketBase project", Action: initAction(), }, + { + Name: "dev", + Usage: "run the PocketBase binary locally", + Action: devAction(), + }, { Name: "deploy", Usage: "deploy the PocketBase project", @@ -57,6 +64,35 @@ func placeholderAction(name string) func(*cli.Context) error { } } +func devAction() func(*cli.Context) error { + return func(c *cli.Context) error { + cwd, err := os.Getwd() + if err != nil { + return err + } + + binaryPath := filepath.Join(cwd, "bin", pocketbaseBinaryName(runtime.GOOS)) + if _, err := os.Stat(binaryPath); err != nil { + return fmt.Errorf("cannot find PocketBase binary at %s: %w", binaryPath, err) + } + + overrides, err := loadEnv(filepath.Join(cwd, ".env")) + if err != nil { + return err + } + + cmd := exec.Command(binaryPath, "serve") + cmd.Dir = cwd + cmd.Env = mergeEnv(overrides) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Stdin = os.Stdin + + fmt.Println("starting PocketBase development server") + return cmd.Run() + } +} + func initAction() func(*cli.Context) error { return func(c *cli.Context) error { cwd, err := os.Getwd() @@ -87,7 +123,7 @@ func initAction() func(*cli.Context) error { return err } - if err := ensureGitignoreEntries(filepath.Join(cwd, ".gitignore"), []string{"bin/pocketbase", "pb.toml"}); err != nil { + if err := ensureGitignoreEntries(filepath.Join(cwd, ".gitignore"), []string{"bin/", "pb.toml"}); err != nil { return err } @@ -267,3 +303,57 @@ func ensureGitignoreEntries(path string, entries []string) error { return os.WriteFile(path, []byte(builder.String()), 0o644) } + +func loadEnv(path string) (map[string]string, error) { + data, err := os.ReadFile(path) + if err != nil { + if errors.Is(err, os.ErrNotExist) { + return nil, nil + } + return nil, err + } + + env := make(map[string]string) + for _, line := range strings.Split(string(data), "\n") { + line = strings.TrimSpace(line) + if line == "" || strings.HasPrefix(line, "#") { + continue + } + idx := strings.Index(line, "=") + if idx == -1 { + continue + } + key := strings.TrimSpace(line[:idx]) + value := strings.TrimSpace(line[idx+1:]) + env[key] = value + } + return env, nil +} + +func mergeEnv(overrides map[string]string) []string { + envMap := make(map[string]string) + for _, kv := range os.Environ() { + parts := strings.SplitN(kv, "=", 2) + key := parts[0] + value := "" + if len(parts) > 1 { + value = parts[1] + } + envMap[key] = value + } + for key, value := range overrides { + envMap[key] = value + } + + keys := make([]string, 0, len(envMap)) + for key := range envMap { + keys = append(keys, key) + } + sort.Strings(keys) + + env := make([]string, 0, len(keys)) + for _, key := range keys { + env = append(env, fmt.Sprintf("%s=%s", key, envMap[key])) + } + return env +}