From ad3f76599b1c50e4f9d95331c4929a819073b91d Mon Sep 17 00:00:00 2001 From: Aaron Korte Date: Fri, 12 Jan 2024 17:54:07 +0100 Subject: [PATCH 1/7] Implement writing directly to file. --- comdirect/cmd/account.go | 6 +++--- comdirect/cmd/balance.go | 8 ++++---- comdirect/cmd/depot.go | 6 +++--- comdirect/cmd/document.go | 12 ++++++------ comdirect/cmd/position.go | 6 +++--- comdirect/cmd/report.go | 6 +++--- comdirect/cmd/root.go | 8 ++++++++ comdirect/cmd/transaction.go | 14 ++------------ comdirect/cmd/util.go | 31 +++++++++++++++++++++++++++++++ 9 files changed, 63 insertions(+), 34 deletions(-) create mode 100644 comdirect/cmd/util.go diff --git a/comdirect/cmd/account.go b/comdirect/cmd/account.go index 82bcfc7..a5e7a15 100644 --- a/comdirect/cmd/account.go +++ b/comdirect/cmd/account.go @@ -1,11 +1,11 @@ package cmd import ( + "log" + "github.com/jsattler/go-comdirect/pkg/comdirect" "github.com/olekukonko/tablewriter" "github.com/spf13/cobra" - "log" - "os" ) var ( @@ -36,7 +36,7 @@ func Account(cmd *cobra.Command, args []string) { } func printAccountTable(account *comdirect.AccountBalances) { - table := tablewriter.NewWriter(os.Stdout) + table := tablewriter.NewWriter(outputFile) table.SetHeader([]string{"ID", "TYPE", "IBAN", "CREDIT LIMIT"}) table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) table.SetCenterSeparator("|") diff --git a/comdirect/cmd/balance.go b/comdirect/cmd/balance.go index d8a97d7..617bf13 100644 --- a/comdirect/cmd/balance.go +++ b/comdirect/cmd/balance.go @@ -2,11 +2,11 @@ package cmd import ( "encoding/csv" + "log" + "github.com/jsattler/go-comdirect/pkg/comdirect" "github.com/olekukonko/tablewriter" "github.com/spf13/cobra" - "log" - "os" ) var ( @@ -39,7 +39,7 @@ func balance(cmd *cobra.Command, args []string) { } func printBalanceCSV(balances *comdirect.AccountBalances) { - table := csv.NewWriter(os.Stdout) + table := csv.NewWriter(outputFile) table.Write([]string{"ID", "TYPE", "IBAN", "BALANCE"}) for _, a := range balances.Values { table.Write([]string{a.AccountId, a.Account.AccountType.Text, a.Account.Iban, a.Balance.Value}) @@ -48,7 +48,7 @@ func printBalanceCSV(balances *comdirect.AccountBalances) { } func printBalanceTable(account *comdirect.AccountBalances) { - table := tablewriter.NewWriter(os.Stdout) + table := tablewriter.NewWriter(outputFile) table.SetHeader([]string{"ID", "TYPE", "IBAN", "BALANCE"}) table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) table.SetCenterSeparator("|") diff --git a/comdirect/cmd/depot.go b/comdirect/cmd/depot.go index 87176ba..1c5168b 100644 --- a/comdirect/cmd/depot.go +++ b/comdirect/cmd/depot.go @@ -2,10 +2,10 @@ package cmd import ( "encoding/csv" + "github.com/jsattler/go-comdirect/pkg/comdirect" "github.com/olekukonko/tablewriter" "github.com/spf13/cobra" - "os" ) var ( @@ -38,7 +38,7 @@ func depot(cmd *cobra.Command, args []string) { } func printDepotsCSV(depots *comdirect.Depots) { - table := csv.NewWriter(os.Stdout) + table := csv.NewWriter(outputFile) table.Write([]string{"DEPOT ID", "DISPLAY ID", "HOLDER NAME", "CLIENT ID"}) for _, d := range depots.Values { table.Write([]string{d.DepotId, d.DepotDisplayId, d.HolderName, d.ClientId}) @@ -46,7 +46,7 @@ func printDepotsCSV(depots *comdirect.Depots) { table.Flush() } func printDepotsTable(depots *comdirect.Depots) { - table := tablewriter.NewWriter(os.Stdout) + table := tablewriter.NewWriter(outputFile) table.SetHeader([]string{"DEPOT ID", "DISPLAY ID", "HOLDER NAME", "CLIENT ID"}) table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) table.SetCenterSeparator("|") diff --git a/comdirect/cmd/document.go b/comdirect/cmd/document.go index 8078ad3..f168857 100644 --- a/comdirect/cmd/document.go +++ b/comdirect/cmd/document.go @@ -2,13 +2,13 @@ package cmd import ( "fmt" - "github.com/jsattler/go-comdirect/pkg/comdirect" - "github.com/olekukonko/tablewriter" - "github.com/spf13/cobra" "log" - "os" "strings" "time" + + "github.com/jsattler/go-comdirect/pkg/comdirect" + "github.com/olekukonko/tablewriter" + "github.com/spf13/cobra" ) var ( @@ -68,7 +68,7 @@ func download(client *comdirect.Client, documents *comdirect.Documents) { log.Fatal("failed to download document: ", err) } // TODO: think about a better solution to limit download requests to 10/sec - if i % 10 == 0 && i != 0{ + if i%10 == 0 && i != 0 { time.Sleep(900 * time.Millisecond) } fmt.Printf("Download complete for document with ID %s\n", d.DocumentID) @@ -76,7 +76,7 @@ func download(client *comdirect.Client, documents *comdirect.Documents) { } func printDocumentTable(documents *comdirect.Documents) { - table := tablewriter.NewWriter(os.Stdout) + table := tablewriter.NewWriter(outputFile) table.SetHeader([]string{"ID", "NAME", "DATE", "OPENED", "TYPE"}) table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) table.SetCenterSeparator("|") diff --git a/comdirect/cmd/position.go b/comdirect/cmd/position.go index ec82e70..54c7a71 100644 --- a/comdirect/cmd/position.go +++ b/comdirect/cmd/position.go @@ -2,10 +2,10 @@ package cmd import ( "encoding/csv" + "github.com/jsattler/go-comdirect/pkg/comdirect" "github.com/olekukonko/tablewriter" "github.com/spf13/cobra" - "os" ) var ( @@ -39,7 +39,7 @@ func position(cmd *cobra.Command, args []string) { } func printPositionsCSV(positions *comdirect.DepotPositions) { - table := csv.NewWriter(os.Stdout) + table := csv.NewWriter(outputFile) table.Write([]string{"POSITION ID", "WKN", "QUANTITY", "CURRENT PRICE", "PREVDAY %", "PURCHASE %", "PURCHASE", "CURRENT"}) for _, d := range positions.Values { table.Write([]string{d.PositionId, d.Wkn, d.Quantity.Value, d.CurrentPrice.Price.Value, d.ProfitLossPrevDayRel, d.ProfitLossPurchaseRel, d.PurchaseValue.Value, d.CurrentValue.Value}) @@ -48,7 +48,7 @@ func printPositionsCSV(positions *comdirect.DepotPositions) { } func printPositionsTable(depots *comdirect.DepotPositions) { - table := tablewriter.NewWriter(os.Stdout) + table := tablewriter.NewWriter(outputFile) table.SetHeader([]string{"POSITION ID", "WKN", "QUANTITY", "CURRENT PRICE", "PREVDAY %", "PURCHASE %", "PURCHASE", "CURRENT"}) table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) table.SetCenterSeparator("|") diff --git a/comdirect/cmd/report.go b/comdirect/cmd/report.go index 8b00f67..972bf7f 100644 --- a/comdirect/cmd/report.go +++ b/comdirect/cmd/report.go @@ -2,10 +2,10 @@ package cmd import ( "encoding/csv" + "github.com/jsattler/go-comdirect/pkg/comdirect" "github.com/olekukonko/tablewriter" "github.com/spf13/cobra" - "os" ) var ( @@ -39,7 +39,7 @@ func report(cmd *cobra.Command, args []string) { } func printReportsCSV(reports *comdirect.Reports) { - table := csv.NewWriter(os.Stdout) + table := csv.NewWriter(outputFile) table.Write(reportsHeader) for _, r := range reports.Values { var balance string @@ -54,7 +54,7 @@ func printReportsCSV(reports *comdirect.Reports) { } func printReportsTable(reports *comdirect.Reports) { - table := tablewriter.NewWriter(os.Stdout) + table := tablewriter.NewWriter(outputFile) table.SetHeader(reportsHeader) table.SetColumnAlignment([]int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_RIGHT}) table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) diff --git a/comdirect/cmd/root.go b/comdirect/cmd/root.go index 2adc3b4..7a8ea93 100644 --- a/comdirect/cmd/root.go +++ b/comdirect/cmd/root.go @@ -26,6 +26,9 @@ var ( passwordFlag string clientIDFlag string clientSecretFlag string + fileFlag string + + outputFile *os.File rootCmd = &cobra.Command{ Use: "comdirect", @@ -54,6 +57,7 @@ func init() { rootCmd.PersistentFlags().StringVarP(&formatFlag, "format", "f", "markdown", "output format (markdown, csv or json)") rootCmd.PersistentFlags().IntVarP(&timeoutFlag, "timeout", "t", 30, "timeout in seconds to validate session TAN (default 30sec)") rootCmd.PersistentFlags().StringVar(&excludeFlag, "exclude", "", "exclude field from response") + rootCmd.PersistentFlags().StringVarP(&fileFlag, "output", "o", "-", "file name to write the output to (defaults to stdout)") rootCmd.AddCommand(documentCmd) rootCmd.AddCommand(depotCmd) @@ -106,5 +110,9 @@ func initClient() *comdirect.Client { } return client } + + // Set the target file to write to from the global fileFlag option. + outputFile = getWriteTarget() + return comdirect.NewWithAuthentication(authentication) } diff --git a/comdirect/cmd/transaction.go b/comdirect/cmd/transaction.go index 51a803b..26e6af0 100644 --- a/comdirect/cmd/transaction.go +++ b/comdirect/cmd/transaction.go @@ -2,10 +2,8 @@ package cmd import ( "encoding/csv" - "encoding/json" "fmt" "log" - "os" "strconv" "time" @@ -103,16 +101,8 @@ func getTransactionsSince(since string, client *comdirect.Client, accountID stri return transactions } -func printJSON(v interface{}) { - b, err := json.MarshalIndent(v, "", " ") - if err != nil { - log.Fatal(err) - } - fmt.Println(string(b)) -} - func printTransactionCSV(transactions *comdirect.AccountTransactions) { - table := csv.NewWriter(os.Stdout) + table := csv.NewWriter(outputFile) table.Write(transactionHeader) for _, t := range transactions.Values { holderName := t.Remitter.HolderName @@ -126,7 +116,7 @@ func printTransactionCSV(transactions *comdirect.AccountTransactions) { table.Flush() } func printTransactionTable(transactions *comdirect.AccountTransactions) { - table := tablewriter.NewWriter(os.Stdout) + table := tablewriter.NewWriter(outputFile) table.SetHeader(transactionHeader) table.SetColumnAlignment([]int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_RIGHT}) table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) diff --git a/comdirect/cmd/util.go b/comdirect/cmd/util.go new file mode 100644 index 0000000..de84449 --- /dev/null +++ b/comdirect/cmd/util.go @@ -0,0 +1,31 @@ +package cmd + +import ( + "encoding/json" + "fmt" + "log" + "os" +) + +func printJSON(v interface{}) { + b, err := json.MarshalIndent(v, "", " ") + if err != nil { + log.Fatal(err) + } + + c := fmt.Sprintf(string(b)) + outputFile.WriteString(c) +} + +func getWriteTarget() *os.File { + t := os.Stdout + if fileFlag != "" && fileFlag != "-" { + outputFile, err := os.OpenFile(fileFlag, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + println(err) + } else { + t = outputFile + } + } + return t +} From e8c786046a19b4febefab085b8580663f50d7e91 Mon Sep 17 00:00:00 2001 From: Aaron Korte Date: Fri, 12 Jan 2024 19:58:59 +0100 Subject: [PATCH 2/7] I don't think we need to format anything here. This just prints bytes. --- comdirect/cmd/util.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/comdirect/cmd/util.go b/comdirect/cmd/util.go index de84449..cb477d5 100644 --- a/comdirect/cmd/util.go +++ b/comdirect/cmd/util.go @@ -2,7 +2,6 @@ package cmd import ( "encoding/json" - "fmt" "log" "os" ) @@ -13,8 +12,7 @@ func printJSON(v interface{}) { log.Fatal(err) } - c := fmt.Sprintf(string(b)) - outputFile.WriteString(c) + outputFile.Write(b) } func getWriteTarget() *os.File { From a8ed6609017cc463ec01b1f129f0101f52c6be3b Mon Sep 17 00:00:00 2001 From: Aaron Korte Date: Fri, 12 Jan 2024 20:40:21 +0100 Subject: [PATCH 3/7] Rename some things. Wrap outputFile to prevent calling Close() on os.Stdout. --- comdirect/cmd/account.go | 4 ++-- comdirect/cmd/balance.go | 6 +++--- comdirect/cmd/depot.go | 7 ++++--- comdirect/cmd/document.go | 4 ++-- comdirect/cmd/position.go | 6 +++--- comdirect/cmd/report.go | 6 +++--- comdirect/cmd/root.go | 13 ++++++++++--- comdirect/cmd/transaction.go | 6 +++--- comdirect/cmd/util.go | 20 ++++++++++++++------ 9 files changed, 44 insertions(+), 28 deletions(-) diff --git a/comdirect/cmd/account.go b/comdirect/cmd/account.go index a5e7a15..5adc723 100644 --- a/comdirect/cmd/account.go +++ b/comdirect/cmd/account.go @@ -27,7 +27,7 @@ func Account(cmd *cobra.Command, args []string) { } switch formatFlag { case "json": - printJSON(balances) + writeJSON(balances) case "markdown": printAccountTable(balances) default: @@ -36,7 +36,7 @@ func Account(cmd *cobra.Command, args []string) { } func printAccountTable(account *comdirect.AccountBalances) { - table := tablewriter.NewWriter(outputFile) + table := tablewriter.NewWriter(getOutputFile()) table.SetHeader([]string{"ID", "TYPE", "IBAN", "CREDIT LIMIT"}) table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) table.SetCenterSeparator("|") diff --git a/comdirect/cmd/balance.go b/comdirect/cmd/balance.go index 617bf13..5051223 100644 --- a/comdirect/cmd/balance.go +++ b/comdirect/cmd/balance.go @@ -28,7 +28,7 @@ func balance(cmd *cobra.Command, args []string) { switch formatFlag { case "json": - printJSON(balances) + writeJSON(balances) case "markdown": printBalanceTable(balances) case "csv": @@ -39,7 +39,7 @@ func balance(cmd *cobra.Command, args []string) { } func printBalanceCSV(balances *comdirect.AccountBalances) { - table := csv.NewWriter(outputFile) + table := csv.NewWriter(getOutputFile()) table.Write([]string{"ID", "TYPE", "IBAN", "BALANCE"}) for _, a := range balances.Values { table.Write([]string{a.AccountId, a.Account.AccountType.Text, a.Account.Iban, a.Balance.Value}) @@ -48,7 +48,7 @@ func printBalanceCSV(balances *comdirect.AccountBalances) { } func printBalanceTable(account *comdirect.AccountBalances) { - table := tablewriter.NewWriter(outputFile) + table := tablewriter.NewWriter(getOutputFile()) table.SetHeader([]string{"ID", "TYPE", "IBAN", "BALANCE"}) table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) table.SetCenterSeparator("|") diff --git a/comdirect/cmd/depot.go b/comdirect/cmd/depot.go index 1c5168b..f061057 100644 --- a/comdirect/cmd/depot.go +++ b/comdirect/cmd/depot.go @@ -27,7 +27,7 @@ func depot(cmd *cobra.Command, args []string) { } switch formatFlag { case "json": - printJSON(depots) + writeJSON(depots) case "markdown": printDepotsTable(depots) case "csv": @@ -38,15 +38,16 @@ func depot(cmd *cobra.Command, args []string) { } func printDepotsCSV(depots *comdirect.Depots) { - table := csv.NewWriter(outputFile) + table := csv.NewWriter(getOutputFile()) table.Write([]string{"DEPOT ID", "DISPLAY ID", "HOLDER NAME", "CLIENT ID"}) for _, d := range depots.Values { table.Write([]string{d.DepotId, d.DepotDisplayId, d.HolderName, d.ClientId}) } table.Flush() } + func printDepotsTable(depots *comdirect.Depots) { - table := tablewriter.NewWriter(outputFile) + table := tablewriter.NewWriter(getOutputFile()) table.SetHeader([]string{"DEPOT ID", "DISPLAY ID", "HOLDER NAME", "CLIENT ID"}) table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) table.SetCenterSeparator("|") diff --git a/comdirect/cmd/document.go b/comdirect/cmd/document.go index f168857..b2a2707 100644 --- a/comdirect/cmd/document.go +++ b/comdirect/cmd/document.go @@ -49,7 +49,7 @@ func document(cmd *cobra.Command, args []string) { } else { switch formatFlag { case "json": - printJSON(filtered) + writeJSON(filtered) case "markdown": printDocumentTable(filtered) default: @@ -76,7 +76,7 @@ func download(client *comdirect.Client, documents *comdirect.Documents) { } func printDocumentTable(documents *comdirect.Documents) { - table := tablewriter.NewWriter(outputFile) + table := tablewriter.NewWriter(getOutputFile()) table.SetHeader([]string{"ID", "NAME", "DATE", "OPENED", "TYPE"}) table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) table.SetCenterSeparator("|") diff --git a/comdirect/cmd/position.go b/comdirect/cmd/position.go index 54c7a71..8b2a5e6 100644 --- a/comdirect/cmd/position.go +++ b/comdirect/cmd/position.go @@ -28,7 +28,7 @@ func position(cmd *cobra.Command, args []string) { } switch formatFlag { case "json": - printJSON(positions) + writeJSON(positions) case "markdown": printPositionsTable(positions) case "csv": @@ -39,7 +39,7 @@ func position(cmd *cobra.Command, args []string) { } func printPositionsCSV(positions *comdirect.DepotPositions) { - table := csv.NewWriter(outputFile) + table := csv.NewWriter(getOutputFile()) table.Write([]string{"POSITION ID", "WKN", "QUANTITY", "CURRENT PRICE", "PREVDAY %", "PURCHASE %", "PURCHASE", "CURRENT"}) for _, d := range positions.Values { table.Write([]string{d.PositionId, d.Wkn, d.Quantity.Value, d.CurrentPrice.Price.Value, d.ProfitLossPrevDayRel, d.ProfitLossPurchaseRel, d.PurchaseValue.Value, d.CurrentValue.Value}) @@ -48,7 +48,7 @@ func printPositionsCSV(positions *comdirect.DepotPositions) { } func printPositionsTable(depots *comdirect.DepotPositions) { - table := tablewriter.NewWriter(outputFile) + table := tablewriter.NewWriter(getOutputFile()) table.SetHeader([]string{"POSITION ID", "WKN", "QUANTITY", "CURRENT PRICE", "PREVDAY %", "PURCHASE %", "PURCHASE", "CURRENT"}) table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) table.SetCenterSeparator("|") diff --git a/comdirect/cmd/report.go b/comdirect/cmd/report.go index 972bf7f..4f9fe29 100644 --- a/comdirect/cmd/report.go +++ b/comdirect/cmd/report.go @@ -28,7 +28,7 @@ func report(cmd *cobra.Command, args []string) { } switch formatFlag { case "json": - printJSON(reports) + writeJSON(reports) case "markdown": printReportsTable(reports) case "csv": @@ -39,7 +39,7 @@ func report(cmd *cobra.Command, args []string) { } func printReportsCSV(reports *comdirect.Reports) { - table := csv.NewWriter(outputFile) + table := csv.NewWriter(getOutputFile()) table.Write(reportsHeader) for _, r := range reports.Values { var balance string @@ -54,7 +54,7 @@ func printReportsCSV(reports *comdirect.Reports) { } func printReportsTable(reports *comdirect.Reports) { - table := tablewriter.NewWriter(outputFile) + table := tablewriter.NewWriter(getOutputFile()) table.SetHeader(reportsHeader) table.SetColumnAlignment([]int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_RIGHT}) table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) diff --git a/comdirect/cmd/root.go b/comdirect/cmd/root.go index 7a8ea93..8056a01 100644 --- a/comdirect/cmd/root.go +++ b/comdirect/cmd/root.go @@ -31,8 +31,9 @@ var ( outputFile *os.File rootCmd = &cobra.Command{ - Use: "comdirect", - Short: "comdirect is a CLI tool to interact with the comdirect REST API", + Use: "comdirect", + Short: "comdirect is a CLI tool to interact with the comdirect REST API", + PersistentPostRun: closeOutputFile, } ) @@ -112,7 +113,13 @@ func initClient() *comdirect.Client { } // Set the target file to write to from the global fileFlag option. - outputFile = getWriteTarget() + outputFile = getOutputFileFromFlag() return comdirect.NewWithAuthentication(authentication) } + +func closeOutputFile(cmd *cobra.Command, args []string) { + if outputFile != nil { + outputFile.Close() + } +} diff --git a/comdirect/cmd/transaction.go b/comdirect/cmd/transaction.go index 26e6af0..76b01ec 100644 --- a/comdirect/cmd/transaction.go +++ b/comdirect/cmd/transaction.go @@ -43,7 +43,7 @@ func transaction(cmd *cobra.Command, args []string) { switch formatFlag { case "json": - printJSON(transactions) + writeJSON(transactions) case "markdown": printTransactionTable(transactions) case "csv": @@ -102,7 +102,7 @@ func getTransactionsSince(since string, client *comdirect.Client, accountID stri } func printTransactionCSV(transactions *comdirect.AccountTransactions) { - table := csv.NewWriter(outputFile) + table := csv.NewWriter(getOutputFile()) table.Write(transactionHeader) for _, t := range transactions.Values { holderName := t.Remitter.HolderName @@ -116,7 +116,7 @@ func printTransactionCSV(transactions *comdirect.AccountTransactions) { table.Flush() } func printTransactionTable(transactions *comdirect.AccountTransactions) { - table := tablewriter.NewWriter(outputFile) + table := tablewriter.NewWriter(getOutputFile()) table.SetHeader(transactionHeader) table.SetColumnAlignment([]int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_RIGHT}) table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) diff --git a/comdirect/cmd/util.go b/comdirect/cmd/util.go index cb477d5..e53160f 100644 --- a/comdirect/cmd/util.go +++ b/comdirect/cmd/util.go @@ -6,24 +6,32 @@ import ( "os" ) -func printJSON(v interface{}) { +// Format JSON input and write to global output file which might be stdout. +func writeJSON(v interface{}) { b, err := json.MarshalIndent(v, "", " ") if err != nil { log.Fatal(err) } - outputFile.Write(b) + getOutputFile().Write(b) } -func getWriteTarget() *os.File { - t := os.Stdout +func getOutputFile() *os.File { + if outputFile == nil { + return os.Stdout + } + return outputFile +} + +// Read global fileFlag variable and set the +func getOutputFileFromFlag() *os.File { if fileFlag != "" && fileFlag != "-" { outputFile, err := os.OpenFile(fileFlag, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { println(err) } else { - t = outputFile + return outputFile } } - return t + return nil } From 2558f4f92c3fea88c0b5126083dcc2b4dc5debcb Mon Sep 17 00:00:00 2001 From: Aaron Korte Date: Fri, 12 Jan 2024 20:42:14 +0100 Subject: [PATCH 4/7] Complete comment. --- comdirect/cmd/util.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/comdirect/cmd/util.go b/comdirect/cmd/util.go index e53160f..46c95ff 100644 --- a/comdirect/cmd/util.go +++ b/comdirect/cmd/util.go @@ -23,7 +23,8 @@ func getOutputFile() *os.File { return outputFile } -// Read global fileFlag variable and set the +// Read global fileFlag variable and return a file pointer to the target file if any. +// This function return nil if the target file is stdout. func getOutputFileFromFlag() *os.File { if fileFlag != "" && fileFlag != "-" { outputFile, err := os.OpenFile(fileFlag, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) From c7826ac6e73947cafe3c844f1a5d300047a81620 Mon Sep 17 00:00:00 2001 From: Aaron Korte Date: Fri, 12 Jan 2024 22:38:02 +0100 Subject: [PATCH 5/7] Refactor file writing process. We now write to an internal buffer and then write that to a file after the command has finished. --- comdirect/cmd/account.go | 2 +- comdirect/cmd/balance.go | 4 ++-- comdirect/cmd/depot.go | 4 ++-- comdirect/cmd/document.go | 2 +- comdirect/cmd/io.go | 39 ++++++++++++++++++++++++++++++++++++ comdirect/cmd/position.go | 4 ++-- comdirect/cmd/report.go | 4 ++-- comdirect/cmd/root.go | 14 +++---------- comdirect/cmd/transaction.go | 4 ++-- comdirect/cmd/util.go | 38 ----------------------------------- 10 files changed, 54 insertions(+), 61 deletions(-) create mode 100644 comdirect/cmd/io.go delete mode 100644 comdirect/cmd/util.go diff --git a/comdirect/cmd/account.go b/comdirect/cmd/account.go index 5adc723..4749476 100644 --- a/comdirect/cmd/account.go +++ b/comdirect/cmd/account.go @@ -36,7 +36,7 @@ func Account(cmd *cobra.Command, args []string) { } func printAccountTable(account *comdirect.AccountBalances) { - table := tablewriter.NewWriter(getOutputFile()) + table := tablewriter.NewWriter(getOutputBuffer()) table.SetHeader([]string{"ID", "TYPE", "IBAN", "CREDIT LIMIT"}) table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) table.SetCenterSeparator("|") diff --git a/comdirect/cmd/balance.go b/comdirect/cmd/balance.go index 5051223..c4137a6 100644 --- a/comdirect/cmd/balance.go +++ b/comdirect/cmd/balance.go @@ -39,7 +39,7 @@ func balance(cmd *cobra.Command, args []string) { } func printBalanceCSV(balances *comdirect.AccountBalances) { - table := csv.NewWriter(getOutputFile()) + table := csv.NewWriter(getOutputBuffer()) table.Write([]string{"ID", "TYPE", "IBAN", "BALANCE"}) for _, a := range balances.Values { table.Write([]string{a.AccountId, a.Account.AccountType.Text, a.Account.Iban, a.Balance.Value}) @@ -48,7 +48,7 @@ func printBalanceCSV(balances *comdirect.AccountBalances) { } func printBalanceTable(account *comdirect.AccountBalances) { - table := tablewriter.NewWriter(getOutputFile()) + table := tablewriter.NewWriter(getOutputBuffer()) table.SetHeader([]string{"ID", "TYPE", "IBAN", "BALANCE"}) table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) table.SetCenterSeparator("|") diff --git a/comdirect/cmd/depot.go b/comdirect/cmd/depot.go index f061057..86115b6 100644 --- a/comdirect/cmd/depot.go +++ b/comdirect/cmd/depot.go @@ -38,7 +38,7 @@ func depot(cmd *cobra.Command, args []string) { } func printDepotsCSV(depots *comdirect.Depots) { - table := csv.NewWriter(getOutputFile()) + table := csv.NewWriter(getOutputBuffer()) table.Write([]string{"DEPOT ID", "DISPLAY ID", "HOLDER NAME", "CLIENT ID"}) for _, d := range depots.Values { table.Write([]string{d.DepotId, d.DepotDisplayId, d.HolderName, d.ClientId}) @@ -47,7 +47,7 @@ func printDepotsCSV(depots *comdirect.Depots) { } func printDepotsTable(depots *comdirect.Depots) { - table := tablewriter.NewWriter(getOutputFile()) + table := tablewriter.NewWriter(getOutputBuffer()) table.SetHeader([]string{"DEPOT ID", "DISPLAY ID", "HOLDER NAME", "CLIENT ID"}) table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) table.SetCenterSeparator("|") diff --git a/comdirect/cmd/document.go b/comdirect/cmd/document.go index b2a2707..d3036b2 100644 --- a/comdirect/cmd/document.go +++ b/comdirect/cmd/document.go @@ -76,7 +76,7 @@ func download(client *comdirect.Client, documents *comdirect.Documents) { } func printDocumentTable(documents *comdirect.Documents) { - table := tablewriter.NewWriter(getOutputFile()) + table := tablewriter.NewWriter(getOutputBuffer()) table.SetHeader([]string{"ID", "NAME", "DATE", "OPENED", "TYPE"}) table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) table.SetCenterSeparator("|") diff --git a/comdirect/cmd/io.go b/comdirect/cmd/io.go new file mode 100644 index 0000000..420e393 --- /dev/null +++ b/comdirect/cmd/io.go @@ -0,0 +1,39 @@ +package cmd + +import ( + "encoding/json" + "io" + "log" + "os" + + "github.com/spf13/cobra" +) + +// Format JSON input and write to global output file which might be stdout. +func writeJSON(v interface{}) { + b, err := json.MarshalIndent(v, "", " ") + if err != nil { + log.Fatal(err) + } + + getOutputBuffer().Write(b) +} + +func getOutputBuffer() io.Writer { + return &outputBuffer +} + +func writeToOutputFile(cmd *cobra.Command, args []string) { + if fileFlag == "-" { + // We have either no file flag at all or the user explicitly specified "-", so we simply write to stdout + outputBuffer.WriteTo(os.Stdout) + } else { + f, err := os.OpenFile(fileFlag, os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + println(err) + } else { + outputBuffer.WriteTo(f) + f.Close() + } + } +} diff --git a/comdirect/cmd/position.go b/comdirect/cmd/position.go index 8b2a5e6..0dc07e7 100644 --- a/comdirect/cmd/position.go +++ b/comdirect/cmd/position.go @@ -39,7 +39,7 @@ func position(cmd *cobra.Command, args []string) { } func printPositionsCSV(positions *comdirect.DepotPositions) { - table := csv.NewWriter(getOutputFile()) + table := csv.NewWriter(getOutputBuffer()) table.Write([]string{"POSITION ID", "WKN", "QUANTITY", "CURRENT PRICE", "PREVDAY %", "PURCHASE %", "PURCHASE", "CURRENT"}) for _, d := range positions.Values { table.Write([]string{d.PositionId, d.Wkn, d.Quantity.Value, d.CurrentPrice.Price.Value, d.ProfitLossPrevDayRel, d.ProfitLossPurchaseRel, d.PurchaseValue.Value, d.CurrentValue.Value}) @@ -48,7 +48,7 @@ func printPositionsCSV(positions *comdirect.DepotPositions) { } func printPositionsTable(depots *comdirect.DepotPositions) { - table := tablewriter.NewWriter(getOutputFile()) + table := tablewriter.NewWriter(getOutputBuffer()) table.SetHeader([]string{"POSITION ID", "WKN", "QUANTITY", "CURRENT PRICE", "PREVDAY %", "PURCHASE %", "PURCHASE", "CURRENT"}) table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) table.SetCenterSeparator("|") diff --git a/comdirect/cmd/report.go b/comdirect/cmd/report.go index 4f9fe29..f4a9700 100644 --- a/comdirect/cmd/report.go +++ b/comdirect/cmd/report.go @@ -39,7 +39,7 @@ func report(cmd *cobra.Command, args []string) { } func printReportsCSV(reports *comdirect.Reports) { - table := csv.NewWriter(getOutputFile()) + table := csv.NewWriter(getOutputBuffer()) table.Write(reportsHeader) for _, r := range reports.Values { var balance string @@ -54,7 +54,7 @@ func printReportsCSV(reports *comdirect.Reports) { } func printReportsTable(reports *comdirect.Reports) { - table := tablewriter.NewWriter(getOutputFile()) + table := tablewriter.NewWriter(getOutputBuffer()) table.SetHeader(reportsHeader) table.SetColumnAlignment([]int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_RIGHT}) table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) diff --git a/comdirect/cmd/root.go b/comdirect/cmd/root.go index 8056a01..b96e6d6 100644 --- a/comdirect/cmd/root.go +++ b/comdirect/cmd/root.go @@ -1,6 +1,7 @@ package cmd import ( + "bytes" "context" "fmt" "log" @@ -28,12 +29,12 @@ var ( clientSecretFlag string fileFlag string - outputFile *os.File + outputBuffer bytes.Buffer rootCmd = &cobra.Command{ Use: "comdirect", Short: "comdirect is a CLI tool to interact with the comdirect REST API", - PersistentPostRun: closeOutputFile, + PersistentPostRun: writeToOutputFile, } ) @@ -112,14 +113,5 @@ func initClient() *comdirect.Client { return client } - // Set the target file to write to from the global fileFlag option. - outputFile = getOutputFileFromFlag() - return comdirect.NewWithAuthentication(authentication) } - -func closeOutputFile(cmd *cobra.Command, args []string) { - if outputFile != nil { - outputFile.Close() - } -} diff --git a/comdirect/cmd/transaction.go b/comdirect/cmd/transaction.go index 76b01ec..98aac42 100644 --- a/comdirect/cmd/transaction.go +++ b/comdirect/cmd/transaction.go @@ -102,7 +102,7 @@ func getTransactionsSince(since string, client *comdirect.Client, accountID stri } func printTransactionCSV(transactions *comdirect.AccountTransactions) { - table := csv.NewWriter(getOutputFile()) + table := csv.NewWriter(getOutputBuffer()) table.Write(transactionHeader) for _, t := range transactions.Values { holderName := t.Remitter.HolderName @@ -116,7 +116,7 @@ func printTransactionCSV(transactions *comdirect.AccountTransactions) { table.Flush() } func printTransactionTable(transactions *comdirect.AccountTransactions) { - table := tablewriter.NewWriter(getOutputFile()) + table := tablewriter.NewWriter(getOutputBuffer()) table.SetHeader(transactionHeader) table.SetColumnAlignment([]int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_RIGHT}) table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) diff --git a/comdirect/cmd/util.go b/comdirect/cmd/util.go deleted file mode 100644 index 46c95ff..0000000 --- a/comdirect/cmd/util.go +++ /dev/null @@ -1,38 +0,0 @@ -package cmd - -import ( - "encoding/json" - "log" - "os" -) - -// Format JSON input and write to global output file which might be stdout. -func writeJSON(v interface{}) { - b, err := json.MarshalIndent(v, "", " ") - if err != nil { - log.Fatal(err) - } - - getOutputFile().Write(b) -} - -func getOutputFile() *os.File { - if outputFile == nil { - return os.Stdout - } - return outputFile -} - -// Read global fileFlag variable and return a file pointer to the target file if any. -// This function return nil if the target file is stdout. -func getOutputFileFromFlag() *os.File { - if fileFlag != "" && fileFlag != "-" { - outputFile, err := os.OpenFile(fileFlag, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) - if err != nil { - println(err) - } else { - return outputFile - } - } - return nil -} From 2a078233c49d1b9a76f9125fda499eea29040a60 Mon Sep 17 00:00:00 2001 From: Aaron Korte Date: Fri, 12 Jan 2024 23:13:12 +0100 Subject: [PATCH 6/7] Change error print to the same format the rest of the repo uses. --- comdirect/cmd/io.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/comdirect/cmd/io.go b/comdirect/cmd/io.go index 420e393..968f733 100644 --- a/comdirect/cmd/io.go +++ b/comdirect/cmd/io.go @@ -2,6 +2,7 @@ package cmd import ( "encoding/json" + "fmt" "io" "log" "os" @@ -30,7 +31,7 @@ func writeToOutputFile(cmd *cobra.Command, args []string) { } else { f, err := os.OpenFile(fileFlag, os.O_CREATE|os.O_WRONLY, 0644) if err != nil { - println(err) + fmt.Println(err) } else { outputBuffer.WriteTo(f) f.Close() From 960b3e9298aa78f2d452501985b393070060ccd4 Mon Sep 17 00:00:00 2001 From: Aaron Korte Date: Fri, 12 Jan 2024 23:18:28 +0100 Subject: [PATCH 7/7] Print a more useful error message and use the log package. --- comdirect/cmd/io.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/comdirect/cmd/io.go b/comdirect/cmd/io.go index 968f733..8335d37 100644 --- a/comdirect/cmd/io.go +++ b/comdirect/cmd/io.go @@ -2,7 +2,6 @@ package cmd import ( "encoding/json" - "fmt" "io" "log" "os" @@ -31,7 +30,7 @@ func writeToOutputFile(cmd *cobra.Command, args []string) { } else { f, err := os.OpenFile(fileFlag, os.O_CREATE|os.O_WRONLY, 0644) if err != nil { - fmt.Println(err) + log.Fatal(err.Error()) } else { outputBuffer.WriteTo(f) f.Close()