in pkg/gcpbuildpack/builderoutput.go [71:126]
func (ctx *Context) saveErrorOutput(err error) {
var be *buildererror.Error
if !errors.As(err, &be) {
be = buildererror.Errorf(buildererror.StatusInternal, "%s", err.Error())
}
outputDir := os.Getenv(builderOutputEnv)
if outputDir == "" {
return
}
if len(be.Message) > maxMessageBytes {
be.Message = keepTail(be.Message)
}
be.BuildpackID, be.BuildpackVersion = ctx.BuildpackID(), ctx.BuildpackVersion()
bo := builderoutput.BuilderOutput{Error: *be}
bm := buildermetrics.GlobalBuilderMetrics()
bmd := buildermetadata.GlobalBuilderMetadata()
bo.Metrics = *bm
bo.Metadata = *bmd
data, err := bo.JSON()
if err != nil {
ctx.Warnf("Failed to marshal, skipping structured error output: %v", err)
return
}
if err := os.MkdirAll(outputDir, 0755); err != nil {
ctx.Warnf("Failed to create dir %s, skipping structured error output: %v", outputDir, err)
return
}
// /bin/detect steps run in parallel, so they might compete over the output file. To eliminate
// this competition, write to temp file, then `mv -f` to final location (last one in wins).
tname := filepath.Join(outputDir, fmt.Sprintf("%s-%d", builderOutputFilename, rand.Int()))
if err := ioutil.WriteFile(tname, data, 0644); err != nil {
ctx.Warnf("Failed to write %s, skipping structured error output: %v", tname, err)
return
}
fname := filepath.Join(outputDir, builderOutputFilename)
if _, err := ctx.Exec([]string{"mv", "-f", tname, fname}); err != nil {
ctx.Warnf("Failed to move %s to %s, skipping structured error output: %v", tname, fname, err)
return
}
if expected := os.Getenv(expectedBuilderOutputEnv); expected != "" {
// This logic is for acceptance tests. Ideally they would examine $BUILDER_OUTPUT themselves, but as
// currently constructed that is difficult. So instead they delegate the task of checking whether
// $BUILDER_OUTPUT contains a certain expected error-message pattern to this code.
r, err := regexp.Compile(expected)
if err == nil {
ctx.Logf("Expected pattern included in error output: %t", r.MatchString(be.Message))
} else {
ctx.Warnf("Bad regexp %q: %v", expectedBuilderOutputEnv, err)
}
}
return
}