Refactor how data dir is initialized
This commit is contained in:
parent
c99b37c5b3
commit
a10a604018
74
srv/src/cfg/data_dir.go
Normal file
74
srv/src/cfg/data_dir.go
Normal file
@ -0,0 +1,74 @@
|
||||
package cfg
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/mediocregopher/mediocre-go-lib/v2/mctx"
|
||||
)
|
||||
|
||||
// DataDir manages the blog's data directory.
|
||||
type DataDir struct {
|
||||
Path string
|
||||
|
||||
deleteOnClose bool
|
||||
}
|
||||
|
||||
// Init initializes the data directory, creating the directory named at path if
|
||||
// it doesn't exist.
|
||||
//
|
||||
// If Path is not set, then a temporary directory will be created and its path
|
||||
// set to the Path field. This directory will be removed when Close is called.
|
||||
func (d *DataDir) Init() error {
|
||||
if d.Path == "" {
|
||||
|
||||
d.deleteOnClose = true
|
||||
var err error
|
||||
|
||||
if d.Path, err = os.MkdirTemp("", "mediocre-blog-data-*"); err != nil {
|
||||
return fmt.Errorf("creating temporary directory: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(d.Path, 0700); err != nil {
|
||||
return fmt.Errorf(
|
||||
"creating directory (and parents) of %q: %w",
|
||||
d.Path,
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetupCfg implement the cfg.Cfger interface.
|
||||
func (d *DataDir) SetupCfg(cfg *Cfg) {
|
||||
|
||||
cfg.StringVar(&d.Path, "data-dir", "", "Directory to use for persistent storage. If unset a temp directory will be created, and will be deleted when the process exits.")
|
||||
|
||||
cfg.OnInit(func(ctx context.Context) error {
|
||||
return d.Init()
|
||||
})
|
||||
}
|
||||
|
||||
// Annotate implements mctx.Annotator interface.
|
||||
func (d *DataDir) Annotate(a mctx.Annotations) {
|
||||
a["dataDirPath"] = d.Path
|
||||
}
|
||||
|
||||
// Close cleans up any temporary state created by DataDir.
|
||||
func (d *DataDir) Close() error {
|
||||
|
||||
if !d.deleteOnClose {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := os.RemoveAll(d.Path); err != nil {
|
||||
return fmt.Errorf("removing temp dir %q: %w", d.Path, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
9
srv/src/cfg/mediocre_blog.go
Normal file
9
srv/src/cfg/mediocre_blog.go
Normal file
@ -0,0 +1,9 @@
|
||||
package cfg
|
||||
|
||||
// this file contains functionality specific to the mediocre blog.
|
||||
|
||||
// NewBlogCfg returns a Cfg specifically configured for mediocre blog processes.
|
||||
func NewBlogCfg(params Params) *Cfg {
|
||||
params.EnvPrefix = "MEDIOCRE_BLOG"
|
||||
return New(params)
|
||||
}
|
@ -4,9 +4,9 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"path"
|
||||
|
||||
"github.com/mediocregopher/blog.mediocregopher.com/srv/cfg"
|
||||
cfgpkg "github.com/mediocregopher/blog.mediocregopher.com/srv/cfg"
|
||||
"github.com/mediocregopher/blog.mediocregopher.com/srv/mailinglist"
|
||||
"github.com/mediocregopher/mediocre-go-lib/v2/mctx"
|
||||
"github.com/mediocregopher/mediocre-go-lib/v2/mlog"
|
||||
@ -17,11 +17,12 @@ func main() {
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
cfg := cfg.New(cfg.Params{
|
||||
EnvPrefix: "MEDIOCRE_BLOG",
|
||||
})
|
||||
cfg := cfgpkg.NewBlogCfg(cfg.Params{})
|
||||
|
||||
dataDir := cfg.String("data-dir", ".", "Directory to use for long term storage")
|
||||
var dataDir cfgpkg.DataDir
|
||||
dataDir.SetupCfg(cfg)
|
||||
defer dataDir.Close()
|
||||
ctx = mctx.WithAnnotator(ctx, &dataDir)
|
||||
|
||||
var mailerParams mailinglist.MailerParams
|
||||
mailerParams.SetupCfg(cfg)
|
||||
@ -54,10 +55,7 @@ func main() {
|
||||
mailer = mailinglist.NewMailer(mailerParams)
|
||||
}
|
||||
|
||||
mailingListDBFile := path.Join(*dataDir, "mailinglist.sqlite3")
|
||||
ctx = mctx.Annotate(ctx, "mailingListDBFile", mailingListDBFile)
|
||||
|
||||
mlStore, err := mailinglist.NewStore(mailingListDBFile)
|
||||
mlStore, err := mailinglist.NewStore(dataDir)
|
||||
if err != nil {
|
||||
logger.Fatal(ctx, "initializing mailing list storage", err)
|
||||
}
|
||||
|
@ -4,12 +4,12 @@ import (
|
||||
"context"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/mediocregopher/blog.mediocregopher.com/srv/api"
|
||||
"github.com/mediocregopher/blog.mediocregopher.com/srv/cfg"
|
||||
cfgpkg "github.com/mediocregopher/blog.mediocregopher.com/srv/cfg"
|
||||
"github.com/mediocregopher/blog.mediocregopher.com/srv/chat"
|
||||
"github.com/mediocregopher/blog.mediocregopher.com/srv/mailinglist"
|
||||
"github.com/mediocregopher/blog.mediocregopher.com/srv/pow"
|
||||
@ -23,11 +23,12 @@ func main() {
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
cfg := cfg.New(cfg.Params{
|
||||
EnvPrefix: "MEDIOCRE_BLOG",
|
||||
})
|
||||
cfg := cfg.NewBlogCfg(cfg.Params{})
|
||||
|
||||
dataDir := cfg.String("data-dir", ".", "Directory to use for long term storage")
|
||||
var dataDir cfgpkg.DataDir
|
||||
dataDir.SetupCfg(cfg)
|
||||
defer dataDir.Close()
|
||||
ctx = mctx.WithAnnotator(ctx, &dataDir)
|
||||
|
||||
var powMgrParams pow.ManagerParams
|
||||
powMgrParams.SetupCfg(cfg)
|
||||
@ -91,10 +92,7 @@ func main() {
|
||||
mailer = mailinglist.NewMailer(mailerParams)
|
||||
}
|
||||
|
||||
mailingListDBFile := path.Join(*dataDir, "mailinglist.sqlite3")
|
||||
ctx = mctx.Annotate(ctx, "mailingListDBFile", mailingListDBFile)
|
||||
|
||||
mlStore, err := mailinglist.NewStore(mailingListDBFile)
|
||||
mlStore, err := mailinglist.NewStore(dataDir)
|
||||
if err != nil {
|
||||
logger.Fatal(ctx, "initializing mailing list storage", err)
|
||||
}
|
||||
|
@ -7,10 +7,12 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/mediocregopher/blog.mediocregopher.com/srv/cfg"
|
||||
migrate "github.com/rubenv/sql-migrate"
|
||||
)
|
||||
|
||||
@ -83,13 +85,15 @@ type store struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
// NewStore initializes a new Store using a sqlite3 database at the given file
|
||||
// path.
|
||||
func NewStore(dbFile string) (Store, error) {
|
||||
// NewStore initializes a new Store using a sqlite3 database in the given
|
||||
// DataDir.
|
||||
func NewStore(dataDir cfg.DataDir) (Store, error) {
|
||||
|
||||
db, err := sql.Open("sqlite3", dbFile)
|
||||
path := path.Join(dataDir.Path, "mailinglist.sqlite3")
|
||||
|
||||
db, err := sql.Open("sqlite3", path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("opening sqlite file: %w", err)
|
||||
return nil, fmt.Errorf("opening sqlite file at %q: %w", path, err)
|
||||
}
|
||||
|
||||
migrations := &migrate.MemoryMigrationSource{Migrations: migrations}
|
||||
|
@ -2,31 +2,24 @@ package mailinglist
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/mediocregopher/blog.mediocregopher.com/srv/cfg"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestStore(t *testing.T) {
|
||||
tmpFile, err := ioutil.TempFile(os.TempDir(), "mediocre-blog-mailinglist-store-test-")
|
||||
if err != nil {
|
||||
t.Fatal("Cannot create temporary file", err)
|
||||
|
||||
var dataDir cfg.DataDir
|
||||
|
||||
if err := dataDir.Init(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tmpFilePath := tmpFile.Name()
|
||||
tmpFile.Close()
|
||||
|
||||
t.Logf("using temporary sqlite file at %q", tmpFilePath)
|
||||
t.Cleanup(func() { dataDir.Close() })
|
||||
|
||||
t.Cleanup(func() {
|
||||
if err := os.Remove(tmpFilePath); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
|
||||
store, err := NewStore(tmpFilePath)
|
||||
store, err := NewStore(dataDir)
|
||||
assert.NoError(t, err)
|
||||
|
||||
t.Cleanup(func() {
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3" // we need dis
|
||||
"github.com/mediocregopher/blog.mediocregopher.com/srv/cfg"
|
||||
migrate "github.com/rubenv/sql-migrate"
|
||||
)
|
||||
|
||||
@ -99,9 +100,7 @@ var migrations = []*migrate.Migration{
|
||||
// Params are parameters used to initialize a new Store. All fields are required
|
||||
// unless otherwise noted.
|
||||
type StoreParams struct {
|
||||
|
||||
// Path to the file the database will be stored at.
|
||||
DBFilePath string
|
||||
DataDir cfg.DataDir
|
||||
}
|
||||
|
||||
type store struct {
|
||||
@ -113,9 +112,11 @@ type store struct {
|
||||
// path.
|
||||
func NewStore(params StoreParams) (Store, error) {
|
||||
|
||||
db, err := sql.Open("sqlite3", params.DBFilePath)
|
||||
path := path.Join(params.DataDir.Path, "post.sqlite3")
|
||||
|
||||
db, err := sql.Open("sqlite3", path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("opening sqlite file: %w", err)
|
||||
return nil, fmt.Errorf("opening sqlite file at %q: %w", path, err)
|
||||
}
|
||||
|
||||
migrations := &migrate.MemoryMigrationSource{Migrations: migrations}
|
||||
|
@ -1,13 +1,12 @@
|
||||
package post
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/mediocregopher/blog.mediocregopher.com/srv/cfg"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tilinna/clock"
|
||||
)
|
||||
@ -29,25 +28,18 @@ type storeTestHarness struct {
|
||||
|
||||
func newStoreTestHarness(t *testing.T) storeTestHarness {
|
||||
|
||||
var dataDir cfg.DataDir
|
||||
|
||||
if err := dataDir.Init(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Cleanup(func() { dataDir.Close() })
|
||||
|
||||
clock := clock.NewMock(time.Now().UTC().Truncate(1 * time.Hour))
|
||||
|
||||
tmpFile, err := ioutil.TempFile(os.TempDir(), "mediocre-blog-post-store-test-")
|
||||
if err != nil {
|
||||
t.Fatal("Cannot create temporary file", err)
|
||||
}
|
||||
tmpFilePath := tmpFile.Name()
|
||||
tmpFile.Close()
|
||||
|
||||
t.Logf("using temporary sqlite file at %q", tmpFilePath)
|
||||
|
||||
t.Cleanup(func() {
|
||||
if err := os.Remove(tmpFilePath); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
|
||||
store, err := NewStore(StoreParams{
|
||||
DBFilePath: tmpFilePath,
|
||||
DataDir: dataDir,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user