Prevent user from specifying replica URL & config flag

Previously, if a replica URL was specified then the `-config` flag
was silently ignored. This commit changes this behavior so that
specifying both the URL & config flag will now return an error.
This commit is contained in:
Ben Johnson
2021-02-28 08:09:24 -07:00
parent 9cee1285b9
commit 325482a97c
7 changed files with 56 additions and 43 deletions

View File

@@ -2,7 +2,6 @@ package main
import ( import (
"context" "context"
"errors"
"flag" "flag"
"fmt" "fmt"
"os" "os"
@@ -15,9 +14,8 @@ type DatabasesCommand struct{}
// Run executes the command. // Run executes the command.
func (c *DatabasesCommand) Run(ctx context.Context, args []string) (err error) { func (c *DatabasesCommand) Run(ctx context.Context, args []string) (err error) {
var configPath string
fs := flag.NewFlagSet("litestream-databases", flag.ContinueOnError) fs := flag.NewFlagSet("litestream-databases", flag.ContinueOnError)
registerConfigFlag(fs, &configPath) configPath := registerConfigFlag(fs)
fs.Usage = c.Usage fs.Usage = c.Usage
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
return err return err
@@ -26,10 +24,10 @@ func (c *DatabasesCommand) Run(ctx context.Context, args []string) (err error) {
} }
// Load configuration. // Load configuration.
if configPath == "" { if *configPath == "" {
return errors.New("-config required") *configPath = DefaultConfigPath()
} }
config, err := ReadConfigFile(configPath) config, err := ReadConfigFile(*configPath)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -2,7 +2,6 @@ package main
import ( import (
"context" "context"
"errors"
"flag" "flag"
"fmt" "fmt"
"log" "log"
@@ -18,9 +17,8 @@ type GenerationsCommand struct{}
// Run executes the command. // Run executes the command.
func (c *GenerationsCommand) Run(ctx context.Context, args []string) (err error) { func (c *GenerationsCommand) Run(ctx context.Context, args []string) (err error) {
var configPath string
fs := flag.NewFlagSet("litestream-generations", flag.ContinueOnError) fs := flag.NewFlagSet("litestream-generations", flag.ContinueOnError)
registerConfigFlag(fs, &configPath) configPath := registerConfigFlag(fs)
replicaName := fs.String("replica", "", "replica name") replicaName := fs.String("replica", "", "replica name")
fs.Usage = c.Usage fs.Usage = c.Usage
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
@@ -35,12 +33,19 @@ func (c *GenerationsCommand) Run(ctx context.Context, args []string) (err error)
var r litestream.Replica var r litestream.Replica
updatedAt := time.Now() updatedAt := time.Now()
if isURL(fs.Arg(0)) { if isURL(fs.Arg(0)) {
if *configPath != "" {
return fmt.Errorf("cannot specify a replica URL and the -config flag")
}
if r, err = NewReplicaFromConfig(&ReplicaConfig{URL: fs.Arg(0)}, nil); err != nil { if r, err = NewReplicaFromConfig(&ReplicaConfig{URL: fs.Arg(0)}, nil); err != nil {
return err return err
} }
} else if configPath != "" { } else {
if *configPath == "" {
*configPath = DefaultConfigPath()
}
// Load configuration. // Load configuration.
config, err := ReadConfigFile(configPath) config, err := ReadConfigFile(*configPath)
if err != nil { if err != nil {
return err return err
} }
@@ -65,8 +70,6 @@ func (c *GenerationsCommand) Run(ctx context.Context, args []string) (err error)
if updatedAt, err = db.UpdatedAt(); err != nil { if updatedAt, err = db.UpdatedAt(); err != nil {
return err return err
} }
} else {
return errors.New("config path or replica URL required")
} }
var replicas []litestream.Replica var replicas []litestream.Replica

View File

@@ -429,8 +429,8 @@ func DefaultConfigPath() string {
return defaultConfigPath return defaultConfigPath
} }
func registerConfigFlag(fs *flag.FlagSet, p *string) { func registerConfigFlag(fs *flag.FlagSet) *string {
fs.StringVar(p, "config", DefaultConfigPath(), "config path") return fs.String("config", "", "config path")
} }
// expand returns an absolute path for s. // expand returns an absolute path for s.

View File

@@ -2,7 +2,6 @@ package main
import ( import (
"context" "context"
"errors"
"flag" "flag"
"fmt" "fmt"
"log" "log"
@@ -19,8 +18,7 @@ import (
// ReplicateCommand represents a command that continuously replicates SQLite databases. // ReplicateCommand represents a command that continuously replicates SQLite databases.
type ReplicateCommand struct { type ReplicateCommand struct {
ConfigPath string Config Config
Config Config
// List of managed databases specified in the config. // List of managed databases specified in the config.
DBs []*litestream.DB DBs []*litestream.DB
@@ -34,7 +32,7 @@ func NewReplicateCommand() *ReplicateCommand {
func (c *ReplicateCommand) ParseFlags(ctx context.Context, args []string) (err error) { func (c *ReplicateCommand) ParseFlags(ctx context.Context, args []string) (err error) {
fs := flag.NewFlagSet("litestream-replicate", flag.ContinueOnError) fs := flag.NewFlagSet("litestream-replicate", flag.ContinueOnError)
tracePath := fs.String("trace", "", "trace path") tracePath := fs.String("trace", "", "trace path")
registerConfigFlag(fs, &c.ConfigPath) configPath := registerConfigFlag(fs)
fs.Usage = c.Usage fs.Usage = c.Usage
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
return err return err
@@ -44,6 +42,10 @@ func (c *ReplicateCommand) ParseFlags(ctx context.Context, args []string) (err e
if fs.NArg() == 1 { if fs.NArg() == 1 {
return fmt.Errorf("must specify at least one replica URL for %s", fs.Arg(0)) return fmt.Errorf("must specify at least one replica URL for %s", fs.Arg(0))
} else if fs.NArg() > 1 { } else if fs.NArg() > 1 {
if *configPath != "" {
return fmt.Errorf("cannot specify a replica URL and the -config flag")
}
dbConfig := &DBConfig{Path: fs.Arg(0)} dbConfig := &DBConfig{Path: fs.Arg(0)}
for _, u := range fs.Args()[1:] { for _, u := range fs.Args()[1:] {
dbConfig.Replicas = append(dbConfig.Replicas, &ReplicaConfig{ dbConfig.Replicas = append(dbConfig.Replicas, &ReplicaConfig{
@@ -52,12 +54,13 @@ func (c *ReplicateCommand) ParseFlags(ctx context.Context, args []string) (err e
}) })
} }
c.Config.DBs = []*DBConfig{dbConfig} c.Config.DBs = []*DBConfig{dbConfig}
} else if c.ConfigPath != "" { } else {
if c.Config, err = ReadConfigFile(c.ConfigPath); err != nil { if *configPath == "" {
*configPath = DefaultConfigPath()
}
if c.Config, err = ReadConfigFile(*configPath); err != nil {
return err return err
} }
} else {
return errors.New("-config flag or database/replica arguments required")
} }
// Enable trace logging. // Enable trace logging.

View File

@@ -17,12 +17,11 @@ type RestoreCommand struct{}
// Run executes the command. // Run executes the command.
func (c *RestoreCommand) Run(ctx context.Context, args []string) (err error) { func (c *RestoreCommand) Run(ctx context.Context, args []string) (err error) {
var configPath string
opt := litestream.NewRestoreOptions() opt := litestream.NewRestoreOptions()
opt.Verbose = true opt.Verbose = true
fs := flag.NewFlagSet("litestream-restore", flag.ContinueOnError) fs := flag.NewFlagSet("litestream-restore", flag.ContinueOnError)
registerConfigFlag(fs, &configPath) configPath := registerConfigFlag(fs)
fs.StringVar(&opt.OutputPath, "o", "", "output path") fs.StringVar(&opt.OutputPath, "o", "", "output path")
fs.StringVar(&opt.ReplicaName, "replica", "", "replica name") fs.StringVar(&opt.ReplicaName, "replica", "", "replica name")
fs.StringVar(&opt.Generation, "generation", "", "generation name") fs.StringVar(&opt.Generation, "generation", "", "generation name")
@@ -59,15 +58,19 @@ func (c *RestoreCommand) Run(ctx context.Context, args []string) (err error) {
// Determine replica & generation to restore from. // Determine replica & generation to restore from.
var r litestream.Replica var r litestream.Replica
if isURL(fs.Arg(0)) { if isURL(fs.Arg(0)) {
if *configPath != "" {
return fmt.Errorf("cannot specify a replica URL and the -config flag")
}
if r, err = c.loadFromURL(ctx, fs.Arg(0), &opt); err != nil { if r, err = c.loadFromURL(ctx, fs.Arg(0), &opt); err != nil {
return err return err
} }
} else if configPath != "" { } else {
if r, err = c.loadFromConfig(ctx, fs.Arg(0), configPath, &opt); err != nil { if *configPath == "" {
*configPath = DefaultConfigPath()
}
if r, err = c.loadFromConfig(ctx, fs.Arg(0), *configPath, &opt); err != nil {
return err return err
} }
} else {
return errors.New("config path or replica URL required")
} }
// Return an error if no matching targets found. // Return an error if no matching targets found.

View File

@@ -2,7 +2,6 @@ package main
import ( import (
"context" "context"
"errors"
"flag" "flag"
"fmt" "fmt"
"os" "os"
@@ -17,9 +16,8 @@ type SnapshotsCommand struct{}
// Run executes the command. // Run executes the command.
func (c *SnapshotsCommand) Run(ctx context.Context, args []string) (err error) { func (c *SnapshotsCommand) Run(ctx context.Context, args []string) (err error) {
var configPath string
fs := flag.NewFlagSet("litestream-snapshots", flag.ContinueOnError) fs := flag.NewFlagSet("litestream-snapshots", flag.ContinueOnError)
registerConfigFlag(fs, &configPath) configPath := registerConfigFlag(fs)
replicaName := fs.String("replica", "", "replica name") replicaName := fs.String("replica", "", "replica name")
fs.Usage = c.Usage fs.Usage = c.Usage
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
@@ -33,12 +31,19 @@ func (c *SnapshotsCommand) Run(ctx context.Context, args []string) (err error) {
var db *litestream.DB var db *litestream.DB
var r litestream.Replica var r litestream.Replica
if isURL(fs.Arg(0)) { if isURL(fs.Arg(0)) {
if *configPath != "" {
return fmt.Errorf("cannot specify a replica URL and the -config flag")
}
if r, err = NewReplicaFromConfig(&ReplicaConfig{URL: fs.Arg(0)}, nil); err != nil { if r, err = NewReplicaFromConfig(&ReplicaConfig{URL: fs.Arg(0)}, nil); err != nil {
return err return err
} }
} else if configPath != "" { } else {
if *configPath == "" {
*configPath = DefaultConfigPath()
}
// Load configuration. // Load configuration.
config, err := ReadConfigFile(configPath) config, err := ReadConfigFile(*configPath)
if err != nil { if err != nil {
return err return err
} }
@@ -58,8 +63,6 @@ func (c *SnapshotsCommand) Run(ctx context.Context, args []string) (err error) {
return fmt.Errorf("replica %q not found for database %q", *replicaName, db.Path()) return fmt.Errorf("replica %q not found for database %q", *replicaName, db.Path())
} }
} }
} else {
return errors.New("config path or replica URL required")
} }
// Find snapshots by db or replica. // Find snapshots by db or replica.

View File

@@ -2,7 +2,6 @@ package main
import ( import (
"context" "context"
"errors"
"flag" "flag"
"fmt" "fmt"
"os" "os"
@@ -17,9 +16,8 @@ type WALCommand struct{}
// Run executes the command. // Run executes the command.
func (c *WALCommand) Run(ctx context.Context, args []string) (err error) { func (c *WALCommand) Run(ctx context.Context, args []string) (err error) {
var configPath string
fs := flag.NewFlagSet("litestream-wal", flag.ContinueOnError) fs := flag.NewFlagSet("litestream-wal", flag.ContinueOnError)
registerConfigFlag(fs, &configPath) configPath := registerConfigFlag(fs)
replicaName := fs.String("replica", "", "replica name") replicaName := fs.String("replica", "", "replica name")
generation := fs.String("generation", "", "generation name") generation := fs.String("generation", "", "generation name")
fs.Usage = c.Usage fs.Usage = c.Usage
@@ -34,12 +32,19 @@ func (c *WALCommand) Run(ctx context.Context, args []string) (err error) {
var db *litestream.DB var db *litestream.DB
var r litestream.Replica var r litestream.Replica
if isURL(fs.Arg(0)) { if isURL(fs.Arg(0)) {
if *configPath != "" {
return fmt.Errorf("cannot specify a replica URL and the -config flag")
}
if r, err = NewReplicaFromConfig(&ReplicaConfig{URL: fs.Arg(0)}, nil); err != nil { if r, err = NewReplicaFromConfig(&ReplicaConfig{URL: fs.Arg(0)}, nil); err != nil {
return err return err
} }
} else if configPath != "" { } else {
if *configPath == "" {
*configPath = DefaultConfigPath()
}
// Load configuration. // Load configuration.
config, err := ReadConfigFile(configPath) config, err := ReadConfigFile(*configPath)
if err != nil { if err != nil {
return err return err
} }
@@ -59,8 +64,6 @@ func (c *WALCommand) Run(ctx context.Context, args []string) (err error) {
return fmt.Errorf("replica %q not found for database %q", *replicaName, db.Path()) return fmt.Errorf("replica %q not found for database %q", *replicaName, db.Path())
} }
} }
} else {
return errors.New("config path or replica URL required")
} }
// Find WAL files by db or replica. // Find WAL files by db or replica.