blob: 852e5b910c26074204ddf42249003583c54849c8 [file] [log] [blame]
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// go work use
package workcmd
import (
"cmd/go/internal/base"
"cmd/go/internal/fsys"
"cmd/go/internal/modload"
"context"
"io/fs"
"os"
"path/filepath"
)
var cmdUse = &base.Command{
UsageLine: "go work use [-r] [moddirs]",
Short: "add modules to workspace file",
Long: `Use provides a command-line interface for adding
directories, optionally recursively, to a go.work file.
A use directive will be added to the go.work file for each argument
directory listed on the command line go.work file, if it exists on disk,
or removed from the go.work file if it does not exist on disk.
The -r flag searches recursively for modules in the argument
directories, and the use command operates as if each of the directories
were specified as arguments: namely, use directives will be added for
directories that exist, and removed for directories that do not exist.
`,
}
var useR = cmdUse.Flag.Bool("r", false, "")
func init() {
cmdUse.Run = runUse // break init cycle
base.AddModCommonFlags(&cmdUse.Flag)
base.AddWorkfileFlag(&cmdUse.Flag)
}
func runUse(ctx context.Context, cmd *base.Command, args []string) {
modload.InitWorkfile()
modload.ForceUseModules = true
var gowork string
modload.InitWorkfile()
gowork = modload.WorkFilePath()
workFile, err := modload.ReadWorkFile(gowork)
if err != nil {
base.Fatalf("go: %v", err)
}
haveDirs := make(map[string]bool)
for _, dir := range workFile.Use {
haveDirs[filepath.Join(filepath.Dir(gowork), filepath.FromSlash(dir.Path))] = true
}
addDirs := make(map[string]bool)
removeDirs := make(map[string]bool)
lookDir := func(dir string) {
absDir := filepath.Join(base.Cwd(), dir)
// If the path is absolute, keep it absolute. If it's relative,
// make it relative to the go.work file rather than the working directory.
if !filepath.IsAbs(dir) {
rel, err := filepath.Rel(filepath.Dir(gowork), absDir)
if err == nil {
dir = rel
}
}
fi, err := os.Stat(filepath.Join(dir, "go.mod"))
if err != nil {
if os.IsNotExist(err) {
if haveDirs[absDir] {
removeDirs[dir] = true
}
return
}
base.Errorf("go: %v", err)
}
if !fi.Mode().IsRegular() {
base.Errorf("go: %v is not regular", filepath.Join(dir, "go.mod"))
}
if !haveDirs[absDir] {
addDirs[dir] = true
}
}
for _, useDir := range args {
if *useR {
fsys.Walk(useDir, func(path string, info fs.FileInfo, err error) error {
if !info.IsDir() {
return nil
}
lookDir(path)
return nil
})
continue
}
lookDir(useDir)
}
for dir := range removeDirs {
workFile.DropUse(filepath.ToSlash(dir))
}
for dir := range addDirs {
workFile.AddUse(filepath.ToSlash(dir), "")
}
modload.UpdateWorkFile(workFile)
modload.WriteWorkFile(gowork, workFile)
}