123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- /* Copyright 2017 The Bazel Authors. All rights reserved.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package main
- import (
- "errors"
- "flag"
- "fmt"
- "os"
- "path/filepath"
- "sync"
- "github.com/bazelbuild/bazel-gazelle/internal/config"
- "github.com/bazelbuild/bazel-gazelle/internal/merger"
- "github.com/bazelbuild/bazel-gazelle/internal/repos"
- "github.com/bazelbuild/bazel-gazelle/internal/rule"
- )
- type updateReposFn func(c *updateReposConfig, oldFile *rule.File, kinds map[string]rule.KindInfo) error
- type updateReposConfig struct {
- fn updateReposFn
- lockFilename string
- importPaths []string
- }
- const updateReposName = "_update-repos"
- func getUpdateReposConfig(c *config.Config) *updateReposConfig {
- return c.Exts[updateReposName].(*updateReposConfig)
- }
- type updateReposConfigurer struct{}
- func (_ *updateReposConfigurer) RegisterFlags(fs *flag.FlagSet, cmd string, c *config.Config) {
- uc := &updateReposConfig{}
- c.Exts[updateReposName] = uc
- fs.StringVar(&uc.lockFilename, "from_file", "", "Gazelle will translate repositories listed in this file into repository rules in WORKSPACE. Currently only dep's Gopkg.lock is supported.")
- }
- func (_ *updateReposConfigurer) CheckFlags(fs *flag.FlagSet, c *config.Config) error {
- uc := getUpdateReposConfig(c)
- switch {
- case uc.lockFilename != "":
- if len(fs.Args()) != 0 {
- return fmt.Errorf("Got %d positional arguments with -from_file; wanted 0.\nTry -help for more information.", len(fs.Args()))
- }
- uc.fn = importFromLockFile
- default:
- if len(fs.Args()) == 0 {
- return fmt.Errorf("No repositories specified\nTry -help for more information.")
- }
- uc.fn = updateImportPaths
- uc.importPaths = fs.Args()
- }
- return nil
- }
- func (_ *updateReposConfigurer) KnownDirectives() []string { return nil }
- func (_ *updateReposConfigurer) Configure(c *config.Config, rel string, f *rule.File) {}
- func updateRepos(args []string) error {
- cexts := make([]config.Configurer, 0, len(languages)+2)
- cexts = append(cexts, &config.CommonConfigurer{}, &updateReposConfigurer{})
- kinds := make(map[string]rule.KindInfo)
- loads := []rule.LoadInfo{}
- for _, lang := range languages {
- cexts = append(cexts, lang)
- loads = append(loads, lang.Loads()...)
- for kind, info := range lang.Kinds() {
- kinds[kind] = info
- }
- }
- c, err := newUpdateReposConfiguration(args, cexts)
- if err != nil {
- return err
- }
- uc := getUpdateReposConfig(c)
- workspacePath := filepath.Join(c.RepoRoot, "WORKSPACE")
- f, err := rule.LoadFile(workspacePath, "")
- if err != nil {
- return fmt.Errorf("error loading %q: %v", workspacePath, err)
- }
- merger.FixWorkspace(f)
- if err := uc.fn(uc, f, kinds); err != nil {
- return err
- }
- merger.FixLoads(f, loads)
- if err := merger.CheckGazelleLoaded(f); err != nil {
- return err
- }
- if err := f.Save(f.Path); err != nil {
- return fmt.Errorf("error writing %q: %v", f.Path, err)
- }
- return nil
- }
- func newUpdateReposConfiguration(args []string, cexts []config.Configurer) (*config.Config, error) {
- c := config.New()
- fs := flag.NewFlagSet("gazelle", flag.ContinueOnError)
- // Flag will call this on any parse error. Don't print usage unless
- // -h or -help were passed explicitly.
- fs.Usage = func() {}
- for _, cext := range cexts {
- cext.RegisterFlags(fs, "update-repos", c)
- }
- if err := fs.Parse(args); err != nil {
- if err == flag.ErrHelp {
- updateReposUsage(fs)
- return nil, err
- }
- // flag already prints the error; don't print it again.
- return nil, errors.New("Try -help for more information")
- }
- for _, cext := range cexts {
- if err := cext.CheckFlags(fs, c); err != nil {
- return nil, err
- }
- }
- return c, nil
- }
- func updateReposUsage(fs *flag.FlagSet) {
- fmt.Fprint(os.Stderr, `usage:
- # Add/update repositories by import path
- gazelle update-repos example.com/repo1 example.com/repo2
- # Import repositories from lock file
- gazelle update-repos -from_file=file
- The update-repos command updates repository rules in the WORKSPACE file.
- update-repos can add or update repositories explicitly by import path.
- update-repos can also import repository rules from a vendoring tool's lock
- file (currently only deps' Gopkg.lock is supported).
- FLAGS:
- `)
- }
- func updateImportPaths(c *updateReposConfig, f *rule.File, kinds map[string]rule.KindInfo) error {
- rs := repos.ListRepositories(f)
- rc := repos.NewRemoteCache(rs)
- genRules := make([]*rule.Rule, len(c.importPaths))
- errs := make([]error, len(c.importPaths))
- var wg sync.WaitGroup
- wg.Add(len(c.importPaths))
- for i, imp := range c.importPaths {
- go func(i int, imp string) {
- defer wg.Done()
- repo, err := repos.UpdateRepo(rc, imp)
- if err != nil {
- errs[i] = err
- return
- }
- repo.Remote = "" // don't set these explicitly
- repo.VCS = ""
- rule := repos.GenerateRule(repo)
- genRules[i] = rule
- }(i, imp)
- }
- wg.Wait()
- for _, err := range errs {
- if err != nil {
- return err
- }
- }
- merger.MergeFile(f, nil, genRules, merger.PreResolve, kinds)
- return nil
- }
- func importFromLockFile(c *updateReposConfig, f *rule.File, kinds map[string]rule.KindInfo) error {
- genRules, err := repos.ImportRepoRules(c.lockFilename)
- if err != nil {
- return err
- }
- merger.MergeFile(f, nil, genRules, merger.PreResolve, kinds)
- return nil
- }
|