1*105f6285SAndroid Build Coastguard Worker// Copyright 2022 The Android Open Source Project 2*105f6285SAndroid Build Coastguard Worker// 3*105f6285SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*105f6285SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*105f6285SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*105f6285SAndroid Build Coastguard Worker// 7*105f6285SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*105f6285SAndroid Build Coastguard Worker// 9*105f6285SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*105f6285SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*105f6285SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*105f6285SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*105f6285SAndroid Build Coastguard Worker// limitations under the License. 14*105f6285SAndroid Build Coastguard Worker 15*105f6285SAndroid Build Coastguard Workerpackage local 16*105f6285SAndroid Build Coastguard Worker 17*105f6285SAndroid Build Coastguard Workerimport ( 18*105f6285SAndroid Build Coastguard Worker "bufio" 19*105f6285SAndroid Build Coastguard Worker "bytes" 20*105f6285SAndroid Build Coastguard Worker "context" 21*105f6285SAndroid Build Coastguard Worker "errors" 22*105f6285SAndroid Build Coastguard Worker "io" 23*105f6285SAndroid Build Coastguard Worker "os/exec" 24*105f6285SAndroid Build Coastguard Worker "time" 25*105f6285SAndroid Build Coastguard Worker) 26*105f6285SAndroid Build Coastguard Worker 27*105f6285SAndroid Build Coastguard Worker// Run the input command via pipe with given arguments, stdout of the pipe is passed to input parser 28*105f6285SAndroid Build Coastguard Worker// argument. 29*105f6285SAndroid Build Coastguard Workerfunc runPipe(ctx context.Context, timeout time.Duration, cmdName string, args []string, parser func(r io.Reader)) (err error, stdErr string) { 30*105f6285SAndroid Build Coastguard Worker ctx, cancel := context.WithTimeout(ctx, timeout) 31*105f6285SAndroid Build Coastguard Worker defer cancel() 32*105f6285SAndroid Build Coastguard Worker 33*105f6285SAndroid Build Coastguard Worker cmd := exec.CommandContext(ctx, cmdName, args[0:]...) 34*105f6285SAndroid Build Coastguard Worker errorBuf := bytes.Buffer{} 35*105f6285SAndroid Build Coastguard Worker cmd.Stderr = &errorBuf 36*105f6285SAndroid Build Coastguard Worker stdout, err := cmd.StdoutPipe() 37*105f6285SAndroid Build Coastguard Worker if err != nil { 38*105f6285SAndroid Build Coastguard Worker return err, errorBuf.String() 39*105f6285SAndroid Build Coastguard Worker } 40*105f6285SAndroid Build Coastguard Worker 41*105f6285SAndroid Build Coastguard Worker if err = cmd.Start(); err != nil { 42*105f6285SAndroid Build Coastguard Worker return err, errorBuf.String() 43*105f6285SAndroid Build Coastguard Worker } 44*105f6285SAndroid Build Coastguard Worker parser(stdout) 45*105f6285SAndroid Build Coastguard Worker if err = cmd.Wait(); err != nil { 46*105f6285SAndroid Build Coastguard Worker return err, errorBuf.String() 47*105f6285SAndroid Build Coastguard Worker } 48*105f6285SAndroid Build Coastguard Worker return nil, "" 49*105f6285SAndroid Build Coastguard Worker} 50*105f6285SAndroid Build Coastguard Worker 51*105f6285SAndroid Build Coastguard Worker// Run input command, stdout is passed via out parameter to user, if error the stderr is provided via 52*105f6285SAndroid Build Coastguard Worker// stdErr string to the user. 53*105f6285SAndroid Build Coastguard Workerfunc run(ctx context.Context, timeout time.Duration, cmdName string, args []string) (out *bytes.Buffer, err error, stdErr string) { 54*105f6285SAndroid Build Coastguard Worker ctx, cancel := context.WithTimeout(ctx, timeout) 55*105f6285SAndroid Build Coastguard Worker defer cancel() 56*105f6285SAndroid Build Coastguard Worker 57*105f6285SAndroid Build Coastguard Worker cmd := exec.CommandContext(ctx, cmdName, args[0:]...) 58*105f6285SAndroid Build Coastguard Worker errorBuf := bytes.Buffer{} 59*105f6285SAndroid Build Coastguard Worker outputBuf := bytes.Buffer{} 60*105f6285SAndroid Build Coastguard Worker cmd.Stderr = &errorBuf 61*105f6285SAndroid Build Coastguard Worker cmd.Stdout = &outputBuf 62*105f6285SAndroid Build Coastguard Worker if err = cmd.Run(); err != nil { 63*105f6285SAndroid Build Coastguard Worker return nil, err, errorBuf.String() 64*105f6285SAndroid Build Coastguard Worker } 65*105f6285SAndroid Build Coastguard Worker 66*105f6285SAndroid Build Coastguard Worker return &outputBuf, nil, "" 67*105f6285SAndroid Build Coastguard Worker} 68*105f6285SAndroid Build Coastguard Worker 69*105f6285SAndroid Build Coastguard Worker// lineScanner 70*105f6285SAndroid Build Coastguard Worker// 71*105f6285SAndroid Build Coastguard Worker// Map output lines to strings, with expected number of 72*105f6285SAndroid Build Coastguard Worker// lines 73*105f6285SAndroid Build Coastguard Workertype lineScanner struct { 74*105f6285SAndroid Build Coastguard Worker Lines []string 75*105f6285SAndroid Build Coastguard Worker} 76*105f6285SAndroid Build Coastguard Worker 77*105f6285SAndroid Build Coastguard Worker// Parse into lines 78*105f6285SAndroid Build Coastguard Workerfunc (l *lineScanner) Parse(s *bufio.Scanner) error { 79*105f6285SAndroid Build Coastguard Worker i := 0 80*105f6285SAndroid Build Coastguard Worker for s.Scan() { 81*105f6285SAndroid Build Coastguard Worker if i < len(l.Lines) { 82*105f6285SAndroid Build Coastguard Worker l.Lines[i] = s.Text() 83*105f6285SAndroid Build Coastguard Worker } else { 84*105f6285SAndroid Build Coastguard Worker i++ 85*105f6285SAndroid Build Coastguard Worker break 86*105f6285SAndroid Build Coastguard Worker } 87*105f6285SAndroid Build Coastguard Worker i++ 88*105f6285SAndroid Build Coastguard Worker } 89*105f6285SAndroid Build Coastguard Worker if i != len(l.Lines) { 90*105f6285SAndroid Build Coastguard Worker return errors.New("cmd: incorrect number of lines") 91*105f6285SAndroid Build Coastguard Worker } 92*105f6285SAndroid Build Coastguard Worker return nil 93*105f6285SAndroid Build Coastguard Worker} 94*105f6285SAndroid Build Coastguard Worker 95*105f6285SAndroid Build Coastguard Workerfunc newLineScanner(numLines int) *lineScanner { 96*105f6285SAndroid Build Coastguard Worker out := &lineScanner{Lines: make([]string, numLines)} 97*105f6285SAndroid Build Coastguard Worker return (out) 98*105f6285SAndroid Build Coastguard Worker} 99