p1: /v2/scrape, /v1/fetch, auth, CLI, contract tests
Single Fetcher.Fetch on the Guard that holds DenyPrefixes. skipTlsVerification is ignored. No 502. keys add writes the secret only to --out. Release binary has no -test-allow-prefix.
This commit is contained in:
+233
@@ -0,0 +1,233 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/pelletier/go-toml/v2/unstable"
|
||||
)
|
||||
|
||||
// DecodeError represents an error encountered during the parsing or decoding
|
||||
// of a TOML document.
|
||||
//
|
||||
// In addition to the error message, it contains the position in the document
|
||||
// where it happened, as well as a human-readable representation that shows
|
||||
// where the error occurred in the document.
|
||||
type DecodeError struct {
|
||||
message string
|
||||
line int
|
||||
column int
|
||||
key Key
|
||||
|
||||
human string
|
||||
}
|
||||
|
||||
// StrictMissingError occurs in a TOML document that does not have a
|
||||
// corresponding field in the target value. It contains all the missing fields
|
||||
// in Errors.
|
||||
//
|
||||
// Emitted by Decoder when DisallowUnknownFields() was called.
|
||||
type StrictMissingError struct {
|
||||
// One error per field that could not be found.
|
||||
Errors []DecodeError
|
||||
}
|
||||
|
||||
// Error returns the canonical string for this error.
|
||||
func (s *StrictMissingError) Error() string {
|
||||
return "strict mode: fields in the document are missing in the target struct"
|
||||
}
|
||||
|
||||
// String returns a human readable description of all errors.
|
||||
func (s *StrictMissingError) String() string {
|
||||
var buf strings.Builder
|
||||
|
||||
for i, e := range s.Errors {
|
||||
if i > 0 {
|
||||
buf.WriteString("\n---\n")
|
||||
}
|
||||
buf.WriteString(e.String())
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// Unwrap returns wrapped decode errors
|
||||
//
|
||||
// Implements errors.Join() interface.
|
||||
func (s *StrictMissingError) Unwrap() []error {
|
||||
errs := make([]error, len(s.Errors))
|
||||
for i := range s.Errors {
|
||||
errs[i] = &s.Errors[i]
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
// Key represents a TOML key as a sequence of key parts.
|
||||
type Key []string
|
||||
|
||||
// Error returns the error message contained in the DecodeError.
|
||||
func (e *DecodeError) Error() string {
|
||||
return "toml: " + e.message
|
||||
}
|
||||
|
||||
// String returns the human-readable contextualized error. This string is
|
||||
// multi-line.
|
||||
func (e *DecodeError) String() string {
|
||||
return e.human
|
||||
}
|
||||
|
||||
// Position returns the (line, column) pair indicating where the error
|
||||
// occurred in the document. Positions are 1-indexed.
|
||||
func (e *DecodeError) Position() (row int, column int) {
|
||||
return e.line, e.column
|
||||
}
|
||||
|
||||
// Key that was being processed when the error occurred.
|
||||
func (e *DecodeError) Key() Key {
|
||||
return e.key
|
||||
}
|
||||
|
||||
// wrapDecodeError creates a DecodeError from a ParserError. The highlight of
|
||||
// the ParserError needs to be a subslice of the document.
|
||||
func wrapDecodeError(document []byte, de *unstable.ParserError) *DecodeError {
|
||||
if de == nil {
|
||||
return nil
|
||||
}
|
||||
return newDecodeError(document, de.Highlight, de.Key, de.Message)
|
||||
}
|
||||
|
||||
// newDecodeError creates a DecodeError pointing at the given highlight, which
|
||||
// needs to be a subslice of the document.
|
||||
func newDecodeError(document []byte, highlight []byte, key Key, message string) *DecodeError {
|
||||
offset := subsliceOffset(document, highlight)
|
||||
|
||||
errLineIdx, errColumn := positionAt(document, offset)
|
||||
|
||||
human := buildHumanContext(document, errLineIdx, errColumn, len(highlight), message)
|
||||
|
||||
return &DecodeError{
|
||||
message: message,
|
||||
line: errLineIdx + 1,
|
||||
column: errColumn,
|
||||
key: key,
|
||||
human: human,
|
||||
}
|
||||
}
|
||||
|
||||
// subsliceOffset returns the offset of the subslice b within the document.
|
||||
func subsliceOffset(document, b []byte) int {
|
||||
// Highlights are subslices of the document, which means they share the
|
||||
// same backing array, and their capacity counts the bytes between their
|
||||
// start and the end of the backing array.
|
||||
offset := cap(document) - cap(b)
|
||||
if offset < 0 || offset+len(b) > len(document) {
|
||||
panic(errors.New("highlight is not a subslice of the document"))
|
||||
}
|
||||
return offset
|
||||
}
|
||||
|
||||
// positionAt returns the 0-indexed line and the 1-indexed column of the given
|
||||
// offset in the document.
|
||||
func positionAt(document []byte, offset int) (lineIdx int, column int) {
|
||||
lineStart := 0
|
||||
for i := 0; i < offset; i++ {
|
||||
if document[i] == '\n' {
|
||||
lineIdx++
|
||||
lineStart = i + 1
|
||||
}
|
||||
}
|
||||
return lineIdx, offset - lineStart + 1
|
||||
}
|
||||
|
||||
// docLines splits the document into lines, removing the trailing newline
|
||||
// characters.
|
||||
func docLines(document []byte) []string {
|
||||
s := string(document)
|
||||
lines := strings.Split(s, "\n")
|
||||
for i, l := range lines {
|
||||
lines[i] = strings.TrimSuffix(l, "\r")
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
// buildHumanContext renders the human-readable multi-line context of an
|
||||
// error: a window of up to 3 lines before and after the error line, with
|
||||
// the error position underlined.
|
||||
func buildHumanContext(document []byte, errLineIdx, errColumn, highlightLen int, message string) string {
|
||||
lines := docLines(document)
|
||||
|
||||
const window = 3
|
||||
firstIdx := errLineIdx - window
|
||||
if firstIdx < 0 {
|
||||
firstIdx = 0
|
||||
}
|
||||
lastIdx := errLineIdx + window
|
||||
if lastIdx > len(lines)-1 {
|
||||
lastIdx = len(lines) - 1
|
||||
}
|
||||
// Empty lines at the edges of the window are dropped, unless the error
|
||||
// is about that very position.
|
||||
for firstIdx < errLineIdx && lines[firstIdx] == "" {
|
||||
firstIdx++
|
||||
}
|
||||
for lastIdx > errLineIdx && lines[lastIdx] == "" {
|
||||
lastIdx--
|
||||
}
|
||||
|
||||
// Width of the column of line numbers.
|
||||
width := len(strconv.Itoa(lastIdx + 1))
|
||||
|
||||
var buf strings.Builder
|
||||
|
||||
writeLine := func(idx int) {
|
||||
number := strconv.Itoa(idx + 1)
|
||||
for i := len(number); i < width; i++ {
|
||||
buf.WriteByte(' ')
|
||||
}
|
||||
buf.WriteString(number)
|
||||
buf.WriteByte('|')
|
||||
if len(lines[idx]) > 0 {
|
||||
buf.WriteByte(' ')
|
||||
buf.WriteString(lines[idx])
|
||||
}
|
||||
buf.WriteByte('\n')
|
||||
}
|
||||
|
||||
for idx := firstIdx; idx <= errLineIdx; idx++ {
|
||||
writeLine(idx)
|
||||
}
|
||||
|
||||
// Underline the error.
|
||||
for i := 0; i < width; i++ {
|
||||
buf.WriteByte(' ')
|
||||
}
|
||||
buf.WriteString("| ")
|
||||
for i := 1; i < errColumn; i++ {
|
||||
buf.WriteByte(' ')
|
||||
}
|
||||
// The highlight cannot extend past the end of its line.
|
||||
tildes := highlightLen
|
||||
if errLineIdx < len(lines) {
|
||||
if avail := len(lines[errLineIdx]) - errColumn + 1; tildes > avail {
|
||||
tildes = avail
|
||||
}
|
||||
}
|
||||
if tildes < 1 {
|
||||
tildes = 1
|
||||
}
|
||||
for i := 0; i < tildes; i++ {
|
||||
buf.WriteByte('~')
|
||||
}
|
||||
if message != "" {
|
||||
buf.WriteByte(' ')
|
||||
buf.WriteString(message)
|
||||
}
|
||||
buf.WriteByte('\n')
|
||||
|
||||
for idx := errLineIdx + 1; idx <= lastIdx; idx++ {
|
||||
writeLine(idx)
|
||||
}
|
||||
|
||||
return strings.TrimSuffix(buf.String(), "\n")
|
||||
}
|
||||
Reference in New Issue
Block a user