internal/build: index unique string slices
Randy Reddig
3 years ago
1 | 1 | |
2 | 2 | import ( |
3 | 3 | "bytes" |
4 | "fmt" | |
4 | 5 | "go/format" |
5 | 6 | "os" |
6 | 7 | "path/filepath" |
45 | 46 | z.TagBits = tagBits(tagValues, z.Tags) |
46 | 47 | } |
47 | 48 | |
48 | data := struct { | |
49 | Zones map[string]*Zone | |
50 | TLDs map[string]*Zone | |
51 | Domains []string | |
52 | Offsets map[string]int | |
53 | TagType string | |
54 | Tags []string | |
55 | TagValues map[string]uint64 | |
56 | }{ | |
57 | zones, | |
58 | tlds, | |
59 | domains, | |
60 | offsets, | |
61 | tagType, | |
62 | tags, | |
63 | tagValues, | |
49 | data := templateData{ | |
50 | Zones: zones, | |
51 | TLDs: tlds, | |
52 | Domains: domains, | |
53 | Offsets: offsets, | |
54 | TagType: tagType, | |
55 | Tags: tags, | |
56 | TagValues: tagValues, | |
57 | Strings: []string{}, | |
58 | } | |
59 | ||
60 | // Pre-index strings and string slices | |
61 | for _, d := range domains { | |
62 | data.domainString(d) | |
63 | } | |
64 | for _, d := range domains { | |
65 | data.domainStringSlice(zones[d].NameServers) | |
66 | } | |
67 | for _, d := range domains { | |
68 | data.domainStringSlice(zones[d].Wildcards) | |
69 | } | |
70 | for _, d := range domains { | |
71 | data.domainString(zones[d].WhoisServer) | |
72 | } | |
73 | for _, d := range domains { | |
74 | data.urlString(zones[d].WhoisURL) | |
75 | } | |
76 | for _, d := range domains { | |
77 | data.urlString(zones[d].InfoURL) | |
78 | } | |
79 | for _, d := range domains { | |
80 | data.indexedStringSlice(zones[d].Locations) | |
81 | } | |
82 | for _, d := range domains { | |
83 | data.indexedStringSlice(zones[d].Languages) | |
64 | 84 | } |
65 | 85 | |
66 | 86 | err := generate("zones.go", zonesGoSrc, &data) |
71 | 91 | return nil |
72 | 92 | } |
73 | 93 | |
74 | // Helper funcs | |
75 | ||
76 | func cont(s string) string { | |
77 | return strings.ReplaceAll(s, "\\\n", "") | |
94 | type templateData struct { | |
95 | Zones map[string]*Zone | |
96 | TLDs map[string]*Zone | |
97 | Domains []string | |
98 | Offsets map[string]int | |
99 | TagType string | |
100 | Tags []string | |
101 | TagValues map[string]uint64 | |
102 | Strings []string | |
103 | } | |
104 | ||
105 | func (data *templateData) indexedString(s string) string { | |
106 | i, _ := IndexOrAppendStrings(&data.Strings, []string{s}) | |
107 | return fmt.Sprintf("s[%d]", i) | |
108 | } | |
109 | ||
110 | func (data *templateData) indexedStringSlice(slice []string) string { | |
111 | i, j := IndexOrAppendStrings(&data.Strings, slice) | |
112 | return fmt.Sprintf("s[%d:%d]", i, j) | |
113 | } | |
114 | ||
115 | func (data *templateData) domainString(s string) string { | |
116 | s = ToASCII(s) | |
117 | i, _ := IndexOrAppendStrings(&data.Strings, []string{s}) | |
118 | return fmt.Sprintf("s[%d]", i) | |
119 | } | |
120 | ||
121 | func (data *templateData) domainStringSlice(slice []string) string { | |
122 | needle := make([]string, len(slice)) | |
123 | for i := range slice { | |
124 | needle[i] = ToASCII(slice[i]) | |
125 | } | |
126 | i, j := IndexOrAppendStrings(&data.Strings, needle) | |
127 | return fmt.Sprintf("s[%d:%d]", i, j) | |
128 | } | |
129 | ||
130 | func (data *templateData) urlString(s string) string { | |
131 | s = ToASCIIURL(s) | |
132 | i, _ := IndexOrAppendStrings(&data.Strings, []string{s}) | |
133 | return fmt.Sprintf("s[%d]", i) | |
134 | } | |
135 | ||
136 | func (data *templateData) urlStringSlice(slice []string) string { | |
137 | needle := make([]string, len(slice)) | |
138 | for i := range slice { | |
139 | needle[i] = ToASCIIURL(slice[i]) | |
140 | } | |
141 | i, j := IndexOrAppendStrings(&data.Strings, needle) | |
142 | return fmt.Sprintf("s[%d:%d]", i, j) | |
78 | 143 | } |
79 | 144 | |
80 | 145 | func quoted(s string) string { |
92 | 157 | return quoted(ToASCIIURL(s)) |
93 | 158 | } |
94 | 159 | |
95 | var ( | |
96 | funcMap = template.FuncMap{ | |
160 | func generate(filename, src string, data *templateData) error { | |
161 | funcMap := template.FuncMap{ | |
97 | 162 | "title": strings.Title, |
98 | 163 | "quoted": quoted, |
99 | 164 | "quotedDomain": quotedDomain, |
100 | 165 | "quotedURL": quotedURL, |
101 | } | |
102 | ) | |
103 | ||
104 | func generate(fn, src string, data interface{}) error { | |
166 | "string": data.indexedString, | |
167 | "stringSlice": data.indexedStringSlice, | |
168 | "domain": data.domainString, | |
169 | "domainSlice": data.domainStringSlice, | |
170 | "url": data.urlString, | |
171 | "urlSlice": data.urlStringSlice, | |
172 | } | |
173 | ||
105 | 174 | t := template.Must(template.New("").Funcs(funcMap).Parse(cont(src))) |
106 | 175 | buf := new(bytes.Buffer) |
107 | 176 | err := t.Execute(buf, data) |
112 | 181 | if err != nil { |
113 | 182 | return err |
114 | 183 | } |
115 | fn = filepath.Join(BaseDir, fn) | |
116 | color.Fprintf(os.Stderr, "@{.}Generating Go source code: %s\n", fn) | |
117 | f, err := os.Create(fn) | |
184 | filename = filepath.Join(BaseDir, filename) | |
185 | color.Fprintf(os.Stderr, "@{.}Generating Go source code: %s\n", filename) | |
186 | f, err := os.Create(filename) | |
118 | 187 | if err != nil { |
119 | 188 | return err |
120 | 189 | } |
121 | 190 | defer f.Close() |
122 | 191 | _, err = f.Write(formatted) |
123 | 192 | return err |
193 | } | |
194 | ||
195 | func cont(s string) string { | |
196 | return strings.ReplaceAll(s, "\\\n", "") | |
124 | 197 | } |
125 | 198 | |
126 | 199 | const zonesGoSrc = `// Automatically generated |