pkg/config/errors.go (116 lines of code) (raw):
// Copyright 2023 Google LLC
//
// 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.
package config
import (
"fmt"
"strings"
"github.com/pkg/errors"
)
// BpError is an error wrapper to augment Path
type BpError struct {
Path Path
Err error
}
func (e BpError) Error() string {
return fmt.Sprintf("%s: %s", e.Path, e.Err)
}
func (e BpError) Unwrap() error {
return e.Err
}
// PosError is an error wrapper to augment Position
type PosError struct {
Pos Pos
Err error
}
func (e PosError) Error() string {
return fmt.Sprintf("line %d column %d: %s", e.Pos.Line, e.Pos.Column, e.Err)
}
func (e PosError) Unwrap() error {
return e.Err
}
// HintError wraps another error to suggest other values
type HintError struct {
Hint string
Err error
}
func (e HintError) Error() string {
if len(e.Hint) > 0 {
return fmt.Sprintf("%s - %s", e.Err, e.Hint)
}
return e.Err.Error()
}
func (e HintError) Unwrap() error {
return e.Err
}
// InvalidSettingError signifies a problem with the supplied setting name in a
// module definition.
type InvalidSettingError struct {
cause string
}
func (err *InvalidSettingError) Error() string {
return fmt.Sprintf("invalid setting provided to a module, cause: %v", err.cause)
}
// UnknownModuleError signifies a problem with the supplied module name.
type UnknownModuleError struct {
ID ModuleID
}
func (e UnknownModuleError) Error() string {
return fmt.Sprintf("unknown module id: %q", e.ID)
}
// Errors is an error wrapper to combine multiple errors
type Errors struct {
Errors []error
}
func (e Errors) Error() string {
errs := make([]string, len(e.Errors))
for i, err := range e.Errors {
errs[i] = err.Error()
}
return fmt.Sprintf("%d errors encountered:\n:%s", len(e.Errors), strings.Join(errs, "\n"))
}
// OrNil returns nil if there are no errors, otherwise returns itself
func (e Errors) OrNil() error {
switch len(e.Errors) {
case 0:
return nil
case 1:
return e.Errors[0]
default:
return e
}
}
func (e *Errors) addDedup(err error) {
msg := err.Error() // Do message comparison
for _, e := range e.Errors {
if msg == e.Error() {
return
}
}
e.Errors = append(e.Errors, err)
}
// Add adds an error to the Errors and returns itself
func (e *Errors) Add(err error) *Errors {
if err == nil {
return e
}
if multi, ok := err.(*Errors); ok {
for _, c := range multi.Errors {
e.addDedup(c)
}
} else {
e.addDedup(err)
}
return e
}
// At is convenience method to conditionally add an error, if one is not nil,
// augmented with a supplied Path.
func (e *Errors) At(path Path, err error) *Errors {
if err == nil {
return e
}
return e.Add(BpError{Path: path, Err: err})
}
// Any returns true if there are any errors
func (e *Errors) Any() bool {
return len(e.Errors) > 0
}
// Sentinel errors
var EmptyModuleID = errors.New("a module id cannot be empty")
var EmptyModuleSource = errors.New("a module source cannot be empty")
var InvalidModuleKind = errors.New("a module kind is invalid")
var UnknownModuleSetting = errors.New("a setting was added that is not found in the module")
var ModuleSettingWithPeriod = errors.New("a setting name contains a period, which is not supported; variable subfields cannot be set independently in a blueprint.")
var ModuleSettingInvalidChar = errors.New("a setting name must begin with a non-numeric character and all characters must be either letters, numbers, dashes ('-') or underscores ('_').")
var EmptyGroupName = errors.New("group name must be set for each deployment group")
var UnexpectedRefFormat = errors.New("Expected reference formats: $(vars.var_name) or $(module_id.output_name)")
// Error messages
const (
errMsgIntergroupOrder = string("references to outputs from other groups must be to earlier groups")
errMsgValueNotString = string("value was not of type string")
errMsgValueEmptyString = string("value is an empty string")
errMsgLabelValueReqs = string("value can only contain lowercase letters, numeric characters, underscores and dashes, and must be between 0 and 63 characters long")
)