From 57835893d5971635ed28dd1c51ad5e5e47a84690 Mon Sep 17 00:00:00 2001 From: Nick Goodall Date: Tue, 13 Jan 2026 11:38:25 +0000 Subject: [PATCH] init & dev commands woo --- main.go | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 4 deletions(-) diff --git a/main.go b/main.go index 5298502..140f530 100644 --- a/main.go +++ b/main.go @@ -224,9 +224,12 @@ func runInit() error { if err := os.MkdirAll(targetDir, 0o755); err != nil { return err } + if err := os.WriteFile(filepath.Join(targetDir, ".keep"), []byte{}, 0o644); err != nil { + return err + } binaryPath := filepath.Join(targetDir, pocketbaseBinaryName(runtime.GOOS)) - if err := downloadPocketbase(defaultPocketbaseVersion, runtime.GOOS, runtime.GOARCH, binaryPath); err != nil { + if err := ensurePocketbaseBinary(defaultPocketbaseVersion, runtime.GOOS, runtime.GOARCH, binaryPath); err != nil { return err } @@ -245,8 +248,8 @@ func runDev() error { } 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) + if err := ensurePocketbaseBinary(defaultPocketbaseVersion, runtime.GOOS, runtime.GOARCH, binaryPath); err != nil { + return err } overrides, err := loadEnv(filepath.Join(cwd, ".env")) @@ -337,7 +340,8 @@ func downloadPocketbase(version, goos, goarch, dest string) error { defer os.Remove(tmpFile.Name()) defer tmpFile.Close() - if _, err := io.Copy(tmpFile, resp.Body); err != nil { + label := fmt.Sprintf("Downloading PocketBase v%s (%s/%s)", version, goos, goarch) + if err := downloadWithProgress(tmpFile, resp.Body, resp.ContentLength, label); err != nil { return err } @@ -348,6 +352,73 @@ func downloadPocketbase(version, goos, goarch, dest string) error { return os.Chmod(dest, 0o755) } +func ensurePocketbaseBinary(version, goos, goarch, dest string) error { + if _, err := os.Stat(dest); err == nil { + return nil + } else if !errors.Is(err, os.ErrNotExist) { + return err + } + + fmt.Println("PocketBase binary missing; downloading...") + return downloadPocketbase(version, goos, goarch, dest) +} + +func downloadWithProgress(dst io.Writer, src io.Reader, total int64, label string) error { + const chunkSize = 32 * 1024 + buf := make([]byte, chunkSize) + var downloaded int64 + lastPercent := int64(-1) + + updateProgress := func(force bool) { + if total > 0 { + percent := downloaded * 100 / total + if force || percent != lastPercent { + fmt.Printf("\r%s %3d%%", label, percent) + lastPercent = percent + } + } else { + fmt.Printf("\r%s %s downloaded", label, formatBytes(downloaded)) + } + } + + for { + n, err := src.Read(buf) + if n > 0 { + if _, writeErr := dst.Write(buf[:n]); writeErr != nil { + fmt.Println() + return writeErr + } + downloaded += int64(n) + updateProgress(false) + } + + if err != nil { + if err == io.EOF { + break + } + fmt.Println() + return err + } + } + + updateProgress(true) + fmt.Println() + return nil +} + +func formatBytes(b int64) string { + const unit = 1024 + if b < unit { + return fmt.Sprintf("%d B", b) + } + div, exp := int64(unit), 0 + for n := b / unit; n >= unit; n /= unit { + div *= unit + exp++ + } + return fmt.Sprintf("%.1f %cB", float64(b)/float64(div), "KMGTPE"[exp]) +} + func releaseAssetURL(version, goos, goarch string) (string, string, error) { osName := map[string]string{ "darwin": "darwin",