| // Copyright 2017 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. |
| |
| // +build !plan9 |
| |
| // The getgo command installs Go to the user's system. |
| package main |
| |
| import ( |
| "bufio" |
| "context" |
| "errors" |
| "flag" |
| "fmt" |
| exec "golang.org/x/sys/execabs" |
| "os" |
| "strings" |
| ) |
| |
| var ( |
| interactive = flag.Bool("i", false, "Interactive mode, prompt for inputs.") |
| verbose = flag.Bool("v", false, "Verbose.") |
| setupOnly = flag.Bool("skip-dl", false, "Don't download - only set up environment variables") |
| goVersion = flag.String("version", "", `Version of Go to install (e.g. "1.8.3"). If empty, uses the latest version.`) |
| |
| version = "devel" |
| ) |
| |
| var errExitCleanly error = errors.New("exit cleanly sentinel value") |
| |
| func main() { |
| flag.Parse() |
| if *goVersion != "" && !strings.HasPrefix(*goVersion, "go") { |
| *goVersion = "go" + *goVersion |
| } |
| |
| ctx := context.Background() |
| |
| verbosef("version " + version) |
| |
| runStep := func(s step) { |
| err := s(ctx) |
| if err == errExitCleanly { |
| os.Exit(0) |
| } |
| if err != nil { |
| fmt.Fprintln(os.Stderr, err) |
| os.Exit(2) |
| } |
| } |
| |
| if !*setupOnly { |
| runStep(welcome) |
| runStep(checkOthers) |
| runStep(chooseVersion) |
| runStep(downloadGo) |
| } |
| |
| runStep(setupGOPATH) |
| } |
| |
| func verbosef(format string, v ...interface{}) { |
| if !*verbose { |
| return |
| } |
| |
| fmt.Printf(format+"\n", v...) |
| } |
| |
| func prompt(ctx context.Context, query, defaultAnswer string) (string, error) { |
| if !*interactive { |
| return defaultAnswer, nil |
| } |
| |
| fmt.Printf("%s [%s]: ", query, defaultAnswer) |
| |
| type result struct { |
| answer string |
| err error |
| } |
| ch := make(chan result, 1) |
| go func() { |
| s := bufio.NewScanner(os.Stdin) |
| if !s.Scan() { |
| ch <- result{"", s.Err()} |
| return |
| } |
| answer := s.Text() |
| if answer == "" { |
| answer = defaultAnswer |
| } |
| ch <- result{answer, nil} |
| }() |
| |
| select { |
| case r := <-ch: |
| return r.answer, r.err |
| case <-ctx.Done(): |
| return "", ctx.Err() |
| } |
| } |
| |
| func runCommand(ctx context.Context, prog string, args ...string) ([]byte, error) { |
| verbosef("Running command: %s %v", prog, args) |
| |
| cmd := exec.CommandContext(ctx, prog, args...) |
| out, err := cmd.CombinedOutput() |
| if err != nil { |
| return nil, fmt.Errorf("running cmd '%s %s' failed: %s err: %v", prog, strings.Join(args, " "), string(out), err) |
| } |
| if out != nil && err == nil && len(out) != 0 { |
| verbosef("%s", out) |
| } |
| |
| return out, nil |
| } |