From ae5afea4be8ca56e3fb7963fea5e337332e50a1f Mon Sep 17 00:00:00 2001 From: bnewbold Date: Tue, 17 Apr 2012 23:15:34 -0400 Subject: basic dumping in several formats --- bommom.go | 271 +++++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 216 insertions(+), 55 deletions(-) (limited to 'bommom.go') 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 \t import a BOM") - fmt.Println("\tdump \t dump a BOM to stdout") + fmt.Println("\tload [user] [bom_name]\t import a BOM") + fmt.Println("\tdump [file.type]\t dump a BOM to stdout") + fmt.Println("\tconvert [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) + } +} -- cgit v1.2.3