Skip to content

Commit 2a00693

Browse files
corylanouclaude
andauthored
refactor: code health audit using golangci-lint as a guide (#713)
Co-authored-by: Claude <[email protected]>
1 parent 346f8fb commit 2a00693

23 files changed

+220
-195
lines changed

cmd/litestream/databases.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
type DatabasesCommand struct{}
1313

1414
// Run executes the command.
15-
func (c *DatabasesCommand) Run(ctx context.Context, args []string) (err error) {
15+
func (c *DatabasesCommand) Run(_ context.Context, args []string) (err error) {
1616
fs := flag.NewFlagSet("litestream-databases", flag.ContinueOnError)
1717
configPath, noExpandEnv := registerConfigFlag(fs)
1818
fs.Usage = c.Usage

cmd/litestream/main.go

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func (e *ConfigValidationError) Unwrap() error {
6868

6969
func main() {
7070
m := NewMain()
71-
if err := m.Run(context.Background(), os.Args[1:]); err == flag.ErrHelp || err == errStop {
71+
if err := m.Run(context.Background(), os.Args[1:]); errors.Is(err, flag.ErrHelp) || errors.Is(err, errStop) {
7272
os.Exit(1)
7373
} else if err != nil {
7474
slog.Error("failed to run", "error", err)
@@ -114,7 +114,7 @@ func (m *Main) Run(ctx context.Context, args []string) (err error) {
114114
// Setup signal handler.
115115
signalCh := signalChan()
116116

117-
if err := c.Run(); err != nil {
117+
if err := c.Run(ctx); err != nil {
118118
return err
119119
}
120120

@@ -139,7 +139,7 @@ func (m *Main) Run(ctx context.Context, args []string) (err error) {
139139
}
140140

141141
// Gracefully close.
142-
if e := c.Close(); e != nil && err == nil {
142+
if e := c.Close(ctx); e != nil && err == nil {
143143
err = e
144144
}
145145
slog.Info("litestream shut down")
@@ -330,9 +330,9 @@ func (c *Config) CompactionLevels() litestream.CompactionLevels {
330330
}
331331

332332
// DBConfig returns database configuration by path.
333-
func (c *Config) DBConfig(path string) *DBConfig {
333+
func (c *Config) DBConfig(configPath string) *DBConfig {
334334
for _, dbConfig := range c.DBs {
335-
if dbConfig.Path == path {
335+
if dbConfig.Path == configPath {
336336
return dbConfig
337337
}
338338
}
@@ -477,13 +477,13 @@ type DBConfig struct {
477477

478478
// NewDBFromConfig instantiates a DB based on a configuration.
479479
func NewDBFromConfig(dbc *DBConfig) (*litestream.DB, error) {
480-
path, err := expand(dbc.Path)
480+
configPath, err := expand(dbc.Path)
481481
if err != nil {
482482
return nil, err
483483
}
484484

485485
// Initialize database with given path.
486-
db := litestream.NewDB(path)
486+
db := litestream.NewDB(configPath)
487487

488488
// Override default database settings if specified in configuration.
489489
if dbc.MetaPath != nil {
@@ -508,11 +508,12 @@ func NewDBFromConfig(dbc *DBConfig) (*litestream.DB, error) {
508508
// Instantiate and attach replica.
509509
// v0.3.x and before supported multiple replicas but that was dropped to
510510
// ensure there's a single remote data authority.
511-
if dbc.Replica == nil && len(dbc.Replicas) == 0 {
511+
switch {
512+
case dbc.Replica == nil && len(dbc.Replicas) == 0:
512513
return nil, fmt.Errorf("must specify replica for database")
513-
} else if dbc.Replica != nil && len(dbc.Replicas) > 0 {
514+
case dbc.Replica != nil && len(dbc.Replicas) > 0:
514515
return nil, fmt.Errorf("cannot specify 'replica' and 'replicas' on a database")
515-
} else if len(dbc.Replicas) > 1 {
516+
case len(dbc.Replicas) > 1:
516517
return nil, fmt.Errorf("multiple replicas on a single database are no longer supported")
517518
}
518519

@@ -649,26 +650,26 @@ func newFileReplicaClientFromConfig(c *ReplicaConfig, r *litestream.Replica) (_
649650
return nil, fmt.Errorf("cannot specify url & path for file replica")
650651
}
651652

652-
// Parse path from URL, if specified.
653-
path := c.Path
653+
// Parse configPath from URL, if specified.
654+
configPath := c.Path
654655
if c.URL != "" {
655-
if _, _, path, err = ParseReplicaURL(c.URL); err != nil {
656+
if _, _, configPath, err = ParseReplicaURL(c.URL); err != nil {
656657
return nil, err
657658
}
658659
}
659660

660661
// Ensure path is set explicitly or derived from URL field.
661-
if path == "" {
662+
if configPath == "" {
662663
return nil, fmt.Errorf("file replica path required")
663664
}
664665

665666
// Expand home prefix and return absolute path.
666-
if path, err = expand(path); err != nil {
667+
if configPath, err = expand(configPath); err != nil {
667668
return nil, err
668669
}
669670

670671
// Instantiate replica and apply time fields, if set.
671-
client := file.NewReplicaClient(path)
672+
client := file.NewReplicaClient(configPath)
672673
client.Replica = r
673674
return client, nil
674675
}
@@ -682,7 +683,7 @@ func newS3ReplicaClientFromConfig(c *ReplicaConfig, _ *litestream.Replica) (_ *s
682683
return nil, fmt.Errorf("cannot specify url & bucket for s3 replica")
683684
}
684685

685-
bucket, path := c.Bucket, c.Path
686+
bucket, configPath := c.Bucket, c.Path
686687
region, endpoint, skipVerify := c.Region, c.Endpoint, c.SkipVerify
687688

688689
// Use path style if an endpoint is explicitly set. This works because the
@@ -701,8 +702,8 @@ func newS3ReplicaClientFromConfig(c *ReplicaConfig, _ *litestream.Replica) (_ *s
701702
ubucket, uregion, uendpoint, uforcePathStyle := s3.ParseHost(host)
702703

703704
// Only apply URL parts to field that have not been overridden.
704-
if path == "" {
705-
path = upath
705+
if configPath == "" {
706+
configPath = upath
706707
}
707708
if bucket == "" {
708709
bucket = ubucket
@@ -728,7 +729,7 @@ func newS3ReplicaClientFromConfig(c *ReplicaConfig, _ *litestream.Replica) (_ *s
728729
client.AccessKeyID = c.AccessKeyID
729730
client.SecretAccessKey = c.SecretAccessKey
730731
client.Bucket = bucket
731-
client.Path = path
732+
client.Path = configPath
732733
client.Region = region
733734
client.Endpoint = endpoint
734735
client.ForcePathStyle = forcePathStyle
@@ -745,7 +746,7 @@ func newGSReplicaClientFromConfig(c *ReplicaConfig, _ *litestream.Replica) (_ *g
745746
return nil, fmt.Errorf("cannot specify url & bucket for gs replica")
746747
}
747748

748-
bucket, path := c.Bucket, c.Path
749+
bucket, configPath := c.Bucket, c.Path
749750

750751
// Apply settings from URL, if specified.
751752
if c.URL != "" {
@@ -755,8 +756,8 @@ func newGSReplicaClientFromConfig(c *ReplicaConfig, _ *litestream.Replica) (_ *g
755756
}
756757

757758
// Only apply URL parts to field that have not been overridden.
758-
if path == "" {
759-
path = upath
759+
if configPath == "" {
760+
configPath = upath
760761
}
761762
if bucket == "" {
762763
bucket = uhost
@@ -771,7 +772,7 @@ func newGSReplicaClientFromConfig(c *ReplicaConfig, _ *litestream.Replica) (_ *g
771772
// Build replica.
772773
client := gs.NewReplicaClient()
773774
client.Bucket = bucket
774-
client.Path = path
775+
client.Path = configPath
775776
return client, nil
776777
}
777778

@@ -873,7 +874,7 @@ func newNATSReplicaClientFromConfig(c *ReplicaConfig, _ *litestream.Replica) (_
873874
// Parse URL if provided to extract bucket name and server URL
874875
var url, bucket string
875876
if c.URL != "" {
876-
scheme, host, path, err := ParseReplicaURL(c.URL)
877+
scheme, host, bucketPath, err := ParseReplicaURL(c.URL)
877878
if err != nil {
878879
return nil, fmt.Errorf("invalid NATS URL: %w", err)
879880
}
@@ -887,8 +888,8 @@ func newNATSReplicaClientFromConfig(c *ReplicaConfig, _ *litestream.Replica) (_
887888
}
888889

889890
// Extract bucket name from path
890-
if path != "" {
891-
bucket = strings.Trim(path, "/")
891+
if bucketPath != "" {
892+
bucket = strings.Trim(bucketPath, "/")
892893
}
893894
}
894895

cmd/litestream/main_windows.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func (s *windowsService) Execute(args []string, r <-chan svc.ChangeRequest, stat
6868
}
6969

7070
// Execute replication command.
71-
if err := c.Run(); err != nil {
71+
if err := c.Run(s.ctx); err != nil {
7272
slog.Error("cannot replicate", "error", err)
7373
statusCh <- svc.Status{State: svc.StopPending}
7474
return true, 2
@@ -82,7 +82,7 @@ func (s *windowsService) Execute(args []string, r <-chan svc.ChangeRequest, stat
8282
case req := <-r:
8383
switch req.Cmd {
8484
case svc.Stop:
85-
c.Close()
85+
c.Close(s.ctx)
8686
statusCh <- svc.Status{State: svc.StopPending}
8787
return false, windows.NO_ERROR
8888
case svc.Interrogate:

cmd/litestream/mcp.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,9 @@ func NewMCP(ctx context.Context, configPath string) (*MCPServer, error) {
5050

5151
func (s *MCPServer) Start(addr string) {
5252
s.httpServer = &http.Server{
53-
Addr: addr,
54-
Handler: s.mux,
53+
Addr: addr,
54+
Handler: s.mux,
55+
ReadHeaderTimeout: 30 * time.Second,
5556
}
5657
go func() {
5758
slog.Info("Starting MCP Streamable HTTP server", "addr", addr)
@@ -65,7 +66,7 @@ func (s *MCPServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
6566
s.mux.ServeHTTP(w, r)
6667
}
6768

68-
// Close attemps to gracefully shutdown the server.
69+
// Close attempts to gracefully shutdown the server.
6970
func (s *MCPServer) Close() error {
7071
ctx, cancel := context.WithTimeout(s.ctx, 10*time.Second)
7172
defer cancel()

cmd/litestream/replicate.go

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func NewReplicateCommand() *ReplicateCommand {
4444
}
4545

4646
// ParseFlags parses the CLI flags and loads the configuration file.
47-
func (c *ReplicateCommand) ParseFlags(ctx context.Context, args []string) (err error) {
47+
func (c *ReplicateCommand) ParseFlags(_ context.Context, args []string) (err error) {
4848
fs := flag.NewFlagSet("litestream-replicate", flag.ContinueOnError)
4949
execFlag := fs.String("exec", "", "execute subcommand")
5050
configPath, noExpandEnv := registerConfigFlag(fs)
@@ -54,9 +54,22 @@ func (c *ReplicateCommand) ParseFlags(ctx context.Context, args []string) (err e
5454
}
5555

5656
// Load configuration or use CLI args to build db/replica.
57-
if fs.NArg() == 1 {
57+
switch fs.NArg() {
58+
case 0:
59+
// No arguments provided, use config file
60+
if *configPath == "" {
61+
*configPath = DefaultConfigPath()
62+
}
63+
if c.Config, err = ReadConfigFile(*configPath, !*noExpandEnv); err != nil {
64+
return err
65+
}
66+
67+
case 1:
68+
// Only database path provided, missing replica URL
5869
return fmt.Errorf("must specify at least one replica URL for %s", fs.Arg(0))
59-
} else if fs.NArg() > 1 {
70+
71+
default:
72+
// Database path and replica URLs provided via CLI
6073
if *configPath != "" {
6174
return fmt.Errorf("cannot specify a replica URL and the -config flag")
6275
}
@@ -73,14 +86,8 @@ func (c *ReplicateCommand) ParseFlags(ctx context.Context, args []string) (err e
7386
})
7487
}
7588
c.Config.DBs = []*DBConfig{dbConfig}
76-
} else {
77-
if *configPath == "" {
78-
*configPath = DefaultConfigPath()
79-
}
80-
if c.Config, err = ReadConfigFile(*configPath, !*noExpandEnv); err != nil {
81-
return err
82-
}
8389
}
90+
8491
c.Config.ConfigPath = *configPath
8592

8693
// Override config exec command, if specified.
@@ -92,13 +99,13 @@ func (c *ReplicateCommand) ParseFlags(ctx context.Context, args []string) (err e
9299
}
93100

94101
// Run loads all databases specified in the configuration.
95-
func (c *ReplicateCommand) Run() (err error) {
102+
func (c *ReplicateCommand) Run(ctx context.Context) (err error) {
96103
// Display version information.
97104
slog.Info("litestream", "version", Version, "level", c.Config.Logging.Level)
98105

99106
// Start MCP server if enabled
100107
if c.Config.MCPAddr != "" {
101-
c.MCP, err = NewMCP(context.Background(), c.Config.ConfigPath)
108+
c.MCP, err = NewMCP(ctx, c.Config.ConfigPath)
102109
if err != nil {
103110
return err
104111
}
@@ -110,7 +117,7 @@ func (c *ReplicateCommand) Run() (err error) {
110117
slog.Error("no databases specified in configuration")
111118
}
112119

113-
var dbs []*litestream.DB
120+
dbs := make([]*litestream.DB, 0, len(c.Config.DBs))
114121
for _, dbConfig := range c.Config.DBs {
115122
db, err := NewDBFromConfig(dbConfig)
116123
if err != nil {
@@ -129,30 +136,30 @@ func (c *ReplicateCommand) Run() (err error) {
129136
if c.Config.Snapshot.Retention != nil {
130137
c.Store.SnapshotRetention = *c.Config.Snapshot.Retention
131138
}
132-
if err := c.Store.Open(context.Background()); err != nil {
139+
if err := c.Store.Open(ctx); err != nil {
133140
return fmt.Errorf("cannot open store: %w", err)
134141
}
135142

136143
// Notify user that initialization is done.
137144
for _, db := range c.Store.DBs() {
138145
r := db.Replica
139146
slog.Info("initialized db", "path", db.Path())
140-
slog := slog.With("type", r.Client.Type(), "sync-interval", r.SyncInterval)
147+
slogWith := slog.With("type", r.Client.Type(), "sync-interval", r.SyncInterval)
141148
switch client := r.Client.(type) {
142149
case *file.ReplicaClient:
143-
slog.Info("replicating to", "path", client.Path())
150+
slogWith.Info("replicating to", "path", client.Path())
144151
case *s3.ReplicaClient:
145-
slog.Info("replicating to", "bucket", client.Bucket, "path", client.Path, "region", client.Region, "endpoint", client.Endpoint)
152+
slogWith.Info("replicating to", "bucket", client.Bucket, "path", client.Path, "region", client.Region, "endpoint", client.Endpoint)
146153
case *gs.ReplicaClient:
147-
slog.Info("replicating to", "bucket", client.Bucket, "path", client.Path)
154+
slogWith.Info("replicating to", "bucket", client.Bucket, "path", client.Path)
148155
case *abs.ReplicaClient:
149-
slog.Info("replicating to", "bucket", client.Bucket, "path", client.Path, "endpoint", client.Endpoint)
156+
slogWith.Info("replicating to", "bucket", client.Bucket, "path", client.Path, "endpoint", client.Endpoint)
150157
case *sftp.ReplicaClient:
151-
slog.Info("replicating to", "host", client.Host, "user", client.User, "path", client.Path)
158+
slogWith.Info("replicating to", "host", client.Host, "user", client.User, "path", client.Path)
152159
case *nats.ReplicaClient:
153-
slog.Info("replicating to", "bucket", client.BucketName, "url", client.URL)
160+
slogWith.Info("replicating to", "bucket", client.BucketName, "url", client.URL)
154161
default:
155-
slog.Info("replicating to")
162+
slogWith.Info("replicating to")
156163
}
157164
}
158165

@@ -181,7 +188,7 @@ func (c *ReplicateCommand) Run() (err error) {
181188
return fmt.Errorf("cannot parse exec command: %w", err)
182189
}
183190

184-
c.cmd = exec.Command(execArgs[0], execArgs[1:]...)
191+
c.cmd = exec.CommandContext(ctx, execArgs[0], execArgs[1:]...)
185192
c.cmd.Env = os.Environ()
186193
c.cmd.Stdout = os.Stdout
187194
c.cmd.Stderr = os.Stderr
@@ -195,16 +202,16 @@ func (c *ReplicateCommand) Run() (err error) {
195202
}
196203

197204
// Close closes all open databases.
198-
func (c *ReplicateCommand) Close() (err error) {
199-
if e := c.Store.Close(); e != nil {
200-
slog.Error("failed to close database", "error", e)
205+
func (c *ReplicateCommand) Close(ctx context.Context) error {
206+
if err := c.Store.Close(ctx); err != nil {
207+
slog.Error("failed to close database", "error", err)
201208
}
202209
if c.Config.MCPAddr != "" {
203210
if err := c.MCP.Close(); err != nil {
204211
slog.Error("error closing MCP server", "error", err)
205212
}
206213
}
207-
return err
214+
return nil
208215
}
209216

210217
// Usage prints the help screen to STDOUT.

cmd/litestream/restore.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ func (c *RestoreCommand) Run(ctx context.Context, args []string) (err error) {
5050
if *configPath != "" {
5151
return fmt.Errorf("cannot specify a replica URL and the -config flag")
5252
}
53-
if r, err = c.loadFromURL(ctx, fs.Arg(0), *ifDBNotExists, &opt); err == errSkipDBExists {
53+
if r, err = c.loadFromURL(ctx, fs.Arg(0), *ifDBNotExists, &opt); errors.Is(err, errSkipDBExists) {
5454
slog.Info("database already exists, skipping")
5555
return nil
5656
} else if err != nil {
@@ -60,7 +60,7 @@ func (c *RestoreCommand) Run(ctx context.Context, args []string) (err error) {
6060
if *configPath == "" {
6161
*configPath = DefaultConfigPath()
6262
}
63-
if r, err = c.loadFromConfig(ctx, fs.Arg(0), *configPath, !*noExpandEnv, *ifDBNotExists, &opt); err == errSkipDBExists {
63+
if r, err = c.loadFromConfig(ctx, fs.Arg(0), *configPath, !*noExpandEnv, *ifDBNotExists, &opt); errors.Is(err, errSkipDBExists) {
6464
slog.Info("database already exists, skipping")
6565
return nil
6666
} else if err != nil {

0 commit comments

Comments
 (0)