pb volume

This commit is contained in:
2026-01-13 15:08:54 +00:00
parent 2aa9e8d672
commit 02169e4621
2 changed files with 54 additions and 11 deletions

View File

@@ -6,7 +6,19 @@ A simple, rsync-based PocketBase deployment tool.
### `init` ### `init`
Start a new PocketBase project (optionally provide a service name via `pb init <name>`) Start a new PocketBase project (optionally provide a service name via `pb init <name>`) with a `pb.toml`:
```toml
[server]
ip = '127.0.0.1'
port = 8090
domain = 'example.com'
[pocketbase]
version = '0.35.1'
service = 'rusty-dusty'
volume = 'pb_data'
```
### `dev` ### `dev`
@@ -27,7 +39,7 @@ Provision a remote PocketBase server. This will:
### `logs` ### `logs`
Connects to the configured server and streams `/root/pb/{service}/{service}.log` via `tail -n 100 -F`. Streams the remote logs (`/root/pb/{service}/{service}.log`).
### `secrets` ### `secrets`

49
main.go
View File

@@ -15,6 +15,7 @@ import (
"net/http" "net/http"
"os" "os"
"os/exec" "os/exec"
"path"
"path/filepath" "path/filepath"
"runtime" "runtime"
"sort" "sort"
@@ -285,7 +286,10 @@ func runDev() error {
return cmd.Run() return cmd.Run()
} }
const defaultPocketbaseVersion = "0.35.1" const (
defaultPocketbaseVersion = "0.35.1"
defaultPocketbaseVolume = "pb_data"
)
func init() { func init() {
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
@@ -297,6 +301,7 @@ func writePBConfig(path, serviceName string) error {
const tmpl = `[pocketbase] const tmpl = `[pocketbase]
version = "%s" version = "%s"
service = "%s" service = "%s"
volume = "%s"
[server] [server]
ip = "127.0.0.1" ip = "127.0.0.1"
@@ -304,7 +309,7 @@ port = 8090
domain = "example.com" domain = "example.com"
` `
return os.WriteFile(path, []byte(fmt.Sprintf(tmpl, defaultPocketbaseVersion, serviceName)), 0o644) return os.WriteFile(path, []byte(fmt.Sprintf(tmpl, defaultPocketbaseVersion, serviceName, defaultPocketbaseVolume)), 0o644)
} }
func generateServiceName() string { func generateServiceName() string {
@@ -914,6 +919,7 @@ type serverConfig struct {
type pocketBaseConfig struct { type pocketBaseConfig struct {
Version string `toml:"version"` Version string `toml:"version"`
ServiceName string `toml:"service"` ServiceName string `toml:"service"`
Volume string `toml:"volume"`
} }
type deploymentContext struct { type deploymentContext struct {
@@ -926,6 +932,8 @@ type deploymentContext struct {
envFile string envFile string
unitServiceDir string unitServiceDir string
unitEnvFile string unitEnvFile string
volume string
unitVolume string
configPath string configPath string
} }
@@ -970,6 +978,12 @@ func buildDeploymentContext() (*deploymentContext, error) {
envFile := renderServiceTemplate(defaultEnvFileTemplate, serviceName) envFile := renderServiceTemplate(defaultEnvFileTemplate, serviceName)
unitServiceDir := renderServiceTemplate(defaultServiceDirTemplate, "%i") unitServiceDir := renderServiceTemplate(defaultServiceDirTemplate, "%i")
unitEnvFile := renderServiceTemplate(defaultEnvFileTemplate, "%i") unitEnvFile := renderServiceTemplate(defaultEnvFileTemplate, "%i")
volumeTemplate := cfg.PocketBase.Volume
if volumeTemplate == "" {
volumeTemplate = defaultPocketbaseVolume
}
volume := resolveVolumePath(volumeTemplate, serviceDir, serviceName)
unitVolume := resolveVolumePath(volumeTemplate, unitServiceDir, "%i")
return &deploymentContext{ return &deploymentContext{
serverIP: serverIP, serverIP: serverIP,
@@ -981,6 +995,8 @@ func buildDeploymentContext() (*deploymentContext, error) {
envFile: envFile, envFile: envFile,
unitServiceDir: unitServiceDir, unitServiceDir: unitServiceDir,
unitEnvFile: unitEnvFile, unitEnvFile: unitEnvFile,
volume: volume,
unitVolume: unitVolume,
configPath: configPath, configPath: configPath,
}, nil }, nil
} }
@@ -1041,13 +1057,13 @@ func performSetup(ctx *deploymentContext) error {
step++ step++
printStep(step, totalSetupSteps, "deploying PocketBase binary") printStep(step, totalSetupSteps, "deploying PocketBase binary")
if err := runSSHCommand(ctx.serverIP, pocketbaseSetupScript(ctx.serviceDir, ctx.envFile, ctx.version, assetURL, ctx.port)); err != nil { if err := runSSHCommand(ctx.serverIP, pocketbaseSetupScript(ctx.serviceDir, ctx.envFile, ctx.version, assetURL, ctx.volume, ctx.port)); err != nil {
return fmt.Errorf("PocketBase setup failed: %w", err) return fmt.Errorf("PocketBase setup failed: %w", err)
} }
step++ step++
printStep(step, totalSetupSteps, "configuring systemd service") printStep(step, totalSetupSteps, "configuring systemd service")
if err := runSSHCommand(ctx.serverIP, systemdScript(ctx.unitServiceDir, ctx.unitEnvFile, ctx.serviceName)); err != nil { if err := runSSHCommand(ctx.serverIP, systemdScript(ctx.unitServiceDir, ctx.unitEnvFile, ctx.unitVolume, ctx.serviceName)); err != nil {
return fmt.Errorf("systemd setup failed: %w", err) return fmt.Errorf("systemd setup failed: %w", err)
} }
@@ -1402,6 +1418,17 @@ func renderServiceTemplate(tpl, serviceName string) string {
return strings.ReplaceAll(tpl, "{service}", serviceName) return strings.ReplaceAll(tpl, "{service}", serviceName)
} }
func resolveVolumePath(volumeTemplate, baseDir, serviceName string) string {
value := renderServiceTemplate(volumeTemplate, serviceName)
if value == "" {
return baseDir
}
if strings.HasPrefix(value, "/") {
return value
}
return path.Join(baseDir, value)
}
func translateMachineArch(value string) (string, error) { func translateMachineArch(value string) (string, error) {
machine := strings.TrimSpace(strings.ToLower(value)) machine := strings.TrimSpace(strings.ToLower(value))
@@ -1496,7 +1523,7 @@ systemctl reload-or-restart caddy.service
`, serviceName, domain, port) `, serviceName, domain, port)
} }
func pocketbaseSetupScript(serviceDir, envFile, version, assetURL string, port int) string { func pocketbaseSetupScript(serviceDir, envFile, version, assetURL, volume string, port int) string {
return fmt.Sprintf(`set -euo pipefail return fmt.Sprintf(`set -euo pipefail
service_dir="%s" service_dir="%s"
mkdir -p "$service_dir" mkdir -p "$service_dir"
@@ -1511,19 +1538,23 @@ if [ ! -x "$binary" ]; then
rm -f "$tmp" rm -f "$tmp"
fi fi
env_file="%s" env_file="%s"
data_dir="%s"
current_port="" current_port=""
if [ -f "$env_file" ]; then if [ -f "$env_file" ]; then
current_port=$(grep '^PORT=' "$env_file" | head -n 1 | cut -d= -f2) current_port=$(grep '^PORT=' "$env_file" | head -n 1 | cut -d= -f2)
fi fi
if [ -n "$data_dir" ]; then
mkdir -p "$data_dir"
fi
if [ "$current_port" != "%d" ]; then if [ "$current_port" != "%d" ]; then
cat <<'EOF' > "$env_file" cat <<'EOF' > "$env_file"
PORT=%d PORT=%d
EOF EOF
fi fi
`, serviceDir, serviceDir, assetURL, envFile, port, port) `, serviceDir, serviceDir, assetURL, envFile, volume, port, port)
} }
func systemdScript(serviceDir, envFile, serviceName string) string { func systemdScript(serviceDir, envFile, volume, serviceName string) string {
return fmt.Sprintf(`set -euo pipefail return fmt.Sprintf(`set -euo pipefail
cat <<'EOF' > /etc/systemd/system/pb@.service cat <<'EOF' > /etc/systemd/system/pb@.service
[Unit] [Unit]
@@ -1541,7 +1572,7 @@ StandardOutput = append:%s/%%i.log
StandardError = append:%s/%%i.log StandardError = append:%s/%%i.log
WorkingDirectory = %s WorkingDirectory = %s
EnvironmentFile = %s EnvironmentFile = %s
ExecStart = %s/pocketbase serve --http="127.0.0.1:${PORT}" ExecStart = %s/pocketbase serve --dir=%s --http="127.0.0.1:${PORT}"
[Install] [Install]
WantedBy = multi-user.target WantedBy = multi-user.target
@@ -1549,7 +1580,7 @@ EOF
systemctl daemon-reload systemctl daemon-reload
systemctl --no-block enable --now pb@%s systemctl --no-block enable --now pb@%s
systemctl --no-block restart pb@%s systemctl --no-block restart pb@%s
`, serviceDir, serviceDir, serviceDir, envFile, serviceDir, serviceName, serviceName) `, serviceDir, serviceDir, serviceDir, envFile, serviceDir, volume, serviceName, serviceName)
} }
func systemdRestartScript(serviceName string) string { func systemdRestartScript(serviceName string) string {