Skip to content

Commit

Permalink
Refactoring the command line main to allow driver additions.
Browse files Browse the repository at this point in the history
This change contains a refactor of the main to only leave code for driver
registration. It also enables the use of flags and removes temporary
code used for flag managment.
  • Loading branch information
xllora committed Mar 1, 2016
1 parent b0a5a01 commit f67db54
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 75 deletions.
21 changes: 6 additions & 15 deletions tools/vcli/bw/assert/assert.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,41 +27,32 @@ import (
"github.com/google/badwolf/storage"
"github.com/google/badwolf/tools/compliance"
"github.com/google/badwolf/tools/vcli/bw/command"
"github.com/google/badwolf/tools/vcli/bw/common"
"github.com/google/badwolf/tools/vcli/bw/io"
"github.com/google/badwolf/triple/literal"
)

// New creates the help command.
func New(store storage.Store, builder literal.Builder) *command.Command {
func New(store storage.Store, builder literal.Builder, chanSize int) *command.Command {
cmd := &command.Command{
UsageLine: "assert [--channel_size=123] folder_path",
UsageLine: "assert folder_path",
Short: "asserts all the stories in the indicated folder.",
Long: `Asserts all the stories in the folder. Each story is stored in a JSON
file containing all the sources and all the assertions to run.
`,
}
cmd.Run = func(ctx context.Context, args []string) int {
return assertCommand(ctx, cmd, args, store, builder)
return assertCommand(ctx, cmd, args, store, builder, chanSize)
}
return cmd
}

// assertCommand runs all the BQL statements available in the file.
func assertCommand(ctx context.Context, cmd *command.Command, args []string, store storage.Store, builder literal.Builder) int {
func assertCommand(ctx context.Context, cmd *command.Command, args []string, store storage.Store, builder literal.Builder, chanSize int) int {
if len(args) < 3 {
fmt.Fprintf(os.Stderr, "Missing required folder path. ")
cmd.Usage()
return 2
}
chanSize := 0
if len(args) >= 4 {
c, err := common.ParseChannelSizeFlag(args[2])
if err != nil {
fmt.Fprintf(os.Stderr, "Fail to parse flag %s with error %v\n", args[2], err)
return 2
}
chanSize = c
}
// Open the folder.
folder := strings.TrimSpace(args[len(args)-1])
f, err := os.Open(folder)
Expand All @@ -83,7 +74,7 @@ func assertCommand(ctx context.Context, cmd *command.Command, args []string, sto
continue
}
fmt.Printf("\tProcessing file %q... ", fi.Name())
lns, err := common.ReadLines(path.Join(folder, fi.Name()))
lns, err := io.ReadLines(path.Join(folder, fi.Name()))
if err != nil {
fmt.Fprintf(os.Stderr, "\n\n\tFailed to read file content with error %v\n\n", err)
return 2
Expand Down
70 changes: 41 additions & 29 deletions tools/vcli/bw/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package common

import (
"bufio"
"fmt"
"os"
"sort"
Expand All @@ -26,37 +25,14 @@ import (

"golang.org/x/net/context"

"github.com/google/badwolf/storage"
"github.com/google/badwolf/tools/vcli/bw/assert"
"github.com/google/badwolf/tools/vcli/bw/command"
"github.com/google/badwolf/tools/vcli/bw/run"
"github.com/google/badwolf/tools/vcli/bw/version"
"github.com/google/badwolf/triple/literal"
)

// ReadLines from a file into a string array.
func ReadLines(path string) ([]string, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()

var lines []string
scanner := bufio.NewScanner(f)
line := ""
for scanner.Scan() {
l := strings.TrimSpace(scanner.Text())
if len(l) == 0 || strings.Index(l, "#") == 0 {
continue
}
line += " " + l
if l[len(l)-1:] == ";" {
lines = append(lines, strings.TrimSpace(line))
line = ""
}
}
if line != "" {
lines = append(lines, strings.TrimSpace(line))
}
return lines, scanner.Err()
}

// ParseChannelSizeFlag attempts to parse the "channel_size" flag.
func ParseChannelSizeFlag(flag string) (int, error) {
ss := strings.Split(flag, "=")
Expand Down Expand Up @@ -100,6 +76,32 @@ func Help(args []string, cmds []*command.Command) int {
return 2
}

// StoreGenerator is a function that generate a new valid storage.Store.
type StoreGenerator func() (storage.Store, error)

// InitializeDriver attemps to initalize the driver.
func InitializeDriver(driverName string, drivers map[string]StoreGenerator) (storage.Store, error) {
f, ok := drivers[driverName]
if !ok {
var ds []string
for k := range drivers {
ds = append(ds, k)
}
return nil, fmt.Errorf("unkown driver name %q; valid drivers [%q]", driverName, strings.Join(ds, ", "))
}
return f()
}

// InitializeCommands intializes the avaialbe commands with the given storage
// instance.
func InitializeCommands(driver storage.Store, chanSize int) []*command.Command {
return []*command.Command{
assert.New(driver, literal.DefaultBuilder(), chanSize),
run.New(driver, chanSize),
version.New(),
}
}

// Eval of the command line version tool. This allows injecting multiple
// drivers.
func Eval(ctx context.Context, args []string, cmds []*command.Command) int {
Expand All @@ -126,3 +128,13 @@ func Eval(ctx context.Context, args []string, cmds []*command.Command) int {
}
return 1
}

// Run executes the main of the command line tool.
func Run(driverName string, drivers map[string]StoreGenerator, chanSize int) {
driver, err := InitializeDriver(driverName, drivers)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(2)
}
os.Exit(Eval(context.Background(), os.Args, InitializeCommands(driver, chanSize)))
}
51 changes: 51 additions & 0 deletions tools/vcli/bw/io/io.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package io contains helper functions for io operatoins on the command line
// bw tool.
package io

import (
"bufio"
"os"
"strings"
)

// ReadLines from a file into a string array.
func ReadLines(path string) ([]string, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()

var lines []string
scanner := bufio.NewScanner(f)
line := ""
for scanner.Scan() {
l := strings.TrimSpace(scanner.Text())
if len(l) == 0 || strings.Index(l, "#") == 0 {
continue
}
line += " " + l
if l[len(l)-1:] == ";" {
lines = append(lines, strings.TrimSpace(line))
line = ""
}
}
if line != "" {
lines = append(lines, strings.TrimSpace(line))
}
return lines, scanner.Err()
}
40 changes: 25 additions & 15 deletions tools/vcli/bw/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,31 +13,41 @@
// limitations under the License.

// BadWolf command line tools allows you to interact with graphs via BQL.

// This file is a template for creating your own bw tool with custom backend
// storage drivers. Just *copy* this file to your project, add the required
// flags that you need to initialize your driver and register your diver on
// the registeredDriver map in the registerDrivers function.
package main

import (
"os"
"flag"

"github.com/google/badwolf/storage"
"github.com/google/badwolf/storage/memory"
"github.com/google/badwolf/tools/vcli/bw/assert"
"github.com/google/badwolf/tools/vcli/bw/command"
"github.com/google/badwolf/tools/vcli/bw/common"
"github.com/google/badwolf/tools/vcli/bw/run"
"github.com/google/badwolf/tools/vcli/bw/version"
"github.com/google/badwolf/triple/literal"
)

"golang.org/x/net/context"
var (
// drivers contains the registed drivers available for this command line tool.
registeredDrivers map[string]common.StoreGenerator
// Available flags.
driver = flag.String("driver", "VOLATILE", "The storage driver to use {VOLATILE}.")
bqlChannelSize = flag.Int("bql_channel_size", 0, "Internal channel size to use on BQL queries.")
// Add your driver flags below.
)

// Registration of the available commands. Please keep sorted.
var cmds = []*command.Command{
assert.New(memory.NewStore(), literal.DefaultBuilder()),
run.New(memory.NewStore()),
version.New(),
// Registers the available drivers.
func registerDrivers() {
registeredDrivers = map[string]common.StoreGenerator{
// Memory only storage driver.
"VOLATILE": func() (storage.Store, error) {
return memory.NewStore(), nil
},
}
}

func main() {
ctx, args := context.Background(), os.Args
os.Exit(common.Eval(ctx, args, cmds))
flag.Parse()
registerDrivers()
common.Run(*driver, registeredDrivers, *bqlChannelSize)
}
23 changes: 7 additions & 16 deletions tools/vcli/bw/run/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,48 +29,39 @@ import (
"github.com/google/badwolf/bql/table"
"github.com/google/badwolf/storage"
"github.com/google/badwolf/tools/vcli/bw/command"
"github.com/google/badwolf/tools/vcli/bw/common"
"github.com/google/badwolf/tools/vcli/bw/io"
)

// New creates the help command.
func New(store storage.Store) *command.Command {
func New(store storage.Store, chanSize int) *command.Command {
cmd := &command.Command{
UsageLine: "run [--channel_size=123] file_path",
UsageLine: "run file_path",
Short: "runs BQL statements.",
Long: `Runs all the commands listed in the provided file. Lines in the
the file starting with # will be ignored. All statements will be run
sequentially.
`,
}
cmd.Run = func(ctx context.Context, args []string) int {
return runCommand(ctx, cmd, args, store)
return runCommand(ctx, cmd, args, store, chanSize)
}
return cmd
}

// runCommand runs all the BQL statements available in the file.
func runCommand(ctx context.Context, cmd *command.Command, args []string, store storage.Store) int {
func runCommand(ctx context.Context, cmd *command.Command, args []string, store storage.Store, chanSize int) int {
if len(args) < 3 {
fmt.Fprintf(os.Stderr, "Missing required file path. ")
cmd.Usage()
return 2
}
chanSize := 0
if len(args) >= 4 {
c, err := common.ParseChannelSizeFlag(args[2])
if err != nil {
fmt.Fprintf(os.Stderr, "Fail to parse flag %s with error %v\n", args[2], err)
return 2
}
chanSize = c
}
file := strings.TrimSpace(args[len(args)-1])
lines, err := getStatementsFromFile(file)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to read file %s\n\n\t%v\n\n", file, err)
return 2
}
fmt.Printf("Processing file %s\n\n", args[2])
fmt.Printf("Processing file %s\n\n", args[len(args)-1])
for idx, stm := range lines {
fmt.Printf("Processing statement (%d/%d):\n%s\n\n", idx+1, len(lines), stm)
tbl, err := runBQL(ctx, stm, store, chanSize)
Expand Down Expand Up @@ -110,7 +101,7 @@ func runBQL(ctx context.Context, bql string, s storage.Store, chanSize int) (*ta

// getStatementsFromFile returns the statements found in the provided file.
func getStatementsFromFile(path string) ([]string, error) {
stms, err := common.ReadLines(path)
stms, err := io.ReadLines(path)
if err != nil {
return nil, err
}
Expand Down

0 comments on commit f67db54

Please sign in to comment.