Skip to content

Commit

Permalink
Added CLI interface and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
achannarasappa committed Jan 24, 2021
1 parent 6bd1b17 commit 81ea90d
Show file tree
Hide file tree
Showing 15 changed files with 703 additions and 98 deletions.
66 changes: 0 additions & 66 deletions cmd/main.go

This file was deleted.

82 changes: 82 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
Copyright © 2021 NAME HERE <EMAIL ADDRESS>
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 cmd

import (
"fmt"
"os"

"github.com/spf13/afero"
"github.com/spf13/cobra"

"ticker/internal/cli"
"ticker/internal/ui"

homedir "github.com/mitchellh/go-homedir"
"github.com/spf13/viper"
)

var (
configPath string
config cli.Config
watchlist string
refreshInterval int
rootCmd = &cobra.Command{
Use: "ticker",
Short: "Terminal stock ticker and stock gain/loss tracker",
Args: cli.Validate(
&config,
afero.NewOsFs(),
cli.Options{
ConfigPath: &configPath,
RefreshInterval: &refreshInterval,
Watchlist: &watchlist,
},
),
Run: cli.Run(ui.Start(&config)),
}
)

func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}

func init() {
cobra.OnInitialize(initConfig)
rootCmd.Flags().StringVar(&configPath, "config", "", "config file (default is $HOME/.ticker.yaml)")
rootCmd.Flags().StringVarP(&watchlist, "watchlist", "w", "", "comma separated list of symbols to watch")
rootCmd.Flags().IntVarP(&refreshInterval, "interval", "i", 0, "Refresh interval in seconds")
}

func initConfig() {
if configPath != "" {
viper.SetConfigFile(configPath)
configPath = viper.ConfigFileUsed()
} else {
home, err := homedir.Dir()
if err != nil {
fmt.Println(err)
os.Exit(1)
}

viper.AddConfigPath(home)
viper.AddConfigPath(".")
viper.SetConfigName(".ticker")
}
}
8 changes: 7 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module ticker-tape
module ticker

go 1.15

Expand All @@ -11,12 +11,18 @@ require (
github.com/jarcoal/httpmock v1.0.7
github.com/lucasb-eyer/go-colorful v1.0.3
github.com/matryer/moq v0.1.4 // indirect
github.com/mitchellh/go-homedir v1.1.0
github.com/muesli/reflow v0.2.1-0.20201126184510-3bcb929042f2
github.com/muesli/termenv v0.7.4
github.com/novalagung/gubrak/v2 v2.0.1
github.com/nxadm/tail v1.4.6 // indirect
github.com/onsi/ginkgo v1.14.2
github.com/onsi/gomega v1.10.1
github.com/pkg/errors v0.9.1
github.com/spf13/afero v1.5.1
github.com/spf13/cobra v1.1.1
github.com/spf13/viper v1.7.0
golang.org/x/sys v0.0.0-20210108172913-0df2131ae363 // indirect
gopkg.in/yaml.v2 v2.4.0
honnef.co/go/tools v0.0.1-2019.2.3
)
286 changes: 286 additions & 0 deletions go.sum

Large diffs are not rendered by default.

94 changes: 94 additions & 0 deletions internal/cli/cli.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package cli

import (
"errors"
"fmt"
"strings"
"ticker/internal/position"

"github.com/spf13/afero"
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
)

type Config struct {
RefreshInterval int `yaml:"interval"`
Watchlist []string `yaml:"watchlist"`
Lots []position.Lot `yaml:"lots"`
}

type Options struct {
ConfigPath *string
RefreshInterval *int
Watchlist *string
}

func Run(uiStartFn func() error) func(*cobra.Command, []string) {
return func(cmd *cobra.Command, args []string) {
err := uiStartFn()

if err != nil {
fmt.Println(fmt.Errorf("Unable to start UI: %w", err).Error())
}
}
}

func Validate(config *Config, fs afero.Fs, options Options) func(*cobra.Command, []string) error {
return func(cmd *cobra.Command, args []string) error {
var err error
*config, err = read(fs, options, config)
if err != nil {
return fmt.Errorf("Invalid config: %w", err)
}
return nil
}
}

func read(fs afero.Fs, options Options, configFile *Config) (Config, error) {

var (
err error
config Config
)
if *options.ConfigPath != "" {

handle, err := fs.Open(*options.ConfigPath)

if err != nil {
return config, err
}

defer handle.Close()
err = yaml.NewDecoder(handle).Decode(&config)

if err != nil {
return config, err
}
}

if len(config.Watchlist) == 0 && len(*options.Watchlist) == 0 {
return config, errors.New("No watchlist provided")
}

if len(*options.Watchlist) != 0 {
config.Watchlist = strings.Split(strings.ReplaceAll(*options.Watchlist, " ", ""), ",")
}

config.RefreshInterval = getRefreshInterval(*options.RefreshInterval, configFile.RefreshInterval)

return config, err

}

func getRefreshInterval(optionsRefreshInterval int, configRefreshInterval int) int {

if optionsRefreshInterval > 0 {
return optionsRefreshInterval
}

if configRefreshInterval > 0 {
return configRefreshInterval
}

return 5
}
13 changes: 13 additions & 0 deletions internal/cli/cli_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package cli_test

import (
"testing"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

func TestCli(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Cli Suite")
}
Loading

0 comments on commit 81ea90d

Please sign in to comment.