New version

- stdin support
- refactored error handling
- help and some comments in src
pull/1/head
Anthony Axenov 2022-02-17 13:11:59 +08:00
parent bcb0a39d82
commit f1aa5d3eff
Signed by: anthony
GPG Key ID: EA9EC32FF7CCD4EC
1 changed files with 89 additions and 22 deletions

111
main.go
View File

@ -2,6 +2,8 @@ package main
import ( import (
"encoding/csv" "encoding/csv"
"errors"
"flag"
"fmt" "fmt"
"log" "log"
"os" "os"
@ -9,33 +11,62 @@ import (
"strings" "strings"
) )
const VERSION = "1.0.0" const VERSION = "1.1.0"
func main() { func main() {
if len(os.Args) < 2 { log.SetFlags(0)
usage() switch len(os.Args) {
os.Exit(1) case 1: // first we read data from stdin and then convert it
} data, err := readRawCsv()
if err != nil {
log.Fatal(err)
}
print(data)
src, err := ExpandPath(os.Args[1]) case 2: // but if 2nd arg is present
if err != nil { // probably user wants to get help
panic(err) help1 := flag.Bool("h", false, "Get help")
} help2 := flag.Bool("help", false, "Get help")
if _, err := os.Stat(src); err != nil { flag.Parse()
panic(err) if os.Args[1] == "help" || *help1 || *help2 {
} usage(os.Stdout)
os.Exit(0)
}
result := convert(readCsv(src)) // ...or to convert data from file
src, err := ExpandPath(os.Args[1])
if err != nil {
log.Fatal(err)
}
if _, err := os.Stat(src); err != nil {
log.Fatal(err)
}
data, err := readCsvFile(src)
if err != nil {
log.Fatal(err)
}
print(data)
// otherwise let's show usage help and exit (probably inaccessible code, but anyway)
default:
usage(os.Stdout)
os.Exit(0)
}
}
// print write converted data to stdout
func print(data [][]string) {
if len(data) == 0 {
usage(os.Stderr)
}
result := convert(data)
for _, row := range result { for _, row := range result {
fmt.Println(row) fmt.Println(row)
} }
} }
func usage() { // ExpandPath return absolute path to file replacing ~ to user's home folder
fmt.Fprintln(os.Stderr, "csv2md v" + VERSION)
fmt.Fprintln(os.Stderr, "Usage: csv2md data.csv > data.md")
}
func ExpandPath(path string) (string, error) { func ExpandPath(path string) (string, error) {
homepath, err := os.UserHomeDir() homepath, err := os.UserHomeDir()
if err != nil { if err != nil {
@ -45,22 +76,34 @@ func ExpandPath(path string) (string, error) {
return newpath, err return newpath, err
} }
func readCsv(filePath string) [][]string { // readRawCsv read data from file
func readCsvFile(filePath string) ([][]string, error) {
f, err := os.Open(filePath) f, err := os.Open(filePath)
if err != nil { if err != nil {
log.Fatal("Unable to read input file " + filePath, err) return nil, errors.New("Failed to open file '" + filePath + "': " + err.Error())
} }
defer f.Close() defer f.Close()
csvReader := csv.NewReader(f) csvReader := csv.NewReader(f)
records, err := csvReader.ReadAll() records, err := csvReader.ReadAll()
if err != nil { if err != nil {
log.Fatal("Unable to parse file as CSV for " + filePath, err) return nil, errors.New("Failed to parse CSV from file '" + filePath + "': " + err.Error())
} }
return records return records, nil
} }
// readRawCsv read data from stdin
func readRawCsv() ([][]string, error) {
csvReader := csv.NewReader(os.Stdin)
records, err := csvReader.ReadAll()
if err != nil {
return nil, errors.New("Failed to parse CSV from stdin: " + err.Error())
}
return records, nil
}
// convert format data from file or stdin as markdown
func convert(records [][]string) []string { func convert(records [][]string) []string {
var result []string var result []string
for idx, row := range records { for idx, row := range records {
@ -79,3 +122,27 @@ func convert(records [][]string) []string {
} }
return result return result
} }
// usage print help into writer
func usage(writer *os.File) {
usage := []string{
"csv2md v" + VERSION,
"Anthony Axenov (c) 2022, MIT license",
"https://github.com/anthonyaxenov/csv2md",
"",
"Usage:",
"\tcsv2md (-h|-help|--help|help) # to get this help",
"\tcsv2md example.csv # convert data from file and write result in stdout",
"\tcsv2md < example.csv # convert data from stdin and write result in stdout",
"\tcat example.csv | csv2md # convert data from stdin and write result in stdout",
"\tcsv2md example.csv > example.md # convert data from file and write result in new file",
"\tcsv2md example.csv | less # convert data from file and write result in stdout using pager",
"\tcsv2md # paste or type data to stdin by hands",
"\t # press Ctrl+D to view result in stdout",
"\tcsv2md > example.md # paste or type data to stdin by hands",
"\t # press Ctrl+D to write result in new file",
}
for _, str := range usage {
fmt.Fprintln(writer, str)
}
}