forked from droyo/go-xml
/
cli.go
129 lines (120 loc) · 3.57 KB
/
cli.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package xsdgen
import (
"errors"
"flag"
"fmt"
"go/ast"
"io/ioutil"
"strings"
"aqwari.net/xml/internal/commandline"
"aqwari.net/xml/internal/gen"
"aqwari.net/xml/xsd"
)
// GenCode reads all xml schema definitions from the provided
// data. If succesful, the returned *Code value can be used to
// lookup identifiers and generate Go code.
func (cfg *Config) GenCode(data ...[]byte) (*Code, error) {
if len(cfg.namespaces) == 0 {
cfg.Option(Namespaces(lookupTargetNS(data...)...))
cfg.debugf("setting namespaces to %q", cfg.namespaces)
}
deps, err := xsd.Parse(data...)
if err != nil {
return nil, err
}
primaries := make([]xsd.Schema, 0, len(cfg.namespaces))
for _, s := range deps {
for _, ns := range cfg.namespaces {
if s.TargetNS == ns {
primaries = append(primaries, s)
break
}
}
}
if len(primaries) < len(cfg.namespaces) {
missing := make([]string, 0, len(cfg.namespaces)-len(primaries))
have := make(map[string]bool)
for _, schema := range primaries {
have[schema.TargetNS] = true
}
for _, ns := range cfg.namespaces {
if !have[ns] {
missing = append(missing, ns)
}
}
return nil, fmt.Errorf("could not find schema for %q", strings.Join(missing, ", "))
}
cfg.addStandardHelpers()
return cfg.gen(primaries, deps)
}
// GenAST creates an *ast.File containing type declarations and
// associated methods based on a set of XML schema.
func (cfg *Config) GenAST(files ...string) (*ast.File, error) {
data := make([][]byte, 0, len(files))
for _, filename := range files {
b, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
cfg.debugf("read %s", filename)
data = append(data, b)
}
code, err := cfg.GenCode(data...)
if err != nil {
return nil, err
}
return code.GenAST()
}
// The GenSource method converts the AST returned by GenAST to formatted
// Go source code.
func (cfg *Config) GenSource(files ...string) ([]byte, error) {
file, err := cfg.GenAST(files...)
if err != nil {
return nil, err
}
return gen.FormattedSource(file, "fixme.go")
}
// GenCLI creates a file containing Go source generated from an XML
// Schema. Main is meant to be called as part of a command, and can
// be used to change the behavior of the xsdgen command in ways that
// its command-line arguments do not allow. The arguments are the
// same as those passed to the xsdgen command.
func (cfg *Config) GenCLI(arguments ...string) error {
var (
err error
replaceRules commandline.ReplaceRuleList
xmlns commandline.Strings
fs = flag.NewFlagSet("xsdgen", flag.ExitOnError)
packageName = fs.String("pkg", "", "name of the the generated package")
output = fs.String("o", "xsdgen_output.go", "name of the output file")
verbose = fs.Bool("v", false, "print verbose output")
debug = fs.Bool("vv", false, "print debug output")
)
fs.Var(&replaceRules, "r", "replacement rule 'regex -> repl' (can be used multiple times)")
fs.Var(&xmlns, "ns", "target namespace(s) to generate types for")
fs.Parse(arguments)
if fs.NArg() == 0 {
return errors.New("Usage: xsdgen [-ns xmlns] [-r rule] [-o file] [-pkg pkg] file ...")
}
if *debug {
cfg.Option(LogLevel(5))
} else if *verbose {
cfg.Option(LogLevel(1))
}
cfg.Option(Namespaces(xmlns...))
for _, r := range replaceRules {
cfg.Option(replaceAllNamesRegex(r.From, r.To))
}
if *packageName != "" {
cfg.Option(PackageName(*packageName))
}
file, err := cfg.GenAST(fs.Args()...)
if err != nil {
return err
}
data, err := gen.FormattedSource(file, *output)
if err != nil {
return err
}
return ioutil.WriteFile(*output, data, 0666)
}