github.com/tiagovtristao/plz@v13.4.0+incompatible/src/cli/stdin.go (about) 1 package cli 2 3 import ( 4 "bufio" 5 "os" 6 "strings" 7 ) 8 9 var seenStdin = false // Used to track that we don't try to read stdin twice 10 // ReadStdin reads a sequence of space-delimited words from standard input. 11 // Words are pushed onto the returned channel asynchronously. 12 func ReadStdin() <-chan string { 13 c := make(chan string) 14 if seenStdin { 15 log.Fatalf("Repeated - on command line; can't reread stdin.") 16 } 17 seenStdin = true 18 go func() { 19 scanner := bufio.NewScanner(os.Stdin) 20 scanner.Split(bufio.ScanWords) 21 for scanner.Scan() { 22 s := strings.TrimSpace(scanner.Text()) 23 if s != "" { 24 c <- s 25 } 26 } 27 if err := scanner.Err(); err != nil { 28 log.Fatalf("Error reading stdin: %s", err) 29 } 30 close(c) 31 }() 32 return c 33 } 34 35 // ReadAllStdin reads standard input in its entirety to a slice. 36 // Since this reads it completely before returning it won't handle a slow input 37 // very nicely. ReadStdin is therefore preferable when possible. 38 func ReadAllStdin() []string { 39 var ret []string 40 for s := range ReadStdin() { 41 ret = append(ret, s) 42 } 43 return ret 44 } 45 46 // StdinStrings is a type used for flags; it accepts a slice of strings but also 47 // if it's a single - it reads its contents from stdin. 48 type StdinStrings []string 49 50 // Get reads stdin if needed and returns the contents of this slice. 51 func (s StdinStrings) Get() []string { 52 if len(s) == 1 && s[0] == "-" { 53 return ReadAllStdin() 54 } else if ContainsString("-", s) { 55 log.Fatalf("Cannot pass - to read stdin along with other arguments.") 56 } 57 return s 58 } 59 60 // ContainsString returns true if the given slice contains an individual string. 61 func ContainsString(needle string, haystack []string) bool { 62 for _, straw := range haystack { 63 if needle == straw { 64 return true 65 } 66 } 67 return false 68 }