kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/go/util/schema/mkdata/mkdata.go (about) 1 /* 2 * Copyright 2018 The Kythe Authors. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 // Program mkdata parses the kythe.proto.schema.Metadata from the Kythe 18 // schema.proto file descriptor into a Go/Java source file that can be compiled 19 // into the schema util package. 20 package main 21 22 import ( 23 "bytes" 24 "compress/gzip" 25 "flag" 26 "fmt" 27 "go/format" 28 "io/ioutil" 29 "reflect" 30 "sort" 31 "strings" 32 33 "kythe.io/kythe/go/util/log" 34 35 "bitbucket.org/creachadair/stringset" 36 "github.com/golang/protobuf/proto" 37 38 dpb "github.com/golang/protobuf/protoc-gen-go/descriptor" 39 scpb "kythe.io/kythe/proto/schema_go_proto" 40 ) 41 42 var ( 43 language = flag.String("language", "", "Generated target language (supported: go java)") 44 outputPath = flag.String("output", "", "Path of output source file") 45 packageName = flag.String("package", "", "Package name to generate") 46 ) 47 48 // A SchemaIndex is a glossary of Kythe enum values and their labels. 49 type SchemaIndex struct { 50 Languages map[string]scpb.Language 51 NodeKinds map[string]scpb.NodeKind 52 Subkinds map[string]scpb.Subkind 53 EdgeKinds map[string]scpb.EdgeKind 54 FactNames map[string]scpb.FactName 55 } 56 57 func main() { 58 flag.Parse() 59 switch { 60 case *outputPath == "": 61 log.Fatal("You must provide a source -output path") 62 case *packageName == "": 63 log.Fatal("You must provide a source -package name") 64 } 65 66 protoFile := scpb.E_Metadata.Filename 67 rd, err := gzip.NewReader(bytes.NewReader(proto.FileDescriptor(protoFile))) 68 if err != nil { 69 log.Fatalf("Failed to read schema.proto file descriptor: %v", err) 70 } 71 rec, err := ioutil.ReadAll(rd) 72 if err != nil { 73 log.Fatalf("Failed to decompress schema.proto file descriptor: %v", err) 74 } 75 var fd dpb.FileDescriptorProto 76 if err := proto.Unmarshal(rec, &fd); err != nil { 77 log.Fatalf("Failed to unmarshal schema.proto file descriptor: %v", err) 78 } 79 80 index := &SchemaIndex{ 81 Languages: make(map[string]scpb.Language), 82 NodeKinds: make(map[string]scpb.NodeKind), 83 Subkinds: make(map[string]scpb.Subkind), 84 EdgeKinds: make(map[string]scpb.EdgeKind), 85 FactNames: make(map[string]scpb.FactName), 86 } 87 for _, enum := range fd.EnumType { 88 for _, val := range enum.Value { 89 ext, err := proto.GetExtension(val.Options, scpb.E_Metadata) 90 if err == nil { 91 md := ext.(*scpb.Metadata) 92 switch enum.GetName() { 93 case "Language": 94 index.Languages[md.Label] = scpb.Language(val.GetNumber()) 95 case "EdgeKind": 96 index.EdgeKinds[md.Label] = scpb.EdgeKind(val.GetNumber()) 97 case "NodeKind": 98 index.NodeKinds[md.Label] = scpb.NodeKind(val.GetNumber()) 99 case "FactName": 100 index.FactNames[md.Label] = scpb.FactName(val.GetNumber()) 101 case "Subkind": 102 index.Subkinds[md.Label] = scpb.Subkind(val.GetNumber()) 103 default: 104 log.Errorf("unknown Kythe enum %s with Metadata: %+v", enum.GetName(), md) 105 } 106 } 107 } 108 } 109 110 switch *language { 111 case "go": 112 generateGo(protoFile, index) 113 case "java": 114 generateJava(protoFile, index) 115 default: 116 log.Fatalf("You must provide a supported generated language (go or java): found %q", *language) 117 } 118 } 119 120 const copyrightHeader = `/* 121 * Copyright 2018 The Kythe Authors. All rights reserved. 122 * 123 * Licensed under the Apache License, Version 2.0 (the "License"); 124 * you may not use this file except in compliance with the License. 125 * You may obtain a copy of the License at 126 * 127 * http://www.apache.org/licenses/LICENSE-2.0 128 * 129 * Unless required by applicable law or agreed to in writing, software 130 * distributed under the License is distributed on an "AS IS" BASIS, 131 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132 * See the License for the specific language governing permissions and 133 * limitations under the License. 134 */` 135 136 func generateGo(protoFile string, index *SchemaIndex) { 137 src := new(strings.Builder) 138 fmt.Fprintln(src, copyrightHeader) 139 fmt.Fprintf(src, "\n\npackage %s\n", *packageName) 140 fmt.Fprintf(src, ` 141 // This is a generated file -- do not edit it by hand. 142 // Input file: %s 143 144 `, protoFile) 145 146 fmt.Fprintln(src, `import scpb "kythe.io/kythe/proto/schema_go_proto"`) 147 fmt.Fprintln(src, `var (`) 148 149 fmt.Fprintln(src, "langs = map[string]scpb.Language{") 150 langsRev := make(map[scpb.Language]string) 151 for _, name := range stringset.FromKeys(index.Languages).Elements() { 152 enum := index.Languages[name] 153 fmt.Fprintf(src, "%q: %d,\n", name, enum) 154 langsRev[enum] = name 155 } 156 fmt.Fprintln(src, "}") 157 158 fmt.Fprintln(src, "nodeKinds = map[string]scpb.NodeKind{") 159 nodeKindsRev := make(map[scpb.NodeKind]string) 160 for _, name := range stringset.FromKeys(index.NodeKinds).Elements() { 161 enum := index.NodeKinds[name] 162 fmt.Fprintf(src, "%q: %d,\n", name, enum) 163 nodeKindsRev[enum] = name 164 } 165 fmt.Fprintln(src, "}") 166 167 fmt.Fprintln(src, "\nsubkinds = map[string]scpb.Subkind{") 168 subkindsRev := make(map[scpb.Subkind]string) 169 for _, name := range stringset.FromKeys(index.Subkinds).Elements() { 170 enum := index.Subkinds[name] 171 fmt.Fprintf(src, "%q: %d,\n", name, enum) 172 subkindsRev[enum] = name 173 } 174 fmt.Fprintln(src, "}") 175 176 fmt.Fprintln(src, "\nfactNames = map[string]scpb.FactName{") 177 factNamesRev := make(map[scpb.FactName]string) 178 for _, name := range stringset.FromKeys(index.FactNames).Elements() { 179 enum := index.FactNames[name] 180 fmt.Fprintf(src, "%q: %d,\n", name, enum) 181 factNamesRev[enum] = name 182 } 183 fmt.Fprintln(src, "}") 184 185 fmt.Fprintln(src, "\nedgeKinds = map[string]scpb.EdgeKind{") 186 edgeKindsRev := make(map[scpb.EdgeKind]string) 187 for _, name := range stringset.FromKeys(index.EdgeKinds).Elements() { 188 enum := index.EdgeKinds[name] 189 fmt.Fprintf(src, "%q: %d,\n", name, enum) 190 edgeKindsRev[enum] = name 191 } 192 fmt.Fprintln(src, "}") 193 194 fmt.Fprintln(src, "\nlangsRev = map[scpb.Language]string{") 195 for _, kind := range sortedKeys(langsRev) { 196 enum := kind.(scpb.Language) 197 name := langsRev[enum] 198 fmt.Fprintf(src, "%d: %q,\n", enum, name) 199 } 200 fmt.Fprintln(src, "}") 201 202 fmt.Fprintln(src, "\nnodeKindsRev = map[scpb.NodeKind]string{") 203 for _, kind := range sortedKeys(nodeKindsRev) { 204 enum := kind.(scpb.NodeKind) 205 name := nodeKindsRev[enum] 206 fmt.Fprintf(src, "%d: %q,\n", enum, name) 207 } 208 fmt.Fprintln(src, "}") 209 210 fmt.Fprintln(src, "\nsubkindsRev = map[scpb.Subkind]string{") 211 for _, kind := range sortedKeys(subkindsRev) { 212 enum := kind.(scpb.Subkind) 213 name := subkindsRev[enum] 214 fmt.Fprintf(src, "%d: %q,\n", enum, name) 215 } 216 fmt.Fprintln(src, "}") 217 218 fmt.Fprintln(src, "\nfactNamesRev = map[scpb.FactName]string{") 219 for _, kind := range sortedKeys(factNamesRev) { 220 enum := kind.(scpb.FactName) 221 name := factNamesRev[enum] 222 fmt.Fprintf(src, "%d: %q,\n", enum, name) 223 } 224 fmt.Fprintln(src, "}") 225 226 fmt.Fprintln(src, "\nedgeKindsRev = map[scpb.EdgeKind]string{") 227 for _, kind := range sortedKeys(edgeKindsRev) { 228 enum := kind.(scpb.EdgeKind) 229 name := edgeKindsRev[enum] 230 fmt.Fprintf(src, "%d: %q,\n", enum, name) 231 } 232 fmt.Fprintln(src, "}") 233 fmt.Fprintln(src, ")") 234 235 fmt.Fprint(src, ` 236 // Language returns the schema enum for the given language. 237 func Language(k string) scpb.Language { return langs[k] } 238 239 // NodeKind returns the schema enum for the given node kind. 240 func NodeKind(k string) scpb.NodeKind { return nodeKinds[k] } 241 242 // EdgeKind returns the schema enum for the given edge kind. 243 func EdgeKind(k string) scpb.EdgeKind { return edgeKinds[k] } 244 245 // FactName returns the schema enum for the given fact name. 246 func FactName(f string) scpb.FactName { return factNames[f] } 247 248 // Subkind returns the schema enum for the given subkind. 249 func Subkind(k string) scpb.Subkind { return subkinds[k] } 250 251 // LanguageString returns the string representation of the given language. 252 func LanguageString(k scpb.Language) string { return langsRev[k] } 253 254 // NodeKindString returns the string representation of the given node kind. 255 func NodeKindString(k scpb.NodeKind) string { return nodeKindsRev[k] } 256 257 // EdgeKindString returns the string representation of the given edge kind. 258 func EdgeKindString(k scpb.EdgeKind) string { return edgeKindsRev[k] } 259 260 // FactNameString returns the string representation of the given fact name. 261 func FactNameString(f scpb.FactName) string { return factNamesRev[f] } 262 263 // SubkindString returns the string representation of the given subkind. 264 func SubkindString(k scpb.Subkind) string { return subkindsRev[k] } 265 266 `) 267 268 // Format and write out the resulting program. 269 text, err := format.Source([]byte(src.String())) 270 if err != nil { 271 log.Fatalf("Formatting Go source: %v", err) 272 } 273 if err := ioutil.WriteFile(*outputPath, text, 0644); err != nil { 274 log.Fatalf("Writing Go output: %v", err) 275 } 276 } 277 278 var u32 = reflect.TypeOf(uint32(0)) 279 280 // sortedKeys returns a slice of the keys of v having type map[X]V, where X is 281 // a type convertible to uint32 (e.g., a proto enumeration). This function 282 // will panic if v does not have an appropriate concrete type. The concrete 283 // type of each returned element remains X (not uint32). 284 func sortedKeys(v any) []any { 285 keys := reflect.ValueOf(v).MapKeys() 286 sort.Slice(keys, func(i, j int) bool { 287 a := keys[i].Convert(u32).Interface().(uint32) 288 b := keys[j].Convert(u32).Interface().(uint32) 289 return a < b 290 }) 291 vals := make([]any, len(keys)) 292 for i, key := range keys { 293 vals[i] = key.Interface() 294 } 295 return vals 296 } 297 298 func generateJava(protoFile string, index *SchemaIndex) { 299 src := new(strings.Builder) 300 fmt.Fprintln(src, copyrightHeader) 301 fmt.Fprintln(src, "\n// This is a generated file -- do not edit it by hand.") 302 fmt.Fprintf(src, "// Input file: %s\n\n", protoFile) 303 fmt.Fprintf(src, "package %s;\n", *packageName) 304 305 fmt.Fprintln(src, "import com.google.common.collect.ImmutableBiMap;") 306 fmt.Fprintln(src, "import com.google.devtools.kythe.proto.Schema.Edge;") 307 fmt.Fprintln(src, "import com.google.devtools.kythe.proto.Schema.EdgeKind;") 308 fmt.Fprintln(src, "import com.google.devtools.kythe.proto.Schema.Fact;") 309 fmt.Fprintln(src, "import com.google.devtools.kythe.proto.Schema.FactName;") 310 fmt.Fprintln(src, "import com.google.devtools.kythe.proto.Schema.Language;") 311 fmt.Fprintln(src, "import com.google.devtools.kythe.proto.Schema.NodeKind;") 312 fmt.Fprintln(src, "import com.google.devtools.kythe.proto.Schema.Subkind;") 313 fmt.Fprintln(src, "import com.google.protobuf.ByteString;") 314 315 fmt.Fprintln(src, "/** Utility for handling schema strings and their corresponding protocol buffer enums. */") 316 fmt.Fprintln(src, "public final class Schema {") 317 fmt.Fprintln(src, "private Schema() {}") 318 319 fmt.Fprintln(src, "private static final ImmutableBiMap<String, Language> LANGUAGES = ImmutableBiMap.<String, Language>builder()") 320 for _, name := range stringset.FromKeys(index.Languages).Elements() { 321 enum := index.Languages[name] 322 fmt.Fprintf(src, ".put(%q, Language.%s)\n", name, enum) 323 } 324 fmt.Fprintln(src, ".build();") 325 326 fmt.Fprintln(src, "private static final ImmutableBiMap<String, NodeKind> NODE_KINDS = ImmutableBiMap.<String, NodeKind>builder()") 327 for _, name := range stringset.FromKeys(index.NodeKinds).Elements() { 328 enum := index.NodeKinds[name] 329 fmt.Fprintf(src, ".put(%q, NodeKind.%s)\n", name, enum) 330 } 331 fmt.Fprintln(src, ".build();") 332 333 fmt.Fprintln(src, "private static final ImmutableBiMap<String, Subkind> SUBKINDS = ImmutableBiMap.<String, Subkind>builder()") 334 for _, name := range stringset.FromKeys(index.Subkinds).Elements() { 335 enum := index.Subkinds[name] 336 fmt.Fprintf(src, ".put(%q, Subkind.%s)\n", name, enum) 337 } 338 fmt.Fprintln(src, ".build();") 339 340 fmt.Fprintln(src, "private static final ImmutableBiMap<String, EdgeKind> EDGE_KINDS = ImmutableBiMap.<String, EdgeKind>builder()") 341 for _, name := range stringset.FromKeys(index.EdgeKinds).Elements() { 342 enum := index.EdgeKinds[name] 343 fmt.Fprintf(src, ".put(%q, EdgeKind.%s)\n", name, enum) 344 } 345 fmt.Fprintln(src, ".build();") 346 347 fmt.Fprintln(src, "private static final ImmutableBiMap<String, FactName> FACT_NAMES = ImmutableBiMap.<String, FactName>builder()") 348 for _, name := range stringset.FromKeys(index.FactNames).Elements() { 349 enum := index.FactNames[name] 350 fmt.Fprintf(src, ".put(%q, FactName.%s)\n", name, enum) 351 } 352 fmt.Fprintln(src, ".build();") 353 354 fmt.Fprintln(src, "/** Returns the schema {@link Language} for the given language. */") 355 fmt.Fprintln(src, "public static Language language(String k) { return LANGUAGES.getOrDefault(k, Language.UNKNOWN_LANGUAGE); }") 356 357 fmt.Fprintln(src, "/** Returns the schema {@link NodeKind} for the given kind. */") 358 fmt.Fprintln(src, "public static NodeKind nodeKind(String k) { return NODE_KINDS.getOrDefault(k, NodeKind.UNKNOWN_NODE_KIND); }") 359 360 fmt.Fprintln(src, "/** Returns the schema {@link NodeKind} for the given kind. */") 361 fmt.Fprintln(src, "public static NodeKind nodeKind(ByteString k) { return nodeKind(k.toStringUtf8()); }") 362 363 fmt.Fprintln(src, "/** Returns the schema {@link Subkind} for the given kind. */") 364 fmt.Fprintln(src, "public static Subkind subkind(String k) { return SUBKINDS.getOrDefault(k, Subkind.UNKNOWN_SUBKIND); }") 365 366 fmt.Fprintln(src, "/** Returns the schema {@link Subkind} for the given kind. */") 367 fmt.Fprintln(src, "public static Subkind subkind(ByteString k) { return subkind(k.toStringUtf8()); }") 368 369 fmt.Fprintln(src, "/** Returns the schema {@link EdgeKind} for the given kind. */") 370 fmt.Fprintln(src, "public static EdgeKind edgeKind(String k) { return EDGE_KINDS.getOrDefault(k, EdgeKind.UNKNOWN_EDGE_KIND); }") 371 372 fmt.Fprintln(src, "/** Returns the schema {@link FactName} for the given name. */") 373 fmt.Fprintln(src, "public static FactName factName(String n) { return FACT_NAMES.getOrDefault(n, FactName.UNKNOWN_FACT_NAME); }") 374 375 fmt.Fprintln(src, "/** Returns the string representation of the given {@link Language}. */") 376 fmt.Fprintln(src, "public static String languageString(Language l) { return LANGUAGES.inverse().getOrDefault(l, \"\"); }") 377 378 fmt.Fprintln(src, "/** Returns the string representation of the given {@link NodeKind}. */") 379 fmt.Fprintln(src, "public static String nodeKindString(NodeKind k) { return NODE_KINDS.inverse().getOrDefault(k, \"\"); }") 380 381 fmt.Fprintln(src, "/** Returns the string representation of the given {@link Subkind}. */") 382 fmt.Fprintln(src, "public static String subkindString(Subkind k) { return SUBKINDS.inverse().getOrDefault(k, \"\"); }") 383 384 fmt.Fprintln(src, "/** Returns the string representation of the given {@link EdgeKind}. */") 385 fmt.Fprintln(src, "public static String edgeKindString(EdgeKind k) { return EDGE_KINDS.inverse().getOrDefault(k, \"\"); }") 386 387 fmt.Fprintln(src, "/** Returns the string representation of the given {@link Edge}'s kind. */") 388 fmt.Fprintln(src, "public static String edgeKindString(Edge e) { return e.getKytheKind().equals(EdgeKind.UNKNOWN_EDGE_KIND) ? e.getGenericKind() : edgeKindString(e.getKytheKind()); }") 389 390 fmt.Fprintln(src, "/** Returns the string representation of the given {@link FactName}. */") 391 fmt.Fprintln(src, "public static String factNameString(FactName n) { return FACT_NAMES.inverse().getOrDefault(n, \"\"); }") 392 393 fmt.Fprintln(src, "/** Returns the string representation of the given {@link Fact}'s name. */") 394 fmt.Fprintln(src, "public static String factNameString(Fact f) { return f.getKytheName().equals(FactName.UNKNOWN_FACT_NAME) ? f.getGenericName() : factNameString(f.getKytheName()); }") 395 396 fmt.Fprintln(src, "}") 397 398 if err := ioutil.WriteFile(*outputPath, []byte(src.String()), 0644); err != nil { 399 log.Fatalf("Writing Java output: %v", err) 400 } 401 }