Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/takashabe/btcli into add-…
Browse files Browse the repository at this point in the history
…history
  • Loading branch information
takashabe committed Aug 21, 2018
2 parents ffd5c4e + 7da62e5 commit 3338336
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 36 deletions.
10 changes: 7 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
SUBPACKAGES := $(shell go list ./...)
APP_MAIN := cmd/btcli/btcli.go
SUBPACKAGES := $(shell go list ./...)
APP_MAIN := cmd/btcli/btcli.go
BRANCH_NAME := $(shell git symbolic-ref --short HEAD)
CURRENT_TIMESTAMP := $(shell date +%Y-%m-%d-%H%M%S)
VERSION := $(CURRENT_TIMESTAMP).$(subst /,_,$(BRANCH_NAME))
LDFLAGS := -ldflags='-s -w -X "main.Version=$(VERSION)"'

.DEFAULT_GOAL := help

##### Operation

build: $(APP_MAIN) ## Build application
go build -a $(APP_MAIN)
go build -a $(LDFLAGS) $(APP_MAIN)

run: $(APP_MAIN) ## Run application
go run $(APP_MAIN)
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

CLI client for the Bigtable with auto-completion.

![tty](https://user-images.githubusercontent.com/681508/44247754-9ad3ea80-a221-11e8-9172-2cb709e1420a.gif)

## Features

btcli is the cloud bigtable client tool. Connect to your bigtable instances and any read items with auto-completion.
Expand All @@ -24,7 +26,7 @@ _write commands are not implemented yet_
## Installation

```
go get github.com/takashabe/btcli
go get github.com/takashabe/btcli/cmd/btcli
```

## Usage
Expand Down
42 changes: 25 additions & 17 deletions api/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import (
"encoding/json"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
Expand All @@ -26,6 +26,8 @@ type Config struct {
Instance string
Creds string
TokenSource oauth2.TokenSource

ErrStream io.Writer
}

// RegisterFlags registers a set of standard flags for this config.
Expand All @@ -35,43 +37,50 @@ func (c *Config) registerFlags() {
flag.StringVar(&c.Creds, "creds", c.Creds, "if set, use application credentials in this file")
}

func NewConfig(writer io.Writer) *Config {
return &Config{
ErrStream: writer,
}
}

// Load returns initialized configuration
func Load() (*Config, error) {
func (c *Config) Load() error {
filename := filepath.Join(os.Getenv("HOME"), ".cbtrc")
data, err := ioutil.ReadFile(filename)
if err != nil {
// silent fail if the file isn't there
if os.IsNotExist(err) {
return &Config{}, nil
return nil
}
return nil, fmt.Errorf("Reading %s: %v", filename, err)
return fmt.Errorf("Reading %s: %v", filename, err)
}
s := bufio.NewScanner(bytes.NewReader(data))
for s.Scan() {
line := s.Text()
i := strings.Index(line, "=")
if i < 0 {
return nil, fmt.Errorf("Bad line in %s: %q", filename, line)
return fmt.Errorf("Bad line in %s: %q", filename, line)
}
key, val := strings.TrimSpace(line[:i]), strings.TrimSpace(line[i+1:])
switch key {
default:
return nil, fmt.Errorf("Unknown key in %s: %q", filename, key)
return fmt.Errorf("Unknown key in %s: %q", filename, key)
case "project":
config.Project = val
c.Project = val
case "instance":
config.Instance = val
c.Instance = val
case "creds":
config.Creds = val
c.Creds = val
}
}

config.registerFlags()
if err := config.setFromGcloud(); err != nil {
return nil, err
c.registerFlags()
flag.Parse()
if err := c.setFromGcloud(); err != nil {
return err
}

return config, s.Err()
return s.Err()
}

type gcloudCredential struct {
Expand Down Expand Up @@ -128,14 +137,14 @@ func (c *Config) setFromGcloud() error {
if c.Creds == "" {
c.Creds = os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")
if c.Creds == "" {
log.Printf("-creds flag unset, will use gcloud credential")
fmt.Fprintln(c.ErrStream, "-creds flag unset, will use gcloud credential")
}
} else {
os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", c.Creds)
}

if c.Project == "" {
log.Printf("-project flag unset, will use gcloud active project")
fmt.Fprintln(c.ErrStream, "-project flag unset, will use gcloud active project")
}

if c.Creds != "" && c.Project != "" {
Expand All @@ -156,8 +165,7 @@ func (c *Config) setFromGcloud() error {
}

if c.Project == "" && gcloudConfig.Configuration.Properties.Core.Project != "" {
log.Printf("gcloud active project is \"%s\"",
gcloudConfig.Configuration.Properties.Core.Project)
fmt.Fprintf(c.ErrStream, "gcloud active project is \"%s\"", gcloudConfig.Configuration.Properties.Core.Project)
c.Project = gcloudConfig.Configuration.Properties.Core.Project
}

Expand Down
27 changes: 18 additions & 9 deletions api/interfaces/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"

prompt "github.com/c-bata/go-prompt"
"github.com/pkg/errors"
"github.com/takashabe/btcli/api/application"
"github.com/takashabe/btcli/api/config"
"github.com/takashabe/btcli/api/infrastructure/bigtable"
Expand All @@ -26,34 +27,42 @@ const (
type CLI struct {
OutStream io.Writer
ErrStream io.Writer

Version string
}

// Run invokes the CLI with the given arguments
func (c *CLI) Run(args []string) int {
conf, err := c.loadConfig()
conf, err := c.loadConfig(args)
if err != nil {
fmt.Fprintf(c.ErrStream, "args parse error: %v\n", err)
return ExitCodeParseError
}

p := c.preparePrompt(conf)
p, err := c.preparePrompt(conf)
if err != nil {
fmt.Fprintf(c.ErrStream, "failed to initialized prompt: %v\n", err)
return ExitCodeError
}

fmt.Fprintf(c.OutStream, "Version: %s\n", c.Version)
fmt.Fprintf(c.OutStream, "Please use `exit` or `Ctrl-D` to exit this program.\n")
p.Run()

// TODO: This is dead code. Invoke os.Exit by the prompt.Run
return ExitCodeOK
}

func (c *CLI) loadConfig() (*config.Config, error) {
conf, err := config.Load()
func (c *CLI) loadConfig(args []string) (*config.Config, error) {
conf := config.NewConfig(c.ErrStream)
err := conf.Load()
if err != nil {
return nil, err
}

flag.Usage = func() {
usage(c.OutStream)
}
flag.Parse()

return conf, nil
}

Expand All @@ -63,10 +72,10 @@ func usage(w io.Writer) {
flag.CommandLine.PrintDefaults()
}

func (c *CLI) preparePrompt(conf *config.Config) *prompt.Prompt {
func (c *CLI) preparePrompt(conf *config.Config) (*prompt.Prompt, error) {
repository, err := bigtable.NewBigtableRepository(conf.Project, conf.Instance)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to initialized bigtable repository:%v", err)
return nil, errors.Wrapf(err, "failed to initialized bigtable repository:%v", err)
}
tableInteractor := application.NewTableInteractor(repository)
rowsInteractor := application.NewRowsInteractor(repository)
Expand All @@ -86,5 +95,5 @@ func (c *CLI) preparePrompt(conf *config.Config) *prompt.Prompt {
completer.Do,
// TODO: Add histories from the history file.
// prompt.OptionHistory(),
)
), nil
}
12 changes: 6 additions & 6 deletions api/interfaces/executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ func TestReadOption(t *testing.T) {

func TestDoReadRowExecutor(t *testing.T) {
tm, _ := time.Parse("2006-01-02 15:04:05", "2018-01-01 00:00:00")
ctrl := gomock.NewController(t)
defer ctrl.Finish()

cases := []struct {
input string
expect string
Expand Down Expand Up @@ -140,10 +143,7 @@ func TestDoReadRowExecutor(t *testing.T) {
},
}
for _, c := range cases {
ctrl := gomock.NewController(t)
mockBtRepo := repository.NewMockBigtable(ctrl)
defer ctrl.Finish()

c.prepare(mockBtRepo)

var buf bytes.Buffer
Expand All @@ -163,6 +163,9 @@ func TestDoReadRowExecutor(t *testing.T) {
}

func TestDoCountExecutor(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

cases := []struct {
input string
expect string
Expand All @@ -177,10 +180,7 @@ func TestDoCountExecutor(t *testing.T) {
},
}
for _, c := range cases {
ctrl := gomock.NewController(t)
mockBtRepo := repository.NewMockBigtable(ctrl)
defer ctrl.Finish()

c.prepare(mockBtRepo)

var buf bytes.Buffer
Expand Down
4 changes: 4 additions & 0 deletions cmd/btcli/btcli.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ import (
"github.com/takashabe/btcli/api/interfaces"
)

// Version app version
var Version = "undefined"

func main() {
cli := &interfaces.CLI{
OutStream: os.Stdout,
ErrStream: os.Stderr,
Version: Version,
}
os.Exit(cli.Run(os.Args))
}

0 comments on commit 3338336

Please sign in to comment.