Skip to content

Commit

Permalink
Better error reporting (#3)
Browse files Browse the repository at this point in the history
Output better error reporting when a package cant be loaded, rather than output a blank *.proto file. The package.Load() error did not contain any useful information about failed package loads, they must be fetched at a lower level. Additionally added some more documentation, hopefully to make it easier for new users to use this.
  • Loading branch information
KatamariJr authored and anjmao committed Oct 8, 2019
1 parent 07c7548 commit b6295fa
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 24 deletions.
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,24 @@

Generate Protobuf messages from given go structs. No RPC, not gogo syntax, just pure Protobuf messages.

### Syntax
```
-f string
Protobuf output file path. (default ".")
-filter string
Filter by struct names. Case insensitive.
-p value
Fully qualified path of packages to analyse. Relative paths ("./example/in") are allowed.
```

### Example

Your package you wish to export must be inside of your working directory. Package paths can be fully-qualified or relative.

```sh
GO111MODULE=off go get -u github.com/anjmao/go2proto
go2proto -f ${PWD}/example/out -p github.com/anjmao/go2proto/example/in
cd ~/go/src/github.com/anjmao/go2proto
go2proto -f ./example/out -p ./example/in
```

### Note
Expand Down
68 changes: 45 additions & 23 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package main

import (
"errors"
"flag"
"fmt"
"go/token"
"go/types"
"log"
Expand All @@ -18,6 +20,8 @@ import (

type arrFlags []string

const outputFileName = "output.proto"

func (i *arrFlags) String() string {
return ""
}
Expand All @@ -28,54 +32,72 @@ func (i *arrFlags) Set(value string) error {
}

var (
filter = flag.String("filter", "", "Filter struct names.")
protoFolder = flag.String("f", "", "Proto output path.")
pkgFlags arrFlags
filter = flag.String("filter", "", "Filter by struct names. Case insensitive.")
targetFolder = flag.String("f", ".", "Protobuf output file path.")
pkgFlags arrFlags
)

func main() {
flag.Var(&pkgFlags, "p", "Go source packages.")
flag.Var(&pkgFlags, "p", `Fully qualified path of packages to analyse. Relative paths ("./example/in") are allowed.`)
flag.Parse()

if len(pkgFlags) == 0 || protoFolder == nil {
flag.PrintDefaults()
os.Exit(1)
pwd, err := os.Getwd()
if err != nil {
log.Fatalf("error getting working directory: %s", err)
}

if err := checkOutFolder(*protoFolder); err != nil {
log.Fatal(err)
if len(pkgFlags) == 0 {
flag.PrintDefaults()
os.Exit(1)
}

pwd, err := os.Getwd()
//ensure the path exists
_, err = os.Stat(*targetFolder)
if err != nil {
log.Fatal(err)
log.Fatalf("error getting output file: %s", err)
}

pkgs, err := loadPackages(pwd, pkgFlags)
if err != nil {
log.Fatal(err)
log.Fatalf("error fetching packages: %s", err)
}

msgs := getMessages(pkgs, *filter)
msgs := getMessages(pkgs, strings.ToLower(*filter))

if err := writeOutput(msgs, *protoFolder); err != nil {
log.Fatal(err)
if err = writeOutput(msgs, *targetFolder); err != nil {
log.Fatalf("error writing output: %s", err)
}
}

func checkOutFolder(path string) error {
_, err := os.Stat(path)
return err
log.Printf("output file written to %s%s%s\n", pwd, string(os.PathSeparator), outputFileName)
}

// attempt to load all packages
func loadPackages(pwd string, pkgs []string) ([]*packages.Package, error) {
fset := token.NewFileSet()
cfg := &packages.Config{
Dir: pwd,
Mode: packages.LoadSyntax,
Fset: fset,
}
return packages.Load(cfg, pkgs...)
packages, err := packages.Load(cfg, pkgs...)
if err != nil {
return nil, err
}
var errs = ""
//check each loaded package for errors during loading
for _, p := range packages {
if len(p.Errors) > 0 {
errs += fmt.Sprintf("error fetching package %s: ", p.String())
for _, e := range p.Errors {
errs += e.Error()
}
errs += "; "
}
}
if errs != "" {
return nil, errors.New(errs)
}
return packages, nil
}

type message struct {
Expand Down Expand Up @@ -106,7 +128,7 @@ func getMessages(pkgs []*packages.Package, filter string) []*message {
}
if s, ok := t.Type().Underlying().(*types.Struct); ok {
seen[t.Name()] = struct{}{}
if filter == "" || strings.Contains(t.Name(), filter) {
if filter == "" || strings.Contains(strings.ToLower(t.Name()), filter) {
out = appendMessage(out, t, s)
}
}
Expand Down Expand Up @@ -214,9 +236,9 @@ message {{.Name}} {
panic(err)
}

f, err := os.Create(filepath.Join(path, "output.proto"))
f, err := os.Create(filepath.Join(path, outputFileName))
if err != nil {
return err
return fmt.Errorf("unable to create file %s : %s", outputFileName, err)
}
defer f.Close()

Expand Down

0 comments on commit b6295fa

Please sign in to comment.