2015-01-23 23:15:10 +01:00
|
|
|
// Copyright 2014 Google Inc. All rights reserved.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2014-05-28 01:34:41 +02:00
|
|
|
package bootstrap
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"flag"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
2014-11-09 20:58:40 +01:00
|
|
|
"path/filepath"
|
2015-04-15 02:22:19 +02:00
|
|
|
"runtime"
|
2016-05-17 22:56:21 +02:00
|
|
|
"runtime/debug"
|
2015-04-21 01:41:55 +02:00
|
|
|
"runtime/pprof"
|
2016-08-05 22:59:43 +02:00
|
|
|
"runtime/trace"
|
2015-04-15 02:22:19 +02:00
|
|
|
|
|
|
|
"github.com/google/blueprint"
|
|
|
|
"github.com/google/blueprint/deptools"
|
2014-05-28 01:34:41 +02:00
|
|
|
)
|
|
|
|
|
2014-09-25 02:51:52 +02:00
|
|
|
var (
|
Simplify bootstrap
tl;dr: Read if you don't use the wrapper or use SKIP_NINJA
Previously, we were relying on the ninja behavior of restarting the
build when the build.ninja file was updated to switch between different
bootstrap stages. But that means that every step that could produce a
build.ninja must pass in order to switch to a different stage. That
wasn't a big problem when we had a two stage build -- there was very
little that could fail in the second stage before we chose to go back to
the first stage. But when we had a three stage build, it was possible to
get into a state (usually during development) where you were in the
second stage, but the build was failing because the first stage needed
to be run. This was fixed in d79f1af7423e0ef7a13573efdae5100a57fabc82
by adding a wrapper that always started building at the first stage.
But this kept all of the complexity of using ninja restarts without any
of the benefits, so this change removes that complexity and just runs
each stage sequentially in the wrapper. So the wrapper is now required.
Since we're no longer going through choosestage, we can also skip the
template parsing for the later stages that don't need to be templated --
this can save a couple of seconds for large files.
In addition to all of the above, this also lets Soong reduce the number
of times the main ninja file is loaded. We had been running the wrapper
once (3 stages), then running ninja again after combining the
Soong-generated build.ninja with the Kati-generated build.ninja. This
change lets us removing the intermediate parsing of Soong's build.ninja,
so that we only execute ninja 3 times per build. It also lets us have
dependencies on pools or rules from Kati in the primary builder, since
we're never executing the main build.ninja without the Kati build.ninja.
The wrapper has a new option, NINJA to provide the path to ninja. This
used to be hardcoded to `ninja`, and will still default to that. But
we'll be running the first two bootstrap stages with $NINJA even if
SKIP_NINJA is set.
The wrapper passes "-w dupbuild=err" to ninja now -- this really should
always be turned on if you care about reliable builds.
Change-Id: I6f656b74eb3d064b8b9e69d1d6dac1129d72b747
2016-08-13 21:42:11 +02:00
|
|
|
outFile string
|
|
|
|
depFile string
|
|
|
|
docFile string
|
|
|
|
cpuprofile string
|
2016-05-17 22:56:21 +02:00
|
|
|
memprofile string
|
Simplify bootstrap
tl;dr: Read if you don't use the wrapper or use SKIP_NINJA
Previously, we were relying on the ninja behavior of restarting the
build when the build.ninja file was updated to switch between different
bootstrap stages. But that means that every step that could produce a
build.ninja must pass in order to switch to a different stage. That
wasn't a big problem when we had a two stage build -- there was very
little that could fail in the second stage before we chose to go back to
the first stage. But when we had a three stage build, it was possible to
get into a state (usually during development) where you were in the
second stage, but the build was failing because the first stage needed
to be run. This was fixed in d79f1af7423e0ef7a13573efdae5100a57fabc82
by adding a wrapper that always started building at the first stage.
But this kept all of the complexity of using ninja restarts without any
of the benefits, so this change removes that complexity and just runs
each stage sequentially in the wrapper. So the wrapper is now required.
Since we're no longer going through choosestage, we can also skip the
template parsing for the later stages that don't need to be templated --
this can save a couple of seconds for large files.
In addition to all of the above, this also lets Soong reduce the number
of times the main ninja file is loaded. We had been running the wrapper
once (3 stages), then running ninja again after combining the
Soong-generated build.ninja with the Kati-generated build.ninja. This
change lets us removing the intermediate parsing of Soong's build.ninja,
so that we only execute ninja 3 times per build. It also lets us have
dependencies on pools or rules from Kati in the primary builder, since
we're never executing the main build.ninja without the Kati build.ninja.
The wrapper has a new option, NINJA to provide the path to ninja. This
used to be hardcoded to `ninja`, and will still default to that. But
we'll be running the first two bootstrap stages with $NINJA even if
SKIP_NINJA is set.
The wrapper passes "-w dupbuild=err" to ninja now -- this really should
always be turned on if you care about reliable builds.
Change-Id: I6f656b74eb3d064b8b9e69d1d6dac1129d72b747
2016-08-13 21:42:11 +02:00
|
|
|
traceFile string
|
|
|
|
runGoTests bool
|
2016-05-17 22:56:21 +02:00
|
|
|
noGC bool
|
2015-07-14 03:11:49 +02:00
|
|
|
|
|
|
|
BuildDir string
|
Simplify bootstrap
tl;dr: Read if you don't use the wrapper or use SKIP_NINJA
Previously, we were relying on the ninja behavior of restarting the
build when the build.ninja file was updated to switch between different
bootstrap stages. But that means that every step that could produce a
build.ninja must pass in order to switch to a different stage. That
wasn't a big problem when we had a two stage build -- there was very
little that could fail in the second stage before we chose to go back to
the first stage. But when we had a three stage build, it was possible to
get into a state (usually during development) where you were in the
second stage, but the build was failing because the first stage needed
to be run. This was fixed in d79f1af7423e0ef7a13573efdae5100a57fabc82
by adding a wrapper that always started building at the first stage.
But this kept all of the complexity of using ninja restarts without any
of the benefits, so this change removes that complexity and just runs
each stage sequentially in the wrapper. So the wrapper is now required.
Since we're no longer going through choosestage, we can also skip the
template parsing for the later stages that don't need to be templated --
this can save a couple of seconds for large files.
In addition to all of the above, this also lets Soong reduce the number
of times the main ninja file is loaded. We had been running the wrapper
once (3 stages), then running ninja again after combining the
Soong-generated build.ninja with the Kati-generated build.ninja. This
change lets us removing the intermediate parsing of Soong's build.ninja,
so that we only execute ninja 3 times per build. It also lets us have
dependencies on pools or rules from Kati in the primary builder, since
we're never executing the main build.ninja without the Kati build.ninja.
The wrapper has a new option, NINJA to provide the path to ninja. This
used to be hardcoded to `ninja`, and will still default to that. But
we'll be running the first two bootstrap stages with $NINJA even if
SKIP_NINJA is set.
The wrapper passes "-w dupbuild=err" to ninja now -- this really should
always be turned on if you care about reliable builds.
Change-Id: I6f656b74eb3d064b8b9e69d1d6dac1129d72b747
2016-08-13 21:42:11 +02:00
|
|
|
SrcDir string
|
2014-09-25 02:51:52 +02:00
|
|
|
)
|
2014-05-28 01:34:41 +02:00
|
|
|
|
|
|
|
func init() {
|
2017-07-19 04:37:37 +02:00
|
|
|
flag.StringVar(&outFile, "o", "build.ninja", "the Ninja file to output")
|
2015-07-14 03:11:49 +02:00
|
|
|
flag.StringVar(&BuildDir, "b", ".", "the build output directory")
|
2014-05-28 01:34:41 +02:00
|
|
|
flag.StringVar(&depFile, "d", "", "the dependency file to output")
|
2015-05-13 23:36:24 +02:00
|
|
|
flag.StringVar(&docFile, "docs", "", "build documentation file to output")
|
2014-09-25 02:51:52 +02:00
|
|
|
flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to file")
|
2016-08-05 22:59:43 +02:00
|
|
|
flag.StringVar(&traceFile, "trace", "", "write trace to file")
|
2016-05-17 22:56:21 +02:00
|
|
|
flag.StringVar(&memprofile, "memprofile", "", "write memory profile to file")
|
|
|
|
flag.BoolVar(&noGC, "nogc", false, "turn off GC for debugging")
|
2015-06-24 02:21:00 +02:00
|
|
|
flag.BoolVar(&runGoTests, "t", false, "build and run go tests during bootstrap")
|
2014-05-28 01:34:41 +02:00
|
|
|
}
|
|
|
|
|
2014-06-27 00:34:06 +02:00
|
|
|
func Main(ctx *blueprint.Context, config interface{}, extraNinjaFileDeps ...string) {
|
2014-05-28 01:34:41 +02:00
|
|
|
if !flag.Parsed() {
|
|
|
|
flag.Parse()
|
|
|
|
}
|
|
|
|
|
2015-04-15 02:22:19 +02:00
|
|
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
|
|
|
|
2016-05-17 22:56:21 +02:00
|
|
|
if noGC {
|
|
|
|
debug.SetGCPercent(-1)
|
|
|
|
}
|
|
|
|
|
2014-09-25 02:51:52 +02:00
|
|
|
if cpuprofile != "" {
|
|
|
|
f, err := os.Create(cpuprofile)
|
|
|
|
if err != nil {
|
|
|
|
fatalf("error opening cpuprofile: %s", err)
|
|
|
|
}
|
|
|
|
pprof.StartCPUProfile(f)
|
|
|
|
defer f.Close()
|
|
|
|
defer pprof.StopCPUProfile()
|
|
|
|
}
|
|
|
|
|
2016-08-05 22:59:43 +02:00
|
|
|
if traceFile != "" {
|
|
|
|
f, err := os.Create(traceFile)
|
|
|
|
if err != nil {
|
|
|
|
fatalf("error opening trace: %s", err)
|
|
|
|
}
|
|
|
|
trace.Start(f)
|
|
|
|
defer f.Close()
|
|
|
|
defer trace.Stop()
|
|
|
|
}
|
|
|
|
|
2014-05-28 01:34:41 +02:00
|
|
|
if flag.NArg() != 1 {
|
|
|
|
fatalf("no Blueprints file specified")
|
|
|
|
}
|
|
|
|
|
Simplify bootstrap
tl;dr: Read if you don't use the wrapper or use SKIP_NINJA
Previously, we were relying on the ninja behavior of restarting the
build when the build.ninja file was updated to switch between different
bootstrap stages. But that means that every step that could produce a
build.ninja must pass in order to switch to a different stage. That
wasn't a big problem when we had a two stage build -- there was very
little that could fail in the second stage before we chose to go back to
the first stage. But when we had a three stage build, it was possible to
get into a state (usually during development) where you were in the
second stage, but the build was failing because the first stage needed
to be run. This was fixed in d79f1af7423e0ef7a13573efdae5100a57fabc82
by adding a wrapper that always started building at the first stage.
But this kept all of the complexity of using ninja restarts without any
of the benefits, so this change removes that complexity and just runs
each stage sequentially in the wrapper. So the wrapper is now required.
Since we're no longer going through choosestage, we can also skip the
template parsing for the later stages that don't need to be templated --
this can save a couple of seconds for large files.
In addition to all of the above, this also lets Soong reduce the number
of times the main ninja file is loaded. We had been running the wrapper
once (3 stages), then running ninja again after combining the
Soong-generated build.ninja with the Kati-generated build.ninja. This
change lets us removing the intermediate parsing of Soong's build.ninja,
so that we only execute ninja 3 times per build. It also lets us have
dependencies on pools or rules from Kati in the primary builder, since
we're never executing the main build.ninja without the Kati build.ninja.
The wrapper has a new option, NINJA to provide the path to ninja. This
used to be hardcoded to `ninja`, and will still default to that. But
we'll be running the first two bootstrap stages with $NINJA even if
SKIP_NINJA is set.
The wrapper passes "-w dupbuild=err" to ninja now -- this really should
always be turned on if you care about reliable builds.
Change-Id: I6f656b74eb3d064b8b9e69d1d6dac1129d72b747
2016-08-13 21:42:11 +02:00
|
|
|
SrcDir = filepath.Dir(flag.Arg(0))
|
|
|
|
|
Enhance bootstrap stage selection
This simplifies the bootstrap process while making it more flexible by
moving the stage selection into a go binary(choosestage). It will now be
possible to have more than two build stages.
Now each stage has a ninja template(main.ninja.in) and a timestamp
file(main.ninja.in.timestamp). The timestamp file may be updated by any
build stage that wishes to regenerate the ninja template. If the
choosestage binaries sees that the timestamp is newer than the template,
it will choose the prior stage.
The main stage no longer writes to the source tree to update the
build.ninja.in file. This was a problem for read-only source trees.
Instead, the choosestage binary first checks to see if that file is
newer than the last bootstrap.ninja.in, copies it in place, and starts
the boostrap stage.
The bootstrap stage regenerates it's own ninja template, but that
required a loop through the main stage to actually run it. The
choosestage binary now detects if the template has changed for the
current stage, and will restart the stage.
One change is that if dependencies do get messed up, instead of silently
failing, there's a higher chance that the bootstrap step will just
continue looping, doing nothing. This can happen if the main stage
has a dependency that triggers the bootstrap stage, but the bootstrap
stage doesn't see anything required to rebuild the main ninja file. A
side effect of this requirement is that changes to test code will now
rebuild the main ninja file.
Change-Id: I9965cfba79dc0dbbd3af05f5944f7653054455a2
2015-07-23 02:05:59 +02:00
|
|
|
stage := StageMain
|
2015-06-25 04:21:21 +02:00
|
|
|
if c, ok := config.(ConfigInterface); ok {
|
2015-07-23 02:06:06 +02:00
|
|
|
if c.GeneratingPrimaryBuilder() {
|
|
|
|
stage = StagePrimary
|
|
|
|
}
|
2015-06-25 04:21:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bootstrapConfig := &Config{
|
Enhance bootstrap stage selection
This simplifies the bootstrap process while making it more flexible by
moving the stage selection into a go binary(choosestage). It will now be
possible to have more than two build stages.
Now each stage has a ninja template(main.ninja.in) and a timestamp
file(main.ninja.in.timestamp). The timestamp file may be updated by any
build stage that wishes to regenerate the ninja template. If the
choosestage binaries sees that the timestamp is newer than the template,
it will choose the prior stage.
The main stage no longer writes to the source tree to update the
build.ninja.in file. This was a problem for read-only source trees.
Instead, the choosestage binary first checks to see if that file is
newer than the last bootstrap.ninja.in, copies it in place, and starts
the boostrap stage.
The bootstrap stage regenerates it's own ninja template, but that
required a loop through the main stage to actually run it. The
choosestage binary now detects if the template has changed for the
current stage, and will restart the stage.
One change is that if dependencies do get messed up, instead of silently
failing, there's a higher chance that the bootstrap step will just
continue looping, doing nothing. This can happen if the main stage
has a dependency that triggers the bootstrap stage, but the bootstrap
stage doesn't see anything required to rebuild the main ninja file. A
side effect of this requirement is that changes to test code will now
rebuild the main ninja file.
Change-Id: I9965cfba79dc0dbbd3af05f5944f7653054455a2
2015-07-23 02:05:59 +02:00
|
|
|
stage: stage,
|
2015-06-25 04:21:21 +02:00
|
|
|
topLevelBlueprintsFile: flag.Arg(0),
|
2015-06-24 02:21:00 +02:00
|
|
|
runGoTests: runGoTests,
|
2015-06-25 04:21:21 +02:00
|
|
|
}
|
|
|
|
|
2015-07-25 01:53:27 +02:00
|
|
|
ctx.RegisterBottomUpMutator("bootstrap_plugin_deps", pluginDeps)
|
2015-06-25 04:21:21 +02:00
|
|
|
ctx.RegisterModuleType("bootstrap_go_package", newGoPackageModuleFactory(bootstrapConfig))
|
2017-07-20 04:22:34 +02:00
|
|
|
ctx.RegisterModuleType("bootstrap_go_binary", newGoBinaryModuleFactory(bootstrapConfig, false))
|
|
|
|
ctx.RegisterModuleType("blueprint_go_binary", newGoBinaryModuleFactory(bootstrapConfig, true))
|
2015-06-25 04:21:21 +02:00
|
|
|
ctx.RegisterSingletonType("bootstrap", newSingletonFactory(bootstrapConfig))
|
2014-05-28 01:34:41 +02:00
|
|
|
|
2016-11-01 19:10:51 +01:00
|
|
|
ctx.RegisterSingletonType("glob", globSingletonFactory(ctx))
|
|
|
|
|
2015-06-25 04:21:21 +02:00
|
|
|
deps, errs := ctx.ParseBlueprintsFiles(bootstrapConfig.topLevelBlueprintsFile)
|
2014-05-28 01:34:41 +02:00
|
|
|
if len(errs) > 0 {
|
|
|
|
fatalErrors(errs)
|
|
|
|
}
|
|
|
|
|
2014-06-27 00:34:06 +02:00
|
|
|
// Add extra ninja file dependencies
|
|
|
|
deps = append(deps, extraNinjaFileDeps...)
|
|
|
|
|
2015-05-13 23:36:24 +02:00
|
|
|
errs = ctx.ResolveDependencies(config)
|
|
|
|
if len(errs) > 0 {
|
|
|
|
fatalErrors(errs)
|
|
|
|
}
|
|
|
|
|
|
|
|
if docFile != "" {
|
|
|
|
err := writeDocs(ctx, filepath.Dir(bootstrapConfig.topLevelBlueprintsFile), docFile)
|
|
|
|
if err != nil {
|
|
|
|
fatalErrors([]error{err})
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2014-06-26 02:21:54 +02:00
|
|
|
extraDeps, errs := ctx.PrepareBuildActions(config)
|
2014-05-28 01:34:41 +02:00
|
|
|
if len(errs) > 0 {
|
|
|
|
fatalErrors(errs)
|
|
|
|
}
|
2014-06-26 02:21:54 +02:00
|
|
|
deps = append(deps, extraDeps...)
|
|
|
|
|
2014-05-28 01:34:41 +02:00
|
|
|
buf := bytes.NewBuffer(nil)
|
|
|
|
err := ctx.WriteBuildFile(buf)
|
|
|
|
if err != nil {
|
|
|
|
fatalf("error generating Ninja file contents: %s", err)
|
|
|
|
}
|
|
|
|
|
2014-06-06 05:00:22 +02:00
|
|
|
const outFilePermissions = 0666
|
Enhance bootstrap stage selection
This simplifies the bootstrap process while making it more flexible by
moving the stage selection into a go binary(choosestage). It will now be
possible to have more than two build stages.
Now each stage has a ninja template(main.ninja.in) and a timestamp
file(main.ninja.in.timestamp). The timestamp file may be updated by any
build stage that wishes to regenerate the ninja template. If the
choosestage binaries sees that the timestamp is newer than the template,
it will choose the prior stage.
The main stage no longer writes to the source tree to update the
build.ninja.in file. This was a problem for read-only source trees.
Instead, the choosestage binary first checks to see if that file is
newer than the last bootstrap.ninja.in, copies it in place, and starts
the boostrap stage.
The bootstrap stage regenerates it's own ninja template, but that
required a loop through the main stage to actually run it. The
choosestage binary now detects if the template has changed for the
current stage, and will restart the stage.
One change is that if dependencies do get messed up, instead of silently
failing, there's a higher chance that the bootstrap step will just
continue looping, doing nothing. This can happen if the main stage
has a dependency that triggers the bootstrap stage, but the bootstrap
stage doesn't see anything required to rebuild the main ninja file. A
side effect of this requirement is that changes to test code will now
rebuild the main ninja file.
Change-Id: I9965cfba79dc0dbbd3af05f5944f7653054455a2
2015-07-23 02:05:59 +02:00
|
|
|
err = ioutil.WriteFile(outFile, buf.Bytes(), outFilePermissions)
|
|
|
|
if err != nil {
|
|
|
|
fatalf("error writing %s: %s", outFile, err)
|
|
|
|
}
|
|
|
|
|
2014-05-28 01:34:41 +02:00
|
|
|
if depFile != "" {
|
2014-10-14 10:30:17 +02:00
|
|
|
err := deptools.WriteDepFile(depFile, outFile, deps)
|
2014-05-28 01:34:41 +02:00
|
|
|
if err != nil {
|
|
|
|
fatalf("error writing depfile: %s", err)
|
|
|
|
}
|
|
|
|
}
|
2014-10-28 06:34:56 +01:00
|
|
|
|
2015-11-18 01:16:58 +01:00
|
|
|
if c, ok := config.(ConfigRemoveAbandonedFiles); !ok || c.RemoveAbandonedFiles() {
|
Simplify bootstrap
tl;dr: Read if you don't use the wrapper or use SKIP_NINJA
Previously, we were relying on the ninja behavior of restarting the
build when the build.ninja file was updated to switch between different
bootstrap stages. But that means that every step that could produce a
build.ninja must pass in order to switch to a different stage. That
wasn't a big problem when we had a two stage build -- there was very
little that could fail in the second stage before we chose to go back to
the first stage. But when we had a three stage build, it was possible to
get into a state (usually during development) where you were in the
second stage, but the build was failing because the first stage needed
to be run. This was fixed in d79f1af7423e0ef7a13573efdae5100a57fabc82
by adding a wrapper that always started building at the first stage.
But this kept all of the complexity of using ninja restarts without any
of the benefits, so this change removes that complexity and just runs
each stage sequentially in the wrapper. So the wrapper is now required.
Since we're no longer going through choosestage, we can also skip the
template parsing for the later stages that don't need to be templated --
this can save a couple of seconds for large files.
In addition to all of the above, this also lets Soong reduce the number
of times the main ninja file is loaded. We had been running the wrapper
once (3 stages), then running ninja again after combining the
Soong-generated build.ninja with the Kati-generated build.ninja. This
change lets us removing the intermediate parsing of Soong's build.ninja,
so that we only execute ninja 3 times per build. It also lets us have
dependencies on pools or rules from Kati in the primary builder, since
we're never executing the main build.ninja without the Kati build.ninja.
The wrapper has a new option, NINJA to provide the path to ninja. This
used to be hardcoded to `ninja`, and will still default to that. But
we'll be running the first two bootstrap stages with $NINJA even if
SKIP_NINJA is set.
The wrapper passes "-w dupbuild=err" to ninja now -- this really should
always be turned on if you care about reliable builds.
Change-Id: I6f656b74eb3d064b8b9e69d1d6dac1129d72b747
2016-08-13 21:42:11 +02:00
|
|
|
err := removeAbandonedFiles(ctx, bootstrapConfig, SrcDir)
|
2015-11-18 01:16:58 +01:00
|
|
|
if err != nil {
|
|
|
|
fatalf("error removing abandoned files: %s", err)
|
|
|
|
}
|
2014-10-28 06:34:56 +01:00
|
|
|
}
|
2016-05-17 22:56:21 +02:00
|
|
|
|
|
|
|
if memprofile != "" {
|
|
|
|
f, err := os.Create(memprofile)
|
|
|
|
if err != nil {
|
|
|
|
fatalf("error opening memprofile: %s", err)
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
pprof.WriteHeapProfile(f)
|
|
|
|
}
|
2014-05-28 01:34:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func fatalf(format string, args ...interface{}) {
|
2014-06-06 05:00:22 +02:00
|
|
|
fmt.Printf(format, args...)
|
2015-08-21 23:47:06 +02:00
|
|
|
fmt.Print("\n")
|
2014-05-28 01:34:41 +02:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
func fatalErrors(errs []error) {
|
2016-01-07 20:16:48 +01:00
|
|
|
red := "\x1b[31m"
|
|
|
|
unred := "\x1b[0m"
|
|
|
|
|
2014-05-28 01:34:41 +02:00
|
|
|
for _, err := range errs {
|
2016-01-07 20:16:48 +01:00
|
|
|
switch err := err.(type) {
|
2016-10-08 02:13:10 +02:00
|
|
|
case *blueprint.BlueprintError,
|
|
|
|
*blueprint.ModuleError,
|
|
|
|
*blueprint.PropertyError:
|
2016-01-07 20:16:48 +01:00
|
|
|
fmt.Printf("%serror:%s %s\n", red, unred, err.Error())
|
2014-05-28 01:34:41 +02:00
|
|
|
default:
|
2016-01-07 20:16:48 +01:00
|
|
|
fmt.Printf("%sinternal error:%s %s\n", red, unred, err)
|
2014-05-28 01:34:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
os.Exit(1)
|
|
|
|
}
|