commit d7ffa94db5cc253006e0bf468097f5c551c46bc1 Author: AnthonyAxenov Date: Wed Feb 16 17:49:22 2022 +0800 Initial version 1.0.0 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4033d3e --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/bin +# /.vscode +*.csv +!example.csv diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..9ceee76 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + { + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Package", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${fileBasename}", + "args": [ + "example.csv", + ] + } + ] + } +} \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..82b8da5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Антон Аксенов (aka Anthony Axenov) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..70ba328 --- /dev/null +++ b/Makefile @@ -0,0 +1,41 @@ +# https://habr.com/ru/post/461467/ +# https://tutorialedge.net/golang/makefiles-for-go-developers/ +# https://earthly.dev/blog/golang-makefile/ +BINARY_NAME=csv2md +ARCH=amd64 + +LINUX_PATH="bin/linux_${ARCH}" +WINDOWS_PATH="bin/windows_${ARCH}" +DARWIN_PATH="bin/darwin_${ARCH}" + +LINUX_FILE="${LINUX_PATH}/${BINARY_NAME}" +WINDOWS_FILE="${WINDOWS_PATH}/${BINARY_NAME}.exe" +DARWIN_FILE="${DARWIN_PATH}/${BINARY_NAME}" + +## clean: Removes all compiled binaries +clean: + @go clean + @rm -rf bin/ + +## linux: Builds new binaries for linux (x64) +linux: + @rm -rf ${LINUX_PATH} + @GOARCH=${ARCH} GOOS=linux go build -o ${LINUX_FILE} . && echo "Compiled: ${LINUX_FILE}" + +## win: Builds new binaries for windows (x64) +win: + @rm -rf ${WINDOWS_PATH} + @GOARCH=${ARCH} GOOS=windows go build -o ${WINDOWS_FILE} . && echo "Compiled: ${WINDOWS_FILE}" + +## darwin: Builds new binaries for darwin (x64) +darwin: + @rm -rf ${DARWIN_PATH} + @GOARCH=${ARCH} GOOS=darwin go build -o ${DARWIN_FILE} . && echo "Compiled: ${DARWIN_FILE}" + +## build: Builds new binaries for linux, windows and darwin (x64) +all: clean linux win darwin + +## compile: This message +help: Makefile + @echo "Choose a command run:" + @sed -n 's/^##//p' $< | column -t -s ':' | sed -e 's/^/ /' diff --git a/README.md b/README.md new file mode 100644 index 0000000..8c624ae --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# csv2md + +Stupidly simple tool to convert csv-file to [markdown](https://spec-md.com/) table. + +Outputs result in stdout. + +Building: + +```shell +make help +``` + +Usage: + +```shell +csv2md example.csv > example.md # makes new file +csv2md example.csv | less # view result using *pager* +...anything is possible with redirection and piping +``` + +> **IMPORTANT:** input must be valid csv and whitespaces are allowed only between double-quotes. + +Examples can be found here: https://people.sc.fsu.edu/~jburkardt/data/csv/csv.html diff --git a/example.csv b/example.csv new file mode 100644 index 0000000..338cc90 --- /dev/null +++ b/example.csv @@ -0,0 +1,14 @@ +"Month","1958","1959","1960" +"JAN",340,360,417 +"FEB",318,342,391 +"MAR",362,406,419 +"APR",348,396,461 +"MAY",363,420,472 +"JUN",435,472,535 +"JUL",491,548,622 +"AUG",505,559,606 +"SEP",404,463,508 +"OCT",359,407,461 +"NOV",310,362,390 +"DEC",337,405,432 + diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..5c9ecb6 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module axenov/csv2md + +go 1.17 diff --git a/main.go b/main.go new file mode 100644 index 0000000..d5d5821 --- /dev/null +++ b/main.go @@ -0,0 +1,81 @@ +package main + +import ( + "encoding/csv" + "fmt" + "log" + "os" + "path/filepath" + "strings" +) + +const VERSION = "1.0.0" + +func main() { + if len(os.Args) < 2 { + usage() + os.Exit(1) + } + + src, err := ExpandPath(os.Args[1]) + if err != nil { + panic(err) + } + if _, err := os.Stat(src); err != nil { + panic(err) + } + + result := convert(readCsv(src)) + for _, row := range result { + fmt.Println(row) + } +} + +func usage() { + fmt.Fprintln(os.Stderr, "csv2md v" + VERSION) + fmt.Fprintln(os.Stderr, "Usage: csv2md data.csv > data.md") +} + +func ExpandPath(path string) (string, error) { + homepath, err := os.UserHomeDir() + if err != nil { + return "", err + } + newpath, err := filepath.Abs(strings.Replace(path, "~", homepath, 1)) + return newpath, err +} + +func readCsv(filePath string) [][]string { + f, err := os.Open(filePath) + if err != nil { + log.Fatal("Unable to read input file " + filePath, err) + } + defer f.Close() + + csvReader := csv.NewReader(f) + records, err := csvReader.ReadAll() + if err != nil { + log.Fatal("Unable to parse file as CSV for " + filePath, err) + } + + return records +} + +func convert(records [][]string) []string { + var result []string + for idx, row := range records { + str := "| " + for _, col := range row { + str += col + " | " + } + result = append(result, str) + if idx == 0 { + str := "| " + for range row { + str += "--- | " + } + result = append(result, str) + } + } + return result +}