| OLD | NEW |
| 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 "path/filepath" |
| 15 "strconv" | 16 "strconv" |
| 16 "strings" | 17 "strings" |
| 17 "syscall" | 18 "syscall" |
| 18 | 19 |
| 19 "github.com/maruel/subcommands" | 20 "github.com/maruel/subcommands" |
| 20 "golang.org/x/net/context" | 21 "golang.org/x/net/context" |
| 21 | 22 |
| 22 "github.com/luci/luci-go/common/cli" | 23 "github.com/luci/luci-go/common/cli" |
| 23 "github.com/luci/luci-go/common/clock" | 24 "github.com/luci/luci-go/common/clock" |
| 24 "github.com/luci/luci-go/common/ctxcmd" | 25 "github.com/luci/luci-go/common/ctxcmd" |
| 26 "github.com/luci/luci-go/common/flag/stringlistflag" |
| 25 ) | 27 ) |
| 26 | 28 |
| 27 // BootstrapStepName is the name of kitchen's step where it makes preparations | 29 // BootstrapStepName is the name of kitchen's step where it makes preparations |
| 28 // for running a recipe, e.g. fetches a repository. | 30 // for running a recipe, e.g. fetches a repository. |
| 29 const BootstrapStepName = "recipe bootstrap" | 31 const BootstrapStepName = "recipe bootstrap" |
| 30 | 32 |
| 31 // cmdCook checks out a repository at a revision and runs a recipe. | 33 // cmdCook checks out a repository at a revision and runs a recipe. |
| 32 var cmdCook = &subcommands.Command{ | 34 var cmdCook = &subcommands.Command{ |
| 33 UsageLine: "cook -repository <repository URL> -revision <revision> -reci
pe <recipe>", | 35 UsageLine: "cook -repository <repository URL> -revision <revision> -reci
pe <recipe>", |
| 34 ShortDesc: "Checks out a repository and runs a recipe.", | 36 ShortDesc: "Checks out a repository and runs a recipe.", |
| 35 LongDesc: "Clones or fetches a repository, checks out a revision and ru
ns a recipe", | 37 LongDesc: "Clones or fetches a repository, checks out a revision and ru
ns a recipe", |
| 36 CommandRun: func() subcommands.CommandRun { | 38 CommandRun: func() subcommands.CommandRun { |
| 37 var c cookRun | 39 var c cookRun |
| 38 fs := &c.Flags | 40 fs := &c.Flags |
| 39 fs.StringVar(&c.RepositoryURL, "repository", "", "URL of a git r
epository to fetch") | 41 fs.StringVar(&c.RepositoryURL, "repository", "", "URL of a git r
epository to fetch") |
| 40 fs.StringVar( | 42 fs.StringVar( |
| 41 &c.Revision, | 43 &c.Revision, |
| 42 "revision", | 44 "revision", |
| 43 "FETCH_HEAD", | 45 "FETCH_HEAD", |
| 44 "Git commit hash to check out.") | 46 "Git commit hash to check out.") |
| 45 fs.StringVar(&c.Recipe, "recipe", "<recipe>", "Name of the recip
e to run") | 47 fs.StringVar(&c.Recipe, "recipe", "<recipe>", "Name of the recip
e to run") |
| 48 fs.Var(&c.PythonPaths, "python-path", "Python path to include. C
an be specified multiple times.") |
| 46 fs.StringVar( | 49 fs.StringVar( |
| 47 &c.CheckoutDir, | 50 &c.CheckoutDir, |
| 48 "checkout-dir", | 51 "checkout-dir", |
| 49 "", | 52 "", |
| 50 "The directory to check out the repository to. "+ | 53 "The directory to check out the repository to. "+ |
| 51 "Defaults to ./<repo name>, where <repo name> is
the last component of -repository.") | 54 "Defaults to ./<repo name>, where <repo name> is
the last component of -repository.") |
| 52 fs.StringVar( | 55 fs.StringVar( |
| 53 &c.Workdir, | 56 &c.Workdir, |
| 54 "workdir", | 57 "workdir", |
| 55 "", | 58 "", |
| (...skipping 21 matching lines...) Expand all Loading... |
| 77 | 80 |
| 78 RepositoryURL string | 81 RepositoryURL string |
| 79 Revision string | 82 Revision string |
| 80 Recipe string | 83 Recipe string |
| 81 CheckoutDir string | 84 CheckoutDir string |
| 82 Workdir string | 85 Workdir string |
| 83 Properties string | 86 Properties string |
| 84 PropertiesFile string | 87 PropertiesFile string |
| 85 OutputResultJSONFile string | 88 OutputResultJSONFile string |
| 86 Timestamps bool | 89 Timestamps bool |
| 90 PythonPaths stringlistflag.Flag |
| 87 } | 91 } |
| 88 | 92 |
| 89 func (c *cookRun) validateFlags() error { | 93 func (c *cookRun) validateFlags() error { |
| 90 // Validate Repository. | 94 // Validate Repository. |
| 91 if c.RepositoryURL == "" { | 95 if c.RepositoryURL == "" { |
| 92 return fmt.Errorf("-repository is required") | 96 return fmt.Errorf("-repository is required") |
| 93 } | 97 } |
| 94 repoURL, err := url.Parse(c.RepositoryURL) | 98 repoURL, err := url.Parse(c.RepositoryURL) |
| 95 if err != nil { | 99 if err != nil { |
| 96 return fmt.Errorf("invalid repository %q: %s", repoURL, err) | 100 return fmt.Errorf("invalid repository %q: %s", repoURL, err) |
| (...skipping 27 matching lines...) Expand all Loading... |
| 124 | 128 |
| 125 if c.Workdir == "" { | 129 if c.Workdir == "" { |
| 126 var tempWorkdir string | 130 var tempWorkdir string |
| 127 if tempWorkdir, err = ioutil.TempDir("", "kitchen-"); err != nil
{ | 131 if tempWorkdir, err = ioutil.TempDir("", "kitchen-"); err != nil
{ |
| 128 return 0, err | 132 return 0, err |
| 129 } | 133 } |
| 130 defer os.RemoveAll(tempWorkdir) | 134 defer os.RemoveAll(tempWorkdir) |
| 131 c.Workdir = tempWorkdir | 135 c.Workdir = tempWorkdir |
| 132 } | 136 } |
| 133 | 137 |
| 138 for i, p := range c.PythonPaths { |
| 139 p := filepath.FromSlash(p) |
| 140 p, err := filepath.Abs(p) |
| 141 if err != nil { |
| 142 return 0, err |
| 143 } |
| 144 c.PythonPaths[i] = p |
| 145 } |
| 146 // Why here? It is much easier than manipulating exec.Command.Env. |
| 147 os.Setenv("PYTHONPATH", strings.Join(c.PythonPaths, string(os.PathListSe
parator))) |
| 148 |
| 134 recipe := recipeRun{ | 149 recipe := recipeRun{ |
| 135 repositoryPath: c.CheckoutDir, | 150 repositoryPath: c.CheckoutDir, |
| 136 workDir: c.Workdir, | 151 workDir: c.Workdir, |
| 137 recipe: c.Recipe, | 152 recipe: c.Recipe, |
| 138 propertiesJSON: c.Properties, | 153 propertiesJSON: c.Properties, |
| 139 propertiesFile: c.PropertiesFile, | 154 propertiesFile: c.PropertiesFile, |
| 140 outputResultJSONFile: c.OutputResultJSONFile, | 155 outputResultJSONFile: c.OutputResultJSONFile, |
| 141 timestamps: c.Timestamps, | 156 timestamps: c.Timestamps, |
| 142 } | 157 } |
| 143 recipeCmd, err := recipe.Command() | 158 recipeCmd, err := recipe.Command() |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 253 } | 268 } |
| 254 | 269 |
| 255 func annotateTime(ctx context.Context) { | 270 func annotateTime(ctx context.Context) { |
| 256 timestamp := clock.Get(ctx).Now().Unix() | 271 timestamp := clock.Get(ctx).Now().Unix() |
| 257 annotate("CURRENT_TIMESTAMP", strconv.FormatInt(timestamp, 10)) | 272 annotate("CURRENT_TIMESTAMP", strconv.FormatInt(timestamp, 10)) |
| 258 } | 273 } |
| 259 | 274 |
| 260 func annotate(args ...string) { | 275 func annotate(args ...string) { |
| 261 fmt.Printf("@@@%s@@@\n", strings.Join(args, "@")) | 276 fmt.Printf("@@@%s@@@\n", strings.Join(args, "@")) |
| 262 } | 277 } |
| OLD | NEW |