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

Side by Side Diff: client/cmd/kitchen/cook.go

Issue 2055283002: kitchen: CURRENT_TIMESTAMP support (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/luci-go@master
Patch Set: Created 4 years, 6 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 | client/cmd/kitchen/recipe.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 2016 The LUCI Authors. All rights reserved. 1 // Copyright 2016 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 "fmt" 9 "fmt"
10 "io/ioutil" 10 "io/ioutil"
11 "net/url" 11 "net/url"
12 "os" 12 "os"
13 "os/exec" 13 "os/exec"
14 "path" 14 "path"
15 "strconv"
15 "strings" 16 "strings"
16 "syscall" 17 "syscall"
17 18
18 "github.com/maruel/subcommands" 19 "github.com/maruel/subcommands"
19 "golang.org/x/net/context" 20 "golang.org/x/net/context"
20 21
21 "github.com/luci/luci-go/common/cli" 22 "github.com/luci/luci-go/common/cli"
23 "github.com/luci/luci-go/common/clock"
22 "github.com/luci/luci-go/common/ctxcmd" 24 "github.com/luci/luci-go/common/ctxcmd"
23 ) 25 )
24 26
25 // BootstrapStepName is the name of kitchen's step where it makes preparations 27 // BootstrapStepName is the name of kitchen's step where it makes preparations
26 // for running a recipe, e.g. fetches a repository. 28 // for running a recipe, e.g. fetches a repository.
27 const BootstrapStepName = "recipe bootstrap" 29 const BootstrapStepName = "recipe bootstrap"
28 30
29 // cmdCook checks out a repository at a revision and runs a recipe. 31 // cmdCook checks out a repository at a revision and runs a recipe.
30 var cmdCook = &subcommands.Command{ 32 var cmdCook = &subcommands.Command{
31 UsageLine: "cook -repository <repository URL> -revision <revision> -reci pe <recipe>", 33 UsageLine: "cook -repository <repository URL> -revision <revision> -reci pe <recipe>",
(...skipping 22 matching lines...) Expand all
54 "The working directory for recipe execution. Defaults to a temp dir.") 56 "The working directory for recipe execution. Defaults to a temp dir.")
55 fs.StringVar(&c.Properties, "properties", "", 57 fs.StringVar(&c.Properties, "properties", "",
56 "A json string containing the properties. Mutually exclu sive with -properties-file.") 58 "A json string containing the properties. Mutually exclu sive with -properties-file.")
57 fs.StringVar(&c.PropertiesFile, "properties-file", "", 59 fs.StringVar(&c.PropertiesFile, "properties-file", "",
58 "A file containing a json string of properties. Mutually exclusive with -properties.") 60 "A file containing a json string of properties. Mutually exclusive with -properties.")
59 fs.StringVar( 61 fs.StringVar(
60 &c.OutputResultJSONFile, 62 &c.OutputResultJSONFile,
61 "output-result-json", 63 "output-result-json",
62 "", 64 "",
63 "The file to write the JSON serialized returned value of the recipe to") 65 "The file to write the JSON serialized returned value of the recipe to")
66 fs.BoolVar(
67 &c.Timestamps,
68 "timestamps",
69 false,
70 "If true, print CURRENT_TIMESTAMP annotations.")
64 return &c 71 return &c
65 }, 72 },
66 } 73 }
67 74
68 type cookRun struct { 75 type cookRun struct {
69 subcommands.CommandRunBase 76 subcommands.CommandRunBase
70 77
71 RepositoryURL string 78 RepositoryURL string
72 Revision string 79 Revision string
73 Recipe string 80 Recipe string
74 CheckoutDir string 81 CheckoutDir string
75 Workdir string 82 Workdir string
76 Properties string 83 Properties string
77 PropertiesFile string 84 PropertiesFile string
78 OutputResultJSONFile string 85 OutputResultJSONFile string
86 Timestamps bool
79 } 87 }
80 88
81 func (c *cookRun) validateFlags() error { 89 func (c *cookRun) validateFlags() error {
82 // Validate Repository. 90 // Validate Repository.
83 if c.RepositoryURL == "" { 91 if c.RepositoryURL == "" {
84 return fmt.Errorf("-repository is required") 92 return fmt.Errorf("-repository is required")
85 } 93 }
86 repoURL, err := url.Parse(c.RepositoryURL) 94 repoURL, err := url.Parse(c.RepositoryURL)
87 if err != nil { 95 if err != nil {
88 return fmt.Errorf("invalid repository %q: %s", repoURL, err) 96 return fmt.Errorf("invalid repository %q: %s", repoURL, err)
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 c.Workdir = tempWorkdir 131 c.Workdir = tempWorkdir
124 } 132 }
125 133
126 recipe := recipeRun{ 134 recipe := recipeRun{
127 repositoryPath: c.CheckoutDir, 135 repositoryPath: c.CheckoutDir,
128 workDir: c.Workdir, 136 workDir: c.Workdir,
129 recipe: c.Recipe, 137 recipe: c.Recipe,
130 propertiesJSON: c.Properties, 138 propertiesJSON: c.Properties,
131 propertiesFile: c.PropertiesFile, 139 propertiesFile: c.PropertiesFile,
132 outputResultJSONFile: c.OutputResultJSONFile, 140 outputResultJSONFile: c.OutputResultJSONFile,
141 timestamps: c.Timestamps,
133 } 142 }
134 recipeCmd, err := recipe.Command() 143 recipeCmd, err := recipe.Command()
135 if err != nil { 144 if err != nil {
136 return 0, err 145 return 0, err
137 } 146 }
138 147
139 fmt.Printf("Running command %q %q in %q\n", 148 fmt.Printf("Running command %q %q in %q\n",
140 recipeCmd.Path, recipeCmd.Args, recipeCmd.Dir) 149 recipeCmd.Path, recipeCmd.Args, recipeCmd.Dir)
141 150
142 recipeCtxCmd := ctxcmd.CtxCmd{Cmd: recipeCmd} 151 recipeCtxCmd := ctxcmd.CtxCmd{Cmd: recipeCmd}
(...skipping 25 matching lines...) Expand all
168 err = fmt.Errorf("unexpected arguments %v\n", args) 177 err = fmt.Errorf("unexpected arguments %v\n", args)
169 } else { 178 } else {
170 err = c.validateFlags() 179 err = c.validateFlags()
171 } 180 }
172 if err != nil { 181 if err != nil {
173 fmt.Fprintln(os.Stderr, err) 182 fmt.Fprintln(os.Stderr, err)
174 c.Flags.Usage() 183 c.Flags.Usage()
175 return 1 184 return 1
176 } 185 }
177 186
187 if c.Timestamps {
188 annotateTime(ctx)
189 }
178 annotate("SEED_STEP", BootstrapStepName) 190 annotate("SEED_STEP", BootstrapStepName)
179 annotate("STEP_CURSOR", BootstrapStepName) 191 annotate("STEP_CURSOR", BootstrapStepName)
180 annotate("STEP_STARTED") 192 annotate("STEP_STARTED")
193 defer func() {
194 annotate("STEP_CURSOR", BootstrapStepName)
195 if c.Timestamps {
196 annotateTime(ctx)
197 }
198 annotate("STEP_CLOSED")
199 if c.Timestamps {
200 annotateTime(ctx)
201 }
202 }()
203
181 props, err := parseProperties(c.Properties, c.PropertiesFile) 204 props, err := parseProperties(c.Properties, c.PropertiesFile)
182 if err != nil { 205 if err != nil {
183 fmt.Fprintln(os.Stderr, err) 206 fmt.Fprintln(os.Stderr, err)
184 return 1 207 return 1
185 } 208 }
186 for k, v := range props { 209 for k, v := range props {
187 // Order is not stable, but that is okay. 210 // Order is not stable, but that is okay.
188 jv, err := json.Marshal(v) 211 jv, err := json.Marshal(v)
189 if err != nil { 212 if err != nil {
190 fmt.Fprintln(os.Stderr, err) 213 fmt.Fprintln(os.Stderr, err)
191 return 1 214 return 1
192 } 215 }
193 annotate("SET_BUILD_PROPERTY", k, string(jv)) 216 annotate("SET_BUILD_PROPERTY", k, string(jv))
194 } 217 }
195 218
196 recipeExitCode, err := c.run(ctx) 219 recipeExitCode, err := c.run(ctx)
197 annotate("STEP_CURSOR", BootstrapStepName)
198 if err != nil { 220 if err != nil {
199 if err != context.Canceled { 221 if err != context.Canceled {
200 fmt.Fprintln(os.Stderr, err) 222 fmt.Fprintln(os.Stderr, err)
201 } 223 }
202 return -1 224 return -1
203 } 225 }
204 annotate("STEP_CLOSED")
205 return recipeExitCode 226 return recipeExitCode
206 } 227 }
207 228
208 func parseProperties(properties, propertiesFile string) (result map[string]inter face{}, err error) { 229 func parseProperties(properties, propertiesFile string) (result map[string]inter face{}, err error) {
209 if properties != "" { 230 if properties != "" {
210 err = json.Unmarshal([]byte(properties), &result) 231 err = json.Unmarshal([]byte(properties), &result)
211 if err != nil { 232 if err != nil {
212 err = fmt.Errorf("could not parse properties %s\n%s", pr operties, err) 233 err = fmt.Errorf("could not parse properties %s\n%s", pr operties, err)
213 } 234 }
214 return 235 return
215 } 236 }
216 if propertiesFile != "" { 237 if propertiesFile != "" {
217 b, err := ioutil.ReadFile(propertiesFile) 238 b, err := ioutil.ReadFile(propertiesFile)
218 if err != nil { 239 if err != nil {
219 err = fmt.Errorf("could not read properties file %s\n%s" , propertiesFile, err) 240 err = fmt.Errorf("could not read properties file %s\n%s" , propertiesFile, err)
220 return nil, err 241 return nil, err
221 } 242 }
222 err = json.Unmarshal(b, &result) 243 err = json.Unmarshal(b, &result)
223 if err != nil { 244 if err != nil {
224 err = fmt.Errorf("could not parse JSON from file %s\n%s\ n%s", 245 err = fmt.Errorf("could not parse JSON from file %s\n%s\ n%s",
225 propertiesFile, b, err) 246 propertiesFile, b, err)
226 } 247 }
227 } 248 }
228 return 249 return
229 } 250 }
230 251
252 func annotateTime(ctx context.Context) {
253 timestamp := clock.Get(ctx).Now().Unix()
254 annotate("CURRENT_TIMESTAMP", strconv.FormatInt(timestamp, 10))
255 }
256
231 func annotate(args ...string) { 257 func annotate(args ...string) {
232 fmt.Printf("@@@%s@@@\n", strings.Join(args, "@")) 258 fmt.Printf("@@@%s@@@\n", strings.Join(args, "@"))
233 } 259 }
OLDNEW
« no previous file with comments | « no previous file | client/cmd/kitchen/recipe.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698