Add vendor deps

This commit is contained in:
Christian Claus 2018-04-12 21:16:37 +02:00
parent 114845577e
commit b5567a3fdb
334 changed files with 36600 additions and 0 deletions

13
vendor/github.com/inconshreveable/mousetrap/LICENSE generated vendored Normal file
View file

@ -0,0 +1,13 @@
Copyright 2014 Alan Shreve
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.

23
vendor/github.com/inconshreveable/mousetrap/README.md generated vendored Normal file
View file

@ -0,0 +1,23 @@
# mousetrap
mousetrap is a tiny library that answers a single question.
On a Windows machine, was the process invoked by someone double clicking on
the executable file while browsing in explorer?
### Motivation
Windows developers unfamiliar with command line tools will often "double-click"
the executable for a tool. Because most CLI tools print the help and then exit
when invoked without arguments, this is often very frustrating for those users.
mousetrap provides a way to detect these invocations so that you can provide
more helpful behavior and instructions on how to run the CLI tool. To see what
this looks like, both from an organizational and a technical perspective, see
https://inconshreveable.com/09-09-2014/sweat-the-small-stuff/
### The interface
The library exposes a single interface:
func StartedByExplorer() (bool)

View file

@ -0,0 +1,15 @@
// +build !windows
package mousetrap
// StartedByExplorer returns true if the program was invoked by the user
// double-clicking on the executable from explorer.exe
//
// It is conservative and returns false if any of the internal calls fail.
// It does not guarantee that the program was run from a terminal. It only can tell you
// whether it was launched from explorer.exe
//
// On non-Windows platforms, it always returns false.
func StartedByExplorer() bool {
return false
}

View file

@ -0,0 +1,98 @@
// +build windows
// +build !go1.4
package mousetrap
import (
"fmt"
"os"
"syscall"
"unsafe"
)
const (
// defined by the Win32 API
th32cs_snapprocess uintptr = 0x2
)
var (
kernel = syscall.MustLoadDLL("kernel32.dll")
CreateToolhelp32Snapshot = kernel.MustFindProc("CreateToolhelp32Snapshot")
Process32First = kernel.MustFindProc("Process32FirstW")
Process32Next = kernel.MustFindProc("Process32NextW")
)
// ProcessEntry32 structure defined by the Win32 API
type processEntry32 struct {
dwSize uint32
cntUsage uint32
th32ProcessID uint32
th32DefaultHeapID int
th32ModuleID uint32
cntThreads uint32
th32ParentProcessID uint32
pcPriClassBase int32
dwFlags uint32
szExeFile [syscall.MAX_PATH]uint16
}
func getProcessEntry(pid int) (pe *processEntry32, err error) {
snapshot, _, e1 := CreateToolhelp32Snapshot.Call(th32cs_snapprocess, uintptr(0))
if snapshot == uintptr(syscall.InvalidHandle) {
err = fmt.Errorf("CreateToolhelp32Snapshot: %v", e1)
return
}
defer syscall.CloseHandle(syscall.Handle(snapshot))
var processEntry processEntry32
processEntry.dwSize = uint32(unsafe.Sizeof(processEntry))
ok, _, e1 := Process32First.Call(snapshot, uintptr(unsafe.Pointer(&processEntry)))
if ok == 0 {
err = fmt.Errorf("Process32First: %v", e1)
return
}
for {
if processEntry.th32ProcessID == uint32(pid) {
pe = &processEntry
return
}
ok, _, e1 = Process32Next.Call(snapshot, uintptr(unsafe.Pointer(&processEntry)))
if ok == 0 {
err = fmt.Errorf("Process32Next: %v", e1)
return
}
}
}
func getppid() (pid int, err error) {
pe, err := getProcessEntry(os.Getpid())
if err != nil {
return
}
pid = int(pe.th32ParentProcessID)
return
}
// StartedByExplorer returns true if the program was invoked by the user double-clicking
// on the executable from explorer.exe
//
// It is conservative and returns false if any of the internal calls fail.
// It does not guarantee that the program was run from a terminal. It only can tell you
// whether it was launched from explorer.exe
func StartedByExplorer() bool {
ppid, err := getppid()
if err != nil {
return false
}
pe, err := getProcessEntry(ppid)
if err != nil {
return false
}
name := syscall.UTF16ToString(pe.szExeFile[:])
return name == "explorer.exe"
}

View file

@ -0,0 +1,46 @@
// +build windows
// +build go1.4
package mousetrap
import (
"os"
"syscall"
"unsafe"
)
func getProcessEntry(pid int) (*syscall.ProcessEntry32, error) {
snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0)
if err != nil {
return nil, err
}
defer syscall.CloseHandle(snapshot)
var procEntry syscall.ProcessEntry32
procEntry.Size = uint32(unsafe.Sizeof(procEntry))
if err = syscall.Process32First(snapshot, &procEntry); err != nil {
return nil, err
}
for {
if procEntry.ProcessID == uint32(pid) {
return &procEntry, nil
}
err = syscall.Process32Next(snapshot, &procEntry)
if err != nil {
return nil, err
}
}
}
// StartedByExplorer returns true if the program was invoked by the user double-clicking
// on the executable from explorer.exe
//
// It is conservative and returns false if any of the internal calls fail.
// It does not guarantee that the program was run from a terminal. It only can tell you
// whether it was launched from explorer.exe
func StartedByExplorer() bool {
pe, err := getProcessEntry(os.Getppid())
if err != nil {
return false
}
return "explorer.exe" == syscall.UTF16ToString(pe.ExeFile[:])
}

2
vendor/github.com/magefile/mage/.gitattributes generated vendored Normal file
View file

@ -0,0 +1,2 @@
site/* linguist-documentation
vendor/* linguist-vendored

23
vendor/github.com/magefile/mage/.gitignore generated vendored Normal file
View file

@ -0,0 +1,23 @@
# Binaries for programs and plugins
*.exe
*.dll
*.so
*.dylib
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
.glide/
# Magefile output
mage_output_file.go
# VScode
.vscode
# stupid osx
.DS_Store

53
vendor/github.com/magefile/mage/.goreleaser.yml generated vendored Normal file
View file

@ -0,0 +1,53 @@
project_name: mage
release:
github:
owner: magefile
name: mage
draft: true
build:
binary: mage
main: .
ldflags: -s -w -X github.com/magefile/mage/mage.timestamp={{.Date}} -X github.com/magefile/mage/mage.commitHash={{.Commit}} -X github.com/magefile/mage/mage.gitTag={{.Version}}
goos:
- darwin
- linux
- windows
- freebsd
- netbsd
- openbsd
- dragonfly
goarch:
- amd64
- 386
- arm
- arm64
ignore:
- goos: openbsd
goarch: arm
goarm: 6
env:
- CGO_ENABLED=0
archive:
name_template: "{{.Binary}}_{{.Version}}_{{.Os}}-{{.Arch}}"
replacements:
amd64: 64bit
386: 32bit
arm: ARM
arm64: ARM64
darwin: macOS
linux: Linux
windows: Windows
openbsd: OpenBSD
netbsd: NetBSD
freebsd: FreeBSD
dragonfly: DragonFlyBSD
format: tar.gz
format_overrides:
- goos: windows
format: zip
files:
- LICENSE
snapshot:
name_template: SNAPSHOT-{{ .Commit }}
checksum:
name_template: '{{ .ProjectName }}_{{ .Version }}_checksums.txt'

28
vendor/github.com/magefile/mage/.travis.yml generated vendored Normal file
View file

@ -0,0 +1,28 @@
language: go
# prevent double test runs for PRs
branches:
only:
- "master"
# In theory, older versions would probably work fine, but since this isn't a
# library, I'm not going to worry about older versions for now.
go:
- 1.9.x
- 1.8.x
- 1.7.x
# don't call go get ./... because this hides when deps are
# not packaged into the vendor directory.
install: true
# don't call go test -v because we want to be able to only show t.Log output when
# a test fails
script: go test -race $(go list ./... | grep -v /vendor/)
# run a test for every major OS
env:
- GOOS=linux
- GOOS=windows
- GOOS=darwin

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

@ -0,0 +1,41 @@
# 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(!). Let's try to 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 try to avoid using features of go and the stdlib that prevent mage from
being buildable with old versions of Go. Definitely avoid anything that
requires go 1.9.
## 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.

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

@ -0,0 +1,35 @@
<h1 align=center>mage</h1>
<p align="center"><img src="https://user-images.githubusercontent.com/3185864/31061203-6f6743dc-a6ec-11e7-9469-b8d667d9bc3f.png"/></p>
<p align="center">Mage is a make/rake-like build tool using Go.</p>
[![Build Status](https://travis-ci.org/magefile/mage.svg?branch=master)](https://travis-ci.org/magefile/mage)
## 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

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

File diff suppressed because it is too large Load diff

446
vendor/github.com/magefile/mage/build/build_test.go generated vendored Normal file
View file

@ -0,0 +1,446 @@
// 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
import (
"io"
"os"
"path/filepath"
"reflect"
"runtime"
"strings"
"testing"
)
func TestMatch(t *testing.T) {
ctxt := Default
what := "default"
match := func(tag string, want map[string]bool) {
m := make(map[string]bool)
if !ctxt.match(tag, m) {
t.Errorf("%s context should match %s, does not", what, tag)
}
if !reflect.DeepEqual(m, want) {
t.Errorf("%s tags = %v, want %v", tag, m, want)
}
}
nomatch := func(tag string, want map[string]bool) {
m := make(map[string]bool)
if ctxt.match(tag, m) {
t.Errorf("%s context should NOT match %s, does", what, tag)
}
if !reflect.DeepEqual(m, want) {
t.Errorf("%s tags = %v, want %v", tag, m, want)
}
}
match(runtime.GOOS+","+runtime.GOARCH, map[string]bool{runtime.GOOS: true, runtime.GOARCH: true})
match(runtime.GOOS+","+runtime.GOARCH+",!foo", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "foo": true})
nomatch(runtime.GOOS+","+runtime.GOARCH+",foo", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "foo": true})
what = "modified"
ctxt.BuildTags = []string{"foo"}
match(runtime.GOOS+","+runtime.GOARCH, map[string]bool{runtime.GOOS: true, runtime.GOARCH: true})
match(runtime.GOOS+","+runtime.GOARCH+",foo", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "foo": true})
nomatch(runtime.GOOS+","+runtime.GOARCH+",!foo", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "foo": true})
match(runtime.GOOS+","+runtime.GOARCH+",!bar", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "bar": true})
nomatch(runtime.GOOS+","+runtime.GOARCH+",bar", map[string]bool{runtime.GOOS: true, runtime.GOARCH: true, "bar": true})
nomatch("!", map[string]bool{})
}
func TestDotSlashImport(t *testing.T) {
p, err := ImportDir("testdata/other", 0)
if err != nil {
t.Fatal(err)
}
if len(p.Imports) != 1 || p.Imports[0] != "./file" {
t.Fatalf("testdata/other: Imports=%v, want [./file]", p.Imports)
}
p1, err := Import("./file", "testdata/other", 0)
if err != nil {
t.Fatal(err)
}
if p1.Name != "file" {
t.Fatalf("./file: Name=%q, want %q", p1.Name, "file")
}
dir := filepath.Clean("testdata/other/file") // Clean to use \ on Windows
if p1.Dir != dir {
t.Fatalf("./file: Dir=%q, want %q", p1.Name, dir)
}
}
func TestEmptyImport(t *testing.T) {
p, err := Import("", Default.GOROOT, FindOnly)
if err == nil {
t.Fatal(`Import("") returned nil error.`)
}
if p == nil {
t.Fatal(`Import("") returned nil package.`)
}
if p.ImportPath != "" {
t.Fatalf("ImportPath=%q, want %q.", p.ImportPath, "")
}
}
func TestEmptyFolderImport(t *testing.T) {
_, err := Import(".", "testdata/empty", 0)
if _, ok := err.(*NoGoError); !ok {
t.Fatal(`Import("testdata/empty") did not return NoGoError.`)
}
}
func TestMultiplePackageImport(t *testing.T) {
_, err := Import(".", "testdata/multi", 0)
mpe, ok := err.(*MultiplePackageError)
if !ok {
t.Fatal(`Import("testdata/multi") did not return MultiplePackageError.`)
}
want := &MultiplePackageError{
Dir: filepath.FromSlash("testdata/multi"),
Packages: []string{"main", "test_package"},
Files: []string{"file.go", "file_appengine.go"},
}
if !reflect.DeepEqual(mpe, want) {
t.Errorf("got %#v; want %#v", mpe, want)
}
}
func TestLocalDirectory(t *testing.T) {
if runtime.GOOS == "darwin" {
switch runtime.GOARCH {
case "arm", "arm64":
t.Skipf("skipping on %s/%s, no valid GOROOT", runtime.GOOS, runtime.GOARCH)
}
}
cwd, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
p, err := ImportDir(cwd, 0)
if err != nil {
t.Fatal(err)
}
if p.ImportPath != "github.com/magefile/mage/build" {
t.Fatalf("ImportPath=%q, want %q", p.ImportPath, "github.com/magefile/mage/build")
}
}
func TestShouldBuild(t *testing.T) {
const file1 = "// +build tag1\n\n" +
"package main\n"
want1 := map[string]bool{"tag1": true}
const file2 = "// +build cgo\n\n" +
"// This package implements parsing of tags like\n" +
"// +build tag1\n" +
"package build"
want2 := map[string]bool{"cgo": true}
const file3 = "// Copyright The Go Authors.\n\n" +
"package build\n\n" +
"// shouldBuild checks tags given by lines of the form\n" +
"// +build tag\n" +
"func shouldBuild(content []byte)\n"
want3 := map[string]bool{}
ctx := &Context{BuildTags: []string{"tag1"}}
m := map[string]bool{}
if !ctx.shouldBuild([]byte(file1), m, nil) {
t.Errorf("shouldBuild(file1) = false, want true")
}
if !reflect.DeepEqual(m, want1) {
t.Errorf("shouldBuild(file1) tags = %v, want %v", m, want1)
}
m = map[string]bool{}
if ctx.shouldBuild([]byte(file2), m, nil) {
t.Errorf("shouldBuild(file2) = true, want false")
}
if !reflect.DeepEqual(m, want2) {
t.Errorf("shouldBuild(file2) tags = %v, want %v", m, want2)
}
m = map[string]bool{}
ctx = &Context{BuildTags: nil}
if !ctx.shouldBuild([]byte(file3), m, nil) {
t.Errorf("shouldBuild(file3) = false, want true")
}
if !reflect.DeepEqual(m, want3) {
t.Errorf("shouldBuild(file3) tags = %v, want %v", m, want3)
}
}
func TestRequiredTags(t *testing.T) {
tests := []struct {
name string
file string
should bool
}{
{
"no req tag",
"package main",
false,
},
{
"has req tag",
`// +build req
package main`,
true,
},
{
"OR with req",
`// +build no req
package main`,
true,
},
}
ctx := &Context{
BuildTags: []string{"req"},
RequiredTags: []string{"req"},
}
for _, tst := range tests {
t.Run(tst.name, func(t *testing.T) {
if tst.should != ctx.shouldBuild([]byte(tst.file), nil, nil) {
t.Errorf("shouldBuild = %v, want %v", !tst.should, tst.should)
}
})
}
}
type readNopCloser struct {
io.Reader
}
func (r readNopCloser) Close() error {
return nil
}
var (
ctxtP9 = Context{GOARCH: "arm", GOOS: "plan9"}
ctxtAndroid = Context{GOARCH: "arm", GOOS: "android"}
)
var matchFileTests = []struct {
ctxt Context
name string
data string
match bool
}{
{ctxtP9, "foo_arm.go", "", true},
{ctxtP9, "foo1_arm.go", "// +build linux\n\npackage main\n", false},
{ctxtP9, "foo_darwin.go", "", false},
{ctxtP9, "foo.go", "", true},
{ctxtP9, "foo1.go", "// +build linux\n\npackage main\n", false},
{ctxtP9, "foo.badsuffix", "", false},
{ctxtAndroid, "foo_linux.go", "", true},
{ctxtAndroid, "foo_android.go", "", true},
{ctxtAndroid, "foo_plan9.go", "", false},
{ctxtAndroid, "android.go", "", true},
{ctxtAndroid, "plan9.go", "", true},
{ctxtAndroid, "plan9_test.go", "", true},
{ctxtAndroid, "arm.s", "", true},
{ctxtAndroid, "amd64.s", "", true},
}
func TestMatchFile(t *testing.T) {
for _, tt := range matchFileTests {
ctxt := tt.ctxt
ctxt.OpenFile = func(path string) (r io.ReadCloser, err error) {
if path != "x+"+tt.name {
t.Fatalf("OpenFile asked for %q, expected %q", path, "x+"+tt.name)
}
return &readNopCloser{strings.NewReader(tt.data)}, nil
}
ctxt.JoinPath = func(elem ...string) string {
return strings.Join(elem, "+")
}
match, err := ctxt.MatchFile("x", tt.name)
if match != tt.match || err != nil {
t.Fatalf("MatchFile(%q) = %v, %v, want %v, nil", tt.name, match, err, tt.match)
}
}
}
func TestImportCmd(t *testing.T) {
if runtime.GOOS == "darwin" {
switch runtime.GOARCH {
case "arm", "arm64":
t.Skipf("skipping on %s/%s, no valid GOROOT", runtime.GOOS, runtime.GOARCH)
}
}
p, err := Import("cmd/internal/objfile", "", 0)
if err != nil {
t.Fatal(err)
}
if !strings.HasSuffix(filepath.ToSlash(p.Dir), "src/cmd/internal/objfile") {
t.Fatalf("Import cmd/internal/objfile returned Dir=%q, want %q", filepath.ToSlash(p.Dir), ".../src/cmd/internal/objfile")
}
}
var (
expandSrcDirPath = filepath.Join(string(filepath.Separator)+"projects", "src", "add")
)
var expandSrcDirTests = []struct {
input, expected string
}{
{"-L ${SRCDIR}/libs -ladd", "-L /projects/src/add/libs -ladd"},
{"${SRCDIR}/add_linux_386.a -pthread -lstdc++", "/projects/src/add/add_linux_386.a -pthread -lstdc++"},
{"Nothing to expand here!", "Nothing to expand here!"},
{"$", "$"},
{"$$", "$$"},
{"${", "${"},
{"$}", "$}"},
{"$FOO ${BAR}", "$FOO ${BAR}"},
{"Find me the $SRCDIRECTORY.", "Find me the $SRCDIRECTORY."},
{"$SRCDIR is missing braces", "$SRCDIR is missing braces"},
}
func TestExpandSrcDir(t *testing.T) {
for _, test := range expandSrcDirTests {
output, _ := expandSrcDir(test.input, expandSrcDirPath)
if output != test.expected {
t.Errorf("%q expands to %q with SRCDIR=%q when %q is expected", test.input, output, expandSrcDirPath, test.expected)
} else {
t.Logf("%q expands to %q with SRCDIR=%q", test.input, output, expandSrcDirPath)
}
}
}
func TestShellSafety(t *testing.T) {
tests := []struct {
input, srcdir, expected string
result bool
}{
{"-I${SRCDIR}/../include", "/projects/src/issue 11868", "-I/projects/src/issue 11868/../include", true},
{"-I${SRCDIR}", "wtf$@%", "-Iwtf$@%", true},
{"-X${SRCDIR}/1,${SRCDIR}/2", "/projects/src/issue 11868", "-X/projects/src/issue 11868/1,/projects/src/issue 11868/2", true},
{"-I/tmp -I/tmp", "/tmp2", "-I/tmp -I/tmp", true},
{"-I/tmp", "/tmp/[0]", "-I/tmp", true},
{"-I${SRCDIR}/dir", "/tmp/[0]", "-I/tmp/[0]/dir", false},
{"-I${SRCDIR}/dir", "/tmp/go go", "-I/tmp/go go/dir", true},
{"-I${SRCDIR}/dir dir", "/tmp/go", "-I/tmp/go/dir dir", true},
}
for _, test := range tests {
output, ok := expandSrcDir(test.input, test.srcdir)
if ok != test.result {
t.Errorf("Expected %t while %q expands to %q with SRCDIR=%q; got %t", test.result, test.input, output, test.srcdir, ok)
}
if output != test.expected {
t.Errorf("Expected %q while %q expands with SRCDIR=%q; got %q", test.expected, test.input, test.srcdir, output)
}
}
}
// Want to get a "cannot find package" error when directory for package does not exist.
// There should be valid partial information in the returned non-nil *Package.
func TestImportDirNotExist(t *testing.T) {
MustHaveGoBuild(t) // really must just have source
ctxt := Default
ctxt.GOPATH = ""
tests := []struct {
label string
path, srcDir string
mode ImportMode
}{
{"Import(full, 0)", "go/build/doesnotexist", "", 0},
{"Import(local, 0)", "./doesnotexist", filepath.Join(ctxt.GOROOT, "src/go/build"), 0},
{"Import(full, FindOnly)", "go/build/doesnotexist", "", FindOnly},
{"Import(local, FindOnly)", "./doesnotexist", filepath.Join(ctxt.GOROOT, "src/go/build"), FindOnly},
}
for _, test := range tests {
p, err := ctxt.Import(test.path, test.srcDir, test.mode)
if err == nil || !strings.HasPrefix(err.Error(), "cannot find package") {
t.Errorf(`%s got error: %q, want "cannot find package" error`, test.label, err)
}
// If an error occurs, build.Import is documented to return
// a non-nil *Package containing partial information.
if p == nil {
t.Fatalf(`%s got nil p, want non-nil *Package`, test.label)
}
// Verify partial information in p.
if p.ImportPath != "go/build/doesnotexist" {
t.Errorf(`%s got p.ImportPath: %q, want "go/build/doesnotexist"`, test.label, p.ImportPath)
}
}
}
func TestImportVendor(t *testing.T) {
MustHaveGoBuild(t) // really must just have source
ctxt := Default
ctxt.GOPATH = ""
p, err := ctxt.Import("golang_org/x/net/http2/hpack", filepath.Join(ctxt.GOROOT, "src/net/http"), 0)
if err != nil {
t.Fatalf("cannot find vendored golang_org/x/net/http2/hpack from net/http directory: %v", err)
}
want := "vendor/golang_org/x/net/http2/hpack"
if p.ImportPath != want {
t.Fatalf("Import succeeded but found %q, want %q", p.ImportPath, want)
}
}
func TestImportVendorFailure(t *testing.T) {
MustHaveGoBuild(t) // really must just have source
ctxt := Default
ctxt.GOPATH = ""
p, err := ctxt.Import("x.com/y/z", filepath.Join(ctxt.GOROOT, "src/net/http"), 0)
if err == nil {
t.Fatalf("found made-up package x.com/y/z in %s", p.Dir)
}
e := err.Error()
if !strings.Contains(e, " (vendor tree)") {
t.Fatalf("error on failed import does not mention GOROOT/src/vendor directory:\n%s", e)
}
}
func TestImportVendorParentFailure(t *testing.T) {
MustHaveGoBuild(t) // really must just have source
ctxt := Default
ctxt.GOPATH = ""
// This import should fail because the vendor/golang.org/x/net/http2 directory has no source code.
p, err := ctxt.Import("golang_org/x/net/http2", filepath.Join(ctxt.GOROOT, "src/net/http"), 0)
if err == nil {
t.Fatalf("found empty parent in %s", p.Dir)
}
if p != nil && p.Dir != "" {
t.Fatalf("decided to use %s", p.Dir)
}
e := err.Error()
if !strings.Contains(e, " (vendor tree)") {
t.Fatalf("error on failed import does not mention GOROOT/src/vendor directory:\n%s", e)
}
}
// HasGoBuild reports whether the current system can build programs with ``go build''
// and then run them with os.StartProcess or exec.Command.
func HasGoBuild() bool {
switch runtime.GOOS {
case "android", "nacl":
return false
case "darwin":
if strings.HasPrefix(runtime.GOARCH, "arm") {
return false
}
}
return true
}
// MustHaveGoBuild checks that the current system can build programs with ``go build''
// and then run them with os.StartProcess or exec.Command.
// If not, MustHaveGoBuild calls t.Skip with an explanation.
func MustHaveGoBuild(t *testing.T) {
if !HasGoBuild() {
t.Skipf("skipping test: 'go build' not available on %s/%s", runtime.GOOS, runtime.GOARCH)
}
}

556
vendor/github.com/magefile/mage/build/deps_test.go generated vendored Normal file
View file

@ -0,0 +1,556 @@
// 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.
// This file exercises the import parser but also checks that
// some low-level packages do not have new dependencies added.
package build
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
)
// pkgDeps defines the expected dependencies between packages in
// the Go source tree. It is a statement of policy.
// Changes should not be made to this map without prior discussion.
//
// The map contains two kinds of entries:
// 1) Lower-case keys are standard import paths and list the
// allowed imports in that package.
// 2) Upper-case keys define aliases for package sets, which can then
// be used as dependencies by other rules.
//
// DO NOT CHANGE THIS DATA TO FIX BUILDS.
//
var pkgDeps = map[string][]string{
// L0 is the lowest level, core, nearly unavoidable packages.
"errors": {},
"io": {"errors", "sync"},
"runtime": {"unsafe", "runtime/internal/atomic", "runtime/internal/sys"},
"runtime/internal/sys": {},
"runtime/internal/atomic": {"unsafe", "runtime/internal/sys"},
"internal/race": {"runtime", "unsafe"},
"sync": {"internal/race", "runtime", "sync/atomic", "unsafe"},
"sync/atomic": {"unsafe"},
"unsafe": {},
"internal/cpu": {"runtime"},
"L0": {
"errors",
"io",
"runtime",
"runtime/internal/atomic",
"sync",
"sync/atomic",
"unsafe",
"internal/cpu",
},
// L1 adds simple functions and strings processing,
// but not Unicode tables.
"math": {"internal/cpu", "unsafe"},
"math/bits": {},
"math/cmplx": {"math"},
"math/rand": {"L0", "math"},
"strconv": {"L0", "unicode/utf8", "math"},
"unicode/utf16": {},
"unicode/utf8": {},
"L1": {
"L0",
"math",
"math/bits",
"math/cmplx",
"math/rand",
"sort",
"strconv",
"unicode/utf16",
"unicode/utf8",
},
// L2 adds Unicode and strings processing.
"bufio": {"L0", "unicode/utf8", "bytes"},
"bytes": {"L0", "unicode", "unicode/utf8"},
"path": {"L0", "unicode/utf8", "strings"},
"strings": {"L0", "unicode", "unicode/utf8"},
"unicode": {},
"L2": {
"L1",
"bufio",
"bytes",
"path",
"strings",
"unicode",
},
// L3 adds reflection and some basic utility packages
// and interface definitions, but nothing that makes
// system calls.
"crypto": {"L2", "hash"}, // interfaces
"crypto/cipher": {"L2", "crypto/subtle"},
"crypto/subtle": {},
"encoding/base32": {"L2"},
"encoding/base64": {"L2"},
"encoding/binary": {"L2", "reflect"},
"hash": {"L2"}, // interfaces
"hash/adler32": {"L2", "hash"},
"hash/crc32": {"L2", "hash"},
"hash/crc64": {"L2", "hash"},
"hash/fnv": {"L2", "hash"},
"image": {"L2", "image/color"}, // interfaces
"image/color": {"L2"}, // interfaces
"image/color/palette": {"L2", "image/color"},
"reflect": {"L2"},
"sort": {"reflect"},
"L3": {
"L2",
"crypto",
"crypto/cipher",
"crypto/internal/cipherhw",
"crypto/subtle",
"encoding/base32",
"encoding/base64",
"encoding/binary",
"hash",
"hash/adler32",
"hash/crc32",
"hash/crc64",
"hash/fnv",
"image",
"image/color",
"image/color/palette",
"reflect",
},
// End of linear dependency definitions.
// Operating system access.
"syscall": {"L0", "internal/race", "internal/syscall/windows/sysdll", "unicode/utf16"},
"internal/syscall/unix": {"L0", "syscall"},
"internal/syscall/windows": {"L0", "syscall", "internal/syscall/windows/sysdll"},
"internal/syscall/windows/registry": {"L0", "syscall", "internal/syscall/windows/sysdll", "unicode/utf16"},
"time": {
// "L0" without the "io" package:
"errors",
"runtime",
"runtime/internal/atomic",
"sync",
"sync/atomic",
"unsafe",
// Other time dependencies:
"internal/syscall/windows/registry",
"syscall",
},
"internal/poll": {"L0", "internal/race", "syscall", "time", "unicode/utf16", "unicode/utf8"},
"os": {"L1", "os", "syscall", "time", "internal/poll", "internal/syscall/windows"},
"path/filepath": {"L2", "os", "syscall"},
"io/ioutil": {"L2", "os", "path/filepath", "time"},
"os/exec": {"L2", "os", "context", "path/filepath", "syscall"},
"os/signal": {"L2", "os", "syscall"},
// OS enables basic operating system functionality,
// but not direct use of package syscall, nor os/signal.
"OS": {
"io/ioutil",
"os",
"os/exec",
"path/filepath",
"time",
},
// Formatted I/O: few dependencies (L1) but we must add reflect.
"fmt": {"L1", "os", "reflect"},
"log": {"L1", "os", "fmt", "time"},
// Packages used by testing must be low-level (L2+fmt).
"regexp": {"L2", "regexp/syntax"},
"regexp/syntax": {"L2"},
"runtime/debug": {"L2", "fmt", "io/ioutil", "os", "time"},
"runtime/pprof": {"L2", "compress/gzip", "context", "encoding/binary", "fmt", "io/ioutil", "os", "text/tabwriter", "time"},
"runtime/trace": {"L0"},
"text/tabwriter": {"L2"},
"testing": {"L2", "flag", "fmt", "internal/race", "os", "runtime/debug", "runtime/pprof", "runtime/trace", "time"},
"testing/iotest": {"L2", "log"},
"testing/quick": {"L2", "flag", "fmt", "reflect", "time"},
"internal/testenv": {"L2", "OS", "flag", "testing", "syscall"},
// L4 is defined as L3+fmt+log+time, because in general once
// you're using L3 packages, use of fmt, log, or time is not a big deal.
"L4": {
"L3",
"fmt",
"log",
"time",
},
// Go parser.
"go/ast": {"L4", "OS", "go/scanner", "go/token"},
"go/doc": {"L4", "go/ast", "go/token", "regexp", "text/template"},
"go/parser": {"L4", "OS", "go/ast", "go/scanner", "go/token"},
"go/printer": {"L4", "OS", "go/ast", "go/scanner", "go/token", "text/tabwriter"},
"go/scanner": {"L4", "OS", "go/token"},
"go/token": {"L4"},
"GOPARSER": {
"go/ast",
"go/doc",
"go/parser",
"go/printer",
"go/scanner",
"go/token",
},
"go/format": {"L4", "GOPARSER", "internal/format"},
"internal/format": {"L4", "GOPARSER"},
// Go type checking.
"go/constant": {"L4", "go/token", "math/big"},
"go/importer": {"L4", "go/build", "go/internal/gccgoimporter", "go/internal/gcimporter", "go/internal/srcimporter", "go/token", "go/types"},
"go/internal/gcimporter": {"L4", "OS", "go/build", "go/constant", "go/token", "go/types", "text/scanner"},
"go/internal/gccgoimporter": {"L4", "OS", "debug/elf", "go/constant", "go/token", "go/types", "text/scanner"},
"go/internal/srcimporter": {"L4", "fmt", "go/ast", "go/build", "go/parser", "go/token", "go/types", "path/filepath"},
"go/types": {"L4", "GOPARSER", "container/heap", "go/constant"},
// One of a kind.
"archive/tar": {"L4", "OS", "syscall"},
"archive/zip": {"L4", "OS", "compress/flate"},
"container/heap": {"sort"},
"compress/bzip2": {"L4"},
"compress/flate": {"L4"},
"compress/gzip": {"L4", "compress/flate"},
"compress/lzw": {"L4"},
"compress/zlib": {"L4", "compress/flate"},
"context": {"errors", "fmt", "reflect", "sync", "time"},
"database/sql": {"L4", "container/list", "context", "database/sql/driver", "database/sql/internal"},
"database/sql/driver": {"L4", "context", "time", "database/sql/internal"},
"debug/dwarf": {"L4"},
"debug/elf": {"L4", "OS", "debug/dwarf", "compress/zlib"},
"debug/gosym": {"L4"},
"debug/macho": {"L4", "OS", "debug/dwarf"},
"debug/pe": {"L4", "OS", "debug/dwarf"},
"debug/plan9obj": {"L4", "OS"},
"encoding": {"L4"},
"encoding/ascii85": {"L4"},
"encoding/asn1": {"L4", "math/big"},
"encoding/csv": {"L4"},
"encoding/gob": {"L4", "OS", "encoding"},
"encoding/hex": {"L4"},
"encoding/json": {"L4", "encoding"},
"encoding/pem": {"L4"},
"encoding/xml": {"L4", "encoding"},
"flag": {"L4", "OS"},
"go/build": {"L4", "OS", "GOPARSER"},
"html": {"L4"},
"image/draw": {"L4", "image/internal/imageutil"},
"image/gif": {"L4", "compress/lzw", "image/color/palette", "image/draw"},
"image/internal/imageutil": {"L4"},
"image/jpeg": {"L4", "image/internal/imageutil"},
"image/png": {"L4", "compress/zlib"},
"index/suffixarray": {"L4", "regexp"},
"internal/singleflight": {"sync"},
"internal/trace": {"L4", "OS"},
"math/big": {"L4"},
"mime": {"L4", "OS", "syscall", "internal/syscall/windows/registry"},
"mime/quotedprintable": {"L4"},
"net/internal/socktest": {"L4", "OS", "syscall"},
"net/url": {"L4"},
"plugin": {"L0", "OS", "CGO"},
"runtime/pprof/internal/profile": {"L4", "OS", "compress/gzip", "regexp"},
"testing/internal/testdeps": {"L4", "runtime/pprof", "regexp"},
"text/scanner": {"L4", "OS"},
"text/template/parse": {"L4"},
"html/template": {
"L4", "OS", "encoding/json", "html", "text/template",
"text/template/parse",
},
"text/template": {
"L4", "OS", "net/url", "text/template/parse",
},
// Cgo.
// If you add a dependency on CGO, you must add the package to
// cgoPackages in cmd/dist/test.go.
"runtime/cgo": {"L0", "C"},
"CGO": {"C", "runtime/cgo"},
// Fake entry to satisfy the pseudo-import "C"
// that shows up in programs that use cgo.
"C": {},
// Race detector/MSan uses cgo.
"runtime/race": {"C"},
"runtime/msan": {"C"},
// Plan 9 alone needs io/ioutil and os.
"os/user": {"L4", "CGO", "io/ioutil", "os", "syscall"},
// Basic networking.
// Because net must be used by any package that wants to
// do networking portably, it must have a small dependency set: just L0+basic os.
"net": {
"L0", "CGO",
"context", "math/rand", "os", "reflect", "sort", "syscall", "time",
"internal/nettrace", "internal/poll",
"internal/syscall/windows", "internal/singleflight", "internal/race",
"golang_org/x/net/lif", "golang_org/x/net/route",
},
// NET enables use of basic network-related packages.
"NET": {
"net",
"mime",
"net/textproto",
"net/url",
},
// Uses of networking.
"log/syslog": {"L4", "OS", "net"},
"net/mail": {"L4", "NET", "OS", "mime"},
"net/textproto": {"L4", "OS", "net"},
// Core crypto.
"crypto/aes": {"L3"},
"crypto/des": {"L3"},
"crypto/hmac": {"L3"},
"crypto/md5": {"L3"},
"crypto/rc4": {"L3"},
"crypto/sha1": {"L3"},
"crypto/sha256": {"L3"},
"crypto/sha512": {"L3"},
"CRYPTO": {
"crypto/aes",
"crypto/des",
"crypto/hmac",
"crypto/md5",
"crypto/rc4",
"crypto/sha1",
"crypto/sha256",
"crypto/sha512",
"golang_org/x/crypto/chacha20poly1305",
"golang_org/x/crypto/curve25519",
"golang_org/x/crypto/poly1305",
},
// Random byte, number generation.
// This would be part of core crypto except that it imports
// math/big, which imports fmt.
"crypto/rand": {"L4", "CRYPTO", "OS", "math/big", "syscall", "internal/syscall/unix"},
// Mathematical crypto: dependencies on fmt (L4) and math/big.
// We could avoid some of the fmt, but math/big imports fmt anyway.
"crypto/dsa": {"L4", "CRYPTO", "math/big"},
"crypto/ecdsa": {"L4", "CRYPTO", "crypto/elliptic", "math/big", "encoding/asn1"},
"crypto/elliptic": {"L4", "CRYPTO", "math/big"},
"crypto/rsa": {"L4", "CRYPTO", "crypto/rand", "math/big"},
"CRYPTO-MATH": {
"CRYPTO",
"crypto/dsa",
"crypto/ecdsa",
"crypto/elliptic",
"crypto/rand",
"crypto/rsa",
"encoding/asn1",
"math/big",
},
// SSL/TLS.
"crypto/tls": {
"L4", "CRYPTO-MATH", "OS",
"container/list", "crypto/x509", "encoding/pem", "net", "syscall",
},
"crypto/x509": {
"L4", "CRYPTO-MATH", "OS", "CGO",
"crypto/x509/pkix", "encoding/pem", "encoding/hex", "net", "os/user", "syscall",
},
"crypto/x509/pkix": {"L4", "CRYPTO-MATH"},
// Simple net+crypto-aware packages.
"mime/multipart": {"L4", "OS", "mime", "crypto/rand", "net/textproto", "mime/quotedprintable"},
"net/smtp": {"L4", "CRYPTO", "NET", "crypto/tls"},
// HTTP, kingpin of dependencies.
"net/http": {
"L4", "NET", "OS",
"compress/gzip",
"container/list",
"context",
"crypto/rand",
"crypto/tls",
"golang_org/x/net/http2/hpack",
"golang_org/x/net/idna",
"golang_org/x/net/lex/httplex",
"golang_org/x/net/proxy",
"golang_org/x/text/unicode/norm",
"golang_org/x/text/width",
"internal/nettrace",
"mime/multipart",
"net/http/httptrace",
"net/http/internal",
"runtime/debug",
},
"net/http/internal": {"L4"},
"net/http/httptrace": {"context", "crypto/tls", "internal/nettrace", "net", "reflect", "time"},
// HTTP-using packages.
"expvar": {"L4", "OS", "encoding/json", "net/http"},
"net/http/cgi": {"L4", "NET", "OS", "crypto/tls", "net/http", "regexp"},
"net/http/cookiejar": {"L4", "NET", "net/http"},
"net/http/fcgi": {"L4", "NET", "OS", "context", "net/http", "net/http/cgi"},
"net/http/httptest": {"L4", "NET", "OS", "crypto/tls", "flag", "net/http", "net/http/internal", "crypto/x509"},
"net/http/httputil": {"L4", "NET", "OS", "context", "net/http", "net/http/internal"},
"net/http/pprof": {"L4", "OS", "html/template", "net/http", "runtime/pprof", "runtime/trace"},
"net/rpc": {"L4", "NET", "encoding/gob", "html/template", "net/http"},
"net/rpc/jsonrpc": {"L4", "NET", "encoding/json", "net/rpc"},
}
// isMacro reports whether p is a package dependency macro
// (uppercase name).
func isMacro(p string) bool {
return 'A' <= p[0] && p[0] <= 'Z'
}
func allowed(pkg string) map[string]bool {
m := map[string]bool{}
var allow func(string)
allow = func(p string) {
if m[p] {
return
}
m[p] = true // set even for macros, to avoid loop on cycle
// Upper-case names are macro-expanded.
if isMacro(p) {
for _, pp := range pkgDeps[p] {
allow(pp)
}
}
}
for _, pp := range pkgDeps[pkg] {
allow(pp)
}
return m
}
// listStdPkgs returns the same list of packages as "go list std".
func listStdPkgs(goroot string) ([]string, error) {
// Based on cmd/go's matchPackages function.
var pkgs []string
src := filepath.Join(goroot, "src") + string(filepath.Separator)
walkFn := func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() || path == src {
return nil
}
base := filepath.Base(path)
if strings.HasPrefix(base, ".") || strings.HasPrefix(base, "_") || base == "testdata" {
return filepath.SkipDir
}
name := filepath.ToSlash(path[len(src):])
if name == "builtin" || name == "cmd" || strings.Contains(name, "golang_org") {
return filepath.SkipDir
}
pkgs = append(pkgs, name)
return nil
}
if err := filepath.Walk(src, walkFn); err != nil {
return nil, err
}
return pkgs, nil
}
// This test does not function well in travis under different go versions for some reason.
//
// func TestDependencies(t *testing.T) {
// iOS := runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64")
// if runtime.GOOS == "nacl" || iOS {
// // Tests run in a limited file system and we do not
// // provide access to every source file.
// t.Skipf("skipping on %s/%s, missing full GOROOT", runtime.GOOS, runtime.GOARCH)
// }
// ctxt := Default
// all, err := listStdPkgs(ctxt.GOROOT)
// if err != nil {
// t.Fatal(err)
// }
// sort.Strings(all)
// for _, pkg := range all {
// imports, err := findImports(pkg)
// if err != nil {
// t.Error(err)
// continue
// }
// ok := allowed(pkg)
// var bad []string
// for _, imp := range imports {
// if !ok[imp] {
// bad = append(bad, imp)
// }
// }
// if bad != nil {
// t.Errorf("unexpected dependency: %s imports %v", pkg, bad)
// }
// }
// }
var buildIgnore = []byte("\n// +build ignore")
func findImports(pkg string) ([]string, error) {
dir := filepath.Join(Default.GOROOT, "src", pkg)
files, err := ioutil.ReadDir(dir)
if err != nil {
return nil, err
}
var imports []string
var haveImport = map[string]bool{}
for _, file := range files {
name := file.Name()
if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
continue
}
f, err := os.Open(filepath.Join(dir, name))
if err != nil {
return nil, err
}
var imp []string
data, err := readImports(f, false, &imp)
f.Close()
if err != nil {
return nil, fmt.Errorf("reading %v: %v", name, err)
}
if bytes.Contains(data, buildIgnore) {
continue
}
for _, quoted := range imp {
path, err := strconv.Unquote(quoted)
if err != nil {
continue
}
if !haveImport[path] {
haveImport[path] = true
imports = append(imports, path)
}
}
}
sort.Strings(imports)
return imports, nil
}

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
}

226
vendor/github.com/magefile/mage/build/read_test.go generated vendored Normal file
View file

@ -0,0 +1,226 @@
// 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 (
"io"
"strings"
"testing"
)
const quote = "`"
type readTest struct {
// Test input contains where readImports should stop.
in string
err string
}
var readImportsTests = []readTest{
{
`package p`,
"",
},
{
`package p; import "x"`,
"",
},
{
`package p; import . "x"`,
"",
},
{
`package p; import "x";var x = 1`,
"",
},
{
`package p
// comment
import "x"
import _ "x"
import a "x"
/* comment */
import (
"x" /* comment */
_ "x"
a "x" // comment
` + quote + `x` + quote + `
_ /*comment*/ ` + quote + `x` + quote + `
a ` + quote + `x` + quote + `
)
import (
)
import ()
import()import()import()
import();import();import()
var x = 1
`,
"",
},
}
var readCommentsTests = []readTest{
{
`package p`,
"",
},
{
`package p; import "x"`,
"",
},
{
`package p; import . "x"`,
"",
},
{
`// foo
/* bar */
/* quux */ // baz
/*/ zot */
// asdf
Hello, world`,
"",
},
}
func testRead(t *testing.T, tests []readTest, read func(io.Reader) ([]byte, error)) {
for i, tt := range tests {
var in, testOut string
j := strings.Index(tt.in, "")
if j < 0 {
in = tt.in
testOut = tt.in
} else {
in = tt.in[:j] + tt.in[j+len(""):]
testOut = tt.in[:j]
}
r := strings.NewReader(in)
buf, err := read(r)
if err != nil {
if tt.err == "" {
t.Errorf("#%d: err=%q, expected success (%q)", i, err, string(buf))
continue
}
if !strings.Contains(err.Error(), tt.err) {
t.Errorf("#%d: err=%q, expected %q", i, err, tt.err)
continue
}
continue
}
if err == nil && tt.err != "" {
t.Errorf("#%d: success, expected %q", i, tt.err)
continue
}
out := string(buf)
if out != testOut {
t.Errorf("#%d: wrong output:\nhave %q\nwant %q\n", i, out, testOut)
}
}
}
func TestReadImports(t *testing.T) {
testRead(t, readImportsTests, func(r io.Reader) ([]byte, error) { return readImports(r, true, nil) })
}
func TestReadComments(t *testing.T) {
testRead(t, readCommentsTests, readComments)
}
var readFailuresTests = []readTest{
{
`package`,
"syntax error",
},
{
"package p\n\x00\nimport `math`\n",
"unexpected NUL in input",
},
{
`package p; import`,
"syntax error",
},
{
`package p; import "`,
"syntax error",
},
{
"package p; import ` \n\n",
"syntax error",
},
{
`package p; import "x`,
"syntax error",
},
{
`package p; import _`,
"syntax error",
},
{
`package p; import _ "`,
"syntax error",
},
{
`package p; import _ "x`,
"syntax error",
},
{
`package p; import .`,
"syntax error",
},
{
`package p; import . "`,
"syntax error",
},
{
`package p; import . "x`,
"syntax error",
},
{
`package p; import (`,
"syntax error",
},
{
`package p; import ("`,
"syntax error",
},
{
`package p; import ("x`,
"syntax error",
},
{
`package p; import ("x"`,
"syntax error",
},
}
func TestReadFailures(t *testing.T) {
// Errors should be reported (true arg to readImports).
testRead(t, readFailuresTests, func(r io.Reader) ([]byte, error) { return readImports(r, true, nil) })
}
func TestReadFailuresIgnored(t *testing.T) {
// Syntax errors should not be reported (false arg to readImports).
// Instead, entire file should be the output and no error.
// Convert tests not to return syntax errors.
tests := make([]readTest, len(readFailuresTests))
copy(tests, readFailuresTests)
for i := range tests {
tt := &tests[i]
if !strings.Contains(tt.err, "NUL") {
tt.err = ""
}
}
testRead(t, tests, func(r io.Reader) ([]byte, error) { return readImports(r, false, nil) })
}

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 "

62
vendor/github.com/magefile/mage/build/syslist_test.go generated vendored Normal file
View file

@ -0,0 +1,62 @@
// 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
import (
"runtime"
"testing"
)
var (
thisOS = runtime.GOOS
thisArch = runtime.GOARCH
otherOS = anotherOS()
otherArch = anotherArch()
)
func anotherOS() string {
if thisOS != "darwin" {
return "darwin"
}
return "linux"
}
func anotherArch() string {
if thisArch != "amd64" {
return "amd64"
}
return "386"
}
type GoodFileTest struct {
name string
result bool
}
var tests = []GoodFileTest{
{"file.go", true},
{"file.c", true},
{"file_foo.go", true},
{"file_" + thisArch + ".go", true},
{"file_" + otherArch + ".go", false},
{"file_" + thisOS + ".go", true},
{"file_" + otherOS + ".go", false},
{"file_" + thisOS + "_" + thisArch + ".go", true},
{"file_" + otherOS + "_" + thisArch + ".go", false},
{"file_" + thisOS + "_" + otherArch + ".go", false},
{"file_" + otherOS + "_" + otherArch + ".go", false},
{"file_foo_" + thisArch + ".go", true},
{"file_foo_" + otherArch + ".go", false},
{"file_" + thisOS + ".c", true},
{"file_" + otherOS + ".c", false},
}
func TestGoodOSArch(t *testing.T) {
for _, test := range tests {
if Default.goodOSArchFile(test.name, make(map[string]bool)) != test.result {
t.Fatalf("goodOSArchFile(%q) != %v", test.name, test.result)
}
}
}

View file

View file

@ -0,0 +1,5 @@
// Test data - not compiled.
package main
func main() {}

View file

@ -0,0 +1,5 @@
// Test data - not compiled.
package test_package
func init() {}

View file

@ -0,0 +1,5 @@
// Test data - not compiled.
package file
func F() {}

View file

@ -0,0 +1,11 @@
// Test data - not compiled.
package main
import (
"./file"
)
func main() {
file.F()
}

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,
}

34
vendor/github.com/magefile/mage/contrib_test.go generated vendored Normal file
View file

@ -0,0 +1,34 @@
package main
import (
"os"
"os/exec"
"testing"
)
func TestGoFormatted(t *testing.T) {
s, err := run("gofmt", "-l", ".")
if s != "" {
t.Fatalf("the following files are not gofmt'ed:\n%s", s)
}
if err != nil {
t.Error(err)
}
}
func TestGoVet(t *testing.T) {
s, err := run("go", "vet", "./...")
if s != "" {
t.Fatalf("go vet fails with:\n%s", s)
}
if err != nil {
t.Error(err)
}
}
func run(cmd string, args ...string) (string, error) {
c := exec.Command(cmd, args...)
c.Env = os.Environ()
b, err := c.CombinedOutput()
return string(b), err
}

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")
}
`

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

@ -0,0 +1,399 @@
package mage
import (
"crypto/sha1"
"errors"
"flag"
"fmt"
"io"
"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"
)
// mageVer is used when hashing the output binary to ensure that we get a new
// binary if we use a differernt version of mage.
const mageVer = "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"
)
// 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, mageInit, showVersion, 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
}
if showVersion {
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
}
if mageInit {
if err := generateInit(dir); err != nil {
log.Println("Error:", err)
return 1
}
log.Println(initFile, "created")
return 0
}
return Invoke(inv)
}
// 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, mageInit, showVersion bool, 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.BoolVar(&mageInit, "init", false, "create a starting template if no mage files exist")
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")
fs.BoolVar(&showVersion, "version", false, "show version info for the mage binary")
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, mageInit, showVersion, err
}
if err == nil && inv.Help && len(fs.Args()) == 0 {
fs.Usage()
// tell upstream, to just exit
return inv, mageInit, showVersion, flag.ErrHelp
}
// 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
}
}
numFlags := 0
if inv.Help {
numFlags++
}
if mageInit {
numFlags++
}
if showVersion {
numFlags++
}
if numFlags > 1 {
return inv, mageInit, showVersion, errors.New("-h, -init, and -version cannot be used simultaneously")
}
inv.Args = fs.Args()
if inv.Help && len(inv.Args) > 1 {
return inv, mageInit, showVersion, errors.New("-h can only show help for a single target")
}
return inv, mageInit, showVersion, 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
}
// 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,
}
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, "") + mageVer))
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())
}

479
vendor/github.com/magefile/mage/mage/main_test.go generated vendored Normal file
View file

@ -0,0 +1,479 @@
package mage
import (
"bytes"
"flag"
"fmt"
"go/parser"
"go/token"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"time"
"github.com/magefile/mage/build"
"github.com/magefile/mage/mg"
)
func TestMain(m *testing.M) {
os.Exit(testmain(m))
}
func testmain(m *testing.M) int {
// ensure we write our temporary binaries to a directory that we'll delete
// after running tests.
dir := "./testing"
abs, err := filepath.Abs(dir)
if err != nil {
log.Fatal(err)
}
if err := os.Setenv(mg.CacheEnv, abs); err != nil {
log.Fatal(err)
}
if err := os.Mkdir(dir, 0700); err != nil {
if os.IsExist(err) {
os.RemoveAll(dir)
} else {
log.Fatal(err)
}
}
defer os.RemoveAll(dir)
return m.Run()
}
func TestGoRun(t *testing.T) {
c := exec.Command("go", "run", "main.go")
c.Dir = "./testdata"
c.Env = os.Environ()
b, err := c.CombinedOutput()
if err != nil {
t.Error("error:", err)
}
actual := string(b)
expected := "stuff\n"
if actual != expected {
t.Fatalf("expected %q, but got %q", expected, actual)
}
}
func TestVerbose(t *testing.T) {
stderr := &bytes.Buffer{}
stdout := &bytes.Buffer{}
inv := Invocation{
Dir: "./testdata",
Stdout: stdout,
Stderr: stderr,
Args: []string{"testverbose"},
}
code := Invoke(inv)
if code != 0 {
t.Errorf("expected to exit with code 0, but got %v", code)
}
actual := stdout.String()
expected := ""
if actual != expected {
t.Fatalf("expected %q, but got %q", expected, actual)
}
stderr.Reset()
stdout.Reset()
inv.Verbose = true
code = Invoke(inv)
if code != 0 {
t.Errorf("expected to exit with code 0, but got %v", code)
}
actual = stderr.String()
expected = "Running target: TestVerbose\nhi!\n"
if actual != expected {
t.Fatalf("expected %q, but got %q", expected, actual)
}
}
func TestVerboseEnv(t *testing.T) {
os.Setenv("MAGE_VERBOSE", "true")
stdout := &bytes.Buffer{}
inv, _, _, err := Parse(stdout, []string{})
if err != nil {
t.Fatal("unexpected error", err)
}
expected := true
if inv.Verbose != true {
t.Fatalf("expected %t, but got %t ", expected, inv.Verbose)
}
os.Unsetenv("MAGE_VERBOSE")
}
func TestList(t *testing.T) {
stdout := &bytes.Buffer{}
inv := Invocation{
Dir: "./testdata/list",
Stdout: stdout,
Stderr: ioutil.Discard,
List: true,
}
code := Invoke(inv)
if code != 0 {
t.Errorf("expected to exit with code 0, but got %v", code)
}
actual := stdout.String()
expected := `
Targets:
somePig* This is the synopsis for SomePig.
testVerbose
* default target
`[1:]
if actual != expected {
t.Logf("expected: %q", expected)
t.Logf(" actual: %q", actual)
t.Fatalf("expected:\n%v\n\ngot:\n%v", expected, actual)
}
}
func TestNoArgNoDefaultList(t *testing.T) {
stdout := &bytes.Buffer{}
stderr := &bytes.Buffer{}
inv := Invocation{
Dir: "testdata/no_default",
Stdout: stdout,
Stderr: stderr,
}
code := Invoke(inv)
if code != 0 {
t.Errorf("expected to exit with code 0, but got %v", code)
}
if err := stderr.String(); err != "" {
t.Errorf("unexpected stderr output:\n%s", err)
}
actual := stdout.String()
expected := `
Targets:
bazBuz Prints out 'BazBuz'.
fooBar Prints out 'FooBar'.
`[1:]
if actual != expected {
t.Fatalf("expected:\n%q\n\ngot:\n%q", expected, actual)
}
}
func TestTargetError(t *testing.T) {
stderr := &bytes.Buffer{}
inv := Invocation{
Dir: "./testdata",
Stdout: ioutil.Discard,
Stderr: stderr,
Args: []string{"returnsnonnilerror"},
}
code := Invoke(inv)
if code != 1 {
t.Fatalf("expected 1, but got %v", code)
}
actual := stderr.String()
expected := "Error: bang!\n"
if actual != expected {
t.Fatalf("expected %q, but got %q", expected, actual)
}
}
func TestStdinCopy(t *testing.T) {
stdout := &bytes.Buffer{}
stdin := strings.NewReader("hi!")
inv := Invocation{
Dir: "./testdata",
Stderr: ioutil.Discard,
Stdout: stdout,
Stdin: stdin,
Args: []string{"CopyStdin"},
}
code := Invoke(inv)
if code != 0 {
t.Fatalf("expected 0, but got %v", code)
}
actual := stdout.String()
expected := "hi!"
if actual != expected {
t.Fatalf("expected %q, but got %q", expected, actual)
}
}
func TestTargetPanics(t *testing.T) {
stderr := &bytes.Buffer{}
inv := Invocation{
Dir: "./testdata",
Stdout: ioutil.Discard,
Stderr: stderr,
Args: []string{"panics"},
}
code := Invoke(inv)
if code != 1 {
t.Fatalf("expected 1, but got %v", code)
}
actual := stderr.String()
expected := "Error: boom!\n"
if actual != expected {
t.Fatalf("expected %q, but got %q", expected, actual)
}
}
func TestPanicsErr(t *testing.T) {
stderr := &bytes.Buffer{}
inv := Invocation{
Dir: "./testdata",
Stdout: ioutil.Discard,
Stderr: stderr,
Args: []string{"panicserr"},
}
code := Invoke(inv)
if code != 1 {
t.Fatalf("expected 1, but got %v", code)
}
actual := stderr.String()
expected := "Error: kaboom!\n"
if actual != expected {
t.Fatalf("expected %q, but got %q", expected, actual)
}
}
// ensure we include the hash of the mainfile template in determining the
// executable name to run, so we automatically create a new exe if the template
// changes.
func TestHashTemplate(t *testing.T) {
templ := tpl
defer func() { tpl = templ }()
name, err := ExeName([]string{"./testdata/func.go", "./testdata/command.go"})
if err != nil {
t.Fatal(err)
}
tpl = "some other template"
changed, err := ExeName([]string{"./testdata/func.go", "./testdata/command.go"})
if changed == name {
t.Fatal("expected executable name to chage if template changed")
}
}
// Test if the -keep flag does keep the mainfile around after running
func TestKeepFlag(t *testing.T) {
buildFile := fmt.Sprintf("./testdata/keep_flag/%s", mainfile)
os.Remove(buildFile)
defer os.Remove(buildFile)
w := tLogWriter{t}
inv := Invocation{
Dir: "./testdata/keep_flag",
Stdout: w,
Stderr: w,
List: true,
Keep: true,
Force: true, // need force so we always regenerate
}
code := Invoke(inv)
if code != 0 {
t.Fatalf("expected code 0, but got %v", code)
}
if _, err := os.Stat(buildFile); err != nil {
t.Fatalf("expected file %q to exist but got err, %v", buildFile, err)
}
}
type tLogWriter struct {
*testing.T
}
func (t tLogWriter) Write(b []byte) (n int, err error) {
t.Log(string(b))
return len(b), nil
}
// Test if generated mainfile references anything other than the stdlib
func TestOnlyStdLib(t *testing.T) {
buildFile := fmt.Sprintf("./testdata/onlyStdLib/%s", mainfile)
os.Remove(buildFile)
defer os.Remove(buildFile)
w := tLogWriter{t}
inv := Invocation{
Dir: "./testdata/onlyStdLib",
Stdout: w,
Stderr: w,
List: true,
Keep: true,
Force: true, // need force so we always regenerate
Verbose: true,
}
code := Invoke(inv)
if code != 0 {
t.Fatalf("expected code 0, but got %v", code)
}
if _, err := os.Stat(buildFile); err != nil {
t.Fatalf("expected file %q to exist but got err, %v", buildFile, err)
}
fset := &token.FileSet{}
// Parse src but stop after processing the imports.
f, err := parser.ParseFile(fset, buildFile, nil, parser.ImportsOnly)
if err != nil {
fmt.Println(err)
return
}
// Print the imports from the file's AST.
for _, s := range f.Imports {
// the path value comes in as a quoted string, i.e. literally \"context\"
path := strings.Trim(s.Path.Value, "\"")
pkg, err := build.Default.Import(path, "./testdata/keep_flag", build.FindOnly)
if err != nil {
t.Fatal(err)
}
if !filepath.HasPrefix(pkg.Dir, build.Default.GOROOT) {
t.Errorf("import of non-stdlib package: %s", s.Path.Value)
}
}
}
func TestMultipleTargets(t *testing.T) {
var stderr, stdout bytes.Buffer
inv := Invocation{
Dir: "./testdata",
Stdout: &stdout,
Stderr: &stderr,
Args: []string{"TestVerbose", "ReturnsNilError"},
Verbose: true,
}
code := Invoke(inv)
if code != 0 {
t.Errorf("expected 0, but got %v", code)
}
actual := stderr.String()
expected := "Running target: TestVerbose\nhi!\nRunning target: ReturnsNilError\n"
if actual != expected {
t.Errorf("expected %q, but got %q", expected, actual)
}
actual = stdout.String()
expected = "stuff\n"
if actual != expected {
t.Errorf("expected %q, but got %q", expected, actual)
}
}
func TestFirstTargetFails(t *testing.T) {
var stderr, stdout bytes.Buffer
inv := Invocation{
Dir: "./testdata",
Stdout: &stdout,
Stderr: &stderr,
Args: []string{"ReturnsNonNilError", "ReturnsNilError"},
Verbose: true,
}
code := Invoke(inv)
if code != 1 {
t.Errorf("expected 1, but got %v", code)
}
actual := stderr.String()
expected := "Running target: ReturnsNonNilError\nError: bang!\n"
if actual != expected {
t.Errorf("expected %q, but got %q", expected, actual)
}
actual = stdout.String()
expected = ""
if actual != expected {
t.Errorf("expected %q, but got %q", expected, actual)
}
}
func TestBadSecondTargets(t *testing.T) {
var stderr, stdout bytes.Buffer
inv := Invocation{
Dir: "./testdata",
Stdout: &stdout,
Stderr: &stderr,
Args: []string{"TestVerbose", "NotGonnaWork"},
}
code := Invoke(inv)
if code != 2 {
t.Errorf("expected 0, but got %v", code)
}
actual := stderr.String()
expected := "Unknown target specified: NotGonnaWork\n"
if actual != expected {
t.Errorf("expected %q, but got %q", expected, actual)
}
actual = stdout.String()
expected = ""
if actual != expected {
t.Errorf("expected %q, but got %q", expected, actual)
}
}
func TestParse(t *testing.T) {
buf := &bytes.Buffer{}
inv, init, showVer, err := Parse(buf, []string{"-v", "build"})
if err != nil {
t.Fatal("unexpected error", err)
}
if init {
t.Fatal("init should be false but was true")
}
if showVer {
t.Fatal("showVersion should be false but was true")
}
if len(inv.Args) != 1 && inv.Args[0] != "build" {
t.Fatalf("expected args to be %q but got %q", []string{"build"}, inv.Args)
}
if s := buf.String(); s != "" {
t.Fatalf("expected no stdout output but got %q", s)
}
}
// Test the timeout option
func TestTimeout(t *testing.T) {
stderr := &bytes.Buffer{}
inv := Invocation{
Dir: "./testdata/context",
Stdout: ioutil.Discard,
Stderr: stderr,
Args: []string{"timeout"},
Timeout: time.Duration(100 * time.Millisecond),
}
code := Invoke(inv)
if code != 1 {
t.Fatalf("expected 1, but got %v", code)
}
actual := stderr.String()
expected := "Error: context deadline exceeded\n"
if actual != expected {
t.Fatalf("expected %q, but got %q", expected, actual)
}
}
func TestParseHelp(t *testing.T) {
buf := &bytes.Buffer{}
_, _, _, err := Parse(buf, []string{"-h"})
if err != flag.ErrHelp {
t.Fatal("unexpected error", err)
}
buf2 := &bytes.Buffer{}
_, _, _, err = Parse(buf2, []string{"--help"})
if err != flag.ErrHelp {
t.Fatal("unexpected error", err)
}
s := buf.String()
s2 := buf2.String()
if s != s2 {
t.Fatalf("expected -h and --help to produce same output, but got different.\n\n-h:\n%s\n\n--help:\n%s", s, s2)
}
}

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

@ -0,0 +1,180 @@
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() {
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 .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")
fmt.Println({{printf "%q" .Comment}})
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 .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)
}
}
}
func list() 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
}
func handleError(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)
}
}
func runTarget(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
}
}
var ctx context.Context
var ctxCancel func()
func getContext() (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
}
`

View file

@ -0,0 +1,29 @@
// +build mage
package main
import (
"fmt"
"log"
"github.com/magefile/mage/mg"
)
// This should work as a default - even if it's in a different file
var Default = ReturnsNilError
// this should not be a target because it returns a string
func ReturnsString() string {
fmt.Println("more stuff")
return ""
}
func TestVerbose() {
log.Println("hi!")
}
func ReturnsVoid() {
mg.Deps(f)
}
func f() {}

View file

@ -0,0 +1,30 @@
// +build mage
package main
import (
"context"
"errors"
"fmt"
"time"
"github.com/magefile/mage/mg"
)
// Returns a non-nil error.
func TakesContextNoError(ctx context.Context) {
deadline, _ := ctx.Deadline()
fmt.Printf("Context timeout: %v\n", deadline)
}
func Timeout(ctx context.Context) {
time.Sleep(200 * time.Millisecond)
}
func TakesContextWithError(ctx context.Context) error {
return errors.New("Something went sideways")
}
func CtxDeps(ctx context.Context) {
mg.CtxDeps(ctx, TakesContextNoError)
}

10
vendor/github.com/magefile/mage/mage/testdata/error.go generated vendored Normal file
View file

@ -0,0 +1,10 @@
// +build mage
package main
import "errors"
// Returns a non-nil error.
func ReturnsNonNilError() error {
return errors.New("bang!")
}

23
vendor/github.com/magefile/mage/mage/testdata/func.go generated vendored Normal file
View file

@ -0,0 +1,23 @@
// +build mage
package main
import (
"fmt"
"io"
"os"
)
// Synopsis for "returns" error.
// And some more text.
func ReturnsNilError() error {
fmt.Println("stuff")
return nil
}
func CopyStdin() error {
_, err := io.Copy(os.Stdout, os.Stdin)
return err
}
func nonexported() {}

View file

@ -0,0 +1,5 @@
// +build mage
package main
func Noop() {}

View file

@ -0,0 +1,29 @@
// +build mage
package main
import (
"fmt"
"log"
"github.com/magefile/mage/mg"
)
var Default = SomePig
// this should not be a target because it returns a string
func ReturnsString() string {
fmt.Println("more stuff")
return ""
}
func TestVerbose() {
log.Println("hi!")
}
// This is the synopsis for SomePig. There's more data that won't show up.
func SomePig() {
mg.Deps(f)
}
func f() {}

13
vendor/github.com/magefile/mage/mage/testdata/main.go generated vendored Normal file
View file

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

View file

@ -0,0 +1,19 @@
// +build mage
package main
import (
"fmt"
)
// No default so we can check the list().
// Prints out 'FooBar'.
func FooBar() {
fmt.Println("FooBar")
}
// Prints out 'BazBuz'.
func BazBuz() {
fmt.Println("BazBuz")
}

View file

@ -0,0 +1,29 @@
// +build mage
package main
import (
"fmt"
"log"
"github.com/magefile/mage/mg"
)
var Default = SomePig
// this should not be a target because it returns a string
func ReturnsString() string {
fmt.Println("more stuff")
return ""
}
func TestVerbose() {
log.Println("hi!")
}
// This is the synopsis for SomePig. There's more data that won't show up.
func SomePig() {
mg.Deps(f)
}
func f() {}

15
vendor/github.com/magefile/mage/mage/testdata/panic.go generated vendored Normal file
View file

@ -0,0 +1,15 @@
// +build mage
package main
import "errors"
// Function that panics.
func Panics() {
panic("boom!")
}
// Error function that panics.
func PanicsErr() error {
panic(errors.New("kaboom!"))
}

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

@ -0,0 +1,72 @@
//+build mage
package main
import (
"bytes"
"errors"
"fmt"
"os"
"time"
"github.com/magefile/mage/sh"
)
// Runs "go install" for mage. This generates the version info the binary.
func Build() error {
ldf, err := flags()
if err != nil {
return err
}
return sh.Run("go", "install", "-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 {
buf := &bytes.Buffer{}
_, _ = sh.Exec(nil, buf, nil, "git", "describe", "--tags")
return buf.String()
}
// 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
}

147
vendor/github.com/magefile/mage/mg/deps_test.go generated vendored Normal file
View file

@ -0,0 +1,147 @@
package mg_test
import (
"errors"
"fmt"
"testing"
"time"
"github.com/magefile/mage/mg"
)
func TestDepsRunOnce(t *testing.T) {
done := make(chan struct{})
f := func() {
done <- struct{}{}
}
go mg.Deps(f, f)
select {
case <-done:
// cool
case <-time.After(time.Millisecond * 100):
t.Fatal("func not run in a reasonable amount of time.")
}
select {
case <-done:
t.Fatal("func run twice!")
case <-time.After(time.Millisecond * 100):
// cool... this should be plenty of time for the goroutine to have run
}
}
func TestDepsOfDeps(t *testing.T) {
ch := make(chan string, 3)
// this->f->g->h
h := func() {
ch <- "h"
}
g := func() {
mg.Deps(h)
ch <- "g"
}
f := func() {
mg.Deps(g)
ch <- "f"
}
mg.Deps(f)
res := <-ch + <-ch + <-ch
if res != "hgf" {
t.Fatal("expected h then g then f to run, but got " + res)
}
}
func TestDepError(t *testing.T) {
// TODO: this test is ugly and relies on implementation details. It should
// be recreated as a full-stack test.
f := func() error {
return errors.New("ouch!")
}
defer func() {
err := recover()
if err == nil {
t.Fatal("expected panic, but didn't get one")
}
actual := fmt.Sprint(err)
if "ouch!" != actual {
t.Fatalf(`expected to get "ouch!" but got "%s"`, actual)
}
}()
mg.Deps(f)
}
func TestDepFatal(t *testing.T) {
f := func() error {
return mg.Fatal(99, "ouch!")
}
defer func() {
v := recover()
if v == nil {
t.Fatal("expected panic, but didn't get one")
}
actual := fmt.Sprint(v)
if "ouch!" != actual {
t.Fatalf(`expected to get "ouch!" but got "%s"`, actual)
}
err, ok := v.(error)
if !ok {
t.Fatalf("expected recovered val to be error but was %T", v)
}
code := mg.ExitStatus(err)
if code != 99 {
t.Fatalf("Expected exit status 99, but got %v", code)
}
}()
mg.Deps(f)
}
func TestDepTwoFatal(t *testing.T) {
f := func() error {
return mg.Fatal(99, "ouch!")
}
g := func() error {
return mg.Fatal(11, "bang!")
}
defer func() {
v := recover()
if v == nil {
t.Fatal("expected panic, but didn't get one")
}
actual := fmt.Sprint(v)
// order is non-deterministic, so check for both orders
if "ouch!\nbang!" != actual && "bang!\nouch!" != actual {
t.Fatalf(`expected to get "ouch!" and "bang!" but got "%s"`, actual)
}
err, ok := v.(error)
if !ok {
t.Fatalf("expected recovered val to be error but was %T", v)
}
code := mg.ExitStatus(err)
// two different error codes returns, so we give up and just use error
// code 1.
if code != 1 {
t.Fatalf("Expected exit status 1, but got %v", code)
}
}()
mg.Deps(f, g)
}
func TestDepWithUnhandledFunc(t *testing.T) {
defer func() {
err := recover()
expected := "Invalid type for dependent function: func(string) string. Dependencies must be func(), func() error, func(context.Context) or func(context.Context) error"
actual, ok := err.(error)
if !ok {
t.Fatalf("Expected type string from panic")
}
if actual.Error() != expected {
t.Fatalf("Expected panic %v but got %v", expected, err)
}
}()
var NotValid func(string) string = func(a string) string {
return a
}
mg.Deps(NotValid)
}

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()
}

19
vendor/github.com/magefile/mage/mg/errors_test.go generated vendored Normal file
View file

@ -0,0 +1,19 @@
package mg
import "testing"
func TestFatalExit(t *testing.T) {
expected := 99
code := ExitStatus(Fatal(expected))
if code != expected {
t.Fatalf("Expected code %v but got %v", expected, code)
}
}
func TestFatalfExit(t *testing.T) {
expected := 99
code := ExitStatus(Fatalf(expected, "boo!"))
if code != expected {
t.Fatalf("Expected code %v but got %v", expected, code)
}
}

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))
}

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

@ -0,0 +1,271 @@
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
}
// 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: doc.Synopsis(f.Doc),
IsError: typ == mgTypes.ErrorType || typ == mgTypes.ContextErrorType,
IsContext: typ == mgTypes.ContextVoidType || typ == mgTypes.ContextErrorType,
})
}
}
setDefault(p, pi, info)
return pi, nil
}
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")
}
}
}
// 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
}

58
vendor/github.com/magefile/mage/parse/parse_test.go generated vendored Normal file
View file

@ -0,0 +1,58 @@
package parse
import (
"reflect"
"testing"
)
func TestParse(t *testing.T) {
info, err := Package("./testdata", []string{"func.go", "command.go"})
if err != nil {
t.Fatal(err)
}
expected := []Function{
{
Name: "ReturnsNilError",
IsError: true,
Comment: "Synopsis for \"returns\" error.\nAnd some more text.\n",
Synopsis: `Synopsis for "returns" error.`,
},
{
Name: "ReturnsVoid",
},
{
Name: "TakesContextReturnsError",
IsError: true,
IsContext: true,
},
{
Name: "TakesContextReturnsVoid",
IsError: false,
IsContext: true,
},
}
// DefaultIsError
if info.DefaultIsError != true {
t.Fatalf("expected DefaultIsError to be true")
}
// DefaultName
if info.DefaultName != "ReturnsNilError" {
t.Fatalf("expected DefaultName to be ReturnsNilError")
}
for _, fn := range expected {
found := false
for _, infoFn := range info.Funcs {
if reflect.DeepEqual(fn, infoFn) {
found = true
break
}
}
if !found {
t.Fatalf("expected:\n%#v\n\nto be in:\n%#v", fn, info.Funcs)
}
}
}

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...)
}

View file

@ -0,0 +1,33 @@
// +build mage
package main
import (
"context"
"fmt"
"github.com/magefile/mage/mg"
)
// This should work as a default - even if it's in a different file
var Default = ReturnsNilError
// this should not be a target because it returns a string
func ReturnsString() string {
fmt.Println("more stuff")
return ""
}
func ReturnsVoid() {
mg.Deps(f)
}
func f() {}
func TakesContextReturnsVoid(ctx context.Context) {
}
func TakesContextReturnsError(ctx context.Context) error {
return nil
}

14
vendor/github.com/magefile/mage/parse/testdata/func.go generated vendored Normal file
View file

@ -0,0 +1,14 @@
// +build mage
package main
import "fmt"
// Synopsis for "returns" error.
// And some more text.
func ReturnsNilError() error {
fmt.Println("stuff")
return nil
}
func nonexported() {}

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
}

72
vendor/github.com/magefile/mage/sh/cmd_test.go generated vendored Normal file
View file

@ -0,0 +1,72 @@
package sh
import (
"bytes"
"os"
"testing"
)
func TestOutCmd(t *testing.T) {
cmd := OutCmd(os.Args[0], "-printArgs", "foo", "bar")
out, err := cmd("baz", "bat")
if err != nil {
t.Fatal(err)
}
expected := "[foo bar baz bat]"
if out != expected {
t.Fatalf("expected %q but got %q", expected, out)
}
}
func TestExitCode(t *testing.T) {
ran, err := Exec(nil, nil, nil, os.Args[0], "-helper", "-exit", "99")
if err == nil {
t.Fatal("unexpected nil error from run")
}
if !ran {
t.Errorf("ran returned as false, but should have been true")
}
code := ExitStatus(err)
if code != 99 {
t.Fatalf("expected exit status 99, but got %v", code)
}
}
func TestEnv(t *testing.T) {
env := "SOME_REALLY_LONG_MAGEFILE_SPECIFIC_THING"
out := &bytes.Buffer{}
ran, err := Exec(map[string]string{env: "foobar"}, out, nil, os.Args[0], "-printVar", env)
if err != nil {
t.Fatalf("unexpected error from runner: %#v", err)
}
if !ran {
t.Errorf("expected ran to be true but was false.")
}
if out.String() != "foobar\n" {
t.Errorf("expected foobar, got %q", out)
}
}
func TestNotRun(t *testing.T) {
ran, err := Exec(nil, nil, nil, "thiswontwork")
if err == nil {
t.Fatal("unexpected nil error")
}
if ran {
t.Fatal("expected ran to be false but was true")
}
}
func TestAutoExpand(t *testing.T) {
if err := os.Setenv("MAGE_FOOBAR", "baz"); err != nil {
t.Fatal(err)
}
s, err := Output("echo", "$MAGE_FOOBAR")
if err != nil {
t.Fatal(err)
}
if s != "baz" {
t.Fatalf(`Expected "baz" but got %q`, s)
}
}

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)
}

46
vendor/github.com/magefile/mage/sh/testmain_test.go generated vendored Normal file
View file

@ -0,0 +1,46 @@
package sh
import (
"flag"
"fmt"
"os"
"testing"
)
var (
helperCmd bool
printArgs bool
stderr string
stdout string
exitCode int
printVar string
)
func init() {
flag.BoolVar(&helperCmd, "helper", false, "")
flag.BoolVar(&printArgs, "printArgs", false, "")
flag.StringVar(&stderr, "stderr", "", "")
flag.StringVar(&stdout, "stdout", "", "")
flag.IntVar(&exitCode, "exit", 0, "")
flag.StringVar(&printVar, "printVar", "", "")
}
func TestMain(m *testing.M) {
flag.Parse()
if printArgs {
fmt.Println(flag.Args())
return
}
if printVar != "" {
fmt.Println(os.Getenv(printVar))
return
}
if helperCmd {
fmt.Fprintln(os.Stderr, stderr)
fmt.Fprintln(os.Stdout, stdout)
os.Exit(exitCode)
}
os.Exit(m.Run())
}

View file

@ -0,0 +1,6 @@
---
title: "{{ replace .TranslationBaseName "-" " " | title }}"
date: {{ .Date }}
draft: true
---

34
vendor/github.com/magefile/mage/site/config.toml generated vendored Normal file
View file

@ -0,0 +1,34 @@
baseURL = "https://magefile.org"
languageCode = "en-US"
defaultContentLanguage = "en"
title = "Mage Documentation"
theme = "learn"
defaultContentLanguageInSubdir= true
[params]
editURL = "https://github.com/magefile/mage/edit/master/site/content/"
description = "Mage"
author = "Nate Finch"
showVisitedLinks = true
[outputs]
home = [ "HTML", "RSS", "JSON"]
[Languages]
[Languages.en]
title = "Mage"
weight = 1
languageName = "English"
[[Languages.en.menu.shortcuts]]
name = "<i class='fa fa-github'></i> Github repo"
# identifier = "ds"
url = "https://github.com/magefile/mage"
weight = 10
[[Languages.en.menu.shortcuts]]
name = "<i class='fa fa-twitter'></i> Twitter Account"
# identifier = "ds"
url = "https://twitter.com/MagefileDotOrg"
weight = 20

View file

@ -0,0 +1,74 @@
+++
title = "Dependencies"
weight = 30
+++
Mage supports a makefile-style tree of dependencies using the helper library
[github.com/magefile/mage/mg](https://godoc.org/github.com/magefile/mage/mg). To
declare dependencies, pass any number of dependent functions of the following
types:
```
func()
func() error
func(ctx context.Context)
func(ctx context.Context) error
```
(they may be targets, but do not need to be and do not have to be exported) to
`mg.Deps()`, and the Deps function will not return until all declared
dependencies have been run (and any dependencies they have are run).
Dependencies are guaranteed to run exactly once in a single execution of mage,
so if two of your dependencies both depend on the same function, it is still
guaranteed to be run only once, and both funcs that depend on it will not
continue until it has been run.
## Parallelism
If run with `mg.Deps` or `mg.CtxDeps`, dependencies are run in their own
goroutines, so they are parellelized as much as possible given the dependency
tree ordering restrictions. If run with `mg.SerialDeps` or `mg.SerialCtxDeps`,
the dependencies are run serially, though each dependency or sub-dependency will
still only ever be run once.
## Contexts and Cancellation
Dependencies that have a context.Context argument will be passed a context,
either a default context if passed into `mg.Deps` or `mg.SerialDeps`, or the one
passed into `mg.CtxDeps` or `mg.SerialCtxDeps`. The default context, which is
also passed into [targets](/targets) with a context argument, will be cancelled
when and if the timeout specified on the command line is hit.
### Example Dependencies
```go
func Build() {
mg.Deps(f, g)
fmt.Println("Build running")
}
func f() {
mg.Deps(h)
fmt.Println("f running")
}
func g() {
mg.Deps(h)
fmt.Println("g running")
}
func h() {
fmt.Println("h running")
}
```
Running `mage build` will produce the following output:
```
h running
g running
f running
Build running
```
Note that since f and g do not depend on each other, and they're running in
their own goroutines, their order is non-deterministic, other than they are
guaranteed to run after h has finished, and before Build continues.

View file

@ -0,0 +1,18 @@
+++
title = "File Sources and Destinations"
weight = 35
+++
Mage supports make-like comparisons of file sources and file targets. Using the
[target](https://godoc.org/github.com/magefile/mage/target) library, you can
easily compare the last modified times of a target file or directory with the
last modified time of the file or directories required to build that target.
`target.Path` compares the last modified time of a target file or directory with
the last modified time of one or more files or directories. If any of the
sources are newer than the destination, the function will return true. Note
that Path does not recurse into directories. If you give it a directory, the
only last modified time it'll check is that of the directory itself.
`target.Dir` is like `target.Path` except that it recursively checks files and
directories under any directories specified, comparing timestamps.

View file

@ -0,0 +1,23 @@
+++
title="How It Works"
weight = 50
+++
Mage scans the current directory for go files with the `mage` build tag (i.e.
`// +build mage`), using the normal go build rules for following build
constraints (aside from requiring the mage tag). It then parses those files to
find the build targets, generates a main file for the command, and compiles a
binary from those files. The magefiles are hashed so that if they remain
unchanged, the same compiled binary will be reused next time, to avoid the
generation overhead.
## Binary Cache
Compiled magefile binaries are stored in $HOME/.magefile. This location can be
customized by setting the MAGEFILE_CACHE environment variable.
## Go Environment
Mage itself requires no dependencies to run. However, because it is compiling
go code, you must have a valid go environment set up on your machine. Mage is
compatible with any go 1.x environment.

72
vendor/github.com/magefile/mage/site/content/index.md generated vendored Normal file
View file

@ -0,0 +1,72 @@
+++
title = "Mage"
+++
<p align="center"><img width=300 src="/images/gary.svg"/></p>
<p align="center">Mage is a make/rake-like build tool using Go.</p>
## 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). To
install, just use `go get`:
`go get github.com/magefile/mage`
## Demo
{{< youtube GOqbD0lF-iA >}}
## Discussion
Join the `#mage` channel on [gophers slack](https://gophers.slack.com/messages/general/) for discussion of usage, development, etc.
## Plugins
There are no plugins. You don't need plugins. It's just Go code. You can
import whatever libraries you want. Every library in the go ecosystem is a mage
plugin. Every tool you use with Go can be used with Magefiles.
## Usage
```
mage [options] [target]
Options:
-f force recreation of compiled magefile
-h show this help
-init
create a starting template if no mage files exist
-keep
keep intermediate mage files around after running
-l list mage targets in this directory
-t string
timeout in duration parsable format (e.g. 5m30s)
-v show verbose output when running mage targets
-version
show version info for the mage binary
```
## Environment Variables
You may set MAGE_VERBOSE=1 to always enable verbose logging in your magefiles,
without having to remember to pass -v every time.
## 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?
## Code
[https://github.com/magefile/mage](https://github.com/magefile/mage)
## Projects that build with Mage
[![Hugo](/images/hugo.png)](https://github.com/gohugoio/hugo) [![Gnorm](/images/gnorm.png)](https://github.com/gnormal/gnorm)

View file

@ -0,0 +1,20 @@
+++
title = "Helper Libraries"
weight = 45
+++
There are three helper libraries bundled with mage,
[mg](https://godoc.org/github.com/magefile/mage/mg),
[sh](https://godoc.org/github.com/magefile/mage/sh), and
[target](https://godoc.org/github.com/magefile/mage/target)
Package `mg` contains mage-specific helpers, such as Deps for declaring
dependent functions, and functions for returning errors with specific error
codes that mage understands.
Package `sh` contains helpers for running shell-like commands with an API that's
easier on the eyes and more helpful than os/exec, including things like
understanding how to expand environment variables in command args.
Package `target` contains helpers for performing make-like timestamp cmoparing
of files. It makes it easy to bail early if this target doesn't need to be run.

View file

@ -0,0 +1,85 @@
+++
title = "Magefiles"
weight = 20
+++
A mage file is any regular go file marked with a build target of "mage" and in
package main.
```go
// +build mage
package main
```
You can quickly create a template mage file with the `-init` option.
`mage -init`
You may have any number of magefiles in the same directory. Mage doesn't care
what they're named aside from normal go filename rules. All they need is to
have the mage build target. Handily, this also excludes them from your regular
builds, so they can live side by side with your normal go files. Magefiles may
use any of Go's usual build constraints, so you can include and exclude
magefiles based on OS, arch, etc, whether in the filename or in the +build line.
```go
// +build mage
package main
import (
"log"
"os"
)
// Build target is any exported function with zero args with no return or an error return.
// If a target has an error return and returns an non-nil error, mage will print
// that error to stdout and return with an exit code of 1.
func Install() error {
}
// The first sentence in the comment will be the short help text shown with mage -l.
// The rest of the comment is long help text that will be shown with mage -h <target>
func Target() {
// by default, the log stdlib package will be set to discard output.
// Running with mage -v will set the output to stdout.
log.Printf("Hi!")
}
// A var named Default indicates which target is the default.
var Default = Install
// Because build targets are case insensitive, you may not have two build targets
// that lowercase to the same text. This would give you an error when you tried
// to run the magefile:
// func BUILD() {}
// Targets may have a context argument, in which case a default context is passed
// to the target, which will be cancelled after a timeout if the -t flag is used.
func Build(ctx context.Context) {
mg.CtxDeps(ctx, Target)
}
```
```
$ mage -l
Targets:
install* Build target is any exported function with zero args with no return or an error return.
target The first sentence in the comment will be the short help text shown with mage -l.
* default target
```
```
$ mage -h target
mage target:
The first sentence in the comment will be the short help text shown with mage -l.
The rest of the comment is long help text that will be shown with mage -h <target>
```

View file

@ -0,0 +1,50 @@
+++
title = "Targets"
weight = 10
+++
A target is any exported function that is one of the following types:
```
func()
func() error
func(context.Context)
func(context.Context) error
```
A target is effectively a subcommand of mage while running mage in
this directory. i.e. you can run a target by running `mage <target>`
If the function has an error return, errors returned from the function will
print to stdout and cause the magefile to exit with an exit code of 1. Any
functions that do not fit this pattern are not considered targets by mage.
Comments on the target function will become documentation accessible by running
`mage -l` which will list all the build targets in this directory with the first
sentence from their docs, or `mage -h <target>` which will show the full comment
from the docs on the function.
A target may be designated the default target, which is run when the user runs
`mage` with no target specified. To denote the default, create a `var Default =
<targetname>` If no default target is specified, running `mage` with no target
will print the list of targets, like `mage -l`.
## Multiple Targets
Multiple targets can be specified as args to Mage, for example `mage foo bar
baz`. Targets will be run serially, from left to right (so in thise case, foo,
then once foo is done, bar, then once bar is done, baz). Dependencies run using
mg.Deps will still only run once per mage execution, so if each of the targets
depend on the same function, that function will only be run once for all
targets. If any target panics or returns an error, no later targets will be run.
## Contexts and Cancellation
A default context is passed into any target with a context argument. This
context will have a timeout if mage was run with -t, and thus will cancel the
running targets and dependencies at that time. To pass this context to
dependencies, use mg.CtxDeps(ctx, ...) to pass the context from the target to
its dependencies (and pass the context to sub-dependencies). Dependencies run
with mg.Deps will not get the starting context, and thus will not be cancelled
when the timeout set with -t expires.
mg.CtxDeps will pass along whatever context you give it, so if you want to
modify the original context, or pass in your own, that will work like you expect
it to.

View file

@ -0,0 +1,42 @@
+++
title = "Zero Install Option"
weight = 40
+++
Don't want to depend on another binary in your environment? You can run mage
directly out of your vendor directory (or GOPATH) with `go run`.
Just save a file like this (I'll call it `mage.go`, but it can be named
anything. Note that the build tag is *not* `+build mage`. Mage will create its own main file, so we need this one to be excluded from when your magefiles are compiled.
Now you can `go run mage.go <target>` and it'll work just as if you ran `mage
<target>`
```go
// +build ignore
package main
import (
"os"
"github.com/magefile/mage/mage"
)
func main() { os.Exit(mage.Main()) }
```
Note that because of the peculiarities of `go run`, if you run this way, go run
will only ever exit with an error code of 0 or 1. If mage exits with error code
99, for example, `go run` will print out `exit status 99" and then exit with
error code 1. Why? Ask the go team. I've tried to get them to fix it, and
they won't.
## Use Mage as a library
All of mage's functionality is accessible as a compile-in library. Checkout
[godoc.org/github.com/magefile/mage/mage](https://godoc.org/github.com/mage/mage)
for full details.
Fair warning, the API of mage/mage may change, so be sure to use vendoring.

View file

@ -0,0 +1,2 @@
<link rel="shortcut icon" href="/images/favicon.ico" type="image/x-icon">
<link rel="icon" href="/images/favicon.ico" type="image/x-icon">

View file

@ -0,0 +1,2 @@
<h1>Mage</h1>
<a id="logo" href="/"><img src="/images/gary.svg" width=300px /></a>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 KiB

View file

@ -0,0 +1,342 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_3" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1250 1250" style="enable-background:new 0 0 1250 1250;" xml:space="preserve">
<style type="text/css">
.st0{fill:#0D526D;stroke:#000000;stroke-miterlimit:10;}
.st1{fill:#6ACFFB;stroke:#000000;stroke-miterlimit:10;}
.st2{fill:url(#SVGID_1_);}
.st3{fill:#54AECF;stroke:#000000;stroke-miterlimit:10;}
.st4{fill:#FFFFFF;}
.st5{fill:#D1B482;stroke:#000000;stroke-miterlimit:10;}
.st6{fill:#FFEBE6;}
.st7{fill:url(#SVGID_2_);}
.st8{fill:url(#SVGID_3_);}
.st9{fill:url(#SVGID_4_);}
.st10{fill:#1A83B7;stroke:#000000;stroke-miterlimit:10;}
.st11{fill:url(#SVGID_5_);}
.st12{fill:url(#SVGID_6_);}
.st13{fill:url(#SVGID_7_);}
.st14{fill:url(#SVGID_8_);}
.st15{fill:#916243;stroke:#000000;stroke-miterlimit:10;}
.st16{fill:#7A4F37;}
.st17{fill:none;stroke:#000000;stroke-miterlimit:10;}
.st18{fill:url(#SVGID_9_);}
.st19{fill:url(#SVGID_10_);}
.st20{fill:url(#SVGID_11_);}
.st21{fill:url(#SVGID_12_);stroke:#000000;stroke-miterlimit:10;}
.st22{fill:url(#SVGID_13_);}
.st23{fill:url(#SVGID_14_);}
.st24{fill:url(#SVGID_15_);}
.st25{fill:url(#SVGID_16_);stroke:#000000;stroke-miterlimit:10;}
.st26{fill:url(#SVGID_17_);}
.st27{fill:url(#SVGID_18_);}
.st28{fill:url(#SVGID_19_);}
.st29{stroke:#000000;stroke-miterlimit:10;}
.st30{fill:#D1B482;}
.st31{fill:url(#SVGID_20_);}
.st32{fill:none;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
.st33{fill:#D1B482;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
.st34{fill:url(#SVGID_21_);}
.st35{fill:url(#SVGID_22_);}
</style>
<g>
<path class="st0" d="M430.6,655.5c0,0-73.3-2-88,0s-32.3,11-25.4,27s92.8,15,124.1,20s156.4,52,201.3,56c45,4,192.5-21,226.7-42
s61.4-44.7,51.8-52c-26.4-20-155.4,10-155.4,10L430.6,655.5z"/>
<g>
<path class="st1" d="M538.5,447.5c0,0-117,96-138,234s9,349,9,349l439,12c0,0,38-320,36-389s-130-211-130-211c-18-8-137-28-160-21
S538.5,447.5,538.5,447.5z"/>
</g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="502.8435" y1="722.8057" x2="498.6619" y2="660.6495">
<stop offset="0.2872" style="stop-color:#6ACFFB"/>
<stop offset="0.8764" style="stop-color:#54AECF"/>
</linearGradient>
<path class="st2" d="M461.9,705.5c22.5,9.3,48.6,8.8,71-0.7c24.5-10.5,44.8-33.4,46.9-60c-30.5,21.7-71.4,23.9-107.9,15.8
c-9.2-2-63.1-17.3-54.3,4C425.1,682.9,444,698.1,461.9,705.5z"/>
<path class="st3" d="M436.6,484.1c-8-3.2-16.4-5.4-24.9-6.6c-4.6-0.7-9.6-0.9-13.4,1.6c-4.9,3.2-6.3,9.9-4.8,15.6
c1.4,5.6,5.1,10.4,8.7,14.9c5,6.4,10,12.8,15.1,19.2c2.1,2.7,4.5,5.6,7.9,6.4c3.5,0.8,7.1-0.8,10.3-2.4c5.6-2.8,11.3-5.7,16.9-8.5
c10.8-5.4,23.2-13.5,22.5-25.6c-0.5-8.4-7.9-15.2-16-17.7s-16.8-1.6-25.2-0.7"/>
<path class="st3" d="M898.2,529.1c8-3.2,16.4-5.4,24.9-6.6c4.6-0.7,9.6-0.9,13.4,1.6c4.9,3.2,6.3,9.9,4.8,15.6
c-1.4,5.6-5.1,10.4-8.7,14.9c-5,6.4-10,12.8-15.1,19.2c-2.1,2.7-4.5,5.6-7.9,6.4c-3.5,0.8-7.1-0.8-10.3-2.4
c-5.6-2.8-11.3-5.7-16.9-8.5c-10.8-5.4-23.2-13.5-22.5-25.6c0.5-8.4,7.9-15.2,16-17.7s16.8-1.6,25.2-0.7"/>
<g>
<path class="st4" d="M645.5,720.3c-9.3,0-16.8-6.1-19.5-16c-2.7-9.9,2.1-27.6,2.9-30.4h47.2c0.5,3.9,3.6,31.8-0.9,37.2
c-4.5,5.4-12.1,6.6-22.8,8.3c-1,0.2-1.9,0.3-2.9,0.5C648.1,720.2,646.8,720.3,645.5,720.3C645.5,720.3,645.5,720.3,645.5,720.3z"
/>
<path d="M675.6,674.5c1.1,9.4,2.9,31.9-0.9,36.4c-4.3,5.2-11.9,6.5-22.5,8.2c-1,0.2-1.9,0.3-2.9,0.5c-1.3,0.2-2.6,0.3-3.8,0.3
c-9.1,0-16.4-6-19-15.6c-2.6-9.4,1.8-26.1,2.8-29.7H675.6 M676.5,673.5h-48c0,0-6,20-3,31c2.7,9.7,10,16.3,20,16.3
c1.3,0,2.6-0.1,4-0.3c12-2,21-3,26-9S676.5,673.5,676.5,673.5L676.5,673.5z"/>
</g>
<path class="st5" d="M510.5,410.9"/>
<path class="st5" d="M808,458.6"/>
<g>
<path class="st6" d="M657.9,658.5c0,0-73.3,1-44,34.2c9.8,11.1,20.7-1,34.5,0c13.8,1,19.8,13.1,30.2,11.1s16.4-21.1,9.5-30.2
C681.2,664.5,657.9,658.5,657.9,658.5z"/>
</g>
<g>
<path class="st1" d="M516.5,1098.4c0,0-45,29.1-40.1,39.9c2.6,5.8,11.4,13.8,30.4,7.4c32.6-11,36.3-26,44.5-38.9
c5.3-8.4-7.7-24.9-7.7-24.9L516.5,1098.4z"/>
</g>
<g>
<path class="st1" d="M787.5,1108.5c0,0,50,24,40,40s-47,13-59,0c-9.7-10.5-26-37-26-37L787.5,1108.5z"/>
</g>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="801.3585" y1="1163.4755" x2="774.4741" y2="1102.8389">
<stop offset="0.2872" style="stop-color:#6ACFFB"/>
<stop offset="0.8764" style="stop-color:#54AECF"/>
</linearGradient>
<path class="st7" d="M811.6,1128.5c-5.2,0.7-10.4,1.4-15.6,2c-5.9,0.8-11.9,1.6-17.2,4.4c-5.2,2.8-9.6,8.1-9.5,14
c-7.8-8.5-10.8-16-17.3-23.1c17.1-3.4,34.7-4.1,52-2.3c5.5,0.6,10.5,1.8,14.8,5.4C816.5,1128,814,1128.2,811.6,1128.5z"/>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="493.4951" y1="1149.1807" x2="527.7737" y2="1102.3068">
<stop offset="0.2872" style="stop-color:#6ACFFB"/>
<stop offset="0.8764" style="stop-color:#54AECF"/>
</linearGradient>
<path class="st8" d="M495.7,1123.1c5.7,0.5,12.1,1.9,15,6.8c2.4,4.2,1.3,9.6-1,13.9c14.4-3.3,26.4-12.5,34.2-25.1
c-18.7,0.4-36.4,0.8-55.1,1.3c-2,0-4.4,1-2.1,2.7C488.1,1123.7,493.8,1122.9,495.7,1123.1z"/>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="673.763" y1="685.9106" x2="860.0123" y2="685.9106">
<stop offset="0.2872" style="stop-color:#6ACFFB"/>
<stop offset="0.8764" style="stop-color:#54AECF"/>
</linearGradient>
<path class="st9" d="M699,759c-16,11,128.5-5.2,129.5-4.5c0.8,0.6,1.9,0.5,2.8,0.4c10.8-1,21.6-2.1,32.5-3.1
c3.2-0.3,6.5-0.7,9.1-2.5c2.8-1.9,7.4-44.4,10.1-46.3c0.4-0.3,0-29,0-29c-1.4-4.5,3-5.8-0.2-9.2c-5.8-6-14.3-8.3-22.4-10.4
c-34.8-9.3-68.7-22.1-100.9-38.2c-5.7-2.8-11.5-5.8-17.8-6.9c-26.2-4.6-12.9,41.4-6.7,54.7C743.3,682,724.6,741.4,699,759z"/>
<g>
<path class="st10" d="M362,741.9c2.7,3.2,5.2,0.9-2.7,17.2c-7.9,16.3,13.8,111,0.6,164.9c-3.2,13.1-7.4,26.5-16.1,36.7
c-5.8,6.8-13.5,12.1-18.2,19.7c-4.6,7.4-6.1,16.4-10.3,24.1c-4.8,8.8-12.9,15.3-20.9,21.3c-34.1,25.6-110.7,57-109.5,65.3
c21.8,26.3,84.4,12.2,126.6,18.3c31.7,4.6,63.3,9.1,95.3,11c87.6,5.2,175.5-10,262.9-3.2c43.2,3.4,86.3,12.1,129.6,9.9
c36.3-1.9,71.8-11.4,106.9-20.9c39.3-10.6,78.6-21.2,117.8-31.8c7-1.9,15.4-5.3,16.2-12.7c0.8-7.6-7.2-12.8-14.2-15.3
c-20.6-7.5-43.2-9.1-62.7-19.2c-6.1-3.2-12.7-8.9-11.5-15.8c0.6-3.6,3.2-6.5,4.6-9.8c4.6-10.9-4.1-22.5-11.6-31.6
c-41.2-49.9-61.9-117.1-55.9-182.2c1.3-14,4-28.6,12.6-39.6c7.6-27.1,21.7-60.7,21.7-81.7c-111.4,134.5-350.2,41-524.1,30
c-81.1-5.1-83.1-22-83.1-22C303.7,693.9,351.3,729.3,362,741.9z"/>
</g>
<g>
<g>
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="598" y1="894.7486" x2="921.0349" y2="894.7486">
<stop offset="0" style="stop-color:#1A83B7"/>
<stop offset="0.8522" style="stop-color:#0E5E77"/>
</linearGradient>
<path class="st11" d="M1026.2,1046.4c-20.6-7.5-43.2-9.1-62.7-19.2c-6.1-3.2-12.7-8.9-11.5-15.8c0.6-3.6,3.2-6.5,4.6-9.8
c4.6-10.9-4.1-22.5-11.6-31.6c-41.2-49.9-61.9-117.1-55.9-182.2c1.3-14,4-28.6,12.6-39.6c7.3-25.8,20.3-57.3,21.6-78.4
c-4.2,3.7-8.4,7.3-12.8,10.8c-29,28.4-65,44.3-105.3,51.9c-16.3,4-33,6.4-49.7,8.3C745,742,733.1,744,723,745
c-10.2,1-21,4-17.9,10.1c5.1,2.6,10.1,5.2,15.2,7.8c1.5,0.7,3,1.6,3.6,3.2c1.2,3.5-3.4,5.9-7,6.7c-37.2,7.7-75.2,11.8-113.3,12.1
c1.9,8.5,12.3,11.6,20.9,13.1c25.2,4.4,50.4,8.9,75.7,13.3c5.2,0.9,11.8,3.6,11.2,8.8c-0.3,2.4-2.2,4.3-3.9,5.9
c-13.6,12.3-29.1,22.4-45.9,29.9c8.8,7.4,9.3,20.4,10.3,31.8c3,31.6,15.6,62.3,35.8,86.8c1.8,2.2,3.8,4.5,4.5,7.3
c1.1,4.6-1.4,9.2-3.6,13.5c-3.6,6.9-6.6,14.2-8.8,21.6c-0.7,2.5-1.4,5.1-0.7,7.5c1.6,5.4,8.6,7,14.1,6c5.5-1,10.9-3.6,16.4-3
c3.1,7.3-2.4,15.2-7.8,21c-9,9.5-19,18.2-26.4,29c-7.4,10.8-16.6,27.9-13.3,40.6c0.9,0.2,1.8,0.4,2.7,0.7
c24.7,2.5,49.4,6.2,74.1,7.9c3.8,0.2,7.6,0.3,11.3,0.5c4.6,0.2,9.1,0.4,13.7,0.5c5.2,0,10.4-0.1,15.7-0.4
c36.3-1.9,71.8-11.4,106.9-20.9c39.3-10.6,78.6-21.2,117.8-31.8c7-1.9,15.4-5.3,16.2-12.7
C1041.1,1054.2,1033.2,1049,1026.2,1046.4z"/>
</g>
</g>
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="609.7143" y1="988.8874" x2="669.9747" y2="898.996">
<stop offset="0" style="stop-color:#1A83B7;stop-opacity:0"/>
<stop offset="0.6251" style="stop-color:#0E5E77"/>
</linearGradient>
<path class="st12" d="M639.6,939.4c-10.6-9.1-19.2-20.2-28.7-30.5c-5.2-5.7-11-11.3-18.3-13.9s-16.5-1.2-21,5c-0.5,0.7-1,1.6-1,2.5
c-0.1,1.4,0.9,2.6,1.8,3.7c16.4,19.2,32.7,38.4,49.1,57.6c3.3,3.9,6.6,7.7,10.3,11.2c4.3,3.9,9.1,7.2,13.4,11.1
c6.8,6.2,12.2,14,16.2,22.3c5.1,10.6,8.1,22.2,8.7,34c3.3-0.8,4.4-5,4.7-8.4c2.2-21.9,5.2-45.5,3.4-67.5c-1.1-13-4.4-9.1-16.1-13.3
C653.8,950.2,646.2,945.1,639.6,939.4z"/>
<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="425.4122" y1="815.0155" x2="536.7072" y2="733.6134">
<stop offset="0" style="stop-color:#1A83B7;stop-opacity:0"/>
<stop offset="0.6251" style="stop-color:#0E5E77"/>
</linearGradient>
<path class="st13" d="M419.4,741.2c14.3,27.4,34.9,50.9,56.8,72.7c9.3,9.3,34.8,40.1,35.8,43.1c8.4,3.6-1.2-2.5,7.2,1
c3.9,1.7,8,3.3,12.2,3c4.2-0.4,8.6-3.5,8.7-7.7c0.1-3.7-2.8-6.7-5.4-9.3c-31.9-30.8-61.3-64.2-87.6-99.9
c-8.9-12.1-20.9-31.6-35.9-36.9c-10.9-3.8-10.4-0.6-6.2,7.6C409.4,723.7,414.8,732.3,419.4,741.2z"/>
<linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="455.0909" y1="1016.1805" x2="440.2752" y2="1193.2762">
<stop offset="0" style="stop-color:#1A83B7;stop-opacity:0"/>
<stop offset="0.6251" style="stop-color:#0E5E77"/>
</linearGradient>
<path class="st14" d="M709,1103c-17.3,1.2-87-1.9-93.6-1.3c-17.8,1.6-35.1-4.7-52.3-10c1.8-3.3,0.5-7.8-2.3-10.5
c-2.9-2.8-6.9-4.1-10.9-5.1c-14.1-3.5-28.7-4.3-42.6-8.7c-6.6-2.1-13-5-19.3-7.9c-19.2-8.7-38.6-17.5-55.9-29.6
c-4.1-2.9-8.1-5.9-12.3-8.6c-2.5,6.3,1.2,13.1,4.7,18.8c4.4,7.1,8.7,14.2,13.1,21.3c1.1,1.7,2.1,3.6,1.9,5.6c0,0.4,1.1,1,3.3,1.8
c-0.1,0-0.2,0-0.2,0c-6.1-1-12.2-1.9-18.4-2c-6.8-0.1-13.6,0.9-20.4,1.3c-14.5,0.8-28-2.1-42.2-3.4c-15.9-1.5-30.3,4.7-45.6,7.9
c-22.7,4.7-46.6-0.1-69.1,5.7c4.3,1.1,5,7.6,2,10.9s-7.7,4.2-12.1,4.7c-16.7,1.9-33.7,1.5-50.2-1.3c24.3,18.8,58.2,16.5,88.9,14.5
c26.5-1.7,45.5,3,71.6,7.9c11.1,2.1,34.9,3.3,46,5c10.8,1.7,21.1,0.6,32,1c22.6,0.9,40.7-0.3,63.3-1.3c19.2-0.9,45.4-0.8,64.7-1.7
c21.1-1,35.3-2.9,56.5-2.3c30.3,0.8,58.5-0.7,88.5,3.3C708,1122,711.5,1102.8,709,1103z"/>
<path class="st15" d="M167.3,514.3c-4.8,27.7,4.2,58.7,26.4,75.9c24.4,18.8,57.9,18.2,88.2,24.1c30.3,5.9,63.8,26.6,62.1,57.4
c-0.2,4.1-1.1,8.4,0.6,12.2c2.8,6.4,11,7.9,17.8,9.9c20.7,6.1,35.3,23.9,49.2,40.3c25.1,29.4,52.2,57,79.7,84.1
c66.1,65.1,134.5,127.7,205.1,187.8c22,18.7,44.3,37.2,66.5,55.7c47.1,39.1,94.1,78.3,141.2,117.4c0.8-12.5-8.1-23.2-16.7-32.3
c-55.1-58.7-119.2-108.1-179.5-161.5c-69.4-61.6-133.8-128.8-194.2-199.1c-36.9-43-72.9-87.6-117.9-122
c-16-12.2-27.7-48.8-41.4-63.6c-11.5-12.4-25.6-1.4-34.2-15.9c-5.7-9.6-11-22.9-3-30.7c5.3-5.2,14.8-5.4,18.7-11.8
c3.3-5.6,0.4-12.7-2.5-18.5c-7.4-14.5-14.7-29-22.1-43.5c-7.1-14.1-14.6-28.5-26.7-38.6C233.1,398.5,175.7,465.6,167.3,514.3z"/>
<path class="st16" d="M696.4,1005.9c22,18.7,44.3,37.2,66.5,55.7c47.1,39.1,94.1,78.3,141.2,117.4c0.8-12.5-8.1-23.2-16.7-32.3
c-55.1-58.7-119.2-108.1-179.5-161.5C638.6,923.6,625.8,945.8,696.4,1005.9z"/>
<path class="st16" d="M613,895c-0.9,0-1,4.6-1.6,5.3c-3.3,3.7-7.2,7-11.7,9c-2,0.9-5.7,4.6-7.7,3.7c-1.4-0.7-7.6-6.5-10.5-10.7
c-0.5-0.7-0.9-1.5-0.8-2.3c0.1-0.8,0.9-1.4,1.5-1.9c4.6-3.2,16.2-11.2,21.7-12.2C604,886,613.2,895,613,895z"/>
<path class="st16" d="M653.9,969.1c6.1,3.9,11.5,8.8,16.1,14.4c0-6.2-0.1-12.5-0.1-18.7c-5,2.6-10.7,3.8-16.3,3.5"/>
<path class="st17" d="M435.7,790.6c0.8,16.6,6.2,33,15.5,46.8"/>
<path class="st17" d="M649.5,686c0.7,7.5,1.4,15.1,2,22.6"/>
<g>
<g>
<linearGradient id="SVGID_9_" gradientUnits="userSpaceOnUse" x1="613.3805" y1="675.2397" x2="697.8409" y2="699.4741">
<stop offset="0.2872" style="stop-color:#FFEBE6"/>
<stop offset="0.8764" style="stop-color:#E5D2CF"/>
</linearGradient>
<path class="st18" d="M673.4,663.9c-0.5,0.1-1,0.1-1.5,0.2c-2,0.4-4.2,1.1-5.5,2.7c-3,3.7-0.1,9.5-2.2,13.8
c-1.8,3.6-6.3,4.6-10.3,4.6c-7.7-0.1-15.7-2.8-22.9-0.1c-2.3,0.9-4.4,2.3-6.6,3.3c-4.3,2-8.6,2.3-12.7,1.6
c0.7,0.9,1.4,1.8,2.3,2.8c9.8,11.1,20.7-1,34.5,0c13.8,1,19.8,13.1,30.2,11.1c10.3-2,16.4-21.1,9.5-30.2
C685.1,669.7,679.2,666.4,673.4,663.9z"/>
</g>
</g>
<g>
<g>
<path d="M657.8,659.5c1.9,0.5,23.1,6.4,29.5,14.7c3.2,4.3,3.7,11.4,1.1,18.3c-2.2,5.7-5.9,9.5-9.9,10.3c-0.7,0.1-1.4,0.2-2.1,0.2
c-4,0-7.4-2.2-11.3-4.7c-4.5-2.9-9.5-6.1-16.5-6.6c-0.6,0-1.2-0.1-1.7-0.1c-4.8,0-9.1,1.3-13.2,2.6c-3.5,1.1-6.8,2.1-9.9,2.1
c-3.5,0-6.4-1.4-9-4.4c-6-6.8-7.9-12.6-5.9-17.2C615.1,660.7,655.1,659.6,657.8,659.5 M657.9,658.5c0,0-73.3,1-44,34.2
c3.1,3.5,6.3,4.7,9.7,4.7c6.8,0,14.4-4.8,23.1-4.8c0.6,0,1.1,0,1.7,0.1c12.7,0.9,18.9,11.3,27.9,11.3c0.7,0,1.5-0.1,2.3-0.2
c10.3-2,16.4-21.1,9.5-30.2C681.2,664.5,657.9,658.5,657.9,658.5L657.9,658.5z"/>
</g>
</g>
<g>
<path class="st1" d="M605.3,862.7c2,3.4,2.3,7.3,2.1,11.1c-0.5,9.2-4,18.8-12.8,24.7c-8.3,5.6-19.7,7-30.4,8.2
c-3.7,0.4-8.1,0.6-10.4-1.7c-1.6-1.6-1.5-3.8-1.4-5.9c0.9-12.5,1.7-29.6,16.3-37.1C578.1,857.1,599.5,853,605.3,862.7z"/>
</g>
<g>
<path class="st1" d="M638.4,929.9c-3.2,1.4-6.7,3.1-7.7,6.4c-0.7,2.2-0.2,4.5,0.4,6.7c2.6,10.4,6.9,22.6,17.3,25.2
c4.8,1.2,9.8-0.1,14.5-1.3c10-2.7,21.2-6.2,25.8-15.6c1.6-3.2,2.1-6.8,2.1-10.4C690.7,903.3,657.4,921.6,638.4,929.9z"/>
</g>
<linearGradient id="SVGID_10_" gradientUnits="userSpaceOnUse" x1="644.2117" y1="940.9792" x2="666.1635" y2="967.2874">
<stop offset="0.2872" style="stop-color:#6ACFFB"/>
<stop offset="0.8764" style="stop-color:#54AECF"/>
</linearGradient>
<path class="st19" d="M652.4,950c5.2-2,9.3-6.4,11.7-11.4c2.3,7.8,4.1,15.7,5.3,23.7c0.1,0.8,0.2,1.8-0.3,2.4
c-0.4,0.4-1,0.6-1.6,0.8c-5,1.2-10.1,2-15.2,2.2c-1.4,0.1-2.9,0.1-4.3-0.3c-1.7-0.4-4.2-1.4-5.5-2.5c-4.5-3.9-7.5-12.9-7.3-13
c1.4-1.1,6.6-0.4,8.2-0.4C646.4,951.3,649.5,951.1,652.4,950z"/>
<linearGradient id="SVGID_11_" gradientUnits="userSpaceOnUse" x1="591.1284" y1="871.0673" x2="594.7662" y2="898.6528">
<stop offset="0.2872" style="stop-color:#6ACFFB"/>
<stop offset="0.8764" style="stop-color:#54AECF"/>
</linearGradient>
<path class="st20" d="M604.9,863.7c1.8,0.9,1.9,3.4,1.8,5.4c-0.1,2.6-0.3,5.1-0.4,7.7c-0.1,2.3-1.3,4.7-1.9,7
c-1.4,5.6-4.4,10.2-9.2,13.5s-10.2,5.2-15.7,6.9c0-3-0.1-6-0.1-8.9c0-1.8-0.9-6.3-0.1-7.9c1.2-2.2,8.2-3.3,10.7-4.8
c3.6-2.1,6.8-4.9,9.4-8.1C600,873.6,606,864.3,604.9,863.7z"/>
<path class="st10" d="M399.4,803.5c2.2,11.5,14.4,17.9,25.2,22.5c46.4,19.9,99.8,38.4,146,18c8.4,4.4,9.4,15.8,9.2,25.3
c-0.9,59.5-1.7,119.1-2.6,178.6c-0.2,15.2-0.5,30.6-5,45c-12,2-27.3-5.6-37.9-11.6c-18.8-10.7-98.8-38.9-113.8-59.9"/>
<linearGradient id="SVGID_12_" gradientUnits="userSpaceOnUse" x1="673.9017" y1="963.3705" x2="853.5" y2="963.3705">
<stop offset="0" style="stop-color:#1A83B7"/>
<stop offset="1" style="stop-color:#0E5E77"/>
</linearGradient>
<path class="st21" d="M824.4,818c-39.5,43.5-92.6,74.6-149.8,87.9c-5.2,1.2-11,2.7-13.5,7.4c-2.5,4.7-0.5,10.4,1.2,15.4
c18.5,54.5-2.5,114.7,6.2,171.5c0.4,2.9,1.2,6.3,3.8,7.7c1.9,1.1,4.4,0.8,6.6,0.5c36.2-5.2,80.8-16.1,106.7-42c12-12,49.2-43,54-56
"/>
<path class="st17" d="M785.5,853.5c6.9-9,9.3-21.5,8-32.8"/>
<linearGradient id="SVGID_13_" gradientUnits="userSpaceOnUse" x1="743.4565" y1="942.679" x2="942.2493" y2="942.679">
<stop offset="0" style="stop-color:#1A83B7"/>
<stop offset="0.6263" style="stop-color:#0E5E77;stop-opacity:0"/>
</linearGradient>
<path class="st22" d="M693.1,915.8c-3.4,0.7-7.1,1.5-9.5,3.9c-3.3,3.4-3.2,8.8-2.9,13.6c1.1,15.7,2.3,31.4,3.5,47.1
c2.8-2.7,5.6-5.5,8.3-8.2c-1.6,11.8-3.2,23.5-4.8,35.3c-1.5,11.4-2.1,25.3,7.3,31.9c6.6,4.7,16,3.5,23-0.6c7-4.1,12.1-10.7,17-17.2
c9-11.8,18-23.6,27-35.5c2.6,22.6-12.2,43.8-29.5,58.7c-13.5,11.7-29.1,21.3-39.5,35.9c-2.6,3.6-4.9,7.7-8.7,10
c-3.8,2.4-9.6,2.3-11.9-1.5c-0.9-1.5-1.1-3.2-1.3-4.9c-2.5-20.8-2.8-41.9-1-62.8c1.3-15.5,3.8-31.1,2.4-46.6
c-1.7-18.4-8.8-36.1-10-54.6c-0.1-2.2-0.2-4.6,1-6.5c1.2-1.9,3.4-3,5.5-3.8c22-8.1,43-14,63.9-23c43.7-18.8,82-50.7,109.6-89.4
c-0.7,4.1-1.4,8.3-2.1,12.4c7.9-4.5,14.9-10.3,20.9-17.1c-4.1,4.8-4.4,15.3-9.2,21.1c-5.9,7.3-13.2,9.6-20.7,14.5
c-13,8.4-23.8,21.7-35.9,31.6C765.3,884.9,731.8,907.5,693.1,915.8z"/>
<linearGradient id="SVGID_14_" gradientUnits="userSpaceOnUse" x1="251.4727" y1="1022.9849" x2="403.3306" y2="1022.9849">
<stop offset="0.2367" style="stop-color:#0E5E77"/>
<stop offset="1" style="stop-color:#1A83B7;stop-opacity:0"/>
</linearGradient>
<path class="st23" d="M320.9,1009c2.6,8.2,10.6,13.7,18.9,15.7c8.3,2,17.1,1.1,25.6,0.2c-4.1,3.2-8.1,6.4-12.2,9.7
c7.7,7.7,19.2,9.9,30,10.8c10.8,0.9,22.1,1.1,31.8,5.9c-18,3.7-36.8,3.6-54.8-0.4c-9.6-2.1-19.1-5.4-28.9-5.1
c-6.2,0.2-12.2,1.9-18.3,2.9c-19.7,3.4-40.1,0.5-59.6,4.8c6-8.5,21.5-13.5,34.5-22.5c18.2-12.6,29-21,32.3-39
C322.2,997,319.1,1003.3,320.9,1009z"/>
<linearGradient id="SVGID_15_" gradientUnits="userSpaceOnUse" x1="274.2131" y1="603.0543" x2="278.36" y2="548.9128">
<stop offset="0.2872" style="stop-color:#916243"/>
<stop offset="0.8764" style="stop-color:#7A4F37"/>
</linearGradient>
<path class="st24" d="M227.9,536.5c1.5,15,10.4,29.2,23.2,37.1c2.2,1.4,4.5,2.5,7,3.1c2.5,0.5,5.2,0.3,7.7,0.2
c15-1.1,31.8-1.6,43,8.4c2.6,2.3,4.8,5.2,7.8,7s7.2,2.4,9.8,0.1c-6-6.1-11.9-13-13.6-21.4s1.9-18.5,10.1-21.3
c-8.9,3.1-17.8,6.2-26.7,9.3c-11,3.8-22.4,7.7-34.1,7.4c-11.7-0.4-23.9-6-28.9-16.5C231.2,545.5,229.5,540.8,227.9,536.5z"/>
<path class="st17" d="M334.5,544.5c-11.5,7.4-38.8,15.5-52,19c-8.7,2.3-17.9,3.7-26.8,2.2c-8.9-1.5-17.5-6.2-22.3-13.8
c-3.3-5.3-4.5-11.6-5.6-17.7c-2.4-12.7-4.8-25.4-7.2-38.1c-0.3-1.4-0.5-2.9,0.1-4.1c0.5-1,1.5-1.6,2.4-2.2
c10.8-6.8,23.1-14,35.6-11.2c9.6,2.1,16.9,9.6,23.6,16.7c3.8,4,7.5,8,11.3,12c2.4,2.5,5,5.7,4.3,9.1c-0.4,2-1.8,3.6-3.3,4.9
c-5,4.3-11.9,6.7-18.4,5.3c-6.5-1.3-12.2-6.6-13.2-13.2"/>
<radialGradient id="SVGID_16_" cx="644" cy="654" r="22.463" gradientTransform="matrix(1 0 0 0.6232 0 246.3962)" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#666666"/>
<stop offset="1" style="stop-color:#000000"/>
</radialGradient>
<path class="st25" d="M682.3,662.1c-1.1,8.2-14.4,13.3-29.7,11.3c-15.3-2-26.9-10.3-25.8-18.5c1.1-8.2,14.4-13.3,29.7-11.3
C671.8,645.6,683.3,653.9,682.3,662.1z"/>
<linearGradient id="SVGID_17_" gradientUnits="userSpaceOnUse" x1="661.8317" y1="633.6916" x2="662.598" y2="468.1831">
<stop offset="0.2872" style="stop-color:#6ACFFB"/>
<stop offset="0.8764" style="stop-color:#54AECF"/>
</linearGradient>
<path class="st26" d="M752.8,569.7c-2.3-3.4-4.8-6.9-7.7-9.8c19.2,0.9,38.5,1.4,57.7,1.3c12.2,0,24.7-0.2,36.3,3.8
c0.3-7.7-3.8-15.1-9.4-20.4c-5.6-5.3-12.7-8.8-19.8-11.9c-20.4-8.9-41.9-15.1-63.5-20.3c-82-20-167.7-27.8-251.1-14.9
c-1.7,0.3-3.5,0.6-4.9,1.7c-4,3.1-6.4,10-4.3,13.1c2.7,4.1,13.2,7.5,17.7,9.6c12.4,5.9,25.3,10.5,38.5,14.1
c26.5,7.3,53.9,10.9,81.2,13.9c21.7,2.4,43.4,4.6,65.1,6.4c0,0,0,0,0,0c3.8,3.5,4.4,9.2,4.6,14.4c1.4,24.9,2.4,51,14.4,72.9
C717.7,661.6,778.5,607.7,752.8,569.7z"/>
<g>
<radialGradient id="SVGID_18_" cx="498.5" cy="596.5" r="103.0109" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="0.4455" style="stop-color:#FDFDFD"/>
<stop offset="1" style="stop-color:#E6E6E6"/>
</radialGradient>
<path class="st27" d="M498.5,698C440.9,698,394,652.5,394,596.5S440.9,495,498.5,495S603,540.5,603,596.5S556.1,698,498.5,698z"/>
<g>
<path d="M498.5,495.5c57.3,0,104,45.3,104,101s-46.7,101-104,101s-104-45.3-104-101S441.2,495.5,498.5,495.5 M498.5,494.5
c-58,0-105,45.7-105,102c0,56.3,47,102,105,102s105-45.7,105-102C603.5,540.2,556.5,494.5,498.5,494.5L498.5,494.5z"/>
</g>
</g>
<g>
<radialGradient id="SVGID_19_" cx="818" cy="599.8713" r="98.5748" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="0.4455" style="stop-color:#FDFDFD"/>
<stop offset="1" style="stop-color:#E6E6E6"/>
</radialGradient>
<path class="st28" d="M818,697c-55.1,0-100-43.6-100-97.1c0-53.6,44.9-97.1,100-97.1s100,43.6,100,97.1
C918,653.4,873.1,697,818,697z"/>
<g>
<path d="M818,503.2c54.9,0,99.5,43.3,99.5,96.6s-44.6,96.6-99.5,96.6s-99.5-43.3-99.5-96.6S763.1,503.2,818,503.2 M818,502.2
c-55.5,0-100.5,43.7-100.5,97.6c0,53.9,45,97.6,100.5,97.6s100.5-43.7,100.5-97.6C918.5,546,873.5,502.2,818,502.2L818,502.2z"/>
</g>
</g>
<ellipse transform="matrix(8.600707e-02 -0.9963 0.9963 8.600707e-02 -114.255 1019.4568)" class="st29" cx="498.5" cy="572" rx="20.5" ry="14"/>
<ellipse transform="matrix(0.9956 -9.351500e-02 9.351500e-02 0.9956 -51.6696 79.3657)" class="st29" cx="821" cy="591" rx="13.5" ry="20.5"/>
<g>
<path class="st30" d="M631.6,538.3c101.9,12.7,346.1,10.9,374-10c27.9-20.8-186.5-133.9-314.4-147.5s-359.1,48.6-375.9,57
C268.2,461.4,529.7,525.7,631.6,538.3z"/>
</g>
<g>
<linearGradient id="SVGID_20_" gradientUnits="userSpaceOnUse" x1="652.8838" y1="501.3271" x2="579.8838" y2="738.3271">
<stop offset="0" style="stop-color:#D1B482"/>
<stop offset="0.6251" style="stop-color:#A68B65"/>
</linearGradient>
<path class="st31" d="M631.6,538.3c101.9,12.7,346.1,10.9,374-10C736,566,367,502,315.3,437.9
C268.2,461.4,529.7,525.7,631.6,538.3z"/>
</g>
<path class="st32" d="M522.2,402.7c-1.5,7.8,5.2,14.6,11.7,19.1c13.5,9.4,29,16,45.2,19.1"/>
<path class="st33" d="M521.6,404.3c45.3-92.8,92.7-184.5,142.2-275.1c6.9-12.7,14.3-25.8,25.9-34.3c9.2-6.7,20.3-10.1,31.3-12.9
c15.8-4.1,31.8-7.3,48-9.6c9.8-1.4,20.2-2.4,29,2c6.9,3.4,11.9,9.8,16.5,16c13.2,17.8,25.4,36.3,36.5,55.5
c8.9,15.4,17.9,32.2,33.6,40.7c15.7,8.5,40,3.1,43.9-14.3c0.5,21.6-10,43.2-27.2,56.3c-17.2,13.1-40.9,17.3-61.6,10.9
c-4.8-1.5-10.2-3.4-14.6-0.9c-4,2.3-5.3,7.4-6.2,11.9c-12.3,65-9.7,132.7,7.5,196.6"/>
<g>
<linearGradient id="SVGID_21_" gradientUnits="userSpaceOnUse" x1="779.9537" y1="84.214" x2="1232.931" y2="270.2047">
<stop offset="0" style="stop-color:#D1B482"/>
<stop offset="0.6251" style="stop-color:#A68B65"/>
</linearGradient>
<path class="st34" d="M799.2,93.1c-0.1-0.7-0.2-1.3-0.2-2C799,91.7,799.1,92.4,799.2,93.1z"/>
<linearGradient id="SVGID_22_" gradientUnits="userSpaceOnUse" x1="687.6368" y1="309.0503" x2="1140.6141" y2="495.041">
<stop offset="0" style="stop-color:#D1B482"/>
<stop offset="0.6251" style="stop-color:#A68B65"/>
</linearGradient>
<path class="st35" d="M819,414.2c-10.1-53.9-10.2-109.7,0-163.6c0.9-4.5,2.2-9.6,6.2-11.9c4.4-2.5,9.8-0.5,14.6,0.9
c9.2,2.8,18.9,3.5,28.5,2.3c-2.3-7.8-5-15.6-7.6-23.3c-7.3-21.4-12.8-40.6-23.9-60.4c-6.5-11.6-13-23.1-19.5-34.7
c-3.9-6.9-16.2-21.7-18-30.5c2.7,23.1,5.3,46.3,3.1,69.4c-2.3,23.8-10.2,47.7-26.4,65.3c-7.3,8-17,17.5-13.2,27.6
c1.5,3.9,4.8,6.8,7.3,10.1c15.8,20.8-1.5,53.1,10.7,76.2c3.2,6,8.3,12.2,6.3,18.6c-1.7,5.1-7.3,7.7-12.3,9.7
c-19,7.4-38.1,14.8-57.1,22.2c12.4,15.2,39.3,10.6,51.9,25.7c1.9,2.3,3.5,5.2,3.2,8.2c-0.6,7.1-9.4,9.7-16.5,10.6
c-31.4,4-62.8,7.9-94.2,11.9c3.7,7.3,7.5,14.7,11.2,22C613.6,495.3,546.3,489.3,482,483c50.2,28.1,105.3,45,161.9,56.7
c108,11.1,334.9,8.7,361.7-11.3C1025.1,513.7,924.8,453.4,819,414.2z"/>
</g>
<path class="st32" d="M818.4,253.1c7.3-30,7.6-61.8,0.8-91.9"/>
<g>
<path class="st17" d="M529.5,389.5c-105.8,15.2-203.2,42.9-214.2,48.4c-47.1,23.5,214.4,87.8,316.3,100.4s346.1,10.9,374-10
c19.8-14.8-80.2-74.7-187-113.9"/>
</g>
<path class="st32" d="M521.6,404.3c45.3-92.8,92.7-184.5,142.2-275.1c6.9-12.7,14.3-25.8,25.9-34.3c9.2-6.7,20.3-10.1,31.3-12.9
c15.8-4.1,31.8-7.3,48-9.6c9.8-1.4,20.2-2.4,29,2c6.9,3.4,11.9,9.8,16.5,16c13.2,17.8,25.4,36.3,36.5,55.5
c8.9,15.4,17.9,32.2,33.6,40.7c15.7,8.5,40,3.1,43.9-14.3c0.5,21.6-10,43.2-27.2,56.3c-17.2,13.1-40.9,17.3-61.6,10.9
c-4.8-1.5-10.2-3.4-14.6-0.9c-4,2.3-5.3,7.4-6.2,11.9c-12.3,65-9.7,132.7,7.5,196.6"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View file

@ -0,0 +1,3 @@
.DS_Store
public/
exampleSite/public

View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Grav
Copyright (c) 2016 MATHIEU CORNIC
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,49 @@
# Hugo Learn Theme
This repository contains a theme for [Hugo](https://gohugo.io/), based on great [Grav Learn Theme](http://learn.getgrav.org/).
Visit the [theme documentation](https://learn.netlify.com/en/) to see what is going on. It is actually built with this theme.
## Main features
- Automatic Search
- Multilingual mode
- Unlimited menu levels
- Automatic next/prev buttons to navigate through menu entries
- Image resizing, shadow…
- Attachments files
- List child pages
- Mermaid diagram (flowchart, sequence, gantt)
- Customizable look and feel and themes variants
- Buttons, Tip/Note/Info/Warning boxes, Expand
## Installation
Navigate to your themes folder in your Hugo site and use the following commands:
```
$ cd themes
$ git clone https://github.com/matcornic/hugo-theme-learn.git
```
Check that your Hugo version is minimum `0.25` with `hugo version`.
![Overview](https://github.com/matcornic/hugo-theme-learn/raw/master/images/tn.png)
## Usage
- [Visit the documentation](https://learn.netlify.com/en/)
## Download old versions (prior to 2.0.0)
If you need old version for compatibility purpose, either download [theme source code from releases](https://github.com/matcornic/hugo-theme-learn/releases) or use the right git tag. For example, with `1.1.0`
- Direct download way: https://github.com/matcornic/hugo-theme-learn/archive/1.1.0.zip
- Git way:
```shell
cd themes/hugo-theme-learn
git checkout tags/1.1.0
```
For both solutions, the documentation is available at https://github.com/matcornic/hugo-theme-learn/releases/download/1.1.0/hugo-learn-doc-1.1.0.zip

View file

@ -0,0 +1,13 @@
+++
title = "{{ replace .TranslationBaseName "-" " " | title }}"
date = {{ .Date }}
weight = 5
chapter = true
pre = "<b>X. </b>"
+++
### Chapter X
# Some Chapter title
Lorem Ipsum.

View file

@ -0,0 +1,7 @@
+++
title = "{{ replace .TranslationBaseName "-" " " | title }}"
date = {{ .Date }}
weight = 5
+++
Lorem Ipsum.

View file

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2016 MATHIEU CORNIC
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,39 @@
- récriture doc -> TODO
- créer une section Showcase
- Menus déroulants icone -> TODO
- créer des jolis thèmes de base (avec des noms ou au moins de meilleures couleurs) -> DOING
- Thème blue : OK
- Thème red: OK
- Theme green: OK
- Passer a Wercker -> OK
- corriger le multilangue pour la recherche et les autres ressources statiques : OK
- Section "MORE" -> OK
- ajouter les childs -> OK
- ajouter les attachments -> OK
- refaire la possibilité d'overrider le style/script/etc -> OK
- sticky bar -> OK
- ajouter Travis pour tester le thème quotidiennement avec les nouvelles versions de Hugo -> OK
- #54 -> OK
- corriger slider menu qui ne fonctionne plus -> OK
- Update font awesome -> OK
- internationalisation -> OK
- Messages: OK
- Ajouter un bouton pour changer de langue : OK
- netlify -> OK
- home page -> OK
- réintégrer la doc dans le même repo -> OK
- récupérer les shortcodes utiles -> OK
- expand : OK
- mermaid : OK
- chapter -> OK
- recherche (avec pointage à la première occurence sur la page) -> OK
- visited links -> OK
- disable Search -> OK
- vérifier que ça fonctionne avec une base url -> OK
- tester les affichages de page enfant -> OK
- comprendre l'histoire de pagination -> OK
- améliorer les couleurs de surlignement de highlightjs -> OK
- créer les archetypes -> OK
-> créé ceux de base -> OK
-> vérifier la possibilité de générer automatiquement le bon weight -> OK

View file

@ -0,0 +1,73 @@
baseURL = "/"
languageCode = "en-US"
defaultContentLanguage = "en"
title = "Hugo Learn Documentation"
theme = "hugo-theme-learn"
themesdir = "../.."
metaDataFormat = "yaml"
defaultContentLanguageInSubdir= true
[params]
editURL = "https://github.com/matcornic/hugo-theme-learn/edit/master/exampleSite/content/"
description = "Documentation for Hugo Learn Theme"
author = "Mathieu Cornic"
showVisitedLinks = true
[outputs]
home = [ "HTML", "RSS", "JSON"]
[Languages]
[Languages.en]
title = "Documentation for Hugo Learn Theme"
weight = 1
languageName = "English"
[[Languages.en.menu.shortcuts]]
name = "<i class='fa fa-github'></i> Github repo"
identifier = "ds"
url = "https://github.com/matcornic/hugo-theme-learn"
weight = 10
[[Languages.en.menu.shortcuts]]
name = "<i class='fa fa-camera'></i> Showcases"
url = "showcase"
weight = 11
[[Languages.en.menu.shortcuts]]
name = "<i class='fa fa-bookmark'></i> Hugo Documentation"
identifier = "hugodoc"
url = "https://gohugo.io/"
weight = 20
[[Languages.en.menu.shortcuts]]
name = "<i class='fa fa-bullhorn'></i> Credits"
url = "/credits"
weight = 30
[Languages.fr]
title = "Documentation du thème Hugo Learn"
weight = 2
languageName = "Français"
[[Languages.fr.menu.shortcuts]]
name = "<i class='fa fa-github'></i> Repo Github"
identifier = "ds"
url = "https://github.com/matcornic/hugo-theme-learn"
weight = 10
[[Languages.fr.menu.shortcuts]]
name = "<i class='fa fa-camera'></i> Vitrine"
url = "/showcase"
weight = 11
[[Languages.fr.menu.shortcuts]]
name = "<i class='fa fa-bookmark'></i> Documentation Hugo"
identifier = "hugodoc"
url = "https://gohugo.io/"
weight = 20
[[Languages.fr.menu.shortcuts]]
name = "<i class='fa fa-bullhorn'></i> Crédits"
url = "/credits"
weight = 30

View file

@ -0,0 +1,41 @@
---
title: "Learn Theme for Hugo"
---
# Hugo learn theme
[Hugo-theme-learn](http://github.com/matcornic/hugo-theme-learn) is a theme for [Hugo](https://gohugo.io/), a fast and modern static website engine written in Go. Where Hugo is often used for blogs, this multilingual-ready theme is **fully designed for documentation**.
This theme is a partial porting of the [Learn theme](http://learn.getgrav.org/) of [Grav](https://getgrav.org/), a modern flat-file CMS written in PHP.
{{% notice tip %}}Learn theme works with a _page tree structure_ to organize content : All contents are pages, which belong to other pages. [read more about this]({{%relref "cont/pages/_index.md"%}})
{{% /notice %}}
## Main features
* [Automatic Search]({{%relref "basics/configuration/_index.md" %}})
* [Multilingual mode]({{%relref "cont/i18n/_index.md" %}})
* **Unlimited menu levels**
* **Automatic next/prev buttons to navigate through menu entries**
* [Image resizing, shadow...]({{%relref "cont/markdown.en.md#images" %}})
* [Attachments files]({{%relref "shortcodes/attachments.en.md" %}})
* [List child pages]({{%relref "shortcodes/children/_index.md" %}})
* [Mermaid diagram]({{%relref "shortcodes/mermaid.en.md" %}}) (flowchart, sequence, gantt)
* [Customizable look and feel and themes variants]({{%relref "basics/configuration/_index.md"%}})
* [Buttons]({{%relref "shortcodes/button.en.md" %}}), [Tip/Note/Info/Warning boxes]({{%relref "shortcodes/notice.en.md" %}}), [Expand]({{%relref "shortcodes/expand.en.md" %}})
![Screenshot](https://github.com/matcornic/hugo-theme-learn/raw/master/images/screenshot.png?width=40pc&classes=shadow)
## Contribute to this documentation
Feel free to update this content, just click the **Edit this page** link displayed on top right of each page, and pullrequest it
{{% notice info %}}
Your modification will be deployed automatically when merged.
{{% /notice %}}
## Documentation website
This current documentation has been statically generated with Hugo with a simple command : `hugo -t hugo-theme-learn` -- source code is [available here at GitHub](https://github.com/matcornic/hugo-theme-learn)
{{% notice note %}}
Automatically published and hosted thanks to [Netlify](https://www.netlify.com/). Read more about [Automated HUGO deployments with Netlify](https://www.netlify.com/blog/2015/07/30/hosting-hugo-on-netlifyinsanely-fast-deploys/)
{{% /notice %}}

View file

@ -0,0 +1,43 @@
---
title: "Learn Theme for Hugo"
---
# Thème Hugo learn
[Hugo-theme-learn](http://github.com/matcornic/hugo-theme-learn) est un thème pour [Hugo](https://gohugo.io/), un générateur de site statique, rapide et modern, écrit en Go. Tandis que Hugo est souvent utilisé pour des blogs, ce thème multi-langue est **entièrement conçu pour la documentation**.
Ce thème est un portage partiel du [thème Learn](http://learn.getgrav.org/) de [Grav](https://getgrav.org/), un CMS modern écrit en PHP.
{{% notice tip %}}Le thème Learn fonctionne grâce à la structure de page aborescentes pour organiser le contenu: tous les contenus sont des pages qui appartiennent à d'autres pages. [Plus d'infos]({{%relref "cont/pages/_index.md"%}})
{{% /notice %}}
## Fonctionnalité principales
* [Recherche automatique]({{%relref "basics/configuration/_index.md" %}})
* [Mode multi-langue]({{%relref "cont/i18n/_index.md" %}})
* **Nombre de niveau infini dans le menu**
* **Boutons suivant/précédent automatiquement générés pour naviguer entre les items du menu**
* [Taille d'image, ombres...]({{%relref "cont/markdown.fr.md#images" %}})
* [Fichiers joints]({{%relref "shortcodes/attachments.fr.md" %}})
* [Lister les pages filles]({{%relref "shortcodes/children/_index.md" %}})
* [Diagrammes Mermaid]({{%relref "shortcodes/mermaid.fr.md" %}}) (flowchart, sequence, gantt)
* [Style configurable and variantes de couleurs]({{%relref "basics/configuration/_index.md"%}})
* [Boutons]({{%relref "shortcodes/button.fr.md" %}}), [Messages Astuce/Note/Info/Attention]({{%relref "shortcodes/notice.fr.md" %}}), [Expand]({{%relref "shortcodes/expand.fr.md" %}})
![Screenshot](https://github.com/matcornic/hugo-theme-learn/raw/master/images/screenshot.png?width=40pc&classes=shadow)
## Contribuer à cette documentation
N'hésitez pas à mettre à jour ce contenu en cliquant sur le lien **Modifier cette page** en haut de chaque page, et créer la Pull Request associée.
{{% notice info %}}
Votre modification sera déployée automatiquement quand elle sera mergée.
{{% /notice %}}
## Site de documentation
Cette documentation statique a été générée avec Hugo avec une simple commande : `hugo -t hugo-theme-learn` -- le code source est [disponible sur Github](https://github.com/matcornic/hugo-theme-learn)
{{% notice note %}}
Le site est auomatiquement publié et hébergé par [Netlify](https://www.netlify.com/). Plus d'infos sur le [déploiement de site Hugo avec Netlify](https://www.netlify.com/blog/2015/07/30/hosting-hugo-on-netlifyinsanely-fast-deploys/)(En anglais)
{{% /notice %}}

View file

@ -0,0 +1,12 @@
---
title: Basics
weight: 5
pre: "<b>1. </b>"
chapter: true
---
### Chapter 1
# Basics
Discover what this Hugo theme is all about and the core-concepts behind it.

View file

@ -0,0 +1,12 @@
---
title: Démarrage
weight: 5
pre: "<b>1. </b>"
chapter: true
---
### Chapitre 1
# Démarrage
Découvrez comment utiliser ce thème Hugo et apprenez en les concepts

View file

@ -0,0 +1,246 @@
---
date: 2016-04-09T16:50:16+02:00
title: Configuration
weight: 20
---
## Global site parameters
On top of [Hugo global configuration](https://gohugo.io/overview/configuration/), **Hugo-theme-learn** lets you define the following parameters in your `config.toml` (here, values are default).
Note that some of these parameters are explained in details in other sections of this documentation.
```toml
[params]
# Prefix URL to edit current page. Will display an "Edit this page" button on top right hand corner of every page.
# Useful to give opportunity to people to create merge request for your doc.
# See the config.toml file from this documentation site to have an example.
editURL = ""
# Author of the site, will be used in meta information
author = ""
# Description of the site, will be used in meta information
description = ""
# Shows a checkmark for visited pages on the menu
showVisitedLinks = false
# Disable search function. It will hide search bar
disableSearch = false
# Javascript and CSS cache are automatically busted when new version of site is generated.
# Set this to true to disable this behavior (some proxies don't handle well this optimization)
disableAssetsBusting = false
# Set this to true to disable copy-to-clipboard button for inline code.
disableInlineCopyToClipBoard = false
# A title for shortcuts in menu is set by default. Set this to true to disable it.
disableShortcutsTitle = false
# When using mulitlingual website, disable the switch language button.
disableLanguageSwitchingButton = false
# Order sections in menu by "weight" or "title". Default to "weight"
ordersectionsby = "weight"
# Change default color scheme with a variant one. Can be "red", "blue", "green".
themeVariant = ""
```
## Activate search
If not already present, add the follow lines in the same `config.toml` file.
```toml
[outputs]
home = [ "HTML", "RSS", "JSON"]
```
Learn theme uses the last improvement available in hugo version 20+ to generate a json index file ready to be consumed by lunr.js javascript search engine.
> Hugo generate lunrjs index.json at the root of public folder.
> When you build the site with hugo server, hugo generates it internally and of course it dont show up in the filesystem
## Style customization
**Hugo-theme-learn** has been built to be as configurable as possible by defining multiple [partials](https://gohugo.io/templates/partials/)
In `themes/hugo-theme-learn/layouts/partials/`, you will find all the partials defined for this theme. If you need to overwrite something, don't change the code directly. Instead [follow this page](https://gohugo.io/themes/customizing/). You'd create a new partial in the `layouts/partials` folder of your local project. This partial will have the priority.
This theme defines the following partials :
- *header*: the header of the content page (contains the breadcrumbs). _Not meant to be overwritten_
- *custom-header*: custom headers in page. Meant to be overwritten when adding CSS imports. Don't forget to include `style` HTML tag directive in your file
- *footer*: the footer of the content page (contains the arrows). _Not meant to be overwritten_
- *custom-footer*: custom footer in page. Meant to be overwritten when adding Javacript. Don't forget to include `javascript` HTML tag directive in your file
- *favicon*: the favicon
- *logo*: the logo, on top left hand corner.
- *meta*: HTML meta tags, if you want to change default behavior
- *menu*: left menu. _Not meant to be overwritten_
- *menu-footer*: footer of the the left menu
- *search*: search box
- *toc*: table of contents
### Change the logo
Create a new file in `layouts/partials/` named `logo.html`. Then write any HTML you want.
You could use an `img` HTML tag and reference an image created under the *static* folder, or you could paste a SVG definition !
{{% notice note %}}
The size of the logo will adapt automatically
{{% /notice %}}
### Change the favicon
If your favicon is a png, just drop off your image in your local `static/images/` folder and names it `favicon.png`
If you need to change this default behavior, create a new file in `layouts/partials/` named `favicon.html`. Then write something like this:
```html
<link rel="shortcut icon" href="/images/favicon.png" type="image/x-icon" />
```
### Change default colors {#theme-variant}
**Hugo Learn theme** let you choose between 3 native color scheme variants, but feel free to add one yourself ! Default color scheme is based on [Grav Learn Theme](https://learn.getgrav.org/).
#### Red variant
```toml
[params]
# Change default color scheme with a variant one. Can be "red", "blue", "green".
themeVariant = "red"
```
![Red variant](/basics/configuration/images/red-variant.png?width=60%)
#### Blue variant
```toml
[params]
# Change default color scheme with a variant one. Can be "red", "blue", "green".
themeVariant = "blue"
```
![Blue variant](/basics/configuration/images/blue-variant.png?width=60%)
#### Green variant
```toml
[params]
# Change default color scheme with a variant one. Can be "red", "blue", "green".
themeVariant = "green"
```
![Green variant](/basics/configuration/images/green-variant.png?width=60%)
#### 'Yours variant
First, create a new CSS file in your local `static/css` folder prefixed by `theme` (e.g. with _mine_ theme `static/css/theme-mine.css`). Copy the following content and modify colors in CSS variables.
```css
:root{
--MAIN-TEXT-color:#323232; /* Color of text by default */
--MAIN-TITLES-TEXT-color: #5e5e5e; /* Color of titles h2-h3-h4-h5 */
--MAIN-LINK-color:#1C90F3; /* Color of links */
--MAIN-LINK-HOVER-color:#167ad0; /* Color of hovered links */
--MAIN-ANCHOR-color: #1C90F3; /* color of anchors on titles */
--MENU-HEADER-BG-color:#1C90F3; /* Background color of menu header */
--MENU-HEADER-BORDER-color:#33a1ff; /*Color of menu header border */
--MENU-SEARCH-BG-color:#167ad0; /* Search field background color (by default borders + icons) */
--MENU-SEARCH-BOX-color: #33a1ff; /* Override search field border color */
--MENU-SEARCH-BOX-ICONS-color: #a1d2fd; /* Override search field icons color */
--MENU-SECTIONS-ACTIVE-BG-color:#20272b; /* Background color of the active section and its childs */
--MENU-SECTIONS-BG-color:#252c31; /* Background color of other sections */
--MENU-SECTIONS-LINK-color: #ccc; /* Color of links in menu */
--MENU-SECTIONS-LINK-HOVER-color: #e6e6e6; /* Color of links in menu, when hovered */
--MENU-SECTION-ACTIVE-CATEGORY-color: #777; /* Color of active category text */
--MENU-SECTION-ACTIVE-CATEGORY-BG-color: #fff; /* Color of background for the active category (only) */
--MENU-VISITED-color: #33a1ff; /* Color of 'page visited' icons in menu */
--MENU-SECTION-HR-color: #20272b; /* Color of <hr> separator in menu */
}
body {
color: var(--MAIN-TEXT-color) !important;
}
textarea:focus, input[type="email"]:focus, input[type="number"]:focus, input[type="password"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="text"]:focus, input[type="url"]:focus, input[type="color"]:focus, input[type="date"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="week"]:focus, select[multiple=multiple]:focus {
border-color: none;
box-shadow: none;
}
h2, h3, h4, h5 {
color: var(--MAIN-TITLES-TEXT-color) !important;
}
a {
color: var(--MAIN-LINK-color);
}
.anchor {
color: var(--MAIN-ANCHOR-color);
}
a:hover {
color: var(--MAIN-LINK-HOVER-color);
}
#sidebar ul li.visited > a .read-icon {
color: var(--MENU-VISITED-color);
}
#body a.highlight:after {
display: block;
content: "";
height: 1px;
width: 0%;
-webkit-transition: width 0.5s ease;
-moz-transition: width 0.5s ease;
-ms-transition: width 0.5s ease;
transition: width 0.5s ease;
background-color: var(--MAIN-HOVER-color);
}
#sidebar {
background-color: var(--MENU-SECTIONS-BG-color);
}
#sidebar #header-wrapper {
background: var(--MENU-HEADER-BG-color);
color: var(--MENU-SEARCH-BOX-color);
border-color: var(--MENU-HEADER-BORDER-color);
}
#sidebar .searchbox {
border-color: var(--MENU-SEARCH-BOX-color);
background: var(--MENU-SEARCH-BG-color);
}
#sidebar ul.topics > li.parent, #sidebar ul.topics > li.active {
background: var(--MENU-SECTIONS-ACTIVE-BG-color);
}
#sidebar .searchbox * {
color: var(--MENU-SEARCH-BOX-ICONS-color);
}
#sidebar a {
color: var(--MENU-SECTIONS-LINK-color);
}
#sidebar a:hover {
color: var(--MENU-SECTIONS-LINK-HOVER-color);
}
#sidebar ul li.active > a {
background: var(--MENU-SECTION-ACTIVE-CATEGORY-BG-color);
color: var(--MENU-SECTION-ACTIVE-CATEGORY-color) !important;
}
#sidebar hr {
border-color: var(--MENU-SECTION-HR-color);
}
```
Then, set the `themeVariant` value with the name of your custom theme file. That's it !
```toml
[params]
# Change default color scheme with a variant one. Can be "red", "blue", "green".
themeVariant = "mine"
```

View file

@ -0,0 +1,245 @@
---
date: 2016-04-09T16:50:16+02:00
title: Configuration
weight: 20
---
## Global site parameters
En plus de la [configuration globale d'Hugo](https://gohugo.io/overview/configuration/), **Hugo-theme-learn** vous permet de définir les paramètres suivant dans votre fichier `config.toml` (ci-dessous sont affichées les valeurs par défaut).
Notez que certains de ces paramètres sont expliqués en détails dans d'autres sections de cette documentation.
```toml
[params]
# L'URL préfixe pour éditer la page courante. Ce paramètre affichera un bouton "Modifier cette page" on haut de de chacune des pages.
# Pratique pour donner les possibilité à vos utilisateurs de créer une merge request pour votre doc.
# Allez voir le fichier config.toml de cette documentation pour avoir un exemple.
editURL = ""
# Autheur du site, est utilisé dans les informations meta
author = ""
# Description du site, est utilisé dans les informations meta
description = ""
# Affiche une icône lorsque la page a été visitée
showVisitedLinks = false
# Désactive la fonction de recherche. Une valeur à true cache la barre de recherche.
disableSearch = false
# Par défaut, le cache Javascript et CSS est automatiquement vidé lorsqu'une nouvelle version du site est générée.
# Utilisez ce paramètre lorsque vous voulez désactiver ce comportement (c'est parfois incompatible avec certains proxys)
disableAssetsBusting = false
# Utilisez ce paramètre pour désactiver le bouton copy-to-clipboard pour le code formatté sur une ligne.
disableInlineCopyToClipBoard = false
# Un titre est défini par défaut lorsque vous utilisez un raccourci dans le menu. Utilisez ce paramètre pour le cacher.
disableShortcutsTitle = false
# Quand vous utilisez un site multi-langue, utilisez ce paramètre pour désactiver le bouton de changement de langue.
disableLanguageSwitchingButton = false
# Ordonne les sections dans menu par poids ("weight") ou titre ("title"). Défaut à "weight"
ordersectionsby = "weight"
# Utilisez ce paramètre pour modifier le schéma de couleur du site. Les valeurs par défaut sont "red", "blue", "green".
themeVariant = ""
```
## Activez la recherche
Si ce n'est pas déjà présent, ajoutez les lignes suivantes dans le fichier `config.toml`.
```toml
[outputs]
home = [ "HTML", "RSS", "JSON"]
```
Le thème *Learn* utilise les dernières amélioraions d'Hugo pour générer un fichier d'index JSON, prêt à être consommé par le moteur de recherche lunr.js.
> Hugo génère lunrjs index.json à la racine du dossier `public`.
> Quand vous générez le site avec `hugo server`, Hugo génère le fichier en mémoire, il n'est donc pas disponible sur le disque.
## Personnaliser le style
**Hugo-theme-learn** a été conçu pour être aussi configurable que possible en définissant plusieurs [partials](https://gohugo.io/templates/partials/)
Dans `themes/hugo-theme-learn/layouts/partials/`, vous pourrez trouver tous les *partials* définis pour ce thème. Si vous avez besoin d'écraser quelque chose, ne modifiez pas le code directement. A la place, [suivez cette page](https://gohugo.io/themes/customizing/). Vous créerez alors un nouveau *partial* dans le dossier `layouts/partials` de votre site local. Ce *partial* aura la priorité.
Ce thème définit les *partials* suivant :
- *header*: l'en-tête de la page page (contient le fil d'Ariane). _Pas voué à être écrasé_
- *custom-header*: En-tête personnalisé. Voué à être écrasé quand vous ajoutez des imports CSS. N'oubliez pas d'inclure la balise HTML `style` dans votre fichier
- *footer*: le pied-de-page de la page (contains les flèches). _Pas voué à être écrasé_
- *custom-footer*: Pied-de-page personnalisé. Voué à être écrasé quand vous ajoutez du Javascript. N'oubliez pas d'inclure la balise HTML `javascript` dans votre fichier
- *favicon*: le favicon
- *logo*: le logo, affiché un haut à gauche.
- *meta*: les balises HTML meta, que vous pouvez écraser sans problème.
- *menu*: Le menu à gauche. _Pas voué à être écrasé_
- *menu-footer*: Le pied-de-page du menu
- *search*: le champ de recherche
- *toc*: le sommaire
### Changer le logo
Créez un nouveau fichier dans `layouts/partials/`, nommé `logo.html`. Puis, écrivez le code HTML voulu.
Vous pourriez utiliser une balise HTML `img` et référencer une image créée dans le dossier *static*, voire même y coller un cod SVG !
{{% notice note %}}
La taille du logo va s'adapter automatiquement
{{% /notice %}}
### Changer le favicon
Si votre favicon est un png, déposez votre image dans votre dossier local `static/images/` et nommez le `favicon.png`
Si vous avez besoin de changer ce comportement par défaut, créer un nouveau fichier dans `layouts/partials/` et nommez le `favicon.html`. Puis ajoutez quelque chose comme:
```html
<link rel="shortcut icon" href="/images/favicon.png" type="image/x-icon" />
```
### Changer les couleurs par défaut {#theme-variant}
**Hugo Learn theme** vous permet de choisir nativement entre 3 schéma de couleurs, mais n'hésitez pas à en ajouter d'autres ! Les couleurs par défaut sont celles de [Grav Learn Theme](https://learn.getgrav.org/).
#### Variante rouge
```toml
[params]
# Modifier le schéma de couleur par défaut. Peut être "red", "blue", "green".
themeVariant = "red"
```
![Variante rouge](/basics/configuration/images/red-variant.png?width=60%)
#### Variante bleue
```toml
[params]
# Modifier le schéma de couleur par défaut. Peut être "red", "blue", "green".
themeVariant = "blue"
```
![Variante bleue](/basics/configuration/images/blue-variant.png?width=60%)
#### Variante verte
```toml
[params]
# Modifier le schéma de couleur par défaut. Peut être "red", "blue", "green".
themeVariant = "green"
```
![Variante verte](/basics/configuration/images/green-variant.png?width=60%)
#### Votre variante
Premièrement, créez un nouveau fichier CSS dans votre dossier `static/css`, préfixé par `theme` (ex: avec le theme_lemien_ `static/css/theme-lemien.css`). Copiez le contenu suivant et modifiez les couleurs dans les variables CSS.
```css
:root{
--MAIN-TEXT-color:#323232; /* Color of text by default */
--MAIN-TITLES-TEXT-color: #5e5e5e; /* Color of titles h2-h3-h4-h5 */
--MAIN-LINK-color:#1C90F3; /* Color of links */
--MAIN-LINK-HOVER-color:#167ad0; /* Color of hovered links */
--MAIN-ANCHOR-color: #1C90F3; /* color of anchors on titles */
--MENU-HEADER-BG-color:#1C90F3; /* Background color of menu header */
--MENU-HEADER-BORDER-color:#33a1ff; /*Color of menu header border */
--MENU-SEARCH-BG-color:#167ad0; /* Search field background color (by default borders + icons) */
--MENU-SEARCH-BOX-color: #33a1ff; /* Override search field border color */
--MENU-SEARCH-BOX-ICONS-color: #a1d2fd; /* Override search field icons color */
--MENU-SECTIONS-ACTIVE-BG-color:#20272b; /* Background color of the active section and its childs */
--MENU-SECTIONS-BG-color:#252c31; /* Background color of other sections */
--MENU-SECTIONS-LINK-color: #ccc; /* Color of links in menu */
--MENU-SECTIONS-LINK-HOVER-color: #e6e6e6; /* Color of links in menu, when hovered */
--MENU-SECTION-ACTIVE-CATEGORY-color: #777; /* Color of active category text */
--MENU-SECTION-ACTIVE-CATEGORY-BG-color: #fff; /* Color of background for the active category (only) */
--MENU-VISITED-color: #33a1ff; /* Color of 'page visited' icons in menu */
--MENU-SECTION-HR-color: #20272b; /* Color of <hr> separator in menu */
}
body {
color: var(--MAIN-TEXT-color) !important;
}
textarea:focus, input[type="email"]:focus, input[type="number"]:focus, input[type="password"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="text"]:focus, input[type="url"]:focus, input[type="color"]:focus, input[type="date"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="week"]:focus, select[multiple=multiple]:focus {
border-color: none;
box-shadow: none;
}
h2, h3, h4, h5 {
color: var(--MAIN-TITLES-TEXT-color) !important;
}
a {
color: var(--MAIN-LINK-color);
}
.anchor {
color: var(--MAIN-ANCHOR-color);
}
a:hover {
color: var(--MAIN-LINK-HOVER-color);
}
#sidebar ul li.visited > a .read-icon {
color: var(--MENU-VISITED-color);
}
#body a.highlight:after {
display: block;
content: "";
height: 1px;
width: 0%;
-webkit-transition: width 0.5s ease;
-moz-transition: width 0.5s ease;
-ms-transition: width 0.5s ease;
transition: width 0.5s ease;
background-color: var(--MAIN-HOVER-color);
}
#sidebar {
background-color: var(--MENU-SECTIONS-BG-color);
}
#sidebar #header-wrapper {
background: var(--MENU-HEADER-BG-color);
color: var(--MENU-SEARCH-BOX-color);
border-color: var(--MENU-HEADER-BORDER-color);
}
#sidebar .searchbox {
border-color: var(--MENU-SEARCH-BOX-color);
background: var(--MENU-SEARCH-BG-color);
}
#sidebar ul.topics > li.parent, #sidebar ul.topics > li.active {
background: var(--MENU-SECTIONS-ACTIVE-BG-color);
}
#sidebar .searchbox * {
color: var(--MENU-SEARCH-BOX-ICONS-color);
}
#sidebar a {
color: var(--MENU-SECTIONS-LINK-color);
}
#sidebar a:hover {
color: var(--MENU-SECTIONS-LINK-HOVER-color);
}
#sidebar ul li.active > a {
background: var(--MENU-SECTION-ACTIVE-CATEGORY-BG-color);
color: var(--MENU-SECTION-ACTIVE-CATEGORY-color) !important;
}
#sidebar hr {
border-color: var(--MENU-SECTION-HR-color);
}
```
Puis, configurez le paramètre `themeVariant` avec le nom de votre variante. C'est tout !
```toml
[params]
# Modifier le schéma de couleur par défaut. Peut être "red", "blue", "green".
themeVariant = "lemien"
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 KiB

View file

@ -0,0 +1,100 @@
---
title: Installation
weight: 15
---
The following steps are here to help you initialize your new website. If you don't know Hugo at all, we strongly suggest you to train by following this [great documentation for beginners](https://gohugo.io/overview/quickstart/).
## Create your project
Hugo provides a `new` command to create a new website.
```
hugo new site <new_project>
```
## Install the theme
Install the **Hugo-theme-learn** theme by following [this documentation](https://gohugo.io/themes/installing/)
The theme's repository is: https://github.com/matcornic/hugo-theme-learn.git
Alternatively, you can [download the theme as .zip](https://github.com/matcornic/hugo-theme-learn/archive/master.zip) file and extract it in the themes directory
## Basic configuration
When building the website, you can set a theme by using `--theme` option. We suggest you to edit your configuration file and set the theme by default. By the way, add requirements for search functionnality to be enabled.
```toml
# Change the default theme to be use when building the site with Hugo
theme = "hugo-theme-learn"
# For search functionnality
[outputs]
home = [ "HTML", "RSS", "JSON"]
```
## Create your first chapter page
Chapters are pages containing other child pages. It has a special layout style and usually just contains a _chapter name_, the _title_ and a _brief abstract_ of the section.
```
### Chapter 1
# Basics
Discover what this Hugo theme is all about and the core-concepts behind it.
```
renders as
![A Chapter](/basics/installation/images/chapter.png?classes=shadow&width=60%)
**Hugo-theme-learn** provides archetypes to create skeletons for your website. Begin by creating your first chapter page with the following command
```
hugo new --kind chapter basics/_index.md
```
By opening the given file, you should see the property `chapter=true` on top, meaning this page is a _chapter_.
## Create your first content pages
Then, create content pages inside the previous chapter. Here are two ways to create content in the chapter :
```
hugo new basics/first-content.md
hugo new basics/second-content/_index.md
```
Feel free to edit thoses files by adding some sample content and replacing `title` value in the beginning of the files.
## Launching the website locally
Launch the following command:
```
hugo serve
```
Go to `http://localhost:1313`
You should notice three things:
1. You have a left **Basics** menu, containing two submenus with names equals to `title` properties in previously created files.
2. The home page explains you to how to customize it. Follow the instructions.
3. With `hugo serve` command, the page refresh as soon as you save a file. Neat !
## Build the website
When your site is ready to deploy, launch the following command:
```
hugo
```
A `public` folder has been generated, containing all statics content and assets for your website. It can now be deployed on any web server !
{{% notice note %}}
This website can be automatically published and hosted with [Netlify](https://www.netlify.com/) (Read more about [Automated HUGO deployments with Netlify](https://www.netlify.com/blog/2015/07/30/hosting-hugo-on-netlifyinsanely-fast-deploys/)). Alternatively, you can use [Github pages](https://gohugo.io/hosting-and-deployment/hosting-on-github/)
{{% /notice %}}

View file

@ -0,0 +1,100 @@
---
title: Installation
weight: 15
---
Les étapes suivantes sont là pour vous aider à initialiser votre site. Si vous ne connaissez pas du tout Hugo, il est fortement conseillé de vous entrainer en suivant ce [super tuto pour débutants](https://gohugo.io/overview/quickstart/).
## Créer votre projet
Hugo fournit une commande `new` pour créer un nouveau site.
```
hugo new site <new_project>
```
## Installer le thème
Installer le thème **Hugo-theme-learn** en suivant [cette documentation](https://gohugo.io/themes/installing/)
Le repo du thème est : https://github.com/matcornic/hugo-theme-learn.git
Sinon, vous pouvez [télécharger le thème sous forme d'un fichier .zip](https://github.com/matcornic/hugo-theme-learn/archive/master.zip) et extrayez le dans votre dossier de thèmes.
## Configuration simple
Lorsque vous générez votre site, vous pouvez définir un thème en utilisant l'option `--theme`. Il est conseillé de modifier votre fichier de configuration `config.toml` and définir votre thème par défaut. En passant, ajoutez les prérequis à l'utilisation de la fonctionnalité de recherche.
```toml
# Modifiez le thème pour qu'il soit utilisé par défaut à chaque génération de site.
theme = "hugo-theme-learn"
# Pour la fonctionnalité de recherche
[outputs]
home = [ "HTML", "RSS", "JSON"]
```
## Créer votre première page chapitre
Les *chapitres* sont des pages contenant d'autre pages filles. Elles ont un affichage spécial et contiennent habituellement juste un _nom_ de chapitre, le _titre_ et un _résumé_ de la section.
```
### Chapitre 1
# Démarrage
Découvrez comment utiliser ce thème Hugo et apprenez en les concepts
```
s'affiche comme
![Un chapitre](/basics/installation/images/chapter.png?classes=shadow&width=60%)
**Hugo-theme-learn** fournit des archétypes pour créer des squelettes pour votre site. Commencez par créer votre premier chapitre avec la commande suivante:
```
hugo new --kind chapter basics/_index.md
```
En ouvrant le fichier généré, vous devriez voir la propriété `chapter=true` en haut, paramètre quit définit que le page est un _chapitre_.
## Créer votre première page
Puis, créez votre premier page dans le chapitre précédent. Pour ce faire, il existe deux possibilités :
```
hugo new basics/first-content.md
hugo new basics/second-content/_index.md
```
N'hésitez pas à éditer ces fichiers en ajoutant des exemple de contenu et en remplaçant le paramètre `title` au début du fichier.
## Lancer le site localement
Lancez la commande suivante :
```
hugo serve
```
Se rendre sur `http://localhost:1313`
Vous devriez voir trois choses:
1. Vous avez un menu **Basics** à gauche, qui contient deux sous-menu avec des noms égal au paramètre `title` des fichiers précédemment générés.
2. La page d'accueil vous explique comment la modifier. Suivez les instructions.
3. Avec la commande `hugo serve`, la page se rafraichit automatiquement à chaque fois que vous sauvegardez. Super !
## Générez le site
Quand votre site est prêt à être déployé, lancez la commande suivante:
```
hugo
```
Un dossier `public` a été généré. Il contient tout le contenu statique et les ressources nécessaires pour votre site. Votre site peut maintenant être déployé en utilisant n'importe quel serveur !
{{% notice note %}}
Ce site peut être automatiquement publié et hébergé avec [Netlify](https://www.netlify.com/) ([Plus d'infos](https://www.netlify.com/blog/2015/07/30/hosting-hugo-on-netlifyinsanely-fast-deploys/)). Sinon, vous pouvez utiliser les [Github pages](https://gohugo.io/hosting-and-deployment/hosting-on-github/)
{{% /notice %}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

View file

@ -0,0 +1,11 @@
---
title: Requirements
weight: 10
disableToc: true
---
Thanks to the simplicity of Hugo, this page is as empty as this theme needs requirements.
Just download latest version of [Hugo binary (> 0.25)](https://gohugo.io/getting-started/installing/) for your OS (Windows, Linux, Mac) : it's that simple.
![Magic](/basics/requirements/images/magic.gif?classes=shadow)

Some files were not shown because too many files have changed in this diff Show more