github.com/bazelbuild/bazel-gazelle@v0.36.1-0.20240520142334-61b277ba6fed/language/lang.go (about)

     1  /* Copyright 2018 The Bazel Authors. All rights reserved.
     2  
     3  Licensed under the Apache License, Version 2.0 (the "License");
     4  you may not use this file except in compliance with the License.
     5  You may obtain a copy of the License at
     6  
     7     http://www.apache.org/licenses/LICENSE-2.0
     8  
     9  Unless required by applicable law or agreed to in writing, software
    10  distributed under the License is distributed on an "AS IS" BASIS,
    11  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  See the License for the specific language governing permissions and
    13  limitations under the License.
    14  */
    15  
    16  // Package language provides an interface for language extensions in Gazelle.
    17  // Support for a new language can be added by defining a package with a
    18  // function named "New" that returns a value assignable to this interface.
    19  //
    20  // TODO(jayconrod): document how to incorporate languages into a gazelle
    21  // binary that can be run by Bazel.
    22  package language
    23  
    24  import (
    25  	"github.com/bazelbuild/bazel-gazelle/config"
    26  	"github.com/bazelbuild/bazel-gazelle/resolve"
    27  	"github.com/bazelbuild/bazel-gazelle/rule"
    28  )
    29  
    30  // Language describes an extension for Gazelle that provides support for
    31  // a set of Bazel rules.
    32  //
    33  // Languages are used primarily by the fix and update commands. The order
    34  // in which languages are used matters, since languages may depend on
    35  // one another. For example, go depends on proto, since go_proto_libraries
    36  // are generated from metadata stored in proto_libraries.
    37  //
    38  // A single instance of Language is created for each fix / update run. Some
    39  // state may be stored in this instance, but stateless behavior is encouraged,
    40  // especially since some operations may be concurrent in the future.
    41  //
    42  // # Tasks languages are used for
    43  //
    44  // * Configuration (embedded interface config.Configurer). Languages may
    45  // define command line flags and alter the configuration in a directory
    46  // based on directives in build files.
    47  //
    48  // * Fixing deprecated usage of rules in build files.
    49  //
    50  // * Generating rules from source files in a directory.
    51  //
    52  // * Resolving library imports (embedded interface resolve.Resolver). For
    53  // example, import strings like "github.com/foo/bar" in Go can be resolved
    54  // into Bazel labels like "@com_github_foo_bar//:go_default_library".
    55  //
    56  // # Tasks languages support
    57  //
    58  // * Generating load statements: languages list files and symbols that may
    59  // be loaded.
    60  //
    61  // * Merging generated rules into existing rules: languages provide metadata
    62  // that helps with rule matching, merging, and deletion.
    63  type Language interface {
    64  	// TODO(jayconrod): is embedding Configurer strictly necessary?
    65  	config.Configurer
    66  	resolve.Resolver
    67  
    68  	// Kinds returns a map of maps rule names (kinds) and information on how to
    69  	// match and merge attributes that may be found in rules of those kinds. All
    70  	// kinds of rules generated for this language may be found here.
    71  	Kinds() map[string]rule.KindInfo
    72  
    73  	// GenerateRules extracts build metadata from source files in a directory.
    74  	// GenerateRules is called in each directory where an update is requested
    75  	// in depth-first post-order.
    76  	//
    77  	// args contains the arguments for GenerateRules. This is passed as a
    78  	// struct to avoid breaking implementations in the future when new
    79  	// fields are added.
    80  	//
    81  	// A GenerateResult struct is returned. Optional fields may be added to this
    82  	// type in the future.
    83  	//
    84  	// Any non-fatal errors this function encounters should be logged using
    85  	// log.Print.
    86  	GenerateRules(args GenerateArgs) GenerateResult
    87  
    88  	// Loads returns .bzl files and symbols they define. Every rule generated by
    89  	// GenerateRules, now or in the past, should be loadable from one of these
    90  	// files.
    91  	//
    92  	// Deprecated: Implement ModuleAwareLanguage's ApparentLoads.
    93  	Loads() []rule.LoadInfo
    94  
    95  	// Fix repairs deprecated usage of language-specific rules in f. This is
    96  	// called before the file is indexed. Unless c.ShouldFix is true, fixes
    97  	// that delete or rename rules should not be performed.
    98  	Fix(c *config.Config, f *rule.File)
    99  }
   100  
   101  // FinishableLanguage allows a Language to be notified when Generate is finished
   102  // being called.
   103  type FinishableLanguage interface {
   104  	// DoneGeneratingRules is called when all calls to GenerateRules have been
   105  	// completed.
   106  	// This allows for hooks to be called, for instance to release resources
   107  	// such as shutting down a background server.
   108  	// No further calls will be made to GenerateRules on this Language instance
   109  	// after this method has been called.
   110  	DoneGeneratingRules()
   111  }
   112  
   113  type ModuleAwareLanguage interface {
   114  	// ApparentLoads returns .bzl files and symbols they define. Every rule
   115  	// generated by GenerateRules, now or in the past, should be loadable from
   116  	// one of these files.
   117  	//
   118  	// The moduleToApparentName argument is a function that resolves a given
   119  	// Bazel module name to the apparent repository name configured for this
   120  	// module in the MODULE.bazel file, or the empty string if there is no such
   121  	// module or the MODULE.bazel file doesn't exist. Languages should use the
   122  	// non-empty value returned by this function to form the repository part of
   123  	// the load statements they return and fall back to using the legacy
   124  	// WORKSPACE name otherwise.
   125  	//
   126  	// See https://bazel.build/external/overview#concepts for more information
   127  	// on repository names.
   128  	//
   129  	// Example: For a project with these lines in its MODULE.bazel file:
   130  	//
   131  	//   bazel_dep(name = "rules_go", version = "0.38.1", repo_name = "my_rules_go")
   132  	//   bazel_dep(name = "gazelle", version = "0.27.0")
   133  	//
   134  	// moduleToApparentName["rules_go"] == "my_rules_go"
   135  	// moduleToApparentName["gazelle"] == "gazelle"
   136  	// moduleToApparentName["foobar"] == ""
   137  	ApparentLoads(moduleToApparentName func(string) string) []rule.LoadInfo
   138  }
   139  
   140  // GenerateArgs contains arguments for language.GenerateRules. Arguments are
   141  // passed in a struct value so that new fields may be added in the future
   142  // without breaking existing implementations.
   143  type GenerateArgs struct {
   144  	// Config is the configuration for the directory where rules are being
   145  	// generated.
   146  	Config *config.Config
   147  
   148  	// Dir is the canonical absolute path to the directory.
   149  	Dir string
   150  
   151  	// Rel is the slash-separated path to the directory, relative to the
   152  	// repository root ("" for the root directory itself). This may be used
   153  	// as the package name in labels.
   154  	Rel string
   155  
   156  	// File is the build file for the directory. File is nil if there is
   157  	// no existing build file.
   158  	File *rule.File
   159  
   160  	// Subdirs is a list of subdirectories in the directory, including
   161  	// symbolic links to directories that Gazelle will follow.
   162  	// RegularFiles is a list of regular files including other symbolic
   163  	// links.
   164  	// GeneratedFiles is a list of generated files in the directory
   165  	// (usually these are mentioned as "out" or "outs" attributes in rules).
   166  	Subdirs, RegularFiles, GenFiles []string
   167  
   168  	// OtherEmpty is a list of empty rules generated by other languages.
   169  	// OtherGen is a list of generated rules generated by other languages.
   170  	OtherEmpty, OtherGen []*rule.Rule
   171  }
   172  
   173  // GenerateResult contains return values for language.GenerateRules.
   174  // Results are returned through a struct value so that new (optional)
   175  // fields may be added without breaking existing implementations.
   176  type GenerateResult struct {
   177  	// Gen is a list of rules generated from files found in the directory
   178  	// GenerateRules was asked to process. These will be merged with existing
   179  	// rules or added to the build file.
   180  	Gen []*rule.Rule
   181  
   182  	// Empty is a list of rules that cannot be built with the files found in the
   183  	// directory GenerateRules was asked to process. These will be merged with
   184  	// existing rules. If the merged rules are empty, they will be deleted.
   185  	Empty []*rule.Rule
   186  
   187  	// Imports contains information about the imported libraries for each
   188  	// rule in Gen. Gen and Imports must have the same length, since they
   189  	// correspond. These values are passed to Resolve after merge. The type
   190  	// is opaque since different languages may use different representations.
   191  	Imports []interface{}
   192  }