blob: a3543613ab487f1824bd18fe15e080e218081fc6 [file] [log] [blame]
// Copyright 2020 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 main
import (
"flag"
"fmt"
"go/go2go"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
)
var gotool = filepath.Join(runtime.GOROOT(), "bin", "go")
var cmds = map[string]bool{
"build": true,
"run": true,
"test": true,
"translate": true,
}
func main() {
flag.Usage = usage
flag.Parse()
args := flag.Args()
if len(args) < 1 {
usage()
}
if !cmds[args[0]] {
usage()
}
importerTmpdir, err := ioutil.TempDir("", "go2go")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(importerTmpdir)
importer := go2go.NewImporter(importerTmpdir)
var rundir string
if args[0] == "run" {
tmpdir := copyToTmpdir(args[1:])
defer os.RemoveAll(tmpdir)
translate(importer, tmpdir)
nargs := []string{"run"}
for _, arg := range args[1:] {
base := filepath.Base(arg)
f := strings.TrimSuffix(base, ".go2") + ".go"
nargs = append(nargs, f)
}
args = nargs
rundir = tmpdir
} else if args[0] == "translate" && isGo2Files(args[1:]...) {
for _, arg := range args[1:] {
translateFile(importer, arg)
}
} else {
for _, dir := range expandPackages(args[1:]) {
translate(importer, dir)
}
}
if args[0] != "translate" {
cmd := exec.Command(gotool, args...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Dir = rundir
gopath := importerTmpdir
if go2path := os.Getenv("GO2PATH"); go2path != "" {
gopath += string(os.PathListSeparator) + go2path
}
if oldGopath := os.Getenv("GOPATH"); oldGopath != "" {
gopath += string(os.PathListSeparator) + oldGopath
}
cmd.Env = append(os.Environ(),
"GOPATH="+gopath,
"GO111MODULE=off",
)
if err := cmd.Run(); err != nil {
die(fmt.Sprintf("%s %v failed: %v", gotool, args, err))
}
}
}
// isGo2Files reports whether the arguments are a list of .go2 files.
func isGo2Files(args ...string) bool {
for _, arg := range args {
if filepath.Ext(arg) != ".go2" {
return false
}
}
return true
}
// expandPackages returns a list of directories expanded from packages.
func expandPackages(pkgs []string) []string {
if len(pkgs) == 0 {
return []string{"."}
}
go2path := os.Getenv("GO2PATH")
var dirs []string
pkgloop:
for _, pkg := range pkgs {
if go2path != "" {
for _, pd := range strings.Split(go2path, string(os.PathListSeparator)) {
d := filepath.Join(pd, "src", pkg)
if fi, err := os.Stat(d); err == nil && fi.IsDir() {
dirs = append(dirs, d)
continue pkgloop
}
}
}
cmd := exec.Command(gotool, "list", "-f", "{{.Dir}}", pkg)
cmd.Stderr = os.Stderr
if go2path != "" {
gopath := go2path
if oldGopath := os.Getenv("GOPATH"); oldGopath != "" {
gopath += string(os.PathListSeparator) + oldGopath
}
cmd.Env = append(os.Environ(),
"GOPATH="+gopath,
"GO111MODULE=off",
)
}
out, err := cmd.Output()
if err != nil {
die(fmt.Sprintf("%s list %q failed: %v", gotool, pkg, err))
}
dirs = append(dirs, strings.Split(string(out), "\n")...)
}
return dirs
}
// copyToTmpdir copies files into a temporary directory.
func copyToTmpdir(files []string) string {
if len(files) == 0 {
die("no files to run")
}
tmpdir, err := ioutil.TempDir("", "go2go-run")
if err != nil {
die(err.Error())
}
for _, file := range files {
data, err := ioutil.ReadFile(file)
if err != nil {
die(err.Error())
}
if err := ioutil.WriteFile(filepath.Join(tmpdir, filepath.Base(file)), data, 0444); err != nil {
die(err.Error())
}
}
return tmpdir
}
// usage reports a usage message and exits with failure.
func usage() {
fmt.Fprint(os.Stderr, `Usage: go2go <command> [arguments]
The commands are:
build translate and build packages
run translate and run list of files
test translate and test packages
translate translate .go2 files into .go files
`)
os.Exit(2)
}
// die reports an error and exits.
func die(msg string) {
fmt.Fprintln(os.Stderr, msg)
os.Exit(1)
}