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

     1  /* Copyright 2023 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 module provides functions to read information out of MODULE.bazel files.
    17  
    18  package module
    19  
    20  import (
    21  	"os"
    22  	"path/filepath"
    23  
    24  	"github.com/bazelbuild/buildtools/build"
    25  )
    26  
    27  // ExtractModuleToApparentNameMapping collects the mapping of module names (e.g. "rules_go") to
    28  // user-configured apparent names (e.g. "my_rules_go") from the repos MODULE.bazel, if it exists.
    29  // See https://bazel.build/external/module#repository_names_and_strict_deps for more information on
    30  // apparent names.
    31  func ExtractModuleToApparentNameMapping(repoRoot string) (func(string) string, error) {
    32  	moduleFile, err := parseModuleFile(repoRoot)
    33  	if err != nil {
    34  		return nil, err
    35  	}
    36  	var moduleToApparentName map[string]string
    37  	if moduleFile != nil {
    38  		moduleToApparentName = collectApparentNames(moduleFile)
    39  	} else {
    40  		// If there is no MODULE.bazel file, return a function that always returns the empty string.
    41  		// Languages will know to fall back to the WORKSPACE names of repos.
    42  		moduleToApparentName = make(map[string]string)
    43  	}
    44  
    45  	return func(moduleName string) string {
    46  		return moduleToApparentName[moduleName]
    47  	}, nil
    48  }
    49  
    50  func parseModuleFile(repoRoot string) (*build.File, error) {
    51  	path := filepath.Join(repoRoot, "MODULE.bazel")
    52  	bytes, err := os.ReadFile(path)
    53  	if os.IsNotExist(err) {
    54  		return nil, nil
    55  	} else if err != nil {
    56  		return nil, err
    57  	}
    58  	return build.ParseModule(path, bytes)
    59  }
    60  
    61  // Collects the mapping of module names (e.g. "rules_go") to user-configured apparent names (e.g.
    62  // "my_rules_go"). See https://bazel.build/external/module#repository_names_and_strict_deps for more
    63  // information on apparent names.
    64  func collectApparentNames(m *build.File) map[string]string {
    65  	apparentNames := make(map[string]string)
    66  
    67  	for _, dep := range m.Rules("") {
    68  		if dep.Name() == "" {
    69  			continue
    70  		}
    71  		if dep.Kind() != "module" && dep.Kind() != "bazel_dep" {
    72  			continue
    73  		}
    74  		// We support module in addition to bazel_dep to handle language repos that use Gazelle to
    75  		// manage their own BUILD files.
    76  		if name := dep.AttrString("name"); name != "" {
    77  			if repoName := dep.AttrString("repo_name"); repoName != "" {
    78  				apparentNames[name] = repoName
    79  			} else {
    80  				apparentNames[name] = name
    81  			}
    82  		}
    83  	}
    84  
    85  	return apparentNames
    86  }