OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // 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 "errors" | 9 "errors" |
10 "flag" | 10 "flag" |
11 "fmt" | 11 "fmt" |
12 "os" | 12 "os" |
13 "time" | 13 "time" |
14 | 14 |
15 "github.com/golang/protobuf/proto" | 15 "github.com/golang/protobuf/proto" |
16 "github.com/luci/luci-go/client/logdog/annotee" | 16 "github.com/luci/luci-go/client/logdog/annotee" |
17 "github.com/luci/luci-go/client/logdog/annotee/executor" | 17 "github.com/luci/luci-go/client/logdog/annotee/executor" |
18 "github.com/luci/luci-go/client/logdog/butlerlib/bootstrap" | 18 "github.com/luci/luci-go/client/logdog/butlerlib/bootstrap" |
19 "github.com/luci/luci-go/client/logdog/butlerlib/streamclient" | 19 "github.com/luci/luci-go/client/logdog/butlerlib/streamclient" |
20 "github.com/luci/luci-go/client/logdog/butlerlib/streamproto" | 20 "github.com/luci/luci-go/client/logdog/butlerlib/streamproto" |
21 "github.com/luci/luci-go/common/clock/clockflag" | 21 "github.com/luci/luci-go/common/clock/clockflag" |
| 22 "github.com/luci/luci-go/common/config" |
22 "github.com/luci/luci-go/common/logdog/types" | 23 "github.com/luci/luci-go/common/logdog/types" |
23 log "github.com/luci/luci-go/common/logging" | 24 log "github.com/luci/luci-go/common/logging" |
24 "github.com/luci/luci-go/common/logging/gologger" | 25 "github.com/luci/luci-go/common/logging/gologger" |
25 "golang.org/x/net/context" | 26 "golang.org/x/net/context" |
26 ) | 27 ) |
27 | 28 |
28 const ( | 29 const ( |
29 // configErrorReturnCode is returned when there is an error with Annotee
's | 30 // configErrorReturnCode is returned when there is an error with Annotee
's |
30 // command-line configuration. | 31 // command-line configuration. |
31 configErrorReturnCode = 2 | 32 configErrorReturnCode = 2 |
(...skipping 18 matching lines...) Expand all Loading... |
50 type application struct { | 51 type application struct { |
51 context.Context | 52 context.Context |
52 | 53 |
53 annotate annotationMode | 54 annotate annotationMode |
54 jsonArgsPath string | 55 jsonArgsPath string |
55 butlerStreamServer string | 56 butlerStreamServer string |
56 tee bool | 57 tee bool |
57 printSummary bool | 58 printSummary bool |
58 testingDir string | 59 testingDir string |
59 annotationInterval clockflag.Duration | 60 annotationInterval clockflag.Duration |
| 61 project config.ProjectName |
60 nameBase streamproto.StreamNameFlag | 62 nameBase streamproto.StreamNameFlag |
61 prefix streamproto.StreamNameFlag | 63 prefix streamproto.StreamNameFlag |
62 logdogHost string | 64 logdogHost string |
63 | 65 |
64 bootstrap *bootstrap.Bootstrap | 66 bootstrap *bootstrap.Bootstrap |
65 } | 67 } |
66 | 68 |
67 func (a *application) addToFlagSet(fs *flag.FlagSet) { | 69 func (a *application) addToFlagSet(fs *flag.FlagSet) { |
68 fs.StringVar(&a.jsonArgsPath, "json-args-path", "", | 70 fs.StringVar(&a.jsonArgsPath, "json-args-path", "", |
69 "If specified, this is a JSON file containing the full command t
o run as an "+ | 71 "If specified, this is a JSON file containing the full command t
o run as an "+ |
70 "array of strings.") | 72 "array of strings.") |
71 fs.Var(&a.annotate, "annotate", | 73 fs.Var(&a.annotate, "annotate", |
72 "Annotation handling mode. Options are: "+annotationFlagEnum.Cho
ices()) | 74 "Annotation handling mode. Options are: "+annotationFlagEnum.Cho
ices()) |
73 fs.StringVar(&a.butlerStreamServer, "butler-stream-server", "", | 75 fs.StringVar(&a.butlerStreamServer, "butler-stream-server", "", |
74 "The Butler stream server location. If empty, Annotee will check
for Butler "+ | 76 "The Butler stream server location. If empty, Annotee will check
for Butler "+ |
75 "bootstrapping and extract the stream server from that."
) | 77 "bootstrapping and extract the stream server from that."
) |
76 fs.BoolVar(&a.tee, "tee", true, | 78 fs.BoolVar(&a.tee, "tee", true, |
77 "Tee the bootstrapped process' STDOUT/STDERR streams.") | 79 "Tee the bootstrapped process' STDOUT/STDERR streams.") |
78 fs.BoolVar(&a.printSummary, "print-summary", true, | 80 fs.BoolVar(&a.printSummary, "print-summary", true, |
79 "Print the annotation protobufs that were emitted at the end.") | 81 "Print the annotation protobufs that were emitted at the end.") |
80 fs.StringVar(&a.testingDir, "testing-dir", "", | 82 fs.StringVar(&a.testingDir, "testing-dir", "", |
81 "Rather than coupling to a Butler instance, output generated ann
otations "+ | 83 "Rather than coupling to a Butler instance, output generated ann
otations "+ |
82 "and streams to this directory.") | 84 "and streams to this directory.") |
83 fs.Var(&a.annotationInterval, "annotation-interval", | 85 fs.Var(&a.annotationInterval, "annotation-interval", |
84 "Buffer annotation updates for this amount of time. <=0 sends ev
ery update.") | 86 "Buffer annotation updates for this amount of time. <=0 sends ev
ery update.") |
| 87 fs.Var(&a.project, "project", "The log prefix's project name (required).
") |
85 fs.Var(&a.nameBase, "name-base", "Base stream name to prepend to generat
ed names.") | 88 fs.Var(&a.nameBase, "name-base", "Base stream name to prepend to generat
ed names.") |
86 fs.Var(&a.prefix, "prefix", "The log stream prefix. If missing, one will
be inferred from bootstrap.") | 89 fs.Var(&a.prefix, "prefix", "The log stream prefix. If missing, one will
be inferred from bootstrap.") |
87 fs.StringVar(&a.logdogHost, "logdog-host", "", | 90 fs.StringVar(&a.logdogHost, "logdog-host", "", |
88 "LogDog Coordinator host name. If supplied, log viewing links wi
ll be generated.") | 91 "LogDog Coordinator host name. If supplied, log viewing links wi
ll be generated.") |
89 } | 92 } |
90 | 93 |
91 func (a *application) loadJSONArgs() ([]string, error) { | 94 func (a *application) loadJSONArgs() ([]string, error) { |
92 fd, err := os.Open(a.jsonArgsPath) | 95 fd, err := os.Open(a.jsonArgsPath) |
93 if err != nil { | 96 if err != nil { |
94 return nil, err | 97 return nil, err |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
151 if err != nil { | 154 if err != nil { |
152 log.WithError(err).Errorf(a, "Failed to get stream client instan
ce.") | 155 log.WithError(err).Errorf(a, "Failed to get stream client instan
ce.") |
153 return configErrorReturnCode | 156 return configErrorReturnCode |
154 } | 157 } |
155 | 158 |
156 prefix := types.StreamName(a.prefix) | 159 prefix := types.StreamName(a.prefix) |
157 if prefix == "" && a.bootstrap != nil { | 160 if prefix == "" && a.bootstrap != nil { |
158 prefix = a.bootstrap.Prefix | 161 prefix = a.bootstrap.Prefix |
159 } | 162 } |
160 | 163 |
| 164 // TODO(dnj): Require project attribute. |
| 165 if a.project == "" { |
| 166 a.project = a.bootstrap.Project |
| 167 } |
| 168 |
161 args = fs.Args() | 169 args = fs.Args() |
162 if a.jsonArgsPath != "" { | 170 if a.jsonArgsPath != "" { |
163 if len(args) > 0 { | 171 if len(args) > 0 { |
164 log.Fields{ | 172 log.Fields{ |
165 "commandLineArgs": args, | 173 "commandLineArgs": args, |
166 "jsonArgsPath": a.jsonArgsPath, | 174 "jsonArgsPath": a.jsonArgsPath, |
167 }.Errorf(a, "Cannot specify both JSON and command-line a
rguments.") | 175 }.Errorf(a, "Cannot specify both JSON and command-line a
rguments.") |
168 return configErrorReturnCode | 176 return configErrorReturnCode |
169 } | 177 } |
170 | 178 |
(...skipping 10 matching lines...) Expand all Loading... |
181 log.Errorf(a, "No command-line arguments were supplied.") | 189 log.Errorf(a, "No command-line arguments were supplied.") |
182 return configErrorReturnCode | 190 return configErrorReturnCode |
183 } | 191 } |
184 | 192 |
185 // Translate "<=0" flag option to Processor's "0", indicating that every | 193 // Translate "<=0" flag option to Processor's "0", indicating that every |
186 // update should be sent. | 194 // update should be sent. |
187 if a.annotationInterval < 0 { | 195 if a.annotationInterval < 0 { |
188 a.annotationInterval = 0 | 196 a.annotationInterval = 0 |
189 } | 197 } |
190 | 198 |
| 199 // Initialize our link generator, if we can. |
| 200 linkGen := &coordinatorLinkGenerator{ |
| 201 base: types.StreamName(a.nameBase), |
| 202 project: a.project, |
| 203 prefix: prefix, |
| 204 } |
| 205 if !linkGen.canGenerateLinks() { |
| 206 linkGen = nil |
| 207 } |
| 208 |
191 e := executor.Executor{ | 209 e := executor.Executor{ |
192 Options: annotee.Options{ | 210 Options: annotee.Options{ |
193 Base: types.StreamName(a.nameBase), | |
194 Prefix: prefix, | |
195 Client: client, | 211 Client: client, |
| 212 LinkGenerator: linkGen, |
196 MetadataUpdateInterval: time.Duration(a.annotationInterv
al), | 213 MetadataUpdateInterval: time.Duration(a.annotationInterv
al), |
197 LogDogHost: a.logdogHost, | |
198 }, | 214 }, |
199 | 215 |
200 Annotate: executor.AnnotationMode(a.annotate), | 216 Annotate: executor.AnnotationMode(a.annotate), |
201 Stdin: os.Stdin, | 217 Stdin: os.Stdin, |
202 } | 218 } |
203 if a.tee { | 219 if a.tee { |
204 e.TeeStdout = os.Stdout | 220 e.TeeStdout = os.Stdout |
205 e.TeeStderr = os.Stderr | 221 e.TeeStderr = os.Stderr |
206 } | 222 } |
207 if err := e.Run(a, args); err != nil { | 223 if err := e.Run(a, args); err != nil { |
(...skipping 13 matching lines...) Expand all Loading... |
221 | 237 |
222 if !e.Executed() { | 238 if !e.Executed() { |
223 return runtimeErrorReturnCode | 239 return runtimeErrorReturnCode |
224 } | 240 } |
225 return e.ReturnCode() | 241 return e.ReturnCode() |
226 } | 242 } |
227 | 243 |
228 func main() { | 244 func main() { |
229 os.Exit(mainImpl(os.Args[1:])) | 245 os.Exit(mainImpl(os.Args[1:])) |
230 } | 246 } |
OLD | NEW |