You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			163 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Go
		
	
			
		
		
	
	
			163 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Go
		
	
| // Copyright 2015 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 objabi
 | |
| 
 | |
| import (
 | |
| 	"flag"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"io/ioutil"
 | |
| 	"log"
 | |
| 	"os"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| func Flagcount(name, usage string, val *int) {
 | |
| 	flag.Var((*count)(val), name, usage)
 | |
| }
 | |
| 
 | |
| func Flagfn1(name, usage string, f func(string)) {
 | |
| 	flag.Var(fn1(f), name, usage)
 | |
| }
 | |
| 
 | |
| func Flagprint(w io.Writer) {
 | |
| 	flag.CommandLine.SetOutput(w)
 | |
| 	flag.PrintDefaults()
 | |
| }
 | |
| 
 | |
| func Flagparse(usage func()) {
 | |
| 	flag.Usage = usage
 | |
| 	os.Args = expandArgs(os.Args)
 | |
| 	flag.Parse()
 | |
| }
 | |
| 
 | |
| // expandArgs expands "response files" arguments in the provided slice.
 | |
| //
 | |
| // A "response file" argument starts with '@' and the rest of that
 | |
| // argument is a filename with CR-or-CRLF-separated arguments. Each
 | |
| // argument in the named files can also contain response file
 | |
| // arguments. See Issue 18468.
 | |
| //
 | |
| // The returned slice 'out' aliases 'in' iff the input did not contain
 | |
| // any response file arguments.
 | |
| //
 | |
| // TODO: handle relative paths of recursive expansions in different directories?
 | |
| // Is there a spec for this? Are relative paths allowed?
 | |
| func expandArgs(in []string) (out []string) {
 | |
| 	// out is nil until we see a "@" argument.
 | |
| 	for i, s := range in {
 | |
| 		if strings.HasPrefix(s, "@") {
 | |
| 			if out == nil {
 | |
| 				out = make([]string, 0, len(in)*2)
 | |
| 				out = append(out, in[:i]...)
 | |
| 			}
 | |
| 			slurp, err := ioutil.ReadFile(s[1:])
 | |
| 			if err != nil {
 | |
| 				log.Fatal(err)
 | |
| 			}
 | |
| 			args := strings.Split(strings.TrimSpace(strings.Replace(string(slurp), "\r", "", -1)), "\n")
 | |
| 			out = append(out, expandArgs(args)...)
 | |
| 		} else if out != nil {
 | |
| 			out = append(out, s)
 | |
| 		}
 | |
| 	}
 | |
| 	if out == nil {
 | |
| 		return in
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func AddVersionFlag() {
 | |
| 	flag.Var(versionFlag{}, "V", "print version and exit")
 | |
| }
 | |
| 
 | |
| var buildID string // filled in by linker
 | |
| 
 | |
| type versionFlag struct{}
 | |
| 
 | |
| func (versionFlag) IsBoolFlag() bool { return true }
 | |
| func (versionFlag) Get() interface{} { return nil }
 | |
| func (versionFlag) String() string   { return "" }
 | |
| func (versionFlag) Set(s string) error {
 | |
| 	name := os.Args[0]
 | |
| 	name = name[strings.LastIndex(name, `/`)+1:]
 | |
| 	name = name[strings.LastIndex(name, `\`)+1:]
 | |
| 	name = strings.TrimSuffix(name, ".exe")
 | |
| 
 | |
| 	// If there's an active experiment, include that,
 | |
| 	// to distinguish go1.10.2 with an experiment
 | |
| 	// from go1.10.2 without an experiment.
 | |
| 	p := Expstring()
 | |
| 	if p == DefaultExpstring() {
 | |
| 		p = ""
 | |
| 	}
 | |
| 	sep := ""
 | |
| 	if p != "" {
 | |
| 		sep = " "
 | |
| 	}
 | |
| 
 | |
| 	// The go command invokes -V=full to get a unique identifier
 | |
| 	// for this tool. It is assumed that the release version is sufficient
 | |
| 	// for releases, but during development we include the full
 | |
| 	// build ID of the binary, so that if the compiler is changed and
 | |
| 	// rebuilt, we notice and rebuild all packages.
 | |
| 	if s == "full" {
 | |
| 		if strings.HasPrefix(Version, "devel") {
 | |
| 			p += " buildID=" + buildID
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	fmt.Printf("%s version %s%s%s\n", name, Version, sep, p)
 | |
| 	os.Exit(0)
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // count is a flag.Value that is like a flag.Bool and a flag.Int.
 | |
| // If used as -name, it increments the count, but -name=x sets the count.
 | |
| // Used for verbose flag -v.
 | |
| type count int
 | |
| 
 | |
| func (c *count) String() string {
 | |
| 	return fmt.Sprint(int(*c))
 | |
| }
 | |
| 
 | |
| func (c *count) Set(s string) error {
 | |
| 	switch s {
 | |
| 	case "true":
 | |
| 		*c++
 | |
| 	case "false":
 | |
| 		*c = 0
 | |
| 	default:
 | |
| 		n, err := strconv.Atoi(s)
 | |
| 		if err != nil {
 | |
| 			return fmt.Errorf("invalid count %q", s)
 | |
| 		}
 | |
| 		*c = count(n)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (c *count) Get() interface{} {
 | |
| 	return int(*c)
 | |
| }
 | |
| 
 | |
| func (c *count) IsBoolFlag() bool {
 | |
| 	return true
 | |
| }
 | |
| 
 | |
| func (c *count) IsCountFlag() bool {
 | |
| 	return true
 | |
| }
 | |
| 
 | |
| type fn1 func(string)
 | |
| 
 | |
| func (f fn1) Set(s string) error {
 | |
| 	f(s)
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (f fn1) String() string { return "" }
 |