go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/tools/cmd/gorun/main.go (about)

     1  // Copyright 2016 The LUCI Authors.
     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  // Package main defines the `gorun` tool, a shorthand tool to extend the
    16  // "go run"-like convenience to packages.
    17  //
    18  // Unfortunately, "go run" is hard to use when the target has more than one
    19  // ".go" file, and even harder when the target has "_test.go" files.
    20  //
    21  // This is just a bootstrap to "go build /path/to/X && /path/to/X" using a
    22  // temporary directory for build storage.
    23  package main
    24  
    25  import (
    26  	"io/ioutil"
    27  	"os"
    28  	"os/exec"
    29  	"path/filepath"
    30  	"runtime"
    31  
    32  	"go.chromium.org/luci/common/errors"
    33  	"go.chromium.org/luci/common/system/exitcode"
    34  )
    35  
    36  func mainImpl(args []string) (int, error) {
    37  	if len(args) < 1 {
    38  		return 1, errors.New("accepts one argument: package")
    39  	}
    40  	pkg, args := args[0], args[1:]
    41  
    42  	// Create a temporary output directory to build into.
    43  	tmpdir, err := ioutil.TempDir("", "luci-gorun")
    44  	if err != nil {
    45  		return 1, errors.Annotate(err, "failed to create temporary directory").Err()
    46  	}
    47  	defer os.RemoveAll(tmpdir)
    48  
    49  	exePath := filepath.Join(tmpdir, "gorun_target")
    50  	if runtime.GOOS == "windows" {
    51  		exePath += ".exe"
    52  	}
    53  
    54  	// Build the package.
    55  	cmd := exec.Command("go", "build", "-o", exePath, pkg)
    56  	cmd.Stdout = os.Stdout
    57  	cmd.Stderr = os.Stderr
    58  	if err := cmd.Run(); err != nil {
    59  		return 1, errors.Annotate(err, "failed to build: %s", pkg).Err()
    60  	}
    61  
    62  	// Run the package.
    63  	cmd = exec.Command(exePath, args...)
    64  	cmd.Stdin = os.Stdin
    65  	cmd.Stdout = os.Stdout
    66  	cmd.Stderr = os.Stderr
    67  	if err := cmd.Run(); err != nil {
    68  		if rc, ok := exitcode.Get(err); ok {
    69  			return rc, nil
    70  		}
    71  		return 1, errors.Annotate(err, "failed to run: %s", pkg).Err()
    72  	}
    73  
    74  	return 0, nil
    75  }
    76  
    77  func main() {
    78  	rc, err := mainImpl(os.Args[1:])
    79  	if err != nil {
    80  		for _, line := range errors.RenderStack(err) {
    81  			os.Stderr.WriteString(line + "\n")
    82  		}
    83  	}
    84  	os.Exit(rc)
    85  }