Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(179)

Side by Side Diff: logdog/client/cmd/logdog_butler/subcommand_run.go

Issue 2317223002: LogDog/Butler: Enable direct output forwarding. (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The LUCI Authors. All rights reserved. 1 // Copyright 2015 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0 2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file. 3 // that can be found in the LICENSE file.
4 4
5 package main 5 package main
6 6
7 import ( 7 import (
8 "encoding/json" 8 "encoding/json"
9 "io" 9 "io"
10 "os" 10 "os"
(...skipping 29 matching lines...) Expand all
40 cmd.Flags.StringVar(&cmd.chdir, "chdir", "", 40 cmd.Flags.StringVar(&cmd.chdir, "chdir", "",
41 "If specified, switch to this directory prior to running the command.") 41 "If specified, switch to this directory prior to running the command.")
42 cmd.Flags.Var(&cmd.streamServerURI, "streamserver-uri", 42 cmd.Flags.Var(&cmd.streamServerURI, "streamserver-uri",
43 "The stream server URI to bind to (e.g., "+string(exampl eStreamServerURI)+").") 43 "The stream server URI to bind to (e.g., "+string(exampl eStreamServerURI)+").")
44 cmd.Flags.BoolVar(&cmd.attach, "attach", true, 44 cmd.Flags.BoolVar(&cmd.attach, "attach", true,
45 "If true, attaches the bootstrapped process' STDOUT and STDERR streams.") 45 "If true, attaches the bootstrapped process' STDOUT and STDERR streams.")
46 cmd.Flags.BoolVar(&cmd.stdin, "forward-stdin", false, 46 cmd.Flags.BoolVar(&cmd.stdin, "forward-stdin", false,
47 "If true, forward STDIN to the bootstrapped process.") 47 "If true, forward STDIN to the bootstrapped process.")
48 48
49 // "stdout" command-line option. 49 // "stdout" command-line option.
50 cmd.stdout.Name = "stdout"
51 stdoutFlag := new(nestedflagset.FlagSet) 50 stdoutFlag := new(nestedflagset.FlagSet)
52 cmd.stdout.addFlags(&stdoutFlag.F) 51 cmd.stdout.addFlags(&stdoutFlag.F)
53 cmd.Flags.Var(stdoutFlag, "stdout", "STDOUT stream parameters.") 52 cmd.Flags.Var(stdoutFlag, "stdout", "STDOUT stream parameters.")
54 53
55 // "stderr" command-line option. 54 // "stderr" command-line option.
56 cmd.stderr.Name = "stderr"
57 stderrFlag := new(nestedflagset.FlagSet) 55 stderrFlag := new(nestedflagset.FlagSet)
58 cmd.stderr.addFlags(&stderrFlag.F) 56 cmd.stderr.addFlags(&stderrFlag.F)
59 cmd.Flags.Var(stderrFlag, "stderr", "STDERR stream parameters.") 57 cmd.Flags.Var(stderrFlag, "stderr", "STDERR stream parameters.")
60 58
61 return cmd 59 return cmd
62 }, 60 },
63 } 61 }
64 62
65 type runCommandRun struct { 63 type runCommandRun struct {
66 subcommands.CommandRunBase 64 subcommands.CommandRunBase
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 Cmd: exec.Command(commandPath, args...), 199 Cmd: exec.Command(commandPath, args...),
202 } 200 }
203 proc.Dir = cmd.chdir 201 proc.Dir = cmd.chdir
204 proc.Env = env.Sorted() 202 proc.Env = env.Sorted()
205 if cmd.stdin { 203 if cmd.stdin {
206 proc.Stdin = os.Stdin 204 proc.Stdin = os.Stdin
207 } 205 }
208 206
209 // Attach STDOUT / STDERR pipes if configured to do so. 207 // Attach STDOUT / STDERR pipes if configured to do so.
210 // 208 //
211 » // We track them with a sync.WaitGroup because we have to wait for them to 209 » // This will happen in one of two ways:
212 » // close before reaping the process (see exec.Cmd's StdoutPipe method). 210 » // - If no stream name is provided, we will not create a Butler stream f or
211 » // this output; instead, we will connect them directly to the bootstra pped
212 » // process.
213 » // - If a stream name is provided, we will create a Butler stream for th is
214 » // output, and tee as necessary.
215 » //
216 » // When connecting the stream to the Butler, we track them with a
217 » // sync.WaitGroup because we have to wait for them to close before reapi ng the
218 » // process (see exec.Cmd's StdoutPipe method).
213 // 219 //
214 // In this case, we will hand them to the Butler, which will Close then when 220 // In this case, we will hand them to the Butler, which will Close then when
215 // it counters io.EOF. 221 // it counters io.EOF.
216 var ( 222 var (
217 stdout, stderr io.ReadCloser 223 stdout, stderr io.ReadCloser
218 streamWG sync.WaitGroup 224 streamWG sync.WaitGroup
219 ) 225 )
220 if cmd.attach { 226 if cmd.attach {
221 » » stdout, err = proc.StdoutPipe() 227 » » // STDOUT
222 » » if err != nil { 228 » » if cmd.stdout.Name == "" {
223 » » » log.WithError(err).Errorf(a, "Failed to get STDOUT pipe. ") 229 » » » // Forward directly.
224 » » » return runtimeErrorReturnCode 230 » » » proc.Stdout = os.Stdout
231 » » } else {
232 » » » // Connect to Butler.
233 » » » stdout, err = proc.StdoutPipe()
234 » » » if err != nil {
235 » » » » log.WithError(err).Errorf(a, "Failed to get STDO UT pipe.")
236 » » » » return runtimeErrorReturnCode
237 » » » }
238 » » » stdout = &callbackReadCloser{stdout, streamWG.Done}
239 » » » streamWG.Add(1)
225 } 240 }
226 stdout = &callbackReadCloser{stdout, streamWG.Done}
227 241
228 » » // Get our STDERR pipe 242 » » // STDERR
229 » » stderr, err = proc.StderrPipe() 243 » » if cmd.stderr.Name == "" {
230 » » if err != nil { 244 » » » // Forward directly.
231 » » » log.WithError(err).Errorf(a, "Failed to get STDERR pipe. ") 245 » » » proc.Stderr = os.Stderr
232 » » » return runtimeErrorReturnCode 246 » » } else {
247 » » » // Connect to Butler.
248 » » » stderr, err = proc.StderrPipe()
249 » » » if err != nil {
250 » » » » log.WithError(err).Errorf(a, "Failed to get STDE RR pipe.")
251 » » » » return runtimeErrorReturnCode
252 » » » }
253 » » » stderr = &callbackReadCloser{stderr, streamWG.Done}
254 » » » streamWG.Add(1)
233 } 255 }
234 stderr = &callbackReadCloser{stderr, streamWG.Done}
235 streamWG.Add(2)
236 } 256 }
237 257
238 if log.IsLogging(a, log.Debug) { 258 if log.IsLogging(a, log.Debug) {
239 log.Fields{ 259 log.Fields{
240 "commandPath": commandPath, 260 "commandPath": commandPath,
241 "cwd": cwd, 261 "cwd": cwd,
242 "args": args, 262 "args": args,
243 }.Debugf(a, "Executing application.") 263 }.Debugf(a, "Executing application.")
244 for _, entry := range proc.Env { 264 for _, entry := range proc.Env {
245 log.Debugf(a, "Environment variable: %s", entry) 265 log.Debugf(a, "Environment variable: %s", entry)
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
372 // callbackReadCloser invokes a callback method when closed. 392 // callbackReadCloser invokes a callback method when closed.
373 type callbackReadCloser struct { 393 type callbackReadCloser struct {
374 io.ReadCloser 394 io.ReadCloser
375 callback func() 395 callback func()
376 } 396 }
377 397
378 func (c *callbackReadCloser) Close() error { 398 func (c *callbackReadCloser) Close() error {
379 defer c.callback() 399 defer c.callback()
380 return c.ReadCloser.Close() 400 return c.ReadCloser.Close()
381 } 401 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698