blob: fcc76d4bc1e2b403333ce835466ddc503a8f79ad [file] [log] [blame]
// Copyright 2018 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.
package vgo
import (
"strings"
"cmd/go/internal/base"
"cmd/go/internal/load"
"cmd/go/internal/modfetch"
"cmd/go/internal/module"
"cmd/go/internal/mvs"
"cmd/go/internal/semver"
"cmd/go/internal/work"
)
var CmdGet = &base.Command{
UsageLine: "get [build flags] [modules or packages]",
Short: "download and install versioned modules and dependencies",
Long: `
Get downloads the latest versions of modules containing the named packages,
along with the versions of the dependencies required by those modules
(not necessarily the latest ones).
It then installs the named packages, like 'go install'.
By default, get downloads the named packages, updates go.mod, and builds the packages.
As a special case if a package is a module root and has no code, no error is reported.
TODO make this better
The -m flag causes get to update the module file but not build anything.
The -d flag causes get to download the code and update the module file but not build anything.
The -u flag causes get to download the latest version of dependencies as well.
Each package being updated can be suffixed with @version to specify
the desired version. Specifying a version older than the one currently
in use causes a downgrade, which may in turn downgrade other
modules using that one, to keep everything consistent.
TODO: Make this documentation better once the semantic dust settles.
`,
}
var (
getD = CmdGet.Flag.Bool("d", false, "")
getM = CmdGet.Flag.Bool("m", false, "")
getU = CmdGet.Flag.Bool("u", false, "")
)
func init() {
CmdGet.Run = runGet // break init loop
work.AddBuildFlags(CmdGet)
}
func runGet(cmd *base.Command, args []string) {
if *getU && len(args) > 0 {
base.Fatalf("vgo get: -u not supported with argument list")
}
if !*getU && len(args) == 0 {
base.Fatalf("vgo get: need arguments or -u")
}
if *getU {
LoadBuildList()
return
}
Init()
InitMod()
var upgrade []module.Version
var downgrade []module.Version
var newPkgs []string
for _, pkg := range args {
var path, vers string
/* OLD CODE
if n := strings.Count(pkg, "(") + strings.Count(pkg, ")"); n > 0 {
i := strings.Index(pkg, "(")
j := strings.Index(pkg, ")")
if n != 2 || i < 0 || j <= i+1 || j != len(pkg)-1 && pkg[j+1] != '/' {
base.Errorf("vgo get: invalid module version syntax: %s", pkg)
continue
}
path, vers = pkg[:i], pkg[i+1:j]
pkg = pkg[:i] + pkg[j+1:]
*/
if i := strings.Index(pkg, "@"); i >= 0 {
path, pkg, vers = pkg[:i], pkg[:i], pkg[i+1:]
if strings.Contains(vers, "@") {
base.Errorf("vgo get: invalid module version syntax: %s", pkg)
continue
}
} else {
path = pkg
vers = "latest"
}
if vers == "none" {
downgrade = append(downgrade, module.Version{Path: path, Version: ""})
} else {
info, err := modfetch.Query(path, vers, allowed)
if err != nil {
base.Errorf("vgo get %v: %v", pkg, err)
continue
}
upgrade = append(upgrade, module.Version{Path: path, Version: info.Version})
newPkgs = append(newPkgs, pkg)
}
}
args = newPkgs
// Upgrade.
var err error
buildList, err = mvs.Upgrade(Target, newReqs(buildList), upgrade...)
if err != nil {
base.Fatalf("vgo get: %v", err)
}
LoadBuildList()
// Downgrade anything that went too far.
version := make(map[string]string)
for _, mod := range buildList {
version[mod.Path] = mod.Version
}
for _, mod := range upgrade {
if semver.Compare(mod.Version, version[mod.Path]) < 0 {
downgrade = append(downgrade, mod)
}
}
if len(downgrade) > 0 {
buildList, err = mvs.Downgrade(Target, newReqs(buildList, buildList[1:]...), downgrade...)
if err != nil {
base.Fatalf("vgo get: %v", err)
}
// TODO: Check that everything we need to import is still available.
/*
local := v.matchPackages("all", v.Reqs[:1])
for _, path := range local {
dir, err := v.importDir(path)
if err != nil {
return err // TODO
}
imports, testImports, err := scanDir(dir, v.Tags)
for _, path := range imports {
xxx
}
for _, path := range testImports {
xxx
}
}
*/
}
WriteGoMod()
if *getD {
// Download all needed code as side-effect.
LoadALL()
}
if *getM {
return
}
if len(args) > 0 {
work.BuildInit()
var list []string
for _, p := range load.PackagesAndErrors(args) {
if p.Error == nil || !strings.HasPrefix(p.Error.Err, "no Go files") {
list = append(list, p.ImportPath)
}
}
if len(list) > 0 {
work.InstallPackages(list)
}
}
}