diff --git a/07-behaviour_error_handling/cmd/beers-cli/main.go b/07-behaviour_error_handling/cmd/beers-cli/main.go index 8fedd45..49b0656 100644 --- a/07-behaviour_error_handling/cmd/beers-cli/main.go +++ b/07-behaviour_error_handling/cmd/beers-cli/main.go @@ -1,11 +1,8 @@ package main import ( - "flag" - "github.com/CodelyTV/golang-examples/07-behaviour_error_handling/internal/storage/ontario" - beerscli "github.com/CodelyTV/golang-examples/07-behaviour_error_handling/internal" "github.com/CodelyTV/golang-examples/07-behaviour_error_handling/internal/cli" "github.com/CodelyTV/golang-examples/07-behaviour_error_handling/internal/storage/csv" "github.com/spf13/cobra" @@ -13,16 +10,10 @@ import ( func main() { - csvData := flag.Bool("csv", false, "load data from csv") - flag.Parse() - var repo beerscli.BeerRepo - repo = csv.NewRepository() - - if !*csvData { - repo = ontario.NewOntarioRepository() - } + repoAPI := csv.NewRepository() + repoCSV := ontario.NewOntarioRepository() rootCmd := &cobra.Command{Use: "beers-cli"} - rootCmd.AddCommand(cli.InitBeersCmd(repo)) + rootCmd.AddCommand(cli.InitBeersCmd(repoAPI, repoCSV)) rootCmd.Execute() } diff --git a/07-behaviour_error_handling/internal/cli/beers.go b/07-behaviour_error_handling/internal/cli/beers.go index 8f8e666..ab4258a 100644 --- a/07-behaviour_error_handling/internal/cli/beers.go +++ b/07-behaviour_error_handling/internal/cli/beers.go @@ -17,22 +17,36 @@ type CobraFn func(cmd *cobra.Command, args []string) const idFlag = "id" // InitBeersCmd initialize beers command -func InitBeersCmd(repository beerscli.BeerRepo) *cobra.Command { +func InitBeersCmd(repoAPI beerscli.BeerRepo, repoCSV beerscli.BeerRepo) *cobra.Command { beersCmd := &cobra.Command{ Use: "beers", Short: "Print data about beers", - Run: runBeersFn(repository), + Run: runBeersFn(repoAPI, repoCSV), } beersCmd.Flags().StringP(idFlag, "i", "", "id of the beer") + beersCmd.Flags().Bool("csv", false, "load data from csv") return beersCmd } -func runBeersFn(repository beerscli.BeerRepo) CobraFn { +func runBeersFn(repoAPI beerscli.BeerRepo, repoCSV beerscli.BeerRepo) CobraFn { return func(cmd *cobra.Command, args []string) { + var repository beerscli.BeerRepo + useCSV, _ := cmd.Flags().GetBool("csv") + if useCSV { + repository = repoAPI + } else { + repository = repoCSV + } beers, err := repository.GetBeers() if errors.IsDataUnreacheable(err) { + log.Printf("https://github.com/caleeli/golang-examples.git/issues/new?assignees=&labels=&template=dataunreachable.md&title=") + } + if errors.IsLoadCSVError(err) { + log.Printf("https://github.com/caleeli/golang-examples.git/issues/new?assignees=&labels=&template=loadcsv.md&title=") + } + if err != nil { log.Fatal(err) } diff --git a/07-behaviour_error_handling/internal/errors/load_csv_errors.go b/07-behaviour_error_handling/internal/errors/load_csv_errors.go new file mode 100644 index 0000000..748c244 --- /dev/null +++ b/07-behaviour_error_handling/internal/errors/load_csv_errors.go @@ -0,0 +1,28 @@ +package errors + +import ( + "github.com/pkg/errors" +) + +type loadCSVError struct { + error +} + +// WrapLoadCSVError returns an error which wraps err that satisfies +// IsLoadCSVError() +func WrapLoadCSVError(err error, format string, args ...interface{}) error { + return &loadCSVError{errors.Wrapf(err, format, args...)} +} + +// NewLoadCSVError returns an error which satisfies IsLoadCSVError() +func NewLoadCSVError(format string, args ...interface{}) error { + return &loadCSVError{errors.Errorf(format, args...)} +} + +// IsLoadCSVError reports whether err was created with LoadCSVErrorf() or +// NewLoadCSVError() +func IsLoadCSVError(err error) bool { + err = errors.Cause(err) + _, ok := err.(*loadCSVError) + return ok +} diff --git a/07-behaviour_error_handling/internal/storage/csv/repository.go b/07-behaviour_error_handling/internal/storage/csv/repository.go index cb1e7cc..047f1a0 100644 --- a/07-behaviour_error_handling/internal/storage/csv/repository.go +++ b/07-behaviour_error_handling/internal/storage/csv/repository.go @@ -7,6 +7,7 @@ import ( "strings" beerscli "github.com/CodelyTV/golang-examples/07-behaviour_error_handling/internal" + "github.com/CodelyTV/golang-examples/07-behaviour_error_handling/internal/errors" ) type repository struct { @@ -19,15 +20,27 @@ func NewRepository() beerscli.BeerRepo { // GetBeers fetch beers data from csv func (r *repository) GetBeers() ([]beerscli.Beer, error) { - f, _ := os.Open("07-behaviour_error_handling/data/beers.csv") + file := "07-behaviour_error_handling/data/beers.csv" + f, err := os.Open(file) + if err != nil { + return nil, errors.WrapLoadCSVError(err, "Unable to open %s", file) + } + reader := bufio.NewReader(f) var beers []beerscli.Beer - for line := readLine(reader); line != nil; line = readLine(reader) { + for line, err := readLine(reader); line != nil; line, err = readLine(reader) { + if err != nil { + return nil, errors.WrapLoadCSVError(err, "Failed reading of line %d", line) + } + values := strings.Split(string(line), ",") - productID, _ := strconv.Atoi(values[0]) + productID, err := strconv.Atoi(values[0]) + if err != nil { + return nil, errors.WrapLoadCSVError(err, "Invalid product ID '%s'", values[0]) + } beer := beerscli.NewBeer( productID, @@ -45,7 +58,7 @@ func (r *repository) GetBeers() ([]beerscli.Beer, error) { return beers, nil } -func readLine(reader *bufio.Reader) (line []byte) { - line, _, _ = reader.ReadLine() +func readLine(reader *bufio.Reader) (line []byte, err error) { + line, _, err = reader.ReadLine() return }