aboutsummaryrefslogtreecommitdiffstats
path: root/bommom.go
diff options
context:
space:
mode:
Diffstat (limited to 'bommom.go')
-rw-r--r--bommom.go271
1 files changed, 216 insertions, 55 deletions
diff --git a/bommom.go b/bommom.go
index 4b6e39d..f7ea966 100644
--- a/bommom.go
+++ b/bommom.go
@@ -3,9 +3,16 @@ package main
// CLI for bommom tools. Also used to launch web interface.
import (
+ "encoding/csv"
+ "encoding/json"
+ "encoding/xml"
"flag"
"fmt"
+ "io"
"log"
+ "os"
+ "path"
+ "strings"
)
// Command line flags
@@ -14,7 +21,7 @@ var (
fileStorePath = flag.String("path", "./filestore", "path to flat file data store top-level directory")
verbose = flag.Bool("verbose", false, "print extra info")
helpFlag = flag.Bool("help", false, "print full help info")
- outFormat = flag.String("format", "text", "command output format (for 'dump' etc)")
+ outFormat = flag.String("format", "", "command output format (for 'dump' etc)")
)
func main() {
@@ -32,6 +39,7 @@ func main() {
printUsage()
return
}
+
if flag.NArg() < 1 {
printUsage()
fmt.Println()
@@ -41,71 +49,134 @@ func main() {
switch flag.Arg(0) {
default:
log.Fatal("Error: unknown command: ", flag.Arg(0))
- case "load", "serve":
+ case "load", "serve", "convert":
log.Fatal("Error: Unimplemented, sorry")
case "init":
log.Println("Initializing...")
- initCmd()
- case "dump":
- log.Println("Dumping...")
- dumpCmd()
- case "list":
- listCmd()
+ initCmd()
+ case "dump":
+ dumpCmd()
+ case "list":
+ listCmd()
}
}
func initCmd() {
- _, err := NewJSONFileBomStore(*fileStorePath)
- if err != nil {
- log.Fatal(err)
- }
+ jfbs, err := NewJSONFileBomStore(*fileStorePath)
+ if err != nil {
+ log.Fatal(err)
+ }
+ jfbs, err = OpenJSONFileBomStore(*fileStorePath)
+ if err != nil {
+ log.Fatal(err)
+ }
+ bs, err := jfbs.GetStub(ShortName("common"), ShortName("gizmo"))
+ if err == nil {
+ // dummy BomStub already exists?
+ return
+ }
+ b := makeTestBom()
+ b.Version = "v001"
+ bs = &BomStub{Name: "gizmo",
+ Owner: "common",
+ Description: "fancy stuff",
+ HeadVersion: b.Version,
+ IsPublicView: true,
+ IsPublicEdit: true}
+ jfbs.Persist(bs, b, "v001")
}
func dumpCmd() {
- b := makeTestBom()
- b.Version = "v001"
- bs := &BomStub{Name: "widget",
- Owner: "common",
- Description: "fancy stuff",
- HeadVersion: b.Version,
- IsPublicView: true,
- IsPublicEdit: true}
- jfbs, err := OpenJSONFileBomStore(*fileStorePath)
- if err != nil {
- log.Fatal(err)
- }
- jfbs.Persist(bs, b, "v001")
+ if flag.NArg() != 3 && flag.NArg() != 4 {
+ log.Fatal("Error: wrong number of arguments (expected user and BOM name, optional file)")
+ }
+ userStr := flag.Arg(1)
+ nameStr := flag.Arg(2)
+ var outFile io.Writer
+ outFile = os.Stdout
+ if flag.NArg() == 4 {
+ f, err := os.Create(flag.Arg(3))
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer f.Close()
+ outFile = io.Writer(f)
+ // if no outFormat defined, infer from file extension
+ if *outFormat == "" {
+ switch ext := path.Ext(f.Name()); ext {
+ case "", ".txt", ".text":
+ // pass
+ case ".json":
+ *outFormat = "json"
+ case ".csv":
+ *outFormat = "csv"
+ case ".xml":
+ *outFormat = "xml"
+ default:
+ log.Fatal("Unknown file extention (use -format): " + ext)
+ }
+ }
+ }
+
+ if !isShortName(userStr) || !isShortName(nameStr) {
+ log.Fatal("Error: not valid ShortName: " + userStr +
+ " and/or " + nameStr)
+ }
+ jfbs, err := OpenJSONFileBomStore(*fileStorePath)
+ if err != nil {
+ log.Fatal(err)
+ }
+ if auth == nil {
+ auth = DummyAuth(true)
+ }
+ bs, b, err := jfbs.GetHead(ShortName(userStr), ShortName(nameStr))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ switch *outFormat {
+ case "text", "":
+ DumpBomAsText(bs, b, outFile)
+ case "json":
+ DumpBomAsJSON(bs, b, outFile)
+ case "csv":
+ DumpBomAsCSV(bs, b, outFile)
+ case "xml":
+ DumpBomAsXML(bs, b, outFile)
+ default:
+ log.Fatal("Error: unknown/unimplemented format: " + *outFormat)
+ }
}
func listCmd() {
- jfbs, err := OpenJSONFileBomStore(*fileStorePath)
- if err != nil {
- log.Fatal(err)
- }
- var bomStubs []BomStub
- if flag.NArg() > 2 {
- log.Fatal("Error: too many arguments...")
- }
- if flag.NArg() == 2 {
- name := flag.Arg(1)
- if !isShortName(name) {
- log.Fatal("Error: not a possible username: " + name)
- }
- bomStubs, err = jfbs.ListBoms(ShortName(name))
- if err != nil {
- log.Fatal(err)
- }
- } else {
- // list all boms from all names
- // TODO: ERROR
- bomStubs, err = jfbs.ListBoms("")
- if err != nil {
- log.Fatal(err)
- }
- }
- for _, bs := range bomStubs {
- fmt.Println(bs.Owner + "/" + bs.Name)
- }
+ jfbs, err := OpenJSONFileBomStore(*fileStorePath)
+ if err != nil {
+ log.Fatal(err)
+ }
+ var bomStubs []BomStub
+ if flag.NArg() > 2 {
+ log.Fatal("Error: too many arguments...")
+ }
+ if flag.NArg() == 2 {
+ name := flag.Arg(1)
+ if !isShortName(name) {
+ log.Fatal("Error: not a possible username: " + name)
+ }
+ bomStubs, err = jfbs.ListBoms(ShortName(name))
+ if err != nil {
+ log.Fatal(err)
+ }
+ } else {
+ // list all boms from all names
+ // TODO: ERROR
+ bomStubs, err = jfbs.ListBoms("")
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+ for _, bs := range bomStubs {
+ fmt.Println(bs.Owner + "/" + bs.Name)
+ }
}
func printUsage() {
@@ -118,11 +189,101 @@ func printUsage() {
fmt.Println("")
fmt.Println("\tinit \t\t initialize BOM and authentication datastores")
fmt.Println("\tlist [user]\t\t list BOMs, optionally filtered by user")
- fmt.Println("\tload <file>\t import a BOM")
- fmt.Println("\tdump <user> <name>\t dump a BOM to stdout")
+ fmt.Println("\tload <file.type> [user] [bom_name]\t import a BOM")
+ fmt.Println("\tdump <user> <name> [file.type]\t dump a BOM to stdout")
+ fmt.Println("\tconvert <infile.type> [outfile.type]\t convert a BOM file")
fmt.Println("\tserve\t\t serve up web interface over HTTP")
fmt.Println("")
fmt.Println("Extra command line options:")
fmt.Println("")
flag.PrintDefaults()
}
+
+// -------- conversion/dump/load routines
+
+func DumpBomAsText(bs *BomStub, b *Bom, out io.Writer) {
+ fmt.Fprintln(out)
+ fmt.Fprintf(out, "%s (version %s, created %s)\n", bs.Name, b.Version, b.Created)
+ fmt.Fprintf(out, "Creator: %s\n", bs.Owner)
+ if bs.Description != "" {
+ fmt.Fprintf(out, "Description: %s\n", bs.Description)
+ }
+ fmt.Println()
+ // "by line item"
+ fmt.Fprintf(out, "tag\tqty\tmanufacturer\tmpn\t\tdescription\t\tcomment\n")
+ for _, li := range b.LineItems {
+ fmt.Fprintf(out, "%s\t%d\t%s\t%s\t\t%s\t\t%s\n",
+ li.Tag,
+ len(li.Elements),
+ li.Manufacturer,
+ li.Mpn,
+ li.Description,
+ li.Comment)
+ }
+ /* // "by circuit element"
+ fmt.Fprintf(out, "tag\tsymbol\tmanufacturer\tmpn\t\tdescription\t\tcomment\n")
+ for _, li := range b.LineItems {
+ for _, elm := range li.Elements {
+ fmt.Fprintf(out, "%s\t%s\t%s\t%s\t\t%s\t\t%s\n",
+ li.Tag,
+ elm,
+ li.Manufacturer,
+ li.Mpn,
+ li.Description,
+ li.Comment)
+ }
+ }
+ */
+}
+
+func DumpBomAsCSV(bs *BomStub, b *Bom, out io.Writer) {
+ dumper := csv.NewWriter(out)
+ defer dumper.Flush()
+ // "by line item"
+ dumper.Write([]string{"qty",
+ "symbols",
+ "manufacturer",
+ "mpn",
+ "description",
+ "comment"})
+ for _, li := range b.LineItems {
+ dumper.Write([]string{
+ fmt.Sprint(len(li.Elements)),
+ strings.Join(li.Elements, ","),
+ li.Manufacturer,
+ li.Mpn,
+ li.Description,
+ li.Comment})
+ }
+}
+
+func DumpBomAsJSON(bs *BomStub, b *Bom, out io.Writer) {
+
+ obj := map[string]interface{}{
+ "bom_meta": bs,
+ "bom": b,
+ }
+
+ enc := json.NewEncoder(out)
+ if err := enc.Encode(&obj); err != nil {
+ log.Fatal(err)
+ }
+}
+
+func DumpBomAsXML(bs *BomStub, b *Bom, out io.Writer) {
+
+ /*
+ obj := map[string] interface{} {
+ "BomMeta": bs,
+ "Bom": b,
+ }
+ */
+
+ enc := xml.NewEncoder(out)
+ if err := enc.Encode(bs); err != nil {
+ log.Fatal(err)
+ }
+ if err := enc.Encode(b); err != nil {
+ log.Fatal(err)
+ }
+}