Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zed: Default app data location #4758

Merged
merged 2 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions cli/lakeflags/datadir.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package lakeflags

import (
"os"
"path/filepath"
"runtime"
)

// getDefaultDataDir returns the default data directory for the current user.
// Derived from https://github.com/btcsuite/btcd/blob/master/btcutil/appdata.go
func getDefaultDataDir() string {
// Resolve the XDG data home directory if set.
if xdgDataHome := os.Getenv("XDG_DATA_HOME"); xdgDataHome != "" {
return filepath.Join(xdgDataHome, "zed")
}
if runtime.GOOS == "windows" {
if appData := os.Getenv("LOCALAPPDATA"); appData != "" {
return filepath.Join(appData, "zed")
}
}
if homeDir, _ := os.UserHomeDir(); homeDir != "" {
// Follow the XDG spec which states:
// If $XDG_DATA_HOME is either not set or empty, a default equal to
// $HOME/.local/share should be used.
return filepath.Join(homeDir, ".local", "share", "zed")
}
// Return an empty string which will cause an error if a default data
// directory cannot be found.
return ""
}
47 changes: 33 additions & 14 deletions cli/lakeflags/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@ var ErrNoHEAD = errors.New("HEAD not specified: indicate with -use or run the \"

type Flags struct {
ConfigDir string
// LakeSpecified is set to true if the lake is explicitly set via either
// command line flag or environment variable.
LakeSpecified bool
Lake string
Quiet bool
Lake string
Quiet bool

lakeSpecified bool
}

func (l *Flags) SetFlags(fs *flag.FlagSet) {
Expand All @@ -35,20 +34,17 @@ func (l *Flags) SetFlags(fs *flag.FlagSet) {
dir = filepath.Join(dir, ".zed")
}
fs.StringVar(&l.ConfigDir, "configdir", dir, "configuration and credentials directory")
l.Lake = "http://localhost:9867"
if s, ok := os.LookupEnv("ZED_LAKE"); ok {
l.Lake = strings.TrimRight(s, "/")
l.LakeSpecified = true
l.Lake, l.lakeSpecified = s, true
}
fs.Func("lake", fmt.Sprintf("lake location (env ZED_LAKE) (default %s)", l.Lake), func(s string) error {
l.Lake = strings.TrimRight(s, "/")
l.LakeSpecified = true
l.Lake, l.lakeSpecified = s, true
return nil
})
}

func (l *Flags) Connection() (*client.Connection, error) {
uri, err := l.URI()
uri, err := l.ClientURI()
if err != nil {
return nil, err
}
Expand All @@ -63,7 +59,7 @@ func (l *Flags) Connection() (*client.Connection, error) {
}

func (l *Flags) Open(ctx context.Context) (api.Interface, error) {
uri, err := l.URI()
uri, err := l.ClientURI()
if err != nil {
return nil, err
}
Expand All @@ -86,12 +82,35 @@ func (l *Flags) AuthStore() *auth0.Store {
}

func (l *Flags) URI() (*storage.URI, error) {
if l.Lake == "" {
lk := strings.TrimRight(l.Lake, "/")
if !l.lakeSpecified {
lk = getDefaultDataDir()
}
if lk == "" {
return nil, errors.New("lake location must be set (either with the -lake flag or ZED_LAKE environment variable)")
}
u, err := storage.ParseURI(l.Lake)
u, err := storage.ParseURI(lk)
if err != nil {
err = fmt.Errorf("error parsing lake location: %w", err)
}
return u, err
}

// ClientURI returns the URI of the lake to connect to. If the lake path is
// the defaultDataDir, it first checks if a zed service is running on
// localhost:9867 and if so uses http://localhost:9867 as the lake location.
func (l *Flags) ClientURI() (*storage.URI, error) {
u, err := l.URI()
if err != nil {
return nil, err
}
if !l.lakeSpecified && localServer() {
u = storage.MustParseURI("http://localhost:9867")
}
return u, nil
}

func localServer() bool {
_, err := client.NewConnection().Ping(context.Background())
return err == nil
}
24 changes: 15 additions & 9 deletions cmd/zed/init/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/brimdata/zed/cmd/zed/root"
"github.com/brimdata/zed/lake/api"
"github.com/brimdata/zed/pkg/charm"
"github.com/brimdata/zed/pkg/storage"
"go.uber.org/zap"
)

Expand Down Expand Up @@ -35,23 +36,28 @@ func (c *Command) Run(args []string) error {
return err
}
defer cleanup()
var path string
var u *storage.URI
if len(args) == 0 {
path = c.LakeFlags.Lake
if u, err = c.LakeFlags.URI(); err != nil {
return err
}
} else if len(args) == 1 {
path = args[0]
path := args[0]
if path == "" {
return errors.New("single lake path argument required")
}
if u, err = storage.ParseURI(path); err != nil {
return err
}
}
if path == "" {
return errors.New("single lake path argument required")
}
if api.IsLakeService(path) {
if api.IsLakeService(u.String()) {
return fmt.Errorf("init command not valid on remote lake")
}
if _, err := api.CreateLocalLake(ctx, zap.Must(zap.NewProduction()), path); err != nil {
if _, err := api.CreateLocalLake(ctx, zap.Must(zap.NewProduction()), u.String()); err != nil {
return err
}
if !c.LakeFlags.Quiet {
fmt.Printf("lake created: %s\n", path)
fmt.Printf("lake created: %s\n", u)
}
return nil
}
9 changes: 2 additions & 7 deletions cmd/zed/serve/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,17 +73,12 @@ func (c *Command) Run(args []string) error {
return err
}
defer cleanup()
if !c.LakeFlags.LakeSpecified {
c.LakeFlags.Lake = ""
}
uri, err := c.LakeFlags.URI()
if err != nil {
if c.conf.Root, err = c.LakeFlags.URI(); err != nil {
return err
}
if api.IsLakeService(uri.String()) {
if api.IsLakeService(c.conf.Root.String()) {
return errors.New("serve command available for local lakes only")
}
c.conf.Root = uri
if c.rootContentFile != "" {
f, err := fs.Open(c.rootContentFile)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion cmd/zed/use/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func (c *Command) Run(args []string) error {
return errors.New("default pool and branch unset")
}
fmt.Printf("HEAD at %s\n", head)
if u, err := c.LakeFlags.URI(); err == nil {
if u, err := c.LakeFlags.ClientURI(); err == nil {
fmt.Printf("Lake at %s\n", u)
}
return nil
Expand Down
2 changes: 1 addition & 1 deletion cmd/zed/ztests/no-lake-location.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
script: |
! zed ls -lake ''
! zed serve
! zed serve -lake ''
outputs:
- name: stderr
Expand Down
8 changes: 8 additions & 0 deletions cmd/zed/ztests/xdg-data-home.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
script: |
export XDG_DATA_HOME=path/to/lake
zed init

outputs:
- name: stdout
regexp: |
lake created: file:.*path/to/lake/zed
2 changes: 1 addition & 1 deletion compiler/ztests/from-error.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
script: |
! zc -C -s 'from p'
! zc -lake='' -C -s 'from p'
echo === >&2
export ZED_LAKE=test
zed init
Expand Down