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  }