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

Side by Side Diff: vpython/run.go

Issue 2963503003: [errors] Greatly simplify common/errors package. (Closed)
Patch Set: fix nits Created 3 years, 5 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 | « vpython/python/version.go ('k') | vpython/spec/load.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2017 The LUCI Authors. All rights reserved. 1 // Copyright 2017 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 vpython 5 package vpython
6 6
7 import ( 7 import (
8 "os" 8 "os"
9 "os/exec" 9 "os/exec"
10 "os/signal" 10 "os/signal"
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
43 // - Identifying the Python interpreter to use. 43 // - Identifying the Python interpreter to use.
44 // - Composing the environment specification. 44 // - Composing the environment specification.
45 // - Constructing the virtual environment (download, install). 45 // - Constructing the virtual environment (download, install).
46 // - Execute the Python process with the supplied arguments. 46 // - Execute the Python process with the supplied arguments.
47 // 47 //
48 // The Python subprocess is bound to the lifetime of ctx, and will be terminated 48 // The Python subprocess is bound to the lifetime of ctx, and will be terminated
49 // if ctx is cancelled. 49 // if ctx is cancelled.
50 func Run(c context.Context, opts Options) error { 50 func Run(c context.Context, opts Options) error {
51 // Resolve our Options. 51 // Resolve our Options.
52 if err := opts.resolve(c); err != nil { 52 if err := opts.resolve(c); err != nil {
53 » » return errors.Annotate(err).Reason("could not resolve options"). Err() 53 » » return errors.Annotate(err, "could not resolve options").Err()
54 } 54 }
55 55
56 // Create a local cancellation option (signal handling). 56 // Create a local cancellation option (signal handling).
57 c, cancelFunc := context.WithCancel(c) 57 c, cancelFunc := context.WithCancel(c)
58 defer cancelFunc() 58 defer cancelFunc()
59 59
60 // Create our virtual environment root directory. 60 // Create our virtual environment root directory.
61 err := venv.With(c, opts.EnvConfig, opts.WaitForEnv, func(c context.Cont ext, ve *venv.Env) error { 61 err := venv.With(c, opts.EnvConfig, opts.WaitForEnv, func(c context.Cont ext, ve *venv.Env) error {
62 // Build the augmented environment variables. 62 // Build the augmented environment variables.
63 e := opts.Environ 63 e := opts.Environ
(...skipping 28 matching lines...) Expand all
92 cmd.Dir = opts.WorkDir 92 cmd.Dir = opts.WorkDir
93 cmd.Env = e.Sorted() 93 cmd.Env = e.Sorted()
94 cmd.Stdin = os.Stdin 94 cmd.Stdin = os.Stdin
95 cmd.Stdout = os.Stdout 95 cmd.Stdout = os.Stdout
96 cmd.Stderr = os.Stderr 96 cmd.Stderr = os.Stderr
97 97
98 logging.Debugf(c, "Running Python command: %s\nWorkDir: %s\nEnv: %s", cmd.Args, cmd.Dir, cmd.Env) 98 logging.Debugf(c, "Running Python command: %s\nWorkDir: %s\nEnv: %s", cmd.Args, cmd.Dir, cmd.Env)
99 99
100 // Output the Python command being executed. 100 // Output the Python command being executed.
101 if err := runAndForwardSignals(c, cmd, cancelFunc); err != nil { 101 if err := runAndForwardSignals(c, cmd, cancelFunc); err != nil {
102 » » » return errors.Annotate(err).Reason("failed to execute bo otstrapped Python").Err() 102 » » » return errors.Annotate(err, "failed to execute bootstrap ped Python").Err()
103 } 103 }
104 return nil 104 return nil
105 }) 105 })
106 if err != nil { 106 if err != nil {
107 » » return errors.Annotate(err).Err() 107 » » return errors.Annotate(err, "").Err()
108 } 108 }
109 return nil 109 return nil
110 } 110 }
111 111
112 func runAndForwardSignals(c context.Context, cmd *exec.Cmd, cancelFunc context.C ancelFunc) error { 112 func runAndForwardSignals(c context.Context, cmd *exec.Cmd, cancelFunc context.C ancelFunc) error {
113 signalC := make(chan os.Signal, 1) 113 signalC := make(chan os.Signal, 1)
114 signalDoneC := make(chan struct{}) 114 signalDoneC := make(chan struct{})
115 signal.Notify(signalC, forwardedSignals...) 115 signal.Notify(signalC, forwardedSignals...)
116 defer func() { 116 defer func() {
117 signal.Stop(signalC) 117 signal.Stop(signalC)
118 118
119 close(signalC) 119 close(signalC)
120 <-signalDoneC 120 <-signalDoneC
121 }() 121 }()
122 122
123 if err := cmd.Start(); err != nil { 123 if err := cmd.Start(); err != nil {
124 » » return errors.Annotate(err).Reason("failed to start process").Er r() 124 » » return errors.Annotate(err, "failed to start process").Err()
125 } 125 }
126 126
127 logging.Fields{ 127 logging.Fields{
128 "pid": cmd.Process.Pid, 128 "pid": cmd.Process.Pid,
129 }.Debugf(c, "Python subprocess has started!") 129 }.Debugf(c, "Python subprocess has started!")
130 130
131 // Start our signal forwarding goroutine, now that the process is runnin g. 131 // Start our signal forwarding goroutine, now that the process is runnin g.
132 go func() { 132 go func() {
133 defer func() { 133 defer func() {
134 close(signalDoneC) 134 close(signalDoneC)
135 }() 135 }()
136 136
137 for sig := range signalC { 137 for sig := range signalC {
138 logging.Debugf(c, "Forwarding signal: %v", sig) 138 logging.Debugf(c, "Forwarding signal: %v", sig)
139 if err := cmd.Process.Signal(sig); err != nil { 139 if err := cmd.Process.Signal(sig); err != nil {
140 logging.Fields{ 140 logging.Fields{
141 logging.ErrorKey: err, 141 logging.ErrorKey: err,
142 "signal": sig, 142 "signal": sig,
143 }.Errorf(c, "Failed to forward signal; terminati ng immediately.") 143 }.Errorf(c, "Failed to forward signal; terminati ng immediately.")
144 cancelFunc() 144 cancelFunc()
145 } 145 }
146 } 146 }
147 }() 147 }()
148 148
149 err := cmd.Wait() 149 err := cmd.Wait()
150 logging.Debugf(c, "Python subprocess has terminated: %v", err) 150 logging.Debugf(c, "Python subprocess has terminated: %v", err)
151 if err != nil { 151 if err != nil {
152 » » return errors.Annotate(err).Err() 152 » » return errors.Annotate(err, "").Err()
153 } 153 }
154 return nil 154 return nil
155 } 155 }
156 156
157 func prefixPATH(env environ.Env, components ...string) { 157 func prefixPATH(env environ.Env, components ...string) {
158 if len(components) == 0 { 158 if len(components) == 0 {
159 return 159 return
160 } 160 }
161 161
162 // Clone "components" so we don't mutate our caller's array. 162 // Clone "components" so we don't mutate our caller's array.
163 components = append([]string(nil), components...) 163 components = append([]string(nil), components...)
164 164
165 // If there is a current PATH (likely), add that to the end. 165 // If there is a current PATH (likely), add that to the end.
166 cur, _ := env.Get("PATH") 166 cur, _ := env.Get("PATH")
167 if len(cur) > 0 { 167 if len(cur) > 0 {
168 components = append(components, cur) 168 components = append(components, cur)
169 } 169 }
170 170
171 env.Set("PATH", strings.Join(components, string(os.PathListSeparator))) 171 env.Set("PATH", strings.Join(components, string(os.PathListSeparator)))
172 } 172 }
OLDNEW
« no previous file with comments | « vpython/python/version.go ('k') | vpython/spec/load.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698