fixes
This commit is contained in:
@@ -6,6 +6,10 @@ A simple, rsync-based PocketBase deployment tool.
|
|||||||
|
|
||||||
- start a new PocketBase project
|
- start a new PocketBase project
|
||||||
|
|
||||||
|
## dev
|
||||||
|
|
||||||
|
- run a local dev server
|
||||||
|
|
||||||
## deploy
|
## deploy
|
||||||
|
|
||||||
## logs
|
## logs
|
||||||
|
|||||||
20
go.mod
20
go.mod
@@ -2,10 +2,22 @@ module pb
|
|||||||
|
|
||||||
go 1.23.1
|
go 1.23.1
|
||||||
|
|
||||||
require github.com/urfave/cli/v2 v2.27.7
|
require github.com/charmbracelet/bubbletea v0.26.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
|
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.18 // indirect
|
||||||
|
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||||
|
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||||
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||||
|
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||||
|
github.com/muesli/reflow v0.3.0 // indirect
|
||||||
|
github.com/muesli/termenv v0.15.2 // indirect
|
||||||
|
github.com/rivo/uniseg v0.4.6 // indirect
|
||||||
|
golang.org/x/sync v0.7.0 // indirect
|
||||||
|
golang.org/x/sys v0.19.0 // indirect
|
||||||
|
golang.org/x/term v0.19.0 // indirect
|
||||||
|
golang.org/x/text v0.3.8 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
45
go.sum
45
go.sum
@@ -1,8 +1,37 @@
|
|||||||
github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
github.com/charmbracelet/bubbletea v0.26.1 h1:xujcQeF73rh4jwu3+zhfQsvV18x+7zIjlw7/CYbzGJ0=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/charmbracelet/bubbletea v0.26.1/go.mod h1:FzKr7sKoO8iFVcdIBM9J0sJOcQv5nDQaYwsee3kpbgo=
|
||||||
github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU=
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
|
||||||
github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4=
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
|
||||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
|
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
|
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||||
|
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
|
||||||
|
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
|
||||||
|
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
|
||||||
|
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||||
|
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||||
|
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
|
||||||
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
|
||||||
|
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
|
||||||
|
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
||||||
|
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
|
||||||
|
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
|
||||||
|
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
|
||||||
|
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
|
||||||
|
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
|
github.com/rivo/uniseg v0.4.6 h1:Sovz9sDSwbOz9tgUy8JpT+KgCkPYJEN/oYzlJiYTNLg=
|
||||||
|
github.com/rivo/uniseg v0.4.6/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
|
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||||
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||||
|
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
|
||||||
|
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||||
|
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
|
||||||
|
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||||
|
|||||||
234
main.go
234
main.go
@@ -16,85 +16,160 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
app := &cli.App{
|
commands := defaultCommands()
|
||||||
Name: "pb",
|
args := os.Args[1:]
|
||||||
Usage: "PocketBase deployment helper",
|
if len(args) > 0 {
|
||||||
Commands: []*cli.Command{
|
if args[0] == "--" {
|
||||||
{
|
args = args[1:]
|
||||||
Name: "init",
|
}
|
||||||
Usage: "start a new PocketBase project",
|
if len(args) > 0 {
|
||||||
Action: initAction(),
|
if err := runCommandByName(commands, args[0]); err != nil {
|
||||||
},
|
log.Fatal(err)
|
||||||
{
|
}
|
||||||
Name: "dev",
|
return
|
||||||
Usage: "run the PocketBase binary locally",
|
}
|
||||||
Action: devAction(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "deploy",
|
|
||||||
Usage: "deploy the PocketBase project",
|
|
||||||
Action: placeholderAction("deploy"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "logs",
|
|
||||||
Usage: "show PocketBase logs",
|
|
||||||
Action: placeholderAction("logs"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "secrets",
|
|
||||||
Usage: "manage deployment secrets",
|
|
||||||
Action: placeholderAction("secrets"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := app.Run(os.Args); err != nil {
|
if err := tea.NewProgram(newModel()).Start(); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func placeholderAction(name string) func(*cli.Context) error {
|
func defaultCommands() []command {
|
||||||
return func(c *cli.Context) error {
|
return []command{
|
||||||
|
{name: "init", description: "start a new PocketBase project", action: runInit},
|
||||||
|
{name: "dev", description: "run the PocketBase binary locally", action: runDev},
|
||||||
|
{name: "deploy", description: "deploy the PocketBase project", action: placeholderAction("deploy")},
|
||||||
|
{name: "logs", description: "show PocketBase logs", action: placeholderAction("logs")},
|
||||||
|
{name: "secrets", description: "manage deployment secrets", action: placeholderAction("secrets")},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type commandAction func() error
|
||||||
|
|
||||||
|
type command struct {
|
||||||
|
name string
|
||||||
|
description string
|
||||||
|
action commandAction
|
||||||
|
}
|
||||||
|
|
||||||
|
func runCommandByName(commands []command, name string) error {
|
||||||
|
for _, cmd := range commands {
|
||||||
|
if cmd.name == name {
|
||||||
|
return cmd.action()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Errorf("unknown command %q", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newModel() model {
|
||||||
|
return model{commands: defaultCommands()}
|
||||||
|
}
|
||||||
|
|
||||||
|
type model struct {
|
||||||
|
commands []command
|
||||||
|
cursor int
|
||||||
|
status string
|
||||||
|
running bool
|
||||||
|
lastCommand string
|
||||||
|
}
|
||||||
|
|
||||||
|
type commandResultMsg struct {
|
||||||
|
name string
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m model) Init() tea.Cmd {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
|
switch msg := msg.(type) {
|
||||||
|
case tea.KeyMsg:
|
||||||
|
switch msg.String() {
|
||||||
|
case "ctrl+c", "q":
|
||||||
|
return m, tea.Quit
|
||||||
|
case "up", "k":
|
||||||
|
if m.running {
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
if m.cursor > 0 {
|
||||||
|
m.cursor--
|
||||||
|
} else {
|
||||||
|
m.cursor = len(m.commands) - 1
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
case "down", "j":
|
||||||
|
if m.running {
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
if m.cursor < len(m.commands)-1 {
|
||||||
|
m.cursor++
|
||||||
|
} else {
|
||||||
|
m.cursor = 0
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
case "enter":
|
||||||
|
if m.running {
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
selected := m.commands[m.cursor]
|
||||||
|
m.running = true
|
||||||
|
m.lastCommand = selected.name
|
||||||
|
m.status = fmt.Sprintf("Running %s...", selected.name)
|
||||||
|
return m, runCommand(selected)
|
||||||
|
}
|
||||||
|
case commandResultMsg:
|
||||||
|
m.running = false
|
||||||
|
if msg.err != nil {
|
||||||
|
m.status = fmt.Sprintf("%s failed: %v", msg.name, msg.err)
|
||||||
|
} else {
|
||||||
|
m.status = fmt.Sprintf("%s finished successfully", msg.name)
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m model) View() string {
|
||||||
|
var b strings.Builder
|
||||||
|
b.WriteString("PocketBase deployment helper\n\n")
|
||||||
|
for idx, cmd := range m.commands {
|
||||||
|
cursor := " "
|
||||||
|
if m.cursor == idx {
|
||||||
|
cursor = ">"
|
||||||
|
}
|
||||||
|
b.WriteString(fmt.Sprintf("%s %s\n %s\n", cursor, cmd.name, cmd.description))
|
||||||
|
}
|
||||||
|
b.WriteString("\n")
|
||||||
|
if m.status != "" {
|
||||||
|
b.WriteString(fmt.Sprintf("%s\n\n", m.status))
|
||||||
|
}
|
||||||
|
if m.running {
|
||||||
|
b.WriteString("(running... press ctrl+c to abort)\n")
|
||||||
|
}
|
||||||
|
b.WriteString("↑/↓ to navigate, enter to run, q to quit\n")
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func runCommand(cmd command) tea.Cmd {
|
||||||
|
return func() tea.Msg {
|
||||||
|
return commandResultMsg{name: cmd.name, err: cmd.action()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func placeholderAction(name string) commandAction {
|
||||||
|
return func() error {
|
||||||
fmt.Printf("TODO: implement %s command\n", name)
|
fmt.Printf("TODO: implement %s command\n", name)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func devAction() func(*cli.Context) error {
|
func runInit() 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()
|
cwd, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -123,13 +198,40 @@ func initAction() func(*cli.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ensureGitignoreEntries(filepath.Join(cwd, ".gitignore"), []string{"bin/", "pb.toml"}); err != nil {
|
if err := ensureGitignoreEntries(filepath.Join(cwd, ".gitignore"), []string{"bin/pocketbase", "pb_data"}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Initialized PocketBase project %q\n", serviceName)
|
fmt.Printf("Initialized PocketBase project %q\n", serviceName)
|
||||||
return nil
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func runDev() 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.Args = append(cmd.Args, "--dir", filepath.Join(cwd, "pb_data"))
|
||||||
|
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()
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultPocketbaseVersion = "0.35.1"
|
const defaultPocketbaseVersion = "0.35.1"
|
||||||
|
|||||||
Reference in New Issue
Block a user