1
0
mirror of https://github.com/prometheus-community/postgres_exporter.git synced 2025-08-08 04:42:07 +03:00

Add cross-compilation Makefile targets and tar-based releases.

Revamp the build system to be more inline with other Prometheus exporters.
Notably add Darwin and Windows build targets, and add support for releases
using tar files.
This commit is contained in:
Will Rouesnel
2017-11-30 03:15:53 +11:00
parent 61b93a17a6
commit 5b9fea01ee
98 changed files with 10599 additions and 1487 deletions

View File

@@ -12,7 +12,7 @@ import (
"strings"
"github.com/mibk/dupl/job"
"github.com/mibk/dupl/output"
"github.com/mibk/dupl/printer"
"github.com/mibk/dupl/syntax"
)
@@ -20,18 +20,18 @@ const defaultThreshold = 15
var (
paths = []string{"."}
vendor = flag.Bool("vendor", false, "check files in vendor directory")
verbose = flag.Bool("verbose", false, "explain what is being done")
threshold = flag.Int("threshold", defaultThreshold, "minimum token sequence as a clone")
files = flag.Bool("files", false, "files names from stdin")
vendor = flag.Bool("vendor", false, "")
verbose = flag.Bool("verbose", false, "")
threshold = flag.Int("threshold", defaultThreshold, "")
files = flag.Bool("files", false, "")
html = flag.Bool("html", false, "html output")
plumbing = flag.Bool("plumbing", false, "plumbing output for consumption by scripts or tools")
html = flag.Bool("html", false, "")
plumbing = flag.Bool("plumbing", false, "")
)
const (
vendorDirPrefix = "vendor" + string(filepath.Separator)
vendorDirInPath = string(filepath.Separator) + "vendor" + string(filepath.Separator)
vendorDirInPath = string(filepath.Separator) + vendorDirPrefix
)
func init() {
@@ -39,43 +39,6 @@ func init() {
flag.IntVar(threshold, "t", defaultThreshold, "alias for -threshold")
}
func usage() {
fmt.Fprintln(os.Stderr, `Usage of dupl:
dupl [flags] [paths]
Paths:
If the given path is a file, dupl will use it regardless of
the file extension. If it is a directory it will recursively
search for *.go files in that directory.
If no path is given dupl will recursively search for *.go
files in the current directory.
Flags:
-files
read file names from stdin one at each line
-html
output the results as HTML, including duplicate code fragments
-plumbing
plumbing (easy-to-parse) output for consumption by scripts or tools
-t, -threshold size
minimum token sequence size as a clone (default 15)
-vendor
check files in vendor directory
-v, -verbose
explain what is being done
Examples:
dupl -t 100
Search clones in the current directory of size at least
100 tokens.
dupl $(find app/ -name '*_test.go')
Search for clones in tests in the app directory.
find app/ -name '*_test.go' |dupl -files
The same as above.`)
os.Exit(2)
}
func main() {
flag.Usage = usage
flag.Parse()
@@ -110,7 +73,17 @@ func main() {
}
close(duplChan)
}()
printDupls(duplChan)
newPrinter := printer.NewText
if *html {
newPrinter = printer.NewHTML
} else if *plumbing {
newPrinter = printer.NewPlumbing
}
p := newPrinter(os.Stdout, ioutil.ReadFile)
if err := printDupls(p, duplChan); err != nil {
log.Fatal(err)
}
}
func filesFeed() chan string {
@@ -120,10 +93,7 @@ func filesFeed() chan string {
s := bufio.NewScanner(os.Stdin)
for s.Scan() {
f := s.Text()
if strings.HasPrefix(f, "./") {
f = f[2:]
}
fchan <- f
fchan <- strings.TrimPrefix(f, "./")
}
close(fchan)
}()
@@ -160,7 +130,7 @@ func crawlPaths(paths []string) chan string {
return fchan
}
func printDupls(duplChan <-chan syntax.Match) {
func printDupls(p printer.Printer, duplChan <-chan syntax.Match) error {
groups := make(map[string][][]*syntax.Node)
for dupl := range duplChan {
groups[dupl.Hash] = append(groups[dupl.Hash], dupl.Frags...)
@@ -171,32 +141,18 @@ func printDupls(duplChan <-chan syntax.Match) {
}
sort.Strings(keys)
p := getPrinter()
if err := p.PrintHeader(); err != nil {
return err
}
for _, k := range keys {
uniq := unique(groups[k])
if len(uniq) > 1 {
if err := p.Print(uniq); err != nil {
log.Fatal(err)
if err := p.PrintClones(uniq); err != nil {
return err
}
}
}
p.Finish()
}
func getPrinter() output.Printer {
var fr fileReader
if *html {
return output.NewHTMLPrinter(os.Stdout, fr)
} else if *plumbing {
return output.NewPlumbingPrinter(os.Stdout, fr)
}
return output.NewTextPrinter(os.Stdout, fr)
}
type fileReader struct{}
func (fileReader) ReadFile(filename string) ([]byte, error) {
return ioutil.ReadFile(filename)
return p.PrintFooter()
}
func unique(group [][]*syntax.Node) [][]*syntax.Node {
@@ -217,3 +173,39 @@ func unique(group [][]*syntax.Node) [][]*syntax.Node {
}
return newGroup
}
func usage() {
fmt.Fprintln(os.Stderr, `Usage: dupl [flags] [paths]
Paths:
If the given path is a file, dupl will use it regardless of
the file extension. If it is a directory, it will recursively
search for *.go files in that directory.
If no path is given, dupl will recursively search for *.go
files in the current directory.
Flags:
-files
read file names from stdin one at each line
-html
output the results as HTML, including duplicate code fragments
-plumbing
plumbing (easy-to-parse) output for consumption by scripts or tools
-t, -threshold size
minimum token sequence size as a clone (default 15)
-vendor
check files in vendor directory
-v, -verbose
explain what is being done
Examples:
dupl -t 100
Search clones in the current directory of size at least
100 tokens.
dupl $(find app/ -name '*_test.go')
Search for clones in tests in the app directory.
find app/ -name '*_test.go' |dupl -files
The same as above.`)
os.Exit(2)
}

120
tools/vendor/github.com/mibk/dupl/printer/html.go generated vendored Normal file
View File

@@ -0,0 +1,120 @@
package printer
import (
"bytes"
"fmt"
"io"
"regexp"
"sort"
"github.com/mibk/dupl/syntax"
)
type html struct {
iota int
w io.Writer
ReadFile
}
func NewHTML(w io.Writer, fread ReadFile) Printer {
return &html{w: w, ReadFile: fread}
}
func (p *html) PrintHeader() error {
_, err := fmt.Fprint(p.w, `<!DOCTYPE html>
<meta charset="utf-8"/>
<title>Duplicates</title>
<style>
pre {
background-color: #FFD;
border: 1px solid #E2E2E2;
padding: 1ex;
}
</style>
`)
return err
}
func (p *html) PrintClones(dups [][]*syntax.Node) error {
p.iota++
fmt.Fprintf(p.w, "<h1>#%d found %d clones</h1>\n", p.iota, len(dups))
clones := make([]clone, len(dups))
for i, dup := range dups {
cnt := len(dup)
if cnt == 0 {
panic("zero length dup")
}
nstart := dup[0]
nend := dup[cnt-1]
file, err := p.ReadFile(nstart.Filename)
if err != nil {
return err
}
lineStart, _ := blockLines(file, nstart.Pos, nend.End)
cl := clone{filename: nstart.Filename, lineStart: lineStart}
start := findLineBeg(file, nstart.Pos)
content := append(toWhitespace(file[start:nstart.Pos]), file[nstart.Pos:nend.End]...)
cl.fragment = deindent(content)
clones[i] = cl
}
sort.Sort(byNameAndLine(clones))
for _, cl := range clones {
fmt.Fprintf(p.w, "<h2>%s:%d</h2>\n<pre>%s</pre>\n", cl.filename, cl.lineStart, cl.fragment)
}
return nil
}
func (*html) PrintFooter() error { return nil }
func findLineBeg(file []byte, index int) int {
for i := index; i >= 0; i-- {
if file[i] == '\n' {
return i + 1
}
}
return 0
}
func toWhitespace(str []byte) []byte {
var out []byte
for _, c := range bytes.Runes(str) {
if c == '\t' {
out = append(out, '\t')
} else {
out = append(out, ' ')
}
}
return out
}
func deindent(block []byte) []byte {
const maxVal = 99
min := maxVal
re := regexp.MustCompile(`(^|\n)(\t*)\S`)
for _, line := range re.FindAllSubmatch(block, -1) {
indent := line[2]
if len(indent) < min {
min = len(indent)
}
}
if min == 0 || min == maxVal {
return block
}
block = block[min:]
Loop:
for i := 0; i < len(block); i++ {
if block[i] == '\n' && i != len(block)-1 {
for j := 0; j < min; j++ {
if block[i+j+1] != '\t' {
continue Loop
}
}
block = append(block[:i+1], block[i+1+min:]...)
}
}
return block
}

36
tools/vendor/github.com/mibk/dupl/printer/plumbing.go generated vendored Normal file
View File

@@ -0,0 +1,36 @@
package printer
import (
"fmt"
"io"
"sort"
"github.com/mibk/dupl/syntax"
)
type plumbing struct {
w io.Writer
ReadFile
}
func NewPlumbing(w io.Writer, fread ReadFile) Printer {
return &plumbing{w, fread}
}
func (p *plumbing) PrintHeader() error { return nil }
func (p *plumbing) PrintClones(dups [][]*syntax.Node) error {
clones, err := prepareClonesInfo(p.ReadFile, dups)
if err != nil {
return err
}
sort.Sort(byNameAndLine(clones))
for i, cl := range clones {
nextCl := clones[(i+1)%len(clones)]
fmt.Fprintf(p.w, "%s:%d-%d: duplicate of %s:%d-%d\n", cl.filename, cl.lineStart, cl.lineEnd,
nextCl.filename, nextCl.lineStart, nextCl.lineEnd)
}
return nil
}
func (p *plumbing) PrintFooter() error { return nil }

11
tools/vendor/github.com/mibk/dupl/printer/printer.go generated vendored Normal file
View File

@@ -0,0 +1,11 @@
package printer
import "github.com/mibk/dupl/syntax"
type ReadFile func(filename string) ([]byte, error)
type Printer interface {
PrintHeader() error
PrintClones(dups [][]*syntax.Node) error
PrintFooter() error
}

100
tools/vendor/github.com/mibk/dupl/printer/text.go generated vendored Normal file
View File

@@ -0,0 +1,100 @@
package printer
import (
"fmt"
"io"
"sort"
"github.com/mibk/dupl/syntax"
)
type text struct {
cnt int
w io.Writer
ReadFile
}
func NewText(w io.Writer, fread ReadFile) Printer {
return &text{w: w, ReadFile: fread}
}
func (p *text) PrintHeader() error { return nil }
func (p *text) PrintClones(dups [][]*syntax.Node) error {
p.cnt++
fmt.Fprintf(p.w, "found %d clones:\n", len(dups))
clones, err := prepareClonesInfo(p.ReadFile, dups)
if err != nil {
return err
}
sort.Sort(byNameAndLine(clones))
for _, cl := range clones {
fmt.Fprintf(p.w, " %s:%d,%d\n", cl.filename, cl.lineStart, cl.lineEnd)
}
return nil
}
func (p *text) PrintFooter() error {
_, err := fmt.Fprintf(p.w, "\nFound total %d clone groups.\n", p.cnt)
return err
}
func prepareClonesInfo(fread ReadFile, dups [][]*syntax.Node) ([]clone, error) {
clones := make([]clone, len(dups))
for i, dup := range dups {
cnt := len(dup)
if cnt == 0 {
panic("zero length dup")
}
nstart := dup[0]
nend := dup[cnt-1]
file, err := fread(nstart.Filename)
if err != nil {
return nil, err
}
cl := clone{filename: nstart.Filename}
cl.lineStart, cl.lineEnd = blockLines(file, nstart.Pos, nend.End)
clones[i] = cl
}
return clones, nil
}
func blockLines(file []byte, from, to int) (int, int) {
line := 1
lineStart, lineEnd := 0, 0
for offset, b := range file {
if b == '\n' {
line++
}
if offset == from {
lineStart = line
}
if offset == to-1 {
lineEnd = line
break
}
}
return lineStart, lineEnd
}
type clone struct {
filename string
lineStart int
lineEnd int
fragment []byte
}
type byNameAndLine []clone
func (c byNameAndLine) Len() int { return len(c) }
func (c byNameAndLine) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c byNameAndLine) Less(i, j int) bool {
if c[i].filename == c[j].filename {
return c[i].lineStart < c[j].lineStart
}
return c[i].filename < c[j].filename
}