You've already forked postgres_exporter
mirror of
https://github.com/prometheus-community/postgres_exporter.git
synced 2025-08-09 15:42:47 +03:00
This commit implements a massive refactor of the repository, and moves the build system over to use Mage (magefile.org) which should allow seamless building across multiple platforms.
248 lines
5.6 KiB
Go
248 lines
5.6 KiB
Go
// Copyright 2012 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package build
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"io"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
type importReader struct {
|
|
b *bufio.Reader
|
|
buf []byte
|
|
peek byte
|
|
err error
|
|
eof bool
|
|
nerr int
|
|
}
|
|
|
|
func isIdent(c byte) bool {
|
|
return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_' || c >= utf8.RuneSelf
|
|
}
|
|
|
|
var (
|
|
errSyntax = errors.New("syntax error")
|
|
errNUL = errors.New("unexpected NUL in input")
|
|
)
|
|
|
|
// syntaxError records a syntax error, but only if an I/O error has not already been recorded.
|
|
func (r *importReader) syntaxError() {
|
|
if r.err == nil {
|
|
r.err = errSyntax
|
|
}
|
|
}
|
|
|
|
// readByte reads the next byte from the input, saves it in buf, and returns it.
|
|
// If an error occurs, readByte records the error in r.err and returns 0.
|
|
func (r *importReader) readByte() byte {
|
|
c, err := r.b.ReadByte()
|
|
if err == nil {
|
|
r.buf = append(r.buf, c)
|
|
if c == 0 {
|
|
err = errNUL
|
|
}
|
|
}
|
|
if err != nil {
|
|
if err == io.EOF {
|
|
r.eof = true
|
|
} else if r.err == nil {
|
|
r.err = err
|
|
}
|
|
c = 0
|
|
}
|
|
return c
|
|
}
|
|
|
|
// peekByte returns the next byte from the input reader but does not advance beyond it.
|
|
// If skipSpace is set, peekByte skips leading spaces and comments.
|
|
func (r *importReader) peekByte(skipSpace bool) byte {
|
|
if r.err != nil {
|
|
if r.nerr++; r.nerr > 10000 {
|
|
panic("go/build: import reader looping")
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// Use r.peek as first input byte.
|
|
// Don't just return r.peek here: it might have been left by peekByte(false)
|
|
// and this might be peekByte(true).
|
|
c := r.peek
|
|
if c == 0 {
|
|
c = r.readByte()
|
|
}
|
|
for r.err == nil && !r.eof {
|
|
if skipSpace {
|
|
// For the purposes of this reader, semicolons are never necessary to
|
|
// understand the input and are treated as spaces.
|
|
switch c {
|
|
case ' ', '\f', '\t', '\r', '\n', ';':
|
|
c = r.readByte()
|
|
continue
|
|
|
|
case '/':
|
|
c = r.readByte()
|
|
if c == '/' {
|
|
for c != '\n' && r.err == nil && !r.eof {
|
|
c = r.readByte()
|
|
}
|
|
} else if c == '*' {
|
|
var c1 byte
|
|
for (c != '*' || c1 != '/') && r.err == nil {
|
|
if r.eof {
|
|
r.syntaxError()
|
|
}
|
|
c, c1 = c1, r.readByte()
|
|
}
|
|
} else {
|
|
r.syntaxError()
|
|
}
|
|
c = r.readByte()
|
|
continue
|
|
}
|
|
}
|
|
break
|
|
}
|
|
r.peek = c
|
|
return r.peek
|
|
}
|
|
|
|
// nextByte is like peekByte but advances beyond the returned byte.
|
|
func (r *importReader) nextByte(skipSpace bool) byte {
|
|
c := r.peekByte(skipSpace)
|
|
r.peek = 0
|
|
return c
|
|
}
|
|
|
|
// readKeyword reads the given keyword from the input.
|
|
// If the keyword is not present, readKeyword records a syntax error.
|
|
func (r *importReader) readKeyword(kw string) {
|
|
r.peekByte(true)
|
|
for i := 0; i < len(kw); i++ {
|
|
if r.nextByte(false) != kw[i] {
|
|
r.syntaxError()
|
|
return
|
|
}
|
|
}
|
|
if isIdent(r.peekByte(false)) {
|
|
r.syntaxError()
|
|
}
|
|
}
|
|
|
|
// readIdent reads an identifier from the input.
|
|
// If an identifier is not present, readIdent records a syntax error.
|
|
func (r *importReader) readIdent() {
|
|
c := r.peekByte(true)
|
|
if !isIdent(c) {
|
|
r.syntaxError()
|
|
return
|
|
}
|
|
for isIdent(r.peekByte(false)) {
|
|
r.peek = 0
|
|
}
|
|
}
|
|
|
|
// readString reads a quoted string literal from the input.
|
|
// If an identifier is not present, readString records a syntax error.
|
|
func (r *importReader) readString(save *[]string) {
|
|
switch r.nextByte(true) {
|
|
case '`':
|
|
start := len(r.buf) - 1
|
|
for r.err == nil {
|
|
if r.nextByte(false) == '`' {
|
|
if save != nil {
|
|
*save = append(*save, string(r.buf[start:]))
|
|
}
|
|
break
|
|
}
|
|
if r.eof {
|
|
r.syntaxError()
|
|
}
|
|
}
|
|
case '"':
|
|
start := len(r.buf) - 1
|
|
for r.err == nil {
|
|
c := r.nextByte(false)
|
|
if c == '"' {
|
|
if save != nil {
|
|
*save = append(*save, string(r.buf[start:]))
|
|
}
|
|
break
|
|
}
|
|
if r.eof || c == '\n' {
|
|
r.syntaxError()
|
|
}
|
|
if c == '\\' {
|
|
r.nextByte(false)
|
|
}
|
|
}
|
|
default:
|
|
r.syntaxError()
|
|
}
|
|
}
|
|
|
|
// readImport reads an import clause - optional identifier followed by quoted string -
|
|
// from the input.
|
|
func (r *importReader) readImport(imports *[]string) {
|
|
c := r.peekByte(true)
|
|
if c == '.' {
|
|
r.peek = 0
|
|
} else if isIdent(c) {
|
|
r.readIdent()
|
|
}
|
|
r.readString(imports)
|
|
}
|
|
|
|
// readComments is like ioutil.ReadAll, except that it only reads the leading
|
|
// block of comments in the file.
|
|
func readComments(f io.Reader) ([]byte, error) {
|
|
r := &importReader{b: bufio.NewReader(f)}
|
|
r.peekByte(true)
|
|
if r.err == nil && !r.eof {
|
|
// Didn't reach EOF, so must have found a non-space byte. Remove it.
|
|
r.buf = r.buf[:len(r.buf)-1]
|
|
}
|
|
return r.buf, r.err
|
|
}
|
|
|
|
// readImports is like ioutil.ReadAll, except that it expects a Go file as input
|
|
// and stops reading the input once the imports have completed.
|
|
func readImports(f io.Reader, reportSyntaxError bool, imports *[]string) ([]byte, error) {
|
|
r := &importReader{b: bufio.NewReader(f)}
|
|
|
|
r.readKeyword("package")
|
|
r.readIdent()
|
|
for r.peekByte(true) == 'i' {
|
|
r.readKeyword("import")
|
|
if r.peekByte(true) == '(' {
|
|
r.nextByte(false)
|
|
for r.peekByte(true) != ')' && r.err == nil {
|
|
r.readImport(imports)
|
|
}
|
|
r.nextByte(false)
|
|
} else {
|
|
r.readImport(imports)
|
|
}
|
|
}
|
|
|
|
// If we stopped successfully before EOF, we read a byte that told us we were done.
|
|
// Return all but that last byte, which would cause a syntax error if we let it through.
|
|
if r.err == nil && !r.eof {
|
|
return r.buf[:len(r.buf)-1], nil
|
|
}
|
|
|
|
// If we stopped for a syntax error, consume the whole file so that
|
|
// we are sure we don't change the errors that go/parser returns.
|
|
if r.err == errSyntax && !reportSyntaxError {
|
|
r.err = nil
|
|
for r.err == nil && !r.eof {
|
|
r.readByte()
|
|
}
|
|
}
|
|
|
|
return r.buf, r.err
|
|
}
|