From 6bafd75d518353690a3bf9140891194d794c13cb Mon Sep 17 00:00:00 2001 From: Michael Merg Date: Mon, 12 Feb 2024 13:52:00 +0000 Subject: [PATCH] Create IDE query script This will be the integration point to provide build artifacts to Cider G. NOTE FOR REVIEWERS - original patch and result patch are not identical. PLEASE REVIEW CAREFULLY. Diffs between the patches: files := flag.Args() > - > - if prev, ok := modules[f]; ok && !strings.HasSuffix(prev.Name, ".impl") { > - log.Printf("File %q found in module %q but is already part of module %q", f, m.Name, prev.Name) > + if modules[f] != nil { > + log.Printf("File %q found in module %q but is already covered by module %q", f, m.Name, modules[f].Name) > - var genFiles []*pb.GeneratedFile > + var generated []*pb.GeneratedFile > - // Note: Contents will be filled below. > - genFiles = append(genFiles, &pb.GeneratedFile{Path: relPath}) > + contents, err := os.ReadFile(d) > + if err != nil { > + fmt.Printf("Generated file %q not found - will be skipped.\n", d) > + continue > + } > + > + generated = append(generated, &pb.GeneratedFile{ > + Path: relPath, > + Contents: contents, > + }) > - file.Generated = genFiles > + file.Generated = generated > - for _, s := range sources { > - for _, g := range s.GetGenerated() { > - contents, err := os.ReadFile(path.Join(env.OutDir, g.GetPath())) > - if err != nil { > - fmt.Printf("Failed to read generated file %q: %v. File contents will be missing.\n", g.GetPath(), err) > - continue > - } > - g.Contents = contents > - } > - } > - > - if strings.HasSuffix(name, "-jarjar") { > + if strings.HasSuffix(name, "-jarjar") || strings.HasSuffix(name, ".impl") { Original patch: diff --git a/tools/ide_query/ide_query.go b/tools/ide_query/ide_query.go old mode 100644 new mode 100644 --- a/tools/ide_query/ide_query.go +++ b/tools/ide_query/ide_query.go @@ -1,3 +1,5 @@ +// Binary ide_query generates and analyzes build artifacts. +// The produced result can be consumed by IDEs to provide language features. package main import ( @@ -34,10 +36,10 @@ var _ flag.Value = (*LunchTarget)(nil) -// Get implements flag.Value. -func (l *LunchTarget) Get() any { - return l -} +// // Get implements flag.Value. +// func (l *LunchTarget) Get() any { +// return l +// } // Set implements flag.Value. func (l *LunchTarget) Set(s string) error { @@ -64,13 +66,12 @@ env.RepoDir = os.Getenv("TOP") flag.Var(&env.LunchTarget, "lunch_target", "The lunch target to query") flag.Parse() - if flag.NArg() == 0 { + files := flag.Args() + if len(files) == 0 { fmt.Println("No files provided.") os.Exit(1) return } - - files := flag.Args() ctx := context.Background() javaDepsPath := pa [[[Original patch trimmed due to size. Decoded string size: 2916. Decoded string SHA1: 5d8fd4a92cc403da51c9ddb8442da2e391e6fcb1.]]] Result patch: diff --git a/tools/ide_query/ide_query.go b/tools/ide_query/ide_query.go index 2e76738..0fdb6de 100644 --- a/tools/ide_query/ide_query.go +++ b/tools/ide_query/ide_query.go @@ -1,3 +1,5 @@ +// Binary ide_query generates and analyzes build artifacts. +// The produced result can be consumed by IDEs to provide language features. package main import ( @@ -34,10 +36,10 @@ var _ flag.Value = (*LunchTarget)(nil) -// Get implements flag.Value. -func (l *LunchTarget) Get() any { - return l -} +// // Get implements flag.Value. +// func (l *LunchTarget) Get() any { +// return l +// } // Set implements flag.Value. func (l *LunchTarget) Set(s string) error { @@ -64,14 +66,13 @@ env.RepoDir = os.Getenv("TOP") flag.Var(&env.LunchTarget, "lunch_target", "The lunch target to query") flag.Parse() - if flag.NArg() == 0 { + files := flag.Args() + if len(files) == 0 { fmt.Println("No files provided.") os.Exit(1) return } - files := flag.Args() - ctx := context.Background() javaDepsPath := path [[[Result patch trimmed due to size. Decoded string size: 3022. Decoded string SHA1: a8824749eafbbb8d09c4e95fe491a16e3ea82569.]]] NOTE FOR REVIEWERS - original patch and result patch are not identical. PLEASE REVIEW CAREFULLY. Diffs between the patches: var javaFiles []string > + for _, f := range files { > + switch { > + case strings.HasSuffix(f, ".java") || strings.HasSuffix(f, ".kt"): > + javaFiles = append(javaFiles, f) > + default: > + log.Printf("File %q is supported - will be skipped.", f) > + } > + } > + > - modules := make(map[string]*javaModule) // file path -> module > - for _, f := range files { > + fileToModule := make(map[string]*javaModule) // file path -> module > + for _, f := range javaFiles { > - if modules[f] != nil { > - log.Printf("File %q found in module %q but is already covered by module %q", f, m.Name, modules[f].Name) > + if fileToModule[f] != nil { > + // TODO(michaelmerg): Handle the case where a file is covered by multiple modules. > + log.Printf("File %q found in module %q but is already covered by module %q", f, m.Name, fileToModule[f].Name) > - modules[f] = m > + fileToModule[f] = m > - for _, m := range modules { > + for _, m := range fileToModule { > + type depsAndGenerated struct { > + Deps []string > + Generated []*pb.GeneratedFile > + } > + moduleToDeps := make(map[string]*depsAndGenerated) > - m := modules[f] > + m := fileToModule[f] > + file.Status = &pb.Status{Code: pb.Status_OK} > + if moduleToDeps[m.Name] != nil { > + file.Generated = moduleToDeps[m.Name].Generated > + file.Deps = moduleToDeps[m.Name].Deps > + continue > + } > + > - > + moduleToDeps[m.Name] = &depsAndGenerated{deps, generated} > - file.Status = &pb.Status{Code: pb.Status_OK} Original patch: diff --git a/tools/ide_query/ide_query.go b/tools/ide_query/ide_query.go old mode 100644 new mode 100644 --- a/tools/ide_query/ide_query.go +++ b/tools/ide_query/ide_query.go @@ -72,6 +72,16 @@ os.Exit(1) return } + + var javaFiles []string + for _, f := range files { + switch { + case strings.HasSuffix(f, ".java") || strings.HasSuffix(f, ".kt"): + javaFiles = append(javaFiles, f) + default: + log.Printf("File %q is supported - will be skipped.", f) + } + } ctx := context.Background() javaDepsPath := path.Join(env.RepoDir, env.OutDir, "soong/module_bp_java_deps.json") @@ -85,22 +95,23 @@ log.Fatalf("Failed to load java modules: %v", err) } - modules := make(map[string]*javaModule) // file path -> module - for _, f := range files { + fileToModule := make(map[string]*javaModule) // file path -> module + for _, f := range javaFiles { for _, m := range javaModules { if !slices.Contains(m.Srcs, f) { continue } - if modules[f] != nil { - log.Printf("File %q found in [[[Original patch trimmed due to size. Decoded string size: 2629. Decoded string SHA1: 4517ba713fdb898ba9d77c4acbe934c08a2d9fe0.]]] Result patch: diff --git a/tools/ide_query/ide_query.go b/tools/ide_query/ide_query.go index 0fdb6de..7335875 100644 --- a/tools/ide_query/ide_query.go +++ b/tools/ide_query/ide_query.go @@ -73,6 +73,16 @@ return } + var javaFiles []string + for _, f := range files { + switch { + case strings.HasSuffix(f, ".java") || strings.HasSuffix(f, ".kt"): + javaFiles = append(javaFiles, f) + default: + log.Printf("File %q is supported - will be skipped.", f) + } + } + ctx := context.Background() javaDepsPath := path.Join(env.RepoDir, env.OutDir, "soong/module_bp_java_deps.json") // TODO(michaelmerg): Figure out if module_bp_java_deps.json is outdated. @@ -85,22 +95,23 @@ log.Fatalf("Failed to load java modules: %v", err) } - modules := make(map[string]*javaModule) // file path -> module - for _, f := range files { + fileToModule := make(map[string]*javaModule) // file path -> module + for _, f := range javaFiles { for _, m := range javaModules { if !slices.Contains(m.Srcs, f) { continue } [[[Result patch trimmed due to size. Decoded string size: 2717. Decoded string SHA1: 5e5223251ebdc548258bc27daf3528d662c39410.]]] Change-Id: Ibe5d386399affd2951206bb5a714972e0e2fee92 --- tools/ide_query/go.mod | 7 + tools/ide_query/go.work | 9 + tools/ide_query/go.work.sum | 5 + tools/ide_query/ide_query.go | 265 +++++++++ tools/ide_query/ide_query.sh | 12 + .../ide_query/ide_query_proto/ide_query.pb.go | 522 ++++++++++++++++++ .../ide_query/ide_query_proto/ide_query.proto | 66 +++ tools/ide_query/ide_query_proto/regen.sh | 3 + 8 files changed, 889 insertions(+) create mode 100644 tools/ide_query/go.mod create mode 100644 tools/ide_query/go.work create mode 100644 tools/ide_query/go.work.sum create mode 100644 tools/ide_query/ide_query.go create mode 100755 tools/ide_query/ide_query.sh create mode 100644 tools/ide_query/ide_query_proto/ide_query.pb.go create mode 100644 tools/ide_query/ide_query_proto/ide_query.proto create mode 100755 tools/ide_query/ide_query_proto/regen.sh diff --git a/tools/ide_query/go.mod b/tools/ide_query/go.mod new file mode 100644 index 0000000000..f9d727f3ab --- /dev/null +++ b/tools/ide_query/go.mod @@ -0,0 +1,7 @@ +module ide_query + +go 1.21 + +require ( + google.golang.org/protobuf v0.0.0 +) diff --git a/tools/ide_query/go.work b/tools/ide_query/go.work new file mode 100644 index 0000000000..851f352af6 --- /dev/null +++ b/tools/ide_query/go.work @@ -0,0 +1,9 @@ +go 1.21 + +use ( + . +) + +replace ( + google.golang.org/protobuf v0.0.0 => ../../../../external/golang-protobuf +) \ No newline at end of file diff --git a/tools/ide_query/go.work.sum b/tools/ide_query/go.work.sum new file mode 100644 index 0000000000..cf42b48eb0 --- /dev/null +++ b/tools/ide_query/go.work.sum @@ -0,0 +1,5 @@ +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1 h1:7QnIQpGRHE5RnLKnESfDoxm2dTapTZua5a0kS0A+VXQ= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= diff --git a/tools/ide_query/ide_query.go b/tools/ide_query/ide_query.go new file mode 100644 index 0000000000..c1c4da0ed5 --- /dev/null +++ b/tools/ide_query/ide_query.go @@ -0,0 +1,265 @@ +// Binary ide_query generates and analyzes build artifacts. +// The produced result can be consumed by IDEs to provide language features. +package main + +import ( + "container/list" + "context" + "encoding/json" + "flag" + "fmt" + "log" + "os" + "os/exec" + "path" + "slices" + "strings" + + "google.golang.org/protobuf/proto" + pb "ide_query/ide_query_proto" +) + +// Env contains information about the current environment. +type Env struct { + LunchTarget LunchTarget + RepoDir string + OutDir string +} + +// LunchTarget is a parsed Android lunch target. +// Input format: -- +type LunchTarget struct { + Product string + Release string + Variant string +} + +var _ flag.Value = (*LunchTarget)(nil) + +// // Get implements flag.Value. +// func (l *LunchTarget) Get() any { +// return l +// } + +// Set implements flag.Value. +func (l *LunchTarget) Set(s string) error { + parts := strings.Split(s, "-") + if len(parts) != 3 { + return fmt.Errorf("invalid lunch target: %q, must have form --", s) + } + *l = LunchTarget{ + Product: parts[0], + Release: parts[1], + Variant: parts[2], + } + return nil +} + +// String implements flag.Value. +func (l *LunchTarget) String() string { + return fmt.Sprintf("%s-%s-%s", l.Product, l.Release, l.Variant) +} + +func main() { + var env Env + env.OutDir = os.Getenv("OUT_DIR") + env.RepoDir = os.Getenv("ANDROID_BUILD_TOP") + flag.Var(&env.LunchTarget, "lunch_target", "The lunch target to query") + flag.Parse() + files := flag.Args() + if len(files) == 0 { + fmt.Println("No files provided.") + os.Exit(1) + return + } + + var javaFiles []string + for _, f := range files { + switch { + case strings.HasSuffix(f, ".java") || strings.HasSuffix(f, ".kt"): + javaFiles = append(javaFiles, f) + default: + log.Printf("File %q is supported - will be skipped.", f) + } + } + + ctx := context.Background() + javaDepsPath := path.Join(env.RepoDir, env.OutDir, "soong/module_bp_java_deps.json") + // TODO(michaelmerg): Figure out if module_bp_java_deps.json is outdated. + runMake(ctx, env, "nothing") + + javaModules, err := loadJavaModules(javaDepsPath) + if err != nil { + log.Fatalf("Failed to load java modules: %v", err) + } + + fileToModule := make(map[string]*javaModule) // file path -> module + for _, f := range javaFiles { + for _, m := range javaModules { + if !slices.Contains(m.Srcs, f) { + continue + } + if fileToModule[f] != nil { + // TODO(michaelmerg): Handle the case where a file is covered by multiple modules. + log.Printf("File %q found in module %q but is already covered by module %q", f, m.Name, fileToModule[f].Name) + continue + } + fileToModule[f] = m + } + } + + var toMake []string + for _, m := range fileToModule { + toMake = append(toMake, m.Name) + } + fmt.Printf("Running make for modules: %v\n", strings.Join(toMake, ", ")) + if err := runMake(ctx, env, toMake...); err != nil { + log.Fatalf("Failed to run make: %v", err) + } + + var sources []*pb.SourceFile + type depsAndGenerated struct { + Deps []string + Generated []*pb.GeneratedFile + } + moduleToDeps := make(map[string]*depsAndGenerated) + for _, f := range files { + file := &pb.SourceFile{ + Path: f, + WorkingDir: env.RepoDir, + } + sources = append(sources, file) + + m := fileToModule[f] + if m == nil { + file.Status = &pb.Status{ + Code: pb.Status_FAILURE, + Message: proto.String("File not found in any module."), + } + continue + } + + file.Status = &pb.Status{Code: pb.Status_OK} + if moduleToDeps[m.Name] != nil { + file.Generated = moduleToDeps[m.Name].Generated + file.Deps = moduleToDeps[m.Name].Deps + continue + } + + deps := transitiveDeps(m, javaModules) + var generated []*pb.GeneratedFile + outPrefix := env.OutDir + "/" + for _, d := range deps { + if relPath, ok := strings.CutPrefix(d, outPrefix); ok { + contents, err := os.ReadFile(d) + if err != nil { + fmt.Printf("Generated file %q not found - will be skipped.\n", d) + continue + } + + generated = append(generated, &pb.GeneratedFile{ + Path: relPath, + Contents: contents, + }) + } + } + moduleToDeps[m.Name] = &depsAndGenerated{deps, generated} + file.Generated = generated + file.Deps = deps + } + + res := &pb.IdeAnalysis{ + BuildArtifactRoot: env.OutDir, + Sources: sources, + Status: &pb.Status{Code: pb.Status_OK}, + } + data, err := proto.Marshal(res) + if err != nil { + log.Fatalf("Failed to marshal result proto: %v", err) + } + + err = os.WriteFile(path.Join(env.OutDir, "ide_query.pb"), data, 0644) + if err != nil { + log.Fatalf("Failed to write result proto: %v", err) + } + + for _, s := range sources { + fmt.Printf("%s: %v (Deps: %d, Generated: %d)\n", s.GetPath(), s.GetStatus(), len(s.GetDeps()), len(s.GetGenerated())) + } +} + +// runMake runs Soong build for the given modules. +func runMake(ctx context.Context, env Env, modules ...string) error { + args := []string{ + "--make-mode", + "ANDROID_BUILD_ENVIRONMENT_CONFIG=googler-cog", + "TARGET_PRODUCT=" + env.LunchTarget.Product, + "TARGET_RELEASE=" + env.LunchTarget.Release, + "TARGET_BUILD_VARIANT=" + env.LunchTarget.Variant, + } + args = append(args, modules...) + cmd := exec.CommandContext(ctx, "build/soong/soong_ui.bash", args...) + cmd.Dir = env.RepoDir + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + return cmd.Run() +} + +type javaModule struct { + Name string + Path []string `json:"path,omitempty"` + Deps []string `json:"dependencies,omitempty"` + Srcs []string `json:"srcs,omitempty"` + Jars []string `json:"jars,omitempty"` + SrcJars []string `json:"srcjars,omitempty"` +} + +func loadJavaModules(path string) (map[string]*javaModule, error) { + data, err := os.ReadFile(path) + if err != nil { + return nil, err + } + + var ret map[string]*javaModule // module name -> module + if err = json.Unmarshal(data, &ret); err != nil { + return nil, err + } + + for name, module := range ret { + if strings.HasSuffix(name, "-jarjar") || strings.HasSuffix(name, ".impl") { + delete(ret, name) + continue + } + + module.Name = name + } + return ret, nil +} + +func transitiveDeps(m *javaModule, modules map[string]*javaModule) []string { + var ret []string + q := list.New() + q.PushBack(m.Name) + seen := make(map[string]bool) // module names -> true + for q.Len() > 0 { + name := q.Remove(q.Front()).(string) + mod := modules[name] + if mod == nil { + continue + } + + ret = append(ret, mod.Srcs...) + ret = append(ret, mod.SrcJars...) + ret = append(ret, mod.Jars...) + for _, d := range mod.Deps { + if seen[d] { + continue + } + seen[d] = true + q.PushBack(d) + } + } + slices.Sort(ret) + ret = slices.Compact(ret) + return ret +} diff --git a/tools/ide_query/ide_query.sh b/tools/ide_query/ide_query.sh new file mode 100755 index 0000000000..663c4dc14a --- /dev/null +++ b/tools/ide_query/ide_query.sh @@ -0,0 +1,12 @@ +#!/bin/bash -e + +cd $(dirname $BASH_SOURCE) +source $(pwd)/../../shell_utils.sh +require_top + +# Ensure cogsetup (out/ will be symlink outside the repo) +. ${TOP}/build/make/cogsetup.sh + +export ANDROID_BUILD_TOP=$TOP +export OUT_DIR=${OUT_DIR} +exec "${TOP}/prebuilts/go/linux-x86/bin/go" "run" "ide_query" "$@" diff --git a/tools/ide_query/ide_query_proto/ide_query.pb.go b/tools/ide_query/ide_query_proto/ide_query.pb.go new file mode 100644 index 0000000000..30571ccd14 --- /dev/null +++ b/tools/ide_query/ide_query_proto/ide_query.pb.go @@ -0,0 +1,522 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.30.0 +// protoc v3.21.12 +// source: ide_query.proto + +package ide_query_proto + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Status_Code int32 + +const ( + Status_OK Status_Code = 0 + Status_FAILURE Status_Code = 1 +) + +// Enum value maps for Status_Code. +var ( + Status_Code_name = map[int32]string{ + 0: "OK", + 1: "FAILURE", + } + Status_Code_value = map[string]int32{ + "OK": 0, + "FAILURE": 1, + } +) + +func (x Status_Code) Enum() *Status_Code { + p := new(Status_Code) + *p = x + return p +} + +func (x Status_Code) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Status_Code) Descriptor() protoreflect.EnumDescriptor { + return file_ide_query_proto_enumTypes[0].Descriptor() +} + +func (Status_Code) Type() protoreflect.EnumType { + return &file_ide_query_proto_enumTypes[0] +} + +func (x Status_Code) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Status_Code.Descriptor instead. +func (Status_Code) EnumDescriptor() ([]byte, []int) { + return file_ide_query_proto_rawDescGZIP(), []int{0, 0} +} + +// Indicates the success/failure for analysis. +type Status struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Code Status_Code `protobuf:"varint,1,opt,name=code,proto3,enum=cider.build.companion.Status_Code" json:"code,omitempty"` + // Details about the status, might be displayed to user. + Message *string `protobuf:"bytes,2,opt,name=message,proto3,oneof" json:"message,omitempty"` +} + +func (x *Status) Reset() { + *x = Status{} + if protoimpl.UnsafeEnabled { + mi := &file_ide_query_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Status) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Status) ProtoMessage() {} + +func (x *Status) ProtoReflect() protoreflect.Message { + mi := &file_ide_query_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Status.ProtoReflect.Descriptor instead. +func (*Status) Descriptor() ([]byte, []int) { + return file_ide_query_proto_rawDescGZIP(), []int{0} +} + +func (x *Status) GetCode() Status_Code { + if x != nil { + return x.Code + } + return Status_OK +} + +func (x *Status) GetMessage() string { + if x != nil && x.Message != nil { + return *x.Message + } + return "" +} + +type GeneratedFile struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Path to the file relative to IdeAnalysis.build_artifact_root. + Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` + // The text of the generated file, if not provided contents will be read + // + // from the path above in user's workstation. + Contents []byte `protobuf:"bytes,2,opt,name=contents,proto3,oneof" json:"contents,omitempty"` +} + +func (x *GeneratedFile) Reset() { + *x = GeneratedFile{} + if protoimpl.UnsafeEnabled { + mi := &file_ide_query_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GeneratedFile) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeneratedFile) ProtoMessage() {} + +func (x *GeneratedFile) ProtoReflect() protoreflect.Message { + mi := &file_ide_query_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeneratedFile.ProtoReflect.Descriptor instead. +func (*GeneratedFile) Descriptor() ([]byte, []int) { + return file_ide_query_proto_rawDescGZIP(), []int{1} +} + +func (x *GeneratedFile) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +func (x *GeneratedFile) GetContents() []byte { + if x != nil { + return x.Contents + } + return nil +} + +type SourceFile struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Repo root relative path to the source file in the tree. + Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` + // Working directory used by the build system. All the relative + // paths in compiler_arguments should be relative to this path. + // Relative to workspace root. + WorkingDir string `protobuf:"bytes,2,opt,name=working_dir,json=workingDir,proto3" json:"working_dir,omitempty"` + // Compiler arguments to compile the source file. If multiple variants + // of the module being compiled are possible, the query script will choose + // one. + CompilerArguments []string `protobuf:"bytes,3,rep,name=compiler_arguments,json=compilerArguments,proto3" json:"compiler_arguments,omitempty"` + // Any generated files that are used in compiling the file. + Generated []*GeneratedFile `protobuf:"bytes,4,rep,name=generated,proto3" json:"generated,omitempty"` + // Paths to all of the sources, like build files, code generators, + // proto files etc. that were used during analysis. Used to figure + // out when a set of build artifacts are stale and the query tool + // must be re-run. + // Relative to workspace root. + Deps []string `protobuf:"bytes,5,rep,name=deps,proto3" json:"deps,omitempty"` + // Represensts analysis status for this particular file. e.g. not part + // of the build graph. + Status *Status `protobuf:"bytes,6,opt,name=status,proto3,oneof" json:"status,omitempty"` +} + +func (x *SourceFile) Reset() { + *x = SourceFile{} + if protoimpl.UnsafeEnabled { + mi := &file_ide_query_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SourceFile) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SourceFile) ProtoMessage() {} + +func (x *SourceFile) ProtoReflect() protoreflect.Message { + mi := &file_ide_query_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SourceFile.ProtoReflect.Descriptor instead. +func (*SourceFile) Descriptor() ([]byte, []int) { + return file_ide_query_proto_rawDescGZIP(), []int{2} +} + +func (x *SourceFile) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +func (x *SourceFile) GetWorkingDir() string { + if x != nil { + return x.WorkingDir + } + return "" +} + +func (x *SourceFile) GetCompilerArguments() []string { + if x != nil { + return x.CompilerArguments + } + return nil +} + +func (x *SourceFile) GetGenerated() []*GeneratedFile { + if x != nil { + return x.Generated + } + return nil +} + +func (x *SourceFile) GetDeps() []string { + if x != nil { + return x.Deps + } + return nil +} + +func (x *SourceFile) GetStatus() *Status { + if x != nil { + return x.Status + } + return nil +} + +type IdeAnalysis struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Path relative to workspace root, containing all the artifacts + // generated by the build system. GeneratedFile.path are always + // relative to this directory. + BuildArtifactRoot string `protobuf:"bytes,1,opt,name=build_artifact_root,json=buildArtifactRoot,proto3" json:"build_artifact_root,omitempty"` + Sources []*SourceFile `protobuf:"bytes,2,rep,name=sources,proto3" json:"sources,omitempty"` + // Status representing overall analysis. + // Should fail only when no analysis can be performed, e.g. workspace + // isn't setup. + Status *Status `protobuf:"bytes,3,opt,name=status,proto3,oneof" json:"status,omitempty"` +} + +func (x *IdeAnalysis) Reset() { + *x = IdeAnalysis{} + if protoimpl.UnsafeEnabled { + mi := &file_ide_query_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *IdeAnalysis) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IdeAnalysis) ProtoMessage() {} + +func (x *IdeAnalysis) ProtoReflect() protoreflect.Message { + mi := &file_ide_query_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IdeAnalysis.ProtoReflect.Descriptor instead. +func (*IdeAnalysis) Descriptor() ([]byte, []int) { + return file_ide_query_proto_rawDescGZIP(), []int{3} +} + +func (x *IdeAnalysis) GetBuildArtifactRoot() string { + if x != nil { + return x.BuildArtifactRoot + } + return "" +} + +func (x *IdeAnalysis) GetSources() []*SourceFile { + if x != nil { + return x.Sources + } + return nil +} + +func (x *IdeAnalysis) GetStatus() *Status { + if x != nil { + return x.Status + } + return nil +} + +var File_ide_query_proto protoreflect.FileDescriptor + +var file_ide_query_proto_rawDesc = []byte{ + 0x0a, 0x0f, 0x69, 0x64, 0x65, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x15, 0x63, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x2e, 0x63, + 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x69, 0x6f, 0x6e, 0x22, 0x88, 0x01, 0x0a, 0x06, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x12, 0x36, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x22, 0x2e, 0x63, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x2e, + 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x1d, 0x0a, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x07, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x88, 0x01, 0x01, 0x22, 0x1b, 0x0a, 0x04, 0x43, 0x6f, + 0x64, 0x65, 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x4b, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x46, 0x41, + 0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0x01, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x22, 0x51, 0x0a, 0x0d, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, + 0x46, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x08, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x8f, 0x02, 0x0a, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x77, 0x6f, 0x72, + 0x6b, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x69, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x44, 0x69, 0x72, 0x12, 0x2d, 0x0a, 0x12, 0x63, 0x6f, + 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x5f, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, + 0x41, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x42, 0x0a, 0x09, 0x67, 0x65, 0x6e, + 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, + 0x69, 0x64, 0x65, 0x72, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x61, + 0x6e, 0x69, 0x6f, 0x6e, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x46, 0x69, + 0x6c, 0x65, 0x52, 0x09, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x12, 0x12, 0x0a, + 0x04, 0x64, 0x65, 0x70, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x70, + 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x2e, + 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, + 0x07, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xc1, 0x01, 0x0a, 0x0b, 0x49, 0x64, 0x65, + 0x41, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x62, 0x75, 0x69, 0x6c, + 0x64, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x41, 0x72, 0x74, 0x69, + 0x66, 0x61, 0x63, 0x74, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x3b, 0x0a, 0x07, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x69, 0x64, 0x65, + 0x72, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x69, 0x6f, + 0x6e, 0x2e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x07, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x62, 0x75, + 0x69, 0x6c, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x88, 0x01, + 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x1b, 0x5a, 0x19, + 0x69, 0x64, 0x65, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2f, 0x69, 0x64, 0x65, 0x5f, 0x71, 0x75, + 0x65, 0x72, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, +} + +var ( + file_ide_query_proto_rawDescOnce sync.Once + file_ide_query_proto_rawDescData = file_ide_query_proto_rawDesc +) + +func file_ide_query_proto_rawDescGZIP() []byte { + file_ide_query_proto_rawDescOnce.Do(func() { + file_ide_query_proto_rawDescData = protoimpl.X.CompressGZIP(file_ide_query_proto_rawDescData) + }) + return file_ide_query_proto_rawDescData +} + +var file_ide_query_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_ide_query_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_ide_query_proto_goTypes = []interface{}{ + (Status_Code)(0), // 0: cider.build.companion.Status.Code + (*Status)(nil), // 1: cider.build.companion.Status + (*GeneratedFile)(nil), // 2: cider.build.companion.GeneratedFile + (*SourceFile)(nil), // 3: cider.build.companion.SourceFile + (*IdeAnalysis)(nil), // 4: cider.build.companion.IdeAnalysis +} +var file_ide_query_proto_depIdxs = []int32{ + 0, // 0: cider.build.companion.Status.code:type_name -> cider.build.companion.Status.Code + 2, // 1: cider.build.companion.SourceFile.generated:type_name -> cider.build.companion.GeneratedFile + 1, // 2: cider.build.companion.SourceFile.status:type_name -> cider.build.companion.Status + 3, // 3: cider.build.companion.IdeAnalysis.sources:type_name -> cider.build.companion.SourceFile + 1, // 4: cider.build.companion.IdeAnalysis.status:type_name -> cider.build.companion.Status + 5, // [5:5] is the sub-list for method output_type + 5, // [5:5] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name +} + +func init() { file_ide_query_proto_init() } +func file_ide_query_proto_init() { + if File_ide_query_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_ide_query_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Status); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ide_query_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GeneratedFile); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ide_query_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SourceFile); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ide_query_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*IdeAnalysis); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_ide_query_proto_msgTypes[0].OneofWrappers = []interface{}{} + file_ide_query_proto_msgTypes[1].OneofWrappers = []interface{}{} + file_ide_query_proto_msgTypes[2].OneofWrappers = []interface{}{} + file_ide_query_proto_msgTypes[3].OneofWrappers = []interface{}{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_ide_query_proto_rawDesc, + NumEnums: 1, + NumMessages: 4, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_ide_query_proto_goTypes, + DependencyIndexes: file_ide_query_proto_depIdxs, + EnumInfos: file_ide_query_proto_enumTypes, + MessageInfos: file_ide_query_proto_msgTypes, + }.Build() + File_ide_query_proto = out.File + file_ide_query_proto_rawDesc = nil + file_ide_query_proto_goTypes = nil + file_ide_query_proto_depIdxs = nil +} diff --git a/tools/ide_query/ide_query_proto/ide_query.proto b/tools/ide_query/ide_query_proto/ide_query.proto new file mode 100644 index 0000000000..63eea39f4d --- /dev/null +++ b/tools/ide_query/ide_query_proto/ide_query.proto @@ -0,0 +1,66 @@ +syntax = "proto3"; + +package ide_query; +option go_package = "ide_query/ide_query_proto"; + +// Indicates the success/failure for analysis. +message Status { + enum Code { + OK = 0; + FAILURE = 1; + } + Code code = 1; + // Details about the status, might be displayed to user. + optional string message = 2; +} + +message GeneratedFile { + // Path to the file relative to IdeAnalysis.build_artifact_root. + string path = 1; + + // The text of the generated file, if not provided contents will be read + // from the path above in user's workstation. + optional bytes contents = 2; +} + +message SourceFile { + // Path to the source file relative to repository root. + string path = 1; + + // Working directory used by the build system. All the relative + // paths in compiler_arguments should be relative to this path. + // Relative to repository root. + string working_dir = 2; + + // Compiler arguments to compile the source file. If multiple variants + // of the module being compiled are possible, the query script will choose + // one. + repeated string compiler_arguments = 3; + + // Any generated files that are used in compiling the file. + repeated GeneratedFile generated = 4; + + // Paths to all of the sources, like build files, code generators, + // proto files etc. that were used during analysis. Used to figure + // out when a set of build artifacts are stale and the query tool + // must be re-run. + // Relative to repository root. + repeated string deps = 5; + + // Represents analysis status for this particular file. e.g. not part + // of the build graph. + optional Status status = 6; +} + +message IdeAnalysis { + // Path relative to repository root, containing all the artifacts + // generated by the build system. GeneratedFile.path are always + // relative to this directory. + string build_artifact_root = 1; + + repeated SourceFile sources = 2; + + // Status representing overall analysis. + // Should fail only when no analysis can be performed. + optional Status status = 3; +} diff --git a/tools/ide_query/ide_query_proto/regen.sh b/tools/ide_query/ide_query_proto/regen.sh new file mode 100755 index 0000000000..eec4f3731b --- /dev/null +++ b/tools/ide_query/ide_query_proto/regen.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +aprotoc --go_out=paths=source_relative:. ide_query.proto