blob: 84723c929d9d0982b3b5b91621baf142671cde41 [file] [log] [blame]
// Copyright 2016 The LUCI Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package main
import (
"context"
"flag"
"os"
"os/signal"
"strings"
"github.com/maruel/subcommands"
"go.chromium.org/luci/common/cli"
"go.chromium.org/luci/common/data/rand/mathrand"
"go.chromium.org/luci/common/errors"
log "go.chromium.org/luci/common/logging"
"go.chromium.org/luci/common/logging/gologger"
"infra/tools/kitchen/build"
)
var logConfig = log.Config{
Level: log.Info,
}
var application = cli.Application{
Name: "kitchen",
Title: "Kitchen. It can run a recipe.",
Context: func(ctx context.Context) context.Context {
cfg := gologger.LoggerConfig{
Out: os.Stderr,
Format: "[%{level:.1s} %{time:2006-01-02 15:04:05}] %{message}",
}
ctx = cfg.Use(ctx)
ctx = logConfig.Set(ctx)
return handleInterruption(ctx)
},
Commands: []*subcommands.Command{
subcommands.CmdHelp,
cmdCook,
},
}
func main() {
mathrand.SeedRandomly()
logConfig.AddFlags(flag.CommandLine)
flag.Parse()
os.Exit(subcommands.Run(&application, flag.Args()))
}
// handleInterruption cancels the context on first SIGTERM and
// exits the process on a second SIGTERM.
func handleInterruption(ctx context.Context) context.Context {
ctx, cancel := context.WithCancel(ctx)
signalC := make(chan os.Signal)
signal.Notify(signalC, os.Interrupt)
go func() {
<-signalC
cancel()
<-signalC
os.Exit(1)
}()
return ctx
}
// logAnnotatedErr logs the full stack trace from an annotated error to the
// installed logger at error level.
func logAnnotatedErr(ctx context.Context, err error) {
if err == nil {
return
}
log.Errorf(ctx, "Annotated error stack:\n%s",
strings.Join(errors.RenderStack(err), "\n"))
}
// infraFailure converts an error to a build.InfraFailure protobuf message.
// TODO(nodir): delete this function.
func infraFailure(err error) *build.InfraFailure {
failure := &build.InfraFailure{
Text: err.Error(),
}
if errors.Unwrap(err) == context.Canceled {
failure.Type = build.InfraFailure_CANCELED
} else {
failure.Type = build.InfraFailure_BOOTSTRAPPER_ERROR
failure.BootstrapperCallStack = errors.RenderStack(err)
}
return failure
}