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

Refactor repository layout and convert build system to Mage.

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.
This commit is contained in:
Will Rouesnel
2018-02-23 01:55:49 +11:00
parent 3e6cf08dc5
commit 989489096e
269 changed files with 35309 additions and 2017 deletions

42
vendor/github.com/magefile/mage/CONTRIBUTING.md generated vendored Normal file
View File

@@ -0,0 +1,42 @@
# Contributing
Of course, contributions are more than welcome. Please read these guidelines for
making the process as painless as possible.
## Discussion
Development discussion should take place on the #mage channel of [gopher
slack](https://gophers.slack.com/).
There is a separate #mage-dev channel that has the github app to post github
activity to the channel, to make it easy to follow.
## Issues
If there's an issue you'd like to work on, please comment on it, so we can
discuss approach, etc. and make sure no one else is currently working on that
issue.
Please always create an issue before sending a PR unless it's an obvious typo
or other trivial change.
## Dependency Management
Currently mage has no dependencies(!) outside the standard libary. Let's keep
it that way. Since it's likely that mage will be vendored into a project,
adding dependencies to mage adds dependencies to every project that uses mage.
## Versions
Please avoid using features of go and the stdlib that prevent mage from being
buildable with older versions of Go. The CI tests currently check that mage is
buildable with go 1.7 and later. You may build with whatever version you like,
but CI has the final say.
## Testing
Please write tests for any new features. Tests must use the normal go testing
package.
Tests must pass the race detector (run `go test -race ./...`).

9
vendor/github.com/magefile/mage/Gopkg.lock generated vendored Normal file
View File

@@ -0,0 +1,9 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "ab4fef131ee828e96ba67d31a7d690bd5f2f42040c6766b1b12fe856f87e0ff7"
solver-name = "gps-cdcl"
solver-version = 1

22
vendor/github.com/magefile/mage/Gopkg.toml generated vendored Normal file
View File

@@ -0,0 +1,22 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"

201
vendor/github.com/magefile/mage/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
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.

61
vendor/github.com/magefile/mage/README.md generated vendored Normal file
View File

@@ -0,0 +1,61 @@
<p align="center"><img src="https://user-images.githubusercontent.com/3185864/32058716-5ee9b512-ba38-11e7-978a-287eb2a62743.png"/></p>
## About [![Build Status](https://travis-ci.org/magefile/mage.svg?branch=master)](https://travis-ci.org/magefile/mage)
Mage is a make/rake-like build tool using Go. You write plain-old go functions,
and Mage automatically uses them as Makefile-like runnable targets.
## Installation
Mage has no dependencies outside the Go standard library, and builds with Go 1.7
and above (possibly even lower versions, but they're not regularly tested).
Install mage by running
```
go get -u -d github.com/magefile/mage
cd $GOPATH/src/github.com/magefile/mage
go run bootstrap.go
```
This will download the code into your GOPATH, and then run the bootstrap script
to build mage with version infomation embedded in it. A normal `go get`
(without -d) will build the binary correctly, but no version info will be
embedded. If you've done this, no worries, just go to
$GOPATH/src/github.com/magefile/mage and run `mage install` or `go run
bootstrap.go` and a new binary will be created with the correct version
information.
The mage binary will be created in your $GOPATH/bin directory.
You may also install a binary release from our
[releases](https://github.com/magefile/mage/releases) page.
## Demo
[![Mage Demo](https://img.youtube.com/vi/GOqbD0lF-iA/maxresdefault.jpg)](https://www.youtube.com/watch?v=GOqbD0lF-iA)
## Discussion
Join the `#mage` channel on [gophers slack](https://gophers.slack.com/messages/general/) for discussion of usage, development, etc.
# Documentation
see [magefile.org](https://magefile.org) for full docs
see [godoc.org/github.com/magefile/mage/mage](https://godoc.org/github.com/magefile/mage/mage) for how to use mage as a library.
# Why?
Makefiles are hard to read and hard to write. Mostly because makefiles are essentially fancy bash scripts with significant white space and additional make-related syntax.
Mage lets you have multiple magefiles, name your magefiles whatever you
want, and they're easy to customize for multiple operating systems. Mage has no
dependencies (aside from go) and runs just fine on all major operating systems, whereas make generally uses bash which is not well supported on Windows.
Go is superior to bash for any non-trivial task involving branching, looping, anything that's not just straight line execution of commands. And if your project is written in Go, why introduce another
language as idiosyncratic as bash? Why not use the language your contributors
are already comfortable with?
# TODO
* File conversion tasks

19
vendor/github.com/magefile/mage/bootstrap.go generated vendored Normal file
View File

@@ -0,0 +1,19 @@
//+build ignore
package main
import (
"os"
"github.com/magefile/mage/mage"
)
// This is a bootstrap builder, to build mage when you don't already *have* mage.
// Run it like
// go run bootstrap.go
// and it will install mage with all the right flags created for you.
func main() {
os.Args = []string{os.Args[0], "-v", "install"}
os.Exit(mage.Main())
}

1655
vendor/github.com/magefile/mage/build/build.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

166
vendor/github.com/magefile/mage/build/doc.go generated vendored Normal file
View File

@@ -0,0 +1,166 @@
// Copyright 2011 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 gathers information about Go packages.
//
// Go Path
//
// The Go path is a list of directory trees containing Go source code.
// It is consulted to resolve imports that cannot be found in the standard
// Go tree. The default path is the value of the GOPATH environment
// variable, interpreted as a path list appropriate to the operating system
// (on Unix, the variable is a colon-separated string;
// on Windows, a semicolon-separated string;
// on Plan 9, a list).
//
// Each directory listed in the Go path must have a prescribed structure:
//
// The src/ directory holds source code. The path below 'src' determines
// the import path or executable name.
//
// The pkg/ directory holds installed package objects.
// As in the Go tree, each target operating system and
// architecture pair has its own subdirectory of pkg
// (pkg/GOOS_GOARCH).
//
// If DIR is a directory listed in the Go path, a package with
// source in DIR/src/foo/bar can be imported as "foo/bar" and
// has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a"
// (or, for gccgo, "DIR/pkg/gccgo/foo/libbar.a").
//
// The bin/ directory holds compiled commands.
// Each command is named for its source directory, but only
// using the final element, not the entire path. That is, the
// command with source in DIR/src/foo/quux is installed into
// DIR/bin/quux, not DIR/bin/foo/quux. The foo/ is stripped
// so that you can add DIR/bin to your PATH to get at the
// installed commands.
//
// Here's an example directory layout:
//
// GOPATH=/home/user/gocode
//
// /home/user/gocode/
// src/
// foo/
// bar/ (go code in package bar)
// x.go
// quux/ (go code in package main)
// y.go
// bin/
// quux (installed command)
// pkg/
// linux_amd64/
// foo/
// bar.a (installed package object)
//
// Build Constraints
//
// A build constraint, also known as a build tag, is a line comment that begins
//
// // +build
//
// that lists the conditions under which a file should be included in the package.
// Constraints may appear in any kind of source file (not just Go), but
// they must appear near the top of the file, preceded
// only by blank lines and other line comments. These rules mean that in Go
// files a build constraint must appear before the package clause.
//
// To distinguish build constraints from package documentation, a series of
// build constraints must be followed by a blank line.
//
// A build constraint is evaluated as the OR of space-separated options;
// each option evaluates as the AND of its comma-separated terms;
// and each term is an alphanumeric word or, preceded by !, its negation.
// That is, the build constraint:
//
// // +build linux,386 darwin,!cgo
//
// corresponds to the boolean formula:
//
// (linux AND 386) OR (darwin AND (NOT cgo))
//
// A file may have multiple build constraints. The overall constraint is the AND
// of the individual constraints. That is, the build constraints:
//
// // +build linux darwin
// // +build 386
//
// corresponds to the boolean formula:
//
// (linux OR darwin) AND 386
//
// During a particular build, the following words are satisfied:
//
// - the target operating system, as spelled by runtime.GOOS
// - the target architecture, as spelled by runtime.GOARCH
// - the compiler being used, either "gc" or "gccgo"
// - "cgo", if ctxt.CgoEnabled is true
// - "go1.1", from Go version 1.1 onward
// - "go1.2", from Go version 1.2 onward
// - "go1.3", from Go version 1.3 onward
// - "go1.4", from Go version 1.4 onward
// - "go1.5", from Go version 1.5 onward
// - "go1.6", from Go version 1.6 onward
// - "go1.7", from Go version 1.7 onward
// - "go1.8", from Go version 1.8 onward
// - "go1.9", from Go version 1.9 onward
// - any additional words listed in ctxt.BuildTags
//
// If a file's name, after stripping the extension and a possible _test suffix,
// matches any of the following patterns:
// *_GOOS
// *_GOARCH
// *_GOOS_GOARCH
// (example: source_windows_amd64.go) where GOOS and GOARCH represent
// any known operating system and architecture values respectively, then
// the file is considered to have an implicit build constraint requiring
// those terms (in addition to any explicit constraints in the file).
//
// To keep a file from being considered for the build:
//
// // +build ignore
//
// (any other unsatisfied word will work as well, but ``ignore'' is conventional.)
//
// To build a file only when using cgo, and only on Linux and OS X:
//
// // +build linux,cgo darwin,cgo
//
// Such a file is usually paired with another file implementing the
// default functionality for other systems, which in this case would
// carry the constraint:
//
// // +build !linux,!darwin !cgo
//
// Naming a file dns_windows.go will cause it to be included only when
// building the package for Windows; similarly, math_386.s will be included
// only when building the package for 32-bit x86.
//
// Using GOOS=android matches build tags and files as for GOOS=linux
// in addition to android tags and files.
//
// Binary-Only Packages
//
// It is possible to distribute packages in binary form without including the
// source code used for compiling the package. To do this, the package must
// be distributed with a source file not excluded by build constraints and
// containing a "//go:binary-only-package" comment.
// Like a build constraint, this comment must appear near the top of the file,
// preceded only by blank lines and other line comments and with a blank line
// following the comment, to separate it from the package documentation.
// Unlike build constraints, this comment is only recognized in non-test
// Go source files.
//
// The minimal source code for a binary-only package is therefore:
//
// //go:binary-only-package
//
// package mypkg
//
// The source code may include additional Go code. That code is never compiled
// but will be processed by tools like godoc and might be useful as end-user
// documentation.
//
package build

247
vendor/github.com/magefile/mage/build/read.go generated vendored Normal file
View File

@@ -0,0 +1,247 @@
// 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
}

8
vendor/github.com/magefile/mage/build/syslist.go generated vendored Normal file
View File

@@ -0,0 +1,8 @@
// Copyright 2011 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
const goosList = "android darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris windows zos "
const goarchList = "386 amd64 amd64p32 arm armbe arm64 arm64be ppc64 ppc64le mips mipsle mips64 mips64le mips64p32 mips64p32le ppc s390 s390x sparc sparc64 "

37
vendor/github.com/magefile/mage/build/zcgo.go generated vendored Normal file
View File

@@ -0,0 +1,37 @@
// auto generated by go tool dist
package build
const defaultCGO_ENABLED = ""
var cgoEnabled = map[string]bool{
"android/386": true,
"android/amd64": true,
"android/arm": true,
"android/arm64": true,
"darwin/386": true,
"darwin/amd64": true,
"darwin/arm": true,
"darwin/arm64": true,
"dragonfly/amd64": true,
"freebsd/386": true,
"freebsd/amd64": true,
"linux/386": true,
"linux/amd64": true,
"linux/arm": true,
"linux/arm64": true,
"linux/mips": true,
"linux/mips64": true,
"linux/mips64le": true,
"linux/mipsle": true,
"linux/ppc64le": true,
"linux/s390x": true,
"netbsd/386": true,
"netbsd/amd64": true,
"netbsd/arm": true,
"openbsd/386": true,
"openbsd/amd64": true,
"solaris/amd64": true,
"windows/386": true,
"windows/amd64": true,
}

16
vendor/github.com/magefile/mage/mage/command_string.go generated vendored Normal file
View File

@@ -0,0 +1,16 @@
// Code generated by "stringer -type=Command"; DO NOT EDIT.
package mage
import "fmt"
const _Command_name = "NoneVersionInitClean"
var _Command_index = [...]uint8{0, 4, 11, 15, 20}
func (i Command) String() string {
if i < 0 || i >= Command(len(_Command_index)-1) {
return fmt.Sprintf("Command(%d)", i)
}
return _Command_name[_Command_index[i]:_Command_index[i+1]]
}

46
vendor/github.com/magefile/mage/mage/magefile_tmpl.go generated vendored Normal file
View File

@@ -0,0 +1,46 @@
package mage
var mageTpl = `// +build mage
package main
import (
"fmt"
"os"
"os/exec"
"github.com/magefile/mage/mg" // mg contains helpful utility functions, like Deps
)
// Default target to run when none is specified
// If not set, running mage will list available targets
// var Default = Build
// A build step that requires additional params, or platform specific steps for example
func Build() error {
mg.Deps(InstallDeps)
fmt.Println("Building...")
cmd := exec.Command("go", "build", "-o", "MyApp", ".")
return cmd.Run()
}
// A custom install step if you need your bin someplace other than go/bin
func Install() error {
mg.Deps(Build)
fmt.Println("Installing...")
return os.Rename("./MyApp", "/usr/bin/MyApp")
}
// Manage your deps, or running package managers.
func InstallDeps() error {
fmt.Println("Installing Deps...")
cmd := exec.Command("go", "get", "github.com/stretchr/piglatin")
return cmd.Run()
}
// Clean up after yourself
func Clean() {
fmt.Println("Cleaning...")
os.RemoveAll("MyApp")
}
`

459
vendor/github.com/magefile/mage/mage/main.go generated vendored Normal file
View File

@@ -0,0 +1,459 @@
package mage
import (
"crypto/sha1"
"errors"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"sort"
"strconv"
"strings"
"text/template"
"time"
"unicode"
"github.com/magefile/mage/build"
"github.com/magefile/mage/mg"
"github.com/magefile/mage/parse"
"github.com/magefile/mage/sh"
)
// magicRebuildKey is used when hashing the output binary to ensure that we get
// a new binary even if nothing in the input files or generated mainfile has
// changed. This can be used when we change how we parse files, or otherwise
// change the inputs to the compiling process.
const magicRebuildKey = "v0.3"
var output = template.Must(template.New("").Funcs(map[string]interface{}{
"lower": strings.ToLower,
"lowerfirst": func(s string) string {
r := []rune(s)
return string(unicode.ToLower(r[0])) + string(r[1:])
},
}).Parse(tpl))
var initOutput = template.Must(template.New("").Parse(mageTpl))
const mainfile = "mage_output_file.go"
const initFile = "magefile.go"
// set by ldflags when you "mage build"
var (
commitHash string
timestamp string
gitTag = "v2"
)
//go:generate stringer -type=Command
// Command tracks invocations of mage that run without targets or other flags.
type Command int
const (
None Command = iota
Version // report the current version of mage
Init // create a starting template for mage
Clean // clean out old compiled mage binaries from the cache
)
// Main is the entrypoint for running mage. It exists external to mage's main
// function to allow it to be used from other programs, specifically so you can
// go run a simple file that run's mage's Main.
func Main() int {
return ParseAndRun(".", os.Stdout, os.Stderr, os.Stdin, os.Args[1:])
}
// Invocation contains the args for invoking a run of Mage.
type Invocation struct {
Dir string // directory to read magefiles from
Force bool // forces recreation of the compiled binary
Verbose bool // tells the magefile to print out log statements
List bool // tells the magefile to print out a list of targets
Help bool // tells the magefile to print out help for a specific target
Keep bool // tells mage to keep the generated main file after compiling
Timeout time.Duration // tells mage to set a timeout to running the targets
Stdout io.Writer // writer to write stdout messages to
Stderr io.Writer // writer to write stderr messages to
Stdin io.Reader // reader to read stdin from
Args []string // args to pass to the compiled binary
}
// ParseAndRun parses the command line, and then compiles and runs the mage
// files in the given directory with the given args (do not include the command
// name in the args).
func ParseAndRun(dir string, stdout, stderr io.Writer, stdin io.Reader, args []string) int {
log := log.New(stderr, "", 0)
inv, cmd, err := Parse(stdout, args)
inv.Dir = dir
inv.Stderr = stderr
inv.Stdin = stdin
if err == flag.ErrHelp {
return 0
}
if err != nil {
log.Println("Error:", err)
return 2
}
switch cmd {
case Version:
if timestamp == "" {
timestamp = "<not set>"
}
if commitHash == "" {
commitHash = "<not set>"
}
log.Println("Mage Build Tool", gitTag)
log.Println("Build Date:", timestamp)
log.Println("Commit:", commitHash)
return 0
case Init:
if err := generateInit(dir); err != nil {
log.Println("Error:", err)
return 1
}
log.Println(initFile, "created")
return 0
case Clean:
dir := mg.CacheDir()
if err := removeContents(dir); err != nil {
log.Println("Error:", err)
return 1
}
log.Println(dir, "cleaned")
return 0
case None:
return Invoke(inv)
default:
panic(fmt.Errorf("Unknown command type: %v", cmd))
}
}
// Parse parses the given args and returns structured data. If parse returns
// flag.ErrHelp, the calling process should exit with code 0.
func Parse(stdout io.Writer, args []string) (inv Invocation, cmd Command, err error) {
inv.Stdout = stdout
fs := flag.FlagSet{}
fs.SetOutput(stdout)
fs.BoolVar(&inv.Force, "f", false, "force recreation of compiled magefile")
fs.BoolVar(&inv.Verbose, "v", false, "show verbose output when running mage targets")
fs.BoolVar(&inv.List, "l", false, "list mage targets in this directory")
fs.BoolVar(&inv.Help, "h", false, "show this help")
fs.DurationVar(&inv.Timeout, "t", 0, "timeout in duration parsable format (e.g. 5m30s)")
fs.BoolVar(&inv.Keep, "keep", false, "keep intermediate mage files around after running")
var showVersion bool
fs.BoolVar(&showVersion, "version", false, "show version info for the mage binary")
var mageInit bool
fs.BoolVar(&mageInit, "init", false, "create a starting template if no mage files exist")
var clean bool
fs.BoolVar(&clean, "clean", false, "clean out old generated binaries from CACHE_DIR")
fs.Usage = func() {
fmt.Fprintln(stdout, "mage [options] [target]")
fmt.Fprintln(stdout, "Options:")
fs.PrintDefaults()
}
err = fs.Parse(args)
if err == flag.ErrHelp {
// parse will have already called fs.Usage()
return inv, cmd, err
}
if err == nil && inv.Help && len(fs.Args()) == 0 {
fs.Usage()
// tell upstream, to just exit
return inv, cmd, flag.ErrHelp
}
numFlags := 0
switch {
case mageInit:
numFlags++
cmd = Init
case showVersion:
numFlags++
cmd = Version
case clean:
numFlags++
cmd = Clean
if fs.NArg() > 0 || fs.NFlag() > 1 {
// Temporary dupe of below check until we refactor the other commands to use this check
return inv, cmd, errors.New("-h, -init, -clean, and -version cannot be used simultaneously")
}
}
if inv.Help {
numFlags++
}
// If verbose is still false, we're going to peek at the environment variable to see if
// MAGE_VERBOSE has been set. If so, we're going to use it for the value of MAGE_VERBOSE.
if inv.Verbose == false {
envVerbose, err := strconv.ParseBool(os.Getenv("MAGE_VERBOSE"))
if err == nil {
inv.Verbose = envVerbose
}
}
if numFlags > 1 {
return inv, cmd, errors.New("-h, -init, -clean, and -version cannot be used simultaneously")
}
inv.Args = fs.Args()
if inv.Help && len(inv.Args) > 1 {
return inv, cmd, errors.New("-h can only show help for a single target")
}
return inv, cmd, err
}
// Invoke runs Mage with the given arguments.
func Invoke(inv Invocation) int {
log := log.New(inv.Stderr, "", 0)
files, err := Magefiles(inv.Dir)
if err != nil {
log.Println("Error:", err)
return 1
}
if len(files) == 0 {
log.Println("No .go files marked with the mage build tag in this directory.")
return 1
}
exePath, err := ExeName(files)
if err != nil {
log.Println("Error:", err)
return 1
}
if !inv.Force {
if _, err := os.Stat(exePath); err == nil {
return RunCompiled(inv, exePath)
}
}
// parse wants dir + filenames... arg
fnames := make([]string, 0, len(files))
for i := range files {
fnames = append(fnames, filepath.Base(files[i]))
}
info, err := parse.Package(inv.Dir, fnames)
if err != nil {
log.Println("Error:", err)
return 1
}
hasDupes, names := CheckDupes(info)
if hasDupes {
log.Println("Build targets must be case insensitive, thus the follow targets conflict:")
for _, v := range names {
if len(v) > 1 {
log.Println(" " + strings.Join(v, ", "))
}
}
return 1
}
main := filepath.Join(inv.Dir, mainfile)
if err := GenerateMainfile(main, info); err != nil {
log.Println("Error:", err)
return 1
}
if !inv.Keep {
defer os.Remove(main)
}
files = append(files, main)
if err := Compile(exePath, inv.Stdout, inv.Stderr, files); err != nil {
log.Println("Error:", err)
return 1
}
if !inv.Keep {
// remove this file before we run the compiled version, in case the
// compiled file screws things up. Yes this doubles up with the above
// defer, that's ok.
os.Remove(main)
}
return RunCompiled(inv, exePath)
}
// CheckDupes checks a package for duplicate target names.
func CheckDupes(info *parse.PkgInfo) (hasDupes bool, names map[string][]string) {
names = map[string][]string{}
lowers := map[string]bool{}
for _, f := range info.Funcs {
low := strings.ToLower(f.Name)
if lowers[low] {
hasDupes = true
}
lowers[low] = true
names[low] = append(names[low], f.Name)
}
return hasDupes, names
}
type data struct {
Funcs []parse.Function
DefaultError bool
Default string
DefaultFunc parse.Function
Aliases map[string]string
}
// Magefiles returns the list of magefiles in dir.
func Magefiles(dir string) ([]string, error) {
ctx := build.Default
ctx.RequiredTags = []string{"mage"}
ctx.BuildTags = []string{"mage"}
p, err := ctx.ImportDir(dir, 0)
if err != nil {
if _, ok := err.(*build.NoGoError); ok {
return []string{}, nil
}
return nil, err
}
for i := range p.GoFiles {
p.GoFiles[i] = filepath.Join(dir, p.GoFiles[i])
}
return p.GoFiles, nil
}
// Compile uses the go tool to compile the files into an executable at path.
func Compile(path string, stdout, stderr io.Writer, gofiles []string) error {
c := exec.Command("go", append([]string{"build", "-o", path}, gofiles...)...)
c.Env = os.Environ()
c.Stderr = stderr
c.Stdout = stdout
err := c.Run()
if err != nil {
return errors.New("error compiling magefiles")
}
if _, err := os.Stat(path); err != nil {
return errors.New("failed to find compiled magefile")
}
return nil
}
// GenerateMainfile creates the mainfile at path with the info from
func GenerateMainfile(path string, info *parse.PkgInfo) error {
f, err := os.Create(path)
if err != nil {
return fmt.Errorf("can't create mainfile: %v", err)
}
defer f.Close()
data := data{
Funcs: info.Funcs,
Default: info.DefaultName,
DefaultFunc: info.DefaultFunc,
Aliases: info.Aliases,
}
data.DefaultError = info.DefaultIsError
if err := output.Execute(f, data); err != nil {
return fmt.Errorf("can't execute mainfile template: %v", err)
}
return nil
}
// ExeName reports the executable filename that this version of Mage would
// create for the given magefiles.
func ExeName(files []string) (string, error) {
var hashes []string
for _, s := range files {
h, err := hashFile(s)
if err != nil {
return "", err
}
hashes = append(hashes, h)
}
// hash the mainfile template to ensure if it gets updated, we make a new
// binary.
hashes = append(hashes, fmt.Sprintf("%x", sha1.Sum([]byte(tpl))))
sort.Strings(hashes)
hash := sha1.Sum([]byte(strings.Join(hashes, "") + magicRebuildKey))
filename := fmt.Sprintf("%x", hash)
out := filepath.Join(mg.CacheDir(), filename)
if runtime.GOOS == "windows" {
out += ".exe"
}
return out, nil
}
func hashFile(fn string) (string, error) {
f, err := os.Open(fn)
if err != nil {
return "", fmt.Errorf("can't open input file: %v", err)
}
defer f.Close()
h := sha1.New()
if _, err := io.Copy(h, f); err != nil {
return "", fmt.Errorf("can't write data to hash: %v", err)
}
return fmt.Sprintf("%x", h.Sum(nil)), nil
}
func generateInit(dir string) error {
f, err := os.Create(filepath.Join(dir, initFile))
if err != nil {
return fmt.Errorf("could not create mage template: %v", err)
}
defer f.Close()
if err := initOutput.Execute(f, nil); err != nil {
return fmt.Errorf("can't execute magefile template: %v", err)
}
return nil
}
// RunCompiled runs an already-compiled mage command with the given args,
func RunCompiled(inv Invocation, exePath string) int {
c := exec.Command(exePath, inv.Args...)
c.Stderr = inv.Stderr
c.Stdout = inv.Stdout
c.Stdin = inv.Stdin
c.Env = os.Environ()
if inv.Verbose {
c.Env = append(c.Env, "MAGEFILE_VERBOSE=1")
}
if inv.List {
c.Env = append(c.Env, "MAGEFILE_LIST=1")
}
if inv.Help {
c.Env = append(c.Env, "MAGEFILE_HELP=1")
}
if inv.Timeout > 0 {
c.Env = append(c.Env, fmt.Sprintf("MAGEFILE_TIMEOUT=%s", inv.Timeout.String()))
}
return sh.ExitStatus(c.Run())
}
func removeContents(dir string) error {
files, err := ioutil.ReadDir(dir)
if err != nil {
return err
}
for _, f := range files {
if f.IsDir() {
continue
}
err = os.Remove(filepath.Join(dir, f.Name()))
if err != nil {
return err
}
}
return nil
}

202
vendor/github.com/magefile/mage/mage/template.go generated vendored Normal file
View File

@@ -0,0 +1,202 @@
package mage
// var only for tests
var tpl = `// +build ignore
package main
import (
"context"
"fmt"
"io/ioutil"
"log"
"os"
"strings"
"text/tabwriter"
"time"
)
func main() {
// These functions are local variables to avoid name conflicts with
// magefiles.
list := func() error {
{{- $default := .Default}}
w := tabwriter.NewWriter(os.Stdout, 0, 4, 4, ' ', 0)
fmt.Println("Targets:")
{{- range .Funcs}}
fmt.Fprintln(w, " {{lowerfirst .Name}}{{if eq .Name $default}}*{{end}}\t" + {{printf "%q" .Synopsis}})
{{- end}}
err := w.Flush()
{{- if .Default}}
if err == nil {
fmt.Println("\n* default target")
}
{{- end}}
return err
}
var ctx context.Context
var ctxCancel func()
getContext := func() (context.Context, func()) {
if ctx != nil {
return ctx, ctxCancel
}
if os.Getenv("MAGEFILE_TIMEOUT") != "" {
timeout, err := time.ParseDuration(os.Getenv("MAGEFILE_TIMEOUT"))
if err != nil {
fmt.Printf("timeout error: %v\n", err)
os.Exit(1)
}
ctx, ctxCancel = context.WithTimeout(context.Background(), timeout)
} else {
ctx = context.Background()
ctxCancel = func() {}
}
return ctx, ctxCancel
}
runTarget := func(fn func(context.Context) error) interface{} {
var err interface{}
ctx, cancel := getContext()
d := make(chan interface{})
go func() {
defer func() {
err := recover()
d <- err
}()
err := fn(ctx)
d <- err
}()
select {
case <-ctx.Done():
cancel()
e := ctx.Err()
fmt.Printf("ctx err: %v\n", e)
return e
case err = <-d:
cancel()
return err
}
}
// This is necessary in case there aren't any targets, to avoid an unused
// variable error.
_ = runTarget
handleError := func(logger *log.Logger, err interface{}) {
if err != nil {
logger.Printf("Error: %v\n", err)
type code interface {
ExitStatus() int
}
if c, ok := err.(code); ok {
os.Exit(c.ExitStatus())
}
os.Exit(1)
}
}
_ = handleError
log.SetFlags(0)
if os.Getenv("MAGEFILE_VERBOSE") == "" {
log.SetOutput(ioutil.Discard)
}
logger := log.New(os.Stderr, "", 0)
if os.Getenv("MAGEFILE_LIST") != "" {
if err := list(); err != nil {
log.Println(err)
os.Exit(1)
}
return
}
targets := map[string]bool {
{{range $alias, $funci := .Aliases}}"{{lower $alias}}": true,
{{end}}
{{range .Funcs}}"{{lower .Name}}": true,
{{end}}
}
var unknown []string
for _, arg := range os.Args[1:] {
if !targets[strings.ToLower(arg)] {
unknown = append(unknown, arg)
}
}
if len(unknown) == 1 {
logger.Println("Unknown target specified:", unknown[0])
os.Exit(2)
}
if len(unknown) > 1 {
logger.Println("Unknown targets specified:", strings.Join(unknown, ", "))
os.Exit(2)
}
if os.Getenv("MAGEFILE_HELP") != "" {
if len(os.Args) < 2 {
logger.Println("no target specified")
os.Exit(1)
}
switch strings.ToLower(os.Args[1]) {
{{range .Funcs}}case "{{lower .Name}}":
fmt.Print("mage {{lower .Name}}:\n\n")
{{if ne .Comment ""}}fmt.Println({{printf "%q" .Comment}}){{end}}
var aliases []string
{{- $name := .Name -}}
{{range $alias, $func := $.Aliases}}
{{if eq $name $func}}aliases = append(aliases, "{{$alias}}"){{end -}}
{{- end}}
if len(aliases) > 0 {
fmt.Printf("Aliases: %s\n\n", strings.Join(aliases, ", "))
}
return
{{end}}
default:
logger.Printf("Unknown target: %q\n", os.Args[1])
os.Exit(1)
}
}
if len(os.Args) < 2 {
{{- if .Default}}
{{.DefaultFunc.TemplateString}}
handleError(logger, err)
return
{{- else}}
if err := list(); err != nil {
logger.Println("Error:", err)
os.Exit(1)
}
return
{{- end}}
}
for _, target := range os.Args[1:] {
switch strings.ToLower(target) {
{{range $alias, $func := .Aliases}}
case "{{lower $alias}}":
target = "{{$func}}"
{{- end}}
}
switch strings.ToLower(target) {
{{range .Funcs }}
case "{{lower .Name}}":
if os.Getenv("MAGEFILE_VERBOSE") != "" {
logger.Println("Running target:", "{{.Name}}")
}
{{.TemplateString}}
handleError(logger, err)
{{- end}}
default:
// should be impossible since we check this above.
logger.Printf("Unknown target: %q\n", os.Args[1])
os.Exit(1)
}
}
}
`

94
vendor/github.com/magefile/mage/magefile.go generated vendored Normal file
View File

@@ -0,0 +1,94 @@
//+build mage
package main
import (
"errors"
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/magefile/mage/sh"
)
// Runs "go install" for mage. This generates the version info the binary.
func Install() error {
ldf, err := flags()
if err != nil {
return err
}
name := "mage"
if runtime.GOOS == "windows" {
name += ".exe"
}
gopath, err := sh.Output("go", "env", "GOPATH")
if err != nil {
return fmt.Errorf("can't determine GOPATH: %v", err)
}
paths := strings.Split(gopath, string([]rune{os.PathListSeparator}))
bin := filepath.Join(paths[0], "bin")
// specifically don't mkdirall, if you have an invalid gopath in the first
// place, that's not on us to fix.
if err := os.Mkdir(bin, 0700); err != nil && !os.IsExist(err) {
return fmt.Errorf("failed to create %q: %v", bin, err)
}
path := filepath.Join(bin, name)
// we use go build here because if someone built with go get, then `go
// install` turns into a no-op, and `go install -a` fails on people's
// machines that have go installed in a non-writeable directory (such as
// normal OS installs in /usr/bin)
return sh.RunV("go", "build", "-o", path, "-ldflags="+ldf, "github.com/magefile/mage")
}
// Generates a new release. Expects the TAG environment variable to be set,
// which will create a new tag with that name.
func Release() (err error) {
if os.Getenv("TAG") == "" {
return errors.New("MSG and TAG environment variables are required")
}
if err := sh.RunV("git", "tag", "-a", "$TAG"); err != nil {
return err
}
if err := sh.RunV("git", "push", "origin", "$TAG"); err != nil {
return err
}
defer func() {
if err != nil {
sh.RunV("git", "tag", "--delete", "$TAG")
sh.RunV("git", "push", "--delete", "origin", "$TAG")
}
}()
return sh.RunV("goreleaser")
}
// Remove the temporarily generated files from Release.
func Clean() error {
return sh.Rm("dist")
}
func flags() (string, error) {
timestamp := time.Now().Format(time.RFC3339)
hash := hash()
tag := tag()
if tag == "" {
tag = "dev"
}
return fmt.Sprintf(`-X "github.com/magefile/mage/mage.timestamp=%s" -X "github.com/magefile/mage/mage.commitHash=%s" -X "github.com/magefile/mage/mage.gitTag=%s"`, timestamp, hash, tag), nil
}
// tag returns the git tag for the current branch or "" if none.
func tag() string {
s, _ := sh.Output("git", "describe", "--tags")
return s
}
// hash returns the git hash for the current repo or "" if none.
func hash() string {
hash, _ := sh.Output("git", "rev-parse", "--short", "HEAD")
return hash
}

11
vendor/github.com/magefile/mage/main.go generated vendored Normal file
View File

@@ -0,0 +1,11 @@
package main
import (
"os"
"github.com/magefile/mage/mage"
)
func main() {
os.Exit(mage.Main())
}

166
vendor/github.com/magefile/mage/mg/deps.go generated vendored Normal file
View File

@@ -0,0 +1,166 @@
package mg
import (
"context"
"fmt"
"reflect"
"runtime"
"strings"
"sync"
"github.com/magefile/mage/types"
)
type onceMap struct {
mu *sync.Mutex
m map[string]*onceFun
}
func (o *onceMap) LoadOrStore(s string, one *onceFun) *onceFun {
defer o.mu.Unlock()
o.mu.Lock()
existing, ok := o.m[s]
if ok {
return existing
}
o.m[s] = one
return one
}
var onces = &onceMap{
mu: &sync.Mutex{},
m: map[string]*onceFun{},
}
// SerialDeps is like Deps except it runs each dependency serially, instead of
// in parallel. This can be useful for resource intensive dependencies that
// shouldn't be run at the same time.
func SerialDeps(fns ...interface{}) {
checkFns(fns)
ctx := context.Background()
for _, f := range fns {
runDeps(ctx, f)
}
}
// SerialCtxDeps is like CtxDeps except it runs each dependency serially,
// instead of in parallel. This can be useful for resource intensive
// dependencies that shouldn't be run at the same time.
func SerialCtxDeps(ctx context.Context, fns ...interface{}) {
checkFns(fns)
for _, f := range fns {
runDeps(ctx, f)
}
}
// CtxDeps runs the given functions as dependencies of the calling function.
// Dependencies must only be of type: github.com/magefile/mage/types.FuncType.
// The function calling Deps is guaranteed that all dependent functions will be
// run exactly once when Deps returns. Dependent functions may in turn declare
// their own dependencies using Deps. Each dependency is run in their own
// goroutines. Each function is given the context provided if the function
// prototype allows for it.
func CtxDeps(ctx context.Context, fns ...interface{}) {
checkFns(fns)
runDeps(ctx, fns...)
}
// runDeps assumes you've already called checkFns.
func runDeps(ctx context.Context, fns ...interface{}) {
mu := &sync.Mutex{}
var errs []string
var exit int
wg := &sync.WaitGroup{}
for _, f := range fns {
fn := addDep(ctx, f)
wg.Add(1)
go func() {
defer func() {
if v := recover(); v != nil {
mu.Lock()
if err, ok := v.(error); ok {
exit = changeExit(exit, ExitStatus(err))
} else {
exit = changeExit(exit, 1)
}
errs = append(errs, fmt.Sprint(v))
mu.Unlock()
}
wg.Done()
}()
if err := fn.run(); err != nil {
mu.Lock()
errs = append(errs, fmt.Sprint(err))
exit = changeExit(exit, ExitStatus(err))
mu.Unlock()
}
}()
}
wg.Wait()
if len(errs) > 0 {
panic(Fatal(exit, strings.Join(errs, "\n")))
}
}
func checkFns(fns []interface{}) {
for _, f := range fns {
if err := types.FuncCheck(f); err != nil {
panic(err)
}
}
}
// Deps runs the given functions with the default runtime context
func Deps(fns ...interface{}) {
CtxDeps(context.Background(), fns...)
}
func changeExit(old, new int) int {
if new == 0 {
return old
}
if old == 0 {
return new
}
if old == new {
return old
}
// both different and both non-zero, just set
// exit to 1. Nothing more we can do.
return 1
}
func addDep(ctx context.Context, f interface{}) *onceFun {
var fn func(context.Context) error
if fn = types.FuncTypeWrap(f); fn == nil {
// should be impossible, since we already checked this
panic("attempted to add a dep that did not match required type")
}
n := name(f)
of := onces.LoadOrStore(n, &onceFun{
fn: fn,
ctx: ctx,
})
return of
}
func name(i interface{}) string {
return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
}
type onceFun struct {
once sync.Once
fn func(context.Context) error
ctx context.Context
}
func (o *onceFun) run() error {
var err error
o.once.Do(func() {
err = o.fn(o.ctx)
})
return err
}

51
vendor/github.com/magefile/mage/mg/errors.go generated vendored Normal file
View File

@@ -0,0 +1,51 @@
package mg
import (
"errors"
"fmt"
)
type fatalErr struct {
code int
error
}
func (f fatalErr) ExitStatus() int {
return f.code
}
type exitStatus interface {
ExitStatus() int
}
// Fatal returns an error that will cause mage to print out the
// given args and exit with the given exit code.
func Fatal(code int, args ...interface{}) error {
return fatalErr{
code: code,
error: errors.New(fmt.Sprint(args...)),
}
}
// Fatalf returns an error that will cause mage to print out the
// given message and exit with an exit code of 1.
func Fatalf(code int, format string, args ...interface{}) error {
return fatalErr{
code: code,
error: fmt.Errorf(format, args...),
}
}
// ExitStatus queries the error for an exit status. If the error is nil, it
// returns 0. If the error does not implement ExitStatus() int, it returns 1.
// Otherwise it retiurns the value from ExitStatus().
func ExitStatus(err error) int {
if err == nil {
return 0
}
exit, ok := err.(exitStatus)
if !ok {
return 1
}
return exit.ExitStatus()
}

36
vendor/github.com/magefile/mage/mg/runtime.go generated vendored Normal file
View File

@@ -0,0 +1,36 @@
package mg
import (
"os"
"path/filepath"
"runtime"
)
// CacheEnv is the environment variable that users may set to change the
// location where mage stores its compiled binaries.
const CacheEnv = "MAGEFILE_CACHE"
// verboseEnv is the environment variable that indicates the user requested
// verbose mode when running a magefile.
const verboseEnv = "MAGEFILE_VERBOSE"
// Verbose reports whether a magefile was run with the verbose flag.
func Verbose() bool {
return os.Getenv(verboseEnv) != ""
}
// CacheDir returns the directory where mage caches compiled binaries. It
// defaults to $HOME/.magefile, but may be overridden by the MAGEFILE_CACHE
// environment variable.
func CacheDir() string {
d := os.Getenv(CacheEnv)
if d != "" {
return d
}
switch runtime.GOOS {
case "windows":
return filepath.Join(os.Getenv("HOMEDRIVE"), os.Getenv("HOMEPATH"), "magefile")
default:
return filepath.Join(os.Getenv("HOME"), ".magefile")
}
}

13
vendor/github.com/magefile/mage/parse/import_go1.9.go generated vendored Normal file
View File

@@ -0,0 +1,13 @@
// +build go1.9
package parse
import (
"go/importer"
"go/token"
"go/types"
)
func getImporter(*token.FileSet) types.Importer {
return importer.For("source", nil)
}

View File

@@ -0,0 +1,15 @@
// +build !go1.9
package parse
import (
"go/build"
"go/token"
"go/types"
"github.com/magefile/mage/parse/srcimporter"
)
func getImporter(fset *token.FileSet) types.Importer {
return srcimporter.New(&build.Default, fset, make(map[string]*types.Package))
}

341
vendor/github.com/magefile/mage/parse/parse.go generated vendored Normal file
View File

@@ -0,0 +1,341 @@
package parse
import (
"fmt"
"go/ast"
"go/build"
"go/doc"
"go/parser"
"go/token"
"go/types"
"log"
"os"
"os/exec"
"strings"
mgTypes "github.com/magefile/mage/types"
)
type PkgInfo struct {
Funcs []Function
DefaultIsError bool
DefaultIsContext bool
DefaultName string
DefaultFunc Function
Aliases map[string]string
}
// Function represented a job function from a mage file
type Function struct {
Name string
IsError bool
IsContext bool
Synopsis string
Comment string
}
// TemplateString returns code for the template switch to run the target.
// It wraps each target call to match the func(context.Context) error that
// runTarget requires.
func (f Function) TemplateString() string {
if f.IsContext && f.IsError {
out := `wrapFn := func(ctx context.Context) error {
return %s(ctx)
}
err := runTarget(wrapFn)`
return fmt.Sprintf(out, f.Name)
}
if f.IsContext && !f.IsError {
out := `wrapFn := func(ctx context.Context) error {
%s(ctx)
return nil
}
err := runTarget(wrapFn)`
return fmt.Sprintf(out, f.Name)
}
if !f.IsContext && f.IsError {
out := `wrapFn := func(ctx context.Context) error {
return %s()
}
err := runTarget(wrapFn)`
return fmt.Sprintf(out, f.Name)
}
if !f.IsContext && !f.IsError {
out := `wrapFn := func(ctx context.Context) error {
%s()
return nil
}
err := runTarget(wrapFn)`
return fmt.Sprintf(out, f.Name)
}
return `fmt.Printf("Error formatting job code\n")
os.Exit(1)`
}
// Package parses a package
func Package(path string, files []string) (*PkgInfo, error) {
fset := token.NewFileSet()
pkg, err := getPackage(path, files, fset)
if err != nil {
return nil, err
}
info, err := makeInfo(path, fset, pkg.Files)
if err != nil {
return nil, err
}
pi := &PkgInfo{}
p := doc.New(pkg, "./", 0)
for _, f := range p.Funcs {
if f.Recv != "" {
// skip methods
continue
}
if !ast.IsExported(f.Name) {
// skip non-exported functions
continue
}
if typ := voidOrError(f.Decl.Type, info); typ != mgTypes.InvalidType {
pi.Funcs = append(pi.Funcs, Function{
Name: f.Name,
Comment: f.Doc,
Synopsis: sanitizeSynopsis(f),
IsError: typ == mgTypes.ErrorType || typ == mgTypes.ContextErrorType,
IsContext: typ == mgTypes.ContextVoidType || typ == mgTypes.ContextErrorType,
})
}
}
setDefault(p, pi, info)
setAliases(p, pi, info)
return pi, nil
}
// sanitizeSynopsis sanitizes function Doc to create a summary.
func sanitizeSynopsis(f *doc.Func) string {
synopsis := doc.Synopsis(f.Doc)
// If the synopsis begins with the function name, remove it. This is done to
// not repeat the text.
// From:
// clean Clean removes the temporarily generated files
// To:
// clean removes the temporarily generated files
if syns := strings.Split(synopsis, " "); strings.EqualFold(f.Name, syns[0]) {
return strings.Join(syns[1:], " ")
}
return synopsis
}
func setDefault(p *doc.Package, pi *PkgInfo, info types.Info) {
for _, v := range p.Vars {
for x, name := range v.Names {
if name != "Default" {
continue
}
spec := v.Decl.Specs[x].(*ast.ValueSpec)
if len(spec.Values) != 1 {
log.Println("warning: default declaration has multiple values")
}
id, ok := spec.Values[0].(*ast.Ident)
if !ok {
log.Println("warning: default declaration is not a function name")
}
for _, f := range pi.Funcs {
if f.Name == id.Name {
pi.DefaultName = f.Name
pi.DefaultIsError = f.IsError
pi.DefaultIsContext = f.IsContext
pi.DefaultFunc = f
return
}
}
log.Println("warning: default declaration does not reference a mage target")
}
}
}
func setAliases(p *doc.Package, pi *PkgInfo, info types.Info) {
for _, v := range p.Vars {
for x, name := range v.Names {
if name != "Aliases" {
continue
}
spec, ok := v.Decl.Specs[x].(*ast.ValueSpec)
if !ok {
log.Println("warning: aliases declaration is not a value")
return
}
if len(spec.Values) != 1 {
log.Println("warning: aliases declaration has multiple values")
}
comp, ok := spec.Values[0].(*ast.CompositeLit)
if !ok {
log.Println("warning: aliases declaration is not a map")
return
}
pi.Aliases = make(map[string]string)
for _, elem := range comp.Elts {
kv, ok := elem.(*ast.KeyValueExpr)
if !ok {
log.Println("warning: alias declaration is not a map element")
return
}
k, ok := kv.Key.(*ast.BasicLit)
if !ok || k.Kind != token.STRING {
log.Println("warning: alias is not a string")
return
}
v, ok := kv.Value.(*ast.Ident)
if !ok {
log.Println("warning: alias target is not a function")
return
}
alias := strings.Trim(k.Value, "\"")
valid := false
for _, f := range pi.Funcs {
valid = valid || f.Name == v.Name
}
if !valid {
log.Printf("warning: alias declaration (%s) does not reference a mage target", alias)
}
pi.Aliases[alias] = v.Name
}
return
}
}
}
// getPackage returns the non-test package at the given path.
func getPackage(path string, files []string, fset *token.FileSet) (*ast.Package, error) {
fm := make(map[string]bool, len(files))
for _, f := range files {
fm[f] = true
}
filter := func(f os.FileInfo) bool {
return fm[f.Name()]
}
pkgs, err := parser.ParseDir(fset, path, filter, parser.ParseComments)
if err != nil {
return nil, fmt.Errorf("failed to parse directory: %v", err)
}
for name, pkg := range pkgs {
if !strings.HasSuffix(name, "_test") {
return pkg, nil
}
}
return nil, fmt.Errorf("no non-test packages found in %s", path)
}
func makeInfo(dir string, fset *token.FileSet, files map[string]*ast.File) (types.Info, error) {
goroot := os.Getenv("GOROOT")
if goroot == "" {
c := exec.Command("go", "env", "GOROOT")
b, err := c.Output()
if err != nil {
return types.Info{}, fmt.Errorf("failed to get GOROOT from 'go env': %v", err)
}
goroot = strings.TrimSpace(string(b))
if goroot == "" {
return types.Info{}, fmt.Errorf("could not determine GOROOT")
}
}
build.Default.GOROOT = goroot
cfg := types.Config{
Importer: getImporter(fset),
}
info := types.Info{
Types: make(map[ast.Expr]types.TypeAndValue),
Defs: make(map[*ast.Ident]types.Object),
Uses: make(map[*ast.Ident]types.Object),
}
fs := make([]*ast.File, 0, len(files))
for _, v := range files {
fs = append(fs, v)
}
_, err := cfg.Check(dir, fset, fs, &info)
if err != nil {
return info, fmt.Errorf("failed to check types in directory: %v", err)
}
return info, nil
}
// errorOrVoid filters the list of functions to only those that return only an
// error or have no return value, and have no parameters.
func errorOrVoid(fns []*ast.FuncDecl, info types.Info) []*ast.FuncDecl {
fds := []*ast.FuncDecl{}
for _, fn := range fns {
if voidOrError(fn.Type, info) != mgTypes.InvalidType {
fds = append(fds, fn)
}
}
return fds
}
func hasContextParam(ft *ast.FuncType, info types.Info) bool {
if ft.Params.NumFields() == 1 {
ret := ft.Params.List[0]
t := info.TypeOf(ret.Type)
if t != nil && t.String() == "context.Context" {
return true
}
}
return false
}
func hasVoidReturn(ft *ast.FuncType, info types.Info) bool {
res := ft.Results
if res.NumFields() == 0 {
return true
}
return false
}
func hasErrorReturn(ft *ast.FuncType, info types.Info) bool {
res := ft.Results
if res.NumFields() == 1 {
ret := res.List[0]
if len(ret.Names) > 1 {
return false
}
t := info.TypeOf(ret.Type)
if t != nil && t.String() == "error" {
return true
}
}
return false
}
func voidOrError(ft *ast.FuncType, info types.Info) mgTypes.FuncType {
if hasContextParam(ft, info) {
if hasVoidReturn(ft, info) {
return mgTypes.ContextVoidType
}
if hasErrorReturn(ft, info) {
return mgTypes.ContextErrorType
}
}
if ft.Params.NumFields() == 0 {
if hasVoidReturn(ft, info) {
return mgTypes.VoidType
}
if hasErrorReturn(ft, info) {
return mgTypes.ErrorType
}
}
return mgTypes.InvalidType
}

View File

@@ -0,0 +1,40 @@
// +build !go1.9
package srcimporter
import "go/types"
// common architecture word sizes and alignments
var gcArchSizes = map[string]*types.StdSizes{
"386": {4, 4},
"arm": {4, 4},
"arm64": {8, 8},
"amd64": {8, 8},
"amd64p32": {4, 8},
"mips": {4, 4},
"mipsle": {4, 4},
"mips64": {8, 8},
"mips64le": {8, 8},
"ppc64": {8, 8},
"ppc64le": {8, 8},
"s390x": {8, 8},
// When adding more architectures here,
// update the doc string of SizesFor below.
}
// SizesFor returns the Sizes used by a compiler for an architecture.
// The result is nil if a compiler/architecture pair is not known.
//
// Supported architectures for compiler "gc":
// "386", "arm", "arm64", "amd64", "amd64p32", "mips", "mipsle",
// "mips64", "mips64le", "ppc64", "ppc64le", "s390x".
func SizesFor(compiler, arch string) types.Sizes {
if compiler != "gc" {
return nil
}
s, ok := gcArchSizes[arch]
if !ok {
return nil
}
return s
}

View File

@@ -0,0 +1,213 @@
// +build !go1.9
// Copyright 2017 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 srcimporter implements importing directly
// from source files rather than installed packages.
package srcimporter
import (
"fmt"
"go/ast"
"go/build"
"go/parser"
"go/token"
"go/types"
"path/filepath"
"sync"
)
// An Importer provides the context for importing packages from source code.
type Importer struct {
ctxt *build.Context
fset *token.FileSet
sizes types.Sizes
packages map[string]*types.Package
}
// NewImporter returns a new Importer for the given context, file set, and map
// of packages. The context is used to resolve import paths to package paths,
// and identifying the files belonging to the package. If the context provides
// non-nil file system functions, they are used instead of the regular package
// os functions. The file set is used to track position information of package
// files; and imported packages are added to the packages map.
func New(ctxt *build.Context, fset *token.FileSet, packages map[string]*types.Package) *Importer {
return &Importer{
ctxt: ctxt,
fset: fset,
sizes: SizesFor(ctxt.Compiler, ctxt.GOARCH), // uses go/types default if GOARCH not found
packages: packages,
}
}
// Importing is a sentinel taking the place in Importer.packages
// for a package that is in the process of being imported.
var importing types.Package
// Import(path) is a shortcut for ImportFrom(path, "", 0).
func (p *Importer) Import(path string) (*types.Package, error) {
return p.ImportFrom(path, "", 0)
}
// ImportFrom imports the package with the given import path resolved from the given srcDir,
// adds the new package to the set of packages maintained by the importer, and returns the
// package. Package path resolution and file system operations are controlled by the context
// maintained with the importer. The import mode must be zero but is otherwise ignored.
// Packages that are not comprised entirely of pure Go files may fail to import because the
// type checker may not be able to determine all exported entities (e.g. due to cgo dependencies).
func (p *Importer) ImportFrom(path, srcDir string, mode types.ImportMode) (*types.Package, error) {
if mode != 0 {
panic("non-zero import mode")
}
// determine package path (do vendor resolution)
var bp *build.Package
var err error
switch {
default:
if abs, err := p.absPath(srcDir); err == nil { // see issue #14282
srcDir = abs
}
bp, err = p.ctxt.Import(path, srcDir, build.FindOnly)
case build.IsLocalImport(path):
// "./x" -> "srcDir/x"
bp, err = p.ctxt.ImportDir(filepath.Join(srcDir, path), build.FindOnly)
case p.isAbsPath(path):
return nil, fmt.Errorf("invalid absolute import path %q", path)
}
if err != nil {
return nil, err // err may be *build.NoGoError - return as is
}
// package unsafe is known to the type checker
if bp.ImportPath == "unsafe" {
return types.Unsafe, nil
}
// no need to re-import if the package was imported completely before
pkg := p.packages[bp.ImportPath]
if pkg != nil {
if pkg == &importing {
return nil, fmt.Errorf("import cycle through package %q", bp.ImportPath)
}
if !pkg.Complete() {
// Package exists but is not complete - we cannot handle this
// at the moment since the source importer replaces the package
// wholesale rather than augmenting it (see #19337 for details).
// Return incomplete package with error (see #16088).
return pkg, fmt.Errorf("reimported partially imported package %q", bp.ImportPath)
}
return pkg, nil
}
p.packages[bp.ImportPath] = &importing
defer func() {
// clean up in case of error
// TODO(gri) Eventually we may want to leave a (possibly empty)
// package in the map in all cases (and use that package to
// identify cycles). See also issue 16088.
if p.packages[bp.ImportPath] == &importing {
p.packages[bp.ImportPath] = nil
}
}()
// collect package files
bp, err = p.ctxt.ImportDir(bp.Dir, 0)
if err != nil {
return nil, err // err may be *build.NoGoError - return as is
}
var filenames []string
filenames = append(filenames, bp.GoFiles...)
filenames = append(filenames, bp.CgoFiles...)
files, err := p.parseFiles(bp.Dir, filenames)
if err != nil {
return nil, err
}
// type-check package files
conf := types.Config{
IgnoreFuncBodies: true,
FakeImportC: true,
Importer: p,
Sizes: p.sizes,
}
pkg, err = conf.Check(bp.ImportPath, p.fset, files, nil)
if err != nil {
// Type-checking stops after the first error (types.Config.Error is not set),
// so the returned package is very likely incomplete. Don't return it since
// we don't know its condition: It's very likely unsafe to use and it's also
// not added to p.packages which may cause further problems (issue #20837).
return nil, fmt.Errorf("type-checking package %q failed (%v)", bp.ImportPath, err)
}
p.packages[bp.ImportPath] = pkg
return pkg, nil
}
func (p *Importer) parseFiles(dir string, filenames []string) ([]*ast.File, error) {
open := p.ctxt.OpenFile // possibly nil
files := make([]*ast.File, len(filenames))
errors := make([]error, len(filenames))
var wg sync.WaitGroup
wg.Add(len(filenames))
for i, filename := range filenames {
go func(i int, filepath string) {
defer wg.Done()
if open != nil {
src, err := open(filepath)
if err != nil {
errors[i] = fmt.Errorf("opening package file %s failed (%v)", filepath, err)
return
}
files[i], errors[i] = parser.ParseFile(p.fset, filepath, src, 0)
src.Close() // ignore Close error - parsing may have succeeded which is all we need
} else {
// Special-case when ctxt doesn't provide a custom OpenFile and use the
// parser's file reading mechanism directly. This appears to be quite a
// bit faster than opening the file and providing an io.ReaderCloser in
// both cases.
// TODO(gri) investigate performance difference (issue #19281)
files[i], errors[i] = parser.ParseFile(p.fset, filepath, nil, 0)
}
}(i, p.joinPath(dir, filename))
}
wg.Wait()
// if there are errors, return the first one for deterministic results
for _, err := range errors {
if err != nil {
return nil, err
}
}
return files, nil
}
// context-controlled file system operations
func (p *Importer) absPath(path string) (string, error) {
// TODO(gri) This should be using p.ctxt.AbsPath which doesn't
// exist but probably should. See also issue #14282.
return filepath.Abs(path)
}
func (p *Importer) isAbsPath(path string) bool {
if f := p.ctxt.IsAbsPath; f != nil {
return f(path)
}
return filepath.IsAbs(path)
}
func (p *Importer) joinPath(elem ...string) string {
if f := p.ctxt.JoinPath; f != nil {
return f(elem...)
}
return filepath.Join(elem...)
}

165
vendor/github.com/magefile/mage/sh/cmd.go generated vendored Normal file
View File

@@ -0,0 +1,165 @@
package sh
import (
"bytes"
"fmt"
"io"
"log"
"os"
"os/exec"
"strings"
"github.com/magefile/mage/mg"
)
// RunCmd returns a function that will call Run with the given command. This is
// useful for creating command aliases to make your scripts easier to read, like
// this:
//
// // in a helper file somewhere
// var g0 = sh.RunCmd("go") // go is a keyword :(
//
// // somewhere in your main code
// if err := g0("install", "github.com/gohugo/hugo"); err != nil {
// return err
// }
//
// Args passed to command get baked in as args to the command when you run it.
// Any args passed in when you run the returned function will be appended to the
// original args. For example, this is equivalent to the above:
//
// var goInstall = sh.RunCmd("go", "install") goInstall("github.com/gohugo/hugo")
//
// RunCmd uses Exec underneath, so see those docs for more details.
func RunCmd(cmd string, args ...string) func(args ...string) error {
return func(args2 ...string) error {
return Run(cmd, append(args, args2...)...)
}
}
// OutCmd is like RunCmd except the command returns the output of the
// command.
func OutCmd(cmd string, args ...string) func(args ...string) (string, error) {
return func(args2 ...string) (string, error) {
return Output(cmd, append(args, args2...)...)
}
}
// Run is like RunWith, but doesn't specify any environment variables.
func Run(cmd string, args ...string) error {
return RunWith(nil, cmd, args...)
}
// RunV is like Run, but always sends the command's stdout to os.Stdout.
func RunV(cmd string, args ...string) error {
_, err := Exec(nil, os.Stdout, os.Stderr, cmd, args...)
return err
}
// RunWith runs the given command, directing stderr to this program's stderr and
// printing stdout to stdout if mage was run with -v. It adds adds env to the
// environment variables for the command being run. Environment variables should
// be in the format name=value.
func RunWith(env map[string]string, cmd string, args ...string) error {
var output io.Writer
if mg.Verbose() {
output = os.Stdout
}
_, err := Exec(env, output, os.Stderr, cmd, args...)
return err
}
// Output runs the command and returns the text from stdout.
func Output(cmd string, args ...string) (string, error) {
buf := &bytes.Buffer{}
_, err := Exec(nil, buf, os.Stderr, cmd, args...)
return strings.TrimSuffix(buf.String(), "\n"), err
}
// OutputWith is like RunWith, ubt returns what is written to stdout.
func OutputWith(env map[string]string, cmd string, args ...string) (string, error) {
buf := &bytes.Buffer{}
_, err := Exec(env, buf, os.Stderr, cmd, args...)
return strings.TrimSuffix(buf.String(), "\n"), err
}
// Exec executes the command, piping its stderr to mage's stderr and
// piping its stdout to the given writer. If the command fails, it will return
// an error that, if returned from a target or mg.Deps call, will cause mage to
// exit with the same code as the command failed with. Env is a list of
// environment variables to set when running the command, these override the
// current environment variables set (which are also passed to the command). cmd
// and args may include references to environment variables in $FOO format, in
// which case these will be expanded before the command is run.
//
// Ran reports if the command ran (rather than was not found or not executable).
// Code reports the exit code the command returned if it ran. If err == nil, ran
// is always true and code is always 0.
func Exec(env map[string]string, stdout, stderr io.Writer, cmd string, args ...string) (ran bool, err error) {
expand := func(s string) string {
s2, ok := env[s]
if ok {
return s2
}
return os.Getenv(s)
}
cmd = os.Expand(cmd, expand)
for i := range args {
args[i] = os.Expand(args[i], expand)
}
ran, code, err := run(env, stdout, stderr, cmd, args...)
if err == nil {
return true, nil
}
if ran {
return ran, mg.Fatalf(code, `running "%s %s" failed with exit code %d`, cmd, strings.Join(args, " "), code)
}
return ran, fmt.Errorf(`failed to run "%s %s: %v"`, cmd, strings.Join(args, " "), err)
}
func run(env map[string]string, stdout, stderr io.Writer, cmd string, args ...string) (ran bool, code int, err error) {
c := exec.Command(cmd, args...)
c.Env = os.Environ()
for k, v := range env {
c.Env = append(c.Env, k+"="+v)
}
c.Stderr = stderr
c.Stdout = stdout
c.Stdin = os.Stdin
log.Println("exec:", cmd, strings.Join(args, " "))
err = c.Run()
return cmdRan(err), ExitStatus(err), err
}
func cmdRan(err error) bool {
if err == nil {
return true
}
ee, ok := err.(*exec.ExitError)
if ok {
return ee.Exited()
}
return false
}
type exitStatus interface {
ExitStatus() int
}
// ExitStatus returns the exit status of the error if it is an exec.ExitError
// or if it implements ExitStatus() int.
// 0 if it is nil or 1 if it is a different error.
func ExitStatus(err error) int {
if err == nil {
return 0
}
if e, ok := err.(exitStatus); ok {
return e.ExitStatus()
}
if e, ok := err.(*exec.ExitError); ok {
if ex, ok := e.Sys().(exitStatus); ok {
return ex.ExitStatus()
}
}
return 1
}

16
vendor/github.com/magefile/mage/sh/helpers.go generated vendored Normal file
View File

@@ -0,0 +1,16 @@
package sh
import (
"fmt"
"os"
)
// Rm removes the given file or directory even if non-empty. It will not return
// an error if the target doesn't exist, only if the target cannot be removed.
func Rm(path string) error {
err := os.RemoveAll(path)
if err == nil || os.IsNotExist(err) {
return nil
}
return fmt.Errorf(`failed to remove %s: %v`, path, err)
}

122
vendor/github.com/magefile/mage/target/target.go generated vendored Normal file
View File

@@ -0,0 +1,122 @@
package target
import (
"os"
"path/filepath"
"time"
)
// Path reports if any of the sources have been modified more recently
// than the destination. Path does not descend into directories, it literally
// just checks the modtime of each thing you pass to it.
func Path(dst string, sources ...string) (bool, error) {
stat, err := os.Stat(dst)
if err != nil {
return false, err
}
srcTime := stat.ModTime()
dt, err := loadTargets(sources)
if err != nil {
return false, err
}
t := dt.modTime()
if t.After(srcTime) {
return true, nil
}
return false, nil
}
// Dir reports whether any of the sources have been modified
// more recently than the destination. If a source or destination is
// a directory, modtimes of files under those directories are compared
// instead.
func Dir(dst string, sources ...string) (bool, error) {
stat, err := os.Stat(dst)
if err != nil {
return false, err
}
srcTime := stat.ModTime()
if stat.IsDir() {
srcTime, err = calDirModTimeRecursive(stat)
if err != nil {
return false, err
}
}
dt, err := loadTargets(sources)
if err != nil {
return false, err
}
t, err := dt.modTimeDir()
if err != nil {
return false, err
}
if t.After(srcTime) {
return true, nil
}
return false, nil
}
func calDirModTimeRecursive(dir os.FileInfo) (time.Time, error) {
t := dir.ModTime()
ferr := filepath.Walk(dir.Name(), func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.ModTime().After(t) {
t = info.ModTime()
}
return nil
})
if ferr != nil {
return time.Time{}, ferr
}
return t, nil
}
type depTargets struct {
src []os.FileInfo
hasdir bool
latest time.Time
}
func loadTargets(targets []string) (*depTargets, error) {
d := &depTargets{}
for _, v := range targets {
stat, err := os.Stat(v)
if err != nil {
return nil, err
}
if stat.IsDir() {
d.hasdir = true
}
d.src = append(d.src, stat)
if stat.ModTime().After(d.latest) {
d.latest = stat.ModTime()
}
}
return d, nil
}
func (d *depTargets) modTime() time.Time {
return d.latest
}
func (d *depTargets) modTimeDir() (time.Time, error) {
if !d.hasdir {
return d.latest, nil
}
var err error
for _, i := range d.src {
t := i.ModTime()
if i.IsDir() {
t, err = calDirModTimeRecursive(i)
if err != nil {
return time.Time{}, err
}
}
if t.After(d.latest) {
d.latest = t
}
}
return d.latest, nil
}

58
vendor/github.com/magefile/mage/types/funcs.go generated vendored Normal file
View File

@@ -0,0 +1,58 @@
package types
import (
"context"
"fmt"
)
// FuncType indicates a prototype of build job function
type FuncType int
// FuncTypes
const (
InvalidType FuncType = iota
VoidType
ErrorType
ContextVoidType
ContextErrorType
)
// FuncCheck tests if a function is one of FuncType
func FuncCheck(fn interface{}) error {
switch fn.(type) {
case func():
return nil
case func() error:
return nil
case func(context.Context):
return nil
case func(context.Context) error:
return nil
}
return fmt.Errorf("Invalid type for dependent function: %T. Dependencies must be func(), func() error, func(context.Context) or func(context.Context) error", fn)
}
// FuncTypeWrap wraps a valid FuncType to FuncContextError
func FuncTypeWrap(fn interface{}) func(context.Context) error {
if FuncCheck(fn) == nil {
switch f := fn.(type) {
case func():
return func(context.Context) error {
f()
return nil
}
case func() error:
return func(context.Context) error {
return f()
}
case func(context.Context):
return func(ctx context.Context) error {
f(ctx)
return nil
}
case func(context.Context) error:
return f
}
}
return nil
}