From eb52c4d2c4c0905024bdc059180f74b540e7f383 Mon Sep 17 00:00:00 2001 From: Andrew Kroh Date: Thu, 7 Jun 2018 19:32:31 -0400 Subject: [PATCH 1/6] Add Windows 2016 to Vagrantfile This image requires membership in the Elastic organization in order to be able to pull it. --- Vagrantfile | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Vagrantfile b/Vagrantfile index 2d5cae6b7931..e161ec5f12b8 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -200,6 +200,16 @@ Vagrant.configure(2) do |config| c.vm.synced_folder ".", "/vagrant", type: "virtualbox" end + # Windows Server 2016 + config.vm.define "win2016", primary: true do |machine| + machine.vm.box = "elastic/windows-2016-x86_64" + machine.vm.provision "shell", inline: $winPsProvision + + machine.vm.provider "virtualbox" do |v| + v.memory = 4096 + end + end + end # -*- mode: ruby -*- From 6d76c298e6d1acf384e862351bdf7c0e1f34fe38 Mon Sep 17 00:00:00 2001 From: Andrew Kroh Date: Thu, 7 Jun 2018 19:21:47 -0400 Subject: [PATCH 2/6] Add github.com/magefile/mage to vendor --- NOTICE.txt | 9 + .../github.com/magefile/mage/CONTRIBUTING.md | 42 + vendor/github.com/magefile/mage/Gopkg.lock | 9 + vendor/github.com/magefile/mage/Gopkg.toml | 22 + vendor/github.com/magefile/mage/LICENSE | 201 ++ vendor/github.com/magefile/mage/README.md | 61 + vendor/github.com/magefile/mage/bootstrap.go | 19 + .../github.com/magefile/mage/build/build.go | 1655 +++++++++++++++++ vendor/github.com/magefile/mage/build/doc.go | 166 ++ vendor/github.com/magefile/mage/build/read.go | 247 +++ .../github.com/magefile/mage/build/syslist.go | 8 + vendor/github.com/magefile/mage/build/zcgo.go | 37 + .../magefile/mage/mage/command_string.go | 16 + .../magefile/mage/mage/magefile_tmpl.go | 46 + vendor/github.com/magefile/mage/mage/main.go | 476 +++++ .../github.com/magefile/mage/mage/template.go | 202 ++ vendor/github.com/magefile/mage/magefile.go | 94 + vendor/github.com/magefile/mage/main.go | 11 + vendor/github.com/magefile/mage/mg/deps.go | 166 ++ vendor/github.com/magefile/mage/mg/errors.go | 51 + vendor/github.com/magefile/mage/mg/runtime.go | 36 + .../magefile/mage/parse/import_go1.9.go | 13 + .../magefile/mage/parse/import_not_go1.9.go | 15 + .../github.com/magefile/mage/parse/parse.go | 341 ++++ .../magefile/mage/parse/srcimporter/sizes.go | 40 + .../mage/parse/srcimporter/srcimporter.go | 213 +++ vendor/github.com/magefile/mage/sh/cmd.go | 165 ++ vendor/github.com/magefile/mage/sh/helpers.go | 16 + .../github.com/magefile/mage/target/target.go | 122 ++ .../github.com/magefile/mage/types/funcs.go | 58 + vendor/vendor.json | 54 + 31 files changed, 4611 insertions(+) create mode 100644 vendor/github.com/magefile/mage/CONTRIBUTING.md create mode 100644 vendor/github.com/magefile/mage/Gopkg.lock create mode 100644 vendor/github.com/magefile/mage/Gopkg.toml create mode 100644 vendor/github.com/magefile/mage/LICENSE create mode 100644 vendor/github.com/magefile/mage/README.md create mode 100644 vendor/github.com/magefile/mage/bootstrap.go create mode 100644 vendor/github.com/magefile/mage/build/build.go create mode 100644 vendor/github.com/magefile/mage/build/doc.go create mode 100644 vendor/github.com/magefile/mage/build/read.go create mode 100644 vendor/github.com/magefile/mage/build/syslist.go create mode 100644 vendor/github.com/magefile/mage/build/zcgo.go create mode 100644 vendor/github.com/magefile/mage/mage/command_string.go create mode 100644 vendor/github.com/magefile/mage/mage/magefile_tmpl.go create mode 100644 vendor/github.com/magefile/mage/mage/main.go create mode 100644 vendor/github.com/magefile/mage/mage/template.go create mode 100644 vendor/github.com/magefile/mage/magefile.go create mode 100644 vendor/github.com/magefile/mage/main.go create mode 100644 vendor/github.com/magefile/mage/mg/deps.go create mode 100644 vendor/github.com/magefile/mage/mg/errors.go create mode 100644 vendor/github.com/magefile/mage/mg/runtime.go create mode 100644 vendor/github.com/magefile/mage/parse/import_go1.9.go create mode 100644 vendor/github.com/magefile/mage/parse/import_not_go1.9.go create mode 100644 vendor/github.com/magefile/mage/parse/parse.go create mode 100644 vendor/github.com/magefile/mage/parse/srcimporter/sizes.go create mode 100644 vendor/github.com/magefile/mage/parse/srcimporter/srcimporter.go create mode 100644 vendor/github.com/magefile/mage/sh/cmd.go create mode 100644 vendor/github.com/magefile/mage/sh/helpers.go create mode 100644 vendor/github.com/magefile/mage/target/target.go create mode 100644 vendor/github.com/magefile/mage/types/funcs.go diff --git a/NOTICE.txt b/NOTICE.txt index 9ef031599e22..dd17d4e44e80 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1396,6 +1396,15 @@ The above copyright notice and this permission notice shall be included in all c 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. +-------------------------------------------------------------------- +Dependency: github.com/magefile/mage +Revision: 5e51f9ad1ed0886c5d06a8c46a09703cfc4d9034 +License type (autodetected): Apache-2.0 +./vendor/github.com/magefile/mage/LICENSE: +-------------------------------------------------------------------- +Apache License 2.0 + + -------------------------------------------------------------------- Dependency: github.com/mattn/go-colorable Revision: 941b50ebc6efddf4c41c8e4537a5f68a4e686b24 diff --git a/vendor/github.com/magefile/mage/CONTRIBUTING.md b/vendor/github.com/magefile/mage/CONTRIBUTING.md new file mode 100644 index 000000000000..e1394d20452c --- /dev/null +++ b/vendor/github.com/magefile/mage/CONTRIBUTING.md @@ -0,0 +1,42 @@ +# Contributing + +Of course, contributions are more than welcome. Please read these guidelines for +making the process as painless as possible. + +## Discussion + +Development discussion should take place on the #mage channel of [gopher +slack](https://gophers.slack.com/). + +There is a separate #mage-dev channel that has the github app to post github +activity to the channel, to make it easy to follow. + +## Issues + +If there's an issue you'd like to work on, please comment on it, so we can +discuss approach, etc. and make sure no one else is currently working on that +issue. + +Please always create an issue before sending a PR unless it's an obvious typo +or other trivial change. + +## Dependency Management + +Currently mage has no dependencies(!) outside the standard libary. Let's keep +it that way. Since it's likely that mage will be vendored into a project, +adding dependencies to mage adds dependencies to every project that uses mage. + +## Versions + +Please avoid using features of go and the stdlib that prevent mage from being +buildable with older versions of Go. The CI tests currently check that mage is +buildable with go 1.7 and later. You may build with whatever version you like, +but CI has the final say. + +## Testing + +Please write tests for any new features. Tests must use the normal go testing +package. + +Tests must pass the race detector (run `go test -race ./...`). + diff --git a/vendor/github.com/magefile/mage/Gopkg.lock b/vendor/github.com/magefile/mage/Gopkg.lock new file mode 100644 index 000000000000..bef2d0092eb5 --- /dev/null +++ b/vendor/github.com/magefile/mage/Gopkg.lock @@ -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 diff --git a/vendor/github.com/magefile/mage/Gopkg.toml b/vendor/github.com/magefile/mage/Gopkg.toml new file mode 100644 index 000000000000..9425a5429667 --- /dev/null +++ b/vendor/github.com/magefile/mage/Gopkg.toml @@ -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" + diff --git a/vendor/github.com/magefile/mage/LICENSE b/vendor/github.com/magefile/mage/LICENSE new file mode 100644 index 000000000000..8dada3edaf50 --- /dev/null +++ b/vendor/github.com/magefile/mage/LICENSE @@ -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. diff --git a/vendor/github.com/magefile/mage/README.md b/vendor/github.com/magefile/mage/README.md new file mode 100644 index 000000000000..63826bb7106b --- /dev/null +++ b/vendor/github.com/magefile/mage/README.md @@ -0,0 +1,61 @@ +

+ +## About [![Build Status](https://travis-ci.org/magefile/mage.svg?branch=master)](https://travis-ci.org/magefile/mage) + +Mage is a make/rake-like build tool using Go. You write plain-old go functions, +and Mage automatically uses them as Makefile-like runnable targets. + +## Installation + +Mage has no dependencies outside the Go standard library, and builds with Go 1.7 +and above (possibly even lower versions, but they're not regularly tested). + +Install mage by running + +``` +go get -u -d github.com/magefile/mage +cd $GOPATH/src/github.com/magefile/mage +go run bootstrap.go +``` + +This will download the code into your GOPATH, and then run the bootstrap script +to build mage with version infomation embedded in it. A normal `go get` +(without -d) will build the binary correctly, but no version info will be +embedded. If you've done this, no worries, just go to +$GOPATH/src/github.com/magefile/mage and run `mage install` or `go run +bootstrap.go` and a new binary will be created with the correct version +information. + +The mage binary will be created in your $GOPATH/bin directory. + +You may also install a binary release from our +[releases](https://github.com/magefile/mage/releases) page. + +## Demo + +[![Mage Demo](https://img.youtube.com/vi/GOqbD0lF-iA/maxresdefault.jpg)](https://www.youtube.com/watch?v=GOqbD0lF-iA) + +## Discussion + +Join the `#mage` channel on [gophers slack](https://gophers.slack.com/messages/general/) for discussion of usage, development, etc. + +# Documentation + +see [magefile.org](https://magefile.org) for full docs + +see [godoc.org/github.com/magefile/mage/mage](https://godoc.org/github.com/magefile/mage/mage) for how to use mage as a library. + +# Why? + +Makefiles are hard to read and hard to write. Mostly because makefiles are essentially fancy bash scripts with significant white space and additional make-related syntax. + +Mage lets you have multiple magefiles, name your magefiles whatever you +want, and they're easy to customize for multiple operating systems. Mage has no +dependencies (aside from go) and runs just fine on all major operating systems, whereas make generally uses bash which is not well supported on Windows. +Go is superior to bash for any non-trivial task involving branching, looping, anything that's not just straight line execution of commands. And if your project is written in Go, why introduce another +language as idiosyncratic as bash? Why not use the language your contributors +are already comfortable with? + +# TODO + +* File conversion tasks diff --git a/vendor/github.com/magefile/mage/bootstrap.go b/vendor/github.com/magefile/mage/bootstrap.go new file mode 100644 index 000000000000..c37f6fc8a5b0 --- /dev/null +++ b/vendor/github.com/magefile/mage/bootstrap.go @@ -0,0 +1,19 @@ +//+build ignore + +package main + +import ( + "os" + + "github.com/magefile/mage/mage" +) + +// This is a bootstrap builder, to build mage when you don't already *have* mage. +// Run it like +// go run bootstrap.go +// and it will install mage with all the right flags created for you. + +func main() { + os.Args = []string{os.Args[0], "-v", "install"} + os.Exit(mage.Main()) +} diff --git a/vendor/github.com/magefile/mage/build/build.go b/vendor/github.com/magefile/mage/build/build.go new file mode 100644 index 000000000000..64198e67110d --- /dev/null +++ b/vendor/github.com/magefile/mage/build/build.go @@ -0,0 +1,1655 @@ +// 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 ( + "bytes" + "errors" + "fmt" + "go/ast" + "go/doc" + "go/parser" + "go/token" + "io" + "io/ioutil" + "log" + "os" + pathpkg "path" + "path/filepath" + "runtime" + "sort" + "strconv" + "strings" + "unicode" + "unicode/utf8" +) + +// A Context specifies the supporting context for a build. +type Context struct { + GOARCH string // target architecture + GOOS string // target operating system + GOROOT string // Go root + GOPATH string // Go path + CgoEnabled bool // whether cgo can be used + UseAllFiles bool // use files regardless of +build lines, file names + Compiler string // compiler to assume when computing target paths + + // RequiredTags lists tags that the must exist in a build tag in order for + // the file to be included in the build. If RequiredTags is empty, no tags + // are required. Note that this is mostly useful in filtering the list of + // files in a single directory. Using required tags across an entire + // compile step will likely exclude much, if not all of the standard library + // files. + RequiredTags []string + + // The build and release tags specify build constraints + // that should be considered satisfied when processing +build lines. + // Clients creating a new context may customize BuildTags, which + // defaults to empty, but it is usually an error to customize ReleaseTags, + // which defaults to the list of Go releases the current release is compatible with. + // In addition to the BuildTags and ReleaseTags, build constraints + // consider the values of GOARCH and GOOS as satisfied tags. + BuildTags []string + ReleaseTags []string + + // The install suffix specifies a suffix to use in the name of the installation + // directory. By default it is empty, but custom builds that need to keep + // their outputs separate can set InstallSuffix to do so. For example, when + // using the race detector, the go command uses InstallSuffix = "race", so + // that on a Linux/386 system, packages are written to a directory named + // "linux_386_race" instead of the usual "linux_386". + InstallSuffix string + + // By default, Import uses the operating system's file system calls + // to read directories and files. To read from other sources, + // callers can set the following functions. They all have default + // behaviors that use the local file system, so clients need only set + // the functions whose behaviors they wish to change. + + // JoinPath joins the sequence of path fragments into a single path. + // If JoinPath is nil, Import uses filepath.Join. + JoinPath func(elem ...string) string + + // SplitPathList splits the path list into a slice of individual paths. + // If SplitPathList is nil, Import uses filepath.SplitList. + SplitPathList func(list string) []string + + // IsAbsPath reports whether path is an absolute path. + // If IsAbsPath is nil, Import uses filepath.IsAbs. + IsAbsPath func(path string) bool + + // IsDir reports whether the path names a directory. + // If IsDir is nil, Import calls os.Stat and uses the result's IsDir method. + IsDir func(path string) bool + + // HasSubdir reports whether dir is lexically a subdirectory of + // root, perhaps multiple levels below. It does not try to check + // whether dir exists. + // If so, HasSubdir sets rel to a slash-separated path that + // can be joined to root to produce a path equivalent to dir. + // If HasSubdir is nil, Import uses an implementation built on + // filepath.EvalSymlinks. + HasSubdir func(root, dir string) (rel string, ok bool) + + // ReadDir returns a slice of os.FileInfo, sorted by Name, + // describing the content of the named directory. + // If ReadDir is nil, Import uses ioutil.ReadDir. + ReadDir func(dir string) ([]os.FileInfo, error) + + // OpenFile opens a file (not a directory) for reading. + // If OpenFile is nil, Import uses os.Open. + OpenFile func(path string) (io.ReadCloser, error) +} + +// joinPath calls ctxt.JoinPath (if not nil) or else filepath.Join. +func (ctxt *Context) joinPath(elem ...string) string { + if f := ctxt.JoinPath; f != nil { + return f(elem...) + } + return filepath.Join(elem...) +} + +// splitPathList calls ctxt.SplitPathList (if not nil) or else filepath.SplitList. +func (ctxt *Context) splitPathList(s string) []string { + if f := ctxt.SplitPathList; f != nil { + return f(s) + } + return filepath.SplitList(s) +} + +// isAbsPath calls ctxt.IsAbsPath (if not nil) or else filepath.IsAbs. +func (ctxt *Context) isAbsPath(path string) bool { + if f := ctxt.IsAbsPath; f != nil { + return f(path) + } + return filepath.IsAbs(path) +} + +// isDir calls ctxt.IsDir (if not nil) or else uses os.Stat. +func (ctxt *Context) isDir(path string) bool { + if f := ctxt.IsDir; f != nil { + return f(path) + } + fi, err := os.Stat(path) + return err == nil && fi.IsDir() +} + +// hasSubdir calls ctxt.HasSubdir (if not nil) or else uses +// the local file system to answer the question. +func (ctxt *Context) hasSubdir(root, dir string) (rel string, ok bool) { + if f := ctxt.HasSubdir; f != nil { + return f(root, dir) + } + + // Try using paths we received. + if rel, ok = hasSubdir(root, dir); ok { + return rel, ok + } + + // Try expanding symlinks and comparing + // expanded against unexpanded and + // expanded against expanded. + rootSym, _ := filepath.EvalSymlinks(root) + dirSym, _ := filepath.EvalSymlinks(dir) + + if rel, ok = hasSubdir(rootSym, dir); ok { + return rel, ok + } + if rel, ok = hasSubdir(root, dirSym); ok { + return rel, ok + } + return hasSubdir(rootSym, dirSym) +} + +// hasSubdir reports if dir is within root by performing lexical analysis only. +func hasSubdir(root, dir string) (rel string, ok bool) { + const sep = string(filepath.Separator) + root = filepath.Clean(root) + if !strings.HasSuffix(root, sep) { + root += sep + } + dir = filepath.Clean(dir) + if !strings.HasPrefix(dir, root) { + return "", false + } + return filepath.ToSlash(dir[len(root):]), true +} + +// readDir calls ctxt.ReadDir (if not nil) or else ioutil.ReadDir. +func (ctxt *Context) readDir(path string) ([]os.FileInfo, error) { + if f := ctxt.ReadDir; f != nil { + return f(path) + } + return ioutil.ReadDir(path) +} + +// openFile calls ctxt.OpenFile (if not nil) or else os.Open. +func (ctxt *Context) openFile(path string) (io.ReadCloser, error) { + if fn := ctxt.OpenFile; fn != nil { + return fn(path) + } + + f, err := os.Open(path) + if err != nil { + return nil, err // nil interface + } + return f, nil +} + +// isFile determines whether path is a file by trying to open it. +// It reuses openFile instead of adding another function to the +// list in Context. +func (ctxt *Context) isFile(path string) bool { + f, err := ctxt.openFile(path) + if err != nil { + return false + } + f.Close() + return true +} + +// gopath returns the list of Go path directories. +func (ctxt *Context) gopath() []string { + var all []string + for _, p := range ctxt.splitPathList(ctxt.GOPATH) { + if p == "" || p == ctxt.GOROOT { + // Empty paths are uninteresting. + // If the path is the GOROOT, ignore it. + // People sometimes set GOPATH=$GOROOT. + // Do not get confused by this common mistake. + continue + } + if strings.HasPrefix(p, "~") { + // Path segments starting with ~ on Unix are almost always + // users who have incorrectly quoted ~ while setting GOPATH, + // preventing it from expanding to $HOME. + // The situation is made more confusing by the fact that + // bash allows quoted ~ in $PATH (most shells do not). + // Do not get confused by this, and do not try to use the path. + // It does not exist, and printing errors about it confuses + // those users even more, because they think "sure ~ exists!". + // The go command diagnoses this situation and prints a + // useful error. + // On Windows, ~ is used in short names, such as c:\progra~1 + // for c:\program files. + continue + } + all = append(all, p) + } + return all +} + +// SrcDirs returns a list of package source root directories. +// It draws from the current Go root and Go path but omits directories +// that do not exist. +func (ctxt *Context) SrcDirs() []string { + var all []string + if ctxt.GOROOT != "" { + dir := ctxt.joinPath(ctxt.GOROOT, "src") + if ctxt.isDir(dir) { + all = append(all, dir) + } + } + for _, p := range ctxt.gopath() { + dir := ctxt.joinPath(p, "src") + if ctxt.isDir(dir) { + all = append(all, dir) + } + } + return all +} + +// Default is the default Context for builds. +// It uses the GOARCH, GOOS, GOROOT, and GOPATH environment variables +// if set, or else the compiled code's GOARCH, GOOS, and GOROOT. +var Default Context = defaultContext() + +func defaultGOPATH() string { + env := "HOME" + if runtime.GOOS == "windows" { + env = "USERPROFILE" + } else if runtime.GOOS == "plan9" { + env = "home" + } + if home := os.Getenv(env); home != "" { + def := filepath.Join(home, "go") + if filepath.Clean(def) == filepath.Clean(runtime.GOROOT()) { + // Don't set the default GOPATH to GOROOT, + // as that will trigger warnings from the go tool. + return "" + } + return def + } + return "" +} + +func defaultContext() Context { + var c Context + + c.GOARCH = envOr("GOARCH", runtime.GOARCH) + c.GOOS = envOr("GOOS", runtime.GOOS) + c.GOROOT = pathpkg.Clean(runtime.GOROOT()) + c.GOPATH = envOr("GOPATH", defaultGOPATH()) + c.Compiler = runtime.Compiler + + // Each major Go release in the Go 1.x series should add a tag here. + // Old tags should not be removed. That is, the go1.x tag is present + // in all releases >= Go 1.x. Code that requires Go 1.x or later should + // say "+build go1.x", and code that should only be built before Go 1.x + // (perhaps it is the stub to use in that case) should say "+build !go1.x". + // NOTE: If you add to this list, also update the doc comment in doc.go. + c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6", "go1.7", "go1.8", "go1.9"} + + env := os.Getenv("CGO_ENABLED") + if env == "" { + env = defaultCGO_ENABLED + } + switch env { + case "1": + c.CgoEnabled = true + case "0": + c.CgoEnabled = false + default: + // cgo must be explicitly enabled for cross compilation builds + if runtime.GOARCH == c.GOARCH && runtime.GOOS == c.GOOS { + c.CgoEnabled = cgoEnabled[c.GOOS+"/"+c.GOARCH] + break + } + c.CgoEnabled = false + } + + return c +} + +func envOr(name, def string) string { + s := os.Getenv(name) + if s == "" { + return def + } + return s +} + +// An ImportMode controls the behavior of the Import method. +type ImportMode uint + +const ( + // If FindOnly is set, Import stops after locating the directory + // that should contain the sources for a package. It does not + // read any files in the directory. + FindOnly ImportMode = 1 << iota + + // If AllowBinary is set, Import can be satisfied by a compiled + // package object without corresponding sources. + // + // Deprecated: + // The supported way to create a compiled-only package is to + // write source code containing a //go:binary-only-package comment at + // the top of the file. Such a package will be recognized + // regardless of this flag setting (because it has source code) + // and will have BinaryOnly set to true in the returned Package. + AllowBinary + + // If ImportComment is set, parse import comments on package statements. + // Import returns an error if it finds a comment it cannot understand + // or finds conflicting comments in multiple source files. + // See golang.org/s/go14customimport for more information. + ImportComment + + // By default, Import searches vendor directories + // that apply in the given source directory before searching + // the GOROOT and GOPATH roots. + // If an Import finds and returns a package using a vendor + // directory, the resulting ImportPath is the complete path + // to the package, including the path elements leading up + // to and including "vendor". + // For example, if Import("y", "x/subdir", 0) finds + // "x/vendor/y", the returned package's ImportPath is "x/vendor/y", + // not plain "y". + // See golang.org/s/go15vendor for more information. + // + // Setting IgnoreVendor ignores vendor directories. + // + // In contrast to the package's ImportPath, + // the returned package's Imports, TestImports, and XTestImports + // are always the exact import paths from the source files: + // Import makes no attempt to resolve or check those paths. + IgnoreVendor +) + +// A Package describes the Go package found in a directory. +type Package struct { + Dir string // directory containing package sources + Name string // package name + ImportComment string // path in import comment on package statement + Doc string // documentation synopsis + ImportPath string // import path of package ("" if unknown) + Root string // root of Go tree where this package lives + SrcRoot string // package source root directory ("" if unknown) + PkgRoot string // package install root directory ("" if unknown) + PkgTargetRoot string // architecture dependent install root directory ("" if unknown) + BinDir string // command install directory ("" if unknown) + Goroot bool // package found in Go root + PkgObj string // installed .a file + AllTags []string // tags that can influence file selection in this directory + ConflictDir string // this directory shadows Dir in $GOPATH + BinaryOnly bool // cannot be rebuilt from source (has //go:binary-only-package comment) + + // Source files + GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) + CgoFiles []string // .go source files that import "C" + IgnoredGoFiles []string // .go source files ignored for this build + InvalidGoFiles []string // .go source files with detected problems (parse error, wrong package name, and so on) + CFiles []string // .c source files + CXXFiles []string // .cc, .cpp and .cxx source files + MFiles []string // .m (Objective-C) source files + HFiles []string // .h, .hh, .hpp and .hxx source files + FFiles []string // .f, .F, .for and .f90 Fortran source files + SFiles []string // .s source files + SwigFiles []string // .swig files + SwigCXXFiles []string // .swigcxx files + SysoFiles []string // .syso system object files to add to archive + + // Cgo directives + CgoCFLAGS []string // Cgo CFLAGS directives + CgoCPPFLAGS []string // Cgo CPPFLAGS directives + CgoCXXFLAGS []string // Cgo CXXFLAGS directives + CgoFFLAGS []string // Cgo FFLAGS directives + CgoLDFLAGS []string // Cgo LDFLAGS directives + CgoPkgConfig []string // Cgo pkg-config directives + + // Dependency information + Imports []string // import paths from GoFiles, CgoFiles + ImportPos map[string][]token.Position // line information for Imports + + // Test information + TestGoFiles []string // _test.go files in package + TestImports []string // import paths from TestGoFiles + TestImportPos map[string][]token.Position // line information for TestImports + XTestGoFiles []string // _test.go files outside package + XTestImports []string // import paths from XTestGoFiles + XTestImportPos map[string][]token.Position // line information for XTestImports +} + +// IsCommand reports whether the package is considered a +// command to be installed (not just a library). +// Packages named "main" are treated as commands. +func (p *Package) IsCommand() bool { + return p.Name == "main" +} + +// ImportDir is like Import but processes the Go package found in +// the named directory. +func (ctxt *Context) ImportDir(dir string, mode ImportMode) (*Package, error) { + return ctxt.Import(".", dir, mode) +} + +// NoGoError is the error used by Import to describe a directory +// containing no buildable Go source files. (It may still contain +// test files, files hidden by build tags, and so on.) +type NoGoError struct { + Dir string +} + +func (e *NoGoError) Error() string { + return "no buildable Go source files in " + e.Dir +} + +// MultiplePackageError describes a directory containing +// multiple buildable Go source files for multiple packages. +type MultiplePackageError struct { + Dir string // directory containing files + Packages []string // package names found + Files []string // corresponding files: Files[i] declares package Packages[i] +} + +func (e *MultiplePackageError) Error() string { + // Error string limited to two entries for compatibility. + return fmt.Sprintf("found packages %s (%s) and %s (%s) in %s", e.Packages[0], e.Files[0], e.Packages[1], e.Files[1], e.Dir) +} + +func nameExt(name string) string { + i := strings.LastIndex(name, ".") + if i < 0 { + return "" + } + return name[i:] +} + +// Import returns details about the Go package named by the import path, +// interpreting local import paths relative to the srcDir directory. +// If the path is a local import path naming a package that can be imported +// using a standard import path, the returned package will set p.ImportPath +// to that path. +// +// In the directory containing the package, .go, .c, .h, and .s files are +// considered part of the package except for: +// +// - .go files in package documentation +// - files starting with _ or . (likely editor temporary files) +// - files with build constraints not satisfied by the context +// +// If an error occurs, Import returns a non-nil error and a non-nil +// *Package containing partial information. +// +func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Package, error) { + p := &Package{ + ImportPath: path, + } + if path == "" { + return p, fmt.Errorf("import %q: invalid import path", path) + } + + var pkgtargetroot string + var pkga string + var pkgerr error + suffix := "" + if ctxt.InstallSuffix != "" { + suffix = "_" + ctxt.InstallSuffix + } + switch ctxt.Compiler { + case "gccgo": + pkgtargetroot = "pkg/gccgo_" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix + case "gc": + pkgtargetroot = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix + default: + // Save error for end of function. + pkgerr = fmt.Errorf("import %q: unknown compiler %q", path, ctxt.Compiler) + } + setPkga := func() { + switch ctxt.Compiler { + case "gccgo": + dir, elem := pathpkg.Split(p.ImportPath) + pkga = pkgtargetroot + "/" + dir + "lib" + elem + ".a" + case "gc": + pkga = pkgtargetroot + "/" + p.ImportPath + ".a" + } + } + setPkga() + + binaryOnly := false + if IsLocalImport(path) { + pkga = "" // local imports have no installed path + if srcDir == "" { + return p, fmt.Errorf("import %q: import relative to unknown directory", path) + } + if !ctxt.isAbsPath(path) { + p.Dir = ctxt.joinPath(srcDir, path) + } + // p.Dir directory may or may not exist. Gather partial information first, check if it exists later. + // Determine canonical import path, if any. + // Exclude results where the import path would include /testdata/. + inTestdata := func(sub string) bool { + return strings.Contains(sub, "/testdata/") || strings.HasSuffix(sub, "/testdata") || strings.HasPrefix(sub, "testdata/") || sub == "testdata" + } + if ctxt.GOROOT != "" { + root := ctxt.joinPath(ctxt.GOROOT, "src") + if sub, ok := ctxt.hasSubdir(root, p.Dir); ok && !inTestdata(sub) { + p.Goroot = true + p.ImportPath = sub + p.Root = ctxt.GOROOT + goto Found + } + } + all := ctxt.gopath() + for i, root := range all { + rootsrc := ctxt.joinPath(root, "src") + if sub, ok := ctxt.hasSubdir(rootsrc, p.Dir); ok && !inTestdata(sub) { + // We found a potential import path for dir, + // but check that using it wouldn't find something + // else first. + if ctxt.GOROOT != "" { + if dir := ctxt.joinPath(ctxt.GOROOT, "src", sub); ctxt.isDir(dir) { + p.ConflictDir = dir + goto Found + } + } + for _, earlyRoot := range all[:i] { + if dir := ctxt.joinPath(earlyRoot, "src", sub); ctxt.isDir(dir) { + p.ConflictDir = dir + goto Found + } + } + + // sub would not name some other directory instead of this one. + // Record it. + p.ImportPath = sub + p.Root = root + goto Found + } + } + // It's okay that we didn't find a root containing dir. + // Keep going with the information we have. + } else { + if strings.HasPrefix(path, "/") { + return p, fmt.Errorf("import %q: cannot import absolute path", path) + } + + // tried records the location of unsuccessful package lookups + var tried struct { + vendor []string + goroot string + gopath []string + } + gopath := ctxt.gopath() + + // Vendor directories get first chance to satisfy import. + if mode&IgnoreVendor == 0 && srcDir != "" { + searchVendor := func(root string, isGoroot bool) bool { + sub, ok := ctxt.hasSubdir(root, srcDir) + if !ok || !strings.HasPrefix(sub, "src/") || strings.Contains(sub, "/testdata/") { + return false + } + for { + vendor := ctxt.joinPath(root, sub, "vendor") + if ctxt.isDir(vendor) { + dir := ctxt.joinPath(vendor, path) + if ctxt.isDir(dir) && hasGoFiles(ctxt, dir) { + p.Dir = dir + p.ImportPath = strings.TrimPrefix(pathpkg.Join(sub, "vendor", path), "src/") + p.Goroot = isGoroot + p.Root = root + setPkga() // p.ImportPath changed + return true + } + tried.vendor = append(tried.vendor, dir) + } + i := strings.LastIndex(sub, "/") + if i < 0 { + break + } + sub = sub[:i] + } + return false + } + if searchVendor(ctxt.GOROOT, true) { + goto Found + } + for _, root := range gopath { + if searchVendor(root, false) { + goto Found + } + } + } + + // Determine directory from import path. + if ctxt.GOROOT != "" { + dir := ctxt.joinPath(ctxt.GOROOT, "src", path) + isDir := ctxt.isDir(dir) + binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga)) + if isDir || binaryOnly { + p.Dir = dir + p.Goroot = true + p.Root = ctxt.GOROOT + goto Found + } + tried.goroot = dir + } + for _, root := range gopath { + dir := ctxt.joinPath(root, "src", path) + isDir := ctxt.isDir(dir) + binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(root, pkga)) + if isDir || binaryOnly { + p.Dir = dir + p.Root = root + goto Found + } + tried.gopath = append(tried.gopath, dir) + } + + // package was not found + var paths []string + format := "\t%s (vendor tree)" + for _, dir := range tried.vendor { + paths = append(paths, fmt.Sprintf(format, dir)) + format = "\t%s" + } + if tried.goroot != "" { + paths = append(paths, fmt.Sprintf("\t%s (from $GOROOT)", tried.goroot)) + } else { + paths = append(paths, "\t($GOROOT not set)") + } + format = "\t%s (from $GOPATH)" + for _, dir := range tried.gopath { + paths = append(paths, fmt.Sprintf(format, dir)) + format = "\t%s" + } + if len(tried.gopath) == 0 { + paths = append(paths, "\t($GOPATH not set. For more details see: 'go help gopath')") + } + return p, fmt.Errorf("cannot find package %q in any of:\n%s", path, strings.Join(paths, "\n")) + } + +Found: + if p.Root != "" { + p.SrcRoot = ctxt.joinPath(p.Root, "src") + p.PkgRoot = ctxt.joinPath(p.Root, "pkg") + p.BinDir = ctxt.joinPath(p.Root, "bin") + if pkga != "" { + p.PkgTargetRoot = ctxt.joinPath(p.Root, pkgtargetroot) + p.PkgObj = ctxt.joinPath(p.Root, pkga) + } + } + + // If it's a local import path, by the time we get here, we still haven't checked + // that p.Dir directory exists. This is the right time to do that check. + // We can't do it earlier, because we want to gather partial information for the + // non-nil *Package returned when an error occurs. + // We need to do this before we return early on FindOnly flag. + if IsLocalImport(path) && !ctxt.isDir(p.Dir) { + // package was not found + return p, fmt.Errorf("cannot find package %q in:\n\t%s", path, p.Dir) + } + + if mode&FindOnly != 0 { + return p, pkgerr + } + if binaryOnly && (mode&AllowBinary) != 0 { + return p, pkgerr + } + + dirs, err := ctxt.readDir(p.Dir) + if err != nil { + return p, err + } + + var badGoError error + var Sfiles []string // files with ".S" (capital S) + var firstFile, firstCommentFile string + imported := make(map[string][]token.Position) + testImported := make(map[string][]token.Position) + xTestImported := make(map[string][]token.Position) + allTags := make(map[string]bool) + fset := token.NewFileSet() + for _, d := range dirs { + if d.IsDir() { + continue + } + + name := d.Name() + ext := nameExt(name) + + badFile := func(err error) { + if badGoError == nil { + badGoError = err + } + p.InvalidGoFiles = append(p.InvalidGoFiles, name) + } + + match, data, filename, err := ctxt.matchFile(p.Dir, name, allTags, &p.BinaryOnly) + if err != nil { + badFile(err) + continue + } + if !match { + if ext == ".go" { + p.IgnoredGoFiles = append(p.IgnoredGoFiles, name) + } + continue + } + + // Going to save the file. For non-Go files, can stop here. + switch ext { + case ".c": + p.CFiles = append(p.CFiles, name) + continue + case ".cc", ".cpp", ".cxx": + p.CXXFiles = append(p.CXXFiles, name) + continue + case ".m": + p.MFiles = append(p.MFiles, name) + continue + case ".h", ".hh", ".hpp", ".hxx": + p.HFiles = append(p.HFiles, name) + continue + case ".f", ".F", ".for", ".f90": + p.FFiles = append(p.FFiles, name) + continue + case ".s": + p.SFiles = append(p.SFiles, name) + continue + case ".S": + Sfiles = append(Sfiles, name) + continue + case ".swig": + p.SwigFiles = append(p.SwigFiles, name) + continue + case ".swigcxx": + p.SwigCXXFiles = append(p.SwigCXXFiles, name) + continue + case ".syso": + // binary objects to add to package archive + // Likely of the form foo_windows.syso, but + // the name was vetted above with goodOSArchFile. + p.SysoFiles = append(p.SysoFiles, name) + continue + } + + pf, err := parser.ParseFile(fset, filename, data, parser.ImportsOnly|parser.ParseComments) + if err != nil { + badFile(err) + continue + } + + pkg := pf.Name.Name + if pkg == "documentation" { + p.IgnoredGoFiles = append(p.IgnoredGoFiles, name) + continue + } + + isTest := strings.HasSuffix(name, "_test.go") + isXTest := false + if isTest && strings.HasSuffix(pkg, "_test") { + isXTest = true + pkg = pkg[:len(pkg)-len("_test")] + } + + if p.Name == "" { + p.Name = pkg + firstFile = name + } else if pkg != p.Name { + badFile(&MultiplePackageError{ + Dir: p.Dir, + Packages: []string{p.Name, pkg}, + Files: []string{firstFile, name}, + }) + p.InvalidGoFiles = append(p.InvalidGoFiles, name) + } + if pf.Doc != nil && p.Doc == "" { + p.Doc = doc.Synopsis(pf.Doc.Text()) + } + + if mode&ImportComment != 0 { + qcom, line := findImportComment(data) + if line != 0 { + com, err := strconv.Unquote(qcom) + if err != nil { + badFile(fmt.Errorf("%s:%d: cannot parse import comment", filename, line)) + } else if p.ImportComment == "" { + p.ImportComment = com + firstCommentFile = name + } else if p.ImportComment != com { + badFile(fmt.Errorf("found import comments %q (%s) and %q (%s) in %s", p.ImportComment, firstCommentFile, com, name, p.Dir)) + } + } + } + + // Record imports and information about cgo. + isCgo := false + for _, decl := range pf.Decls { + d, ok := decl.(*ast.GenDecl) + if !ok { + continue + } + for _, dspec := range d.Specs { + spec, ok := dspec.(*ast.ImportSpec) + if !ok { + continue + } + quoted := spec.Path.Value + path, err := strconv.Unquote(quoted) + if err != nil { + log.Panicf("%s: parser returned invalid quoted string: <%s>", filename, quoted) + } + if isXTest { + xTestImported[path] = append(xTestImported[path], fset.Position(spec.Pos())) + } else if isTest { + testImported[path] = append(testImported[path], fset.Position(spec.Pos())) + } else { + imported[path] = append(imported[path], fset.Position(spec.Pos())) + } + if path == "C" { + if isTest { + badFile(fmt.Errorf("use of cgo in test %s not supported", filename)) + } else { + cg := spec.Doc + if cg == nil && len(d.Specs) == 1 { + cg = d.Doc + } + if cg != nil { + if err := ctxt.saveCgo(filename, p, cg); err != nil { + badFile(err) + } + } + isCgo = true + } + } + } + } + if isCgo { + allTags["cgo"] = true + if ctxt.CgoEnabled { + p.CgoFiles = append(p.CgoFiles, name) + } else { + p.IgnoredGoFiles = append(p.IgnoredGoFiles, name) + } + } else if isXTest { + p.XTestGoFiles = append(p.XTestGoFiles, name) + } else if isTest { + p.TestGoFiles = append(p.TestGoFiles, name) + } else { + p.GoFiles = append(p.GoFiles, name) + } + } + if badGoError != nil { + return p, badGoError + } + if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 { + return p, &NoGoError{p.Dir} + } + + for tag := range allTags { + p.AllTags = append(p.AllTags, tag) + } + sort.Strings(p.AllTags) + + p.Imports, p.ImportPos = cleanImports(imported) + p.TestImports, p.TestImportPos = cleanImports(testImported) + p.XTestImports, p.XTestImportPos = cleanImports(xTestImported) + + // add the .S files only if we are using cgo + // (which means gcc will compile them). + // The standard assemblers expect .s files. + if len(p.CgoFiles) > 0 { + p.SFiles = append(p.SFiles, Sfiles...) + sort.Strings(p.SFiles) + } + + return p, pkgerr +} + +// hasGoFiles reports whether dir contains any files with names ending in .go. +// For a vendor check we must exclude directories that contain no .go files. +// Otherwise it is not possible to vendor just a/b/c and still import the +// non-vendored a/b. See golang.org/issue/13832. +func hasGoFiles(ctxt *Context, dir string) bool { + ents, _ := ctxt.readDir(dir) + for _, ent := range ents { + if !ent.IsDir() && strings.HasSuffix(ent.Name(), ".go") { + return true + } + } + return false +} + +func findImportComment(data []byte) (s string, line int) { + // expect keyword package + word, data := parseWord(data) + if string(word) != "package" { + return "", 0 + } + + // expect package name + _, data = parseWord(data) + + // now ready for import comment, a // or /* */ comment + // beginning and ending on the current line. + for len(data) > 0 && (data[0] == ' ' || data[0] == '\t' || data[0] == '\r') { + data = data[1:] + } + + var comment []byte + switch { + case bytes.HasPrefix(data, slashSlash): + i := bytes.Index(data, newline) + if i < 0 { + i = len(data) + } + comment = data[2:i] + case bytes.HasPrefix(data, slashStar): + data = data[2:] + i := bytes.Index(data, starSlash) + if i < 0 { + // malformed comment + return "", 0 + } + comment = data[:i] + if bytes.Contains(comment, newline) { + return "", 0 + } + } + comment = bytes.TrimSpace(comment) + + // split comment into `import`, `"pkg"` + word, arg := parseWord(comment) + if string(word) != "import" { + return "", 0 + } + + line = 1 + bytes.Count(data[:cap(data)-cap(arg)], newline) + return strings.TrimSpace(string(arg)), line +} + +var ( + slashSlash = []byte("//") + slashStar = []byte("/*") + starSlash = []byte("*/") + newline = []byte("\n") +) + +// skipSpaceOrComment returns data with any leading spaces or comments removed. +func skipSpaceOrComment(data []byte) []byte { + for len(data) > 0 { + switch data[0] { + case ' ', '\t', '\r', '\n': + data = data[1:] + continue + case '/': + if bytes.HasPrefix(data, slashSlash) { + i := bytes.Index(data, newline) + if i < 0 { + return nil + } + data = data[i+1:] + continue + } + if bytes.HasPrefix(data, slashStar) { + data = data[2:] + i := bytes.Index(data, starSlash) + if i < 0 { + return nil + } + data = data[i+2:] + continue + } + } + break + } + return data +} + +// parseWord skips any leading spaces or comments in data +// and then parses the beginning of data as an identifier or keyword, +// returning that word and what remains after the word. +func parseWord(data []byte) (word, rest []byte) { + data = skipSpaceOrComment(data) + + // Parse past leading word characters. + rest = data + for { + r, size := utf8.DecodeRune(rest) + if unicode.IsLetter(r) || '0' <= r && r <= '9' || r == '_' { + rest = rest[size:] + continue + } + break + } + + word = data[:len(data)-len(rest)] + if len(word) == 0 { + return nil, nil + } + + return word, rest +} + +// MatchFile reports whether the file with the given name in the given directory +// matches the context and would be included in a Package created by ImportDir +// of that directory. +// +// MatchFile considers the name of the file and may use ctxt.OpenFile to +// read some or all of the file's content. +func (ctxt *Context) MatchFile(dir, name string) (match bool, err error) { + match, _, _, err = ctxt.matchFile(dir, name, nil, nil) + return match, err + +} + +// matchFile determines whether the file with the given name in the given directory +// should be included in the package being constructed. +// It returns the data read from the file. +// If name denotes a Go program, matchFile reads until the end of the +// imports (and returns that data) even though it only considers text +// until the first non-comment. +// If allTags is non-nil, matchFile records any encountered build tag +// by setting allTags[tag] = true. +func (ctxt *Context) matchFile(dir, name string, allTags map[string]bool, binaryOnly *bool) (match bool, data []byte, filename string, err error) { + if strings.HasPrefix(name, "_") || + strings.HasPrefix(name, ".") { + return match, data, filename, err + } + + i := strings.LastIndex(name, ".") + if i < 0 { + i = len(name) + } + ext := name[i:] + + if !ctxt.goodOSArchFile(name, allTags) && !ctxt.UseAllFiles { + return match, data, filename, err + } + + switch ext { + case ".go", ".c", ".cc", ".cxx", ".cpp", ".m", ".s", ".h", ".hh", ".hpp", ".hxx", ".f", ".F", ".f90", ".S", ".swig", ".swigcxx": + // tentatively okay - read to make sure + case ".syso": + // binary, no reading + match = true + return match, data, filename, err + default: + // skip + return match, data, filename, err + } + + filename = ctxt.joinPath(dir, name) + f, err := ctxt.openFile(filename) + if err != nil { + return match, data, filename, err + } + + if strings.HasSuffix(filename, ".go") { + data, err = readImports(f, false, nil) + if strings.HasSuffix(filename, "_test.go") { + binaryOnly = nil // ignore //go:binary-only-package comments in _test.go files + } + } else { + binaryOnly = nil // ignore //go:binary-only-package comments in non-Go sources + data, err = readComments(f) + } + f.Close() + if err != nil { + err = fmt.Errorf("read %s: %v", filename, err) + return match, data, filename, err + } + + // Look for +build comments to accept or reject the file. + var sawBinaryOnly bool + if !ctxt.shouldBuild(data, allTags, &sawBinaryOnly) && !ctxt.UseAllFiles { + return match, data, filename, err + } + + if binaryOnly != nil && sawBinaryOnly { + *binaryOnly = true + } + match = true + return match, data, filename, err +} + +func cleanImports(m map[string][]token.Position) ([]string, map[string][]token.Position) { + all := make([]string, 0, len(m)) + for path := range m { + all = append(all, path) + } + sort.Strings(all) + return all, m +} + +// Import is shorthand for Default.Import. +func Import(path, srcDir string, mode ImportMode) (*Package, error) { + return Default.Import(path, srcDir, mode) +} + +// ImportDir is shorthand for Default.ImportDir. +func ImportDir(dir string, mode ImportMode) (*Package, error) { + return Default.ImportDir(dir, mode) +} + +var slashslash = []byte("//") + +// Special comment denoting a binary-only package. +// See https://golang.org/design/2775-binary-only-packages +// for more about the design of binary-only packages. +var binaryOnlyComment = []byte("//go:binary-only-package") + +// shouldBuild reports whether it is okay to use this file, +// The rule is that in the file's leading run of // comments +// and blank lines, which must be followed by a blank line +// (to avoid including a Go package clause doc comment), +// lines beginning with '// +build' are taken as build directives. +// +// The file is accepted only if each such line lists something +// matching the file. For example: +// +// // +build windows linux +// +// marks the file as applicable only on Windows and Linux. +// +// If shouldBuild finds a //go:binary-only-package comment in the file, +// it sets *binaryOnly to true. Otherwise it does not change *binaryOnly. +// +func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool, binaryOnly *bool) bool { + sawBinaryOnly := false + + // Pass 1. Identify leading run of // comments and blank lines, + // which must be followed by a blank line. + end := 0 + p := content + for len(p) > 0 { + line := p + if i := bytes.IndexByte(line, '\n'); i >= 0 { + line, p = line[:i], p[i+1:] + } else { + p = p[len(p):] + } + line = bytes.TrimSpace(line) + if len(line) == 0 { // Blank line + end = len(content) - len(p) + continue + } + if !bytes.HasPrefix(line, slashslash) { // Not comment line + break + } + } + content = content[:end] + + // Pass 2. Process each line in the run. + p = content + hasReq := len(ctxt.RequiredTags) > 0 + allok := !hasReq + for len(p) > 0 { + line := p + if i := bytes.IndexByte(line, '\n'); i >= 0 { + line, p = line[:i], p[i+1:] + } else { + p = p[len(p):] + } + line = bytes.TrimSpace(line) + if bytes.HasPrefix(line, slashslash) { + if bytes.Equal(line, binaryOnlyComment) { + sawBinaryOnly = true + } + line = bytes.TrimSpace(line[len(slashslash):]) + if len(line) > 0 && line[0] == '+' { + // Looks like a comment +line. + f := strings.Fields(string(line)) + if f[0] == "+build" { + ok := false + for _, tok := range f[1:] { + tags := map[string]bool{} + if ctxt.match(tok, tags) { + if containsAll(tags, ctxt.RequiredTags) { + ok = true + } + } + merge(allTags, tags) + } + if !hasReq { + if !ok { + allok = false + } + } else { + if ok { + allok = true + } + } + } + } + } + } + + if binaryOnly != nil && sawBinaryOnly { + *binaryOnly = true + } + + return allok +} + +func merge(to, from map[string]bool) { + if to == nil { + return + } + for k, v := range from { + to[k] = v + } +} + +func containsAll(m map[string]bool, vals []string) bool { + // yes this is N^2, but N is small. + for _, v := range vals { + if !m[v] { + return false + } + } + return true +} + +func contains(list []string, s string) bool { + for _, l := range list { + if l == s { + return true + } + } + return false +} + +// saveCgo saves the information from the #cgo lines in the import "C" comment. +// These lines set CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS and pkg-config directives +// that affect the way cgo's C code is built. +func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup) error { + text := cg.Text() + for _, line := range strings.Split(text, "\n") { + orig := line + + // Line is + // #cgo [GOOS/GOARCH...] LDFLAGS: stuff + // + line = strings.TrimSpace(line) + if len(line) < 5 || line[:4] != "#cgo" || (line[4] != ' ' && line[4] != '\t') { + continue + } + + // Split at colon. + line = strings.TrimSpace(line[4:]) + i := strings.Index(line, ":") + if i < 0 { + return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig) + } + line, argstr := line[:i], line[i+1:] + + // Parse GOOS/GOARCH stuff. + f := strings.Fields(line) + if len(f) < 1 { + return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig) + } + + cond, verb := f[:len(f)-1], f[len(f)-1] + if len(cond) > 0 { + ok := false + for _, c := range cond { + if ctxt.match(c, nil) { + ok = true + break + } + } + if !ok { + continue + } + } + + args, err := splitQuoted(argstr) + if err != nil { + return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig) + } + var ok bool + for i, arg := range args { + if arg, ok = expandSrcDir(arg, di.Dir); !ok { + return fmt.Errorf("%s: malformed #cgo argument: %s", filename, arg) + } + args[i] = arg + } + + switch verb { + case "CFLAGS", "CPPFLAGS", "CXXFLAGS", "FFLAGS", "LDFLAGS": + // Change relative paths to absolute. + ctxt.makePathsAbsolute(args, di.Dir) + } + + switch verb { + case "CFLAGS": + di.CgoCFLAGS = append(di.CgoCFLAGS, args...) + case "CPPFLAGS": + di.CgoCPPFLAGS = append(di.CgoCPPFLAGS, args...) + case "CXXFLAGS": + di.CgoCXXFLAGS = append(di.CgoCXXFLAGS, args...) + case "FFLAGS": + di.CgoFFLAGS = append(di.CgoFFLAGS, args...) + case "LDFLAGS": + di.CgoLDFLAGS = append(di.CgoLDFLAGS, args...) + case "pkg-config": + di.CgoPkgConfig = append(di.CgoPkgConfig, args...) + default: + return fmt.Errorf("%s: invalid #cgo verb: %s", filename, orig) + } + } + return nil +} + +// expandSrcDir expands any occurrence of ${SRCDIR}, making sure +// the result is safe for the shell. +func expandSrcDir(str string, srcdir string) (string, bool) { + // "\" delimited paths cause safeCgoName to fail + // so convert native paths with a different delimiter + // to "/" before starting (eg: on windows). + srcdir = filepath.ToSlash(srcdir) + + chunks := strings.Split(str, "${SRCDIR}") + if len(chunks) < 2 { + return str, safeCgoName(str) + } + ok := true + for _, chunk := range chunks { + ok = ok && (chunk == "" || safeCgoName(chunk)) + } + ok = ok && (srcdir == "" || safeCgoName(srcdir)) + res := strings.Join(chunks, srcdir) + return res, ok && res != "" +} + +// makePathsAbsolute looks for compiler options that take paths and +// makes them absolute. We do this because through the 1.8 release we +// ran the compiler in the package directory, so any relative -I or -L +// options would be relative to that directory. In 1.9 we changed to +// running the compiler in the build directory, to get consistent +// build results (issue #19964). To keep builds working, we change any +// relative -I or -L options to be absolute. +// +// Using filepath.IsAbs and filepath.Join here means the results will be +// different on different systems, but that's OK: -I and -L options are +// inherently system-dependent. +func (ctxt *Context) makePathsAbsolute(args []string, srcDir string) { + nextPath := false + for i, arg := range args { + if nextPath { + if !filepath.IsAbs(arg) { + args[i] = filepath.Join(srcDir, arg) + } + nextPath = false + } else if strings.HasPrefix(arg, "-I") || strings.HasPrefix(arg, "-L") { + if len(arg) == 2 { + nextPath = true + } else { + if !filepath.IsAbs(arg[2:]) { + args[i] = arg[:2] + filepath.Join(srcDir, arg[2:]) + } + } + } + } +} + +// NOTE: $ is not safe for the shell, but it is allowed here because of linker options like -Wl,$ORIGIN. +// We never pass these arguments to a shell (just to programs we construct argv for), so this should be okay. +// See golang.org/issue/6038. +// The @ is for OS X. See golang.org/issue/13720. +// The % is for Jenkins. See golang.org/issue/16959. +const safeString = "+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:$@% " + +func safeCgoName(s string) bool { + if s == "" { + return false + } + for i := 0; i < len(s); i++ { + if c := s[i]; c < utf8.RuneSelf && strings.IndexByte(safeString, c) < 0 { + return false + } + } + return true +} + +// splitQuoted splits the string s around each instance of one or more consecutive +// white space characters while taking into account quotes and escaping, and +// returns an array of substrings of s or an empty list if s contains only white space. +// Single quotes and double quotes are recognized to prevent splitting within the +// quoted region, and are removed from the resulting substrings. If a quote in s +// isn't closed err will be set and r will have the unclosed argument as the +// last element. The backslash is used for escaping. +// +// For example, the following string: +// +// a b:"c d" 'e''f' "g\"" +// +// Would be parsed as: +// +// []string{"a", "b:c d", "ef", `g"`} +// +func splitQuoted(s string) (r []string, err error) { + var args []string + arg := make([]rune, len(s)) + escaped := false + quoted := false + quote := '\x00' + i := 0 + for _, rune := range s { + switch { + case escaped: + escaped = false + case rune == '\\': + escaped = true + continue + case quote != '\x00': + if rune == quote { + quote = '\x00' + continue + } + case rune == '"' || rune == '\'': + quoted = true + quote = rune + continue + case unicode.IsSpace(rune): + if quoted || i > 0 { + quoted = false + args = append(args, string(arg[:i])) + i = 0 + } + continue + } + arg[i] = rune + i++ + } + if quoted || i > 0 { + args = append(args, string(arg[:i])) + } + if quote != 0 { + err = errors.New("unclosed quote") + } else if escaped { + err = errors.New("unfinished escaping") + } + return args, err +} + +// match reports whether the name is one of: +// +// $GOOS +// $GOARCH +// cgo (if cgo is enabled) +// !cgo (if cgo is disabled) +// ctxt.Compiler +// !ctxt.Compiler +// tag (if tag is listed in ctxt.BuildTags or ctxt.ReleaseTags) +// !tag (if tag is not listed in ctxt.BuildTags or ctxt.ReleaseTags) +// a comma-separated list of any of these +// +func (ctxt *Context) match(name string, allTags map[string]bool) bool { + if name == "" { + if allTags != nil { + allTags[name] = true + } + return false + } + if i := strings.Index(name, ","); i >= 0 { + // comma-separated list + ok1 := ctxt.match(name[:i], allTags) + ok2 := ctxt.match(name[i+1:], allTags) + return ok1 && ok2 + } + if strings.HasPrefix(name, "!!") { // bad syntax, reject always + return false + } + if strings.HasPrefix(name, "!") { // negation + return len(name) > 1 && !ctxt.match(name[1:], allTags) + } + + if allTags != nil { + allTags[name] = true + } + + // Tags must be letters, digits, underscores or dots. + // Unlike in Go identifiers, all digits are fine (e.g., "386"). + for _, c := range name { + if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' { + return false + } + } + + // special tags + if ctxt.CgoEnabled && name == "cgo" { + return true + } + if name == ctxt.GOOS || name == ctxt.GOARCH || name == ctxt.Compiler { + return true + } + if ctxt.GOOS == "android" && name == "linux" { + return true + } + + // other tags + for _, tag := range ctxt.BuildTags { + if tag == name { + return true + } + } + for _, tag := range ctxt.ReleaseTags { + if tag == name { + return true + } + } + + return false +} + +// goodOSArchFile returns false if the name contains a $GOOS or $GOARCH +// suffix which does not match the current system. +// The recognized name formats are: +// +// name_$(GOOS).* +// name_$(GOARCH).* +// name_$(GOOS)_$(GOARCH).* +// name_$(GOOS)_test.* +// name_$(GOARCH)_test.* +// name_$(GOOS)_$(GOARCH)_test.* +// +// An exception: if GOOS=android, then files with GOOS=linux are also matched. +func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool { + if dot := strings.Index(name, "."); dot != -1 { + name = name[:dot] + } + + // Before Go 1.4, a file called "linux.go" would be equivalent to having a + // build tag "linux" in that file. For Go 1.4 and beyond, we require this + // auto-tagging to apply only to files with a non-empty prefix, so + // "foo_linux.go" is tagged but "linux.go" is not. This allows new operating + // systems, such as android, to arrive without breaking existing code with + // innocuous source code in "android.go". The easiest fix: cut everything + // in the name before the initial _. + i := strings.Index(name, "_") + if i < 0 { + return true + } + name = name[i:] // ignore everything before first _ + + l := strings.Split(name, "_") + if n := len(l); n > 0 && l[n-1] == "test" { + l = l[:n-1] + } + n := len(l) + if n >= 2 && knownOS[l[n-2]] && knownArch[l[n-1]] { + if allTags != nil { + allTags[l[n-2]] = true + allTags[l[n-1]] = true + } + if l[n-1] != ctxt.GOARCH { + return false + } + if ctxt.GOOS == "android" && l[n-2] == "linux" { + return true + } + return l[n-2] == ctxt.GOOS + } + if n >= 1 && knownOS[l[n-1]] { + if allTags != nil { + allTags[l[n-1]] = true + } + if ctxt.GOOS == "android" && l[n-1] == "linux" { + return true + } + return l[n-1] == ctxt.GOOS + } + if n >= 1 && knownArch[l[n-1]] { + if allTags != nil { + allTags[l[n-1]] = true + } + return l[n-1] == ctxt.GOARCH + } + return true +} + +var knownOS = make(map[string]bool) +var knownArch = make(map[string]bool) + +func init() { + for _, v := range strings.Fields(goosList) { + knownOS[v] = true + } + for _, v := range strings.Fields(goarchList) { + knownArch[v] = true + } +} + +// ToolDir is the directory containing build tools. +var ToolDir = filepath.Join(runtime.GOROOT(), "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH) + +// IsLocalImport reports whether the import path is +// a local import path, like ".", "..", "./foo", or "../foo". +func IsLocalImport(path string) bool { + return path == "." || path == ".." || + strings.HasPrefix(path, "./") || strings.HasPrefix(path, "../") +} + +// ArchChar returns "?" and an error. +// In earlier versions of Go, the returned string was used to derive +// the compiler and linker tool names, the default object file suffix, +// and the default linker output name. As of Go 1.5, those strings +// no longer vary by architecture; they are compile, link, .o, and a.out, respectively. +func ArchChar(goarch string) (string, error) { + return "?", errors.New("architecture letter no longer used") +} diff --git a/vendor/github.com/magefile/mage/build/doc.go b/vendor/github.com/magefile/mage/build/doc.go new file mode 100644 index 000000000000..422e1a5ffd20 --- /dev/null +++ b/vendor/github.com/magefile/mage/build/doc.go @@ -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 diff --git a/vendor/github.com/magefile/mage/build/read.go b/vendor/github.com/magefile/mage/build/read.go new file mode 100644 index 000000000000..29b8cdc78671 --- /dev/null +++ b/vendor/github.com/magefile/mage/build/read.go @@ -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 +} diff --git a/vendor/github.com/magefile/mage/build/syslist.go b/vendor/github.com/magefile/mage/build/syslist.go new file mode 100644 index 000000000000..73fdbe6c856e --- /dev/null +++ b/vendor/github.com/magefile/mage/build/syslist.go @@ -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 " diff --git a/vendor/github.com/magefile/mage/build/zcgo.go b/vendor/github.com/magefile/mage/build/zcgo.go new file mode 100644 index 000000000000..86e2a2d973bd --- /dev/null +++ b/vendor/github.com/magefile/mage/build/zcgo.go @@ -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, +} diff --git a/vendor/github.com/magefile/mage/mage/command_string.go b/vendor/github.com/magefile/mage/mage/command_string.go new file mode 100644 index 000000000000..fcdaf9f94944 --- /dev/null +++ b/vendor/github.com/magefile/mage/mage/command_string.go @@ -0,0 +1,16 @@ +// Code generated by "stringer -type=Command"; DO NOT EDIT. + +package mage + +import "strconv" + +const _Command_name = "NoneVersionInitCleanCompileStatic" + +var _Command_index = [...]uint8{0, 4, 11, 15, 20, 33} + +func (i Command) String() string { + if i < 0 || i >= Command(len(_Command_index)-1) { + return "Command(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _Command_name[_Command_index[i]:_Command_index[i+1]] +} diff --git a/vendor/github.com/magefile/mage/mage/magefile_tmpl.go b/vendor/github.com/magefile/mage/mage/magefile_tmpl.go new file mode 100644 index 000000000000..01b878600641 --- /dev/null +++ b/vendor/github.com/magefile/mage/mage/magefile_tmpl.go @@ -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") +} +` diff --git a/vendor/github.com/magefile/mage/mage/main.go b/vendor/github.com/magefile/mage/mage/main.go new file mode 100644 index 000000000000..46176503426f --- /dev/null +++ b/vendor/github.com/magefile/mage/mage/main.go @@ -0,0 +1,476 @@ +package mage + +import ( + "crypto/sha1" + "errors" + "flag" + "fmt" + "io" + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" + "runtime" + "sort" + "strconv" + "strings" + "text/template" + "time" + "unicode" + + "github.com/magefile/mage/build" + "github.com/magefile/mage/mg" + "github.com/magefile/mage/parse" + "github.com/magefile/mage/sh" +) + +// magicRebuildKey is used when hashing the output binary to ensure that we get +// a new binary even if nothing in the input files or generated mainfile has +// changed. This can be used when we change how we parse files, or otherwise +// change the inputs to the compiling process. +const magicRebuildKey = "v0.3" + +var output = template.Must(template.New("").Funcs(map[string]interface{}{ + "lower": strings.ToLower, + "lowerfirst": func(s string) string { + r := []rune(s) + return string(unicode.ToLower(r[0])) + string(r[1:]) + }, +}).Parse(tpl)) +var initOutput = template.Must(template.New("").Parse(mageTpl)) + +const mainfile = "mage_output_file.go" +const initFile = "magefile.go" + +// set by ldflags when you "mage build" +var ( + commitHash string + timestamp string + gitTag = "v2" +) + +//go:generate stringer -type=Command + +// Command tracks invocations of mage that run without targets or other flags. +type Command int + +const ( + None Command = iota + Version // report the current version of mage + Init // create a starting template for mage + Clean // clean out old compiled mage binaries from the cache + CompileStatic // compile a static binary of the current directory +) + +// 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 + CompileOut string // tells mage to compile a static binary to this path, but not execute + Stdout io.Writer // writer to write stdout messages to + Stderr io.Writer // writer to write stderr messages to + Stdin io.Reader // reader to read stdin from + Args []string // args to pass to the compiled binary +} + +// ParseAndRun parses the command line, and then compiles and runs the mage +// files in the given directory with the given args (do not include the command +// name in the args). +func ParseAndRun(dir string, stdout, stderr io.Writer, stdin io.Reader, args []string) int { + log := log.New(stderr, "", 0) + inv, cmd, err := Parse(stdout, args) + inv.Dir = dir + inv.Stderr = stderr + inv.Stdin = stdin + if err == flag.ErrHelp { + return 0 + } + if err != nil { + log.Println("Error:", err) + return 2 + } + + switch cmd { + case Version: + if timestamp == "" { + timestamp = "" + } + if commitHash == "" { + commitHash = "" + } + log.Println("Mage Build Tool", gitTag) + log.Println("Build Date:", timestamp) + log.Println("Commit:", commitHash) + return 0 + case Init: + if err := generateInit(dir); err != nil { + log.Println("Error:", err) + return 1 + } + log.Println(initFile, "created") + return 0 + case Clean: + dir := mg.CacheDir() + if err := removeContents(dir); err != nil { + log.Println("Error:", err) + return 1 + } + log.Println(dir, "cleaned") + return 0 + case CompileStatic: + return Invoke(inv) + case None: + return Invoke(inv) + default: + panic(fmt.Errorf("Unknown command type: %v", cmd)) + } +} + +// Parse parses the given args and returns structured data. If parse returns +// flag.ErrHelp, the calling process should exit with code 0. +func Parse(stdout io.Writer, args []string) (inv Invocation, cmd Command, err error) { + inv.Stdout = stdout + fs := flag.FlagSet{} + fs.SetOutput(stdout) + fs.BoolVar(&inv.Force, "f", false, "force recreation of compiled magefile") + fs.BoolVar(&inv.Verbose, "v", false, "show verbose output when running mage targets") + fs.BoolVar(&inv.List, "l", false, "list mage targets in this directory") + fs.BoolVar(&inv.Help, "h", false, "show this help") + fs.DurationVar(&inv.Timeout, "t", 0, "timeout in duration parsable format (e.g. 5m30s)") + fs.BoolVar(&inv.Keep, "keep", false, "keep intermediate mage files around after running") + var showVersion bool + fs.BoolVar(&showVersion, "version", false, "show version info for the mage binary") + var mageInit bool + fs.BoolVar(&mageInit, "init", false, "create a starting template if no mage files exist") + var clean bool + fs.BoolVar(&clean, "clean", false, "clean out old generated binaries from CACHE_DIR") + var compileOutPath string + fs.StringVar(&compileOutPath, "compile", "", "path to which to output a static 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, cmd, err + } + if err == nil && inv.Help && len(fs.Args()) == 0 { + fs.Usage() + // tell upstream, to just exit + return inv, cmd, flag.ErrHelp + } + + numFlags := 0 + switch { + case mageInit: + numFlags++ + cmd = Init + case compileOutPath != "": + numFlags++ + cmd = CompileStatic + inv.CompileOut = compileOutPath + inv.Force = true + case showVersion: + numFlags++ + cmd = Version + case clean: + numFlags++ + cmd = Clean + if fs.NArg() > 0 || fs.NFlag() > 1 { + // Temporary dupe of below check until we refactor the other commands to use this check + return inv, cmd, errors.New("-h, -init, -clean, -compile and -version cannot be used simultaneously") + + } + } + if inv.Help { + numFlags++ + } + + // If verbose is still false, we're going to peek at the environment variable to see if + // MAGE_VERBOSE has been set. If so, we're going to use it for the value of MAGE_VERBOSE. + if inv.Verbose == false { + envVerbose, err := strconv.ParseBool(os.Getenv("MAGE_VERBOSE")) + if err == nil { + inv.Verbose = envVerbose + } + } + + if numFlags > 1 { + return inv, cmd, errors.New("-h, -init, -clean, -compile and -version cannot be used simultaneously") + } + + inv.Args = fs.Args() + if inv.Help && len(inv.Args) > 1 { + return inv, cmd, errors.New("-h can only show help for a single target") + } + + return inv, cmd, err +} + +// Invoke runs Mage with the given arguments. +func Invoke(inv Invocation) int { + log := log.New(inv.Stderr, "", 0) + + files, err := Magefiles(inv.Dir) + if err != nil { + log.Println("Error:", err) + return 1 + } + + if len(files) == 0 { + log.Println("No .go files marked with the mage build tag in this directory.") + return 1 + } + + exePath, err := ExeName(files) + if err != nil { + log.Println("Error:", err) + return 1 + } + if inv.CompileOut != "" { + exePath = inv.CompileOut + } + + 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) + } + + if inv.CompileOut != "" { + return 0 + } + + return RunCompiled(inv, exePath) +} + +// CheckDupes checks a package for duplicate target names. +func CheckDupes(info *parse.PkgInfo) (hasDupes bool, names map[string][]string) { + names = map[string][]string{} + lowers := map[string]bool{} + for _, f := range info.Funcs { + low := strings.ToLower(f.Name) + if lowers[low] { + hasDupes = true + } + lowers[low] = true + names[low] = append(names[low], f.Name) + } + return hasDupes, names +} + +type data struct { + Funcs []parse.Function + DefaultError bool + Default string + DefaultFunc parse.Function + Aliases map[string]string +} + +// Magefiles returns the list of magefiles in dir. +func Magefiles(dir string) ([]string, error) { + ctx := build.Default + ctx.RequiredTags = []string{"mage"} + ctx.BuildTags = []string{"mage"} + p, err := ctx.ImportDir(dir, 0) + if err != nil { + if _, ok := err.(*build.NoGoError); ok { + return []string{}, nil + } + return nil, err + } + for i := range p.GoFiles { + p.GoFiles[i] = filepath.Join(dir, p.GoFiles[i]) + } + return p.GoFiles, nil +} + +// Compile uses the go tool to compile the files into an executable at path. +func Compile(path string, stdout, stderr io.Writer, gofiles []string) error { + c := exec.Command("go", append([]string{"build", "-o", path}, gofiles...)...) + c.Env = os.Environ() + c.Stderr = stderr + c.Stdout = stdout + err := c.Run() + if err != nil { + return errors.New("error compiling magefiles") + } + if _, err := os.Stat(path); err != nil { + return errors.New("failed to find compiled magefile") + } + return nil +} + +// GenerateMainfile creates the mainfile at path with the info from +func GenerateMainfile(path string, info *parse.PkgInfo) error { + f, err := os.Create(path) + if err != nil { + return fmt.Errorf("can't create mainfile: %v", err) + } + defer f.Close() + + data := data{ + Funcs: info.Funcs, + Default: info.DefaultName, + DefaultFunc: info.DefaultFunc, + Aliases: info.Aliases, + } + + data.DefaultError = info.DefaultIsError + + if err := output.Execute(f, data); err != nil { + return fmt.Errorf("can't execute mainfile template: %v", err) + } + return nil +} + +// ExeName reports the executable filename that this version of Mage would +// create for the given magefiles. +func ExeName(files []string) (string, error) { + var hashes []string + for _, s := range files { + h, err := hashFile(s) + if err != nil { + return "", err + } + hashes = append(hashes, h) + } + // hash the mainfile template to ensure if it gets updated, we make a new + // binary. + hashes = append(hashes, fmt.Sprintf("%x", sha1.Sum([]byte(tpl)))) + sort.Strings(hashes) + hash := sha1.Sum([]byte(strings.Join(hashes, "") + magicRebuildKey)) + filename := fmt.Sprintf("%x", hash) + + out := filepath.Join(mg.CacheDir(), filename) + if runtime.GOOS == "windows" { + out += ".exe" + } + return out, nil +} + +func hashFile(fn string) (string, error) { + f, err := os.Open(fn) + if err != nil { + return "", fmt.Errorf("can't open input file: %v", err) + } + defer f.Close() + + h := sha1.New() + if _, err := io.Copy(h, f); err != nil { + return "", fmt.Errorf("can't write data to hash: %v", err) + } + return fmt.Sprintf("%x", h.Sum(nil)), nil +} + +func generateInit(dir string) error { + f, err := os.Create(filepath.Join(dir, initFile)) + if err != nil { + return fmt.Errorf("could not create mage template: %v", err) + } + defer f.Close() + + if err := initOutput.Execute(f, nil); err != nil { + return fmt.Errorf("can't execute magefile template: %v", err) + } + + return nil +} + +// RunCompiled runs an already-compiled mage command with the given args, +func RunCompiled(inv Invocation, exePath string) int { + c := exec.Command(exePath, inv.Args...) + c.Stderr = inv.Stderr + c.Stdout = inv.Stdout + c.Stdin = inv.Stdin + c.Env = os.Environ() + if inv.Verbose { + c.Env = append(c.Env, "MAGEFILE_VERBOSE=1") + } + if inv.List { + c.Env = append(c.Env, "MAGEFILE_LIST=1") + } + if inv.Help { + c.Env = append(c.Env, "MAGEFILE_HELP=1") + } + if inv.Timeout > 0 { + c.Env = append(c.Env, fmt.Sprintf("MAGEFILE_TIMEOUT=%s", inv.Timeout.String())) + } + return sh.ExitStatus(c.Run()) +} + +func removeContents(dir string) error { + files, err := ioutil.ReadDir(dir) + if err != nil { + return err + } + for _, f := range files { + if f.IsDir() { + continue + } + err = os.Remove(filepath.Join(dir, f.Name())) + if err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/magefile/mage/mage/template.go b/vendor/github.com/magefile/mage/mage/template.go new file mode 100644 index 000000000000..9b75be792cc6 --- /dev/null +++ b/vendor/github.com/magefile/mage/mage/template.go @@ -0,0 +1,202 @@ +package mage + +// var only for tests +var tpl = `// +build ignore + +package main + +import ( + "context" + "fmt" + "io/ioutil" + "log" + "os" + "strings" + "text/tabwriter" + "time" +) + +func main() { + // These functions are local variables to avoid name conflicts with + // magefiles. + list := func() error { + {{- $default := .Default}} + w := tabwriter.NewWriter(os.Stdout, 0, 4, 4, ' ', 0) + fmt.Println("Targets:") + {{- range .Funcs}} + fmt.Fprintln(w, " {{lowerfirst .Name}}{{if eq .Name $default}}*{{end}}\t" + {{printf "%q" .Synopsis}}) + {{- end}} + err := w.Flush() + {{- if .Default}} + if err == nil { + fmt.Println("\n* default target") + } + {{- end}} + return err + } + + var ctx context.Context + var ctxCancel func() + + getContext := func() (context.Context, func()) { + if ctx != nil { + return ctx, ctxCancel + } + + if os.Getenv("MAGEFILE_TIMEOUT") != "" { + timeout, err := time.ParseDuration(os.Getenv("MAGEFILE_TIMEOUT")) + if err != nil { + fmt.Printf("timeout error: %v\n", err) + os.Exit(1) + } + + ctx, ctxCancel = context.WithTimeout(context.Background(), timeout) + } else { + ctx = context.Background() + ctxCancel = func() {} + } + return ctx, ctxCancel + } + + runTarget := func(fn func(context.Context) error) interface{} { + var err interface{} + ctx, cancel := getContext() + d := make(chan interface{}) + go func() { + defer func() { + err := recover() + d <- err + }() + err := fn(ctx) + d <- err + }() + select { + case <-ctx.Done(): + cancel() + e := ctx.Err() + fmt.Printf("ctx err: %v\n", e) + return e + case err = <-d: + cancel() + return err + } + } + // This is necessary in case there aren't any targets, to avoid an unused + // variable error. + _ = runTarget + + handleError := func(logger *log.Logger, err interface{}) { + if err != nil { + logger.Printf("Error: %v\n", err) + type code interface { + ExitStatus() int + } + if c, ok := err.(code); ok { + os.Exit(c.ExitStatus()) + } + os.Exit(1) + } + } + _ = handleError + + log.SetFlags(0) + if os.Getenv("MAGEFILE_VERBOSE") == "" { + log.SetOutput(ioutil.Discard) + } + logger := log.New(os.Stderr, "", 0) + if os.Getenv("MAGEFILE_LIST") != "" { + if err := list(); err != nil { + log.Println(err) + os.Exit(1) + } + return + } + + targets := map[string]bool { + {{range $alias, $funci := .Aliases}}"{{lower $alias}}": true, + {{end}} + {{range .Funcs}}"{{lower .Name}}": true, + {{end}} + } + + var unknown []string + for _, arg := range os.Args[1:] { + if !targets[strings.ToLower(arg)] { + unknown = append(unknown, arg) + } + } + if len(unknown) == 1 { + logger.Println("Unknown target specified:", unknown[0]) + os.Exit(2) + } + if len(unknown) > 1 { + logger.Println("Unknown targets specified:", strings.Join(unknown, ", ")) + os.Exit(2) + } + + if os.Getenv("MAGEFILE_HELP") != "" { + if len(os.Args) < 2 { + logger.Println("no target specified") + os.Exit(1) + } + switch strings.ToLower(os.Args[1]) { + {{range .Funcs}}case "{{lower .Name}}": + fmt.Print("mage {{lower .Name}}:\n\n") + {{if ne .Comment ""}}fmt.Println({{printf "%q" .Comment}}){{end}} + var aliases []string + {{- $name := .Name -}} + {{range $alias, $func := $.Aliases}} + {{if eq $name $func}}aliases = append(aliases, "{{$alias}}"){{end -}} + {{- end}} + if len(aliases) > 0 { + fmt.Printf("Aliases: %s\n\n", strings.Join(aliases, ", ")) + } + return + {{end}} + default: + logger.Printf("Unknown target: %q\n", os.Args[1]) + os.Exit(1) + } + } + + if len(os.Args) < 2 { + {{- if .Default}} + {{.DefaultFunc.TemplateString}} + handleError(logger, err) + return + {{- else}} + if err := list(); err != nil { + logger.Println("Error:", err) + os.Exit(1) + } + return + {{- end}} + } + for _, target := range os.Args[1:] { + switch strings.ToLower(target) { + {{range $alias, $func := .Aliases}} + case "{{lower $alias}}": + target = "{{$func}}" + {{- end}} + } + switch strings.ToLower(target) { + {{range .Funcs }} + case "{{lower .Name}}": + if os.Getenv("MAGEFILE_VERBOSE") != "" { + logger.Println("Running target:", "{{.Name}}") + } + {{.TemplateString}} + handleError(logger, err) + {{- end}} + default: + // should be impossible since we check this above. + logger.Printf("Unknown target: %q\n", os.Args[1]) + os.Exit(1) + } + } +} + + + + +` diff --git a/vendor/github.com/magefile/mage/magefile.go b/vendor/github.com/magefile/mage/magefile.go new file mode 100644 index 000000000000..2bb3ace6fee2 --- /dev/null +++ b/vendor/github.com/magefile/mage/magefile.go @@ -0,0 +1,94 @@ +//+build mage + +package main + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "runtime" + "strings" + "time" + + "github.com/magefile/mage/sh" +) + +// Runs "go install" for mage. This generates the version info the binary. +func Install() error { + ldf, err := flags() + if err != nil { + return err + } + + name := "mage" + if runtime.GOOS == "windows" { + name += ".exe" + } + gopath, err := sh.Output("go", "env", "GOPATH") + if err != nil { + return fmt.Errorf("can't determine GOPATH: %v", err) + } + paths := strings.Split(gopath, string([]rune{os.PathListSeparator})) + bin := filepath.Join(paths[0], "bin") + // specifically don't mkdirall, if you have an invalid gopath in the first + // place, that's not on us to fix. + if err := os.Mkdir(bin, 0700); err != nil && !os.IsExist(err) { + return fmt.Errorf("failed to create %q: %v", bin, err) + } + path := filepath.Join(bin, name) + + // we use go build here because if someone built with go get, then `go + // install` turns into a no-op, and `go install -a` fails on people's + // machines that have go installed in a non-writeable directory (such as + // normal OS installs in /usr/bin) + return sh.RunV("go", "build", "-o", path, "-ldflags="+ldf, "github.com/magefile/mage") +} + +// Generates a new release. Expects the TAG environment variable to be set, +// which will create a new tag with that name. +func Release() (err error) { + if os.Getenv("TAG") == "" { + return errors.New("MSG and TAG environment variables are required") + } + if err := sh.RunV("git", "tag", "-a", "$TAG"); err != nil { + return err + } + if err := sh.RunV("git", "push", "origin", "$TAG"); err != nil { + return err + } + defer func() { + if err != nil { + sh.RunV("git", "tag", "--delete", "$TAG") + sh.RunV("git", "push", "--delete", "origin", "$TAG") + } + }() + return sh.RunV("goreleaser") +} + +// Remove the temporarily generated files from Release. +func Clean() error { + return sh.Rm("dist") +} + +func flags() (string, error) { + timestamp := time.Now().Format(time.RFC3339) + hash := hash() + tag := tag() + if tag == "" { + tag = "dev" + } + return fmt.Sprintf(`-X "github.com/magefile/mage/mage.timestamp=%s" -X "github.com/magefile/mage/mage.commitHash=%s" -X "github.com/magefile/mage/mage.gitTag=%s"`, timestamp, hash, tag), nil +} + +// tag returns the git tag for the current branch or "" if none. +func tag() string { + s, _ := sh.Output("git", "describe", "--tags") + return s +} + +// hash returns the git hash for the current repo or "" if none. +func hash() string { + hash, _ := sh.Output("git", "rev-parse", "--short", "HEAD") + return hash +} diff --git a/vendor/github.com/magefile/mage/main.go b/vendor/github.com/magefile/mage/main.go new file mode 100644 index 000000000000..d596ac7f0673 --- /dev/null +++ b/vendor/github.com/magefile/mage/main.go @@ -0,0 +1,11 @@ +package main + +import ( + "os" + + "github.com/magefile/mage/mage" +) + +func main() { + os.Exit(mage.Main()) +} diff --git a/vendor/github.com/magefile/mage/mg/deps.go b/vendor/github.com/magefile/mage/mg/deps.go new file mode 100644 index 000000000000..30d6edc4191d --- /dev/null +++ b/vendor/github.com/magefile/mage/mg/deps.go @@ -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 +} diff --git a/vendor/github.com/magefile/mage/mg/errors.go b/vendor/github.com/magefile/mage/mg/errors.go new file mode 100644 index 000000000000..06a869086c18 --- /dev/null +++ b/vendor/github.com/magefile/mage/mg/errors.go @@ -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() +} diff --git a/vendor/github.com/magefile/mage/mg/runtime.go b/vendor/github.com/magefile/mage/mg/runtime.go new file mode 100644 index 000000000000..8b99613d699c --- /dev/null +++ b/vendor/github.com/magefile/mage/mg/runtime.go @@ -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") + } +} diff --git a/vendor/github.com/magefile/mage/parse/import_go1.9.go b/vendor/github.com/magefile/mage/parse/import_go1.9.go new file mode 100644 index 000000000000..9b5c71212ba6 --- /dev/null +++ b/vendor/github.com/magefile/mage/parse/import_go1.9.go @@ -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) +} diff --git a/vendor/github.com/magefile/mage/parse/import_not_go1.9.go b/vendor/github.com/magefile/mage/parse/import_not_go1.9.go new file mode 100644 index 000000000000..ed4e951ed3c7 --- /dev/null +++ b/vendor/github.com/magefile/mage/parse/import_not_go1.9.go @@ -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)) +} diff --git a/vendor/github.com/magefile/mage/parse/parse.go b/vendor/github.com/magefile/mage/parse/parse.go new file mode 100644 index 000000000000..052262901712 --- /dev/null +++ b/vendor/github.com/magefile/mage/parse/parse.go @@ -0,0 +1,341 @@ +package parse + +import ( + "fmt" + "go/ast" + "go/build" + "go/doc" + "go/parser" + "go/token" + "go/types" + "log" + "os" + "os/exec" + "strings" + + mgTypes "github.com/magefile/mage/types" +) + +type PkgInfo struct { + Funcs []Function + DefaultIsError bool + DefaultIsContext bool + DefaultName string + DefaultFunc Function + Aliases map[string]string +} + +// Function represented a job function from a mage file +type Function struct { + Name string + IsError bool + IsContext bool + Synopsis string + Comment string +} + +// TemplateString returns code for the template switch to run the target. +// It wraps each target call to match the func(context.Context) error that +// runTarget requires. +func (f Function) TemplateString() string { + if f.IsContext && f.IsError { + out := `wrapFn := func(ctx context.Context) error { + return %s(ctx) + } + err := runTarget(wrapFn)` + return fmt.Sprintf(out, f.Name) + } + if f.IsContext && !f.IsError { + out := `wrapFn := func(ctx context.Context) error { + %s(ctx) + return nil + } + err := runTarget(wrapFn)` + return fmt.Sprintf(out, f.Name) + } + if !f.IsContext && f.IsError { + out := `wrapFn := func(ctx context.Context) error { + return %s() + } + err := runTarget(wrapFn)` + return fmt.Sprintf(out, f.Name) + } + if !f.IsContext && !f.IsError { + out := `wrapFn := func(ctx context.Context) error { + %s() + return nil + } + err := runTarget(wrapFn)` + return fmt.Sprintf(out, f.Name) + } + return `fmt.Printf("Error formatting job code\n") + os.Exit(1)` +} + +// Package parses a package +func Package(path string, files []string) (*PkgInfo, error) { + fset := token.NewFileSet() + + pkg, err := getPackage(path, files, fset) + if err != nil { + return nil, err + } + + info, err := makeInfo(path, fset, pkg.Files) + if err != nil { + return nil, err + } + + pi := &PkgInfo{} + + p := doc.New(pkg, "./", 0) + for _, f := range p.Funcs { + if f.Recv != "" { + // skip methods + continue + } + if !ast.IsExported(f.Name) { + // skip non-exported functions + continue + } + if typ := voidOrError(f.Decl.Type, info); typ != mgTypes.InvalidType { + pi.Funcs = append(pi.Funcs, Function{ + Name: f.Name, + Comment: f.Doc, + Synopsis: sanitizeSynopsis(f), + IsError: typ == mgTypes.ErrorType || typ == mgTypes.ContextErrorType, + IsContext: typ == mgTypes.ContextVoidType || typ == mgTypes.ContextErrorType, + }) + } + } + + setDefault(p, pi, info) + setAliases(p, pi, info) + + return pi, nil +} + +// sanitizeSynopsis sanitizes function Doc to create a summary. +func sanitizeSynopsis(f *doc.Func) string { + synopsis := doc.Synopsis(f.Doc) + + // If the synopsis begins with the function name, remove it. This is done to + // not repeat the text. + // From: + // clean Clean removes the temporarily generated files + // To: + // clean removes the temporarily generated files + if syns := strings.Split(synopsis, " "); strings.EqualFold(f.Name, syns[0]) { + return strings.Join(syns[1:], " ") + } + + return synopsis +} + +func setDefault(p *doc.Package, pi *PkgInfo, info types.Info) { + for _, v := range p.Vars { + for x, name := range v.Names { + if name != "Default" { + continue + } + spec := v.Decl.Specs[x].(*ast.ValueSpec) + if len(spec.Values) != 1 { + log.Println("warning: default declaration has multiple values") + } + id, ok := spec.Values[0].(*ast.Ident) + if !ok { + log.Println("warning: default declaration is not a function name") + } + for _, f := range pi.Funcs { + if f.Name == id.Name { + pi.DefaultName = f.Name + pi.DefaultIsError = f.IsError + pi.DefaultIsContext = f.IsContext + pi.DefaultFunc = f + return + } + } + log.Println("warning: default declaration does not reference a mage target") + } + } +} + +func setAliases(p *doc.Package, pi *PkgInfo, info types.Info) { + for _, v := range p.Vars { + for x, name := range v.Names { + if name != "Aliases" { + continue + } + spec, ok := v.Decl.Specs[x].(*ast.ValueSpec) + if !ok { + log.Println("warning: aliases declaration is not a value") + return + } + if len(spec.Values) != 1 { + log.Println("warning: aliases declaration has multiple values") + } + comp, ok := spec.Values[0].(*ast.CompositeLit) + if !ok { + log.Println("warning: aliases declaration is not a map") + return + } + pi.Aliases = make(map[string]string) + for _, elem := range comp.Elts { + kv, ok := elem.(*ast.KeyValueExpr) + if !ok { + log.Println("warning: alias declaration is not a map element") + return + } + k, ok := kv.Key.(*ast.BasicLit) + if !ok || k.Kind != token.STRING { + log.Println("warning: alias is not a string") + return + } + v, ok := kv.Value.(*ast.Ident) + if !ok { + log.Println("warning: alias target is not a function") + return + } + alias := strings.Trim(k.Value, "\"") + valid := false + for _, f := range pi.Funcs { + valid = valid || f.Name == v.Name + } + if !valid { + log.Printf("warning: alias declaration (%s) does not reference a mage target", alias) + } + pi.Aliases[alias] = v.Name + } + return + } + } +} + +// getPackage returns the non-test package at the given path. +func getPackage(path string, files []string, fset *token.FileSet) (*ast.Package, error) { + fm := make(map[string]bool, len(files)) + for _, f := range files { + fm[f] = true + } + + filter := func(f os.FileInfo) bool { + return fm[f.Name()] + } + + pkgs, err := parser.ParseDir(fset, path, filter, parser.ParseComments) + if err != nil { + return nil, fmt.Errorf("failed to parse directory: %v", err) + } + + for name, pkg := range pkgs { + if !strings.HasSuffix(name, "_test") { + return pkg, nil + } + } + return nil, fmt.Errorf("no non-test packages found in %s", path) +} + +func makeInfo(dir string, fset *token.FileSet, files map[string]*ast.File) (types.Info, error) { + goroot := os.Getenv("GOROOT") + if goroot == "" { + c := exec.Command("go", "env", "GOROOT") + b, err := c.Output() + if err != nil { + return types.Info{}, fmt.Errorf("failed to get GOROOT from 'go env': %v", err) + } + goroot = strings.TrimSpace(string(b)) + if goroot == "" { + return types.Info{}, fmt.Errorf("could not determine GOROOT") + } + } + + build.Default.GOROOT = goroot + + cfg := types.Config{ + Importer: getImporter(fset), + } + + info := types.Info{ + Types: make(map[ast.Expr]types.TypeAndValue), + Defs: make(map[*ast.Ident]types.Object), + Uses: make(map[*ast.Ident]types.Object), + } + + fs := make([]*ast.File, 0, len(files)) + for _, v := range files { + fs = append(fs, v) + } + + _, err := cfg.Check(dir, fset, fs, &info) + if err != nil { + return info, fmt.Errorf("failed to check types in directory: %v", err) + } + return info, nil +} + +// errorOrVoid filters the list of functions to only those that return only an +// error or have no return value, and have no parameters. +func errorOrVoid(fns []*ast.FuncDecl, info types.Info) []*ast.FuncDecl { + fds := []*ast.FuncDecl{} + + for _, fn := range fns { + if voidOrError(fn.Type, info) != mgTypes.InvalidType { + fds = append(fds, fn) + } + } + return fds +} + +func hasContextParam(ft *ast.FuncType, info types.Info) bool { + if ft.Params.NumFields() == 1 { + ret := ft.Params.List[0] + t := info.TypeOf(ret.Type) + if t != nil && t.String() == "context.Context" { + return true + } + } + return false +} + +func hasVoidReturn(ft *ast.FuncType, info types.Info) bool { + res := ft.Results + if res.NumFields() == 0 { + return true + } + return false +} + +func hasErrorReturn(ft *ast.FuncType, info types.Info) bool { + res := ft.Results + if res.NumFields() == 1 { + ret := res.List[0] + if len(ret.Names) > 1 { + return false + } + t := info.TypeOf(ret.Type) + if t != nil && t.String() == "error" { + return true + } + } + return false +} + +func voidOrError(ft *ast.FuncType, info types.Info) mgTypes.FuncType { + if hasContextParam(ft, info) { + if hasVoidReturn(ft, info) { + return mgTypes.ContextVoidType + } + if hasErrorReturn(ft, info) { + return mgTypes.ContextErrorType + } + } + if ft.Params.NumFields() == 0 { + if hasVoidReturn(ft, info) { + return mgTypes.VoidType + } + if hasErrorReturn(ft, info) { + return mgTypes.ErrorType + } + } + return mgTypes.InvalidType +} diff --git a/vendor/github.com/magefile/mage/parse/srcimporter/sizes.go b/vendor/github.com/magefile/mage/parse/srcimporter/sizes.go new file mode 100644 index 000000000000..a9e1b329a03f --- /dev/null +++ b/vendor/github.com/magefile/mage/parse/srcimporter/sizes.go @@ -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 +} diff --git a/vendor/github.com/magefile/mage/parse/srcimporter/srcimporter.go b/vendor/github.com/magefile/mage/parse/srcimporter/srcimporter.go new file mode 100644 index 000000000000..a488a990c7b0 --- /dev/null +++ b/vendor/github.com/magefile/mage/parse/srcimporter/srcimporter.go @@ -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...) +} diff --git a/vendor/github.com/magefile/mage/sh/cmd.go b/vendor/github.com/magefile/mage/sh/cmd.go new file mode 100644 index 000000000000..23fc37228e77 --- /dev/null +++ b/vendor/github.com/magefile/mage/sh/cmd.go @@ -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 +} diff --git a/vendor/github.com/magefile/mage/sh/helpers.go b/vendor/github.com/magefile/mage/sh/helpers.go new file mode 100644 index 000000000000..86b075ef2c94 --- /dev/null +++ b/vendor/github.com/magefile/mage/sh/helpers.go @@ -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) +} diff --git a/vendor/github.com/magefile/mage/target/target.go b/vendor/github.com/magefile/mage/target/target.go new file mode 100644 index 000000000000..a2866e92fa14 --- /dev/null +++ b/vendor/github.com/magefile/mage/target/target.go @@ -0,0 +1,122 @@ +package target + +import ( + "os" + "path/filepath" + "time" +) + +// Path reports if any of the sources have been modified more recently +// than the destination. Path does not descend into directories, it literally +// just checks the modtime of each thing you pass to it. +func Path(dst string, sources ...string) (bool, error) { + stat, err := os.Stat(dst) + if err != nil { + return false, err + } + srcTime := stat.ModTime() + dt, err := loadTargets(sources) + if err != nil { + return false, err + } + t := dt.modTime() + if t.After(srcTime) { + return true, nil + } + return false, nil +} + +// Dir reports whether any of the sources have been modified +// more recently than the destination. If a source or destination is +// a directory, modtimes of files under those directories are compared +// instead. +func Dir(dst string, sources ...string) (bool, error) { + stat, err := os.Stat(dst) + if err != nil { + return false, err + } + srcTime := stat.ModTime() + if stat.IsDir() { + srcTime, err = calDirModTimeRecursive(stat) + if err != nil { + return false, err + } + } + dt, err := loadTargets(sources) + if err != nil { + return false, err + } + t, err := dt.modTimeDir() + if err != nil { + return false, err + } + if t.After(srcTime) { + return true, nil + } + return false, nil +} + +func calDirModTimeRecursive(dir os.FileInfo) (time.Time, error) { + t := dir.ModTime() + ferr := filepath.Walk(dir.Name(), func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.ModTime().After(t) { + t = info.ModTime() + } + return nil + }) + if ferr != nil { + return time.Time{}, ferr + } + return t, nil +} + +type depTargets struct { + src []os.FileInfo + hasdir bool + latest time.Time +} + +func loadTargets(targets []string) (*depTargets, error) { + d := &depTargets{} + for _, v := range targets { + stat, err := os.Stat(v) + if err != nil { + return nil, err + } + if stat.IsDir() { + d.hasdir = true + } + d.src = append(d.src, stat) + if stat.ModTime().After(d.latest) { + d.latest = stat.ModTime() + } + } + return d, nil +} + +func (d *depTargets) modTime() time.Time { + return d.latest +} + +func (d *depTargets) modTimeDir() (time.Time, error) { + if !d.hasdir { + return d.latest, nil + } + var err error + for _, i := range d.src { + t := i.ModTime() + if i.IsDir() { + t, err = calDirModTimeRecursive(i) + if err != nil { + return time.Time{}, err + } + } + if t.After(d.latest) { + d.latest = t + } + } + return d.latest, nil +} diff --git a/vendor/github.com/magefile/mage/types/funcs.go b/vendor/github.com/magefile/mage/types/funcs.go new file mode 100644 index 000000000000..9e2e1331b384 --- /dev/null +++ b/vendor/github.com/magefile/mage/types/funcs.go @@ -0,0 +1,58 @@ +package types + +import ( + "context" + "fmt" +) + +// FuncType indicates a prototype of build job function +type FuncType int + +// FuncTypes +const ( + InvalidType FuncType = iota + VoidType + ErrorType + ContextVoidType + ContextErrorType +) + +// FuncCheck tests if a function is one of FuncType +func FuncCheck(fn interface{}) error { + switch fn.(type) { + case func(): + return nil + case func() error: + return nil + case func(context.Context): + return nil + case func(context.Context) error: + return nil + } + return fmt.Errorf("Invalid type for dependent function: %T. Dependencies must be func(), func() error, func(context.Context) or func(context.Context) error", fn) +} + +// FuncTypeWrap wraps a valid FuncType to FuncContextError +func FuncTypeWrap(fn interface{}) func(context.Context) error { + if FuncCheck(fn) == nil { + switch f := fn.(type) { + case func(): + return func(context.Context) error { + f() + return nil + } + case func() error: + return func(context.Context) error { + return f() + } + case func(context.Context): + return func(ctx context.Context) error { + f(ctx) + return nil + } + case func(context.Context) error: + return f + } + } + return nil +} diff --git a/vendor/vendor.json b/vendor/vendor.json index 1e92662ee7a8..7a07365d1295 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -1114,6 +1114,60 @@ "revision": "1bab8b35b6bb565f92cbc97939610af9369f942a", "revisionTime": "2017-02-10T14:05:23Z" }, + { + "checksumSHA1": "k3e1TD8wrhxfUUG3pQBb10ppNGA=", + "path": "github.com/magefile/mage", + "revision": "5e51f9ad1ed0886c5d06a8c46a09703cfc4d9034", + "revisionTime": "2018-04-12T15:54:34Z" + }, + { + "checksumSHA1": "KODorM0Am1g55qObNz3jVOdRVFs=", + "path": "github.com/magefile/mage/build", + "revision": "5e51f9ad1ed0886c5d06a8c46a09703cfc4d9034", + "revisionTime": "2018-04-12T15:54:34Z" + }, + { + "checksumSHA1": "9yeXUlqhNcsR7MlYMouJTO3AXv0=", + "path": "github.com/magefile/mage/mage", + "revision": "5e51f9ad1ed0886c5d06a8c46a09703cfc4d9034", + "revisionTime": "2018-04-12T15:54:34Z" + }, + { + "checksumSHA1": "TkAemcxaY44gsEjO1BiBxwlEI4A=", + "path": "github.com/magefile/mage/mg", + "revision": "5e51f9ad1ed0886c5d06a8c46a09703cfc4d9034", + "revisionTime": "2018-04-12T15:54:34Z" + }, + { + "checksumSHA1": "b1qY9BFtpJnIZEa8yvpJCRbOhRM=", + "path": "github.com/magefile/mage/parse", + "revision": "5e51f9ad1ed0886c5d06a8c46a09703cfc4d9034", + "revisionTime": "2018-04-12T15:54:34Z" + }, + { + "checksumSHA1": "fEuDveZzYX6oqYOT9jqyZROun/Q=", + "path": "github.com/magefile/mage/parse/srcimporter", + "revision": "5e51f9ad1ed0886c5d06a8c46a09703cfc4d9034", + "revisionTime": "2018-04-12T15:54:34Z" + }, + { + "checksumSHA1": "0/j3qlGc8fsWG42uIDZ5p8tVzPM=", + "path": "github.com/magefile/mage/sh", + "revision": "5e51f9ad1ed0886c5d06a8c46a09703cfc4d9034", + "revisionTime": "2018-04-12T15:54:34Z" + }, + { + "checksumSHA1": "oAjx69UIs6F6hPh+2GQSBMaHAfc=", + "path": "github.com/magefile/mage/target", + "revision": "5e51f9ad1ed0886c5d06a8c46a09703cfc4d9034", + "revisionTime": "2018-04-12T15:54:34Z" + }, + { + "checksumSHA1": "He+VtZO7BsPDCZhZtJ1IkNp629o=", + "path": "github.com/magefile/mage/types", + "revision": "5e51f9ad1ed0886c5d06a8c46a09703cfc4d9034", + "revisionTime": "2018-04-12T15:54:34Z" + }, { "checksumSHA1": "qNkx9+OTwZI6aFv7K9zuFCGODUw=", "path": "github.com/mattn/go-colorable", From 93b679d7c61c41be27366e2d05ecf702d033733e Mon Sep 17 00:00:00 2001 From: Andrew Kroh Date: Thu, 7 Jun 2018 19:27:03 -0400 Subject: [PATCH 3/6] Remove dev-tools/packer and related deps --- dev-tools/.beatconfig | 4 - dev-tools/packer/.gitignore | 7 - dev-tools/packer/Makefile | 131 - dev-tools/packer/README.md | 96 - dev-tools/packer/archs/386.yml | 5 - dev-tools/packer/archs/amd64.yml | 5 - dev-tools/packer/archs/arm.yml | 2 - dev-tools/packer/docker/deb-rpm-s3/.gitignore | 1 - dev-tools/packer/docker/deb-rpm-s3/Dockerfile | 38 - dev-tools/packer/docker/deb-rpm-s3/build.sh | 10 - .../packer/docker/deb-rpm-s3/deb-rpm-s3.sh | 45 - .../packer/docker/deb-rpm-s3/deb-s3.expect | 19 - .../packer/docker/deb-rpm-s3/debsign.expect | 20 - .../publish-package-repositories.sh | 226 -- .../packer/docker/deb-rpm-s3/rpm-s3.expect | 20 - dev-tools/packer/docker/deb-rpm-s3/rpmmacros | 2 - .../packer/docker/deb-rpm-s3/rpmsign.expect | 20 - dev-tools/packer/docker/fpm-image/Dockerfile | 11 - dev-tools/packer/docker/go-daemon/Dockerfile | 10 - .../docker/go-daemon/build_go_daemon.sh | 17 - .../packer/docker/xgo-image-deb7/.gitignore | 2 - .../docker/xgo-image-deb7/base/Dockerfile | 49 - .../docker/xgo-image-deb7/base/bootstrap.sh | 31 - .../xgo-image-deb7/base/bootstrap_pure.sh | 26 - .../docker/xgo-image-deb7/base/build_deps.sh | 36 - .../docker/xgo-image-deb7/base/fetch.sh | 17 - .../xgo-image-deb7/beats-builder/Dockerfile | 33 - .../beats-builder/gopacket_pcap.patch | 26 - .../packer/docker/xgo-image-deb7/build.sh | 6 - .../xgo-image-deb7/go-1.10.3/Dockerfile | 15 - dev-tools/packer/docker/xgo-image/.gitignore | 2 - .../packer/docker/xgo-image/base/Dockerfile | 76 - .../packer/docker/xgo-image/base/bootstrap.sh | 48 - .../docker/xgo-image/base/bootstrap_pure.sh | 41 - .../packer/docker/xgo-image/base/build.sh | 207 -- .../docker/xgo-image/base/build_deps.sh | 36 - .../packer/docker/xgo-image/base/fetch.sh | 17 - .../packer/docker/xgo-image/base/patch.tar.xz | Bin 294820 -> 0 bytes .../docker/xgo-image/beats-builder/Dockerfile | 47 - .../beats-builder/gopacket_pcap.patch | 24 - .../docker/xgo-image/beats-builder/wpcap.dll | Bin 281104 -> 0 bytes dev-tools/packer/docker/xgo-image/build.sh | 7 - .../docker/xgo-image/go-1.10.3/Dockerfile | 15 - .../packer/docker/xgo-image/push_image.md | 16 - dev-tools/packer/platforms/README | 1 - dev-tools/packer/platforms/binary/build.sh | 19 - dev-tools/packer/platforms/binary/run.sh.j2 | 31 - .../packer/platforms/centos/beatname.sh.j2 | 11 - dev-tools/packer/platforms/centos/build.sh | 23 - dev-tools/packer/platforms/centos/init.j2 | 119 - dev-tools/packer/platforms/centos/run.sh.j2 | 64 - dev-tools/packer/platforms/centos/systemd.j2 | 12 - dev-tools/packer/platforms/darwin/build.sh | 19 - dev-tools/packer/platforms/darwin/run.sh.j2 | 28 - .../packer/platforms/dashboards/build.sh | 18 - .../packer/platforms/dashboards/run.sh.j2 | 22 - .../packer/platforms/debian/beatname.sh.j2 | 11 - dev-tools/packer/platforms/debian/build.sh | 23 - dev-tools/packer/platforms/debian/init.j2 | 188 -- dev-tools/packer/platforms/debian/run.sh.j2 | 62 - dev-tools/packer/platforms/debian/systemd.j2 | 12 - dev-tools/packer/platforms/windows/build.sh | 21 - .../platforms/windows/install-service.ps1.j2 | 14 - dev-tools/packer/platforms/windows/run.sh.j2 | 31 - .../windows/uninstall-service.ps1.j2 | 5 - dev-tools/packer/readme.md.j2 | 23 - dev-tools/packer/version.yml | 1 - dev-tools/packer/xgo-scripts/before_build.sh | 68 - dev-tools/vendor/github.com/tsg/gotpl/LICENSE | 11 - .../vendor/github.com/tsg/gotpl/README.md | 26 - dev-tools/vendor/github.com/tsg/gotpl/tpl.go | 48 - dev-tools/vendor/gopkg.in/yaml.v2/LICENSE | 201 -- .../vendor/gopkg.in/yaml.v2/LICENSE.libyaml | 31 - dev-tools/vendor/gopkg.in/yaml.v2/README.md | 135 - dev-tools/vendor/gopkg.in/yaml.v2/apic.go | 742 ----- dev-tools/vendor/gopkg.in/yaml.v2/decode.go | 685 ----- dev-tools/vendor/gopkg.in/yaml.v2/emitterc.go | 1684 ---------- dev-tools/vendor/gopkg.in/yaml.v2/encode.go | 306 -- dev-tools/vendor/gopkg.in/yaml.v2/parserc.go | 1095 ------- dev-tools/vendor/gopkg.in/yaml.v2/readerc.go | 394 --- dev-tools/vendor/gopkg.in/yaml.v2/resolve.go | 208 -- dev-tools/vendor/gopkg.in/yaml.v2/scannerc.go | 2711 ----------------- dev-tools/vendor/gopkg.in/yaml.v2/sorter.go | 104 - dev-tools/vendor/gopkg.in/yaml.v2/writerc.go | 89 - dev-tools/vendor/gopkg.in/yaml.v2/yaml.go | 357 --- dev-tools/vendor/gopkg.in/yaml.v2/yamlh.go | 716 ----- .../vendor/gopkg.in/yaml.v2/yamlprivateh.go | 173 -- dev-tools/vendor/vendor.json | 8 - 88 files changed, 12016 deletions(-) delete mode 100644 dev-tools/.beatconfig delete mode 100644 dev-tools/packer/.gitignore delete mode 100644 dev-tools/packer/Makefile delete mode 100644 dev-tools/packer/README.md delete mode 100644 dev-tools/packer/archs/386.yml delete mode 100644 dev-tools/packer/archs/amd64.yml delete mode 100644 dev-tools/packer/archs/arm.yml delete mode 100644 dev-tools/packer/docker/deb-rpm-s3/.gitignore delete mode 100644 dev-tools/packer/docker/deb-rpm-s3/Dockerfile delete mode 100755 dev-tools/packer/docker/deb-rpm-s3/build.sh delete mode 100755 dev-tools/packer/docker/deb-rpm-s3/deb-rpm-s3.sh delete mode 100644 dev-tools/packer/docker/deb-rpm-s3/deb-s3.expect delete mode 100755 dev-tools/packer/docker/deb-rpm-s3/debsign.expect delete mode 100755 dev-tools/packer/docker/deb-rpm-s3/publish-package-repositories.sh delete mode 100644 dev-tools/packer/docker/deb-rpm-s3/rpm-s3.expect delete mode 100644 dev-tools/packer/docker/deb-rpm-s3/rpmmacros delete mode 100755 dev-tools/packer/docker/deb-rpm-s3/rpmsign.expect delete mode 100644 dev-tools/packer/docker/fpm-image/Dockerfile delete mode 100644 dev-tools/packer/docker/go-daemon/Dockerfile delete mode 100644 dev-tools/packer/docker/go-daemon/build_go_daemon.sh delete mode 100644 dev-tools/packer/docker/xgo-image-deb7/.gitignore delete mode 100644 dev-tools/packer/docker/xgo-image-deb7/base/Dockerfile delete mode 100644 dev-tools/packer/docker/xgo-image-deb7/base/bootstrap.sh delete mode 100644 dev-tools/packer/docker/xgo-image-deb7/base/bootstrap_pure.sh delete mode 100644 dev-tools/packer/docker/xgo-image-deb7/base/build_deps.sh delete mode 100644 dev-tools/packer/docker/xgo-image-deb7/base/fetch.sh delete mode 100644 dev-tools/packer/docker/xgo-image-deb7/beats-builder/Dockerfile delete mode 100644 dev-tools/packer/docker/xgo-image-deb7/beats-builder/gopacket_pcap.patch delete mode 100755 dev-tools/packer/docker/xgo-image-deb7/build.sh delete mode 100644 dev-tools/packer/docker/xgo-image-deb7/go-1.10.3/Dockerfile delete mode 100644 dev-tools/packer/docker/xgo-image/.gitignore delete mode 100644 dev-tools/packer/docker/xgo-image/base/Dockerfile delete mode 100644 dev-tools/packer/docker/xgo-image/base/bootstrap.sh delete mode 100644 dev-tools/packer/docker/xgo-image/base/bootstrap_pure.sh delete mode 100644 dev-tools/packer/docker/xgo-image/base/build.sh delete mode 100644 dev-tools/packer/docker/xgo-image/base/build_deps.sh delete mode 100644 dev-tools/packer/docker/xgo-image/base/fetch.sh delete mode 100644 dev-tools/packer/docker/xgo-image/base/patch.tar.xz delete mode 100644 dev-tools/packer/docker/xgo-image/beats-builder/Dockerfile delete mode 100644 dev-tools/packer/docker/xgo-image/beats-builder/gopacket_pcap.patch delete mode 100644 dev-tools/packer/docker/xgo-image/beats-builder/wpcap.dll delete mode 100755 dev-tools/packer/docker/xgo-image/build.sh delete mode 100644 dev-tools/packer/docker/xgo-image/go-1.10.3/Dockerfile delete mode 100644 dev-tools/packer/docker/xgo-image/push_image.md delete mode 100644 dev-tools/packer/platforms/README delete mode 100755 dev-tools/packer/platforms/binary/build.sh delete mode 100644 dev-tools/packer/platforms/binary/run.sh.j2 delete mode 100644 dev-tools/packer/platforms/centos/beatname.sh.j2 delete mode 100755 dev-tools/packer/platforms/centos/build.sh delete mode 100755 dev-tools/packer/platforms/centos/init.j2 delete mode 100644 dev-tools/packer/platforms/centos/run.sh.j2 delete mode 100644 dev-tools/packer/platforms/centos/systemd.j2 delete mode 100755 dev-tools/packer/platforms/darwin/build.sh delete mode 100644 dev-tools/packer/platforms/darwin/run.sh.j2 delete mode 100755 dev-tools/packer/platforms/dashboards/build.sh delete mode 100644 dev-tools/packer/platforms/dashboards/run.sh.j2 delete mode 100644 dev-tools/packer/platforms/debian/beatname.sh.j2 delete mode 100755 dev-tools/packer/platforms/debian/build.sh delete mode 100755 dev-tools/packer/platforms/debian/init.j2 delete mode 100644 dev-tools/packer/platforms/debian/run.sh.j2 delete mode 100644 dev-tools/packer/platforms/debian/systemd.j2 delete mode 100755 dev-tools/packer/platforms/windows/build.sh delete mode 100644 dev-tools/packer/platforms/windows/install-service.ps1.j2 delete mode 100644 dev-tools/packer/platforms/windows/run.sh.j2 delete mode 100644 dev-tools/packer/platforms/windows/uninstall-service.ps1.j2 delete mode 100644 dev-tools/packer/readme.md.j2 delete mode 100644 dev-tools/packer/version.yml delete mode 100755 dev-tools/packer/xgo-scripts/before_build.sh delete mode 100644 dev-tools/vendor/github.com/tsg/gotpl/LICENSE delete mode 100644 dev-tools/vendor/github.com/tsg/gotpl/README.md delete mode 100644 dev-tools/vendor/github.com/tsg/gotpl/tpl.go delete mode 100644 dev-tools/vendor/gopkg.in/yaml.v2/LICENSE delete mode 100644 dev-tools/vendor/gopkg.in/yaml.v2/LICENSE.libyaml delete mode 100644 dev-tools/vendor/gopkg.in/yaml.v2/README.md delete mode 100644 dev-tools/vendor/gopkg.in/yaml.v2/apic.go delete mode 100644 dev-tools/vendor/gopkg.in/yaml.v2/decode.go delete mode 100644 dev-tools/vendor/gopkg.in/yaml.v2/emitterc.go delete mode 100644 dev-tools/vendor/gopkg.in/yaml.v2/encode.go delete mode 100644 dev-tools/vendor/gopkg.in/yaml.v2/parserc.go delete mode 100644 dev-tools/vendor/gopkg.in/yaml.v2/readerc.go delete mode 100644 dev-tools/vendor/gopkg.in/yaml.v2/resolve.go delete mode 100644 dev-tools/vendor/gopkg.in/yaml.v2/scannerc.go delete mode 100644 dev-tools/vendor/gopkg.in/yaml.v2/sorter.go delete mode 100644 dev-tools/vendor/gopkg.in/yaml.v2/writerc.go delete mode 100644 dev-tools/vendor/gopkg.in/yaml.v2/yaml.go delete mode 100644 dev-tools/vendor/gopkg.in/yaml.v2/yamlh.go delete mode 100644 dev-tools/vendor/gopkg.in/yaml.v2/yamlprivateh.go diff --git a/dev-tools/.beatconfig b/dev-tools/.beatconfig deleted file mode 100644 index 6821aff8ce0f..000000000000 --- a/dev-tools/.beatconfig +++ /dev/null @@ -1,4 +0,0 @@ -packetbeat-/packetbeat- -filebeat-/filebeat- -winlogonbeat-/winlogonbeat- -logstash-/logstash- diff --git a/dev-tools/packer/.gitignore b/dev-tools/packer/.gitignore deleted file mode 100644 index 5778a7d708a8..000000000000 --- a/dev-tools/packer/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -*.swp -*.swo -/build/ -/env/ - -# copied over from xgo-image/ -docker/xgo-image-deb7/base/build.sh diff --git a/dev-tools/packer/Makefile b/dev-tools/packer/Makefile deleted file mode 100644 index c89da1b2a186..000000000000 --- a/dev-tools/packer/Makefile +++ /dev/null @@ -1,131 +0,0 @@ -BUILDID?=$(shell git rev-parse HEAD) -SNAPSHOT?=yes - -BEATS_BUILDER_IMAGE?=tudorg/beats-builder -BEATS_BUILDER_DEB_IMAGE?=tudorg/beats-builder-deb7 -BEATS_GOPATH=$(firstword $(subst :, ,${GOPATH})) - -makefile_abspath:=$(abspath $(lastword $(MAKEFILE_LIST))) -packer_absdir=$(shell dirname ${makefile_abspath}) -beat_abspath=${BEATS_GOPATH}/src/${BEAT_PATH} - - -%/deb: ${BUILD_DIR}/god-linux-386 ${BUILD_DIR}/god-linux-amd64 fpm-image - echo Creating DEB packages for $(@D) - ARCH=386 BEAT=$(@D) BUILD_DIR=${BUILD_DIR} UPLOAD_DIR=${UPLOAD_DIR} BEAT_PATH=$(beat_abspath) BUILDID=$(BUILDID) SNAPSHOT=$(SNAPSHOT) BEAT_REF_YAML=${BEAT_REF_YAML} $(packer_absdir)/platforms/debian/build.sh - ARCH=amd64 BEAT=$(@D) BUILD_DIR=${BUILD_DIR} UPLOAD_DIR=${UPLOAD_DIR} BEAT_PATH=$(beat_abspath) BUILDID=$(BUILDID) SNAPSHOT=$(SNAPSHOT) BEAT_REF_YAML=${BEAT_REF_YAML} $(packer_absdir)/platforms/debian/build.sh - -%/rpm: ${BUILD_DIR}/god-linux-386 ${BUILD_DIR}/god-linux-amd64 fpm-image - echo Creating RPM packages for $(@D) - ARCH=386 BEAT=$(@D) BUILD_DIR=${BUILD_DIR} UPLOAD_DIR=${UPLOAD_DIR} BEAT_PATH=$(beat_abspath) BUILDID=$(BUILDID) SNAPSHOT=$(SNAPSHOT) BEAT_REF_YAML=${BEAT_REF_YAML} $(packer_absdir)/platforms/centos/build.sh - ARCH=amd64 BEAT=$(@D) BUILD_DIR=${BUILD_DIR} UPLOAD_DIR=${UPLOAD_DIR} BEAT_PATH=$(beat_abspath) BUILDID=$(BUILDID) SNAPSHOT=$(SNAPSHOT) BEAT_REF_YAML=${BEAT_REF_YAML} $(packer_absdir)/platforms/centos/build.sh - -%/darwin: - echo Creating Darwin packages for $(@D) - ARCH=amd64 BEAT=$(@D) BUILD_DIR=${BUILD_DIR} UPLOAD_DIR=${UPLOAD_DIR} BEAT_PATH=$(beat_abspath) BUILDID=$(BUILDID) SNAPSHOT=$(SNAPSHOT) BEAT_REF_YAML=${BEAT_REF_YAML} $(packer_absdir)/platforms/darwin/build.sh - -%/win: - echo Creating Darwin packages for $(@D) - ARCH=386 BEAT=$(@D) BUILD_DIR=${BUILD_DIR} UPLOAD_DIR=${UPLOAD_DIR} BEAT_PATH=$(beat_abspath) BUILDID=$(BUILDID) SNAPSHOT=$(SNAPSHOT) BEAT_REF_YAML=${BEAT_REF_YAML} $(packer_absdir)/platforms/windows/build.sh - ARCH=amd64 BEAT=$(@D) BUILD_DIR=${BUILD_DIR} UPLOAD_DIR=${UPLOAD_DIR} BEAT_PATH=$(beat_abspath) BUILDID=$(BUILDID) SNAPSHOT=$(SNAPSHOT) BEAT_REF_YAML=${BEAT_REF_YAML} $(packer_absdir)/platforms/windows/build.sh - -%/bin: - echo Creating Linux packages for $(@D) - ARCH=386 BEAT=$(@D) BUILD_DIR=${BUILD_DIR} UPLOAD_DIR=${UPLOAD_DIR} BEAT_PATH=$(beat_abspath) BUILDID=$(BUILDID) SNAPSHOT=$(SNAPSHOT) BEAT_REF_YAML=${BEAT_REF_YAML} $(packer_absdir)/platforms/binary/build.sh - ARCH=amd64 BEAT=$(@D) BUILD_DIR=${BUILD_DIR} UPLOAD_DIR=${UPLOAD_DIR} BEAT_PATH=$(beat_abspath) BUILDID=$(BUILDID) SNAPSHOT=$(SNAPSHOT) BEAT_REF_YAML=${BEAT_REF_YAML} $(packer_absdir)/platforms/binary/build.sh - -%/arm: - echo Creating ARM packages for $(@D) - ARCH=arm BEAT=$(@D) BUILD_DIR=${BUILD_DIR} BEAT_PATH=$(beat_abspath) BUILDID=$(BUILDID) SNAPSHOT=$(SNAPSHOT) $(packer_absdir)/platforms/binary/build.sh - -.PHONY: package-dashboards -package-dashboards: - echo Creating the Dashboards package - UPLOAD_DIR=${UPLOAD_DIR} BUILDID=$(BUILDID) SNAPSHOT=$(SNAPSHOT) BEAT_REF_YAML=${BEAT_REF_YAML} $(packer_absdir)/platforms/dashboards/build.sh - -.PHONY: deps -deps: - cd ../vendor/github.com/tsg/gotpl; go install - -.PHONY: xgo-image -xgo-image: - cd $(packer_absdir)/docker/xgo-image/; ./build.sh - # copy build.sh script in the xgo-image-deb7 to avoid code duplication - cp $(packer_absdir)/docker/xgo-image/base/build.sh $(packer_absdir)/docker/xgo-image-deb7/base/build.sh - cd $(packer_absdir)/docker/xgo-image-deb7/; ./build.sh - -.PHONY: fpm-image -fpm-image: - docker build --rm=true -t tudorg/fpm $(packer_absdir)/docker/fpm-image - -.PHONY: go-daemon-image -go-daemon-image: - docker build --rm=true -t tudorg/go-daemon $(packer_absdir)/docker/go-daemon/ - -${BUILD_DIR}/god-linux-386 ${BUILD_DIR}/god-linux-amd64: - docker run --rm -v ${BUILD_DIR}:/build tudorg/go-daemon - -${UPLOAD_DIR}: - mkdir -p ${UPLOAD_DIR} - -${UPLOAD_DIR}/build_id.txt: - echo $(BUILDID) > ${UPLOAD_DIR}/build_id.txt - -# Build the image required for package-upload. -.PHONY: deb-rpm-s3 -deb-rpm-s3: - $(packer_absdir)/docker/deb-rpm-s3/build.sh - -.PHONY: run-interactive-builder-deb -run-interactive-builder-deb: - docker run -t -i -v $(shell pwd)/build:/build \ - -v $(shell pwd)/xgo-scripts/:/scripts \ - -v $(shell pwd)/../..:/source \ - --entrypoint=bash ${BEATS_BUILDER_DEB_IMAGE} - -.PHONY: run-interactive-builder -run-interactive-builder: - docker run -t -i -v $(shell pwd)/build:/build \ - -v $(packer_absdir)/xgo-scripts/:/scripts \ - -v $(shell pwd)/../..:/source \ - --entrypoint=bash ${BEATS_BUILDER_IMAGE} - -.PHONY: images -images: xgo-image fpm-image go-daemon-image - -.PHONY: push-images -push-images: - docker push ${BEATS_BUILDER_IMAGE} - docker push ${BEATS_BUILDER_DEB_IMAGE} - docker push tudorg/fpm - docker push tudorg/go-daemon - -.PHONY: pull-images -pull-images: - docker pull ${BEATS_BUILDER_IMAGE} - docker pull ${BEATS_BUILDER_DEB_IMAGE} - docker pull tudorg/fpm - docker pull tudorg/go-daemon - - -define rm-image = -@echo "Cleaning $(1) image..." - @if [ $(shell docker ps -n 1 -a -q --filter="image=$(1)" ) ]; then \ - docker stop $(shell docker ps -a -q --filter="image=$(1)"); \ - docker rm $(shell docker ps -a -q --filter="image=$(1)"); \ - fi; \ -\ - if [ $(shell docker images -q $(1)) ]; then \ - docker rmi $(1); \ - fi -endef - - -.PHONY: clean-images -clean-images: - @$(call rm-image, ${BEATS_BUILDER_DEB_IMAGE}) - @$(call rm-image, ${BEATS_BUILDER_IMAGE}) - -.PHONY: clean -clean: - $(call rm-image,build-image) diff --git a/dev-tools/packer/README.md b/dev-tools/packer/README.md deleted file mode 100644 index 9860d123e41d..000000000000 --- a/dev-tools/packer/README.md +++ /dev/null @@ -1,96 +0,0 @@ -[![Build Status](https://travis-ci.org/elastic/beats-packer.svg)](https://travis-ci.org/elastic/beats-packer) - -# Beats Packer - -Tools, scripts and docker images for cross-compiling and packaging the Elastic -[Beats](https://www.elastic.co/products/beats). - -## Prepare - -You need Go and docker installed. This project uses several docker files, you -can either build them with: - - make images - -Or pull them from the Docker registry with: - - make pull-images - -Prepare the rest with: - - make deps - -## Cross-compile - -The cross compilation part is based on [xgo](https://github.com/karalabe/xgo), -with some [changes](https://github.com/tsg/xgo) that add a bit more -extensibility that we needed for the Beats (e.g. static compiling, custom -docker image). - -You can cross-compile one Beat for all platforms with (e.g.): - - make packetbeat - -## Packaging - -For each OS (named platform here) we execute a `build.sh` script which is -free to do whatever it is required to build the proper packages for that -platform. This can include running docker containers with the right tools -included or with that OS installed for native packaging. - -The deb and rpm creation is based on [fpm](https://github.com/jordansissel/fpm) -which is executed from a container. - -Besides the platform, there are three other dimensions: architecture, -beat and the release. Each of these is defined by YAML files in their folders. -These dimensions only set static options, the platforms is the only one -scripted. - -The runner is currently (ab)using a Makefile, which is nice because it can -parallelize things automatically, but it's hacky so we might replace it in -a future. - -Building all Beats for all platforms: - - make clean && make - -## Naming conventions - -We use a set of package name conventions across all the Elastic stack: - -* The general form is `name-version-os-arch.ext`. Note that this means we - use dashes even for Deb files. -* The archs are called `x86` and `x64` except for deb/rpm where we keep the - OS preferred names (i386/amd64, i686/x86_64). -* For version strings like `5.0.0-alpha3` we use dashes in all filenames. The - only exception is the RPM metadata (not the filename) where we replace the - dash with an underscore (`5.0.0_alpha3`). -* We omit the release number from the filenames. It's always `1` in the metadata. - -For example, here are the artifacts created for Filebeat: - -``` -filebeat-5.0.0-amd64.deb -filebeat-5.0.0-darwin-x86_64.tar.gz -filebeat-5.0.0-i386.deb -filebeat-5.0.0-i686.rpm -filebeat-5.0.0-linux-x86.tar.gz -filebeat-5.0.0-linux-x86_64.tar.gz -filebeat-5.0.0-windows-x86.zip -filebeat-5.0.0-windows-x86_64.zip -filebeat-5.0.0-x86_64.rpm -``` - -And the SNAPSHOT versions: - -``` -filebeat-5.0.0-SNAPSHOT-amd64.deb -filebeat-5.0.0-SNAPSHOT-darwin-x86_64.tar.gz -filebeat-5.0.0-SNAPSHOT-i386.deb -filebeat-5.0.0-SNAPSHOT-i686.rpm -filebeat-5.0.0-SNAPSHOT-linux-x86.tar.gz -filebeat-5.0.0-SNAPSHOT-linux-x86_64.tar.gz -filebeat-5.0.0-SNAPSHOT-windows-x86.zip -filebeat-5.0.0-SNAPSHOT-windows-x86_64.zip -filebeat-5.0.0-SNAPSHOT-x86_64.rpm -``` diff --git a/dev-tools/packer/archs/386.yml b/dev-tools/packer/archs/386.yml deleted file mode 100644 index 96f314538eb8..000000000000 --- a/dev-tools/packer/archs/386.yml +++ /dev/null @@ -1,5 +0,0 @@ -arch: '386' -deb_arch: i386 -rpm_arch: i686 -bin_arch: x86 -win_arch: x86 diff --git a/dev-tools/packer/archs/amd64.yml b/dev-tools/packer/archs/amd64.yml deleted file mode 100644 index 299012d85127..000000000000 --- a/dev-tools/packer/archs/amd64.yml +++ /dev/null @@ -1,5 +0,0 @@ -arch: amd64 -deb_arch: amd64 -rpm_arch: x86_64 -bin_arch: x86_64 -win_arch: x86_64 diff --git a/dev-tools/packer/archs/arm.yml b/dev-tools/packer/archs/arm.yml deleted file mode 100644 index 4b2e2f35f6e1..000000000000 --- a/dev-tools/packer/archs/arm.yml +++ /dev/null @@ -1,2 +0,0 @@ -arch: 'arm' -bin_arch: arm diff --git a/dev-tools/packer/docker/deb-rpm-s3/.gitignore b/dev-tools/packer/docker/deb-rpm-s3/.gitignore deleted file mode 100644 index 78a9141e3749..000000000000 --- a/dev-tools/packer/docker/deb-rpm-s3/.gitignore +++ /dev/null @@ -1 +0,0 @@ -elasticsearch.asc diff --git a/dev-tools/packer/docker/deb-rpm-s3/Dockerfile b/dev-tools/packer/docker/deb-rpm-s3/Dockerfile deleted file mode 100644 index fca7551a615a..000000000000 --- a/dev-tools/packer/docker/deb-rpm-s3/Dockerfile +++ /dev/null @@ -1,38 +0,0 @@ -# Dockerfile for building an image that contains all of the necessary -# dependencies for signing deb/rpm packages and publishing APT and YUM -# repositories to Amazon S3. -FROM debian:jessie - -RUN apt-get update -RUN apt-get install -y git \ - rubygems ruby-dev patch gcc make zlib1g-dev rpm curl dpkg-sig \ - yum python-deltarpm \ - expect - -# Install python-boto from source to get latest version. -RUN git clone git://github.com/boto/boto.git && \ - cd boto && \ - git checkout 2.38.0 && \ - python setup.py install - -# Install deb-s3 -RUN gem install deb-s3 - -# Install rpm-s3 -# WARNING: Pulling from master, may not be repeatable. -RUN cd /usr/local && \ - git clone https://github.com/crohr/rpm-s3 --recursive && \ - echo '[s3]\ncalling_format = boto.s3.connection.OrdinaryCallingFormat' > /etc/boto.cfg - # Use HTTP for debugging traffic to S3. - #echo '[Boto]\nis_secure = False' >> /etc/boto.cfg -ENV PATH /usr/local/rpm-s3/bin:$PATH -ADD rpmmacros /root/.rpmmacros - -# Add the scripts that are executed by within the container. -ADD *.expect / -ADD publish-package-repositories.sh / - -# Execute the publish-package-repositories.sh when the container -# is run. -ENTRYPOINT ["/publish-package-repositories.sh"] -CMD ["--help"] diff --git a/dev-tools/packer/docker/deb-rpm-s3/build.sh b/dev-tools/packer/docker/deb-rpm-s3/build.sh deleted file mode 100755 index e5a253720174..000000000000 --- a/dev-tools/packer/docker/deb-rpm-s3/build.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -set -e - -# -# Build script for the deb-rpm-s3 docker container. -# - -cd "$(dirname "$0")" - -docker build -t deb-rpm-s3 . diff --git a/dev-tools/packer/docker/deb-rpm-s3/deb-rpm-s3.sh b/dev-tools/packer/docker/deb-rpm-s3/deb-rpm-s3.sh deleted file mode 100755 index bd0ed1c26985..000000000000 --- a/dev-tools/packer/docker/deb-rpm-s3/deb-rpm-s3.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash - -# -# Wrapper script for starting the docker container. -# -# You must set AWS_ACCESS_KEY and AWS_SECRET_KEY in your environment prior to -# running. You can optionally pass the GPG key's passphrase as the environment -# variable PASS. -# - -cd "$(dirname "$0")" - -if [ ! -e "elasticsearch.asc" ]; then - cat << EOF -You must place a copy of the Elasticsearch GPG signing key (named -elasticsearch.asc) into - - $PWD - -prior to building this docker image. - -EOF - exit 1 -fi - -bucket="packages.elasticsearch.org" -prefix="beats" -dir="/beats-packer/build/upload" -gpg_key="/beats-packer/dev-tools/packer/docker/deb-rpm-s3/elasticsearch.asc" -origin=Elastic - -docker run -it --rm \ - --env="PASS=$PASS" \ - --volume `pwd`/../../../..:/beats-packer \ - deb-rpm-s3 \ - --bucket=$bucket \ - --prefix=$prefix \ - --directory="$dir" \ - --aws-access-key="$AWS_ACCESS_KEY" \ - --aws-secret-key="$AWS_SECRET_KEY" \ - --gpg-key="$gpg_key" \ - --origin="$origin" \ - --verbose \ - "$@" - diff --git a/dev-tools/packer/docker/deb-rpm-s3/deb-s3.expect b/dev-tools/packer/docker/deb-rpm-s3/deb-s3.expect deleted file mode 100644 index ea6b146ab731..000000000000 --- a/dev-tools/packer/docker/deb-rpm-s3/deb-s3.expect +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/expect -f - -# Expect wrapper for deb-s3 that provides the GPG signing password -# when prompted. - -spawn deb-s3 upload \ - --sign \ - --preserve_versions \ - --bucket "$env(BUCKET)" \ - --prefix "$env(PREFIX)/apt" \ - --arch $env(arch) \ - -o "$env(ORIGIN)" \ - {*}$argv -expect { - "Enter passphrase: " { - send -- "$env(PASS)\r" - exp_continue - } -} diff --git a/dev-tools/packer/docker/deb-rpm-s3/debsign.expect b/dev-tools/packer/docker/deb-rpm-s3/debsign.expect deleted file mode 100755 index c3bcac3f0ef2..000000000000 --- a/dev-tools/packer/docker/deb-rpm-s3/debsign.expect +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/expect -f - -# Expect wrapper for 'dpkg-sig --sign' that provides the GPG signing password -# when prompted. -# -# Set password in PASS environment variable prior to running -# this expect script. -# -# Example usage: -# expect debsign.expect example.deb -# -# expect debsign.expect example.deb other.deb - -spawn dpkg-sig --sign builder {*}$argv -expect { - "Enter passphrase: " { - send -- "$env(PASS)\r" - exp_continue - } -} diff --git a/dev-tools/packer/docker/deb-rpm-s3/publish-package-repositories.sh b/dev-tools/packer/docker/deb-rpm-s3/publish-package-repositories.sh deleted file mode 100755 index cc531aee39aa..000000000000 --- a/dev-tools/packer/docker/deb-rpm-s3/publish-package-repositories.sh +++ /dev/null @@ -1,226 +0,0 @@ -#!/bin/bash -set -e - -# Script directory: -SDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -usage() { -cat << EOF - Usage: $(basename $0) [-vh] [-d=directory] [-b=bucket] [-p=prefix] - [--access-key-id=aws id] [--secret-key-id=aws secret] - - Description: Sign packages and publish them to APT and YUM repositories - hosted from an S3 bucket. When publishing, the repository metadata is - also signed to prevent tampering. - - You will be prompted once for the GPG signing key's password. If the - PASS environment variable is set then that value will be used and you - will not be prompted. - - Options: - --aws-access-key=AWS_ACCESS_KEY Required. AWS access key. Alternatively, - AWS_ACCESS_KEY may be set as an environment - variable. - - --aws-secret-key=AWS_SECRET_KEY Required. AWS secret key. Alternatively, - AWS_SECRET_KEY may be set as an environment - variable. - - -b=BUCKET | --bucket=BUCKET Required. The S3 bucket in which to publish. - - -p=PREFIX | --prefix=PREFIX Required. Path to prefix to all published - repositories. - - -d=DIR | --directory=DIR Required. Directory to recursively search - for .rpm and .deb files. - - -g=GPG_KEY | --gpg-key=GPG_KEY Optional. Path to GPG key file to import. - - -o=ORIGIN | --origin=ORIGIN Optional. Origin to use in APT repo metadata. - - -v | --verbose Optional. Enable verbose logging to stderr. - - -h | --help Optional. Print this usage information. -EOF -} - -# Write a debug message to stderr. -debug() -{ - if [ "$VERBOSE" == "true" ]; then - echo "DEBUG: $1" >&2 - fi -} - -# Write and error message to stderr. -err() -{ - echo "ERROR: $1" >&2 -} - -# Parse command line arguments. -parseArgs() { - for i in "$@" - do - case $i in - --aws-access-key=*) - AWS_ACCESS_KEY="${i#*=}" - shift - ;; - --aws-secret-key=*) - AWS_SECRET_KEY="${i#*=}" - shift - ;; - -b=*|--bucket=*) - BUCKET="${i#*=}" - shift - ;; - -d=*|--directory=*) - DIRECTORY="${i#*=}" - shift - ;; - -g=*|--gpg-key=*) - GPG_KEY="${i#*=}" - shift - ;; - -h|--help) - usage - exit 1 - ;; - -o=*|--origin=*) - ORIGIN="${i#*=}" - shift - ;; - -p=*|--prefix=*) - PREFIX="${i#*=}" - shift - ;; - -v|--verbose) - VERBOSE=true - shift - ;; - *) - echo "Invalid argument: $i" - usage - exit 1 - ;; - esac - done - - if [ -z "$BUCKET" ]; then - err "-b=BUCKET or --bucket=BUCKET is required." - exit 1 - fi - - if [ -z "$DIRECTORY" ]; then - err "-d=DIRECTORY or --directory=DIRECTORY is required." - exit 1 - fi - - if [ ! -e "$DIRECTORY" ]; then - err "Directory $DIRECTORY does not exists." - exit 1 - fi - - if [ -z "$PREFIX" ]; then - err "-p=PREFIX or --prefix=PREFIX is required." - exit 1 - fi - - if [ -z "$AWS_ACCESS_KEY" ]; then - err "--access-key-id=AWS_ACCESS_KEY is required." - exit 1 - fi - - if [ -z "$AWS_SECRET_KEY" ]; then - err "--secret-access-key-id=AWS_SECRET_KEY is required." - exit 1 - fi - - export BUCKET - export ORIGIN - export PREFIX - export AWS_ACCESS_KEY - export AWS_SECRET_KEY -} - -importGpg() { - if [ ! -z "$GPG_KEY" ]; then - if [ ! -f "$GPG_KEY" ]; then - err "GPG key file $GPG_KEY does not exists." - exit 1 - fi - - debug "Importing GPG key $GPG_KEY" - gpg --import --allow-secret-key-import "$GPG_KEY" | true - else - debug "Not importing a GPG key because --gpg-key not specified." - fi -} - -getPassword() { - if [ -z "$PASS" ]; then - echo -n "Enter GPG pass phrase: " - read -s PASS - fi - - export PASS -} - -signDebianPackages() { - debug "Entering signDebianPackages" - find $DIRECTORY -name '*.deb' | xargs expect $SDIR/debsign.expect - debug "Exiting signDebianPackages" -} - -signRpmPackages() { - debug "Entering signRpmPackages" - find $DIRECTORY -name '*.rpm' | xargs expect $SDIR/rpmsign.expect - debug "Exiting signRpmPackages" -} - -publishToAptRepo() { - debug "Entering publishToAptRepo" - - # Verify the repository and credentials before continuing. - deb-s3 verify --bucket "$BUCKET" --prefix "${PREFIX}/apt" - - for arch in i386 amd64 - do - debug "Publishing $arch .deb packages..." - export arch - - for deb in $(find "$DIRECTORY" -name "*${arch}.deb") - do - expect $SDIR/deb-s3.expect "$deb" - done - done -} - -publishToYumRepo() { - debug "Entering publishToYumRepo" - - for arch in i686 x86_64 - do - debug "Publishing $arch .rpm packages..." - export arch - - for rpm in $(find "$DIRECTORY" -name "*${arch}.rpm") - do - expect $SDIR/rpm-s3.expect "$rpm" - done - done -} - -main() { - parseArgs $* - importGpg - getPassword - signDebianPackages - signRpmPackages - publishToAptRepo - publishToYumRepo - debug "Success" -} - -main $* diff --git a/dev-tools/packer/docker/deb-rpm-s3/rpm-s3.expect b/dev-tools/packer/docker/deb-rpm-s3/rpm-s3.expect deleted file mode 100644 index 246785f6ead7..000000000000 --- a/dev-tools/packer/docker/deb-rpm-s3/rpm-s3.expect +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/expect -f - -# Expect wrapper for rpm-s3 that provides the GPG signing password -# when prompted. - -spawn rpm-s3 \ - -vv \ - --sign \ - --region=external-1 \ - --keep=500 \ - --visibility=public-read \ - --bucket=$env(BUCKET) \ - --repopath=$env(PREFIX)/yum/el/$env(arch) \ - {*}$argv -expect { - "Enter passphrase: " { - send -- "$env(PASS)\r" - exp_continue - } -} diff --git a/dev-tools/packer/docker/deb-rpm-s3/rpmmacros b/dev-tools/packer/docker/deb-rpm-s3/rpmmacros deleted file mode 100644 index 2408b6c189c4..000000000000 --- a/dev-tools/packer/docker/deb-rpm-s3/rpmmacros +++ /dev/null @@ -1,2 +0,0 @@ -%_signature gpg -%_gpg_name Elasticsearch (Elasticsearch Signing Key) diff --git a/dev-tools/packer/docker/deb-rpm-s3/rpmsign.expect b/dev-tools/packer/docker/deb-rpm-s3/rpmsign.expect deleted file mode 100755 index d60da47e8bd5..000000000000 --- a/dev-tools/packer/docker/deb-rpm-s3/rpmsign.expect +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/expect -f - -# Expect wrapper for 'rpm --resign' that provides the GPG signing password -# when prompted. -# -# Set password in PASS environment variable prior to running -# this expect script. -# -# Example usage: -# expect rpmsign.expect example.rpm -# -# expect rpmsign.expect example.rpm other.rpm - -spawn rpm --resign \ - --define "_signature gpg" \ - --define "_gpg_name Elasticsearch (Elasticsearch Signing Key) " \ - {*}$argv -expect -exact "Enter pass phrase: " -send -- "$env(PASS)\r" -expect eof diff --git a/dev-tools/packer/docker/fpm-image/Dockerfile b/dev-tools/packer/docker/fpm-image/Dockerfile deleted file mode 100644 index 1d8be72276f4..000000000000 --- a/dev-tools/packer/docker/fpm-image/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM ubuntu:16.04 - -MAINTAINER Tudor Golubenco - -# install fpm -RUN \ - apt-get update && \ - apt-get install -y --no-install-recommends \ - autoconf build-essential libffi-dev ruby-dev rpm zip dos2unix libgmp3-dev - -RUN gem install fpm -v 1.9.2 diff --git a/dev-tools/packer/docker/go-daemon/Dockerfile b/dev-tools/packer/docker/go-daemon/Dockerfile deleted file mode 100644 index 99d13c0d5c1d..000000000000 --- a/dev-tools/packer/docker/go-daemon/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM tudorg/xgo-base - -MAINTAINER Tudor Golubenco - -# Inject the build script -ADD build_go_daemon.sh /build_go_daemon.sh -ENV BUILD_GO_DAEMON /build_go_daemon.sh -RUN chmod +x $BUILD_GO_DAEMON - -ENTRYPOINT ["/build_go_daemon.sh"] diff --git a/dev-tools/packer/docker/go-daemon/build_go_daemon.sh b/dev-tools/packer/docker/go-daemon/build_go_daemon.sh deleted file mode 100644 index b5ace906590c..000000000000 --- a/dev-tools/packer/docker/go-daemon/build_go_daemon.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -set -e - -echo "Fetching go-daemon" -git clone https://github.com/tsg/go-daemon.git - -cd /go-daemon - -echo "Compiling for linux/amd64.." -cc god.c -m64 -o god-linux-amd64 -lpthread -static - -echo "Compiling for linux/i386.." -gcc god.c -m32 -o god-linux-386 -lpthread -static - -echo "Copying to host.." -cp god-linux-amd64 god-linux-386 /build/ diff --git a/dev-tools/packer/docker/xgo-image-deb7/.gitignore b/dev-tools/packer/docker/xgo-image-deb7/.gitignore deleted file mode 100644 index 29554abab065..000000000000 --- a/dev-tools/packer/docker/xgo-image-deb7/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -beats-builder/yaml.v2 -beats-builder/gotpl diff --git a/dev-tools/packer/docker/xgo-image-deb7/base/Dockerfile b/dev-tools/packer/docker/xgo-image-deb7/base/Dockerfile deleted file mode 100644 index 62a57d770a3a..000000000000 --- a/dev-tools/packer/docker/xgo-image-deb7/base/Dockerfile +++ /dev/null @@ -1,49 +0,0 @@ -# Go cross compiler (xgo): Base cross-compilation layer -# Copyright (c) 2014 Péter Szilágyi. All rights reserved. -# -# Released under the MIT license. - -FROM debian:7 - -MAINTAINER Tudor Golubenco - -# Configure the Go environment, since it's not going to change -ENV PATH /usr/local/go/bin:$PATH -ENV GOPATH /go - - -# Inject the remote file fetcher and checksum verifier -ADD fetch.sh /fetch.sh -ENV FETCH /fetch.sh -RUN chmod +x $FETCH - - -# Make sure apt-get is up to date and dependent packages are installed -RUN \ - apt-get update && \ - apt-get install -y automake autogen build-essential ca-certificates \ - gcc-multilib \ - clang llvm-dev libtool libxml2-dev uuid-dev libssl-dev pkg-config \ - patch make xz-utils cpio wget unzip git mercurial bzr rsync --no-install-recommends - -# Inject the Go package downloader and tool-chain bootstrapper -ADD bootstrap.sh /bootstrap.sh -ENV BOOTSTRAP /bootstrap.sh -RUN chmod +x $BOOTSTRAP - -# Inject the new Go root distribution downloader and secondary bootstrapper -ADD bootstrap_pure.sh /bootstrap_pure.sh -ENV BOOTSTRAP_PURE /bootstrap_pure.sh -RUN chmod +x $BOOTSTRAP_PURE - -# Inject the C dependency cross compiler -ADD build_deps.sh /build_deps.sh -ENV BUILD_DEPS /build_deps.sh -RUN chmod +x $BUILD_DEPS - -# Inject the container entry point, the build script -ADD build.sh /build.sh -ENV BUILD /build.sh -RUN chmod +x $BUILD - -ENTRYPOINT ["/build.sh"] diff --git a/dev-tools/packer/docker/xgo-image-deb7/base/bootstrap.sh b/dev-tools/packer/docker/xgo-image-deb7/base/bootstrap.sh deleted file mode 100644 index ce0817756ed9..000000000000 --- a/dev-tools/packer/docker/xgo-image-deb7/base/bootstrap.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -# -# Contains the Go tool-chain bootstrapper, that retrieves all the configured -# distribution packages, extracts the binaries and deletes anything not needed. -# -# Usage: bootstrap.sh -# -# Needed environment variables: -# FETCH - Remote file fetcher and checksum verifier (injected by image) -# DIST_LINUX_64, DIST_LINUX_64_SHA1 - 64 bit Linux Go binaries and checksum -# DIST_LINUX_32, DIST_LINUX_32_SHA1 - 32 bit Linux Go binaries and checksum -# DIST_LINUX_ARM, DIST_LINUX_ARM_SHA1 - ARM v5 Linux Go binaries and checksum -# DIST_OSX_64, DIST_OSX_64_SHA1 - 64 bit Mac OSX Go binaries and checksum -# DIST_OSX_32, DIST_OSX_32_SHA1 - 32 bit Mac OSX Go binaries and checksum -# DIST_WIN_64, DIST_WIN_64_SHA1 - 64 bit Windows Go binaries and checksum -# DIST_WIN_32, DIST_WIN_32_SHA1 - 32 bit Windows Go binaries and checksum -set -e - -# Download and verify all the binary packages -$FETCH $DIST_LINUX_64 $DIST_LINUX_64_SHA1 -$FETCH $DIST_LINUX_32 $DIST_LINUX_32_SHA1 - -# Extract the 64 bit Linux package as the primary Go SDK -tar -C /usr/local -xzf `basename $DIST_LINUX_64` - -# Extract all other packages as secondary ones, keeping only the binaries -tar -C /usr/local --wildcards -xzf `basename $DIST_LINUX_32` go/pkg/linux_386* -GOOS=linux GOARCH=386 /usr/local/go/pkg/tool/linux_amd64/dist bootstrap - -# Delete all the intermediate downloaded files -rm -f `basename $DIST_LINUX_64` `basename $DIST_LINUX_32` diff --git a/dev-tools/packer/docker/xgo-image-deb7/base/bootstrap_pure.sh b/dev-tools/packer/docker/xgo-image-deb7/base/bootstrap_pure.sh deleted file mode 100644 index aa40cd40b76e..000000000000 --- a/dev-tools/packer/docker/xgo-image-deb7/base/bootstrap_pure.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -# -# Contains the Go tool-chain pure-Go bootstrapper, that as of Go 1.5, initiates -# not only a few pre-built Go cross compilers, but rather bootstraps all of the -# supported platforms from the origin Linux amd64 distribution. -# -# Usage: bootstrap.sh -# -# Needed environment variables: -# FETCH - Remote file fetcher and checksum verifier (injected by image) -# ROOT_DIST - 64 bit Linux Go binary distribution package -# ROOT_DIST_SHA1 - 64 bit Linux Go distribution package checksum -set -e - -# Download, verify and install the root distribution -$FETCH $ROOT_DIST $ROOT_DIST_SHA1 - -tar -C /usr/local -xzf `basename $ROOT_DIST` -rm -f `basename $ROOT_DIST` - -export GOROOT=/usr/local/go -export GOROOT_BOOTSTRAP=$GOROOT - -# Pre-build all guest distributions based on the root distribution -echo "Bootstrapping linux/386..." -GOOS=linux GOARCH=386 CGO_ENABLED=1 go install std diff --git a/dev-tools/packer/docker/xgo-image-deb7/base/build_deps.sh b/dev-tools/packer/docker/xgo-image-deb7/base/build_deps.sh deleted file mode 100644 index e6445b95ed9a..000000000000 --- a/dev-tools/packer/docker/xgo-image-deb7/base/build_deps.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash -# -# Contains the dependency builder to iterate over all installed dependencies -# and cross compile them to the requested target platform. -# -# Usage: build_deps.sh dependency_root_folder dependency1 dependency_2 ... -# -# Needed environment variables: -# CC - C cross compiler to use for the build -# HOST - Target platform to build (used to find the needed tool-chains) -# PREFIX - File-system path where to install the built binaries -# STATIC - true if the libraries are statically linked to the go application -set -e - -DEP_ROOT_FOLDER=$1 - -# Remove any previous build leftovers, and copy a fresh working set (clean doesn't work for cross compiling) -rm -rf /deps-build && cp -r $DEP_ROOT_FOLDER /deps-build - -args=("$@") - -if [ "$STATIC" == "true" ]; then DISABLE_SHARED=-disable-shared; fi - -# Build all the dependencies -for ((i=1; i<${#args[@]}; i++)); do - dep=${args[i]} - echo "Configuring dependency $dep for $HOST..." - if [ -f "/deps-build/$dep/autogen.sh" ]; then (cd /deps-build/$dep && ./autogen.sh); fi - (cd /deps-build/$dep && ./configure $DISABLE_SHARED --host=$HOST --prefix=$PREFIX --silent) - - echo "Building dependency $dep for $HOST..." - (cd /deps-build/$dep && make --silent -j install) -done - -# Remove any build artifacts -rm -rf /deps-build diff --git a/dev-tools/packer/docker/xgo-image-deb7/base/fetch.sh b/dev-tools/packer/docker/xgo-image-deb7/base/fetch.sh deleted file mode 100644 index baeae631f1b6..000000000000 --- a/dev-tools/packer/docker/xgo-image-deb7/base/fetch.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -# -# Contains a simple fetcher to download a file from a remote URL and verify its -# SHA1 checksum. -# -# Usage: fetch.sh -set -e - -# Pull the file from the remote URL -file=`basename $1` -echo "Downloading $1..." -wget --no-check-certificate -q $1 - -# Generate a desired checksum report and check against it -echo "$2 $file" > $file.sum -sha1sum -c $file.sum -rm $file.sum diff --git a/dev-tools/packer/docker/xgo-image-deb7/beats-builder/Dockerfile b/dev-tools/packer/docker/xgo-image-deb7/beats-builder/Dockerfile deleted file mode 100644 index da39f7835097..000000000000 --- a/dev-tools/packer/docker/xgo-image-deb7/beats-builder/Dockerfile +++ /dev/null @@ -1,33 +0,0 @@ -FROM tudorg/xgo-deb7-1.10.3 - -MAINTAINER Tudor Golubenco - -# Get libpcap-32 binaries from a DEB file -RUN \ - mkdir -p /libpcap && \ - wget http://archive.debian.org/debian/pool/main/libp/libpcap/libpcap0.8-dev_1.1.1-2+squeeze1_i386.deb && \ - dpkg -x libpcap0.8-dev_*_i386.deb /libpcap/i386 && \ - rm libpcap0.8-dev*.deb - -# Get libpcap-64 binaries by compiling from source -RUN \ - apt-get update && \ - apt-get install -y flex bison -RUN ./fetch.sh http://www.tcpdump.org/release/libpcap-1.8.1.tar.gz 32d7526dde8f8a2f75baf40c01670602aeef7e39 && \ - mkdir -p /libpcap/amd64 && \ - tar -C /libpcap/amd64/ -xvf libpcap-1.8.1.tar.gz && \ - cd /libpcap/amd64/libpcap-1.8.1 && \ - ./configure --enable-usb=no --enable-bluetooth=no --enable-dbus=no && \ - make - -# Old git version which does not support proxy with go get directly, and git cloning -# from github also no longer works. -ADD yaml.v2 /go/src/gopkg.in/yaml.v2 -ADD gotpl /go/src/github.com/tsg/gotpl - -# Load gotpl which is needed for creating the templates. -RUN cd /go/src/github.com/tsg/gotpl && \ - go install - -# add patch for gopacket -ADD gopacket_pcap.patch /gopacket_pcap.patch diff --git a/dev-tools/packer/docker/xgo-image-deb7/beats-builder/gopacket_pcap.patch b/dev-tools/packer/docker/xgo-image-deb7/beats-builder/gopacket_pcap.patch deleted file mode 100644 index cc7592b7de3f..000000000000 --- a/dev-tools/packer/docker/xgo-image-deb7/beats-builder/gopacket_pcap.patch +++ /dev/null @@ -1,26 +0,0 @@ -diff --git a/vendor/github.com/tsg/gopacket/pcap/pcap.go b/vendor/github.com/tsg/gopacket/pcap/pcap.go -index f5612e6..0c77efa 100644 ---- a/vendor/github.com/tsg/gopacket/pcap/pcap.go -+++ b/vendor/github.com/tsg/gopacket/pcap/pcap.go -@@ -8,14 +8,17 @@ - package pcap - - /* --#cgo linux LDFLAGS: -lpcap -+#cgo linux,386 CFLAGS: -I/libpcap/i386/usr/include/ -+#cgo linux,386 LDFLAGS: -L/libpcap/i386/usr/lib/ -lpcap -+#cgo linux,amd64 CFLAGS: -I/libpcap/amd64/libpcap-1.8.1 -+#cgo linux,amd64 LDFLAGS: -L/libpcap/amd64/libpcap-1.8.1 -lpcap - #cgo freebsd LDFLAGS: -lpcap - #cgo openbsd LDFLAGS: -lpcap - #cgo darwin LDFLAGS: -lpcap - #cgo solaris LDFLAGS: -lpcap --#cgo windows CFLAGS: -I C:/WpdPack/Include --#cgo windows,386 LDFLAGS: -L C:/WpdPack/Lib -lwpcap --#cgo windows,amd64 LDFLAGS: -L C:/WpdPack/Lib/x64 -lwpcap -+#cgo windows CFLAGS: -I/libpcap/win/WpdPack/Include -+#cgo windows,386 LDFLAGS: -L/libpcap/win/WpdPack/Lib -lwpcap -+#cgo windows,amd64 LDFLAGS: -L/libpcap/win/WpdPack/Lib/x64 -lwpcap - #include - #include - diff --git a/dev-tools/packer/docker/xgo-image-deb7/build.sh b/dev-tools/packer/docker/xgo-image-deb7/build.sh deleted file mode 100755 index 33218c3d4046..000000000000 --- a/dev-tools/packer/docker/xgo-image-deb7/build.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -cp -r ../../../vendor/gopkg.in/yaml.v2 beats-builder/yaml.v2 -cp -r ../../../vendor/github.com/tsg/gotpl beats-builder/gotpl -docker build --rm=true -t tudorg/xgo-deb7-base base/ && \ - docker build --rm=true -t tudorg/xgo-deb7-1.10.3 go-1.10.3/ && - docker build --rm=true -t tudorg/beats-builder-deb7 beats-builder diff --git a/dev-tools/packer/docker/xgo-image-deb7/go-1.10.3/Dockerfile b/dev-tools/packer/docker/xgo-image-deb7/go-1.10.3/Dockerfile deleted file mode 100644 index 798378d8b2bb..000000000000 --- a/dev-tools/packer/docker/xgo-image-deb7/go-1.10.3/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -# Go cross compiler (xgo): Go 1.10.3 layer -# Copyright (c) 2014 Péter Szilágyi. All rights reserved. -# -# Released under the MIT license. - -FROM tudorg/xgo-deb7-base - -MAINTAINER Tudor Golubenco - -# Configure the root Go distribution and bootstrap based on it -RUN \ - export ROOT_DIST="https://storage.googleapis.com/golang/go1.10.3.linux-amd64.tar.gz" && \ - export ROOT_DIST_SHA1="dfa39cac093a7a9c94d25130671ec474d51a2995" && \ - \ - $BOOTSTRAP_PURE diff --git a/dev-tools/packer/docker/xgo-image/.gitignore b/dev-tools/packer/docker/xgo-image/.gitignore deleted file mode 100644 index 29554abab065..000000000000 --- a/dev-tools/packer/docker/xgo-image/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -beats-builder/yaml.v2 -beats-builder/gotpl diff --git a/dev-tools/packer/docker/xgo-image/base/Dockerfile b/dev-tools/packer/docker/xgo-image/base/Dockerfile deleted file mode 100644 index 81ea1eb44765..000000000000 --- a/dev-tools/packer/docker/xgo-image/base/Dockerfile +++ /dev/null @@ -1,76 +0,0 @@ -# Go cross compiler (xgo): Base cross-compilation layer -# Copyright (c) 2014 Péter Szilágyi. All rights reserved. -# -# Released under the MIT license. - -FROM ubuntu:14.04 - -MAINTAINER Tudor Golubenco - -# Configure the Go environment, since it's not going to change -ENV PATH /usr/local/go/bin:$PATH -ENV GOPATH /go - - -# Inject the remote file fetcher and checksum verifier -ADD fetch.sh /fetch.sh -ENV FETCH /fetch.sh -RUN chmod +x $FETCH - - -# Make sure apt-get is up to date and dependent packages are installed -# XXX: The first line is a workaround for the "Sum hash mismatch" error, from here: -# https://askubuntu.com/questions/760574/sudo-apt-get-update-failes-due-to-hash-sum-mismatch -RUN \ - apt-get clean && \ - apt-get update && \ - apt-get install -y automake autogen build-essential ca-certificates \ - gcc-arm-linux-gnueabi g++-arm-linux-gnueabi libc6-dev-armel-cross \ - gcc-multilib g++-multilib mingw-w64 clang llvm-dev \ - libtool libxml2-dev uuid-dev libssl-dev swig pkg-config patch \ - make xz-utils cpio wget zip unzip p7zip git mercurial bzr texinfo help2man \ - binutils-multiarch rsync \ - --no-install-recommends - -# Configure the container for OSX cross compilation -ENV OSX_SDK MacOSX10.11.sdk -ENV OSX_NDK_X86 /usr/local/osx-ndk-x86 - -RUN \ - OSX_SDK_PATH=https://github.com/phracker/MacOSX-SDKs/releases/download/MacOSX10.11.sdk/MacOSX10.11.sdk.tar.xz && \ - $FETCH $OSX_SDK_PATH f3430e3d923644e66c0c13f7a48754e7b6aa2e3f && \ - \ - git clone https://github.com/tpoechtrager/osxcross.git && \ - mv `basename $OSX_SDK_PATH` /osxcross/tarballs/ && \ - \ - sed -i -e 's|-march=native||g' /osxcross/build_clang.sh /osxcross/wrapper/build.sh && \ - UNATTENDED=yes OSX_VERSION_MIN=10.6 /osxcross/build.sh && \ - mv /osxcross/target $OSX_NDK_X86 && \ - \ - rm -rf /osxcross - -ADD patch.tar.xz $OSX_NDK_X86/SDK/$OSX_SDK/usr/include/c++ -ENV PATH $OSX_NDK_X86/bin:$PATH - - -# Inject the Go package downloader and tool-chain bootstrapper -ADD bootstrap.sh /bootstrap.sh -ENV BOOTSTRAP /bootstrap.sh -RUN chmod +x $BOOTSTRAP - -# Inject the new Go root distribution downloader and secondary bootstrapper -ADD bootstrap_pure.sh /bootstrap_pure.sh -ENV BOOTSTRAP_PURE /bootstrap_pure.sh -RUN chmod +x $BOOTSTRAP_PURE - -# Inject the C dependency cross compiler -ADD build_deps.sh /build_deps.sh -ENV BUILD_DEPS /build_deps.sh -RUN chmod +x $BUILD_DEPS - -# Inject the container entry point, the build script -ADD build.sh /build.sh -ENV BUILD /build.sh -RUN chmod +x $BUILD - -ENTRYPOINT ["/build.sh"] diff --git a/dev-tools/packer/docker/xgo-image/base/bootstrap.sh b/dev-tools/packer/docker/xgo-image/base/bootstrap.sh deleted file mode 100644 index b0d44a05a374..000000000000 --- a/dev-tools/packer/docker/xgo-image/base/bootstrap.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash -# -# Contains the Go tool-chain bootstrapper, that retrieves all the configured -# distribution packages, extracts the binaries and deletes anything not needed. -# -# Usage: bootstrap.sh -# -# Needed environment variables: -# FETCH - Remote file fetcher and checksum verifier (injected by image) -# DIST_LINUX_64, DIST_LINUX_64_SHA1 - 64 bit Linux Go binaries and checksum -# DIST_LINUX_32, DIST_LINUX_32_SHA1 - 32 bit Linux Go binaries and checksum -# DIST_LINUX_ARM, DIST_LINUX_ARM_SHA1 - ARM v5 Linux Go binaries and checksum -# DIST_OSX_64, DIST_OSX_64_SHA1 - 64 bit Mac OSX Go binaries and checksum -# DIST_OSX_32, DIST_OSX_32_SHA1 - 32 bit Mac OSX Go binaries and checksum -# DIST_WIN_64, DIST_WIN_64_SHA1 - 64 bit Windows Go binaries and checksum -# DIST_WIN_32, DIST_WIN_32_SHA1 - 32 bit Windows Go binaries and checksum -set -e - -# Download and verify all the binary packages -$FETCH $DIST_LINUX_64 $DIST_LINUX_64_SHA1 -$FETCH $DIST_LINUX_32 $DIST_LINUX_32_SHA1 -$FETCH $DIST_OSX_64 $DIST_OSX_64_SHA1 -$FETCH $DIST_WIN_64 $DIST_WIN_64_SHA1 -$FETCH $DIST_WIN_32 $DIST_WIN_32_SHA1 - -# Extract the 64 bit Linux package as the primary Go SDK -tar -C /usr/local -xzf `basename $DIST_LINUX_64` - -# Extract all other packages as secondary ones, keeping only the binaries -tar -C /usr/local --wildcards -xzf `basename $DIST_LINUX_32` go/pkg/linux_386* -GOOS=linux GOARCH=386 /usr/local/go/pkg/tool/linux_amd64/dist bootstrap -tar -C /usr/local --wildcards -xzf `basename $DIST_LINUX_ARM` go/pkg/linux_arm* -GOOS=linux GOARCH=arm /usr/local/go/pkg/tool/linux_amd64/dist bootstrap - -tar -C /usr/local --wildcards -xzf `basename $DIST_OSX_64` go/pkg/darwin_amd64* -GOOS=darwin GOARCH=amd64 /usr/local/go/pkg/tool/linux_amd64/dist bootstrap -tar -C /usr/local --wildcards -xzf `basename $DIST_OSX_32` go/pkg/darwin_386* -GOOS=darwin GOARCH=386 /usr/local/go/pkg/tool/linux_amd64/dist bootstrap - -unzip -d /usr/local -q `basename $DIST_WIN_64` go/pkg/windows_amd64* -GOOS=windows GOARCH=amd64 /usr/local/go/pkg/tool/linux_amd64/dist bootstrap -unzip -d /usr/local -q `basename $DIST_WIN_32` go/pkg/windows_386* -GOOS=windows GOARCH=386 /usr/local/go/pkg/tool/linux_amd64/dist bootstrap - -# Delete all the intermediate downloaded files -rm -f `basename $DIST_LINUX_64` `basename $DIST_LINUX_32` `basename $DIST_LINUX_ARM` \ - `basename $DIST_OSX_64` `basename $DIST_OSX_32` \ - `basename $DIST_WIN_64` `basename $DIST_WIN_32` diff --git a/dev-tools/packer/docker/xgo-image/base/bootstrap_pure.sh b/dev-tools/packer/docker/xgo-image/base/bootstrap_pure.sh deleted file mode 100644 index 98b04d394974..000000000000 --- a/dev-tools/packer/docker/xgo-image/base/bootstrap_pure.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash -# -# Contains the Go tool-chain pure-Go bootstrapper, that as of Go 1.5, initiates -# not only a few pre-built Go cross compilers, but rather bootstraps all of the -# supported platforms from the origin Linux amd64 distribution. -# -# Usage: bootstrap.sh -# -# Needed environment variables: -# FETCH - Remote file fetcher and checksum verifier (injected by image) -# ROOT_DIST - 64 bit Linux Go binary distribution package -# ROOT_DIST_SHA1 - 64 bit Linux Go distribution package checksum -set -e - -# Download, verify and install the root distribution -$FETCH $ROOT_DIST $ROOT_DIST_SHA1 - -tar -C /usr/local -xzf `basename $ROOT_DIST` -rm -f `basename $ROOT_DIST` - -export GOROOT=/usr/local/go -export GOROOT_BOOTSTRAP=$GOROOT - -# Pre-build all guest distributions based on the root distribution -echo "Bootstrapping linux/386..." -GOOS=linux GOARCH=386 CGO_ENABLED=1 go install std - -echo "Bootstrapping linux/arm..." -GOOS=linux GOARCH=arm CGO_ENABLED=1 CC=arm-linux-gnueabi-gcc go install std - -echo "Bootstrapping windows/amd64..." -GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc go install std - -echo "Bootstrapping windows/386..." -GOOS=windows GOARCH=386 CGO_ENABLED=1 CC=i686-w64-mingw32-gcc go install std - -echo "Bootstrapping darwin/amd64..." -GOOS=darwin GOARCH=amd64 CGO_ENABLED=1 CC=o64-clang go install std - -echo "Bootstrapping darwin/386..." -GOOS=darwin GOARCH=386 CGO_ENABLED=1 CC=o32-clang go install std diff --git a/dev-tools/packer/docker/xgo-image/base/build.sh b/dev-tools/packer/docker/xgo-image/base/build.sh deleted file mode 100644 index 50adedb1fa04..000000000000 --- a/dev-tools/packer/docker/xgo-image/base/build.sh +++ /dev/null @@ -1,207 +0,0 @@ -#!/bin/bash -# -# Contains the main cross compiler, that individually sets up each target build -# platform, compiles all the C dependencies, then build the requested executable -# itself. -# -# Usage: build.sh -# -# Needed environment variables: -# REPO_REMOTE - Optional VCS remote if not the primary repository is needed -# REPO_BRANCH - Optional VCS branch to use, if not the master branch -# DEPS - Optional list of C dependency packages to build -# PACK - Optional sub-package, if not the import path is being built -# OUT - Optional output prefix to override the package name -# FLAG_V - Optional verbosity flag to set on the Go builder -# FLAG_RACE - Optional race flag to set on the Go builder -# TARGETS - Comma separated list of build targets to compile for - - - -# Download the canonical import path (may fail, don't allow failures beyond) -SRC_FOLDER=$SOURCE - -DST_FOLDER=`dirname $GOPATH/src/$BEAT_PATH` -GIT_REPO=$BEAT_PATH - -if [ "$PUREGO" == "yes" ]; then - CGO_ENABLED=0 -else - CGO_ENABLED=1 -fi - -# If it is an official beat, libbeat is not vendored, need special treatment -if [[ $GIT_REPO == "github.com/elastic/beats"* ]]; then - echo "Overwrite directories because official beat" - DST_FOLDER=$GOPATH/src/github.com/elastic/beats - GIT_REPO=github.com/elastic/beats -fi - -# It is assumed all dependencies are inside the working directory -# The working directory is the parent of the beat directory -WORKING_DIRECTORY=$DST_FOLDER - -echo "Working directory=$WORKING_DIRECTORY" - -if [ "$SOURCE" != "" ]; then - mkdir -p ${DST_FOLDER} - echo "Copying main source folder ${SRC_FOLDER} to folder ${DST_FOLDER}" - rsync --exclude ".git" --exclude "build/" -a ${SRC_FOLDER}/ ${DST_FOLDER} -else - mkdir -p $GOPATH/src/${GIT_REPO} - cd $GOPATH/src/${GIT_REPO} - echo "Fetching main git repository ${GIT_REPO} in folder $GOPATH/src/${GIT_REPO}" - git clone https://${GIT_REPO}.git -fi - -set -e - -cd $WORKING_DIRECTORY - -# Switch over the code-base to another checkout if requested -if [ "$REPO_REMOTE" != "" ]; then - echo "Switching over to remote $REPO_REMOTE..." - if [ -d ".git" ]; then - git remote set-url origin $REPO_REMOTE - git pull - elif [ -d ".hg" ]; then - echo -e "[paths]\ndefault = $REPO_REMOTE\n" >> .hg/hgrc - hg pull - fi -fi - -if [ "$REPO_BRANCH" != "" ]; then - echo "Switching over to branch $REPO_BRANCH..." - if [ -d ".git" ]; then - git checkout $REPO_BRANCH - elif [ -d ".hg" ]; then - hg checkout $REPO_BRANCH - fi -fi - -# Download all the C dependencies -echo "Fetching dependencies..." -BUILD_DEPS=/build_deps.sh -DEPS_FOLDER=/deps -LIST_DEPS="" -mkdir -p $DEPS_FOLDER -DEPS=($DEPS) && for dep in "${DEPS[@]}"; do - dep_filename=${dep##*/} - echo "Downloading $dep to $DEPS_FOLDER/$dep_filename" - wget -q $dep --directory-prefix=$DEPS_FOLDER - dep_name=$(tar --list --no-recursion --file=$DEPS_FOLDER/$dep_filename --exclude="*/*" | sed 's/\///g') - LIST_DEPS="${LIST_DEPS} ${dep_name}" - if [ "${dep_filename##*.}" == "tar" ]; then tar -xf $DEPS_FOLDER/$dep_filename --directory $DEPS_FOLDER/ ; fi - if [ "${dep_filename##*.}" == "gz" ]; then tar -xzf $DEPS_FOLDER/$dep_filename --directory $DEPS_FOLDER/ ; fi - if [ "${dep_filename##*.}" == "bz2" ]; then tar -xj $DEPS_FOLDER/$dep_filename --directory $DEPS_FOLDER/ ; fi -done - -# Configure some global build parameters -NAME=${PACK} -if [ "$OUT" != "" ]; then - NAME=$OUT -fi - - -if [ "$FLAG_V" == "true" ]; then V=-v; fi -if [ "$FLAG_RACE" == "true" ]; then R=-race; fi - -# exactly one -ldflags allowed -LDFLAGS_STATIC="" -if [ "$STATIC" == "true" ]; then LDFLAGS_STATIC='-extldflags "-static"'; fi -NOW=$(date -u '+%Y-%m-%dT%H:%M:%SZ') -LDFLAGS_VERSION="-X=github.com/elastic/beats/libbeat/version.buildTime=${NOW} -X=github.com/elastic/beats/libbeat/version.commit=${BUILDID}" -LDFLAGS_VENDOR_VERSION="-X=${BEAT_PATH}/vendor/github.com/elastic/beats/libbeat/version.buildTime=${NOW} -X=${BEAT_PATH}/vendor/github.com/elastic/beats/libbeat/version.commit=${BUILDID}" -LDFLAGS="${LDFLAGS_VERSION} ${LDFLAGS_VENDOR_VERSION} ${LDFLAGS_STATIC}" - -if [ -n $BEFORE_BUILD ]; then - chmod +x /scripts/$BEFORE_BUILD - echo "Execute /scripts/$BEFORE_BUILD ${BEAT_PATH} ${ES_BEATS}" - /scripts/$BEFORE_BUILD -fi - - -# If no build targets were specified, inject a catch all wildcard -if [ "$TARGETS" == "" ]; then - TARGETS="./." -fi - - -for TARGET in $TARGETS; do - # Split the target into platform and architecture - XGOOS=`echo $TARGET | cut -d '/' -f 1` - XGOARCH=`echo $TARGET | cut -d '/' -f 2` - - # Check and build for Linux targets - if ([ $XGOOS == "." ] || [ $XGOOS == "linux" ]) && ([ $XGOARCH == "." ] || [ $XGOARCH == "amd64" ]); then - echo "Compiling $PACK for linux/amd64..." - HOST=x86_64-linux PREFIX=/usr/local $BUILD_DEPS /deps $LIST_DEPS - export PKG_CONFIG_PATH=/usr/aarch64-linux-gnu/lib/pkgconfig - - GOOS=linux GOARCH=amd64 CGO_ENABLED=${CGO_ENABLED} go get -d ./$PACK - sh -c "GOOS=linux GOARCH=amd64 CGO_ENABLED=${CGO_ENABLED} go build $V $R -ldflags=\"${LDFLAGS}\" -o /build/$NAME-linux-amd64$R ./$PACK" - fi - if ([ $XGOOS == "." ] || [ $XGOOS == "linux" ]) && ([ $XGOARCH == "." ] || [ $XGOARCH == "386" ]); then - echo "Compiling $PACK for linux/386..." - CFLAGS=-m32 CXXFLAGS=-m32 LDFLAGS=-m32 HOST=i686-linux PREFIX=/usr/local $BUILD_DEPS /deps $LIST_DEPS - GOOS=linux GOARCH=386 CGO_ENABLED=${CGO_ENABLED} go get -d ./$PACK - sh -c "GOOS=linux GOARCH=386 CGO_ENABLED=${CGO_ENABLED} go build $V $R -ldflags=\"${LDFLAGS}\" -o /build/$NAME-linux-386$R ./$PACK" - fi - if ([ $XGOOS == "." ] || [ $XGOOS == "linux" ]) && ([ $XGOARCH == "." ] || [ $XGOARCH == "arm" ]); then - echo "Compiling $PACK for linux/arm..." - CC=arm-linux-gnueabi-gcc CXX=rm-linux-gnueabi-g++ HOST=arm-linux PREFIX=/usr/local/arm $BUILD_DEPS /deps $LIST_DEPS - - CC=arm-linux-gnueabi-gcc CXX=rm-linux-gnueabi-g++ GOOS=linux GOARCH=arm CGO_ENABLED=${CGO_ENABLED} GOARM=5 go get -d ./$PACK - CC=arm-linux-gnueabi-gcc CXX=rm-linux-gnueabi-g++ GOOS=linux GOARCH=arm CGO_ENABLED=${CGO_ENABLED} GOARM=5 go build $V -ldflags="${LDFLAGS}" -o /build/$NAME-linux-arm ./$PACK - fi - - # Check and build for Windows targets - if [ $XGOOS == "." ] || [[ $XGOOS == windows* ]]; then - # Split the platform version and configure the Windows NT version - PLATFORM=`echo $XGOOS | cut -d '-' -f 2` - if [ "$PLATFORM" == "" ] || [ "$PLATFORM" == "." ] || [ "$PLATFORM" == "windows" ]; then - PLATFORM=4.0 # Windows NT - fi - - MAJOR=`echo $PLATFORM | cut -d '.' -f 1` - if [ "${PLATFORM/.}" != "$PLATFORM" ] ; then - MINOR=`echo $PLATFORM | cut -d '.' -f 2` - fi - CGO_NTDEF="-D_WIN32_WINNT=0x`printf "%02d" $MAJOR``printf "%02d" $MINOR`" - - # Build the requested windows binaries - if [ $XGOARCH == "." ] || [ $XGOARCH == "amd64" ]; then - echo "Compiling $PACK for windows-$PLATFORM/amd64..." - CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ CFLAGS="$CGO_NTDEF" CXXFLAGS="$CGO_NTDEF" HOST=x86_64-w64-mingw32 PREFIX=/usr/x86_64-w64-mingw32 $BUILD_DEPS /deps $LIST_DEPS - export PKG_CONFIG_PATH=/usr/x86_64-w64-mingw32/lib/pkgconfig - - CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ GOOS=windows GOARCH=amd64 CGO_ENABLED=${CGO_ENABLED} CGO_CFLAGS="$CGO_NTDEF" CGO_CXXFLAGS="$CGO_NTDEF" go get -d ./$PACK - CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ GOOS=windows GOARCH=amd64 CGO_ENABLED=${CGO_ENABLED} CGO_CFLAGS="$CGO_NTDEF" CGO_CXXFLAGS="$CGO_NTDEF" go build $V $R -ldflags="${LDFLAGS}" -o /build/$NAME-windows-amd64$R.exe ./$PACK - fi - - if [ $XGOARCH == "." ] || [ $XGOARCH == "386" ]; then - echo "Compiling $PACK for windows-$PLATFORM/386..." - CC=i686-w64-mingw32-gcc CXX=i686-w64-mingw32-g++ CFLAGS="$CGO_NTDEF" CXXFLAGS="$CGO_NTDEF" HOST=i686-w64-mingw32 PREFIX=/usr/i686-w64-mingw32 $BUILD_DEPS /deps $LIST_DEPS - export PKG_CONFIG_PATH=/usr/i686-w64-mingw32/lib/pkgconfig - - CC=i686-w64-mingw32-gcc CXX=i686-w64-mingw32-g++ GOOS=windows GOARCH=386 CGO_ENABLED=${CGO_ENABLED} CGO_CFLAGS="$CGO_NTDEF" CGO_CXXFLAGS="$CGO_NTDEF" go get -d ./$PACK - CC=i686-w64-mingw32-gcc CXX=i686-w64-mingw32-g++ GOOS=windows GOARCH=386 CGO_ENABLED=${CGO_ENABLED} CGO_CFLAGS="$CGO_NTDEF" CGO_CXXFLAGS="$CGO_NTDEF" go build $V -ldflags="${LDFLAGS}" -o /build/$NAME-windows-386.exe ./$PACK - fi - fi - - # Check and build for OSX targets - if ([ $XGOOS == "." ] || [ $XGOOS == "darwin" ]) && ([ $XGOARCH == "." ] || [ $XGOARCH == "amd64" ]); then - echo "Compiling $PACK for darwin/amd64..." - CC=o64-clang CXX=o64-clang++ HOST=x86_64-apple-darwin10 PREFIX=/usr/local $BUILD_DEPS /deps $LIST_DEPS - CC=o64-clang CXX=o64-clang++ GOOS=darwin GOARCH=amd64 CGO_ENABLED=${CGO_ENABLED} go get -d ./$PACK - CC=o64-clang CXX=o64-clang++ GOOS=darwin GOARCH=amd64 CGO_ENABLED=${CGO_ENABLED} go build $V $R -ldflags="-s ${LDFLAGS}" -o /build/$NAME-darwin-amd64$R ./$PACK - fi - if ([ $XGOOS == "." ] || [ $XGOOS == "darwin" ]) && ([ $XGOARCH == "." ] || [ $XGOARCH == "386" ]); then - echo "Compiling for darwin/386..." - CC=o32-clang CXX=o32-clang++ HOST=i386-apple-darwin10 PREFIX=/usr/local $BUILD_DEPS /deps $LIST_DEPS - CC=o32-clang CXX=o32-clang++ GOOS=darwin GOARCH=386 CGO_ENABLED=${CGO_ENABLED} go get -d ./$PACK - CC=o32-clang CXX=o32-clang++ GOOS=darwin GOARCH=386 CGO_ENABLED=${CGO_ENABLED} go build $V -ldflags="${LDFLAGS}" -o /build/$NAME-darwin-386 ./$PACK - fi -done - -echo "Build process completed" diff --git a/dev-tools/packer/docker/xgo-image/base/build_deps.sh b/dev-tools/packer/docker/xgo-image/base/build_deps.sh deleted file mode 100644 index e6445b95ed9a..000000000000 --- a/dev-tools/packer/docker/xgo-image/base/build_deps.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash -# -# Contains the dependency builder to iterate over all installed dependencies -# and cross compile them to the requested target platform. -# -# Usage: build_deps.sh dependency_root_folder dependency1 dependency_2 ... -# -# Needed environment variables: -# CC - C cross compiler to use for the build -# HOST - Target platform to build (used to find the needed tool-chains) -# PREFIX - File-system path where to install the built binaries -# STATIC - true if the libraries are statically linked to the go application -set -e - -DEP_ROOT_FOLDER=$1 - -# Remove any previous build leftovers, and copy a fresh working set (clean doesn't work for cross compiling) -rm -rf /deps-build && cp -r $DEP_ROOT_FOLDER /deps-build - -args=("$@") - -if [ "$STATIC" == "true" ]; then DISABLE_SHARED=-disable-shared; fi - -# Build all the dependencies -for ((i=1; i<${#args[@]}; i++)); do - dep=${args[i]} - echo "Configuring dependency $dep for $HOST..." - if [ -f "/deps-build/$dep/autogen.sh" ]; then (cd /deps-build/$dep && ./autogen.sh); fi - (cd /deps-build/$dep && ./configure $DISABLE_SHARED --host=$HOST --prefix=$PREFIX --silent) - - echo "Building dependency $dep for $HOST..." - (cd /deps-build/$dep && make --silent -j install) -done - -# Remove any build artifacts -rm -rf /deps-build diff --git a/dev-tools/packer/docker/xgo-image/base/fetch.sh b/dev-tools/packer/docker/xgo-image/base/fetch.sh deleted file mode 100644 index d0b50399e70c..000000000000 --- a/dev-tools/packer/docker/xgo-image/base/fetch.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -# -# Contains a simple fetcher to download a file from a remote URL and verify its -# SHA1 checksum. -# -# Usage: fetch.sh -set -e - -# Pull the file from the remote URL -file=`basename $1` -echo "Downloading $1..." -wget -q $1 - -# Generate a desired checksum report and check against it -echo "$2 $file" > $file.sum -sha1sum -c $file.sum -rm $file.sum diff --git a/dev-tools/packer/docker/xgo-image/base/patch.tar.xz b/dev-tools/packer/docker/xgo-image/base/patch.tar.xz deleted file mode 100644 index bff5da4eafaa47f9cfb7b68bb7ee51277d4c4546..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 294820 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 z®X1kLj25SPU)vP$~_sgg^l8`ZfqrBs;V2UxjE*ZR^@h2J+RB{x+G>f!S_zmmJ{ zqFsN?ElGb>QOEF*{|jz?tT6F@SoQ#_ohart5xk4-(!*`vMw8K3?Hbg_aN}Ic^z+5l z-00Z|wO*oHkl75`1U*J~Cshu^_|>X#U|}{UOcnv2&Kn6LhqJbG9x8G|L(0VD6+{D$ zzp5*NN`asGjy5Bbn5hf|bJqbcn3`eOg~0{x31@6~CjwgKon^+#r-=QNt6*tz*Oo1a zY95xnub@dFBb#Y1xe6#20^c*k*$H)6p`%GuFGYb^uFi3Nhq=9~-zmZ_2x#T0Rt1PU zCqxVAa%@ToI?6>~Rl5H{K}IV+TH)i9$}lzgl#X2xfX3Ml7VmP<9P^`c2@+%~~#Ia{g7zRG)ELFMmBeE5h|d(=itG_%SEY4>Pp9RL}`ByHe| z;MgJQy!ZT1DN*bDmFv)`s=N1%`(tOF2bz6T|pn$r#ists*e(;tptM8vK~ttjFgd_6ru@U z`UrupE{k)2=|+VoP*}DI0QUodKhZl1LHS5skyAqzT~5wM&n8vcSp7jNQ0U0)F&&Z3 z`g%#$HqB}v*r7L?PA-4jc^f|`&J>#(o$EeFelMQFiF1-0@=t>(k?{b@+!P06Y)2`f%T z?rqdErb?OCgmCnkxww*s%S??+>vK&;>ImGQ3PWKJAY&7Kf*&ayJ33gahyT>n(tCM? zwQ!rQC_klDtU{*FEVCXJ==;MLXZT8s$QY9@H!n@s{+B5fsCC1smww{b&C?Ea0NV(hE%* zP<*&=bM;gmcTaDCS32*si){N6Q)h%bz>8=_8gy|X?NUDt+rb|>TG|qgIYZZ?Qh^o; zom6=6&DI<3aiE5e3%0e}z*6{|T@Rq#Bl%28`SmBmC0P1wQAGu*t)=DwST-PyZtx1` zo)v@i&WvY#oJDTK6p?|U$5NhXg(A-lMG%kzPbPXMH*|4NM&o(n3=G%WJrVW{yEB8o z(({yNsPI!Ip)OSVZCB*pUdXZ`s)}Z(gj{0cVwjN zrX4L-XEEvVXgWfOBe-fW1WCq>?r>^@@M$d_v#?lP?FzN(B2etgJ(tp5Al

?va8l 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 X0RR91NZYEY6c;-%0{{R300dcDz9W;H diff --git a/dev-tools/packer/docker/xgo-image/beats-builder/Dockerfile b/dev-tools/packer/docker/xgo-image/beats-builder/Dockerfile deleted file mode 100644 index 00ae34ca59ed..000000000000 --- a/dev-tools/packer/docker/xgo-image/beats-builder/Dockerfile +++ /dev/null @@ -1,47 +0,0 @@ -FROM tudorg/xgo-1.10.3 - -MAINTAINER Tudor Golubenco - -# Get libpcap binaries for linux -RUN \ - dpkg --add-architecture i386 && \ - apt-get update && \ - apt-get install -y libpcap0.8-dev - -RUN \ - mkdir -p /libpcap && \ - apt-get download libpcap0.8-dev:i386 && \ - dpkg -x libpcap0.8-dev_*_i386.deb /libpcap/i386 && \ - apt-get download libpcap0.8-dev && \ - dpkg -x libpcap0.8-dev_*_amd64.deb /libpcap/amd64 && \ - rm libpcap0.8-dev*.deb - - -# Get libpcap binaries for win -ENV WPDPACK_URL https://www.winpcap.org/install/bin/WpdPack_4_1_2.zip -RUN \ - ./fetch.sh $WPDPACK_URL f5c80885bd48f07f41833d0f65bf85da1ef1727a && \ - unzip `basename $WPDPACK_URL` -d /libpcap/win && \ - rm `basename $WPDPACK_URL` - -# Load gotpl -ADD yaml.v2 /go/src/gopkg.in/yaml.v2 -ADD gotpl /go/src/github.com/tsg/gotpl -RUN cd /go/src/github.com/tsg/gotpl && \ - go install - -# Add patch for gopacket. -ADD gopacket_pcap.patch /gopacket_pcap.patch - -# Add the wpcap.dll from the WinPcap_4_1_2.exe installer so that -# we can generate a 64-bit compatible libwpcap.a. -ENV WINPCAP_DLL_SHA1 d2afb08d0379bd96e423857963791e2ba00c9645 -ADD wpcap.dll /libpcap/win/wpcap.dll -RUN \ - apt-get install mingw-w64-tools && \ - cd /libpcap/win && \ - echo "$WINPCAP_DLL_SHA1 wpcap.dll" | sha1sum -c - && \ - gendef /libpcap/win/wpcap.dll && \ - x86_64-w64-mingw32-dlltool --as-flags=--64 -m i386:x86-64 -k --output-lib /libpcap/win/WpdPack/Lib/x64/libwpcap.a --input-def wpcap.def && \ - rm wpcap.def wpcap.dll - diff --git a/dev-tools/packer/docker/xgo-image/beats-builder/gopacket_pcap.patch b/dev-tools/packer/docker/xgo-image/beats-builder/gopacket_pcap.patch deleted file mode 100644 index b3c3407a14aa..000000000000 --- a/dev-tools/packer/docker/xgo-image/beats-builder/gopacket_pcap.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff --git a/vendor/github.com/tsg/gopacket/pcap/pcap.go b/vendor/github.com/tsg/gopacket/pcap/pcap.go -index f5612e6..4438e6f 100644 ---- a/vendor/github.com/tsg/gopacket/pcap/pcap.go -+++ b/vendor/github.com/tsg/gopacket/pcap/pcap.go -@@ -8,14 +8,15 @@ - package pcap - - /* --#cgo linux LDFLAGS: -lpcap -+#cgo linux,386 LDFLAGS: /libpcap/i386/usr/lib/i386-linux-gnu/libpcap.a -+#cgo linux,amd64 LDFLAGS: /libpcap/amd64/usr/lib/x86_64-linux-gnu/libpcap.a - #cgo freebsd LDFLAGS: -lpcap - #cgo openbsd LDFLAGS: -lpcap - #cgo darwin LDFLAGS: -lpcap - #cgo solaris LDFLAGS: -lpcap --#cgo windows CFLAGS: -I C:/WpdPack/Include --#cgo windows,386 LDFLAGS: -L C:/WpdPack/Lib -lwpcap --#cgo windows,amd64 LDFLAGS: -L C:/WpdPack/Lib/x64 -lwpcap -+#cgo windows CFLAGS: -I /libpcap/win/WpdPack/Include -+#cgo windows,386 LDFLAGS: -L /libpcap/win/WpdPack/Lib -lwpcap -+#cgo windows,amd64 LDFLAGS: -L /libpcap/win/WpdPack/Lib/x64 -lwpcap - #include - #include - diff --git a/dev-tools/packer/docker/xgo-image/beats-builder/wpcap.dll b/dev-tools/packer/docker/xgo-image/beats-builder/wpcap.dll deleted file mode 100644 index ebb17ad55c754a57be4cf1916d729d1f804ed930..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 281104 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�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 diff --git a/dev-tools/packer/docker/xgo-image/build.sh b/dev-tools/packer/docker/xgo-image/build.sh deleted file mode 100755 index 298b606eabc3..000000000000 --- a/dev-tools/packer/docker/xgo-image/build.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -cp -r ../../../vendor/gopkg.in/yaml.v2 beats-builder/yaml.v2 -cp -r ../../../vendor/github.com/tsg/gotpl beats-builder/gotpl -docker pull tudorg/xgo-base:v20180222 && \ - docker build --rm=true -t tudorg/xgo-1.10.3 go-1.10.3/ && - docker build --rm=true -t tudorg/beats-builder beats-builder diff --git a/dev-tools/packer/docker/xgo-image/go-1.10.3/Dockerfile b/dev-tools/packer/docker/xgo-image/go-1.10.3/Dockerfile deleted file mode 100644 index edf768f22aa2..000000000000 --- a/dev-tools/packer/docker/xgo-image/go-1.10.3/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -# Go cross compiler (xgo): Go 1.10.3 layer -# Copyright (c) 2014 Péter Szilágyi. All rights reserved. -# -# Released under the MIT license. - -FROM tudorg/xgo-base - -MAINTAINER Tudor Golubenco - -# Configure the root Go distribution and bootstrap based on it -RUN \ - export ROOT_DIST="https://storage.googleapis.com/golang/go1.10.3.linux-amd64.tar.gz" && \ - export ROOT_DIST_SHA1="dfa39cac093a7a9c94d25130671ec474d51a2995" && \ - \ - $BOOTSTRAP_PURE diff --git a/dev-tools/packer/docker/xgo-image/push_image.md b/dev-tools/packer/docker/xgo-image/push_image.md deleted file mode 100644 index 30e6c2af9318..000000000000 --- a/dev-tools/packer/docker/xgo-image/push_image.md +++ /dev/null @@ -1,16 +0,0 @@ -XXX: this should be temporary until we can use the Elastic Registry. - -To update the `tudorg/xgo-base` image on Docker HUB, do the following: - -* `docker login` with your docker hub credentials. Feel free to publish the image - to your own account if Tudor is not available. - -* Build the image: `docker build --rm=true -t tudorg/xgo-base base/` - -* List the images: `docker images` - -* Tag it: `docker tag tudorg/xgo-base:$(date '+v%Y%m%d')` - -* Push: `docker push tudorg/xgo-base` - -* Update `build.sh` to use the new image/tag diff --git a/dev-tools/packer/platforms/README b/dev-tools/packer/platforms/README deleted file mode 100644 index 60935fa5467c..000000000000 --- a/dev-tools/packer/platforms/README +++ /dev/null @@ -1 +0,0 @@ -Pseudo-platform to build the dashboards in their own package. diff --git a/dev-tools/packer/platforms/binary/build.sh b/dev-tools/packer/platforms/binary/build.sh deleted file mode 100755 index 06ee52052a77..000000000000 --- a/dev-tools/packer/platforms/binary/build.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -set -e - -BASEDIR=$(dirname "$0") -ARCHDIR=${BASEDIR}/../../ - -# executed from the top directory -runid=binary-$BEAT-$ARCH - -cat ${BUILD_DIR}/package.yml ${ARCHDIR}/archs/$ARCH.yml > ${BUILD_DIR}/settings-$runid.yml -gotpl ${BASEDIR}/run.sh.j2 < ${BUILD_DIR}/settings-$runid.yml > ${BUILD_DIR}/run-$runid.sh -chmod +x ${BUILD_DIR}/run-$runid.sh - -docker run --rm -v ${BUILD_DIR}:/build -v ${UPLOAD_DIR}:/upload \ - -e BUILDID=$BUILDID -e SNAPSHOT=$SNAPSHOT -e RUNID=$runid -e BEAT_REF_YAML=$BEAT_REF_YAML \ - tudorg/fpm /build/run-$runid.sh - -rm ${BUILD_DIR}/settings-$runid.yml ${BUILD_DIR}/run-$runid.sh diff --git a/dev-tools/packer/platforms/binary/run.sh.j2 b/dev-tools/packer/platforms/binary/run.sh.j2 deleted file mode 100644 index 05eaadeecff9..000000000000 --- a/dev-tools/packer/platforms/binary/run.sh.j2 +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash - -# this is executed in the docker fpm image -set -e -cd /build - -# add SNAPSHOT if it was requested -VERSION={{.version}} -if [ "$SNAPSHOT" = "yes" ]; then - VERSION="${VERSION}-SNAPSHOT" -fi - -BEATS_YML_NAME="{{.beat_name}}-linux-{{.arch}}" -[ -f "${BEATS_YML_NAME}.yml" ] || BEATS_YML_NAME="{{.beat_name}}-linux" - -mkdir /{{.beat_name}}-${VERSION}-linux-{{.bin_arch}} -cp -a homedir/. /{{.beat_name}}-${VERSION}-linux-{{.bin_arch}}/ -cp {{.beat_name}}-linux-{{.arch}} /{{.beat_name}}-${VERSION}-linux-{{.bin_arch}}/{{.beat_name}} -cp ${BEATS_YML_NAME}.yml /{{.beat_name}}-${VERSION}-linux-{{.bin_arch}}/{{.beat_name}}.yml -if [ -z "${BEAT_REF_YAML}" ] || [ ${BEAT_REF_YAML} = true ]; then - cp ${BEATS_YML_NAME}.reference.yml /{{.beat_name}}-${VERSION}-linux-{{.bin_arch}}/{{.beat_name}}.reference.yml -fi -cp fields.yml /{{.beat_name}}-${VERSION}-linux-{{.bin_arch}}/ -cp -a modules.d-linux/ /{{.beat_name}}-${VERSION}-linux-{{.bin_arch}}/modules.d || true - -tar czvf /upload/{{.beat_name}}{{.beat_pkg_suffix}}-${VERSION}-linux-{{.bin_arch}}.tar.gz /{{.beat_name}}-${VERSION}-linux-{{.bin_arch}} -echo "Created /upload/{{.beat_name}}{{.beat_pkg_suffix}}--${VERSION}-linux-{{.bin_arch}}.tar.gz" - -cd /upload -sha512sum {{.beat_name}}{{.beat_pkg_suffix}}-${VERSION}-linux-{{.bin_arch}}.tar.gz > {{.beat_name}}{{.beat_pkg_suffix}}-${VERSION}-linux-{{.bin_arch}}.tar.gz.sha512 -echo "Created /upload/{{.beat_name}}{{.beat_pkg_suffix}}-${VERSION}-linux-{{.bin_arch}}.tar.gz.sha512" diff --git a/dev-tools/packer/platforms/centos/beatname.sh.j2 b/dev-tools/packer/platforms/centos/beatname.sh.j2 deleted file mode 100644 index 2601507722c9..000000000000 --- a/dev-tools/packer/platforms/centos/beatname.sh.j2 +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -# Script to run {.beat_name} in foreground with the same path settings that -# the init script / systemd unit file would do. - -exec /usr/share/{{.beat_name}}/bin/{{.beat_name}} \ - -path.home /usr/share/{{.beat_name}} \ - -path.config /etc/{{.beat_name}} \ - -path.data /var/lib/{{.beat_name}} \ - -path.logs /var/log/{{.beat_name}} \ - "$@" diff --git a/dev-tools/packer/platforms/centos/build.sh b/dev-tools/packer/platforms/centos/build.sh deleted file mode 100755 index 7198928f26b1..000000000000 --- a/dev-tools/packer/platforms/centos/build.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh - -set -e - -BASEDIR=$(dirname "$0") -ARCHDIR=${BASEDIR}/../../ - -# executed from the top directory -runid=centos-$BEAT-$ARCH - -cat ${BUILD_DIR}/package.yml ${ARCHDIR}/archs/$ARCH.yml > ${BUILD_DIR}/settings-$runid.yml -gotpl ${BASEDIR}/run.sh.j2 < ${BUILD_DIR}/settings-$runid.yml > ${BUILD_DIR}/run-$runid.sh -chmod +x ${BUILD_DIR}/run-$runid.sh -gotpl ${BASEDIR}/init.j2 < ${BUILD_DIR}/settings-$runid.yml > ${BUILD_DIR}/$runid.init -gotpl ${BASEDIR}/systemd.j2 < ${BUILD_DIR}/settings-$runid.yml > ${BUILD_DIR}/$runid.service -gotpl ${BASEDIR}/beatname.sh.j2 < ${BUILD_DIR}/settings-$runid.yml > ${BUILD_DIR}/beatname-$runid.sh -chmod +x ${BUILD_DIR}/beatname-$runid.sh - -docker run --rm -v ${BUILD_DIR}:/build -v ${UPLOAD_DIR}:/upload \ - -e BUILDID=$BUILDID -e SNAPSHOT=$SNAPSHOT -e RUNID=$runid -e BEAT_REF_YAML=$BEAT_REF_YAML \ - tudorg/fpm /build/run-$runid.sh - -rm ${BUILD_DIR}/settings-$runid.yml ${BUILD_DIR}/run-$runid.sh diff --git a/dev-tools/packer/platforms/centos/init.j2 b/dev-tools/packer/platforms/centos/init.j2 deleted file mode 100755 index f713575539e3..000000000000 --- a/dev-tools/packer/platforms/centos/init.j2 +++ /dev/null @@ -1,119 +0,0 @@ -#!/bin/bash -# -# {{.beat_pkg_name}} {{.beat_name}} shipper -# -# chkconfig: 2345 98 02 -# description: Starts and stops a single {{.beat_name}} instance on this system -# - -### BEGIN INIT INFO -# Provides: {{.beat_pkg_name}} -# Required-Start: $local_fs $network $syslog -# Required-Stop: $local_fs $network $syslog -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: {{.beat_description}} -# Description: {{.beat_name}} is a shipper part of the Elastic Beats -# family. Please see: https://www.elastic.co/products/beats -### END INIT INFO - - - -PATH=/usr/bin:/sbin:/bin:/usr/sbin -export PATH - -[ -f /etc/sysconfig/{{.beat_pkg_name}} ] && . /etc/sysconfig/{{.beat_pkg_name}} -pidfile=${PIDFILE-/var/run/{{.beat_pkg_name}}.pid} -agent=${BEATS_AGENT-/usr/share/{{.beat_name}}/bin/{{.beat_name}}} -args="-c /etc/{{.beat_name}}/{{.beat_name}}.yml -path.home /usr/share/{{.beat_name}} -path.config /etc/{{.beat_name}} -path.data /var/lib/{{.beat_name}} -path.logs /var/log/{{.beat_name}}" -test_args="-e test config" -beat_user="${BEAT_USER:-root}" -wrapper="/usr/share/{{.beat_name}}/bin/{{.beat_name}}-god" -wrapperopts="-r / -n -p $pidfile" -user_wrapper="su" -user_wrapperopts="$beat_user -c" -RETVAL=0 - -# Source function library. -. /etc/rc.d/init.d/functions - -# Determine if we can use the -p option to daemon, killproc, and status. -# RHEL < 5 can't. -if status | grep -q -- '-p' 2>/dev/null; then - daemonopts="--pidfile $pidfile" - pidopts="-p $pidfile" -fi - -if command -v runuser >/dev/null 2>&1; then - user_wrapper="runuser" -fi - -[ "$beat_user" != "root" ] && wrapperopts="$wrapperopts -u $beat_user" - -test() { - $user_wrapper $user_wrapperopts "$agent $args $test_args" -} - -start() { - echo -n $"Starting {{.beat_name}}: " - test - if [ $? -ne 0 ]; then - echo - exit 1 - fi - daemon $daemonopts $wrapper $wrapperopts -- $agent $args - RETVAL=$? - echo - return $RETVAL -} - -stop() { - echo -n $"Stopping {{.beat_name}}: " - killproc $pidopts $wrapper - RETVAL=$? - echo - [ $RETVAL = 0 ] && rm -f ${pidfile} -} - -restart() { - test - if [ $? -ne 0 ]; then - return 1 - fi - stop - start -} - -rh_status() { - status $pidopts $wrapper - RETVAL=$? - return $RETVAL -} - -rh_status_q() { - rh_status >/dev/null 2>&1 -} - -case "$1" in - start) - start - ;; - stop) - stop - ;; - restart) - restart - ;; - condrestart|try-restart) - rh_status_q || exit 0 - restart - ;; - status) - rh_status - ;; - *) - echo $"Usage: $0 {start|stop|status|restart|condrestart}" - exit 1 -esac - -exit $RETVAL diff --git a/dev-tools/packer/platforms/centos/run.sh.j2 b/dev-tools/packer/platforms/centos/run.sh.j2 deleted file mode 100644 index f23517d2e816..000000000000 --- a/dev-tools/packer/platforms/centos/run.sh.j2 +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/bash - -# this is executed in the docker fpm image -set -e -cd /build - -# the init scripts needs to have the right name -cp ${RUNID}.init /tmp/{{.beat_pkg_name}}.init - -# create script to reload systemd config -echo "#!/bin/bash" > /tmp/systemd-daemon-reload.sh -echo "systemctl daemon-reload 2> /dev/null || true" >> /tmp/systemd-daemon-reload.sh - -# add SNAPSHOT if it was requested -VERSION="{{.version}}" -if [ "$SNAPSHOT" = "yes" ]; then - VERSION="${VERSION}-SNAPSHOT" -fi - -BEATS_YML_NAME="{{.beat_name}}-linux-{{.arch}}" -[ -f "${BEATS_YML_NAME}.yml" ] || BEATS_YML_NAME="{{.beat_name}}-linux" - -# fpm replaces - with _ in the version -RPM_VERSION=`echo ${VERSION} | sed 's/-/_/g'` - -# create rpm -FPM_ARGS=( - --force -s dir -t rpm - -n {{.beat_pkg_name}}{{.beat_pkg_suffix}} -v ${RPM_VERSION} - --architecture {{.rpm_arch}} - --vendor "{{.beat_vendor}}" - --license "{{.beat_license}}" - --description "{{.beat_description}}" - --url {{.beat_url}} - --rpm-init /tmp/{{.beat_pkg_name}}.init - --after-install /tmp/systemd-daemon-reload.sh - --config-files /etc/{{.beat_name}}/{{.beat_name}}.yml - homedir/=/usr/share/{{.beat_name}} - beatname-${RUNID}.sh=/usr/bin/{{.beat_name}} - {{.beat_name}}-linux-{{.arch}}=/usr/share/{{.beat_name}}/bin/{{.beat_name}} - ${BEATS_YML_NAME}.yml=/etc/{{.beat_name}}/{{.beat_name}}.yml - fields.yml=/etc/{{.beat_name}}/fields.yml - ${RUNID}.service=/lib/systemd/system/{{.beat_pkg_name}}.service - god-linux-{{.arch}}=/usr/share/{{.beat_name}}/bin/{{.beat_name}}-god - ) - -if [ -z "${BEAT_REF_YAML}" ] || [ ${BEAT_REF_YAML} = true ]; then - FPM_ARGS+=(${BEATS_YML_NAME}.reference.yml=/etc/{{.beat_name}}/{{.beat_name}}.reference.yml) -fi - -if [ -d modules.d-linux ]; then - FPM_ARGS+=(modules.d-linux/=/etc/{{.beat_name}}/modules.d/) -fi - -fpm "${FPM_ARGS[@]}" - -# rename so that the filename respects semver rules -mv {{.beat_pkg_name}}{{.beat_pkg_suffix}}-${RPM_VERSION}-1.{{.rpm_arch}}.rpm /upload/{{.beat_name}}{{.beat_pkg_suffix}}-${VERSION}-{{.rpm_arch}}.rpm -echo "Created /upload/{{.beat_name}}{{.beat_pkg_suffix}}-${VERSION}-{{.rpm_arch}}.rpm" - -# create sha512 file -cd /upload -sha512sum {{.beat_name}}{{.beat_pkg_suffix}}-${VERSION}-{{.rpm_arch}}.rpm > {{.beat_name}}{{.beat_pkg_suffix}}-${VERSION}-{{.rpm_arch}}.rpm.sha512 -echo "Created /upload/{{.beat_name}}{{.beat_pkg_suffix}}-${VERSION}-{{.rpm_arch}}.rpm.sha512" diff --git a/dev-tools/packer/platforms/centos/systemd.j2 b/dev-tools/packer/platforms/centos/systemd.j2 deleted file mode 100644 index 8f14e9effcea..000000000000 --- a/dev-tools/packer/platforms/centos/systemd.j2 +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description={{.beat_name}} -Documentation={{.beat_doc_url}} -Wants=network-online.target -After=network-online.target - -[Service] -ExecStart=/usr/share/{{.beat_name}}/bin/{{.beat_name}} -c /etc/{{.beat_name}}/{{.beat_name}}.yml -path.home /usr/share/{{.beat_name}} -path.config /etc/{{.beat_name}} -path.data /var/lib/{{.beat_name}} -path.logs /var/log/{{.beat_name}} -Restart=always - -[Install] -WantedBy=multi-user.target diff --git a/dev-tools/packer/platforms/darwin/build.sh b/dev-tools/packer/platforms/darwin/build.sh deleted file mode 100755 index 14c57f751494..000000000000 --- a/dev-tools/packer/platforms/darwin/build.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -set -e - -BASEDIR=$(dirname "$0") -ARCHDIR=${BASEDIR}/../../ - -# executed from the top directory -runid=darwin-$BEAT-$ARCH - -cat ${BUILD_DIR}/package.yml ${ARCHDIR}/archs/$ARCH.yml > ${BUILD_DIR}/settings-$runid.yml -gotpl ${BASEDIR}/run.sh.j2 < ${BUILD_DIR}/settings-$runid.yml > ${BUILD_DIR}/run-$runid.sh -chmod +x ${BUILD_DIR}/run-$runid.sh - -docker run --rm -v ${BUILD_DIR}:/build -v ${UPLOAD_DIR}:/upload \ - -e BUILDID=$BUILDID -e SNAPSHOT=$SNAPSHOT -e RUNID=$runid -e BEAT_REF_YAML=$BEAT_REF_YAML \ - tudorg/fpm /build/run-$runid.sh - -rm ${BUILD_DIR}/settings-$runid.yml ${BUILD_DIR}/run-$runid.sh diff --git a/dev-tools/packer/platforms/darwin/run.sh.j2 b/dev-tools/packer/platforms/darwin/run.sh.j2 deleted file mode 100644 index 18c8f62e5fc7..000000000000 --- a/dev-tools/packer/platforms/darwin/run.sh.j2 +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -# this is executed in the docker fpm image -set -e -cd /build - -# add SNAPSHOT if it was requested -VERSION={{.version}} -if [ "$SNAPSHOT" = "yes" ]; then - VERSION="${VERSION}-SNAPSHOT" -fi - -mkdir /{{.beat_name}}-${VERSION}-darwin-x86_64 -cp -a homedir/. /{{.beat_name}}-${VERSION}-darwin-x86_64/ -cp {{.beat_name}}-darwin-amd64 /{{.beat_name}}-${VERSION}-darwin-x86_64/{{.beat_name}} -cp {{.beat_name}}-darwin.yml /{{.beat_name}}-${VERSION}-darwin-x86_64/{{.beat_name}}.yml -if [ -z "${BEAT_REF_YAML}" ] || [ ${BEAT_REF_YAML} = true ]; then - cp {{.beat_name}}-darwin.reference.yml /{{.beat_name}}-${VERSION}-darwin-x86_64/{{.beat_name}}.reference.yml -fi -cp fields.yml /{{.beat_name}}-${VERSION}-darwin-x86_64/ -cp -a modules.d-darwin/ /{{.beat_name}}-${VERSION}-darwin-x86_64/modules.d || true - -tar czvf /upload/{{.beat_name}}{{.beat_pkg_suffix}}-${VERSION}-darwin-x86_64.tar.gz /{{.beat_name}}-${VERSION}-darwin-x86_64 -echo "Created /upload/{{.beat_name}}-${VERSION}-darwin-x86_64.tar.gz" - -cd /upload -sha512sum {{.beat_name}}{{.beat_pkg_suffix}}-${VERSION}-darwin-x86_64.tar.gz > {{.beat_name}}{{.beat_pkg_suffix}}-${VERSION}-darwin-x86_64.tar.gz.sha512 -echo "Created /upload/{{.beat_name}}{{.beat_pkg_suffix}}-${VERSION}-darwin-x86_64.tar.gz.sha512" diff --git a/dev-tools/packer/platforms/dashboards/build.sh b/dev-tools/packer/platforms/dashboards/build.sh deleted file mode 100755 index 67b04828fcd0..000000000000 --- a/dev-tools/packer/platforms/dashboards/build.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh - -set -e - -BASEDIR=$(dirname "$0") -ARCHDIR=${BASEDIR}/../../ - -runid=dashboards - -cat ${ARCHDIR}/version.yml > ${BUILD_DIR}/settings-$runid.yml -gotpl ${BASEDIR}/run.sh.j2 < ${BUILD_DIR}/settings-$runid.yml > ${BUILD_DIR}/run-$runid.sh -chmod +x ${BUILD_DIR}/run-$runid.sh - -docker run --rm -v ${BUILD_DIR}:/build -v ${UPLOAD_DIR}:/upload \ - -e BUILDID=$BUILDID -e SNAPSHOT=$SNAPSHOT -e RUNID=$runid -e BEAT_NAME=$BEAT_NAME -e BEAT_REF_YAML=$BEAT_REF_YAML \ - tudorg/fpm /build/run-$runid.sh - -rm ${BUILD_DIR}/settings-$runid.yml ${BUILD_DIR}/run-$runid.sh diff --git a/dev-tools/packer/platforms/dashboards/run.sh.j2 b/dev-tools/packer/platforms/dashboards/run.sh.j2 deleted file mode 100644 index 96d272aaf2a2..000000000000 --- a/dev-tools/packer/platforms/dashboards/run.sh.j2 +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -# this is executed in the docker fpm image -set -e -cd /build - -# add SNAPSHOT if it was requested -VERSION={{.version}} -if [ "$SNAPSHOT" = "yes" ]; then - VERSION="${VERSION}-SNAPSHOT" -fi - -mkdir /${BEAT_NAME:-beats}-dashboards-${VERSION} -cp -a dashboards/. /${BEAT_NAME:-beats}-dashboards-${VERSION}/ -echo "$BUILDID" > /${BEAT_NAME:-beats}-dashboards-${VERSION}/.build_hash.txt - -zip -r /upload/${BEAT_NAME:-beats}-dashboards-${VERSION}.zip /${BEAT_NAME:-beats}-dashboards-${VERSION} -echo "Created /upload/${BEAT_NAME:-beats}-dashboards-${VERSION}.zip" - -cd /upload -sha512sum ${BEAT_NAME:-beats}-dashboards-${VERSION}.zip > ${BEAT_NAME:-beats}-dashboards-${VERSION}.zip.sha512 -echo "Created /upload/${BEAT_NAME:-beats}-dashboards-${VERSION}.zip.sha512" diff --git a/dev-tools/packer/platforms/debian/beatname.sh.j2 b/dev-tools/packer/platforms/debian/beatname.sh.j2 deleted file mode 100644 index fc36a268b832..000000000000 --- a/dev-tools/packer/platforms/debian/beatname.sh.j2 +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -# Script to run {{.beat_name}} in foreground with the same path settings that -# the init script / systemd unit file would do. - -exec /usr/share/{{.beat_name}}/bin/{{.beat_name}} \ - -path.home /usr/share/{{.beat_name}} \ - -path.config /etc/{{.beat_name}} \ - -path.data /var/lib/{{.beat_name}} \ - -path.logs /var/log/{{.beat_name}} \ - "$@" diff --git a/dev-tools/packer/platforms/debian/build.sh b/dev-tools/packer/platforms/debian/build.sh deleted file mode 100755 index 64f989f7d80d..000000000000 --- a/dev-tools/packer/platforms/debian/build.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh - -set -e - -BASEDIR=$(dirname "$0") -ARCHDIR=${BASEDIR}/../../ - -# executed from the top directory -runid=debian-$BEAT-$ARCH - -cat ${BUILD_DIR}/package.yml ${ARCHDIR}/archs/$ARCH.yml > ${BUILD_DIR}/settings-$runid.yml -gotpl ${BASEDIR}/run.sh.j2 < ${BUILD_DIR}/settings-$runid.yml > ${BUILD_DIR}/run-$runid.sh -chmod +x ${BUILD_DIR}/run-$runid.sh -gotpl ${BASEDIR}/init.j2 < ${BUILD_DIR}/settings-$runid.yml > ${BUILD_DIR}/$runid.init -gotpl ${BASEDIR}/systemd.j2 < ${BUILD_DIR}/settings-$runid.yml > ${BUILD_DIR}/$runid.service -gotpl ${BASEDIR}/beatname.sh.j2 < ${BUILD_DIR}/settings-$runid.yml > ${BUILD_DIR}/beatname-$runid.sh -chmod +x ${BUILD_DIR}/beatname-$runid.sh - -docker run --rm -v ${BUILD_DIR}:/build -v ${UPLOAD_DIR}:/upload \ - -e BUILDID=$BUILDID -e SNAPSHOT=$SNAPSHOT -e RUNID=$runid -e BEAT_REF_YAML=$BEAT_REF_YAML \ - tudorg/fpm /build/run-$runid.sh - -rm ${BUILD_DIR}/settings-$runid.yml ${BUILD_DIR}/run-$runid.sh diff --git a/dev-tools/packer/platforms/debian/init.j2 b/dev-tools/packer/platforms/debian/init.j2 deleted file mode 100755 index 04c24242d817..000000000000 --- a/dev-tools/packer/platforms/debian/init.j2 +++ /dev/null @@ -1,188 +0,0 @@ -#!/bin/sh -### BEGIN INIT INFO -# Provides: {{.beat_pkg_name}} -# Required-Start: $local_fs $network $syslog -# Required-Stop: $local_fs $network $syslog -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: {{.beat_description}} -# Description: {{.beat_name}} is a shipper part of the Elastic Beats -# family. Please see: https://www.elastic.co/products/beats -### END INIT INFO - -# Do NOT "set -e" - -# PATH should only include /usr/* if it runs after the mountnfs.sh script -PATH=/sbin:/usr/sbin:/bin:/usr/bin -DESC="{{.beat_description}}" -NAME="{{.beat_name}}" -DAEMON=/usr/share/{{.beat_name}}/bin/$NAME -DAEMON_ARGS="-c /etc/{{.beat_name}}/{{.beat_name}}.yml -path.home /usr/share/{{.beat_name}} -path.config /etc/{{.beat_name}} -path.data /var/lib/{{.beat_name}} -path.logs /var/log/{{.beat_name}}" -TEST_ARGS="-e test config" -PIDFILE=/var/run/{{.beat_pkg_name}}.pid -WRAPPER="/usr/share/{{.beat_name}}/bin/{{.beat_name}}-god" -BEAT_USER="root" -WRAPPER_ARGS="-r / -n -p $PIDFILE" -SCRIPTNAME=/etc/init.d/$NAME - -# Exit if the package is not installed -[ -x "$DAEMON" ] || exit 0 - -# Read configuration variable file if it is present -[ -r /etc/default/{{.beat_pkg_name}} ] && . /etc/default/{{.beat_pkg_name}} - -[ "$BEAT_USER" != "root" ] && WRAPPER_ARGS="$WRAPPER_ARGS -u $BEAT_USER" -USER_WRAPPER="su" -USER_WRAPPER_ARGS="$BEAT_USER -c" - -if command -v runuser >/dev/null 2>&1; then - USER_WRAPPER="runuser" -fi - -# Load the VERBOSE setting and other rcS variables -. /lib/init/vars.sh - -# Define LSB log_* functions. -# Depend on lsb-base (>= 3.2-14) to ensure that this file is present -# and status_of_proc is working. -. /lib/lsb/init-functions - -# -# Function that calls runs the service in foreground -# to test its configuration. -# -do_test() -{ - $USER_WRAPPER $USER_WRAPPER_ARGS "$DAEMON $DAEMON_ARGS $TEST_ARGS" -} - -# -# Function that starts the daemon/service -# -do_start() -{ - # Return - # 0 if daemon has been started - # 1 if daemon was already running - # 2 if daemon could not be started - start-stop-daemon --start \ - --pidfile $PIDFILE \ - --exec $WRAPPER -- $WRAPPER_ARGS -- $DAEMON $DAEMON_ARGS \ - || return 2 -} - -# -# Function that stops the daemon/service -# -do_stop() -{ - # Return - # 0 if daemon has been stopped - # 1 if daemon was already stopped - # 2 if daemon could not be stopped - # other if a failure occurred - start-stop-daemon --stop --quiet --retry=TERM/5/KILL/5 --pidfile $PIDFILE --exec $WRAPPER - RETVAL="$?" - [ "$RETVAL" = 2 ] && return 2 - # Wait for children to finish too if this is a daemon that forks - # and if the daemon is only ever run from this initscript. - # If the above conditions are not satisfied then add some other code - # that waits for the process to drop all resources that could be - # needed by services started subsequently. A last resort is to - # sleep for some time. - start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON - [ "$?" = 2 ] && return 2 - # Many daemons don't delete their pidfiles when they exit. - rm -f $PIDFILE - return "$RETVAL" -} - -# -# Function that sends a SIGHUP to the daemon/service -# -do_reload() { - # - # If the daemon can reload its configuration without - # restarting (for example, when it is sent a SIGHUP), - # then implement that here. - # - start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --exec $DAEMON - return 0 -} - -case "$1" in - start) - [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" - do_test - case "$?" in - 0) ;; - *) - log_end_msg 1 - exit 1 - ;; - esac - do_start - case "$?" in - 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; - 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; - esac - ;; - stop) - [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" - do_stop - case "$?" in - 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; - 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; - esac - ;; - status) - status_of_proc "$WRAPPER" "$NAME" && exit 0 || exit $? - ;; - #reload|force-reload) - # - # If do_reload() is not implemented then leave this commented out - # and leave 'force-reload' as an alias for 'restart'. - # - #log_daemon_msg "Reloading $DESC" "$NAME" - #do_reload - #log_end_msg $? - #;; - restart|force-reload) - # - # If the "reload" option is implemented then remove the - # 'force-reload' alias - # - log_daemon_msg "Restarting $DESC" "$NAME" - do_test - case "$?" in - 0) ;; - *) - log_end_msg 1 # Old process is still running - exit 1 - ;; - esac - - do_stop - case "$?" in - 0|1) - do_start - case "$?" in - 0) log_end_msg 0 ;; - 1) log_end_msg 1 ;; # Old process is still running - *) log_end_msg 1 ;; # Failed to start - esac - ;; - *) - # Failed to stop - log_end_msg 1 - ;; - esac - ;; - *) - #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 - echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 - exit 3 - ;; -esac - -: diff --git a/dev-tools/packer/platforms/debian/run.sh.j2 b/dev-tools/packer/platforms/debian/run.sh.j2 deleted file mode 100644 index fcf2cdba33c3..000000000000 --- a/dev-tools/packer/platforms/debian/run.sh.j2 +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash - -# this is executed in the docker fpm image -set -e -cd /build - -# the init scripts needs to have the right name -cp ${RUNID}.init /tmp/{{.beat_pkg_name}}.init - -# create script to reload systemd config -echo "#!/bin/bash" > /tmp/systemd-daemon-reload.sh -echo "systemctl daemon-reload 2> /dev/null || true" >> /tmp/systemd-daemon-reload.sh - -# add SNAPSHOT if it was requested -VERSION="{{.version}}" -if [ "$SNAPSHOT" = "yes" ]; then - VERSION="${VERSION}-SNAPSHOT" -fi - -BEATS_YML_NAME="{{.beat_name}}-linux-{{.arch}}" -[ -f "${BEATS_YML_NAME}.yml" ] || BEATS_YML_NAME="{{.beat_name}}-linux" - -# create deb -FPM_ARGS=( - --force -s dir -t deb - -n {{.beat_pkg_name}}{{.beat_pkg_suffix}} -v ${VERSION} - --vendor "{{.beat_vendor}}" - --license $(echo {{.beat_license}} | tr " " "-") - --architecture {{.deb_arch}} - --description "{{.beat_description}}" - --url {{.beat_url}} - --deb-init /tmp/{{.beat_pkg_name}}.init - --after-install /tmp/systemd-daemon-reload.sh - --config-files /etc/{{.beat_name}}/{{.beat_name}}.yml - homedir/=/usr/share/{{.beat_name}} - beatname-${RUNID}.sh=/usr/bin/{{.beat_name}} - {{.beat_name}}-linux-{{.arch}}=/usr/share/{{.beat_name}}/bin/{{.beat_name}} - ${BEATS_YML_NAME}.yml=/etc/{{.beat_name}}/{{.beat_name}}.yml - fields.yml=/etc/{{.beat_name}}/fields.yml - ${RUNID}.service=/lib/systemd/system/{{.beat_pkg_name}}.service - god-linux-{{.arch}}=/usr/share/{{.beat_name}}/bin/{{.beat_name}}-god - ) - -if [ -z "${BEAT_REF_YAML}" ] || [ ${BEAT_REF_YAML} = true ]; then - FPM_ARGS+=(${BEATS_YML_NAME}.reference.yml=/etc/{{.beat_name}}/{{.beat_name}}.reference.yml) -fi - - -if [ -d modules.d-linux ]; then - FPM_ARGS+=(modules.d-linux/=/etc/{{.beat_name}}/modules.d/) -fi - -fpm "${FPM_ARGS[@]}" - -# move and rename to use the elastic conventions -mv {{.beat_pkg_name}}{{.beat_pkg_suffix}}_${VERSION}_{{.deb_arch}}.deb /upload/{{.beat_name}}{{.beat_pkg_suffix}}-${VERSION}-{{.deb_arch}}.deb -echo "Created /upload/{{.beat_name}}{{.beat_pkg_suffix}}-${VERSION}-{{.deb_arch}}.deb" - -# create sha512 file -cd /upload -sha512sum {{.beat_name}}{{.beat_pkg_suffix}}-${VERSION}-{{.deb_arch}}.deb > {{.beat_name}}{{.beat_pkg_suffix}}-${VERSION}-{{.deb_arch}}.deb.sha512 -echo "Created /upload/{{.beat_name}}{{.beat_pkg_suffix}}-${VERSION}-{{.deb_arch}}.deb.sha512" diff --git a/dev-tools/packer/platforms/debian/systemd.j2 b/dev-tools/packer/platforms/debian/systemd.j2 deleted file mode 100644 index 8f14e9effcea..000000000000 --- a/dev-tools/packer/platforms/debian/systemd.j2 +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description={{.beat_name}} -Documentation={{.beat_doc_url}} -Wants=network-online.target -After=network-online.target - -[Service] -ExecStart=/usr/share/{{.beat_name}}/bin/{{.beat_name}} -c /etc/{{.beat_name}}/{{.beat_name}}.yml -path.home /usr/share/{{.beat_name}} -path.config /etc/{{.beat_name}} -path.data /var/lib/{{.beat_name}} -path.logs /var/log/{{.beat_name}} -Restart=always - -[Install] -WantedBy=multi-user.target diff --git a/dev-tools/packer/platforms/windows/build.sh b/dev-tools/packer/platforms/windows/build.sh deleted file mode 100755 index bdecc7c04fd1..000000000000 --- a/dev-tools/packer/platforms/windows/build.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh - -set -e - -BASEDIR=$(dirname "$0") -ARCHDIR=${BASEDIR}/../.. - -# executed from the top directory -runid=windows-$BEAT-$ARCH - -cat ${BUILD_DIR}/package.yml ${ARCHDIR}/archs/$ARCH.yml > ${BUILD_DIR}/settings-$runid.yml -gotpl ${BASEDIR}/run.sh.j2 < ${BUILD_DIR}/settings-$runid.yml > ${BUILD_DIR}/run-$runid.sh -gotpl ${BASEDIR}/install-service.ps1.j2 < ${BUILD_DIR}/settings-$runid.yml > ${BUILD_DIR}/install-service-$BEAT.ps1 -gotpl ${BASEDIR}/uninstall-service.ps1.j2 < ${BUILD_DIR}/settings-$runid.yml > ${BUILD_DIR}/uninstall-service-$BEAT.ps1 -chmod +x ${BUILD_DIR}/run-$runid.sh - -docker run --rm -v ${BUILD_DIR}:/build -v ${UPLOAD_DIR}:/upload \ - -e BUILDID=$BUILDID -e SNAPSHOT=$SNAPSHOT -e RUNID=$runid -e BEAT_REF_YAML=$BEAT_REF_YAML \ - tudorg/fpm /build/run-$runid.sh - -rm ${BUILD_DIR}/settings-$runid.yml ${BUILD_DIR}/run-$runid.sh diff --git a/dev-tools/packer/platforms/windows/install-service.ps1.j2 b/dev-tools/packer/platforms/windows/install-service.ps1.j2 deleted file mode 100644 index e95e4311670a..000000000000 --- a/dev-tools/packer/platforms/windows/install-service.ps1.j2 +++ /dev/null @@ -1,14 +0,0 @@ -# delete service if it already exists -if (Get-Service {{.beat_name}} -ErrorAction SilentlyContinue) { - $service = Get-WmiObject -Class Win32_Service -Filter "name='{{.beat_name}}'" - $service.StopService() - Start-Sleep -s 1 - $service.delete() -} - -$workdir = Split-Path $MyInvocation.MyCommand.Path - -# create new service -New-Service -name {{.beat_name}} ` - -displayName {{.beat_name}} ` - -binaryPathName "`"$workdir\{{.beat_name}}.exe`" -c `"$workdir\{{.beat_name}}.yml`" -path.home `"$workdir`" -path.data `"C:\ProgramData\{{.beat_name}}`" -path.logs `"C:\ProgramData\{{.beat_name}}\logs`"" diff --git a/dev-tools/packer/platforms/windows/run.sh.j2 b/dev-tools/packer/platforms/windows/run.sh.j2 deleted file mode 100644 index 2a65ca120d06..000000000000 --- a/dev-tools/packer/platforms/windows/run.sh.j2 +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash - -# this is executed in the docker fpm image -set -e -cd /build - -# add SNAPSHOT if it was requested -VERSION={{.version}} -if [ "$SNAPSHOT" = "yes" ]; then - VERSION="${VERSION}-SNAPSHOT" -fi - -mkdir /{{.beat_name}}-${VERSION}-windows-{{.win_arch}} -cp -a homedir/. /{{.beat_name}}-${VERSION}-windows-{{.win_arch}}/ -cp {{.beat_name}}-windows-{{.arch}}.exe /{{.beat_name}}-${VERSION}-windows-{{.win_arch}}/{{.beat_name}}.exe -unix2dos {{.beat_name}}-win.yml -cp {{.beat_name}}-win.yml /{{.beat_name}}-${VERSION}-windows-{{.win_arch}}/{{.beat_name}}.yml -if [ -z "${BEAT_REF_YAML}" ] || [ ${BEAT_REF_YAML} = true ]; then - cp {{.beat_name}}-win.reference.yml /{{.beat_name}}-${VERSION}-windows-{{.win_arch}}/{{.beat_name}}.reference.yml -fi -cp fields.yml /{{.beat_name}}-${VERSION}-windows-{{.win_arch}}/ -cp -a modules.d-win/ /{{.beat_name}}-${VERSION}-windows-{{.win_arch}}/modules.d || true -cp install-service-{{.beat_name}}.ps1 /{{.beat_name}}-${VERSION}-windows-{{.win_arch}}/ -cp uninstall-service-{{.beat_name}}.ps1 /{{.beat_name}}-${VERSION}-windows-{{.win_arch}}/ - -zip -r /upload/{{.beat_name}}{{.beat_pkg_suffix}}-${VERSION}-windows-{{.win_arch}}.zip /{{.beat_name}}-${VERSION}-windows-{{.win_arch}} -echo "Created /upload/{{.beat_name}}{{.beat_pkg_suffix}}-${VERSION}-windows-{{.win_arch}}.zip" - -cd /upload -sha512sum {{.beat_name}}{{.beat_pkg_suffix}}-${VERSION}-windows-{{.win_arch}}.zip > {{.beat_name}}{{.beat_pkg_suffix}}-${VERSION}-windows-{{.win_arch}}.zip.sha512 -echo "Created /upload/{{.beat_name}}{{.beat_pkg_suffix}}-${VERSION}-windows-{{.win_arch}}.zip.sha512" diff --git a/dev-tools/packer/platforms/windows/uninstall-service.ps1.j2 b/dev-tools/packer/platforms/windows/uninstall-service.ps1.j2 deleted file mode 100644 index c9e753c7ce30..000000000000 --- a/dev-tools/packer/platforms/windows/uninstall-service.ps1.j2 +++ /dev/null @@ -1,5 +0,0 @@ -# delete service if it exists -if (Get-Service {{.beat_name}} -ErrorAction SilentlyContinue) { - $service = Get-WmiObject -Class Win32_Service -Filter "name='{{.beat_name}}'" - $service.delete() -} diff --git a/dev-tools/packer/readme.md.j2 b/dev-tools/packer/readme.md.j2 deleted file mode 100644 index b4b016a33f38..000000000000 --- a/dev-tools/packer/readme.md.j2 +++ /dev/null @@ -1,23 +0,0 @@ -# Welcome to {{.beat_name}} {{.version}} - -{{.beat_description}} - -## Getting Started - -To get started with {{.beat_name}}, you need to set up Elasticsearch on your localhost first. After that, start {{.beat_name}} with: - - ./{{.beat_name}} -c {{.beat_name}}.yml -e - -This will start the beat and send the data to your Elasticsearch instance. To load the dashboards for {{.beat_name}} into Kibana, run: - - ./{{.beat_name}} setup -e - -For further steps visit the [Getting started](https://www.elastic.co/guide/en/beats/{{.beat_name}}/{{.doc_branch}}/{{.beat_name}}-getting-started.html) guide. - -## Documentation - -Visit [Elastic.co Docs](https://www.elastic.co/guide/en/beats/{{.beat_name}}/{{.doc_branch}}/index.html) for the full {{.beat_name}} documentation. - -## Release notes - -https://www.elastic.co/guide/en/beats/libbeat/{{.doc_branch}}/release-notes-{{.version}}.html diff --git a/dev-tools/packer/version.yml b/dev-tools/packer/version.yml deleted file mode 100644 index 5d5f902f661f..000000000000 --- a/dev-tools/packer/version.yml +++ /dev/null @@ -1 +0,0 @@ -version: "7.0.0-alpha1" diff --git a/dev-tools/packer/xgo-scripts/before_build.sh b/dev-tools/packer/xgo-scripts/before_build.sh deleted file mode 100755 index ba80f676ff03..000000000000 --- a/dev-tools/packer/xgo-scripts/before_build.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/bin/sh - -set -e - -if [ $BEAT_NAME = "packetbeat" ]; then - patch -p1 < /gopacket_pcap.patch -fi - -cd $GOPATH/src/$BEAT_PATH - -# Files must be copied before before-build calls to allow modifications on the config files - -PREFIX=/build - -# Copy fields.yml -cp fields.yml $PREFIX/fields.yml - -# linux -cp $BEAT_NAME.yml $PREFIX/$BEAT_NAME-linux.yml -chmod 0600 $PREFIX/$BEAT_NAME-linux.yml -chmod 0600 $PREFIX/$BEAT_NAME-linux-386.yml || true -if [ -z "${BEAT_REF_YAML}" ] || [ ${BEAT_REF_YAML} = true ]; then - cp $BEAT_NAME.reference.yml $PREFIX/$BEAT_NAME-linux.reference.yml -fi -rm -rf $PREFIX/modules.d-linux -cp -r modules.d/ $PREFIX/modules.d-linux || true -[ -d "$PREFIX/modules.d-linux" ] && chmod 0755 $PREFIX/modules.d-linux - -# darwin -cp $BEAT_NAME.yml $PREFIX/$BEAT_NAME-darwin.yml -chmod 0600 $PREFIX/$BEAT_NAME-darwin.yml -if [ -z "${BEAT_REF_YAML}" ] || [ ${BEAT_REF_YAML} = true ]; then - cp $BEAT_NAME.reference.yml $PREFIX/$BEAT_NAME-darwin.reference.yml -fi -rm -rf $PREFIX/modules.d-darwin -cp -r modules.d/ $PREFIX/modules.d-darwin || true -[ -d "$PREFIX/modules.d-darwin" ] && chmod 0755 $PREFIX/modules.d-darwin - -# win -cp $BEAT_NAME.yml $PREFIX/$BEAT_NAME-win.yml -chmod 0600 $PREFIX/$BEAT_NAME-win.yml -if [ -z "${BEAT_REF_YAML}" ] || [ ${BEAT_REF_YAML} = true ]; then - cp $BEAT_NAME.reference.yml $PREFIX/$BEAT_NAME-win.reference.yml -fi -rm -rf $PREFIX/modules.d-win -cp -r modules.d/ $PREFIX/modules.d-win || true -[ -d "$PREFIX/modules.d-win" ] && chmod 0755 $PREFIX/modules.d-win - -# Runs beat specific tasks which should be done before building -PREFIX=$PREFIX make before-build - -# Add data to the home directory -mkdir -p $PREFIX/homedir -make install-home HOME_PREFIX=$PREFIX/homedir LICENSE_FILE=${LICENSE_FILE} - -if [ -n "BUILDID" ]; then - echo "$BUILDID" > $PREFIX/homedir/.build_hash.txt -fi - -# Append doc versions to package.yml -cat ${ES_BEATS}/libbeat/docs/version.asciidoc >> ${PREFIX}/package.yml - -# Make variable naming of doc-branch compatible with gotpl. Generate and copy README.md into homedir -# Add " to the version as gotpl interprets 6.0 as 6 -sed -i -e 's/:doc-branch: \(.*\)/doc_branch: "\1" /g' ${PREFIX}/package.yml - -# Create README file -/go/bin/gotpl /templates/readme.md.j2 < ${PREFIX}/package.yml > ${PREFIX}/homedir/README.md diff --git a/dev-tools/vendor/github.com/tsg/gotpl/LICENSE b/dev-tools/vendor/github.com/tsg/gotpl/LICENSE deleted file mode 100644 index 51fca54c2a05..000000000000 --- a/dev-tools/vendor/github.com/tsg/gotpl/LICENSE +++ /dev/null @@ -1,11 +0,0 @@ -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. diff --git a/dev-tools/vendor/github.com/tsg/gotpl/README.md b/dev-tools/vendor/github.com/tsg/gotpl/README.md deleted file mode 100644 index 6914c14836cc..000000000000 --- a/dev-tools/vendor/github.com/tsg/gotpl/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# gotpl - CLI tool for Golang templates - -Command line tool that compiles Golang -[templates](http://golang.org/pkg/text/template/) with values from YAML files. - -Inspired by Python/Jinja2's [j2cli](https://github.com/kolypto/j2cli). - -## Install - - go get github.com/tsg/gotpl - -## Usage - -Say you have a `template` file like this: - - {{.first_name}} {{.last_name}} is {{.age}} years old. - -and a `user.yml` YAML file like this one: - - first_name: Max - last_name: Mustermann - age: 30 - -You can compile the template like this: - - gotpl template < user.yml diff --git a/dev-tools/vendor/github.com/tsg/gotpl/tpl.go b/dev-tools/vendor/github.com/tsg/gotpl/tpl.go deleted file mode 100644 index 563d84713602..000000000000 --- a/dev-tools/vendor/github.com/tsg/gotpl/tpl.go +++ /dev/null @@ -1,48 +0,0 @@ -package main - -import ( - "bytes" - "fmt" - "io" - "log" - "os" - "text/template" - - "gopkg.in/yaml.v2" -) - -// Reads a YAML document from the values_in stream, uses it as values -// for the tpl_files templates and writes the executed templates to -// the out stream. -func ExecuteTemplates(values_in io.Reader, out io.Writer, tpl_files ...string) error { - tpl, err := template.ParseFiles(tpl_files...) - if err != nil { - return fmt.Errorf("Error parsing template(s): %v", err) - } - - buf := bytes.NewBuffer(nil) - _, err = io.Copy(buf, values_in) - if err != nil { - return fmt.Errorf("Failed to read standard input: %v", err) - } - - var values map[string]interface{} - err = yaml.Unmarshal(buf.Bytes(), &values) - if err != nil { - return fmt.Errorf("Failed to parse standard input: %v", err) - } - - err = tpl.Execute(out, values) - if err != nil { - return fmt.Errorf("Failed to parse standard input: %v", err) - } - return nil -} - -func main() { - err := ExecuteTemplates(os.Stdin, os.Stdout, os.Args[1:]...) - if err != nil { - log.Println(err) - os.Exit(1) - } -} diff --git a/dev-tools/vendor/gopkg.in/yaml.v2/LICENSE b/dev-tools/vendor/gopkg.in/yaml.v2/LICENSE deleted file mode 100644 index 8dada3edaf50..000000000000 --- a/dev-tools/vendor/gopkg.in/yaml.v2/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - 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. diff --git a/dev-tools/vendor/gopkg.in/yaml.v2/LICENSE.libyaml b/dev-tools/vendor/gopkg.in/yaml.v2/LICENSE.libyaml deleted file mode 100644 index 8da58fbf6f84..000000000000 --- a/dev-tools/vendor/gopkg.in/yaml.v2/LICENSE.libyaml +++ /dev/null @@ -1,31 +0,0 @@ -The following files were ported to Go from C files of libyaml, and thus -are still covered by their original copyright and license: - - apic.go - emitterc.go - parserc.go - readerc.go - scannerc.go - writerc.go - yamlh.go - yamlprivateh.go - -Copyright (c) 2006 Kirill Simonov - -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. diff --git a/dev-tools/vendor/gopkg.in/yaml.v2/README.md b/dev-tools/vendor/gopkg.in/yaml.v2/README.md deleted file mode 100644 index 2ed3314c7393..000000000000 --- a/dev-tools/vendor/gopkg.in/yaml.v2/README.md +++ /dev/null @@ -1,135 +0,0 @@ -# YAML support for the Go language - -Introduction ------------- - -The yaml package enables Go programs to comfortably encode and decode YAML -values. It was developed within [Canonical](https://www.canonical.com) as -part of the [juju](https://juju.ubuntu.com) project, and is based on a -pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML) -C library to parse and generate YAML data quickly and reliably. - -Compatibility -------------- - -The yaml package supports most of YAML 1.1 and 1.2, including support for -anchors, tags, map merging, etc. Multi-document unmarshalling is not yet -implemented, and base-60 floats from YAML 1.1 are purposefully not -supported since they're a poor design and are gone in YAML 1.2. - -Installation and usage ----------------------- - -The import path for the package is *gopkg.in/yaml.v2*. - -To install it, run: - - go get gopkg.in/yaml.v2 - -API documentation ------------------ - -If opened in a browser, the import path itself leads to the API documentation: - - * [https://gopkg.in/yaml.v2](https://gopkg.in/yaml.v2) - -API stability -------------- - -The package API for yaml v2 will remain stable as described in [gopkg.in](https://gopkg.in). - - -License -------- - -The yaml package is licensed under the Apache License 2.0. Please see the LICENSE file for details. - - -Example -------- - -Some more examples can be found in the "examples" folder. - -```Go -package main - -import ( - "fmt" - "log" - - "gopkg.in/yaml.v2" -) - -var data = ` -a: Easy! -b: - c: 2 - d: [3, 4] -` - -// Note: struct fields must be public in order for unmarshal to -// correctly populate the data. -type T struct { - A string - B struct { - RenamedC int `yaml:"c"` - D []int `yaml:",flow"` - } -} - -func main() { - t := T{} - - err := yaml.Unmarshal([]byte(data), &t) - if err != nil { - log.Fatalf("error: %v", err) - } - fmt.Printf("--- t:\n%v\n\n", t) - - d, err := yaml.Marshal(&t) - if err != nil { - log.Fatalf("error: %v", err) - } - fmt.Printf("--- t dump:\n%s\n\n", string(d)) - - m := make(map[interface{}]interface{}) - - err = yaml.Unmarshal([]byte(data), &m) - if err != nil { - log.Fatalf("error: %v", err) - } - fmt.Printf("--- m:\n%v\n\n", m) - - d, err = yaml.Marshal(&m) - if err != nil { - log.Fatalf("error: %v", err) - } - fmt.Printf("--- m dump:\n%s\n\n", string(d)) -} -``` - -This example will generate the following output: - -``` ---- t: -{Easy! {2 [3 4]}} - ---- t dump: -a: Easy! -b: - c: 2 - d: [3, 4] - - ---- m: -map[a:Easy! b:map[c:2 d:[3 4]]] - ---- m dump: -a: Easy! -b: - c: 2 - d: - - 3 - - 4 -``` - diff --git a/dev-tools/vendor/gopkg.in/yaml.v2/apic.go b/dev-tools/vendor/gopkg.in/yaml.v2/apic.go deleted file mode 100644 index 95ec014e8ccf..000000000000 --- a/dev-tools/vendor/gopkg.in/yaml.v2/apic.go +++ /dev/null @@ -1,742 +0,0 @@ -package yaml - -import ( - "io" - "os" -) - -func yaml_insert_token(parser *yaml_parser_t, pos int, token *yaml_token_t) { - //fmt.Println("yaml_insert_token", "pos:", pos, "typ:", token.typ, "head:", parser.tokens_head, "len:", len(parser.tokens)) - - // Check if we can move the queue at the beginning of the buffer. - if parser.tokens_head > 0 && len(parser.tokens) == cap(parser.tokens) { - if parser.tokens_head != len(parser.tokens) { - copy(parser.tokens, parser.tokens[parser.tokens_head:]) - } - parser.tokens = parser.tokens[:len(parser.tokens)-parser.tokens_head] - parser.tokens_head = 0 - } - parser.tokens = append(parser.tokens, *token) - if pos < 0 { - return - } - copy(parser.tokens[parser.tokens_head+pos+1:], parser.tokens[parser.tokens_head+pos:]) - parser.tokens[parser.tokens_head+pos] = *token -} - -// Create a new parser object. -func yaml_parser_initialize(parser *yaml_parser_t) bool { - *parser = yaml_parser_t{ - raw_buffer: make([]byte, 0, input_raw_buffer_size), - buffer: make([]byte, 0, input_buffer_size), - } - return true -} - -// Destroy a parser object. -func yaml_parser_delete(parser *yaml_parser_t) { - *parser = yaml_parser_t{} -} - -// String read handler. -func yaml_string_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) { - if parser.input_pos == len(parser.input) { - return 0, io.EOF - } - n = copy(buffer, parser.input[parser.input_pos:]) - parser.input_pos += n - return n, nil -} - -// File read handler. -func yaml_file_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) { - return parser.input_file.Read(buffer) -} - -// Set a string input. -func yaml_parser_set_input_string(parser *yaml_parser_t, input []byte) { - if parser.read_handler != nil { - panic("must set the input source only once") - } - parser.read_handler = yaml_string_read_handler - parser.input = input - parser.input_pos = 0 -} - -// Set a file input. -func yaml_parser_set_input_file(parser *yaml_parser_t, file *os.File) { - if parser.read_handler != nil { - panic("must set the input source only once") - } - parser.read_handler = yaml_file_read_handler - parser.input_file = file -} - -// Set the source encoding. -func yaml_parser_set_encoding(parser *yaml_parser_t, encoding yaml_encoding_t) { - if parser.encoding != yaml_ANY_ENCODING { - panic("must set the encoding only once") - } - parser.encoding = encoding -} - -// Create a new emitter object. -func yaml_emitter_initialize(emitter *yaml_emitter_t) bool { - *emitter = yaml_emitter_t{ - buffer: make([]byte, output_buffer_size), - raw_buffer: make([]byte, 0, output_raw_buffer_size), - states: make([]yaml_emitter_state_t, 0, initial_stack_size), - events: make([]yaml_event_t, 0, initial_queue_size), - } - return true -} - -// Destroy an emitter object. -func yaml_emitter_delete(emitter *yaml_emitter_t) { - *emitter = yaml_emitter_t{} -} - -// String write handler. -func yaml_string_write_handler(emitter *yaml_emitter_t, buffer []byte) error { - *emitter.output_buffer = append(*emitter.output_buffer, buffer...) - return nil -} - -// File write handler. -func yaml_file_write_handler(emitter *yaml_emitter_t, buffer []byte) error { - _, err := emitter.output_file.Write(buffer) - return err -} - -// Set a string output. -func yaml_emitter_set_output_string(emitter *yaml_emitter_t, output_buffer *[]byte) { - if emitter.write_handler != nil { - panic("must set the output target only once") - } - emitter.write_handler = yaml_string_write_handler - emitter.output_buffer = output_buffer -} - -// Set a file output. -func yaml_emitter_set_output_file(emitter *yaml_emitter_t, file io.Writer) { - if emitter.write_handler != nil { - panic("must set the output target only once") - } - emitter.write_handler = yaml_file_write_handler - emitter.output_file = file -} - -// Set the output encoding. -func yaml_emitter_set_encoding(emitter *yaml_emitter_t, encoding yaml_encoding_t) { - if emitter.encoding != yaml_ANY_ENCODING { - panic("must set the output encoding only once") - } - emitter.encoding = encoding -} - -// Set the canonical output style. -func yaml_emitter_set_canonical(emitter *yaml_emitter_t, canonical bool) { - emitter.canonical = canonical -} - -//// Set the indentation increment. -func yaml_emitter_set_indent(emitter *yaml_emitter_t, indent int) { - if indent < 2 || indent > 9 { - indent = 2 - } - emitter.best_indent = indent -} - -// Set the preferred line width. -func yaml_emitter_set_width(emitter *yaml_emitter_t, width int) { - if width < 0 { - width = -1 - } - emitter.best_width = width -} - -// Set if unescaped non-ASCII characters are allowed. -func yaml_emitter_set_unicode(emitter *yaml_emitter_t, unicode bool) { - emitter.unicode = unicode -} - -// Set the preferred line break character. -func yaml_emitter_set_break(emitter *yaml_emitter_t, line_break yaml_break_t) { - emitter.line_break = line_break -} - -///* -// * Destroy a token object. -// */ -// -//YAML_DECLARE(void) -//yaml_token_delete(yaml_token_t *token) -//{ -// assert(token); // Non-NULL token object expected. -// -// switch (token.type) -// { -// case YAML_TAG_DIRECTIVE_TOKEN: -// yaml_free(token.data.tag_directive.handle); -// yaml_free(token.data.tag_directive.prefix); -// break; -// -// case YAML_ALIAS_TOKEN: -// yaml_free(token.data.alias.value); -// break; -// -// case YAML_ANCHOR_TOKEN: -// yaml_free(token.data.anchor.value); -// break; -// -// case YAML_TAG_TOKEN: -// yaml_free(token.data.tag.handle); -// yaml_free(token.data.tag.suffix); -// break; -// -// case YAML_SCALAR_TOKEN: -// yaml_free(token.data.scalar.value); -// break; -// -// default: -// break; -// } -// -// memset(token, 0, sizeof(yaml_token_t)); -//} -// -///* -// * Check if a string is a valid UTF-8 sequence. -// * -// * Check 'reader.c' for more details on UTF-8 encoding. -// */ -// -//static int -//yaml_check_utf8(yaml_char_t *start, size_t length) -//{ -// yaml_char_t *end = start+length; -// yaml_char_t *pointer = start; -// -// while (pointer < end) { -// unsigned char octet; -// unsigned int width; -// unsigned int value; -// size_t k; -// -// octet = pointer[0]; -// width = (octet & 0x80) == 0x00 ? 1 : -// (octet & 0xE0) == 0xC0 ? 2 : -// (octet & 0xF0) == 0xE0 ? 3 : -// (octet & 0xF8) == 0xF0 ? 4 : 0; -// value = (octet & 0x80) == 0x00 ? octet & 0x7F : -// (octet & 0xE0) == 0xC0 ? octet & 0x1F : -// (octet & 0xF0) == 0xE0 ? octet & 0x0F : -// (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; -// if (!width) return 0; -// if (pointer+width > end) return 0; -// for (k = 1; k < width; k ++) { -// octet = pointer[k]; -// if ((octet & 0xC0) != 0x80) return 0; -// value = (value << 6) + (octet & 0x3F); -// } -// if (!((width == 1) || -// (width == 2 && value >= 0x80) || -// (width == 3 && value >= 0x800) || -// (width == 4 && value >= 0x10000))) return 0; -// -// pointer += width; -// } -// -// return 1; -//} -// - -// Create STREAM-START. -func yaml_stream_start_event_initialize(event *yaml_event_t, encoding yaml_encoding_t) bool { - *event = yaml_event_t{ - typ: yaml_STREAM_START_EVENT, - encoding: encoding, - } - return true -} - -// Create STREAM-END. -func yaml_stream_end_event_initialize(event *yaml_event_t) bool { - *event = yaml_event_t{ - typ: yaml_STREAM_END_EVENT, - } - return true -} - -// Create DOCUMENT-START. -func yaml_document_start_event_initialize(event *yaml_event_t, version_directive *yaml_version_directive_t, - tag_directives []yaml_tag_directive_t, implicit bool) bool { - *event = yaml_event_t{ - typ: yaml_DOCUMENT_START_EVENT, - version_directive: version_directive, - tag_directives: tag_directives, - implicit: implicit, - } - return true -} - -// Create DOCUMENT-END. -func yaml_document_end_event_initialize(event *yaml_event_t, implicit bool) bool { - *event = yaml_event_t{ - typ: yaml_DOCUMENT_END_EVENT, - implicit: implicit, - } - return true -} - -///* -// * Create ALIAS. -// */ -// -//YAML_DECLARE(int) -//yaml_alias_event_initialize(event *yaml_event_t, anchor *yaml_char_t) -//{ -// mark yaml_mark_t = { 0, 0, 0 } -// anchor_copy *yaml_char_t = NULL -// -// assert(event) // Non-NULL event object is expected. -// assert(anchor) // Non-NULL anchor is expected. -// -// if (!yaml_check_utf8(anchor, strlen((char *)anchor))) return 0 -// -// anchor_copy = yaml_strdup(anchor) -// if (!anchor_copy) -// return 0 -// -// ALIAS_EVENT_INIT(*event, anchor_copy, mark, mark) -// -// return 1 -//} - -// Create SCALAR. -func yaml_scalar_event_initialize(event *yaml_event_t, anchor, tag, value []byte, plain_implicit, quoted_implicit bool, style yaml_scalar_style_t) bool { - *event = yaml_event_t{ - typ: yaml_SCALAR_EVENT, - anchor: anchor, - tag: tag, - value: value, - implicit: plain_implicit, - quoted_implicit: quoted_implicit, - style: yaml_style_t(style), - } - return true -} - -// Create SEQUENCE-START. -func yaml_sequence_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_sequence_style_t) bool { - *event = yaml_event_t{ - typ: yaml_SEQUENCE_START_EVENT, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(style), - } - return true -} - -// Create SEQUENCE-END. -func yaml_sequence_end_event_initialize(event *yaml_event_t) bool { - *event = yaml_event_t{ - typ: yaml_SEQUENCE_END_EVENT, - } - return true -} - -// Create MAPPING-START. -func yaml_mapping_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_mapping_style_t) bool { - *event = yaml_event_t{ - typ: yaml_MAPPING_START_EVENT, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(style), - } - return true -} - -// Create MAPPING-END. -func yaml_mapping_end_event_initialize(event *yaml_event_t) bool { - *event = yaml_event_t{ - typ: yaml_MAPPING_END_EVENT, - } - return true -} - -// Destroy an event object. -func yaml_event_delete(event *yaml_event_t) { - *event = yaml_event_t{} -} - -///* -// * Create a document object. -// */ -// -//YAML_DECLARE(int) -//yaml_document_initialize(document *yaml_document_t, -// version_directive *yaml_version_directive_t, -// tag_directives_start *yaml_tag_directive_t, -// tag_directives_end *yaml_tag_directive_t, -// start_implicit int, end_implicit int) -//{ -// struct { -// error yaml_error_type_t -// } context -// struct { -// start *yaml_node_t -// end *yaml_node_t -// top *yaml_node_t -// } nodes = { NULL, NULL, NULL } -// version_directive_copy *yaml_version_directive_t = NULL -// struct { -// start *yaml_tag_directive_t -// end *yaml_tag_directive_t -// top *yaml_tag_directive_t -// } tag_directives_copy = { NULL, NULL, NULL } -// value yaml_tag_directive_t = { NULL, NULL } -// mark yaml_mark_t = { 0, 0, 0 } -// -// assert(document) // Non-NULL document object is expected. -// assert((tag_directives_start && tag_directives_end) || -// (tag_directives_start == tag_directives_end)) -// // Valid tag directives are expected. -// -// if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error -// -// if (version_directive) { -// version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t)) -// if (!version_directive_copy) goto error -// version_directive_copy.major = version_directive.major -// version_directive_copy.minor = version_directive.minor -// } -// -// if (tag_directives_start != tag_directives_end) { -// tag_directive *yaml_tag_directive_t -// if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE)) -// goto error -// for (tag_directive = tag_directives_start -// tag_directive != tag_directives_end; tag_directive ++) { -// assert(tag_directive.handle) -// assert(tag_directive.prefix) -// if (!yaml_check_utf8(tag_directive.handle, -// strlen((char *)tag_directive.handle))) -// goto error -// if (!yaml_check_utf8(tag_directive.prefix, -// strlen((char *)tag_directive.prefix))) -// goto error -// value.handle = yaml_strdup(tag_directive.handle) -// value.prefix = yaml_strdup(tag_directive.prefix) -// if (!value.handle || !value.prefix) goto error -// if (!PUSH(&context, tag_directives_copy, value)) -// goto error -// value.handle = NULL -// value.prefix = NULL -// } -// } -// -// DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy, -// tag_directives_copy.start, tag_directives_copy.top, -// start_implicit, end_implicit, mark, mark) -// -// return 1 -// -//error: -// STACK_DEL(&context, nodes) -// yaml_free(version_directive_copy) -// while (!STACK_EMPTY(&context, tag_directives_copy)) { -// value yaml_tag_directive_t = POP(&context, tag_directives_copy) -// yaml_free(value.handle) -// yaml_free(value.prefix) -// } -// STACK_DEL(&context, tag_directives_copy) -// yaml_free(value.handle) -// yaml_free(value.prefix) -// -// return 0 -//} -// -///* -// * Destroy a document object. -// */ -// -//YAML_DECLARE(void) -//yaml_document_delete(document *yaml_document_t) -//{ -// struct { -// error yaml_error_type_t -// } context -// tag_directive *yaml_tag_directive_t -// -// context.error = YAML_NO_ERROR // Eliminate a compliler warning. -// -// assert(document) // Non-NULL document object is expected. -// -// while (!STACK_EMPTY(&context, document.nodes)) { -// node yaml_node_t = POP(&context, document.nodes) -// yaml_free(node.tag) -// switch (node.type) { -// case YAML_SCALAR_NODE: -// yaml_free(node.data.scalar.value) -// break -// case YAML_SEQUENCE_NODE: -// STACK_DEL(&context, node.data.sequence.items) -// break -// case YAML_MAPPING_NODE: -// STACK_DEL(&context, node.data.mapping.pairs) -// break -// default: -// assert(0) // Should not happen. -// } -// } -// STACK_DEL(&context, document.nodes) -// -// yaml_free(document.version_directive) -// for (tag_directive = document.tag_directives.start -// tag_directive != document.tag_directives.end -// tag_directive++) { -// yaml_free(tag_directive.handle) -// yaml_free(tag_directive.prefix) -// } -// yaml_free(document.tag_directives.start) -// -// memset(document, 0, sizeof(yaml_document_t)) -//} -// -///** -// * Get a document node. -// */ -// -//YAML_DECLARE(yaml_node_t *) -//yaml_document_get_node(document *yaml_document_t, index int) -//{ -// assert(document) // Non-NULL document object is expected. -// -// if (index > 0 && document.nodes.start + index <= document.nodes.top) { -// return document.nodes.start + index - 1 -// } -// return NULL -//} -// -///** -// * Get the root object. -// */ -// -//YAML_DECLARE(yaml_node_t *) -//yaml_document_get_root_node(document *yaml_document_t) -//{ -// assert(document) // Non-NULL document object is expected. -// -// if (document.nodes.top != document.nodes.start) { -// return document.nodes.start -// } -// return NULL -//} -// -///* -// * Add a scalar node to a document. -// */ -// -//YAML_DECLARE(int) -//yaml_document_add_scalar(document *yaml_document_t, -// tag *yaml_char_t, value *yaml_char_t, length int, -// style yaml_scalar_style_t) -//{ -// struct { -// error yaml_error_type_t -// } context -// mark yaml_mark_t = { 0, 0, 0 } -// tag_copy *yaml_char_t = NULL -// value_copy *yaml_char_t = NULL -// node yaml_node_t -// -// assert(document) // Non-NULL document object is expected. -// assert(value) // Non-NULL value is expected. -// -// if (!tag) { -// tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG -// } -// -// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error -// tag_copy = yaml_strdup(tag) -// if (!tag_copy) goto error -// -// if (length < 0) { -// length = strlen((char *)value) -// } -// -// if (!yaml_check_utf8(value, length)) goto error -// value_copy = yaml_malloc(length+1) -// if (!value_copy) goto error -// memcpy(value_copy, value, length) -// value_copy[length] = '\0' -// -// SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark) -// if (!PUSH(&context, document.nodes, node)) goto error -// -// return document.nodes.top - document.nodes.start -// -//error: -// yaml_free(tag_copy) -// yaml_free(value_copy) -// -// return 0 -//} -// -///* -// * Add a sequence node to a document. -// */ -// -//YAML_DECLARE(int) -//yaml_document_add_sequence(document *yaml_document_t, -// tag *yaml_char_t, style yaml_sequence_style_t) -//{ -// struct { -// error yaml_error_type_t -// } context -// mark yaml_mark_t = { 0, 0, 0 } -// tag_copy *yaml_char_t = NULL -// struct { -// start *yaml_node_item_t -// end *yaml_node_item_t -// top *yaml_node_item_t -// } items = { NULL, NULL, NULL } -// node yaml_node_t -// -// assert(document) // Non-NULL document object is expected. -// -// if (!tag) { -// tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG -// } -// -// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error -// tag_copy = yaml_strdup(tag) -// if (!tag_copy) goto error -// -// if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error -// -// SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end, -// style, mark, mark) -// if (!PUSH(&context, document.nodes, node)) goto error -// -// return document.nodes.top - document.nodes.start -// -//error: -// STACK_DEL(&context, items) -// yaml_free(tag_copy) -// -// return 0 -//} -// -///* -// * Add a mapping node to a document. -// */ -// -//YAML_DECLARE(int) -//yaml_document_add_mapping(document *yaml_document_t, -// tag *yaml_char_t, style yaml_mapping_style_t) -//{ -// struct { -// error yaml_error_type_t -// } context -// mark yaml_mark_t = { 0, 0, 0 } -// tag_copy *yaml_char_t = NULL -// struct { -// start *yaml_node_pair_t -// end *yaml_node_pair_t -// top *yaml_node_pair_t -// } pairs = { NULL, NULL, NULL } -// node yaml_node_t -// -// assert(document) // Non-NULL document object is expected. -// -// if (!tag) { -// tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG -// } -// -// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error -// tag_copy = yaml_strdup(tag) -// if (!tag_copy) goto error -// -// if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error -// -// MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end, -// style, mark, mark) -// if (!PUSH(&context, document.nodes, node)) goto error -// -// return document.nodes.top - document.nodes.start -// -//error: -// STACK_DEL(&context, pairs) -// yaml_free(tag_copy) -// -// return 0 -//} -// -///* -// * Append an item to a sequence node. -// */ -// -//YAML_DECLARE(int) -//yaml_document_append_sequence_item(document *yaml_document_t, -// sequence int, item int) -//{ -// struct { -// error yaml_error_type_t -// } context -// -// assert(document) // Non-NULL document is required. -// assert(sequence > 0 -// && document.nodes.start + sequence <= document.nodes.top) -// // Valid sequence id is required. -// assert(document.nodes.start[sequence-1].type == YAML_SEQUENCE_NODE) -// // A sequence node is required. -// assert(item > 0 && document.nodes.start + item <= document.nodes.top) -// // Valid item id is required. -// -// if (!PUSH(&context, -// document.nodes.start[sequence-1].data.sequence.items, item)) -// return 0 -// -// return 1 -//} -// -///* -// * Append a pair of a key and a value to a mapping node. -// */ -// -//YAML_DECLARE(int) -//yaml_document_append_mapping_pair(document *yaml_document_t, -// mapping int, key int, value int) -//{ -// struct { -// error yaml_error_type_t -// } context -// -// pair yaml_node_pair_t -// -// assert(document) // Non-NULL document is required. -// assert(mapping > 0 -// && document.nodes.start + mapping <= document.nodes.top) -// // Valid mapping id is required. -// assert(document.nodes.start[mapping-1].type == YAML_MAPPING_NODE) -// // A mapping node is required. -// assert(key > 0 && document.nodes.start + key <= document.nodes.top) -// // Valid key id is required. -// assert(value > 0 && document.nodes.start + value <= document.nodes.top) -// // Valid value id is required. -// -// pair.key = key -// pair.value = value -// -// if (!PUSH(&context, -// document.nodes.start[mapping-1].data.mapping.pairs, pair)) -// return 0 -// -// return 1 -//} -// -// diff --git a/dev-tools/vendor/gopkg.in/yaml.v2/decode.go b/dev-tools/vendor/gopkg.in/yaml.v2/decode.go deleted file mode 100644 index e85eb2e3fe1b..000000000000 --- a/dev-tools/vendor/gopkg.in/yaml.v2/decode.go +++ /dev/null @@ -1,685 +0,0 @@ -package yaml - -import ( - "encoding" - "encoding/base64" - "fmt" - "math" - "reflect" - "strconv" - "time" -) - -const ( - documentNode = 1 << iota - mappingNode - sequenceNode - scalarNode - aliasNode -) - -type node struct { - kind int - line, column int - tag string - value string - implicit bool - children []*node - anchors map[string]*node -} - -// ---------------------------------------------------------------------------- -// Parser, produces a node tree out of a libyaml event stream. - -type parser struct { - parser yaml_parser_t - event yaml_event_t - doc *node -} - -func newParser(b []byte) *parser { - p := parser{} - if !yaml_parser_initialize(&p.parser) { - panic("failed to initialize YAML emitter") - } - - if len(b) == 0 { - b = []byte{'\n'} - } - - yaml_parser_set_input_string(&p.parser, b) - - p.skip() - if p.event.typ != yaml_STREAM_START_EVENT { - panic("expected stream start event, got " + strconv.Itoa(int(p.event.typ))) - } - p.skip() - return &p -} - -func (p *parser) destroy() { - if p.event.typ != yaml_NO_EVENT { - yaml_event_delete(&p.event) - } - yaml_parser_delete(&p.parser) -} - -func (p *parser) skip() { - if p.event.typ != yaml_NO_EVENT { - if p.event.typ == yaml_STREAM_END_EVENT { - failf("attempted to go past the end of stream; corrupted value?") - } - yaml_event_delete(&p.event) - } - if !yaml_parser_parse(&p.parser, &p.event) { - p.fail() - } -} - -func (p *parser) fail() { - var where string - var line int - if p.parser.problem_mark.line != 0 { - line = p.parser.problem_mark.line - } else if p.parser.context_mark.line != 0 { - line = p.parser.context_mark.line - } - if line != 0 { - where = "line " + strconv.Itoa(line) + ": " - } - var msg string - if len(p.parser.problem) > 0 { - msg = p.parser.problem - } else { - msg = "unknown problem parsing YAML content" - } - failf("%s%s", where, msg) -} - -func (p *parser) anchor(n *node, anchor []byte) { - if anchor != nil { - p.doc.anchors[string(anchor)] = n - } -} - -func (p *parser) parse() *node { - switch p.event.typ { - case yaml_SCALAR_EVENT: - return p.scalar() - case yaml_ALIAS_EVENT: - return p.alias() - case yaml_MAPPING_START_EVENT: - return p.mapping() - case yaml_SEQUENCE_START_EVENT: - return p.sequence() - case yaml_DOCUMENT_START_EVENT: - return p.document() - case yaml_STREAM_END_EVENT: - // Happens when attempting to decode an empty buffer. - return nil - default: - panic("attempted to parse unknown event: " + strconv.Itoa(int(p.event.typ))) - } -} - -func (p *parser) node(kind int) *node { - return &node{ - kind: kind, - line: p.event.start_mark.line, - column: p.event.start_mark.column, - } -} - -func (p *parser) document() *node { - n := p.node(documentNode) - n.anchors = make(map[string]*node) - p.doc = n - p.skip() - n.children = append(n.children, p.parse()) - if p.event.typ != yaml_DOCUMENT_END_EVENT { - panic("expected end of document event but got " + strconv.Itoa(int(p.event.typ))) - } - p.skip() - return n -} - -func (p *parser) alias() *node { - n := p.node(aliasNode) - n.value = string(p.event.anchor) - p.skip() - return n -} - -func (p *parser) scalar() *node { - n := p.node(scalarNode) - n.value = string(p.event.value) - n.tag = string(p.event.tag) - n.implicit = p.event.implicit - p.anchor(n, p.event.anchor) - p.skip() - return n -} - -func (p *parser) sequence() *node { - n := p.node(sequenceNode) - p.anchor(n, p.event.anchor) - p.skip() - for p.event.typ != yaml_SEQUENCE_END_EVENT { - n.children = append(n.children, p.parse()) - } - p.skip() - return n -} - -func (p *parser) mapping() *node { - n := p.node(mappingNode) - p.anchor(n, p.event.anchor) - p.skip() - for p.event.typ != yaml_MAPPING_END_EVENT { - n.children = append(n.children, p.parse(), p.parse()) - } - p.skip() - return n -} - -// ---------------------------------------------------------------------------- -// Decoder, unmarshals a node into a provided value. - -type decoder struct { - doc *node - aliases map[string]bool - mapType reflect.Type - terrors []string - strict bool -} - -var ( - mapItemType = reflect.TypeOf(MapItem{}) - durationType = reflect.TypeOf(time.Duration(0)) - defaultMapType = reflect.TypeOf(map[interface{}]interface{}{}) - ifaceType = defaultMapType.Elem() -) - -func newDecoder(strict bool) *decoder { - d := &decoder{mapType: defaultMapType, strict: strict} - d.aliases = make(map[string]bool) - return d -} - -func (d *decoder) terror(n *node, tag string, out reflect.Value) { - if n.tag != "" { - tag = n.tag - } - value := n.value - if tag != yaml_SEQ_TAG && tag != yaml_MAP_TAG { - if len(value) > 10 { - value = " `" + value[:7] + "...`" - } else { - value = " `" + value + "`" - } - } - d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.line+1, shortTag(tag), value, out.Type())) -} - -func (d *decoder) callUnmarshaler(n *node, u Unmarshaler) (good bool) { - terrlen := len(d.terrors) - err := u.UnmarshalYAML(func(v interface{}) (err error) { - defer handleErr(&err) - d.unmarshal(n, reflect.ValueOf(v)) - if len(d.terrors) > terrlen { - issues := d.terrors[terrlen:] - d.terrors = d.terrors[:terrlen] - return &TypeError{issues} - } - return nil - }) - if e, ok := err.(*TypeError); ok { - d.terrors = append(d.terrors, e.Errors...) - return false - } - if err != nil { - fail(err) - } - return true -} - -// d.prepare initializes and dereferences pointers and calls UnmarshalYAML -// if a value is found to implement it. -// It returns the initialized and dereferenced out value, whether -// unmarshalling was already done by UnmarshalYAML, and if so whether -// its types unmarshalled appropriately. -// -// If n holds a null value, prepare returns before doing anything. -func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) { - if n.tag == yaml_NULL_TAG || n.kind == scalarNode && n.tag == "" && (n.value == "null" || n.value == "~" || n.value == "" && n.implicit) { - return out, false, false - } - again := true - for again { - again = false - if out.Kind() == reflect.Ptr { - if out.IsNil() { - out.Set(reflect.New(out.Type().Elem())) - } - out = out.Elem() - again = true - } - if out.CanAddr() { - if u, ok := out.Addr().Interface().(Unmarshaler); ok { - good = d.callUnmarshaler(n, u) - return out, true, good - } - } - } - return out, false, false -} - -func (d *decoder) unmarshal(n *node, out reflect.Value) (good bool) { - switch n.kind { - case documentNode: - return d.document(n, out) - case aliasNode: - return d.alias(n, out) - } - out, unmarshaled, good := d.prepare(n, out) - if unmarshaled { - return good - } - switch n.kind { - case scalarNode: - good = d.scalar(n, out) - case mappingNode: - good = d.mapping(n, out) - case sequenceNode: - good = d.sequence(n, out) - default: - panic("internal error: unknown node kind: " + strconv.Itoa(n.kind)) - } - return good -} - -func (d *decoder) document(n *node, out reflect.Value) (good bool) { - if len(n.children) == 1 { - d.doc = n - d.unmarshal(n.children[0], out) - return true - } - return false -} - -func (d *decoder) alias(n *node, out reflect.Value) (good bool) { - an, ok := d.doc.anchors[n.value] - if !ok { - failf("unknown anchor '%s' referenced", n.value) - } - if d.aliases[n.value] { - failf("anchor '%s' value contains itself", n.value) - } - d.aliases[n.value] = true - good = d.unmarshal(an, out) - delete(d.aliases, n.value) - return good -} - -var zeroValue reflect.Value - -func resetMap(out reflect.Value) { - for _, k := range out.MapKeys() { - out.SetMapIndex(k, zeroValue) - } -} - -func (d *decoder) scalar(n *node, out reflect.Value) (good bool) { - var tag string - var resolved interface{} - if n.tag == "" && !n.implicit { - tag = yaml_STR_TAG - resolved = n.value - } else { - tag, resolved = resolve(n.tag, n.value) - if tag == yaml_BINARY_TAG { - data, err := base64.StdEncoding.DecodeString(resolved.(string)) - if err != nil { - failf("!!binary value contains invalid base64 data") - } - resolved = string(data) - } - } - if resolved == nil { - if out.Kind() == reflect.Map && !out.CanAddr() { - resetMap(out) - } else { - out.Set(reflect.Zero(out.Type())) - } - return true - } - if s, ok := resolved.(string); ok && out.CanAddr() { - if u, ok := out.Addr().Interface().(encoding.TextUnmarshaler); ok { - err := u.UnmarshalText([]byte(s)) - if err != nil { - fail(err) - } - return true - } - } - switch out.Kind() { - case reflect.String: - if tag == yaml_BINARY_TAG { - out.SetString(resolved.(string)) - good = true - } else if resolved != nil { - out.SetString(n.value) - good = true - } - case reflect.Interface: - if resolved == nil { - out.Set(reflect.Zero(out.Type())) - } else { - out.Set(reflect.ValueOf(resolved)) - } - good = true - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - switch resolved := resolved.(type) { - case int: - if !out.OverflowInt(int64(resolved)) { - out.SetInt(int64(resolved)) - good = true - } - case int64: - if !out.OverflowInt(resolved) { - out.SetInt(resolved) - good = true - } - case uint64: - if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) { - out.SetInt(int64(resolved)) - good = true - } - case float64: - if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) { - out.SetInt(int64(resolved)) - good = true - } - case string: - if out.Type() == durationType { - d, err := time.ParseDuration(resolved) - if err == nil { - out.SetInt(int64(d)) - good = true - } - } - } - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - switch resolved := resolved.(type) { - case int: - if resolved >= 0 && !out.OverflowUint(uint64(resolved)) { - out.SetUint(uint64(resolved)) - good = true - } - case int64: - if resolved >= 0 && !out.OverflowUint(uint64(resolved)) { - out.SetUint(uint64(resolved)) - good = true - } - case uint64: - if !out.OverflowUint(uint64(resolved)) { - out.SetUint(uint64(resolved)) - good = true - } - case float64: - if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) { - out.SetUint(uint64(resolved)) - good = true - } - } - case reflect.Bool: - switch resolved := resolved.(type) { - case bool: - out.SetBool(resolved) - good = true - } - case reflect.Float32, reflect.Float64: - switch resolved := resolved.(type) { - case int: - out.SetFloat(float64(resolved)) - good = true - case int64: - out.SetFloat(float64(resolved)) - good = true - case uint64: - out.SetFloat(float64(resolved)) - good = true - case float64: - out.SetFloat(resolved) - good = true - } - case reflect.Ptr: - if out.Type().Elem() == reflect.TypeOf(resolved) { - // TODO DOes this make sense? When is out a Ptr except when decoding a nil value? - elem := reflect.New(out.Type().Elem()) - elem.Elem().Set(reflect.ValueOf(resolved)) - out.Set(elem) - good = true - } - } - if !good { - d.terror(n, tag, out) - } - return good -} - -func settableValueOf(i interface{}) reflect.Value { - v := reflect.ValueOf(i) - sv := reflect.New(v.Type()).Elem() - sv.Set(v) - return sv -} - -func (d *decoder) sequence(n *node, out reflect.Value) (good bool) { - l := len(n.children) - - var iface reflect.Value - switch out.Kind() { - case reflect.Slice: - out.Set(reflect.MakeSlice(out.Type(), l, l)) - case reflect.Interface: - // No type hints. Will have to use a generic sequence. - iface = out - out = settableValueOf(make([]interface{}, l)) - default: - d.terror(n, yaml_SEQ_TAG, out) - return false - } - et := out.Type().Elem() - - j := 0 - for i := 0; i < l; i++ { - e := reflect.New(et).Elem() - if ok := d.unmarshal(n.children[i], e); ok { - out.Index(j).Set(e) - j++ - } - } - out.Set(out.Slice(0, j)) - if iface.IsValid() { - iface.Set(out) - } - return true -} - -func (d *decoder) mapping(n *node, out reflect.Value) (good bool) { - switch out.Kind() { - case reflect.Struct: - return d.mappingStruct(n, out) - case reflect.Slice: - return d.mappingSlice(n, out) - case reflect.Map: - // okay - case reflect.Interface: - if d.mapType.Kind() == reflect.Map { - iface := out - out = reflect.MakeMap(d.mapType) - iface.Set(out) - } else { - slicev := reflect.New(d.mapType).Elem() - if !d.mappingSlice(n, slicev) { - return false - } - out.Set(slicev) - return true - } - default: - d.terror(n, yaml_MAP_TAG, out) - return false - } - outt := out.Type() - kt := outt.Key() - et := outt.Elem() - - mapType := d.mapType - if outt.Key() == ifaceType && outt.Elem() == ifaceType { - d.mapType = outt - } - - if out.IsNil() { - out.Set(reflect.MakeMap(outt)) - } - l := len(n.children) - for i := 0; i < l; i += 2 { - if isMerge(n.children[i]) { - d.merge(n.children[i+1], out) - continue - } - k := reflect.New(kt).Elem() - if d.unmarshal(n.children[i], k) { - kkind := k.Kind() - if kkind == reflect.Interface { - kkind = k.Elem().Kind() - } - if kkind == reflect.Map || kkind == reflect.Slice { - failf("invalid map key: %#v", k.Interface()) - } - e := reflect.New(et).Elem() - if d.unmarshal(n.children[i+1], e) { - out.SetMapIndex(k, e) - } - } - } - d.mapType = mapType - return true -} - -func (d *decoder) mappingSlice(n *node, out reflect.Value) (good bool) { - outt := out.Type() - if outt.Elem() != mapItemType { - d.terror(n, yaml_MAP_TAG, out) - return false - } - - mapType := d.mapType - d.mapType = outt - - var slice []MapItem - var l = len(n.children) - for i := 0; i < l; i += 2 { - if isMerge(n.children[i]) { - d.merge(n.children[i+1], out) - continue - } - item := MapItem{} - k := reflect.ValueOf(&item.Key).Elem() - if d.unmarshal(n.children[i], k) { - v := reflect.ValueOf(&item.Value).Elem() - if d.unmarshal(n.children[i+1], v) { - slice = append(slice, item) - } - } - } - out.Set(reflect.ValueOf(slice)) - d.mapType = mapType - return true -} - -func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) { - sinfo, err := getStructInfo(out.Type()) - if err != nil { - panic(err) - } - name := settableValueOf("") - l := len(n.children) - - var inlineMap reflect.Value - var elemType reflect.Type - if sinfo.InlineMap != -1 { - inlineMap = out.Field(sinfo.InlineMap) - inlineMap.Set(reflect.New(inlineMap.Type()).Elem()) - elemType = inlineMap.Type().Elem() - } - - for i := 0; i < l; i += 2 { - ni := n.children[i] - if isMerge(ni) { - d.merge(n.children[i+1], out) - continue - } - if !d.unmarshal(ni, name) { - continue - } - if info, ok := sinfo.FieldsMap[name.String()]; ok { - var field reflect.Value - if info.Inline == nil { - field = out.Field(info.Num) - } else { - field = out.FieldByIndex(info.Inline) - } - d.unmarshal(n.children[i+1], field) - } else if sinfo.InlineMap != -1 { - if inlineMap.IsNil() { - inlineMap.Set(reflect.MakeMap(inlineMap.Type())) - } - value := reflect.New(elemType).Elem() - d.unmarshal(n.children[i+1], value) - inlineMap.SetMapIndex(name, value) - } else if d.strict { - d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in struct %s", ni.line+1, name.String(), out.Type())) - } - } - return true -} - -func failWantMap() { - failf("map merge requires map or sequence of maps as the value") -} - -func (d *decoder) merge(n *node, out reflect.Value) { - switch n.kind { - case mappingNode: - d.unmarshal(n, out) - case aliasNode: - an, ok := d.doc.anchors[n.value] - if ok && an.kind != mappingNode { - failWantMap() - } - d.unmarshal(n, out) - case sequenceNode: - // Step backwards as earlier nodes take precedence. - for i := len(n.children) - 1; i >= 0; i-- { - ni := n.children[i] - if ni.kind == aliasNode { - an, ok := d.doc.anchors[ni.value] - if ok && an.kind != mappingNode { - failWantMap() - } - } else if ni.kind != mappingNode { - failWantMap() - } - d.unmarshal(ni, out) - } - default: - failWantMap() - } -} - -func isMerge(n *node) bool { - return n.kind == scalarNode && n.value == "<<" && (n.implicit == true || n.tag == yaml_MERGE_TAG) -} diff --git a/dev-tools/vendor/gopkg.in/yaml.v2/emitterc.go b/dev-tools/vendor/gopkg.in/yaml.v2/emitterc.go deleted file mode 100644 index dcaf502f0ebd..000000000000 --- a/dev-tools/vendor/gopkg.in/yaml.v2/emitterc.go +++ /dev/null @@ -1,1684 +0,0 @@ -package yaml - -import ( - "bytes" -) - -// Flush the buffer if needed. -func flush(emitter *yaml_emitter_t) bool { - if emitter.buffer_pos+5 >= len(emitter.buffer) { - return yaml_emitter_flush(emitter) - } - return true -} - -// Put a character to the output buffer. -func put(emitter *yaml_emitter_t, value byte) bool { - if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) { - return false - } - emitter.buffer[emitter.buffer_pos] = value - emitter.buffer_pos++ - emitter.column++ - return true -} - -// Put a line break to the output buffer. -func put_break(emitter *yaml_emitter_t) bool { - if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) { - return false - } - switch emitter.line_break { - case yaml_CR_BREAK: - emitter.buffer[emitter.buffer_pos] = '\r' - emitter.buffer_pos += 1 - case yaml_LN_BREAK: - emitter.buffer[emitter.buffer_pos] = '\n' - emitter.buffer_pos += 1 - case yaml_CRLN_BREAK: - emitter.buffer[emitter.buffer_pos+0] = '\r' - emitter.buffer[emitter.buffer_pos+1] = '\n' - emitter.buffer_pos += 2 - default: - panic("unknown line break setting") - } - emitter.column = 0 - emitter.line++ - return true -} - -// Copy a character from a string into buffer. -func write(emitter *yaml_emitter_t, s []byte, i *int) bool { - if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) { - return false - } - p := emitter.buffer_pos - w := width(s[*i]) - switch w { - case 4: - emitter.buffer[p+3] = s[*i+3] - fallthrough - case 3: - emitter.buffer[p+2] = s[*i+2] - fallthrough - case 2: - emitter.buffer[p+1] = s[*i+1] - fallthrough - case 1: - emitter.buffer[p+0] = s[*i+0] - default: - panic("unknown character width") - } - emitter.column++ - emitter.buffer_pos += w - *i += w - return true -} - -// Write a whole string into buffer. -func write_all(emitter *yaml_emitter_t, s []byte) bool { - for i := 0; i < len(s); { - if !write(emitter, s, &i) { - return false - } - } - return true -} - -// Copy a line break character from a string into buffer. -func write_break(emitter *yaml_emitter_t, s []byte, i *int) bool { - if s[*i] == '\n' { - if !put_break(emitter) { - return false - } - *i++ - } else { - if !write(emitter, s, i) { - return false - } - emitter.column = 0 - emitter.line++ - } - return true -} - -// Set an emitter error and return false. -func yaml_emitter_set_emitter_error(emitter *yaml_emitter_t, problem string) bool { - emitter.error = yaml_EMITTER_ERROR - emitter.problem = problem - return false -} - -// Emit an event. -func yaml_emitter_emit(emitter *yaml_emitter_t, event *yaml_event_t) bool { - emitter.events = append(emitter.events, *event) - for !yaml_emitter_need_more_events(emitter) { - event := &emitter.events[emitter.events_head] - if !yaml_emitter_analyze_event(emitter, event) { - return false - } - if !yaml_emitter_state_machine(emitter, event) { - return false - } - yaml_event_delete(event) - emitter.events_head++ - } - return true -} - -// Check if we need to accumulate more events before emitting. -// -// We accumulate extra -// - 1 event for DOCUMENT-START -// - 2 events for SEQUENCE-START -// - 3 events for MAPPING-START -// -func yaml_emitter_need_more_events(emitter *yaml_emitter_t) bool { - if emitter.events_head == len(emitter.events) { - return true - } - var accumulate int - switch emitter.events[emitter.events_head].typ { - case yaml_DOCUMENT_START_EVENT: - accumulate = 1 - break - case yaml_SEQUENCE_START_EVENT: - accumulate = 2 - break - case yaml_MAPPING_START_EVENT: - accumulate = 3 - break - default: - return false - } - if len(emitter.events)-emitter.events_head > accumulate { - return false - } - var level int - for i := emitter.events_head; i < len(emitter.events); i++ { - switch emitter.events[i].typ { - case yaml_STREAM_START_EVENT, yaml_DOCUMENT_START_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT: - level++ - case yaml_STREAM_END_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_END_EVENT, yaml_MAPPING_END_EVENT: - level-- - } - if level == 0 { - return false - } - } - return true -} - -// Append a directive to the directives stack. -func yaml_emitter_append_tag_directive(emitter *yaml_emitter_t, value *yaml_tag_directive_t, allow_duplicates bool) bool { - for i := 0; i < len(emitter.tag_directives); i++ { - if bytes.Equal(value.handle, emitter.tag_directives[i].handle) { - if allow_duplicates { - return true - } - return yaml_emitter_set_emitter_error(emitter, "duplicate %TAG directive") - } - } - - // [Go] Do we actually need to copy this given garbage collection - // and the lack of deallocating destructors? - tag_copy := yaml_tag_directive_t{ - handle: make([]byte, len(value.handle)), - prefix: make([]byte, len(value.prefix)), - } - copy(tag_copy.handle, value.handle) - copy(tag_copy.prefix, value.prefix) - emitter.tag_directives = append(emitter.tag_directives, tag_copy) - return true -} - -// Increase the indentation level. -func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow, indentless bool) bool { - emitter.indents = append(emitter.indents, emitter.indent) - if emitter.indent < 0 { - if flow { - emitter.indent = emitter.best_indent - } else { - emitter.indent = 0 - } - } else if !indentless { - emitter.indent += emitter.best_indent - } - return true -} - -// State dispatcher. -func yaml_emitter_state_machine(emitter *yaml_emitter_t, event *yaml_event_t) bool { - switch emitter.state { - default: - case yaml_EMIT_STREAM_START_STATE: - return yaml_emitter_emit_stream_start(emitter, event) - - case yaml_EMIT_FIRST_DOCUMENT_START_STATE: - return yaml_emitter_emit_document_start(emitter, event, true) - - case yaml_EMIT_DOCUMENT_START_STATE: - return yaml_emitter_emit_document_start(emitter, event, false) - - case yaml_EMIT_DOCUMENT_CONTENT_STATE: - return yaml_emitter_emit_document_content(emitter, event) - - case yaml_EMIT_DOCUMENT_END_STATE: - return yaml_emitter_emit_document_end(emitter, event) - - case yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE: - return yaml_emitter_emit_flow_sequence_item(emitter, event, true) - - case yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE: - return yaml_emitter_emit_flow_sequence_item(emitter, event, false) - - case yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE: - return yaml_emitter_emit_flow_mapping_key(emitter, event, true) - - case yaml_EMIT_FLOW_MAPPING_KEY_STATE: - return yaml_emitter_emit_flow_mapping_key(emitter, event, false) - - case yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE: - return yaml_emitter_emit_flow_mapping_value(emitter, event, true) - - case yaml_EMIT_FLOW_MAPPING_VALUE_STATE: - return yaml_emitter_emit_flow_mapping_value(emitter, event, false) - - case yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE: - return yaml_emitter_emit_block_sequence_item(emitter, event, true) - - case yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE: - return yaml_emitter_emit_block_sequence_item(emitter, event, false) - - case yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE: - return yaml_emitter_emit_block_mapping_key(emitter, event, true) - - case yaml_EMIT_BLOCK_MAPPING_KEY_STATE: - return yaml_emitter_emit_block_mapping_key(emitter, event, false) - - case yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE: - return yaml_emitter_emit_block_mapping_value(emitter, event, true) - - case yaml_EMIT_BLOCK_MAPPING_VALUE_STATE: - return yaml_emitter_emit_block_mapping_value(emitter, event, false) - - case yaml_EMIT_END_STATE: - return yaml_emitter_set_emitter_error(emitter, "expected nothing after STREAM-END") - } - panic("invalid emitter state") -} - -// Expect STREAM-START. -func yaml_emitter_emit_stream_start(emitter *yaml_emitter_t, event *yaml_event_t) bool { - if event.typ != yaml_STREAM_START_EVENT { - return yaml_emitter_set_emitter_error(emitter, "expected STREAM-START") - } - if emitter.encoding == yaml_ANY_ENCODING { - emitter.encoding = event.encoding - if emitter.encoding == yaml_ANY_ENCODING { - emitter.encoding = yaml_UTF8_ENCODING - } - } - if emitter.best_indent < 2 || emitter.best_indent > 9 { - emitter.best_indent = 2 - } - if emitter.best_width >= 0 && emitter.best_width <= emitter.best_indent*2 { - emitter.best_width = 80 - } - if emitter.best_width < 0 { - emitter.best_width = 1<<31 - 1 - } - if emitter.line_break == yaml_ANY_BREAK { - emitter.line_break = yaml_LN_BREAK - } - - emitter.indent = -1 - emitter.line = 0 - emitter.column = 0 - emitter.whitespace = true - emitter.indention = true - - if emitter.encoding != yaml_UTF8_ENCODING { - if !yaml_emitter_write_bom(emitter) { - return false - } - } - emitter.state = yaml_EMIT_FIRST_DOCUMENT_START_STATE - return true -} - -// Expect DOCUMENT-START or STREAM-END. -func yaml_emitter_emit_document_start(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { - - if event.typ == yaml_DOCUMENT_START_EVENT { - - if event.version_directive != nil { - if !yaml_emitter_analyze_version_directive(emitter, event.version_directive) { - return false - } - } - - for i := 0; i < len(event.tag_directives); i++ { - tag_directive := &event.tag_directives[i] - if !yaml_emitter_analyze_tag_directive(emitter, tag_directive) { - return false - } - if !yaml_emitter_append_tag_directive(emitter, tag_directive, false) { - return false - } - } - - for i := 0; i < len(default_tag_directives); i++ { - tag_directive := &default_tag_directives[i] - if !yaml_emitter_append_tag_directive(emitter, tag_directive, true) { - return false - } - } - - implicit := event.implicit - if !first || emitter.canonical { - implicit = false - } - - if emitter.open_ended && (event.version_directive != nil || len(event.tag_directives) > 0) { - if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - - if event.version_directive != nil { - implicit = false - if !yaml_emitter_write_indicator(emitter, []byte("%YAML"), true, false, false) { - return false - } - if !yaml_emitter_write_indicator(emitter, []byte("1.1"), true, false, false) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - - if len(event.tag_directives) > 0 { - implicit = false - for i := 0; i < len(event.tag_directives); i++ { - tag_directive := &event.tag_directives[i] - if !yaml_emitter_write_indicator(emitter, []byte("%TAG"), true, false, false) { - return false - } - if !yaml_emitter_write_tag_handle(emitter, tag_directive.handle) { - return false - } - if !yaml_emitter_write_tag_content(emitter, tag_directive.prefix, true) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - } - - if yaml_emitter_check_empty_document(emitter) { - implicit = false - } - if !implicit { - if !yaml_emitter_write_indent(emitter) { - return false - } - if !yaml_emitter_write_indicator(emitter, []byte("---"), true, false, false) { - return false - } - if emitter.canonical { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - } - - emitter.state = yaml_EMIT_DOCUMENT_CONTENT_STATE - return true - } - - if event.typ == yaml_STREAM_END_EVENT { - if emitter.open_ended { - if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !yaml_emitter_flush(emitter) { - return false - } - emitter.state = yaml_EMIT_END_STATE - return true - } - - return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-START or STREAM-END") -} - -// Expect the root node. -func yaml_emitter_emit_document_content(emitter *yaml_emitter_t, event *yaml_event_t) bool { - emitter.states = append(emitter.states, yaml_EMIT_DOCUMENT_END_STATE) - return yaml_emitter_emit_node(emitter, event, true, false, false, false) -} - -// Expect DOCUMENT-END. -func yaml_emitter_emit_document_end(emitter *yaml_emitter_t, event *yaml_event_t) bool { - if event.typ != yaml_DOCUMENT_END_EVENT { - return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-END") - } - if !yaml_emitter_write_indent(emitter) { - return false - } - if !event.implicit { - // [Go] Allocate the slice elsewhere. - if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !yaml_emitter_flush(emitter) { - return false - } - emitter.state = yaml_EMIT_DOCUMENT_START_STATE - emitter.tag_directives = emitter.tag_directives[:0] - return true -} - -// Expect a flow item node. -func yaml_emitter_emit_flow_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { - if first { - if !yaml_emitter_write_indicator(emitter, []byte{'['}, true, true, false) { - return false - } - if !yaml_emitter_increase_indent(emitter, true, false) { - return false - } - emitter.flow_level++ - } - - if event.typ == yaml_SEQUENCE_END_EVENT { - emitter.flow_level-- - emitter.indent = emitter.indents[len(emitter.indents)-1] - emitter.indents = emitter.indents[:len(emitter.indents)-1] - if emitter.canonical && !first { - if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !yaml_emitter_write_indicator(emitter, []byte{']'}, false, false, false) { - return false - } - emitter.state = emitter.states[len(emitter.states)-1] - emitter.states = emitter.states[:len(emitter.states)-1] - - return true - } - - if !first { - if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { - return false - } - } - - if emitter.canonical || emitter.column > emitter.best_width { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - emitter.states = append(emitter.states, yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE) - return yaml_emitter_emit_node(emitter, event, false, true, false, false) -} - -// Expect a flow key node. -func yaml_emitter_emit_flow_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { - if first { - if !yaml_emitter_write_indicator(emitter, []byte{'{'}, true, true, false) { - return false - } - if !yaml_emitter_increase_indent(emitter, true, false) { - return false - } - emitter.flow_level++ - } - - if event.typ == yaml_MAPPING_END_EVENT { - emitter.flow_level-- - emitter.indent = emitter.indents[len(emitter.indents)-1] - emitter.indents = emitter.indents[:len(emitter.indents)-1] - if emitter.canonical && !first { - if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { - return false - } - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !yaml_emitter_write_indicator(emitter, []byte{'}'}, false, false, false) { - return false - } - emitter.state = emitter.states[len(emitter.states)-1] - emitter.states = emitter.states[:len(emitter.states)-1] - return true - } - - if !first { - if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { - return false - } - } - if emitter.canonical || emitter.column > emitter.best_width { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - - if !emitter.canonical && yaml_emitter_check_simple_key(emitter) { - emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE) - return yaml_emitter_emit_node(emitter, event, false, false, true, true) - } - if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, false) { - return false - } - emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_VALUE_STATE) - return yaml_emitter_emit_node(emitter, event, false, false, true, false) -} - -// Expect a flow value node. -func yaml_emitter_emit_flow_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool { - if simple { - if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) { - return false - } - } else { - if emitter.canonical || emitter.column > emitter.best_width { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, false) { - return false - } - } - emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_KEY_STATE) - return yaml_emitter_emit_node(emitter, event, false, false, true, false) -} - -// Expect a block item node. -func yaml_emitter_emit_block_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { - if first { - if !yaml_emitter_increase_indent(emitter, false, emitter.mapping_context && !emitter.indention) { - return false - } - } - if event.typ == yaml_SEQUENCE_END_EVENT { - emitter.indent = emitter.indents[len(emitter.indents)-1] - emitter.indents = emitter.indents[:len(emitter.indents)-1] - emitter.state = emitter.states[len(emitter.states)-1] - emitter.states = emitter.states[:len(emitter.states)-1] - return true - } - if !yaml_emitter_write_indent(emitter) { - return false - } - if !yaml_emitter_write_indicator(emitter, []byte{'-'}, true, false, true) { - return false - } - emitter.states = append(emitter.states, yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE) - return yaml_emitter_emit_node(emitter, event, false, true, false, false) -} - -// Expect a block key node. -func yaml_emitter_emit_block_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { - if first { - if !yaml_emitter_increase_indent(emitter, false, false) { - return false - } - } - if event.typ == yaml_MAPPING_END_EVENT { - emitter.indent = emitter.indents[len(emitter.indents)-1] - emitter.indents = emitter.indents[:len(emitter.indents)-1] - emitter.state = emitter.states[len(emitter.states)-1] - emitter.states = emitter.states[:len(emitter.states)-1] - return true - } - if !yaml_emitter_write_indent(emitter) { - return false - } - if yaml_emitter_check_simple_key(emitter) { - emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE) - return yaml_emitter_emit_node(emitter, event, false, false, true, true) - } - if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, true) { - return false - } - emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_VALUE_STATE) - return yaml_emitter_emit_node(emitter, event, false, false, true, false) -} - -// Expect a block value node. -func yaml_emitter_emit_block_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool { - if simple { - if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) { - return false - } - } else { - if !yaml_emitter_write_indent(emitter) { - return false - } - if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, true) { - return false - } - } - emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_KEY_STATE) - return yaml_emitter_emit_node(emitter, event, false, false, true, false) -} - -// Expect a node. -func yaml_emitter_emit_node(emitter *yaml_emitter_t, event *yaml_event_t, - root bool, sequence bool, mapping bool, simple_key bool) bool { - - emitter.root_context = root - emitter.sequence_context = sequence - emitter.mapping_context = mapping - emitter.simple_key_context = simple_key - - switch event.typ { - case yaml_ALIAS_EVENT: - return yaml_emitter_emit_alias(emitter, event) - case yaml_SCALAR_EVENT: - return yaml_emitter_emit_scalar(emitter, event) - case yaml_SEQUENCE_START_EVENT: - return yaml_emitter_emit_sequence_start(emitter, event) - case yaml_MAPPING_START_EVENT: - return yaml_emitter_emit_mapping_start(emitter, event) - default: - return yaml_emitter_set_emitter_error(emitter, - "expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS") - } -} - -// Expect ALIAS. -func yaml_emitter_emit_alias(emitter *yaml_emitter_t, event *yaml_event_t) bool { - if !yaml_emitter_process_anchor(emitter) { - return false - } - emitter.state = emitter.states[len(emitter.states)-1] - emitter.states = emitter.states[:len(emitter.states)-1] - return true -} - -// Expect SCALAR. -func yaml_emitter_emit_scalar(emitter *yaml_emitter_t, event *yaml_event_t) bool { - if !yaml_emitter_select_scalar_style(emitter, event) { - return false - } - if !yaml_emitter_process_anchor(emitter) { - return false - } - if !yaml_emitter_process_tag(emitter) { - return false - } - if !yaml_emitter_increase_indent(emitter, true, false) { - return false - } - if !yaml_emitter_process_scalar(emitter) { - return false - } - emitter.indent = emitter.indents[len(emitter.indents)-1] - emitter.indents = emitter.indents[:len(emitter.indents)-1] - emitter.state = emitter.states[len(emitter.states)-1] - emitter.states = emitter.states[:len(emitter.states)-1] - return true -} - -// Expect SEQUENCE-START. -func yaml_emitter_emit_sequence_start(emitter *yaml_emitter_t, event *yaml_event_t) bool { - if !yaml_emitter_process_anchor(emitter) { - return false - } - if !yaml_emitter_process_tag(emitter) { - return false - } - if emitter.flow_level > 0 || emitter.canonical || event.sequence_style() == yaml_FLOW_SEQUENCE_STYLE || - yaml_emitter_check_empty_sequence(emitter) { - emitter.state = yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE - } else { - emitter.state = yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE - } - return true -} - -// Expect MAPPING-START. -func yaml_emitter_emit_mapping_start(emitter *yaml_emitter_t, event *yaml_event_t) bool { - if !yaml_emitter_process_anchor(emitter) { - return false - } - if !yaml_emitter_process_tag(emitter) { - return false - } - if emitter.flow_level > 0 || emitter.canonical || event.mapping_style() == yaml_FLOW_MAPPING_STYLE || - yaml_emitter_check_empty_mapping(emitter) { - emitter.state = yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE - } else { - emitter.state = yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE - } - return true -} - -// Check if the document content is an empty scalar. -func yaml_emitter_check_empty_document(emitter *yaml_emitter_t) bool { - return false // [Go] Huh? -} - -// Check if the next events represent an empty sequence. -func yaml_emitter_check_empty_sequence(emitter *yaml_emitter_t) bool { - if len(emitter.events)-emitter.events_head < 2 { - return false - } - return emitter.events[emitter.events_head].typ == yaml_SEQUENCE_START_EVENT && - emitter.events[emitter.events_head+1].typ == yaml_SEQUENCE_END_EVENT -} - -// Check if the next events represent an empty mapping. -func yaml_emitter_check_empty_mapping(emitter *yaml_emitter_t) bool { - if len(emitter.events)-emitter.events_head < 2 { - return false - } - return emitter.events[emitter.events_head].typ == yaml_MAPPING_START_EVENT && - emitter.events[emitter.events_head+1].typ == yaml_MAPPING_END_EVENT -} - -// Check if the next node can be expressed as a simple key. -func yaml_emitter_check_simple_key(emitter *yaml_emitter_t) bool { - length := 0 - switch emitter.events[emitter.events_head].typ { - case yaml_ALIAS_EVENT: - length += len(emitter.anchor_data.anchor) - case yaml_SCALAR_EVENT: - if emitter.scalar_data.multiline { - return false - } - length += len(emitter.anchor_data.anchor) + - len(emitter.tag_data.handle) + - len(emitter.tag_data.suffix) + - len(emitter.scalar_data.value) - case yaml_SEQUENCE_START_EVENT: - if !yaml_emitter_check_empty_sequence(emitter) { - return false - } - length += len(emitter.anchor_data.anchor) + - len(emitter.tag_data.handle) + - len(emitter.tag_data.suffix) - case yaml_MAPPING_START_EVENT: - if !yaml_emitter_check_empty_mapping(emitter) { - return false - } - length += len(emitter.anchor_data.anchor) + - len(emitter.tag_data.handle) + - len(emitter.tag_data.suffix) - default: - return false - } - return length <= 128 -} - -// Determine an acceptable scalar style. -func yaml_emitter_select_scalar_style(emitter *yaml_emitter_t, event *yaml_event_t) bool { - - no_tag := len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0 - if no_tag && !event.implicit && !event.quoted_implicit { - return yaml_emitter_set_emitter_error(emitter, "neither tag nor implicit flags are specified") - } - - style := event.scalar_style() - if style == yaml_ANY_SCALAR_STYLE { - style = yaml_PLAIN_SCALAR_STYLE - } - if emitter.canonical { - style = yaml_DOUBLE_QUOTED_SCALAR_STYLE - } - if emitter.simple_key_context && emitter.scalar_data.multiline { - style = yaml_DOUBLE_QUOTED_SCALAR_STYLE - } - - if style == yaml_PLAIN_SCALAR_STYLE { - if emitter.flow_level > 0 && !emitter.scalar_data.flow_plain_allowed || - emitter.flow_level == 0 && !emitter.scalar_data.block_plain_allowed { - style = yaml_SINGLE_QUOTED_SCALAR_STYLE - } - if len(emitter.scalar_data.value) == 0 && (emitter.flow_level > 0 || emitter.simple_key_context) { - style = yaml_SINGLE_QUOTED_SCALAR_STYLE - } - if no_tag && !event.implicit { - style = yaml_SINGLE_QUOTED_SCALAR_STYLE - } - } - if style == yaml_SINGLE_QUOTED_SCALAR_STYLE { - if !emitter.scalar_data.single_quoted_allowed { - style = yaml_DOUBLE_QUOTED_SCALAR_STYLE - } - } - if style == yaml_LITERAL_SCALAR_STYLE || style == yaml_FOLDED_SCALAR_STYLE { - if !emitter.scalar_data.block_allowed || emitter.flow_level > 0 || emitter.simple_key_context { - style = yaml_DOUBLE_QUOTED_SCALAR_STYLE - } - } - - if no_tag && !event.quoted_implicit && style != yaml_PLAIN_SCALAR_STYLE { - emitter.tag_data.handle = []byte{'!'} - } - emitter.scalar_data.style = style - return true -} - -// Write an achor. -func yaml_emitter_process_anchor(emitter *yaml_emitter_t) bool { - if emitter.anchor_data.anchor == nil { - return true - } - c := []byte{'&'} - if emitter.anchor_data.alias { - c[0] = '*' - } - if !yaml_emitter_write_indicator(emitter, c, true, false, false) { - return false - } - return yaml_emitter_write_anchor(emitter, emitter.anchor_data.anchor) -} - -// Write a tag. -func yaml_emitter_process_tag(emitter *yaml_emitter_t) bool { - if len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0 { - return true - } - if len(emitter.tag_data.handle) > 0 { - if !yaml_emitter_write_tag_handle(emitter, emitter.tag_data.handle) { - return false - } - if len(emitter.tag_data.suffix) > 0 { - if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) { - return false - } - } - } else { - // [Go] Allocate these slices elsewhere. - if !yaml_emitter_write_indicator(emitter, []byte("!<"), true, false, false) { - return false - } - if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) { - return false - } - if !yaml_emitter_write_indicator(emitter, []byte{'>'}, false, false, false) { - return false - } - } - return true -} - -// Write a scalar. -func yaml_emitter_process_scalar(emitter *yaml_emitter_t) bool { - switch emitter.scalar_data.style { - case yaml_PLAIN_SCALAR_STYLE: - return yaml_emitter_write_plain_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context) - - case yaml_SINGLE_QUOTED_SCALAR_STYLE: - return yaml_emitter_write_single_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context) - - case yaml_DOUBLE_QUOTED_SCALAR_STYLE: - return yaml_emitter_write_double_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context) - - case yaml_LITERAL_SCALAR_STYLE: - return yaml_emitter_write_literal_scalar(emitter, emitter.scalar_data.value) - - case yaml_FOLDED_SCALAR_STYLE: - return yaml_emitter_write_folded_scalar(emitter, emitter.scalar_data.value) - } - panic("unknown scalar style") -} - -// Check if a %YAML directive is valid. -func yaml_emitter_analyze_version_directive(emitter *yaml_emitter_t, version_directive *yaml_version_directive_t) bool { - if version_directive.major != 1 || version_directive.minor != 1 { - return yaml_emitter_set_emitter_error(emitter, "incompatible %YAML directive") - } - return true -} - -// Check if a %TAG directive is valid. -func yaml_emitter_analyze_tag_directive(emitter *yaml_emitter_t, tag_directive *yaml_tag_directive_t) bool { - handle := tag_directive.handle - prefix := tag_directive.prefix - if len(handle) == 0 { - return yaml_emitter_set_emitter_error(emitter, "tag handle must not be empty") - } - if handle[0] != '!' { - return yaml_emitter_set_emitter_error(emitter, "tag handle must start with '!'") - } - if handle[len(handle)-1] != '!' { - return yaml_emitter_set_emitter_error(emitter, "tag handle must end with '!'") - } - for i := 1; i < len(handle)-1; i += width(handle[i]) { - if !is_alpha(handle, i) { - return yaml_emitter_set_emitter_error(emitter, "tag handle must contain alphanumerical characters only") - } - } - if len(prefix) == 0 { - return yaml_emitter_set_emitter_error(emitter, "tag prefix must not be empty") - } - return true -} - -// Check if an anchor is valid. -func yaml_emitter_analyze_anchor(emitter *yaml_emitter_t, anchor []byte, alias bool) bool { - if len(anchor) == 0 { - problem := "anchor value must not be empty" - if alias { - problem = "alias value must not be empty" - } - return yaml_emitter_set_emitter_error(emitter, problem) - } - for i := 0; i < len(anchor); i += width(anchor[i]) { - if !is_alpha(anchor, i) { - problem := "anchor value must contain alphanumerical characters only" - if alias { - problem = "alias value must contain alphanumerical characters only" - } - return yaml_emitter_set_emitter_error(emitter, problem) - } - } - emitter.anchor_data.anchor = anchor - emitter.anchor_data.alias = alias - return true -} - -// Check if a tag is valid. -func yaml_emitter_analyze_tag(emitter *yaml_emitter_t, tag []byte) bool { - if len(tag) == 0 { - return yaml_emitter_set_emitter_error(emitter, "tag value must not be empty") - } - for i := 0; i < len(emitter.tag_directives); i++ { - tag_directive := &emitter.tag_directives[i] - if bytes.HasPrefix(tag, tag_directive.prefix) { - emitter.tag_data.handle = tag_directive.handle - emitter.tag_data.suffix = tag[len(tag_directive.prefix):] - return true - } - } - emitter.tag_data.suffix = tag - return true -} - -// Check if a scalar is valid. -func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool { - var ( - block_indicators = false - flow_indicators = false - line_breaks = false - special_characters = false - - leading_space = false - leading_break = false - trailing_space = false - trailing_break = false - break_space = false - space_break = false - - preceded_by_whitespace = false - followed_by_whitespace = false - previous_space = false - previous_break = false - ) - - emitter.scalar_data.value = value - - if len(value) == 0 { - emitter.scalar_data.multiline = false - emitter.scalar_data.flow_plain_allowed = false - emitter.scalar_data.block_plain_allowed = true - emitter.scalar_data.single_quoted_allowed = true - emitter.scalar_data.block_allowed = false - return true - } - - if len(value) >= 3 && ((value[0] == '-' && value[1] == '-' && value[2] == '-') || (value[0] == '.' && value[1] == '.' && value[2] == '.')) { - block_indicators = true - flow_indicators = true - } - - preceded_by_whitespace = true - for i, w := 0, 0; i < len(value); i += w { - w = width(value[i]) - followed_by_whitespace = i+w >= len(value) || is_blank(value, i+w) - - if i == 0 { - switch value[i] { - case '#', ',', '[', ']', '{', '}', '&', '*', '!', '|', '>', '\'', '"', '%', '@', '`': - flow_indicators = true - block_indicators = true - case '?', ':': - flow_indicators = true - if followed_by_whitespace { - block_indicators = true - } - case '-': - if followed_by_whitespace { - flow_indicators = true - block_indicators = true - } - } - } else { - switch value[i] { - case ',', '?', '[', ']', '{', '}': - flow_indicators = true - case ':': - flow_indicators = true - if followed_by_whitespace { - block_indicators = true - } - case '#': - if preceded_by_whitespace { - flow_indicators = true - block_indicators = true - } - } - } - - if !is_printable(value, i) || !is_ascii(value, i) && !emitter.unicode { - special_characters = true - } - if is_space(value, i) { - if i == 0 { - leading_space = true - } - if i+width(value[i]) == len(value) { - trailing_space = true - } - if previous_break { - break_space = true - } - previous_space = true - previous_break = false - } else if is_break(value, i) { - line_breaks = true - if i == 0 { - leading_break = true - } - if i+width(value[i]) == len(value) { - trailing_break = true - } - if previous_space { - space_break = true - } - previous_space = false - previous_break = true - } else { - previous_space = false - previous_break = false - } - - // [Go]: Why 'z'? Couldn't be the end of the string as that's the loop condition. - preceded_by_whitespace = is_blankz(value, i) - } - - emitter.scalar_data.multiline = line_breaks - emitter.scalar_data.flow_plain_allowed = true - emitter.scalar_data.block_plain_allowed = true - emitter.scalar_data.single_quoted_allowed = true - emitter.scalar_data.block_allowed = true - - if leading_space || leading_break || trailing_space || trailing_break { - emitter.scalar_data.flow_plain_allowed = false - emitter.scalar_data.block_plain_allowed = false - } - if trailing_space { - emitter.scalar_data.block_allowed = false - } - if break_space { - emitter.scalar_data.flow_plain_allowed = false - emitter.scalar_data.block_plain_allowed = false - emitter.scalar_data.single_quoted_allowed = false - } - if space_break || special_characters { - emitter.scalar_data.flow_plain_allowed = false - emitter.scalar_data.block_plain_allowed = false - emitter.scalar_data.single_quoted_allowed = false - emitter.scalar_data.block_allowed = false - } - if line_breaks { - emitter.scalar_data.flow_plain_allowed = false - emitter.scalar_data.block_plain_allowed = false - } - if flow_indicators { - emitter.scalar_data.flow_plain_allowed = false - } - if block_indicators { - emitter.scalar_data.block_plain_allowed = false - } - return true -} - -// Check if the event data is valid. -func yaml_emitter_analyze_event(emitter *yaml_emitter_t, event *yaml_event_t) bool { - - emitter.anchor_data.anchor = nil - emitter.tag_data.handle = nil - emitter.tag_data.suffix = nil - emitter.scalar_data.value = nil - - switch event.typ { - case yaml_ALIAS_EVENT: - if !yaml_emitter_analyze_anchor(emitter, event.anchor, true) { - return false - } - - case yaml_SCALAR_EVENT: - if len(event.anchor) > 0 { - if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) { - return false - } - } - if len(event.tag) > 0 && (emitter.canonical || (!event.implicit && !event.quoted_implicit)) { - if !yaml_emitter_analyze_tag(emitter, event.tag) { - return false - } - } - if !yaml_emitter_analyze_scalar(emitter, event.value) { - return false - } - - case yaml_SEQUENCE_START_EVENT: - if len(event.anchor) > 0 { - if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) { - return false - } - } - if len(event.tag) > 0 && (emitter.canonical || !event.implicit) { - if !yaml_emitter_analyze_tag(emitter, event.tag) { - return false - } - } - - case yaml_MAPPING_START_EVENT: - if len(event.anchor) > 0 { - if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) { - return false - } - } - if len(event.tag) > 0 && (emitter.canonical || !event.implicit) { - if !yaml_emitter_analyze_tag(emitter, event.tag) { - return false - } - } - } - return true -} - -// Write the BOM character. -func yaml_emitter_write_bom(emitter *yaml_emitter_t) bool { - if !flush(emitter) { - return false - } - pos := emitter.buffer_pos - emitter.buffer[pos+0] = '\xEF' - emitter.buffer[pos+1] = '\xBB' - emitter.buffer[pos+2] = '\xBF' - emitter.buffer_pos += 3 - return true -} - -func yaml_emitter_write_indent(emitter *yaml_emitter_t) bool { - indent := emitter.indent - if indent < 0 { - indent = 0 - } - if !emitter.indention || emitter.column > indent || (emitter.column == indent && !emitter.whitespace) { - if !put_break(emitter) { - return false - } - } - for emitter.column < indent { - if !put(emitter, ' ') { - return false - } - } - emitter.whitespace = true - emitter.indention = true - return true -} - -func yaml_emitter_write_indicator(emitter *yaml_emitter_t, indicator []byte, need_whitespace, is_whitespace, is_indention bool) bool { - if need_whitespace && !emitter.whitespace { - if !put(emitter, ' ') { - return false - } - } - if !write_all(emitter, indicator) { - return false - } - emitter.whitespace = is_whitespace - emitter.indention = (emitter.indention && is_indention) - emitter.open_ended = false - return true -} - -func yaml_emitter_write_anchor(emitter *yaml_emitter_t, value []byte) bool { - if !write_all(emitter, value) { - return false - } - emitter.whitespace = false - emitter.indention = false - return true -} - -func yaml_emitter_write_tag_handle(emitter *yaml_emitter_t, value []byte) bool { - if !emitter.whitespace { - if !put(emitter, ' ') { - return false - } - } - if !write_all(emitter, value) { - return false - } - emitter.whitespace = false - emitter.indention = false - return true -} - -func yaml_emitter_write_tag_content(emitter *yaml_emitter_t, value []byte, need_whitespace bool) bool { - if need_whitespace && !emitter.whitespace { - if !put(emitter, ' ') { - return false - } - } - for i := 0; i < len(value); { - var must_write bool - switch value[i] { - case ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '_', '.', '~', '*', '\'', '(', ')', '[', ']': - must_write = true - default: - must_write = is_alpha(value, i) - } - if must_write { - if !write(emitter, value, &i) { - return false - } - } else { - w := width(value[i]) - for k := 0; k < w; k++ { - octet := value[i] - i++ - if !put(emitter, '%') { - return false - } - - c := octet >> 4 - if c < 10 { - c += '0' - } else { - c += 'A' - 10 - } - if !put(emitter, c) { - return false - } - - c = octet & 0x0f - if c < 10 { - c += '0' - } else { - c += 'A' - 10 - } - if !put(emitter, c) { - return false - } - } - } - } - emitter.whitespace = false - emitter.indention = false - return true -} - -func yaml_emitter_write_plain_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool { - if !emitter.whitespace { - if !put(emitter, ' ') { - return false - } - } - - spaces := false - breaks := false - for i := 0; i < len(value); { - if is_space(value, i) { - if allow_breaks && !spaces && emitter.column > emitter.best_width && !is_space(value, i+1) { - if !yaml_emitter_write_indent(emitter) { - return false - } - i += width(value[i]) - } else { - if !write(emitter, value, &i) { - return false - } - } - spaces = true - } else if is_break(value, i) { - if !breaks && value[i] == '\n' { - if !put_break(emitter) { - return false - } - } - if !write_break(emitter, value, &i) { - return false - } - emitter.indention = true - breaks = true - } else { - if breaks { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !write(emitter, value, &i) { - return false - } - emitter.indention = false - spaces = false - breaks = false - } - } - - emitter.whitespace = false - emitter.indention = false - if emitter.root_context { - emitter.open_ended = true - } - - return true -} - -func yaml_emitter_write_single_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool { - - if !yaml_emitter_write_indicator(emitter, []byte{'\''}, true, false, false) { - return false - } - - spaces := false - breaks := false - for i := 0; i < len(value); { - if is_space(value, i) { - if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 && !is_space(value, i+1) { - if !yaml_emitter_write_indent(emitter) { - return false - } - i += width(value[i]) - } else { - if !write(emitter, value, &i) { - return false - } - } - spaces = true - } else if is_break(value, i) { - if !breaks && value[i] == '\n' { - if !put_break(emitter) { - return false - } - } - if !write_break(emitter, value, &i) { - return false - } - emitter.indention = true - breaks = true - } else { - if breaks { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if value[i] == '\'' { - if !put(emitter, '\'') { - return false - } - } - if !write(emitter, value, &i) { - return false - } - emitter.indention = false - spaces = false - breaks = false - } - } - if !yaml_emitter_write_indicator(emitter, []byte{'\''}, false, false, false) { - return false - } - emitter.whitespace = false - emitter.indention = false - return true -} - -func yaml_emitter_write_double_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool { - spaces := false - if !yaml_emitter_write_indicator(emitter, []byte{'"'}, true, false, false) { - return false - } - - for i := 0; i < len(value); { - if !is_printable(value, i) || (!emitter.unicode && !is_ascii(value, i)) || - is_bom(value, i) || is_break(value, i) || - value[i] == '"' || value[i] == '\\' { - - octet := value[i] - - var w int - var v rune - switch { - case octet&0x80 == 0x00: - w, v = 1, rune(octet&0x7F) - case octet&0xE0 == 0xC0: - w, v = 2, rune(octet&0x1F) - case octet&0xF0 == 0xE0: - w, v = 3, rune(octet&0x0F) - case octet&0xF8 == 0xF0: - w, v = 4, rune(octet&0x07) - } - for k := 1; k < w; k++ { - octet = value[i+k] - v = (v << 6) + (rune(octet) & 0x3F) - } - i += w - - if !put(emitter, '\\') { - return false - } - - var ok bool - switch v { - case 0x00: - ok = put(emitter, '0') - case 0x07: - ok = put(emitter, 'a') - case 0x08: - ok = put(emitter, 'b') - case 0x09: - ok = put(emitter, 't') - case 0x0A: - ok = put(emitter, 'n') - case 0x0b: - ok = put(emitter, 'v') - case 0x0c: - ok = put(emitter, 'f') - case 0x0d: - ok = put(emitter, 'r') - case 0x1b: - ok = put(emitter, 'e') - case 0x22: - ok = put(emitter, '"') - case 0x5c: - ok = put(emitter, '\\') - case 0x85: - ok = put(emitter, 'N') - case 0xA0: - ok = put(emitter, '_') - case 0x2028: - ok = put(emitter, 'L') - case 0x2029: - ok = put(emitter, 'P') - default: - if v <= 0xFF { - ok = put(emitter, 'x') - w = 2 - } else if v <= 0xFFFF { - ok = put(emitter, 'u') - w = 4 - } else { - ok = put(emitter, 'U') - w = 8 - } - for k := (w - 1) * 4; ok && k >= 0; k -= 4 { - digit := byte((v >> uint(k)) & 0x0F) - if digit < 10 { - ok = put(emitter, digit+'0') - } else { - ok = put(emitter, digit+'A'-10) - } - } - } - if !ok { - return false - } - spaces = false - } else if is_space(value, i) { - if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 { - if !yaml_emitter_write_indent(emitter) { - return false - } - if is_space(value, i+1) { - if !put(emitter, '\\') { - return false - } - } - i += width(value[i]) - } else if !write(emitter, value, &i) { - return false - } - spaces = true - } else { - if !write(emitter, value, &i) { - return false - } - spaces = false - } - } - if !yaml_emitter_write_indicator(emitter, []byte{'"'}, false, false, false) { - return false - } - emitter.whitespace = false - emitter.indention = false - return true -} - -func yaml_emitter_write_block_scalar_hints(emitter *yaml_emitter_t, value []byte) bool { - if is_space(value, 0) || is_break(value, 0) { - indent_hint := []byte{'0' + byte(emitter.best_indent)} - if !yaml_emitter_write_indicator(emitter, indent_hint, false, false, false) { - return false - } - } - - emitter.open_ended = false - - var chomp_hint [1]byte - if len(value) == 0 { - chomp_hint[0] = '-' - } else { - i := len(value) - 1 - for value[i]&0xC0 == 0x80 { - i-- - } - if !is_break(value, i) { - chomp_hint[0] = '-' - } else if i == 0 { - chomp_hint[0] = '+' - emitter.open_ended = true - } else { - i-- - for value[i]&0xC0 == 0x80 { - i-- - } - if is_break(value, i) { - chomp_hint[0] = '+' - emitter.open_ended = true - } - } - } - if chomp_hint[0] != 0 { - if !yaml_emitter_write_indicator(emitter, chomp_hint[:], false, false, false) { - return false - } - } - return true -} - -func yaml_emitter_write_literal_scalar(emitter *yaml_emitter_t, value []byte) bool { - if !yaml_emitter_write_indicator(emitter, []byte{'|'}, true, false, false) { - return false - } - if !yaml_emitter_write_block_scalar_hints(emitter, value) { - return false - } - if !put_break(emitter) { - return false - } - emitter.indention = true - emitter.whitespace = true - breaks := true - for i := 0; i < len(value); { - if is_break(value, i) { - if !write_break(emitter, value, &i) { - return false - } - emitter.indention = true - breaks = true - } else { - if breaks { - if !yaml_emitter_write_indent(emitter) { - return false - } - } - if !write(emitter, value, &i) { - return false - } - emitter.indention = false - breaks = false - } - } - - return true -} - -func yaml_emitter_write_folded_scalar(emitter *yaml_emitter_t, value []byte) bool { - if !yaml_emitter_write_indicator(emitter, []byte{'>'}, true, false, false) { - return false - } - if !yaml_emitter_write_block_scalar_hints(emitter, value) { - return false - } - - if !put_break(emitter) { - return false - } - emitter.indention = true - emitter.whitespace = true - - breaks := true - leading_spaces := true - for i := 0; i < len(value); { - if is_break(value, i) { - if !breaks && !leading_spaces && value[i] == '\n' { - k := 0 - for is_break(value, k) { - k += width(value[k]) - } - if !is_blankz(value, k) { - if !put_break(emitter) { - return false - } - } - } - if !write_break(emitter, value, &i) { - return false - } - emitter.indention = true - breaks = true - } else { - if breaks { - if !yaml_emitter_write_indent(emitter) { - return false - } - leading_spaces = is_blank(value, i) - } - if !breaks && is_space(value, i) && !is_space(value, i+1) && emitter.column > emitter.best_width { - if !yaml_emitter_write_indent(emitter) { - return false - } - i += width(value[i]) - } else { - if !write(emitter, value, &i) { - return false - } - } - emitter.indention = false - breaks = false - } - } - return true -} diff --git a/dev-tools/vendor/gopkg.in/yaml.v2/encode.go b/dev-tools/vendor/gopkg.in/yaml.v2/encode.go deleted file mode 100644 index 84f84995517b..000000000000 --- a/dev-tools/vendor/gopkg.in/yaml.v2/encode.go +++ /dev/null @@ -1,306 +0,0 @@ -package yaml - -import ( - "encoding" - "fmt" - "reflect" - "regexp" - "sort" - "strconv" - "strings" - "time" -) - -type encoder struct { - emitter yaml_emitter_t - event yaml_event_t - out []byte - flow bool -} - -func newEncoder() (e *encoder) { - e = &encoder{} - e.must(yaml_emitter_initialize(&e.emitter)) - yaml_emitter_set_output_string(&e.emitter, &e.out) - yaml_emitter_set_unicode(&e.emitter, true) - e.must(yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING)) - e.emit() - e.must(yaml_document_start_event_initialize(&e.event, nil, nil, true)) - e.emit() - return e -} - -func (e *encoder) finish() { - e.must(yaml_document_end_event_initialize(&e.event, true)) - e.emit() - e.emitter.open_ended = false - e.must(yaml_stream_end_event_initialize(&e.event)) - e.emit() -} - -func (e *encoder) destroy() { - yaml_emitter_delete(&e.emitter) -} - -func (e *encoder) emit() { - // This will internally delete the e.event value. - if !yaml_emitter_emit(&e.emitter, &e.event) && e.event.typ != yaml_DOCUMENT_END_EVENT && e.event.typ != yaml_STREAM_END_EVENT { - e.must(false) - } -} - -func (e *encoder) must(ok bool) { - if !ok { - msg := e.emitter.problem - if msg == "" { - msg = "unknown problem generating YAML content" - } - failf("%s", msg) - } -} - -func (e *encoder) marshal(tag string, in reflect.Value) { - if !in.IsValid() { - e.nilv() - return - } - iface := in.Interface() - if m, ok := iface.(Marshaler); ok { - v, err := m.MarshalYAML() - if err != nil { - fail(err) - } - if v == nil { - e.nilv() - return - } - in = reflect.ValueOf(v) - } else if m, ok := iface.(encoding.TextMarshaler); ok { - text, err := m.MarshalText() - if err != nil { - fail(err) - } - in = reflect.ValueOf(string(text)) - } - switch in.Kind() { - case reflect.Interface: - if in.IsNil() { - e.nilv() - } else { - e.marshal(tag, in.Elem()) - } - case reflect.Map: - e.mapv(tag, in) - case reflect.Ptr: - if in.IsNil() { - e.nilv() - } else { - e.marshal(tag, in.Elem()) - } - case reflect.Struct: - e.structv(tag, in) - case reflect.Slice: - if in.Type().Elem() == mapItemType { - e.itemsv(tag, in) - } else { - e.slicev(tag, in) - } - case reflect.String: - e.stringv(tag, in) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - if in.Type() == durationType { - e.stringv(tag, reflect.ValueOf(iface.(time.Duration).String())) - } else { - e.intv(tag, in) - } - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - e.uintv(tag, in) - case reflect.Float32, reflect.Float64: - e.floatv(tag, in) - case reflect.Bool: - e.boolv(tag, in) - default: - panic("cannot marshal type: " + in.Type().String()) - } -} - -func (e *encoder) mapv(tag string, in reflect.Value) { - e.mappingv(tag, func() { - keys := keyList(in.MapKeys()) - sort.Sort(keys) - for _, k := range keys { - e.marshal("", k) - e.marshal("", in.MapIndex(k)) - } - }) -} - -func (e *encoder) itemsv(tag string, in reflect.Value) { - e.mappingv(tag, func() { - slice := in.Convert(reflect.TypeOf([]MapItem{})).Interface().([]MapItem) - for _, item := range slice { - e.marshal("", reflect.ValueOf(item.Key)) - e.marshal("", reflect.ValueOf(item.Value)) - } - }) -} - -func (e *encoder) structv(tag string, in reflect.Value) { - sinfo, err := getStructInfo(in.Type()) - if err != nil { - panic(err) - } - e.mappingv(tag, func() { - for _, info := range sinfo.FieldsList { - var value reflect.Value - if info.Inline == nil { - value = in.Field(info.Num) - } else { - value = in.FieldByIndex(info.Inline) - } - if info.OmitEmpty && isZero(value) { - continue - } - e.marshal("", reflect.ValueOf(info.Key)) - e.flow = info.Flow - e.marshal("", value) - } - if sinfo.InlineMap >= 0 { - m := in.Field(sinfo.InlineMap) - if m.Len() > 0 { - e.flow = false - keys := keyList(m.MapKeys()) - sort.Sort(keys) - for _, k := range keys { - if _, found := sinfo.FieldsMap[k.String()]; found { - panic(fmt.Sprintf("Can't have key %q in inlined map; conflicts with struct field", k.String())) - } - e.marshal("", k) - e.flow = false - e.marshal("", m.MapIndex(k)) - } - } - } - }) -} - -func (e *encoder) mappingv(tag string, f func()) { - implicit := tag == "" - style := yaml_BLOCK_MAPPING_STYLE - if e.flow { - e.flow = false - style = yaml_FLOW_MAPPING_STYLE - } - e.must(yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)) - e.emit() - f() - e.must(yaml_mapping_end_event_initialize(&e.event)) - e.emit() -} - -func (e *encoder) slicev(tag string, in reflect.Value) { - implicit := tag == "" - style := yaml_BLOCK_SEQUENCE_STYLE - if e.flow { - e.flow = false - style = yaml_FLOW_SEQUENCE_STYLE - } - e.must(yaml_sequence_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)) - e.emit() - n := in.Len() - for i := 0; i < n; i++ { - e.marshal("", in.Index(i)) - } - e.must(yaml_sequence_end_event_initialize(&e.event)) - e.emit() -} - -// isBase60 returns whether s is in base 60 notation as defined in YAML 1.1. -// -// The base 60 float notation in YAML 1.1 is a terrible idea and is unsupported -// in YAML 1.2 and by this package, but these should be marshalled quoted for -// the time being for compatibility with other parsers. -func isBase60Float(s string) (result bool) { - // Fast path. - if s == "" { - return false - } - c := s[0] - if !(c == '+' || c == '-' || c >= '0' && c <= '9') || strings.IndexByte(s, ':') < 0 { - return false - } - // Do the full match. - return base60float.MatchString(s) -} - -// From http://yaml.org/type/float.html, except the regular expression there -// is bogus. In practice parsers do not enforce the "\.[0-9_]*" suffix. -var base60float = regexp.MustCompile(`^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+(?:\.[0-9_]*)?$`) - -func (e *encoder) stringv(tag string, in reflect.Value) { - var style yaml_scalar_style_t - s := in.String() - rtag, rs := resolve("", s) - if rtag == yaml_BINARY_TAG { - if tag == "" || tag == yaml_STR_TAG { - tag = rtag - s = rs.(string) - } else if tag == yaml_BINARY_TAG { - failf("explicitly tagged !!binary data must be base64-encoded") - } else { - failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag)) - } - } - if tag == "" && (rtag != yaml_STR_TAG || isBase60Float(s)) { - style = yaml_DOUBLE_QUOTED_SCALAR_STYLE - } else if strings.Contains(s, "\n") { - style = yaml_LITERAL_SCALAR_STYLE - } else { - style = yaml_PLAIN_SCALAR_STYLE - } - e.emitScalar(s, "", tag, style) -} - -func (e *encoder) boolv(tag string, in reflect.Value) { - var s string - if in.Bool() { - s = "true" - } else { - s = "false" - } - e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) -} - -func (e *encoder) intv(tag string, in reflect.Value) { - s := strconv.FormatInt(in.Int(), 10) - e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) -} - -func (e *encoder) uintv(tag string, in reflect.Value) { - s := strconv.FormatUint(in.Uint(), 10) - e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) -} - -func (e *encoder) floatv(tag string, in reflect.Value) { - // FIXME: Handle 64 bits here. - s := strconv.FormatFloat(float64(in.Float()), 'g', -1, 32) - switch s { - case "+Inf": - s = ".inf" - case "-Inf": - s = "-.inf" - case "NaN": - s = ".nan" - } - e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) -} - -func (e *encoder) nilv() { - e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE) -} - -func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t) { - implicit := tag == "" - e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style)) - e.emit() -} diff --git a/dev-tools/vendor/gopkg.in/yaml.v2/parserc.go b/dev-tools/vendor/gopkg.in/yaml.v2/parserc.go deleted file mode 100644 index 81d05dfe573f..000000000000 --- a/dev-tools/vendor/gopkg.in/yaml.v2/parserc.go +++ /dev/null @@ -1,1095 +0,0 @@ -package yaml - -import ( - "bytes" -) - -// The parser implements the following grammar: -// -// stream ::= STREAM-START implicit_document? explicit_document* STREAM-END -// implicit_document ::= block_node DOCUMENT-END* -// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* -// block_node_or_indentless_sequence ::= -// ALIAS -// | properties (block_content | indentless_block_sequence)? -// | block_content -// | indentless_block_sequence -// block_node ::= ALIAS -// | properties block_content? -// | block_content -// flow_node ::= ALIAS -// | properties flow_content? -// | flow_content -// properties ::= TAG ANCHOR? | ANCHOR TAG? -// block_content ::= block_collection | flow_collection | SCALAR -// flow_content ::= flow_collection | SCALAR -// block_collection ::= block_sequence | block_mapping -// flow_collection ::= flow_sequence | flow_mapping -// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END -// indentless_sequence ::= (BLOCK-ENTRY block_node?)+ -// block_mapping ::= BLOCK-MAPPING_START -// ((KEY block_node_or_indentless_sequence?)? -// (VALUE block_node_or_indentless_sequence?)?)* -// BLOCK-END -// flow_sequence ::= FLOW-SEQUENCE-START -// (flow_sequence_entry FLOW-ENTRY)* -// flow_sequence_entry? -// FLOW-SEQUENCE-END -// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// flow_mapping ::= FLOW-MAPPING-START -// (flow_mapping_entry FLOW-ENTRY)* -// flow_mapping_entry? -// FLOW-MAPPING-END -// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? - -// Peek the next token in the token queue. -func peek_token(parser *yaml_parser_t) *yaml_token_t { - if parser.token_available || yaml_parser_fetch_more_tokens(parser) { - return &parser.tokens[parser.tokens_head] - } - return nil -} - -// Remove the next token from the queue (must be called after peek_token). -func skip_token(parser *yaml_parser_t) { - parser.token_available = false - parser.tokens_parsed++ - parser.stream_end_produced = parser.tokens[parser.tokens_head].typ == yaml_STREAM_END_TOKEN - parser.tokens_head++ -} - -// Get the next event. -func yaml_parser_parse(parser *yaml_parser_t, event *yaml_event_t) bool { - // Erase the event object. - *event = yaml_event_t{} - - // No events after the end of the stream or error. - if parser.stream_end_produced || parser.error != yaml_NO_ERROR || parser.state == yaml_PARSE_END_STATE { - return true - } - - // Generate the next event. - return yaml_parser_state_machine(parser, event) -} - -// Set parser error. -func yaml_parser_set_parser_error(parser *yaml_parser_t, problem string, problem_mark yaml_mark_t) bool { - parser.error = yaml_PARSER_ERROR - parser.problem = problem - parser.problem_mark = problem_mark - return false -} - -func yaml_parser_set_parser_error_context(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string, problem_mark yaml_mark_t) bool { - parser.error = yaml_PARSER_ERROR - parser.context = context - parser.context_mark = context_mark - parser.problem = problem - parser.problem_mark = problem_mark - return false -} - -// State dispatcher. -func yaml_parser_state_machine(parser *yaml_parser_t, event *yaml_event_t) bool { - //trace("yaml_parser_state_machine", "state:", parser.state.String()) - - switch parser.state { - case yaml_PARSE_STREAM_START_STATE: - return yaml_parser_parse_stream_start(parser, event) - - case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE: - return yaml_parser_parse_document_start(parser, event, true) - - case yaml_PARSE_DOCUMENT_START_STATE: - return yaml_parser_parse_document_start(parser, event, false) - - case yaml_PARSE_DOCUMENT_CONTENT_STATE: - return yaml_parser_parse_document_content(parser, event) - - case yaml_PARSE_DOCUMENT_END_STATE: - return yaml_parser_parse_document_end(parser, event) - - case yaml_PARSE_BLOCK_NODE_STATE: - return yaml_parser_parse_node(parser, event, true, false) - - case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE: - return yaml_parser_parse_node(parser, event, true, true) - - case yaml_PARSE_FLOW_NODE_STATE: - return yaml_parser_parse_node(parser, event, false, false) - - case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE: - return yaml_parser_parse_block_sequence_entry(parser, event, true) - - case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE: - return yaml_parser_parse_block_sequence_entry(parser, event, false) - - case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE: - return yaml_parser_parse_indentless_sequence_entry(parser, event) - - case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE: - return yaml_parser_parse_block_mapping_key(parser, event, true) - - case yaml_PARSE_BLOCK_MAPPING_KEY_STATE: - return yaml_parser_parse_block_mapping_key(parser, event, false) - - case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE: - return yaml_parser_parse_block_mapping_value(parser, event) - - case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE: - return yaml_parser_parse_flow_sequence_entry(parser, event, true) - - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE: - return yaml_parser_parse_flow_sequence_entry(parser, event, false) - - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE: - return yaml_parser_parse_flow_sequence_entry_mapping_key(parser, event) - - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE: - return yaml_parser_parse_flow_sequence_entry_mapping_value(parser, event) - - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE: - return yaml_parser_parse_flow_sequence_entry_mapping_end(parser, event) - - case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE: - return yaml_parser_parse_flow_mapping_key(parser, event, true) - - case yaml_PARSE_FLOW_MAPPING_KEY_STATE: - return yaml_parser_parse_flow_mapping_key(parser, event, false) - - case yaml_PARSE_FLOW_MAPPING_VALUE_STATE: - return yaml_parser_parse_flow_mapping_value(parser, event, false) - - case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE: - return yaml_parser_parse_flow_mapping_value(parser, event, true) - - default: - panic("invalid parser state") - } -} - -// Parse the production: -// stream ::= STREAM-START implicit_document? explicit_document* STREAM-END -// ************ -func yaml_parser_parse_stream_start(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_STREAM_START_TOKEN { - return yaml_parser_set_parser_error(parser, "did not find expected ", token.start_mark) - } - parser.state = yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE - *event = yaml_event_t{ - typ: yaml_STREAM_START_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - encoding: token.encoding, - } - skip_token(parser) - return true -} - -// Parse the productions: -// implicit_document ::= block_node DOCUMENT-END* -// * -// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* -// ************************* -func yaml_parser_parse_document_start(parser *yaml_parser_t, event *yaml_event_t, implicit bool) bool { - - token := peek_token(parser) - if token == nil { - return false - } - - // Parse extra document end indicators. - if !implicit { - for token.typ == yaml_DOCUMENT_END_TOKEN { - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - } - } - - if implicit && token.typ != yaml_VERSION_DIRECTIVE_TOKEN && - token.typ != yaml_TAG_DIRECTIVE_TOKEN && - token.typ != yaml_DOCUMENT_START_TOKEN && - token.typ != yaml_STREAM_END_TOKEN { - // Parse an implicit document. - if !yaml_parser_process_directives(parser, nil, nil) { - return false - } - parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE) - parser.state = yaml_PARSE_BLOCK_NODE_STATE - - *event = yaml_event_t{ - typ: yaml_DOCUMENT_START_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - } - - } else if token.typ != yaml_STREAM_END_TOKEN { - // Parse an explicit document. - var version_directive *yaml_version_directive_t - var tag_directives []yaml_tag_directive_t - start_mark := token.start_mark - if !yaml_parser_process_directives(parser, &version_directive, &tag_directives) { - return false - } - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_DOCUMENT_START_TOKEN { - yaml_parser_set_parser_error(parser, - "did not find expected ", token.start_mark) - return false - } - parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE) - parser.state = yaml_PARSE_DOCUMENT_CONTENT_STATE - end_mark := token.end_mark - - *event = yaml_event_t{ - typ: yaml_DOCUMENT_START_EVENT, - start_mark: start_mark, - end_mark: end_mark, - version_directive: version_directive, - tag_directives: tag_directives, - implicit: false, - } - skip_token(parser) - - } else { - // Parse the stream end. - parser.state = yaml_PARSE_END_STATE - *event = yaml_event_t{ - typ: yaml_STREAM_END_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - } - skip_token(parser) - } - - return true -} - -// Parse the productions: -// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* -// *********** -// -func yaml_parser_parse_document_content(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - if token.typ == yaml_VERSION_DIRECTIVE_TOKEN || - token.typ == yaml_TAG_DIRECTIVE_TOKEN || - token.typ == yaml_DOCUMENT_START_TOKEN || - token.typ == yaml_DOCUMENT_END_TOKEN || - token.typ == yaml_STREAM_END_TOKEN { - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - return yaml_parser_process_empty_scalar(parser, event, - token.start_mark) - } - return yaml_parser_parse_node(parser, event, true, false) -} - -// Parse the productions: -// implicit_document ::= block_node DOCUMENT-END* -// ************* -// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* -// -func yaml_parser_parse_document_end(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - - start_mark := token.start_mark - end_mark := token.start_mark - - implicit := true - if token.typ == yaml_DOCUMENT_END_TOKEN { - end_mark = token.end_mark - skip_token(parser) - implicit = false - } - - parser.tag_directives = parser.tag_directives[:0] - - parser.state = yaml_PARSE_DOCUMENT_START_STATE - *event = yaml_event_t{ - typ: yaml_DOCUMENT_END_EVENT, - start_mark: start_mark, - end_mark: end_mark, - implicit: implicit, - } - return true -} - -// Parse the productions: -// block_node_or_indentless_sequence ::= -// ALIAS -// ***** -// | properties (block_content | indentless_block_sequence)? -// ********** * -// | block_content | indentless_block_sequence -// * -// block_node ::= ALIAS -// ***** -// | properties block_content? -// ********** * -// | block_content -// * -// flow_node ::= ALIAS -// ***** -// | properties flow_content? -// ********** * -// | flow_content -// * -// properties ::= TAG ANCHOR? | ANCHOR TAG? -// ************************* -// block_content ::= block_collection | flow_collection | SCALAR -// ****** -// flow_content ::= flow_collection | SCALAR -// ****** -func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, indentless_sequence bool) bool { - //defer trace("yaml_parser_parse_node", "block:", block, "indentless_sequence:", indentless_sequence)() - - token := peek_token(parser) - if token == nil { - return false - } - - if token.typ == yaml_ALIAS_TOKEN { - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - *event = yaml_event_t{ - typ: yaml_ALIAS_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - anchor: token.value, - } - skip_token(parser) - return true - } - - start_mark := token.start_mark - end_mark := token.start_mark - - var tag_token bool - var tag_handle, tag_suffix, anchor []byte - var tag_mark yaml_mark_t - if token.typ == yaml_ANCHOR_TOKEN { - anchor = token.value - start_mark = token.start_mark - end_mark = token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ == yaml_TAG_TOKEN { - tag_token = true - tag_handle = token.value - tag_suffix = token.suffix - tag_mark = token.start_mark - end_mark = token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - } - } else if token.typ == yaml_TAG_TOKEN { - tag_token = true - tag_handle = token.value - tag_suffix = token.suffix - start_mark = token.start_mark - tag_mark = token.start_mark - end_mark = token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ == yaml_ANCHOR_TOKEN { - anchor = token.value - end_mark = token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - } - } - - var tag []byte - if tag_token { - if len(tag_handle) == 0 { - tag = tag_suffix - tag_suffix = nil - } else { - for i := range parser.tag_directives { - if bytes.Equal(parser.tag_directives[i].handle, tag_handle) { - tag = append([]byte(nil), parser.tag_directives[i].prefix...) - tag = append(tag, tag_suffix...) - break - } - } - if len(tag) == 0 { - yaml_parser_set_parser_error_context(parser, - "while parsing a node", start_mark, - "found undefined tag handle", tag_mark) - return false - } - } - } - - implicit := len(tag) == 0 - if indentless_sequence && token.typ == yaml_BLOCK_ENTRY_TOKEN { - end_mark = token.end_mark - parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE - *event = yaml_event_t{ - typ: yaml_SEQUENCE_START_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE), - } - return true - } - if token.typ == yaml_SCALAR_TOKEN { - var plain_implicit, quoted_implicit bool - end_mark = token.end_mark - if (len(tag) == 0 && token.style == yaml_PLAIN_SCALAR_STYLE) || (len(tag) == 1 && tag[0] == '!') { - plain_implicit = true - } else if len(tag) == 0 { - quoted_implicit = true - } - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - - *event = yaml_event_t{ - typ: yaml_SCALAR_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - value: token.value, - implicit: plain_implicit, - quoted_implicit: quoted_implicit, - style: yaml_style_t(token.style), - } - skip_token(parser) - return true - } - if token.typ == yaml_FLOW_SEQUENCE_START_TOKEN { - // [Go] Some of the events below can be merged as they differ only on style. - end_mark = token.end_mark - parser.state = yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE - *event = yaml_event_t{ - typ: yaml_SEQUENCE_START_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(yaml_FLOW_SEQUENCE_STYLE), - } - return true - } - if token.typ == yaml_FLOW_MAPPING_START_TOKEN { - end_mark = token.end_mark - parser.state = yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE - *event = yaml_event_t{ - typ: yaml_MAPPING_START_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(yaml_FLOW_MAPPING_STYLE), - } - return true - } - if block && token.typ == yaml_BLOCK_SEQUENCE_START_TOKEN { - end_mark = token.end_mark - parser.state = yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE - *event = yaml_event_t{ - typ: yaml_SEQUENCE_START_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE), - } - return true - } - if block && token.typ == yaml_BLOCK_MAPPING_START_TOKEN { - end_mark = token.end_mark - parser.state = yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE - *event = yaml_event_t{ - typ: yaml_MAPPING_START_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - implicit: implicit, - style: yaml_style_t(yaml_BLOCK_MAPPING_STYLE), - } - return true - } - if len(anchor) > 0 || len(tag) > 0 { - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - - *event = yaml_event_t{ - typ: yaml_SCALAR_EVENT, - start_mark: start_mark, - end_mark: end_mark, - anchor: anchor, - tag: tag, - implicit: implicit, - quoted_implicit: false, - style: yaml_style_t(yaml_PLAIN_SCALAR_STYLE), - } - return true - } - - context := "while parsing a flow node" - if block { - context = "while parsing a block node" - } - yaml_parser_set_parser_error_context(parser, context, start_mark, - "did not find expected node content", token.start_mark) - return false -} - -// Parse the productions: -// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END -// ******************** *********** * ********* -// -func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { - if first { - token := peek_token(parser) - parser.marks = append(parser.marks, token.start_mark) - skip_token(parser) - } - - token := peek_token(parser) - if token == nil { - return false - } - - if token.typ == yaml_BLOCK_ENTRY_TOKEN { - mark := token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_BLOCK_ENTRY_TOKEN && token.typ != yaml_BLOCK_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE) - return yaml_parser_parse_node(parser, event, true, false) - } else { - parser.state = yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE - return yaml_parser_process_empty_scalar(parser, event, mark) - } - } - if token.typ == yaml_BLOCK_END_TOKEN { - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - - *event = yaml_event_t{ - typ: yaml_SEQUENCE_END_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - } - - skip_token(parser) - return true - } - - context_mark := parser.marks[len(parser.marks)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - return yaml_parser_set_parser_error_context(parser, - "while parsing a block collection", context_mark, - "did not find expected '-' indicator", token.start_mark) -} - -// Parse the productions: -// indentless_sequence ::= (BLOCK-ENTRY block_node?)+ -// *********** * -func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - - if token.typ == yaml_BLOCK_ENTRY_TOKEN { - mark := token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_BLOCK_ENTRY_TOKEN && - token.typ != yaml_KEY_TOKEN && - token.typ != yaml_VALUE_TOKEN && - token.typ != yaml_BLOCK_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE) - return yaml_parser_parse_node(parser, event, true, false) - } - parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE - return yaml_parser_process_empty_scalar(parser, event, mark) - } - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - - *event = yaml_event_t{ - typ: yaml_SEQUENCE_END_EVENT, - start_mark: token.start_mark, - end_mark: token.start_mark, // [Go] Shouldn't this be token.end_mark? - } - return true -} - -// Parse the productions: -// block_mapping ::= BLOCK-MAPPING_START -// ******************* -// ((KEY block_node_or_indentless_sequence?)? -// *** * -// (VALUE block_node_or_indentless_sequence?)?)* -// -// BLOCK-END -// ********* -// -func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { - if first { - token := peek_token(parser) - parser.marks = append(parser.marks, token.start_mark) - skip_token(parser) - } - - token := peek_token(parser) - if token == nil { - return false - } - - if token.typ == yaml_KEY_TOKEN { - mark := token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_KEY_TOKEN && - token.typ != yaml_VALUE_TOKEN && - token.typ != yaml_BLOCK_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_VALUE_STATE) - return yaml_parser_parse_node(parser, event, true, true) - } else { - parser.state = yaml_PARSE_BLOCK_MAPPING_VALUE_STATE - return yaml_parser_process_empty_scalar(parser, event, mark) - } - } else if token.typ == yaml_BLOCK_END_TOKEN { - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - *event = yaml_event_t{ - typ: yaml_MAPPING_END_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - } - skip_token(parser) - return true - } - - context_mark := parser.marks[len(parser.marks)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - return yaml_parser_set_parser_error_context(parser, - "while parsing a block mapping", context_mark, - "did not find expected key", token.start_mark) -} - -// Parse the productions: -// block_mapping ::= BLOCK-MAPPING_START -// -// ((KEY block_node_or_indentless_sequence?)? -// -// (VALUE block_node_or_indentless_sequence?)?)* -// ***** * -// BLOCK-END -// -// -func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - if token.typ == yaml_VALUE_TOKEN { - mark := token.end_mark - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_KEY_TOKEN && - token.typ != yaml_VALUE_TOKEN && - token.typ != yaml_BLOCK_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_KEY_STATE) - return yaml_parser_parse_node(parser, event, true, true) - } - parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE - return yaml_parser_process_empty_scalar(parser, event, mark) - } - parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE - return yaml_parser_process_empty_scalar(parser, event, token.start_mark) -} - -// Parse the productions: -// flow_sequence ::= FLOW-SEQUENCE-START -// ******************* -// (flow_sequence_entry FLOW-ENTRY)* -// * ********** -// flow_sequence_entry? -// * -// FLOW-SEQUENCE-END -// ***************** -// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// * -// -func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { - if first { - token := peek_token(parser) - parser.marks = append(parser.marks, token.start_mark) - skip_token(parser) - } - token := peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { - if !first { - if token.typ == yaml_FLOW_ENTRY_TOKEN { - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - } else { - context_mark := parser.marks[len(parser.marks)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - return yaml_parser_set_parser_error_context(parser, - "while parsing a flow sequence", context_mark, - "did not find expected ',' or ']'", token.start_mark) - } - } - - if token.typ == yaml_KEY_TOKEN { - parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE - *event = yaml_event_t{ - typ: yaml_MAPPING_START_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - implicit: true, - style: yaml_style_t(yaml_FLOW_MAPPING_STYLE), - } - skip_token(parser) - return true - } else if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE) - return yaml_parser_parse_node(parser, event, false, false) - } - } - - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - - *event = yaml_event_t{ - typ: yaml_SEQUENCE_END_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - } - - skip_token(parser) - return true -} - -// -// Parse the productions: -// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// *** * -// -func yaml_parser_parse_flow_sequence_entry_mapping_key(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_VALUE_TOKEN && - token.typ != yaml_FLOW_ENTRY_TOKEN && - token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE) - return yaml_parser_parse_node(parser, event, false, false) - } - mark := token.end_mark - skip_token(parser) - parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE - return yaml_parser_process_empty_scalar(parser, event, mark) -} - -// Parse the productions: -// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// ***** * -// -func yaml_parser_parse_flow_sequence_entry_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - if token.typ == yaml_VALUE_TOKEN { - skip_token(parser) - token := peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE) - return yaml_parser_parse_node(parser, event, false, false) - } - } - parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE - return yaml_parser_process_empty_scalar(parser, event, token.start_mark) -} - -// Parse the productions: -// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// * -// -func yaml_parser_parse_flow_sequence_entry_mapping_end(parser *yaml_parser_t, event *yaml_event_t) bool { - token := peek_token(parser) - if token == nil { - return false - } - parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE - *event = yaml_event_t{ - typ: yaml_MAPPING_END_EVENT, - start_mark: token.start_mark, - end_mark: token.start_mark, // [Go] Shouldn't this be end_mark? - } - return true -} - -// Parse the productions: -// flow_mapping ::= FLOW-MAPPING-START -// ****************** -// (flow_mapping_entry FLOW-ENTRY)* -// * ********** -// flow_mapping_entry? -// ****************** -// FLOW-MAPPING-END -// **************** -// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// * *** * -// -func yaml_parser_parse_flow_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { - if first { - token := peek_token(parser) - parser.marks = append(parser.marks, token.start_mark) - skip_token(parser) - } - - token := peek_token(parser) - if token == nil { - return false - } - - if token.typ != yaml_FLOW_MAPPING_END_TOKEN { - if !first { - if token.typ == yaml_FLOW_ENTRY_TOKEN { - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - } else { - context_mark := parser.marks[len(parser.marks)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - return yaml_parser_set_parser_error_context(parser, - "while parsing a flow mapping", context_mark, - "did not find expected ',' or '}'", token.start_mark) - } - } - - if token.typ == yaml_KEY_TOKEN { - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_VALUE_TOKEN && - token.typ != yaml_FLOW_ENTRY_TOKEN && - token.typ != yaml_FLOW_MAPPING_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_VALUE_STATE) - return yaml_parser_parse_node(parser, event, false, false) - } else { - parser.state = yaml_PARSE_FLOW_MAPPING_VALUE_STATE - return yaml_parser_process_empty_scalar(parser, event, token.start_mark) - } - } else if token.typ != yaml_FLOW_MAPPING_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE) - return yaml_parser_parse_node(parser, event, false, false) - } - } - - parser.state = parser.states[len(parser.states)-1] - parser.states = parser.states[:len(parser.states)-1] - parser.marks = parser.marks[:len(parser.marks)-1] - *event = yaml_event_t{ - typ: yaml_MAPPING_END_EVENT, - start_mark: token.start_mark, - end_mark: token.end_mark, - } - skip_token(parser) - return true -} - -// Parse the productions: -// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? -// * ***** * -// -func yaml_parser_parse_flow_mapping_value(parser *yaml_parser_t, event *yaml_event_t, empty bool) bool { - token := peek_token(parser) - if token == nil { - return false - } - if empty { - parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE - return yaml_parser_process_empty_scalar(parser, event, token.start_mark) - } - if token.typ == yaml_VALUE_TOKEN { - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_MAPPING_END_TOKEN { - parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_KEY_STATE) - return yaml_parser_parse_node(parser, event, false, false) - } - } - parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE - return yaml_parser_process_empty_scalar(parser, event, token.start_mark) -} - -// Generate an empty scalar event. -func yaml_parser_process_empty_scalar(parser *yaml_parser_t, event *yaml_event_t, mark yaml_mark_t) bool { - *event = yaml_event_t{ - typ: yaml_SCALAR_EVENT, - start_mark: mark, - end_mark: mark, - value: nil, // Empty - implicit: true, - style: yaml_style_t(yaml_PLAIN_SCALAR_STYLE), - } - return true -} - -var default_tag_directives = []yaml_tag_directive_t{ - {[]byte("!"), []byte("!")}, - {[]byte("!!"), []byte("tag:yaml.org,2002:")}, -} - -// Parse directives. -func yaml_parser_process_directives(parser *yaml_parser_t, - version_directive_ref **yaml_version_directive_t, - tag_directives_ref *[]yaml_tag_directive_t) bool { - - var version_directive *yaml_version_directive_t - var tag_directives []yaml_tag_directive_t - - token := peek_token(parser) - if token == nil { - return false - } - - for token.typ == yaml_VERSION_DIRECTIVE_TOKEN || token.typ == yaml_TAG_DIRECTIVE_TOKEN { - if token.typ == yaml_VERSION_DIRECTIVE_TOKEN { - if version_directive != nil { - yaml_parser_set_parser_error(parser, - "found duplicate %YAML directive", token.start_mark) - return false - } - if token.major != 1 || token.minor != 1 { - yaml_parser_set_parser_error(parser, - "found incompatible YAML document", token.start_mark) - return false - } - version_directive = &yaml_version_directive_t{ - major: token.major, - minor: token.minor, - } - } else if token.typ == yaml_TAG_DIRECTIVE_TOKEN { - value := yaml_tag_directive_t{ - handle: token.value, - prefix: token.prefix, - } - if !yaml_parser_append_tag_directive(parser, value, false, token.start_mark) { - return false - } - tag_directives = append(tag_directives, value) - } - - skip_token(parser) - token = peek_token(parser) - if token == nil { - return false - } - } - - for i := range default_tag_directives { - if !yaml_parser_append_tag_directive(parser, default_tag_directives[i], true, token.start_mark) { - return false - } - } - - if version_directive_ref != nil { - *version_directive_ref = version_directive - } - if tag_directives_ref != nil { - *tag_directives_ref = tag_directives - } - return true -} - -// Append a tag directive to the directives stack. -func yaml_parser_append_tag_directive(parser *yaml_parser_t, value yaml_tag_directive_t, allow_duplicates bool, mark yaml_mark_t) bool { - for i := range parser.tag_directives { - if bytes.Equal(value.handle, parser.tag_directives[i].handle) { - if allow_duplicates { - return true - } - return yaml_parser_set_parser_error(parser, "found duplicate %TAG directive", mark) - } - } - - // [Go] I suspect the copy is unnecessary. This was likely done - // because there was no way to track ownership of the data. - value_copy := yaml_tag_directive_t{ - handle: make([]byte, len(value.handle)), - prefix: make([]byte, len(value.prefix)), - } - copy(value_copy.handle, value.handle) - copy(value_copy.prefix, value.prefix) - parser.tag_directives = append(parser.tag_directives, value_copy) - return true -} diff --git a/dev-tools/vendor/gopkg.in/yaml.v2/readerc.go b/dev-tools/vendor/gopkg.in/yaml.v2/readerc.go deleted file mode 100644 index f450791717bf..000000000000 --- a/dev-tools/vendor/gopkg.in/yaml.v2/readerc.go +++ /dev/null @@ -1,394 +0,0 @@ -package yaml - -import ( - "io" -) - -// Set the reader error and return 0. -func yaml_parser_set_reader_error(parser *yaml_parser_t, problem string, offset int, value int) bool { - parser.error = yaml_READER_ERROR - parser.problem = problem - parser.problem_offset = offset - parser.problem_value = value - return false -} - -// Byte order marks. -const ( - bom_UTF8 = "\xef\xbb\xbf" - bom_UTF16LE = "\xff\xfe" - bom_UTF16BE = "\xfe\xff" -) - -// Determine the input stream encoding by checking the BOM symbol. If no BOM is -// found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure. -func yaml_parser_determine_encoding(parser *yaml_parser_t) bool { - // Ensure that we had enough bytes in the raw buffer. - for !parser.eof && len(parser.raw_buffer)-parser.raw_buffer_pos < 3 { - if !yaml_parser_update_raw_buffer(parser) { - return false - } - } - - // Determine the encoding. - buf := parser.raw_buffer - pos := parser.raw_buffer_pos - avail := len(buf) - pos - if avail >= 2 && buf[pos] == bom_UTF16LE[0] && buf[pos+1] == bom_UTF16LE[1] { - parser.encoding = yaml_UTF16LE_ENCODING - parser.raw_buffer_pos += 2 - parser.offset += 2 - } else if avail >= 2 && buf[pos] == bom_UTF16BE[0] && buf[pos+1] == bom_UTF16BE[1] { - parser.encoding = yaml_UTF16BE_ENCODING - parser.raw_buffer_pos += 2 - parser.offset += 2 - } else if avail >= 3 && buf[pos] == bom_UTF8[0] && buf[pos+1] == bom_UTF8[1] && buf[pos+2] == bom_UTF8[2] { - parser.encoding = yaml_UTF8_ENCODING - parser.raw_buffer_pos += 3 - parser.offset += 3 - } else { - parser.encoding = yaml_UTF8_ENCODING - } - return true -} - -// Update the raw buffer. -func yaml_parser_update_raw_buffer(parser *yaml_parser_t) bool { - size_read := 0 - - // Return if the raw buffer is full. - if parser.raw_buffer_pos == 0 && len(parser.raw_buffer) == cap(parser.raw_buffer) { - return true - } - - // Return on EOF. - if parser.eof { - return true - } - - // Move the remaining bytes in the raw buffer to the beginning. - if parser.raw_buffer_pos > 0 && parser.raw_buffer_pos < len(parser.raw_buffer) { - copy(parser.raw_buffer, parser.raw_buffer[parser.raw_buffer_pos:]) - } - parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)-parser.raw_buffer_pos] - parser.raw_buffer_pos = 0 - - // Call the read handler to fill the buffer. - size_read, err := parser.read_handler(parser, parser.raw_buffer[len(parser.raw_buffer):cap(parser.raw_buffer)]) - parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)+size_read] - if err == io.EOF { - parser.eof = true - } else if err != nil { - return yaml_parser_set_reader_error(parser, "input error: "+err.Error(), parser.offset, -1) - } - return true -} - -// Ensure that the buffer contains at least `length` characters. -// Return true on success, false on failure. -// -// The length is supposed to be significantly less that the buffer size. -func yaml_parser_update_buffer(parser *yaml_parser_t, length int) bool { - if parser.read_handler == nil { - panic("read handler must be set") - } - - // If the EOF flag is set and the raw buffer is empty, do nothing. - if parser.eof && parser.raw_buffer_pos == len(parser.raw_buffer) { - return true - } - - // Return if the buffer contains enough characters. - if parser.unread >= length { - return true - } - - // Determine the input encoding if it is not known yet. - if parser.encoding == yaml_ANY_ENCODING { - if !yaml_parser_determine_encoding(parser) { - return false - } - } - - // Move the unread characters to the beginning of the buffer. - buffer_len := len(parser.buffer) - if parser.buffer_pos > 0 && parser.buffer_pos < buffer_len { - copy(parser.buffer, parser.buffer[parser.buffer_pos:]) - buffer_len -= parser.buffer_pos - parser.buffer_pos = 0 - } else if parser.buffer_pos == buffer_len { - buffer_len = 0 - parser.buffer_pos = 0 - } - - // Open the whole buffer for writing, and cut it before returning. - parser.buffer = parser.buffer[:cap(parser.buffer)] - - // Fill the buffer until it has enough characters. - first := true - for parser.unread < length { - - // Fill the raw buffer if necessary. - if !first || parser.raw_buffer_pos == len(parser.raw_buffer) { - if !yaml_parser_update_raw_buffer(parser) { - parser.buffer = parser.buffer[:buffer_len] - return false - } - } - first = false - - // Decode the raw buffer. - inner: - for parser.raw_buffer_pos != len(parser.raw_buffer) { - var value rune - var width int - - raw_unread := len(parser.raw_buffer) - parser.raw_buffer_pos - - // Decode the next character. - switch parser.encoding { - case yaml_UTF8_ENCODING: - // Decode a UTF-8 character. Check RFC 3629 - // (http://www.ietf.org/rfc/rfc3629.txt) for more details. - // - // The following table (taken from the RFC) is used for - // decoding. - // - // Char. number range | UTF-8 octet sequence - // (hexadecimal) | (binary) - // --------------------+------------------------------------ - // 0000 0000-0000 007F | 0xxxxxxx - // 0000 0080-0000 07FF | 110xxxxx 10xxxxxx - // 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx - // 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - // - // Additionally, the characters in the range 0xD800-0xDFFF - // are prohibited as they are reserved for use with UTF-16 - // surrogate pairs. - - // Determine the length of the UTF-8 sequence. - octet := parser.raw_buffer[parser.raw_buffer_pos] - switch { - case octet&0x80 == 0x00: - width = 1 - case octet&0xE0 == 0xC0: - width = 2 - case octet&0xF0 == 0xE0: - width = 3 - case octet&0xF8 == 0xF0: - width = 4 - default: - // The leading octet is invalid. - return yaml_parser_set_reader_error(parser, - "invalid leading UTF-8 octet", - parser.offset, int(octet)) - } - - // Check if the raw buffer contains an incomplete character. - if width > raw_unread { - if parser.eof { - return yaml_parser_set_reader_error(parser, - "incomplete UTF-8 octet sequence", - parser.offset, -1) - } - break inner - } - - // Decode the leading octet. - switch { - case octet&0x80 == 0x00: - value = rune(octet & 0x7F) - case octet&0xE0 == 0xC0: - value = rune(octet & 0x1F) - case octet&0xF0 == 0xE0: - value = rune(octet & 0x0F) - case octet&0xF8 == 0xF0: - value = rune(octet & 0x07) - default: - value = 0 - } - - // Check and decode the trailing octets. - for k := 1; k < width; k++ { - octet = parser.raw_buffer[parser.raw_buffer_pos+k] - - // Check if the octet is valid. - if (octet & 0xC0) != 0x80 { - return yaml_parser_set_reader_error(parser, - "invalid trailing UTF-8 octet", - parser.offset+k, int(octet)) - } - - // Decode the octet. - value = (value << 6) + rune(octet&0x3F) - } - - // Check the length of the sequence against the value. - switch { - case width == 1: - case width == 2 && value >= 0x80: - case width == 3 && value >= 0x800: - case width == 4 && value >= 0x10000: - default: - return yaml_parser_set_reader_error(parser, - "invalid length of a UTF-8 sequence", - parser.offset, -1) - } - - // Check the range of the value. - if value >= 0xD800 && value <= 0xDFFF || value > 0x10FFFF { - return yaml_parser_set_reader_error(parser, - "invalid Unicode character", - parser.offset, int(value)) - } - - case yaml_UTF16LE_ENCODING, yaml_UTF16BE_ENCODING: - var low, high int - if parser.encoding == yaml_UTF16LE_ENCODING { - low, high = 0, 1 - } else { - low, high = 1, 0 - } - - // The UTF-16 encoding is not as simple as one might - // naively think. Check RFC 2781 - // (http://www.ietf.org/rfc/rfc2781.txt). - // - // Normally, two subsequent bytes describe a Unicode - // character. However a special technique (called a - // surrogate pair) is used for specifying character - // values larger than 0xFFFF. - // - // A surrogate pair consists of two pseudo-characters: - // high surrogate area (0xD800-0xDBFF) - // low surrogate area (0xDC00-0xDFFF) - // - // The following formulas are used for decoding - // and encoding characters using surrogate pairs: - // - // U = U' + 0x10000 (0x01 00 00 <= U <= 0x10 FF FF) - // U' = yyyyyyyyyyxxxxxxxxxx (0 <= U' <= 0x0F FF FF) - // W1 = 110110yyyyyyyyyy - // W2 = 110111xxxxxxxxxx - // - // where U is the character value, W1 is the high surrogate - // area, W2 is the low surrogate area. - - // Check for incomplete UTF-16 character. - if raw_unread < 2 { - if parser.eof { - return yaml_parser_set_reader_error(parser, - "incomplete UTF-16 character", - parser.offset, -1) - } - break inner - } - - // Get the character. - value = rune(parser.raw_buffer[parser.raw_buffer_pos+low]) + - (rune(parser.raw_buffer[parser.raw_buffer_pos+high]) << 8) - - // Check for unexpected low surrogate area. - if value&0xFC00 == 0xDC00 { - return yaml_parser_set_reader_error(parser, - "unexpected low surrogate area", - parser.offset, int(value)) - } - - // Check for a high surrogate area. - if value&0xFC00 == 0xD800 { - width = 4 - - // Check for incomplete surrogate pair. - if raw_unread < 4 { - if parser.eof { - return yaml_parser_set_reader_error(parser, - "incomplete UTF-16 surrogate pair", - parser.offset, -1) - } - break inner - } - - // Get the next character. - value2 := rune(parser.raw_buffer[parser.raw_buffer_pos+low+2]) + - (rune(parser.raw_buffer[parser.raw_buffer_pos+high+2]) << 8) - - // Check for a low surrogate area. - if value2&0xFC00 != 0xDC00 { - return yaml_parser_set_reader_error(parser, - "expected low surrogate area", - parser.offset+2, int(value2)) - } - - // Generate the value of the surrogate pair. - value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF) - } else { - width = 2 - } - - default: - panic("impossible") - } - - // Check if the character is in the allowed range: - // #x9 | #xA | #xD | [#x20-#x7E] (8 bit) - // | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD] (16 bit) - // | [#x10000-#x10FFFF] (32 bit) - switch { - case value == 0x09: - case value == 0x0A: - case value == 0x0D: - case value >= 0x20 && value <= 0x7E: - case value == 0x85: - case value >= 0xA0 && value <= 0xD7FF: - case value >= 0xE000 && value <= 0xFFFD: - case value >= 0x10000 && value <= 0x10FFFF: - default: - return yaml_parser_set_reader_error(parser, - "control characters are not allowed", - parser.offset, int(value)) - } - - // Move the raw pointers. - parser.raw_buffer_pos += width - parser.offset += width - - // Finally put the character into the buffer. - if value <= 0x7F { - // 0000 0000-0000 007F . 0xxxxxxx - parser.buffer[buffer_len+0] = byte(value) - buffer_len += 1 - } else if value <= 0x7FF { - // 0000 0080-0000 07FF . 110xxxxx 10xxxxxx - parser.buffer[buffer_len+0] = byte(0xC0 + (value >> 6)) - parser.buffer[buffer_len+1] = byte(0x80 + (value & 0x3F)) - buffer_len += 2 - } else if value <= 0xFFFF { - // 0000 0800-0000 FFFF . 1110xxxx 10xxxxxx 10xxxxxx - parser.buffer[buffer_len+0] = byte(0xE0 + (value >> 12)) - parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 6) & 0x3F)) - parser.buffer[buffer_len+2] = byte(0x80 + (value & 0x3F)) - buffer_len += 3 - } else { - // 0001 0000-0010 FFFF . 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - parser.buffer[buffer_len+0] = byte(0xF0 + (value >> 18)) - parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 12) & 0x3F)) - parser.buffer[buffer_len+2] = byte(0x80 + ((value >> 6) & 0x3F)) - parser.buffer[buffer_len+3] = byte(0x80 + (value & 0x3F)) - buffer_len += 4 - } - - parser.unread++ - } - - // On EOF, put NUL into the buffer and return. - if parser.eof { - parser.buffer[buffer_len] = 0 - buffer_len++ - parser.unread++ - break - } - } - parser.buffer = parser.buffer[:buffer_len] - return true -} diff --git a/dev-tools/vendor/gopkg.in/yaml.v2/resolve.go b/dev-tools/vendor/gopkg.in/yaml.v2/resolve.go deleted file mode 100644 index 232313cc0845..000000000000 --- a/dev-tools/vendor/gopkg.in/yaml.v2/resolve.go +++ /dev/null @@ -1,208 +0,0 @@ -package yaml - -import ( - "encoding/base64" - "math" - "regexp" - "strconv" - "strings" - "unicode/utf8" -) - -type resolveMapItem struct { - value interface{} - tag string -} - -var resolveTable = make([]byte, 256) -var resolveMap = make(map[string]resolveMapItem) - -func init() { - t := resolveTable - t[int('+')] = 'S' // Sign - t[int('-')] = 'S' - for _, c := range "0123456789" { - t[int(c)] = 'D' // Digit - } - for _, c := range "yYnNtTfFoO~" { - t[int(c)] = 'M' // In map - } - t[int('.')] = '.' // Float (potentially in map) - - var resolveMapList = []struct { - v interface{} - tag string - l []string - }{ - {true, yaml_BOOL_TAG, []string{"y", "Y", "yes", "Yes", "YES"}}, - {true, yaml_BOOL_TAG, []string{"true", "True", "TRUE"}}, - {true, yaml_BOOL_TAG, []string{"on", "On", "ON"}}, - {false, yaml_BOOL_TAG, []string{"n", "N", "no", "No", "NO"}}, - {false, yaml_BOOL_TAG, []string{"false", "False", "FALSE"}}, - {false, yaml_BOOL_TAG, []string{"off", "Off", "OFF"}}, - {nil, yaml_NULL_TAG, []string{"", "~", "null", "Null", "NULL"}}, - {math.NaN(), yaml_FLOAT_TAG, []string{".nan", ".NaN", ".NAN"}}, - {math.Inf(+1), yaml_FLOAT_TAG, []string{".inf", ".Inf", ".INF"}}, - {math.Inf(+1), yaml_FLOAT_TAG, []string{"+.inf", "+.Inf", "+.INF"}}, - {math.Inf(-1), yaml_FLOAT_TAG, []string{"-.inf", "-.Inf", "-.INF"}}, - {"<<", yaml_MERGE_TAG, []string{"<<"}}, - } - - m := resolveMap - for _, item := range resolveMapList { - for _, s := range item.l { - m[s] = resolveMapItem{item.v, item.tag} - } - } -} - -const longTagPrefix = "tag:yaml.org,2002:" - -func shortTag(tag string) string { - // TODO This can easily be made faster and produce less garbage. - if strings.HasPrefix(tag, longTagPrefix) { - return "!!" + tag[len(longTagPrefix):] - } - return tag -} - -func longTag(tag string) string { - if strings.HasPrefix(tag, "!!") { - return longTagPrefix + tag[2:] - } - return tag -} - -func resolvableTag(tag string) bool { - switch tag { - case "", yaml_STR_TAG, yaml_BOOL_TAG, yaml_INT_TAG, yaml_FLOAT_TAG, yaml_NULL_TAG: - return true - } - return false -} - -var yamlStyleFloat = regexp.MustCompile(`^[-+]?[0-9]*\.?[0-9]+([eE][-+][0-9]+)?$`) - -func resolve(tag string, in string) (rtag string, out interface{}) { - if !resolvableTag(tag) { - return tag, in - } - - defer func() { - switch tag { - case "", rtag, yaml_STR_TAG, yaml_BINARY_TAG: - return - } - failf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(tag)) - }() - - // Any data is accepted as a !!str or !!binary. - // Otherwise, the prefix is enough of a hint about what it might be. - hint := byte('N') - if in != "" { - hint = resolveTable[in[0]] - } - if hint != 0 && tag != yaml_STR_TAG && tag != yaml_BINARY_TAG { - // Handle things we can lookup in a map. - if item, ok := resolveMap[in]; ok { - return item.tag, item.value - } - - // Base 60 floats are a bad idea, were dropped in YAML 1.2, and - // are purposefully unsupported here. They're still quoted on - // the way out for compatibility with other parser, though. - - switch hint { - case 'M': - // We've already checked the map above. - - case '.': - // Not in the map, so maybe a normal float. - floatv, err := strconv.ParseFloat(in, 64) - if err == nil { - return yaml_FLOAT_TAG, floatv - } - - case 'D', 'S': - // Int, float, or timestamp. - plain := strings.Replace(in, "_", "", -1) - intv, err := strconv.ParseInt(plain, 0, 64) - if err == nil { - if intv == int64(int(intv)) { - return yaml_INT_TAG, int(intv) - } else { - return yaml_INT_TAG, intv - } - } - uintv, err := strconv.ParseUint(plain, 0, 64) - if err == nil { - return yaml_INT_TAG, uintv - } - if yamlStyleFloat.MatchString(plain) { - floatv, err := strconv.ParseFloat(plain, 64) - if err == nil { - return yaml_FLOAT_TAG, floatv - } - } - if strings.HasPrefix(plain, "0b") { - intv, err := strconv.ParseInt(plain[2:], 2, 64) - if err == nil { - if intv == int64(int(intv)) { - return yaml_INT_TAG, int(intv) - } else { - return yaml_INT_TAG, intv - } - } - uintv, err := strconv.ParseUint(plain[2:], 2, 64) - if err == nil { - return yaml_INT_TAG, uintv - } - } else if strings.HasPrefix(plain, "-0b") { - intv, err := strconv.ParseInt(plain[3:], 2, 64) - if err == nil { - if intv == int64(int(intv)) { - return yaml_INT_TAG, -int(intv) - } else { - return yaml_INT_TAG, -intv - } - } - } - // XXX Handle timestamps here. - - default: - panic("resolveTable item not yet handled: " + string(rune(hint)) + " (with " + in + ")") - } - } - if tag == yaml_BINARY_TAG { - return yaml_BINARY_TAG, in - } - if utf8.ValidString(in) { - return yaml_STR_TAG, in - } - return yaml_BINARY_TAG, encodeBase64(in) -} - -// encodeBase64 encodes s as base64 that is broken up into multiple lines -// as appropriate for the resulting length. -func encodeBase64(s string) string { - const lineLen = 70 - encLen := base64.StdEncoding.EncodedLen(len(s)) - lines := encLen/lineLen + 1 - buf := make([]byte, encLen*2+lines) - in := buf[0:encLen] - out := buf[encLen:] - base64.StdEncoding.Encode(in, []byte(s)) - k := 0 - for i := 0; i < len(in); i += lineLen { - j := i + lineLen - if j > len(in) { - j = len(in) - } - k += copy(out[k:], in[i:j]) - if lines > 1 { - out[k] = '\n' - k++ - } - } - return string(out[:k]) -} diff --git a/dev-tools/vendor/gopkg.in/yaml.v2/scannerc.go b/dev-tools/vendor/gopkg.in/yaml.v2/scannerc.go deleted file mode 100644 index 074484455827..000000000000 --- a/dev-tools/vendor/gopkg.in/yaml.v2/scannerc.go +++ /dev/null @@ -1,2711 +0,0 @@ -package yaml - -import ( - "bytes" - "fmt" -) - -// Introduction -// ************ -// -// The following notes assume that you are familiar with the YAML specification -// (http://yaml.org/spec/1.2/spec.html). We mostly follow it, although in -// some cases we are less restrictive that it requires. -// -// The process of transforming a YAML stream into a sequence of events is -// divided on two steps: Scanning and Parsing. -// -// The Scanner transforms the input stream into a sequence of tokens, while the -// parser transform the sequence of tokens produced by the Scanner into a -// sequence of parsing events. -// -// The Scanner is rather clever and complicated. The Parser, on the contrary, -// is a straightforward implementation of a recursive-descendant parser (or, -// LL(1) parser, as it is usually called). -// -// Actually there are two issues of Scanning that might be called "clever", the -// rest is quite straightforward. The issues are "block collection start" and -// "simple keys". Both issues are explained below in details. -// -// Here the Scanning step is explained and implemented. We start with the list -// of all the tokens produced by the Scanner together with short descriptions. -// -// Now, tokens: -// -// STREAM-START(encoding) # The stream start. -// STREAM-END # The stream end. -// VERSION-DIRECTIVE(major,minor) # The '%YAML' directive. -// TAG-DIRECTIVE(handle,prefix) # The '%TAG' directive. -// DOCUMENT-START # '---' -// DOCUMENT-END # '...' -// BLOCK-SEQUENCE-START # Indentation increase denoting a block -// BLOCK-MAPPING-START # sequence or a block mapping. -// BLOCK-END # Indentation decrease. -// FLOW-SEQUENCE-START # '[' -// FLOW-SEQUENCE-END # ']' -// BLOCK-SEQUENCE-START # '{' -// BLOCK-SEQUENCE-END # '}' -// BLOCK-ENTRY # '-' -// FLOW-ENTRY # ',' -// KEY # '?' or nothing (simple keys). -// VALUE # ':' -// ALIAS(anchor) # '*anchor' -// ANCHOR(anchor) # '&anchor' -// TAG(handle,suffix) # '!handle!suffix' -// SCALAR(value,style) # A scalar. -// -// The following two tokens are "virtual" tokens denoting the beginning and the -// end of the stream: -// -// STREAM-START(encoding) -// STREAM-END -// -// We pass the information about the input stream encoding with the -// STREAM-START token. -// -// The next two tokens are responsible for tags: -// -// VERSION-DIRECTIVE(major,minor) -// TAG-DIRECTIVE(handle,prefix) -// -// Example: -// -// %YAML 1.1 -// %TAG ! !foo -// %TAG !yaml! tag:yaml.org,2002: -// --- -// -// The correspoding sequence of tokens: -// -// STREAM-START(utf-8) -// VERSION-DIRECTIVE(1,1) -// TAG-DIRECTIVE("!","!foo") -// TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:") -// DOCUMENT-START -// STREAM-END -// -// Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole -// line. -// -// The document start and end indicators are represented by: -// -// DOCUMENT-START -// DOCUMENT-END -// -// Note that if a YAML stream contains an implicit document (without '---' -// and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be -// produced. -// -// In the following examples, we present whole documents together with the -// produced tokens. -// -// 1. An implicit document: -// -// 'a scalar' -// -// Tokens: -// -// STREAM-START(utf-8) -// SCALAR("a scalar",single-quoted) -// STREAM-END -// -// 2. An explicit document: -// -// --- -// 'a scalar' -// ... -// -// Tokens: -// -// STREAM-START(utf-8) -// DOCUMENT-START -// SCALAR("a scalar",single-quoted) -// DOCUMENT-END -// STREAM-END -// -// 3. Several documents in a stream: -// -// 'a scalar' -// --- -// 'another scalar' -// --- -// 'yet another scalar' -// -// Tokens: -// -// STREAM-START(utf-8) -// SCALAR("a scalar",single-quoted) -// DOCUMENT-START -// SCALAR("another scalar",single-quoted) -// DOCUMENT-START -// SCALAR("yet another scalar",single-quoted) -// STREAM-END -// -// We have already introduced the SCALAR token above. The following tokens are -// used to describe aliases, anchors, tag, and scalars: -// -// ALIAS(anchor) -// ANCHOR(anchor) -// TAG(handle,suffix) -// SCALAR(value,style) -// -// The following series of examples illustrate the usage of these tokens: -// -// 1. A recursive sequence: -// -// &A [ *A ] -// -// Tokens: -// -// STREAM-START(utf-8) -// ANCHOR("A") -// FLOW-SEQUENCE-START -// ALIAS("A") -// FLOW-SEQUENCE-END -// STREAM-END -// -// 2. A tagged scalar: -// -// !!float "3.14" # A good approximation. -// -// Tokens: -// -// STREAM-START(utf-8) -// TAG("!!","float") -// SCALAR("3.14",double-quoted) -// STREAM-END -// -// 3. Various scalar styles: -// -// --- # Implicit empty plain scalars do not produce tokens. -// --- a plain scalar -// --- 'a single-quoted scalar' -// --- "a double-quoted scalar" -// --- |- -// a literal scalar -// --- >- -// a folded -// scalar -// -// Tokens: -// -// STREAM-START(utf-8) -// DOCUMENT-START -// DOCUMENT-START -// SCALAR("a plain scalar",plain) -// DOCUMENT-START -// SCALAR("a single-quoted scalar",single-quoted) -// DOCUMENT-START -// SCALAR("a double-quoted scalar",double-quoted) -// DOCUMENT-START -// SCALAR("a literal scalar",literal) -// DOCUMENT-START -// SCALAR("a folded scalar",folded) -// STREAM-END -// -// Now it's time to review collection-related tokens. We will start with -// flow collections: -// -// FLOW-SEQUENCE-START -// FLOW-SEQUENCE-END -// FLOW-MAPPING-START -// FLOW-MAPPING-END -// FLOW-ENTRY -// KEY -// VALUE -// -// The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and -// FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}' -// correspondingly. FLOW-ENTRY represent the ',' indicator. Finally the -// indicators '?' and ':', which are used for denoting mapping keys and values, -// are represented by the KEY and VALUE tokens. -// -// The following examples show flow collections: -// -// 1. A flow sequence: -// -// [item 1, item 2, item 3] -// -// Tokens: -// -// STREAM-START(utf-8) -// FLOW-SEQUENCE-START -// SCALAR("item 1",plain) -// FLOW-ENTRY -// SCALAR("item 2",plain) -// FLOW-ENTRY -// SCALAR("item 3",plain) -// FLOW-SEQUENCE-END -// STREAM-END -// -// 2. A flow mapping: -// -// { -// a simple key: a value, # Note that the KEY token is produced. -// ? a complex key: another value, -// } -// -// Tokens: -// -// STREAM-START(utf-8) -// FLOW-MAPPING-START -// KEY -// SCALAR("a simple key",plain) -// VALUE -// SCALAR("a value",plain) -// FLOW-ENTRY -// KEY -// SCALAR("a complex key",plain) -// VALUE -// SCALAR("another value",plain) -// FLOW-ENTRY -// FLOW-MAPPING-END -// STREAM-END -// -// A simple key is a key which is not denoted by the '?' indicator. Note that -// the Scanner still produce the KEY token whenever it encounters a simple key. -// -// For scanning block collections, the following tokens are used (note that we -// repeat KEY and VALUE here): -// -// BLOCK-SEQUENCE-START -// BLOCK-MAPPING-START -// BLOCK-END -// BLOCK-ENTRY -// KEY -// VALUE -// -// The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation -// increase that precedes a block collection (cf. the INDENT token in Python). -// The token BLOCK-END denote indentation decrease that ends a block collection -// (cf. the DEDENT token in Python). However YAML has some syntax pecularities -// that makes detections of these tokens more complex. -// -// The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators -// '-', '?', and ':' correspondingly. -// -// The following examples show how the tokens BLOCK-SEQUENCE-START, -// BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner: -// -// 1. Block sequences: -// -// - item 1 -// - item 2 -// - -// - item 3.1 -// - item 3.2 -// - -// key 1: value 1 -// key 2: value 2 -// -// Tokens: -// -// STREAM-START(utf-8) -// BLOCK-SEQUENCE-START -// BLOCK-ENTRY -// SCALAR("item 1",plain) -// BLOCK-ENTRY -// SCALAR("item 2",plain) -// BLOCK-ENTRY -// BLOCK-SEQUENCE-START -// BLOCK-ENTRY -// SCALAR("item 3.1",plain) -// BLOCK-ENTRY -// SCALAR("item 3.2",plain) -// BLOCK-END -// BLOCK-ENTRY -// BLOCK-MAPPING-START -// KEY -// SCALAR("key 1",plain) -// VALUE -// SCALAR("value 1",plain) -// KEY -// SCALAR("key 2",plain) -// VALUE -// SCALAR("value 2",plain) -// BLOCK-END -// BLOCK-END -// STREAM-END -// -// 2. Block mappings: -// -// a simple key: a value # The KEY token is produced here. -// ? a complex key -// : another value -// a mapping: -// key 1: value 1 -// key 2: value 2 -// a sequence: -// - item 1 -// - item 2 -// -// Tokens: -// -// STREAM-START(utf-8) -// BLOCK-MAPPING-START -// KEY -// SCALAR("a simple key",plain) -// VALUE -// SCALAR("a value",plain) -// KEY -// SCALAR("a complex key",plain) -// VALUE -// SCALAR("another value",plain) -// KEY -// SCALAR("a mapping",plain) -// BLOCK-MAPPING-START -// KEY -// SCALAR("key 1",plain) -// VALUE -// SCALAR("value 1",plain) -// KEY -// SCALAR("key 2",plain) -// VALUE -// SCALAR("value 2",plain) -// BLOCK-END -// KEY -// SCALAR("a sequence",plain) -// VALUE -// BLOCK-SEQUENCE-START -// BLOCK-ENTRY -// SCALAR("item 1",plain) -// BLOCK-ENTRY -// SCALAR("item 2",plain) -// BLOCK-END -// BLOCK-END -// STREAM-END -// -// YAML does not always require to start a new block collection from a new -// line. If the current line contains only '-', '?', and ':' indicators, a new -// block collection may start at the current line. The following examples -// illustrate this case: -// -// 1. Collections in a sequence: -// -// - - item 1 -// - item 2 -// - key 1: value 1 -// key 2: value 2 -// - ? complex key -// : complex value -// -// Tokens: -// -// STREAM-START(utf-8) -// BLOCK-SEQUENCE-START -// BLOCK-ENTRY -// BLOCK-SEQUENCE-START -// BLOCK-ENTRY -// SCALAR("item 1",plain) -// BLOCK-ENTRY -// SCALAR("item 2",plain) -// BLOCK-END -// BLOCK-ENTRY -// BLOCK-MAPPING-START -// KEY -// SCALAR("key 1",plain) -// VALUE -// SCALAR("value 1",plain) -// KEY -// SCALAR("key 2",plain) -// VALUE -// SCALAR("value 2",plain) -// BLOCK-END -// BLOCK-ENTRY -// BLOCK-MAPPING-START -// KEY -// SCALAR("complex key") -// VALUE -// SCALAR("complex value") -// BLOCK-END -// BLOCK-END -// STREAM-END -// -// 2. Collections in a mapping: -// -// ? a sequence -// : - item 1 -// - item 2 -// ? a mapping -// : key 1: value 1 -// key 2: value 2 -// -// Tokens: -// -// STREAM-START(utf-8) -// BLOCK-MAPPING-START -// KEY -// SCALAR("a sequence",plain) -// VALUE -// BLOCK-SEQUENCE-START -// BLOCK-ENTRY -// SCALAR("item 1",plain) -// BLOCK-ENTRY -// SCALAR("item 2",plain) -// BLOCK-END -// KEY -// SCALAR("a mapping",plain) -// VALUE -// BLOCK-MAPPING-START -// KEY -// SCALAR("key 1",plain) -// VALUE -// SCALAR("value 1",plain) -// KEY -// SCALAR("key 2",plain) -// VALUE -// SCALAR("value 2",plain) -// BLOCK-END -// BLOCK-END -// STREAM-END -// -// YAML also permits non-indented sequences if they are included into a block -// mapping. In this case, the token BLOCK-SEQUENCE-START is not produced: -// -// key: -// - item 1 # BLOCK-SEQUENCE-START is NOT produced here. -// - item 2 -// -// Tokens: -// -// STREAM-START(utf-8) -// BLOCK-MAPPING-START -// KEY -// SCALAR("key",plain) -// VALUE -// BLOCK-ENTRY -// SCALAR("item 1",plain) -// BLOCK-ENTRY -// SCALAR("item 2",plain) -// BLOCK-END -// - -// Ensure that the buffer contains the required number of characters. -// Return true on success, false on failure (reader error or memory error). -func cache(parser *yaml_parser_t, length int) bool { - // [Go] This was inlined: !cache(A, B) -> unread < B && !update(A, B) - return parser.unread >= length || yaml_parser_update_buffer(parser, length) -} - -// Advance the buffer pointer. -func skip(parser *yaml_parser_t) { - parser.mark.index++ - parser.mark.column++ - parser.unread-- - parser.buffer_pos += width(parser.buffer[parser.buffer_pos]) -} - -func skip_line(parser *yaml_parser_t) { - if is_crlf(parser.buffer, parser.buffer_pos) { - parser.mark.index += 2 - parser.mark.column = 0 - parser.mark.line++ - parser.unread -= 2 - parser.buffer_pos += 2 - } else if is_break(parser.buffer, parser.buffer_pos) { - parser.mark.index++ - parser.mark.column = 0 - parser.mark.line++ - parser.unread-- - parser.buffer_pos += width(parser.buffer[parser.buffer_pos]) - } -} - -// Copy a character to a string buffer and advance pointers. -func read(parser *yaml_parser_t, s []byte) []byte { - w := width(parser.buffer[parser.buffer_pos]) - if w == 0 { - panic("invalid character sequence") - } - if len(s) == 0 { - s = make([]byte, 0, 32) - } - if w == 1 && len(s)+w <= cap(s) { - s = s[:len(s)+1] - s[len(s)-1] = parser.buffer[parser.buffer_pos] - parser.buffer_pos++ - } else { - s = append(s, parser.buffer[parser.buffer_pos:parser.buffer_pos+w]...) - parser.buffer_pos += w - } - parser.mark.index++ - parser.mark.column++ - parser.unread-- - return s -} - -// Copy a line break character to a string buffer and advance pointers. -func read_line(parser *yaml_parser_t, s []byte) []byte { - buf := parser.buffer - pos := parser.buffer_pos - switch { - case buf[pos] == '\r' && buf[pos+1] == '\n': - // CR LF . LF - s = append(s, '\n') - parser.buffer_pos += 2 - parser.mark.index++ - parser.unread-- - case buf[pos] == '\r' || buf[pos] == '\n': - // CR|LF . LF - s = append(s, '\n') - parser.buffer_pos += 1 - case buf[pos] == '\xC2' && buf[pos+1] == '\x85': - // NEL . LF - s = append(s, '\n') - parser.buffer_pos += 2 - case buf[pos] == '\xE2' && buf[pos+1] == '\x80' && (buf[pos+2] == '\xA8' || buf[pos+2] == '\xA9'): - // LS|PS . LS|PS - s = append(s, buf[parser.buffer_pos:pos+3]...) - parser.buffer_pos += 3 - default: - return s - } - parser.mark.index++ - parser.mark.column = 0 - parser.mark.line++ - parser.unread-- - return s -} - -// Get the next token. -func yaml_parser_scan(parser *yaml_parser_t, token *yaml_token_t) bool { - // Erase the token object. - *token = yaml_token_t{} // [Go] Is this necessary? - - // No tokens after STREAM-END or error. - if parser.stream_end_produced || parser.error != yaml_NO_ERROR { - return true - } - - // Ensure that the tokens queue contains enough tokens. - if !parser.token_available { - if !yaml_parser_fetch_more_tokens(parser) { - return false - } - } - - // Fetch the next token from the queue. - *token = parser.tokens[parser.tokens_head] - parser.tokens_head++ - parser.tokens_parsed++ - parser.token_available = false - - if token.typ == yaml_STREAM_END_TOKEN { - parser.stream_end_produced = true - } - return true -} - -// Set the scanner error and return false. -func yaml_parser_set_scanner_error(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string) bool { - parser.error = yaml_SCANNER_ERROR - parser.context = context - parser.context_mark = context_mark - parser.problem = problem - parser.problem_mark = parser.mark - return false -} - -func yaml_parser_set_scanner_tag_error(parser *yaml_parser_t, directive bool, context_mark yaml_mark_t, problem string) bool { - context := "while parsing a tag" - if directive { - context = "while parsing a %TAG directive" - } - return yaml_parser_set_scanner_error(parser, context, context_mark, problem) -} - -func trace(args ...interface{}) func() { - pargs := append([]interface{}{"+++"}, args...) - fmt.Println(pargs...) - pargs = append([]interface{}{"---"}, args...) - return func() { fmt.Println(pargs...) } -} - -// Ensure that the tokens queue contains at least one token which can be -// returned to the Parser. -func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool { - // While we need more tokens to fetch, do it. - for { - // Check if we really need to fetch more tokens. - need_more_tokens := false - - if parser.tokens_head == len(parser.tokens) { - // Queue is empty. - need_more_tokens = true - } else { - // Check if any potential simple key may occupy the head position. - if !yaml_parser_stale_simple_keys(parser) { - return false - } - - for i := range parser.simple_keys { - simple_key := &parser.simple_keys[i] - if simple_key.possible && simple_key.token_number == parser.tokens_parsed { - need_more_tokens = true - break - } - } - } - - // We are finished. - if !need_more_tokens { - break - } - // Fetch the next token. - if !yaml_parser_fetch_next_token(parser) { - return false - } - } - - parser.token_available = true - return true -} - -// The dispatcher for token fetchers. -func yaml_parser_fetch_next_token(parser *yaml_parser_t) bool { - // Ensure that the buffer is initialized. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - // Check if we just started scanning. Fetch STREAM-START then. - if !parser.stream_start_produced { - return yaml_parser_fetch_stream_start(parser) - } - - // Eat whitespaces and comments until we reach the next token. - if !yaml_parser_scan_to_next_token(parser) { - return false - } - - // Remove obsolete potential simple keys. - if !yaml_parser_stale_simple_keys(parser) { - return false - } - - // Check the indentation level against the current column. - if !yaml_parser_unroll_indent(parser, parser.mark.column) { - return false - } - - // Ensure that the buffer contains at least 4 characters. 4 is the length - // of the longest indicators ('--- ' and '... '). - if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { - return false - } - - // Is it the end of the stream? - if is_z(parser.buffer, parser.buffer_pos) { - return yaml_parser_fetch_stream_end(parser) - } - - // Is it a directive? - if parser.mark.column == 0 && parser.buffer[parser.buffer_pos] == '%' { - return yaml_parser_fetch_directive(parser) - } - - buf := parser.buffer - pos := parser.buffer_pos - - // Is it the document start indicator? - if parser.mark.column == 0 && buf[pos] == '-' && buf[pos+1] == '-' && buf[pos+2] == '-' && is_blankz(buf, pos+3) { - return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_START_TOKEN) - } - - // Is it the document end indicator? - if parser.mark.column == 0 && buf[pos] == '.' && buf[pos+1] == '.' && buf[pos+2] == '.' && is_blankz(buf, pos+3) { - return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_END_TOKEN) - } - - // Is it the flow sequence start indicator? - if buf[pos] == '[' { - return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_SEQUENCE_START_TOKEN) - } - - // Is it the flow mapping start indicator? - if parser.buffer[parser.buffer_pos] == '{' { - return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_MAPPING_START_TOKEN) - } - - // Is it the flow sequence end indicator? - if parser.buffer[parser.buffer_pos] == ']' { - return yaml_parser_fetch_flow_collection_end(parser, - yaml_FLOW_SEQUENCE_END_TOKEN) - } - - // Is it the flow mapping end indicator? - if parser.buffer[parser.buffer_pos] == '}' { - return yaml_parser_fetch_flow_collection_end(parser, - yaml_FLOW_MAPPING_END_TOKEN) - } - - // Is it the flow entry indicator? - if parser.buffer[parser.buffer_pos] == ',' { - return yaml_parser_fetch_flow_entry(parser) - } - - // Is it the block entry indicator? - if parser.buffer[parser.buffer_pos] == '-' && is_blankz(parser.buffer, parser.buffer_pos+1) { - return yaml_parser_fetch_block_entry(parser) - } - - // Is it the key indicator? - if parser.buffer[parser.buffer_pos] == '?' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) { - return yaml_parser_fetch_key(parser) - } - - // Is it the value indicator? - if parser.buffer[parser.buffer_pos] == ':' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) { - return yaml_parser_fetch_value(parser) - } - - // Is it an alias? - if parser.buffer[parser.buffer_pos] == '*' { - return yaml_parser_fetch_anchor(parser, yaml_ALIAS_TOKEN) - } - - // Is it an anchor? - if parser.buffer[parser.buffer_pos] == '&' { - return yaml_parser_fetch_anchor(parser, yaml_ANCHOR_TOKEN) - } - - // Is it a tag? - if parser.buffer[parser.buffer_pos] == '!' { - return yaml_parser_fetch_tag(parser) - } - - // Is it a literal scalar? - if parser.buffer[parser.buffer_pos] == '|' && parser.flow_level == 0 { - return yaml_parser_fetch_block_scalar(parser, true) - } - - // Is it a folded scalar? - if parser.buffer[parser.buffer_pos] == '>' && parser.flow_level == 0 { - return yaml_parser_fetch_block_scalar(parser, false) - } - - // Is it a single-quoted scalar? - if parser.buffer[parser.buffer_pos] == '\'' { - return yaml_parser_fetch_flow_scalar(parser, true) - } - - // Is it a double-quoted scalar? - if parser.buffer[parser.buffer_pos] == '"' { - return yaml_parser_fetch_flow_scalar(parser, false) - } - - // Is it a plain scalar? - // - // A plain scalar may start with any non-blank characters except - // - // '-', '?', ':', ',', '[', ']', '{', '}', - // '#', '&', '*', '!', '|', '>', '\'', '\"', - // '%', '@', '`'. - // - // In the block context (and, for the '-' indicator, in the flow context - // too), it may also start with the characters - // - // '-', '?', ':' - // - // if it is followed by a non-space character. - // - // The last rule is more restrictive than the specification requires. - // [Go] Make this logic more reasonable. - //switch parser.buffer[parser.buffer_pos] { - //case '-', '?', ':', ',', '?', '-', ',', ':', ']', '[', '}', '{', '&', '#', '!', '*', '>', '|', '"', '\'', '@', '%', '-', '`': - //} - if !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '-' || - parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':' || - parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '[' || - parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' || - parser.buffer[parser.buffer_pos] == '}' || parser.buffer[parser.buffer_pos] == '#' || - parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '*' || - parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '|' || - parser.buffer[parser.buffer_pos] == '>' || parser.buffer[parser.buffer_pos] == '\'' || - parser.buffer[parser.buffer_pos] == '"' || parser.buffer[parser.buffer_pos] == '%' || - parser.buffer[parser.buffer_pos] == '@' || parser.buffer[parser.buffer_pos] == '`') || - (parser.buffer[parser.buffer_pos] == '-' && !is_blank(parser.buffer, parser.buffer_pos+1)) || - (parser.flow_level == 0 && - (parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':') && - !is_blankz(parser.buffer, parser.buffer_pos+1)) { - return yaml_parser_fetch_plain_scalar(parser) - } - - // If we don't determine the token type so far, it is an error. - return yaml_parser_set_scanner_error(parser, - "while scanning for the next token", parser.mark, - "found character that cannot start any token") -} - -// Check the list of potential simple keys and remove the positions that -// cannot contain simple keys anymore. -func yaml_parser_stale_simple_keys(parser *yaml_parser_t) bool { - // Check for a potential simple key for each flow level. - for i := range parser.simple_keys { - simple_key := &parser.simple_keys[i] - - // The specification requires that a simple key - // - // - is limited to a single line, - // - is shorter than 1024 characters. - if simple_key.possible && (simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index) { - - // Check if the potential simple key to be removed is required. - if simple_key.required { - return yaml_parser_set_scanner_error(parser, - "while scanning a simple key", simple_key.mark, - "could not find expected ':'") - } - simple_key.possible = false - } - } - return true -} - -// Check if a simple key may start at the current position and add it if -// needed. -func yaml_parser_save_simple_key(parser *yaml_parser_t) bool { - // A simple key is required at the current position if the scanner is in - // the block context and the current column coincides with the indentation - // level. - - required := parser.flow_level == 0 && parser.indent == parser.mark.column - - // A simple key is required only when it is the first token in the current - // line. Therefore it is always allowed. But we add a check anyway. - if required && !parser.simple_key_allowed { - panic("should not happen") - } - - // - // If the current position may start a simple key, save it. - // - if parser.simple_key_allowed { - simple_key := yaml_simple_key_t{ - possible: true, - required: required, - token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head), - } - simple_key.mark = parser.mark - - if !yaml_parser_remove_simple_key(parser) { - return false - } - parser.simple_keys[len(parser.simple_keys)-1] = simple_key - } - return true -} - -// Remove a potential simple key at the current flow level. -func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool { - i := len(parser.simple_keys) - 1 - if parser.simple_keys[i].possible { - // If the key is required, it is an error. - if parser.simple_keys[i].required { - return yaml_parser_set_scanner_error(parser, - "while scanning a simple key", parser.simple_keys[i].mark, - "could not find expected ':'") - } - } - // Remove the key from the stack. - parser.simple_keys[i].possible = false - return true -} - -// Increase the flow level and resize the simple key list if needed. -func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool { - // Reset the simple key on the next level. - parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{}) - - // Increase the flow level. - parser.flow_level++ - return true -} - -// Decrease the flow level. -func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool { - if parser.flow_level > 0 { - parser.flow_level-- - parser.simple_keys = parser.simple_keys[:len(parser.simple_keys)-1] - } - return true -} - -// Push the current indentation level to the stack and set the new level -// the current column is greater than the indentation level. In this case, -// append or insert the specified token into the token queue. -func yaml_parser_roll_indent(parser *yaml_parser_t, column, number int, typ yaml_token_type_t, mark yaml_mark_t) bool { - // In the flow context, do nothing. - if parser.flow_level > 0 { - return true - } - - if parser.indent < column { - // Push the current indentation level to the stack and set the new - // indentation level. - parser.indents = append(parser.indents, parser.indent) - parser.indent = column - - // Create a token and insert it into the queue. - token := yaml_token_t{ - typ: typ, - start_mark: mark, - end_mark: mark, - } - if number > -1 { - number -= parser.tokens_parsed - } - yaml_insert_token(parser, number, &token) - } - return true -} - -// Pop indentation levels from the indents stack until the current level -// becomes less or equal to the column. For each indentation level, append -// the BLOCK-END token. -func yaml_parser_unroll_indent(parser *yaml_parser_t, column int) bool { - // In the flow context, do nothing. - if parser.flow_level > 0 { - return true - } - - // Loop through the indentation levels in the stack. - for parser.indent > column { - // Create a token and append it to the queue. - token := yaml_token_t{ - typ: yaml_BLOCK_END_TOKEN, - start_mark: parser.mark, - end_mark: parser.mark, - } - yaml_insert_token(parser, -1, &token) - - // Pop the indentation level. - parser.indent = parser.indents[len(parser.indents)-1] - parser.indents = parser.indents[:len(parser.indents)-1] - } - return true -} - -// Initialize the scanner and produce the STREAM-START token. -func yaml_parser_fetch_stream_start(parser *yaml_parser_t) bool { - - // Set the initial indentation. - parser.indent = -1 - - // Initialize the simple key stack. - parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{}) - - // A simple key is allowed at the beginning of the stream. - parser.simple_key_allowed = true - - // We have started. - parser.stream_start_produced = true - - // Create the STREAM-START token and append it to the queue. - token := yaml_token_t{ - typ: yaml_STREAM_START_TOKEN, - start_mark: parser.mark, - end_mark: parser.mark, - encoding: parser.encoding, - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the STREAM-END token and shut down the scanner. -func yaml_parser_fetch_stream_end(parser *yaml_parser_t) bool { - - // Force new line. - if parser.mark.column != 0 { - parser.mark.column = 0 - parser.mark.line++ - } - - // Reset the indentation level. - if !yaml_parser_unroll_indent(parser, -1) { - return false - } - - // Reset simple keys. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - parser.simple_key_allowed = false - - // Create the STREAM-END token and append it to the queue. - token := yaml_token_t{ - typ: yaml_STREAM_END_TOKEN, - start_mark: parser.mark, - end_mark: parser.mark, - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token. -func yaml_parser_fetch_directive(parser *yaml_parser_t) bool { - // Reset the indentation level. - if !yaml_parser_unroll_indent(parser, -1) { - return false - } - - // Reset simple keys. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - parser.simple_key_allowed = false - - // Create the YAML-DIRECTIVE or TAG-DIRECTIVE token. - token := yaml_token_t{} - if !yaml_parser_scan_directive(parser, &token) { - return false - } - // Append the token to the queue. - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the DOCUMENT-START or DOCUMENT-END token. -func yaml_parser_fetch_document_indicator(parser *yaml_parser_t, typ yaml_token_type_t) bool { - // Reset the indentation level. - if !yaml_parser_unroll_indent(parser, -1) { - return false - } - - // Reset simple keys. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - parser.simple_key_allowed = false - - // Consume the token. - start_mark := parser.mark - - skip(parser) - skip(parser) - skip(parser) - - end_mark := parser.mark - - // Create the DOCUMENT-START or DOCUMENT-END token. - token := yaml_token_t{ - typ: typ, - start_mark: start_mark, - end_mark: end_mark, - } - // Append the token to the queue. - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token. -func yaml_parser_fetch_flow_collection_start(parser *yaml_parser_t, typ yaml_token_type_t) bool { - // The indicators '[' and '{' may start a simple key. - if !yaml_parser_save_simple_key(parser) { - return false - } - - // Increase the flow level. - if !yaml_parser_increase_flow_level(parser) { - return false - } - - // A simple key may follow the indicators '[' and '{'. - parser.simple_key_allowed = true - - // Consume the token. - start_mark := parser.mark - skip(parser) - end_mark := parser.mark - - // Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token. - token := yaml_token_t{ - typ: typ, - start_mark: start_mark, - end_mark: end_mark, - } - // Append the token to the queue. - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token. -func yaml_parser_fetch_flow_collection_end(parser *yaml_parser_t, typ yaml_token_type_t) bool { - // Reset any potential simple key on the current flow level. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - // Decrease the flow level. - if !yaml_parser_decrease_flow_level(parser) { - return false - } - - // No simple keys after the indicators ']' and '}'. - parser.simple_key_allowed = false - - // Consume the token. - - start_mark := parser.mark - skip(parser) - end_mark := parser.mark - - // Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token. - token := yaml_token_t{ - typ: typ, - start_mark: start_mark, - end_mark: end_mark, - } - // Append the token to the queue. - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the FLOW-ENTRY token. -func yaml_parser_fetch_flow_entry(parser *yaml_parser_t) bool { - // Reset any potential simple keys on the current flow level. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - // Simple keys are allowed after ','. - parser.simple_key_allowed = true - - // Consume the token. - start_mark := parser.mark - skip(parser) - end_mark := parser.mark - - // Create the FLOW-ENTRY token and append it to the queue. - token := yaml_token_t{ - typ: yaml_FLOW_ENTRY_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the BLOCK-ENTRY token. -func yaml_parser_fetch_block_entry(parser *yaml_parser_t) bool { - // Check if the scanner is in the block context. - if parser.flow_level == 0 { - // Check if we are allowed to start a new entry. - if !parser.simple_key_allowed { - return yaml_parser_set_scanner_error(parser, "", parser.mark, - "block sequence entries are not allowed in this context") - } - // Add the BLOCK-SEQUENCE-START token if needed. - if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_SEQUENCE_START_TOKEN, parser.mark) { - return false - } - } else { - // It is an error for the '-' indicator to occur in the flow context, - // but we let the Parser detect and report about it because the Parser - // is able to point to the context. - } - - // Reset any potential simple keys on the current flow level. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - // Simple keys are allowed after '-'. - parser.simple_key_allowed = true - - // Consume the token. - start_mark := parser.mark - skip(parser) - end_mark := parser.mark - - // Create the BLOCK-ENTRY token and append it to the queue. - token := yaml_token_t{ - typ: yaml_BLOCK_ENTRY_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the KEY token. -func yaml_parser_fetch_key(parser *yaml_parser_t) bool { - - // In the block context, additional checks are required. - if parser.flow_level == 0 { - // Check if we are allowed to start a new key (not nessesary simple). - if !parser.simple_key_allowed { - return yaml_parser_set_scanner_error(parser, "", parser.mark, - "mapping keys are not allowed in this context") - } - // Add the BLOCK-MAPPING-START token if needed. - if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) { - return false - } - } - - // Reset any potential simple keys on the current flow level. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - // Simple keys are allowed after '?' in the block context. - parser.simple_key_allowed = parser.flow_level == 0 - - // Consume the token. - start_mark := parser.mark - skip(parser) - end_mark := parser.mark - - // Create the KEY token and append it to the queue. - token := yaml_token_t{ - typ: yaml_KEY_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the VALUE token. -func yaml_parser_fetch_value(parser *yaml_parser_t) bool { - - simple_key := &parser.simple_keys[len(parser.simple_keys)-1] - - // Have we found a simple key? - if simple_key.possible { - // Create the KEY token and insert it into the queue. - token := yaml_token_t{ - typ: yaml_KEY_TOKEN, - start_mark: simple_key.mark, - end_mark: simple_key.mark, - } - yaml_insert_token(parser, simple_key.token_number-parser.tokens_parsed, &token) - - // In the block context, we may need to add the BLOCK-MAPPING-START token. - if !yaml_parser_roll_indent(parser, simple_key.mark.column, - simple_key.token_number, - yaml_BLOCK_MAPPING_START_TOKEN, simple_key.mark) { - return false - } - - // Remove the simple key. - simple_key.possible = false - - // A simple key cannot follow another simple key. - parser.simple_key_allowed = false - - } else { - // The ':' indicator follows a complex key. - - // In the block context, extra checks are required. - if parser.flow_level == 0 { - - // Check if we are allowed to start a complex value. - if !parser.simple_key_allowed { - return yaml_parser_set_scanner_error(parser, "", parser.mark, - "mapping values are not allowed in this context") - } - - // Add the BLOCK-MAPPING-START token if needed. - if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) { - return false - } - } - - // Simple keys after ':' are allowed in the block context. - parser.simple_key_allowed = parser.flow_level == 0 - } - - // Consume the token. - start_mark := parser.mark - skip(parser) - end_mark := parser.mark - - // Create the VALUE token and append it to the queue. - token := yaml_token_t{ - typ: yaml_VALUE_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the ALIAS or ANCHOR token. -func yaml_parser_fetch_anchor(parser *yaml_parser_t, typ yaml_token_type_t) bool { - // An anchor or an alias could be a simple key. - if !yaml_parser_save_simple_key(parser) { - return false - } - - // A simple key cannot follow an anchor or an alias. - parser.simple_key_allowed = false - - // Create the ALIAS or ANCHOR token and append it to the queue. - var token yaml_token_t - if !yaml_parser_scan_anchor(parser, &token, typ) { - return false - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the TAG token. -func yaml_parser_fetch_tag(parser *yaml_parser_t) bool { - // A tag could be a simple key. - if !yaml_parser_save_simple_key(parser) { - return false - } - - // A simple key cannot follow a tag. - parser.simple_key_allowed = false - - // Create the TAG token and append it to the queue. - var token yaml_token_t - if !yaml_parser_scan_tag(parser, &token) { - return false - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens. -func yaml_parser_fetch_block_scalar(parser *yaml_parser_t, literal bool) bool { - // Remove any potential simple keys. - if !yaml_parser_remove_simple_key(parser) { - return false - } - - // A simple key may follow a block scalar. - parser.simple_key_allowed = true - - // Create the SCALAR token and append it to the queue. - var token yaml_token_t - if !yaml_parser_scan_block_scalar(parser, &token, literal) { - return false - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens. -func yaml_parser_fetch_flow_scalar(parser *yaml_parser_t, single bool) bool { - // A plain scalar could be a simple key. - if !yaml_parser_save_simple_key(parser) { - return false - } - - // A simple key cannot follow a flow scalar. - parser.simple_key_allowed = false - - // Create the SCALAR token and append it to the queue. - var token yaml_token_t - if !yaml_parser_scan_flow_scalar(parser, &token, single) { - return false - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Produce the SCALAR(...,plain) token. -func yaml_parser_fetch_plain_scalar(parser *yaml_parser_t) bool { - // A plain scalar could be a simple key. - if !yaml_parser_save_simple_key(parser) { - return false - } - - // A simple key cannot follow a flow scalar. - parser.simple_key_allowed = false - - // Create the SCALAR token and append it to the queue. - var token yaml_token_t - if !yaml_parser_scan_plain_scalar(parser, &token) { - return false - } - yaml_insert_token(parser, -1, &token) - return true -} - -// Eat whitespaces and comments until the next token is found. -func yaml_parser_scan_to_next_token(parser *yaml_parser_t) bool { - - // Until the next token is not found. - for { - // Allow the BOM mark to start a line. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if parser.mark.column == 0 && is_bom(parser.buffer, parser.buffer_pos) { - skip(parser) - } - - // Eat whitespaces. - // Tabs are allowed: - // - in the flow context - // - in the block context, but not at the beginning of the line or - // after '-', '?', or ':' (complex value). - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - for parser.buffer[parser.buffer_pos] == ' ' || ((parser.flow_level > 0 || !parser.simple_key_allowed) && parser.buffer[parser.buffer_pos] == '\t') { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Eat a comment until a line break. - if parser.buffer[parser.buffer_pos] == '#' { - for !is_breakz(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - } - - // If it is a line break, eat it. - if is_break(parser.buffer, parser.buffer_pos) { - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - skip_line(parser) - - // In the block context, a new line may start a simple key. - if parser.flow_level == 0 { - parser.simple_key_allowed = true - } - } else { - break // We have found a token. - } - } - - return true -} - -// Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token. -// -// Scope: -// %YAML 1.1 # a comment \n -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -// %TAG !yaml! tag:yaml.org,2002: \n -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -// -func yaml_parser_scan_directive(parser *yaml_parser_t, token *yaml_token_t) bool { - // Eat '%'. - start_mark := parser.mark - skip(parser) - - // Scan the directive name. - var name []byte - if !yaml_parser_scan_directive_name(parser, start_mark, &name) { - return false - } - - // Is it a YAML directive? - if bytes.Equal(name, []byte("YAML")) { - // Scan the VERSION directive value. - var major, minor int8 - if !yaml_parser_scan_version_directive_value(parser, start_mark, &major, &minor) { - return false - } - end_mark := parser.mark - - // Create a VERSION-DIRECTIVE token. - *token = yaml_token_t{ - typ: yaml_VERSION_DIRECTIVE_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - major: major, - minor: minor, - } - - // Is it a TAG directive? - } else if bytes.Equal(name, []byte("TAG")) { - // Scan the TAG directive value. - var handle, prefix []byte - if !yaml_parser_scan_tag_directive_value(parser, start_mark, &handle, &prefix) { - return false - } - end_mark := parser.mark - - // Create a TAG-DIRECTIVE token. - *token = yaml_token_t{ - typ: yaml_TAG_DIRECTIVE_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - value: handle, - prefix: prefix, - } - - // Unknown directive. - } else { - yaml_parser_set_scanner_error(parser, "while scanning a directive", - start_mark, "found unknown directive name") - return false - } - - // Eat the rest of the line including any comments. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - for is_blank(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - if parser.buffer[parser.buffer_pos] == '#' { - for !is_breakz(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - } - - // Check if we are at the end of the line. - if !is_breakz(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a directive", - start_mark, "did not find expected comment or line break") - return false - } - - // Eat a line break. - if is_break(parser.buffer, parser.buffer_pos) { - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - skip_line(parser) - } - - return true -} - -// Scan the directive name. -// -// Scope: -// %YAML 1.1 # a comment \n -// ^^^^ -// %TAG !yaml! tag:yaml.org,2002: \n -// ^^^ -// -func yaml_parser_scan_directive_name(parser *yaml_parser_t, start_mark yaml_mark_t, name *[]byte) bool { - // Consume the directive name. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - var s []byte - for is_alpha(parser.buffer, parser.buffer_pos) { - s = read(parser, s) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Check if the name is empty. - if len(s) == 0 { - yaml_parser_set_scanner_error(parser, "while scanning a directive", - start_mark, "could not find expected directive name") - return false - } - - // Check for an blank character after the name. - if !is_blankz(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a directive", - start_mark, "found unexpected non-alphabetical character") - return false - } - *name = s - return true -} - -// Scan the value of VERSION-DIRECTIVE. -// -// Scope: -// %YAML 1.1 # a comment \n -// ^^^^^^ -func yaml_parser_scan_version_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, major, minor *int8) bool { - // Eat whitespaces. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - for is_blank(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Consume the major version number. - if !yaml_parser_scan_version_directive_number(parser, start_mark, major) { - return false - } - - // Eat '.'. - if parser.buffer[parser.buffer_pos] != '.' { - return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", - start_mark, "did not find expected digit or '.' character") - } - - skip(parser) - - // Consume the minor version number. - if !yaml_parser_scan_version_directive_number(parser, start_mark, minor) { - return false - } - return true -} - -const max_number_length = 2 - -// Scan the version number of VERSION-DIRECTIVE. -// -// Scope: -// %YAML 1.1 # a comment \n -// ^ -// %YAML 1.1 # a comment \n -// ^ -func yaml_parser_scan_version_directive_number(parser *yaml_parser_t, start_mark yaml_mark_t, number *int8) bool { - - // Repeat while the next character is digit. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - var value, length int8 - for is_digit(parser.buffer, parser.buffer_pos) { - // Check if the number is too long. - length++ - if length > max_number_length { - return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", - start_mark, "found extremely long version number") - } - value = value*10 + int8(as_digit(parser.buffer, parser.buffer_pos)) - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Check if the number was present. - if length == 0 { - return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", - start_mark, "did not find expected version number") - } - *number = value - return true -} - -// Scan the value of a TAG-DIRECTIVE token. -// -// Scope: -// %TAG !yaml! tag:yaml.org,2002: \n -// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -// -func yaml_parser_scan_tag_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, handle, prefix *[]byte) bool { - var handle_value, prefix_value []byte - - // Eat whitespaces. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - for is_blank(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Scan a handle. - if !yaml_parser_scan_tag_handle(parser, true, start_mark, &handle_value) { - return false - } - - // Expect a whitespace. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if !is_blank(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", - start_mark, "did not find expected whitespace") - return false - } - - // Eat whitespaces. - for is_blank(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Scan a prefix. - if !yaml_parser_scan_tag_uri(parser, true, nil, start_mark, &prefix_value) { - return false - } - - // Expect a whitespace or line break. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if !is_blankz(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", - start_mark, "did not find expected whitespace or line break") - return false - } - - *handle = handle_value - *prefix = prefix_value - return true -} - -func yaml_parser_scan_anchor(parser *yaml_parser_t, token *yaml_token_t, typ yaml_token_type_t) bool { - var s []byte - - // Eat the indicator character. - start_mark := parser.mark - skip(parser) - - // Consume the value. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - for is_alpha(parser.buffer, parser.buffer_pos) { - s = read(parser, s) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - end_mark := parser.mark - - /* - * Check if length of the anchor is greater than 0 and it is followed by - * a whitespace character or one of the indicators: - * - * '?', ':', ',', ']', '}', '%', '@', '`'. - */ - - if len(s) == 0 || - !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '?' || - parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == ',' || - parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '}' || - parser.buffer[parser.buffer_pos] == '%' || parser.buffer[parser.buffer_pos] == '@' || - parser.buffer[parser.buffer_pos] == '`') { - context := "while scanning an alias" - if typ == yaml_ANCHOR_TOKEN { - context = "while scanning an anchor" - } - yaml_parser_set_scanner_error(parser, context, start_mark, - "did not find expected alphabetic or numeric character") - return false - } - - // Create a token. - *token = yaml_token_t{ - typ: typ, - start_mark: start_mark, - end_mark: end_mark, - value: s, - } - - return true -} - -/* - * Scan a TAG token. - */ - -func yaml_parser_scan_tag(parser *yaml_parser_t, token *yaml_token_t) bool { - var handle, suffix []byte - - start_mark := parser.mark - - // Check if the tag is in the canonical form. - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - - if parser.buffer[parser.buffer_pos+1] == '<' { - // Keep the handle as '' - - // Eat '!<' - skip(parser) - skip(parser) - - // Consume the tag value. - if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) { - return false - } - - // Check for '>' and eat it. - if parser.buffer[parser.buffer_pos] != '>' { - yaml_parser_set_scanner_error(parser, "while scanning a tag", - start_mark, "did not find the expected '>'") - return false - } - - skip(parser) - } else { - // The tag has either the '!suffix' or the '!handle!suffix' form. - - // First, try to scan a handle. - if !yaml_parser_scan_tag_handle(parser, false, start_mark, &handle) { - return false - } - - // Check if it is, indeed, handle. - if handle[0] == '!' && len(handle) > 1 && handle[len(handle)-1] == '!' { - // Scan the suffix now. - if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) { - return false - } - } else { - // It wasn't a handle after all. Scan the rest of the tag. - if !yaml_parser_scan_tag_uri(parser, false, handle, start_mark, &suffix) { - return false - } - - // Set the handle to '!'. - handle = []byte{'!'} - - // A special case: the '!' tag. Set the handle to '' and the - // suffix to '!'. - if len(suffix) == 0 { - handle, suffix = suffix, handle - } - } - } - - // Check the character which ends the tag. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if !is_blankz(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a tag", - start_mark, "did not find expected whitespace or line break") - return false - } - - end_mark := parser.mark - - // Create a token. - *token = yaml_token_t{ - typ: yaml_TAG_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - value: handle, - suffix: suffix, - } - return true -} - -// Scan a tag handle. -func yaml_parser_scan_tag_handle(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, handle *[]byte) bool { - // Check the initial '!' character. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if parser.buffer[parser.buffer_pos] != '!' { - yaml_parser_set_scanner_tag_error(parser, directive, - start_mark, "did not find expected '!'") - return false - } - - var s []byte - - // Copy the '!' character. - s = read(parser, s) - - // Copy all subsequent alphabetical and numerical characters. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - for is_alpha(parser.buffer, parser.buffer_pos) { - s = read(parser, s) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Check if the trailing character is '!' and copy it. - if parser.buffer[parser.buffer_pos] == '!' { - s = read(parser, s) - } else { - // It's either the '!' tag or not really a tag handle. If it's a %TAG - // directive, it's an error. If it's a tag token, it must be a part of URI. - if directive && string(s) != "!" { - yaml_parser_set_scanner_tag_error(parser, directive, - start_mark, "did not find expected '!'") - return false - } - } - - *handle = s - return true -} - -// Scan a tag. -func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte, start_mark yaml_mark_t, uri *[]byte) bool { - //size_t length = head ? strlen((char *)head) : 0 - var s []byte - hasTag := len(head) > 0 - - // Copy the head if needed. - // - // Note that we don't copy the leading '!' character. - if len(head) > 1 { - s = append(s, head[1:]...) - } - - // Scan the tag. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - // The set of characters that may appear in URI is as follows: - // - // '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&', - // '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']', - // '%'. - // [Go] Convert this into more reasonable logic. - for is_alpha(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == ';' || - parser.buffer[parser.buffer_pos] == '/' || parser.buffer[parser.buffer_pos] == '?' || - parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == '@' || - parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '=' || - parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '$' || - parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '.' || - parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '~' || - parser.buffer[parser.buffer_pos] == '*' || parser.buffer[parser.buffer_pos] == '\'' || - parser.buffer[parser.buffer_pos] == '(' || parser.buffer[parser.buffer_pos] == ')' || - parser.buffer[parser.buffer_pos] == '[' || parser.buffer[parser.buffer_pos] == ']' || - parser.buffer[parser.buffer_pos] == '%' { - // Check if it is a URI-escape sequence. - if parser.buffer[parser.buffer_pos] == '%' { - if !yaml_parser_scan_uri_escapes(parser, directive, start_mark, &s) { - return false - } - } else { - s = read(parser, s) - } - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - hasTag = true - } - - if !hasTag { - yaml_parser_set_scanner_tag_error(parser, directive, - start_mark, "did not find expected tag URI") - return false - } - *uri = s - return true -} - -// Decode an URI-escape sequence corresponding to a single UTF-8 character. -func yaml_parser_scan_uri_escapes(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, s *[]byte) bool { - - // Decode the required number of characters. - w := 1024 - for w > 0 { - // Check for a URI-escaped octet. - if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) { - return false - } - - if !(parser.buffer[parser.buffer_pos] == '%' && - is_hex(parser.buffer, parser.buffer_pos+1) && - is_hex(parser.buffer, parser.buffer_pos+2)) { - return yaml_parser_set_scanner_tag_error(parser, directive, - start_mark, "did not find URI escaped octet") - } - - // Get the octet. - octet := byte((as_hex(parser.buffer, parser.buffer_pos+1) << 4) + as_hex(parser.buffer, parser.buffer_pos+2)) - - // If it is the leading octet, determine the length of the UTF-8 sequence. - if w == 1024 { - w = width(octet) - if w == 0 { - return yaml_parser_set_scanner_tag_error(parser, directive, - start_mark, "found an incorrect leading UTF-8 octet") - } - } else { - // Check if the trailing octet is correct. - if octet&0xC0 != 0x80 { - return yaml_parser_set_scanner_tag_error(parser, directive, - start_mark, "found an incorrect trailing UTF-8 octet") - } - } - - // Copy the octet and move the pointers. - *s = append(*s, octet) - skip(parser) - skip(parser) - skip(parser) - w-- - } - return true -} - -// Scan a block scalar. -func yaml_parser_scan_block_scalar(parser *yaml_parser_t, token *yaml_token_t, literal bool) bool { - // Eat the indicator '|' or '>'. - start_mark := parser.mark - skip(parser) - - // Scan the additional block scalar indicators. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - // Check for a chomping indicator. - var chomping, increment int - if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' { - // Set the chomping method and eat the indicator. - if parser.buffer[parser.buffer_pos] == '+' { - chomping = +1 - } else { - chomping = -1 - } - skip(parser) - - // Check for an indentation indicator. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if is_digit(parser.buffer, parser.buffer_pos) { - // Check that the indentation is greater than 0. - if parser.buffer[parser.buffer_pos] == '0' { - yaml_parser_set_scanner_error(parser, "while scanning a block scalar", - start_mark, "found an indentation indicator equal to 0") - return false - } - - // Get the indentation level and eat the indicator. - increment = as_digit(parser.buffer, parser.buffer_pos) - skip(parser) - } - - } else if is_digit(parser.buffer, parser.buffer_pos) { - // Do the same as above, but in the opposite order. - - if parser.buffer[parser.buffer_pos] == '0' { - yaml_parser_set_scanner_error(parser, "while scanning a block scalar", - start_mark, "found an indentation indicator equal to 0") - return false - } - increment = as_digit(parser.buffer, parser.buffer_pos) - skip(parser) - - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' { - if parser.buffer[parser.buffer_pos] == '+' { - chomping = +1 - } else { - chomping = -1 - } - skip(parser) - } - } - - // Eat whitespaces and comments to the end of the line. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - for is_blank(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - if parser.buffer[parser.buffer_pos] == '#' { - for !is_breakz(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - } - - // Check if we are at the end of the line. - if !is_breakz(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a block scalar", - start_mark, "did not find expected comment or line break") - return false - } - - // Eat a line break. - if is_break(parser.buffer, parser.buffer_pos) { - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - skip_line(parser) - } - - end_mark := parser.mark - - // Set the indentation level if it was specified. - var indent int - if increment > 0 { - if parser.indent >= 0 { - indent = parser.indent + increment - } else { - indent = increment - } - } - - // Scan the leading line breaks and determine the indentation level if needed. - var s, leading_break, trailing_breaks []byte - if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) { - return false - } - - // Scan the block scalar content. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - var leading_blank, trailing_blank bool - for parser.mark.column == indent && !is_z(parser.buffer, parser.buffer_pos) { - // We are at the beginning of a non-empty line. - - // Is it a trailing whitespace? - trailing_blank = is_blank(parser.buffer, parser.buffer_pos) - - // Check if we need to fold the leading line break. - if !literal && !leading_blank && !trailing_blank && len(leading_break) > 0 && leading_break[0] == '\n' { - // Do we need to join the lines by space? - if len(trailing_breaks) == 0 { - s = append(s, ' ') - } - } else { - s = append(s, leading_break...) - } - leading_break = leading_break[:0] - - // Append the remaining line breaks. - s = append(s, trailing_breaks...) - trailing_breaks = trailing_breaks[:0] - - // Is it a leading whitespace? - leading_blank = is_blank(parser.buffer, parser.buffer_pos) - - // Consume the current line. - for !is_breakz(parser.buffer, parser.buffer_pos) { - s = read(parser, s) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Consume the line break. - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - - leading_break = read_line(parser, leading_break) - - // Eat the following indentation spaces and line breaks. - if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) { - return false - } - } - - // Chomp the tail. - if chomping != -1 { - s = append(s, leading_break...) - } - if chomping == 1 { - s = append(s, trailing_breaks...) - } - - // Create a token. - *token = yaml_token_t{ - typ: yaml_SCALAR_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - value: s, - style: yaml_LITERAL_SCALAR_STYLE, - } - if !literal { - token.style = yaml_FOLDED_SCALAR_STYLE - } - return true -} - -// Scan indentation spaces and line breaks for a block scalar. Determine the -// indentation level if needed. -func yaml_parser_scan_block_scalar_breaks(parser *yaml_parser_t, indent *int, breaks *[]byte, start_mark yaml_mark_t, end_mark *yaml_mark_t) bool { - *end_mark = parser.mark - - // Eat the indentation spaces and line breaks. - max_indent := 0 - for { - // Eat the indentation spaces. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - for (*indent == 0 || parser.mark.column < *indent) && is_space(parser.buffer, parser.buffer_pos) { - skip(parser) - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - if parser.mark.column > max_indent { - max_indent = parser.mark.column - } - - // Check for a tab character messing the indentation. - if (*indent == 0 || parser.mark.column < *indent) && is_tab(parser.buffer, parser.buffer_pos) { - return yaml_parser_set_scanner_error(parser, "while scanning a block scalar", - start_mark, "found a tab character where an indentation space is expected") - } - - // Have we found a non-empty line? - if !is_break(parser.buffer, parser.buffer_pos) { - break - } - - // Consume the line break. - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - // [Go] Should really be returning breaks instead. - *breaks = read_line(parser, *breaks) - *end_mark = parser.mark - } - - // Determine the indentation level if needed. - if *indent == 0 { - *indent = max_indent - if *indent < parser.indent+1 { - *indent = parser.indent + 1 - } - if *indent < 1 { - *indent = 1 - } - } - return true -} - -// Scan a quoted scalar. -func yaml_parser_scan_flow_scalar(parser *yaml_parser_t, token *yaml_token_t, single bool) bool { - // Eat the left quote. - start_mark := parser.mark - skip(parser) - - // Consume the content of the quoted scalar. - var s, leading_break, trailing_breaks, whitespaces []byte - for { - // Check that there are no document indicators at the beginning of the line. - if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { - return false - } - - if parser.mark.column == 0 && - ((parser.buffer[parser.buffer_pos+0] == '-' && - parser.buffer[parser.buffer_pos+1] == '-' && - parser.buffer[parser.buffer_pos+2] == '-') || - (parser.buffer[parser.buffer_pos+0] == '.' && - parser.buffer[parser.buffer_pos+1] == '.' && - parser.buffer[parser.buffer_pos+2] == '.')) && - is_blankz(parser.buffer, parser.buffer_pos+3) { - yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", - start_mark, "found unexpected document indicator") - return false - } - - // Check for EOF. - if is_z(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", - start_mark, "found unexpected end of stream") - return false - } - - // Consume non-blank characters. - leading_blanks := false - for !is_blankz(parser.buffer, parser.buffer_pos) { - if single && parser.buffer[parser.buffer_pos] == '\'' && parser.buffer[parser.buffer_pos+1] == '\'' { - // Is is an escaped single quote. - s = append(s, '\'') - skip(parser) - skip(parser) - - } else if single && parser.buffer[parser.buffer_pos] == '\'' { - // It is a right single quote. - break - } else if !single && parser.buffer[parser.buffer_pos] == '"' { - // It is a right double quote. - break - - } else if !single && parser.buffer[parser.buffer_pos] == '\\' && is_break(parser.buffer, parser.buffer_pos+1) { - // It is an escaped line break. - if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) { - return false - } - skip(parser) - skip_line(parser) - leading_blanks = true - break - - } else if !single && parser.buffer[parser.buffer_pos] == '\\' { - // It is an escape sequence. - code_length := 0 - - // Check the escape character. - switch parser.buffer[parser.buffer_pos+1] { - case '0': - s = append(s, 0) - case 'a': - s = append(s, '\x07') - case 'b': - s = append(s, '\x08') - case 't', '\t': - s = append(s, '\x09') - case 'n': - s = append(s, '\x0A') - case 'v': - s = append(s, '\x0B') - case 'f': - s = append(s, '\x0C') - case 'r': - s = append(s, '\x0D') - case 'e': - s = append(s, '\x1B') - case ' ': - s = append(s, '\x20') - case '"': - s = append(s, '"') - case '\'': - s = append(s, '\'') - case '\\': - s = append(s, '\\') - case 'N': // NEL (#x85) - s = append(s, '\xC2') - s = append(s, '\x85') - case '_': // #xA0 - s = append(s, '\xC2') - s = append(s, '\xA0') - case 'L': // LS (#x2028) - s = append(s, '\xE2') - s = append(s, '\x80') - s = append(s, '\xA8') - case 'P': // PS (#x2029) - s = append(s, '\xE2') - s = append(s, '\x80') - s = append(s, '\xA9') - case 'x': - code_length = 2 - case 'u': - code_length = 4 - case 'U': - code_length = 8 - default: - yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", - start_mark, "found unknown escape character") - return false - } - - skip(parser) - skip(parser) - - // Consume an arbitrary escape code. - if code_length > 0 { - var value int - - // Scan the character value. - if parser.unread < code_length && !yaml_parser_update_buffer(parser, code_length) { - return false - } - for k := 0; k < code_length; k++ { - if !is_hex(parser.buffer, parser.buffer_pos+k) { - yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", - start_mark, "did not find expected hexdecimal number") - return false - } - value = (value << 4) + as_hex(parser.buffer, parser.buffer_pos+k) - } - - // Check the value and write the character. - if (value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF { - yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", - start_mark, "found invalid Unicode character escape code") - return false - } - if value <= 0x7F { - s = append(s, byte(value)) - } else if value <= 0x7FF { - s = append(s, byte(0xC0+(value>>6))) - s = append(s, byte(0x80+(value&0x3F))) - } else if value <= 0xFFFF { - s = append(s, byte(0xE0+(value>>12))) - s = append(s, byte(0x80+((value>>6)&0x3F))) - s = append(s, byte(0x80+(value&0x3F))) - } else { - s = append(s, byte(0xF0+(value>>18))) - s = append(s, byte(0x80+((value>>12)&0x3F))) - s = append(s, byte(0x80+((value>>6)&0x3F))) - s = append(s, byte(0x80+(value&0x3F))) - } - - // Advance the pointer. - for k := 0; k < code_length; k++ { - skip(parser) - } - } - } else { - // It is a non-escaped non-blank character. - s = read(parser, s) - } - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - } - - // Check if we are at the end of the scalar. - if single { - if parser.buffer[parser.buffer_pos] == '\'' { - break - } - } else { - if parser.buffer[parser.buffer_pos] == '"' { - break - } - } - - // Consume blank characters. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) { - if is_blank(parser.buffer, parser.buffer_pos) { - // Consume a space or a tab character. - if !leading_blanks { - whitespaces = read(parser, whitespaces) - } else { - skip(parser) - } - } else { - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - - // Check if it is a first line break. - if !leading_blanks { - whitespaces = whitespaces[:0] - leading_break = read_line(parser, leading_break) - leading_blanks = true - } else { - trailing_breaks = read_line(parser, trailing_breaks) - } - } - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Join the whitespaces or fold line breaks. - if leading_blanks { - // Do we need to fold line breaks? - if len(leading_break) > 0 && leading_break[0] == '\n' { - if len(trailing_breaks) == 0 { - s = append(s, ' ') - } else { - s = append(s, trailing_breaks...) - } - } else { - s = append(s, leading_break...) - s = append(s, trailing_breaks...) - } - trailing_breaks = trailing_breaks[:0] - leading_break = leading_break[:0] - } else { - s = append(s, whitespaces...) - whitespaces = whitespaces[:0] - } - } - - // Eat the right quote. - skip(parser) - end_mark := parser.mark - - // Create a token. - *token = yaml_token_t{ - typ: yaml_SCALAR_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - value: s, - style: yaml_SINGLE_QUOTED_SCALAR_STYLE, - } - if !single { - token.style = yaml_DOUBLE_QUOTED_SCALAR_STYLE - } - return true -} - -// Scan a plain scalar. -func yaml_parser_scan_plain_scalar(parser *yaml_parser_t, token *yaml_token_t) bool { - - var s, leading_break, trailing_breaks, whitespaces []byte - var leading_blanks bool - var indent = parser.indent + 1 - - start_mark := parser.mark - end_mark := parser.mark - - // Consume the content of the plain scalar. - for { - // Check for a document indicator. - if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { - return false - } - if parser.mark.column == 0 && - ((parser.buffer[parser.buffer_pos+0] == '-' && - parser.buffer[parser.buffer_pos+1] == '-' && - parser.buffer[parser.buffer_pos+2] == '-') || - (parser.buffer[parser.buffer_pos+0] == '.' && - parser.buffer[parser.buffer_pos+1] == '.' && - parser.buffer[parser.buffer_pos+2] == '.')) && - is_blankz(parser.buffer, parser.buffer_pos+3) { - break - } - - // Check for a comment. - if parser.buffer[parser.buffer_pos] == '#' { - break - } - - // Consume non-blank characters. - for !is_blankz(parser.buffer, parser.buffer_pos) { - - // Check for 'x:x' in the flow context. TODO: Fix the test "spec-08-13". - if parser.flow_level > 0 && - parser.buffer[parser.buffer_pos] == ':' && - !is_blankz(parser.buffer, parser.buffer_pos+1) { - yaml_parser_set_scanner_error(parser, "while scanning a plain scalar", - start_mark, "found unexpected ':'") - return false - } - - // Check for indicators that may end a plain scalar. - if (parser.buffer[parser.buffer_pos] == ':' && is_blankz(parser.buffer, parser.buffer_pos+1)) || - (parser.flow_level > 0 && - (parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == ':' || - parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == '[' || - parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' || - parser.buffer[parser.buffer_pos] == '}')) { - break - } - - // Check if we need to join whitespaces and breaks. - if leading_blanks || len(whitespaces) > 0 { - if leading_blanks { - // Do we need to fold line breaks? - if leading_break[0] == '\n' { - if len(trailing_breaks) == 0 { - s = append(s, ' ') - } else { - s = append(s, trailing_breaks...) - } - } else { - s = append(s, leading_break...) - s = append(s, trailing_breaks...) - } - trailing_breaks = trailing_breaks[:0] - leading_break = leading_break[:0] - leading_blanks = false - } else { - s = append(s, whitespaces...) - whitespaces = whitespaces[:0] - } - } - - // Copy the character. - s = read(parser, s) - - end_mark = parser.mark - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - } - - // Is it the end? - if !(is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos)) { - break - } - - // Consume blank characters. - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - - for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) { - if is_blank(parser.buffer, parser.buffer_pos) { - - // Check for tab character that abuse indentation. - if leading_blanks && parser.mark.column < indent && is_tab(parser.buffer, parser.buffer_pos) { - yaml_parser_set_scanner_error(parser, "while scanning a plain scalar", - start_mark, "found a tab character that violate indentation") - return false - } - - // Consume a space or a tab character. - if !leading_blanks { - whitespaces = read(parser, whitespaces) - } else { - skip(parser) - } - } else { - if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { - return false - } - - // Check if it is a first line break. - if !leading_blanks { - whitespaces = whitespaces[:0] - leading_break = read_line(parser, leading_break) - leading_blanks = true - } else { - trailing_breaks = read_line(parser, trailing_breaks) - } - } - if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { - return false - } - } - - // Check indentation level. - if parser.flow_level == 0 && parser.mark.column < indent { - break - } - } - - // Create a token. - *token = yaml_token_t{ - typ: yaml_SCALAR_TOKEN, - start_mark: start_mark, - end_mark: end_mark, - value: s, - style: yaml_PLAIN_SCALAR_STYLE, - } - - // Note that we change the 'simple_key_allowed' flag. - if leading_blanks { - parser.simple_key_allowed = true - } - return true -} diff --git a/dev-tools/vendor/gopkg.in/yaml.v2/sorter.go b/dev-tools/vendor/gopkg.in/yaml.v2/sorter.go deleted file mode 100644 index 5958822f9c6b..000000000000 --- a/dev-tools/vendor/gopkg.in/yaml.v2/sorter.go +++ /dev/null @@ -1,104 +0,0 @@ -package yaml - -import ( - "reflect" - "unicode" -) - -type keyList []reflect.Value - -func (l keyList) Len() int { return len(l) } -func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } -func (l keyList) Less(i, j int) bool { - a := l[i] - b := l[j] - ak := a.Kind() - bk := b.Kind() - for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() { - a = a.Elem() - ak = a.Kind() - } - for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() { - b = b.Elem() - bk = b.Kind() - } - af, aok := keyFloat(a) - bf, bok := keyFloat(b) - if aok && bok { - if af != bf { - return af < bf - } - if ak != bk { - return ak < bk - } - return numLess(a, b) - } - if ak != reflect.String || bk != reflect.String { - return ak < bk - } - ar, br := []rune(a.String()), []rune(b.String()) - for i := 0; i < len(ar) && i < len(br); i++ { - if ar[i] == br[i] { - continue - } - al := unicode.IsLetter(ar[i]) - bl := unicode.IsLetter(br[i]) - if al && bl { - return ar[i] < br[i] - } - if al || bl { - return bl - } - var ai, bi int - var an, bn int64 - for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ { - an = an*10 + int64(ar[ai]-'0') - } - for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ { - bn = bn*10 + int64(br[bi]-'0') - } - if an != bn { - return an < bn - } - if ai != bi { - return ai < bi - } - return ar[i] < br[i] - } - return len(ar) < len(br) -} - -// keyFloat returns a float value for v if it is a number/bool -// and whether it is a number/bool or not. -func keyFloat(v reflect.Value) (f float64, ok bool) { - switch v.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return float64(v.Int()), true - case reflect.Float32, reflect.Float64: - return v.Float(), true - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return float64(v.Uint()), true - case reflect.Bool: - if v.Bool() { - return 1, true - } - return 0, true - } - return 0, false -} - -// numLess returns whether a < b. -// a and b must necessarily have the same kind. -func numLess(a, b reflect.Value) bool { - switch a.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return a.Int() < b.Int() - case reflect.Float32, reflect.Float64: - return a.Float() < b.Float() - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return a.Uint() < b.Uint() - case reflect.Bool: - return !a.Bool() && b.Bool() - } - panic("not a number") -} diff --git a/dev-tools/vendor/gopkg.in/yaml.v2/writerc.go b/dev-tools/vendor/gopkg.in/yaml.v2/writerc.go deleted file mode 100644 index 190362f25dfb..000000000000 --- a/dev-tools/vendor/gopkg.in/yaml.v2/writerc.go +++ /dev/null @@ -1,89 +0,0 @@ -package yaml - -// Set the writer error and return false. -func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool { - emitter.error = yaml_WRITER_ERROR - emitter.problem = problem - return false -} - -// Flush the output buffer. -func yaml_emitter_flush(emitter *yaml_emitter_t) bool { - if emitter.write_handler == nil { - panic("write handler not set") - } - - // Check if the buffer is empty. - if emitter.buffer_pos == 0 { - return true - } - - // If the output encoding is UTF-8, we don't need to recode the buffer. - if emitter.encoding == yaml_UTF8_ENCODING { - if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil { - return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error()) - } - emitter.buffer_pos = 0 - return true - } - - // Recode the buffer into the raw buffer. - var low, high int - if emitter.encoding == yaml_UTF16LE_ENCODING { - low, high = 0, 1 - } else { - high, low = 1, 0 - } - - pos := 0 - for pos < emitter.buffer_pos { - // See the "reader.c" code for more details on UTF-8 encoding. Note - // that we assume that the buffer contains a valid UTF-8 sequence. - - // Read the next UTF-8 character. - octet := emitter.buffer[pos] - - var w int - var value rune - switch { - case octet&0x80 == 0x00: - w, value = 1, rune(octet&0x7F) - case octet&0xE0 == 0xC0: - w, value = 2, rune(octet&0x1F) - case octet&0xF0 == 0xE0: - w, value = 3, rune(octet&0x0F) - case octet&0xF8 == 0xF0: - w, value = 4, rune(octet&0x07) - } - for k := 1; k < w; k++ { - octet = emitter.buffer[pos+k] - value = (value << 6) + (rune(octet) & 0x3F) - } - pos += w - - // Write the character. - if value < 0x10000 { - var b [2]byte - b[high] = byte(value >> 8) - b[low] = byte(value & 0xFF) - emitter.raw_buffer = append(emitter.raw_buffer, b[0], b[1]) - } else { - // Write the character using a surrogate pair (check "reader.c"). - var b [4]byte - value -= 0x10000 - b[high] = byte(0xD8 + (value >> 18)) - b[low] = byte((value >> 10) & 0xFF) - b[high+2] = byte(0xDC + ((value >> 8) & 0xFF)) - b[low+2] = byte(value & 0xFF) - emitter.raw_buffer = append(emitter.raw_buffer, b[0], b[1], b[2], b[3]) - } - } - - // Write the raw buffer. - if err := emitter.write_handler(emitter, emitter.raw_buffer); err != nil { - return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error()) - } - emitter.buffer_pos = 0 - emitter.raw_buffer = emitter.raw_buffer[:0] - return true -} diff --git a/dev-tools/vendor/gopkg.in/yaml.v2/yaml.go b/dev-tools/vendor/gopkg.in/yaml.v2/yaml.go deleted file mode 100644 index 5e3c2daee435..000000000000 --- a/dev-tools/vendor/gopkg.in/yaml.v2/yaml.go +++ /dev/null @@ -1,357 +0,0 @@ -// Package yaml implements YAML support for the Go language. -// -// Source code and other details for the project are available at GitHub: -// -// https://github.com/go-yaml/yaml -// -package yaml - -import ( - "errors" - "fmt" - "reflect" - "strings" - "sync" -) - -// MapSlice encodes and decodes as a YAML map. -// The order of keys is preserved when encoding and decoding. -type MapSlice []MapItem - -// MapItem is an item in a MapSlice. -type MapItem struct { - Key, Value interface{} -} - -// The Unmarshaler interface may be implemented by types to customize their -// behavior when being unmarshaled from a YAML document. The UnmarshalYAML -// method receives a function that may be called to unmarshal the original -// YAML value into a field or variable. It is safe to call the unmarshal -// function parameter more than once if necessary. -type Unmarshaler interface { - UnmarshalYAML(unmarshal func(interface{}) error) error -} - -// The Marshaler interface may be implemented by types to customize their -// behavior when being marshaled into a YAML document. The returned value -// is marshaled in place of the original value implementing Marshaler. -// -// If an error is returned by MarshalYAML, the marshaling procedure stops -// and returns with the provided error. -type Marshaler interface { - MarshalYAML() (interface{}, error) -} - -// Unmarshal decodes the first document found within the in byte slice -// and assigns decoded values into the out value. -// -// Maps and pointers (to a struct, string, int, etc) are accepted as out -// values. If an internal pointer within a struct is not initialized, -// the yaml package will initialize it if necessary for unmarshalling -// the provided data. The out parameter must not be nil. -// -// The type of the decoded values should be compatible with the respective -// values in out. If one or more values cannot be decoded due to a type -// mismatches, decoding continues partially until the end of the YAML -// content, and a *yaml.TypeError is returned with details for all -// missed values. -// -// Struct fields are only unmarshalled if they are exported (have an -// upper case first letter), and are unmarshalled using the field name -// lowercased as the default key. Custom keys may be defined via the -// "yaml" name in the field tag: the content preceding the first comma -// is used as the key, and the following comma-separated options are -// used to tweak the marshalling process (see Marshal). -// Conflicting names result in a runtime error. -// -// For example: -// -// type T struct { -// F int `yaml:"a,omitempty"` -// B int -// } -// var t T -// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t) -// -// See the documentation of Marshal for the format of tags and a list of -// supported tag options. -// -func Unmarshal(in []byte, out interface{}) (err error) { - return unmarshal(in, out, false) -} - -// UnmarshalStrict is like Unmarshal except that any fields that are found -// in the data that do not have corresponding struct members will result in -// an error. -func UnmarshalStrict(in []byte, out interface{}) (err error) { - return unmarshal(in, out, true) -} - -func unmarshal(in []byte, out interface{}, strict bool) (err error) { - defer handleErr(&err) - d := newDecoder(strict) - p := newParser(in) - defer p.destroy() - node := p.parse() - if node != nil { - v := reflect.ValueOf(out) - if v.Kind() == reflect.Ptr && !v.IsNil() { - v = v.Elem() - } - d.unmarshal(node, v) - } - if len(d.terrors) > 0 { - return &TypeError{d.terrors} - } - return nil -} - -// Marshal serializes the value provided into a YAML document. The structure -// of the generated document will reflect the structure of the value itself. -// Maps and pointers (to struct, string, int, etc) are accepted as the in value. -// -// Struct fields are only unmarshalled if they are exported (have an upper case -// first letter), and are unmarshalled using the field name lowercased as the -// default key. Custom keys may be defined via the "yaml" name in the field -// tag: the content preceding the first comma is used as the key, and the -// following comma-separated options are used to tweak the marshalling process. -// Conflicting names result in a runtime error. -// -// The field tag format accepted is: -// -// `(...) yaml:"[][,[,]]" (...)` -// -// The following flags are currently supported: -// -// omitempty Only include the field if it's not set to the zero -// value for the type or to empty slices or maps. -// Does not apply to zero valued structs. -// -// flow Marshal using a flow style (useful for structs, -// sequences and maps). -// -// inline Inline the field, which must be a struct or a map, -// causing all of its fields or keys to be processed as if -// they were part of the outer struct. For maps, keys must -// not conflict with the yaml keys of other struct fields. -// -// In addition, if the key is "-", the field is ignored. -// -// For example: -// -// type T struct { -// F int `yaml:"a,omitempty"` -// B int -// } -// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n" -// yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n" -// -func Marshal(in interface{}) (out []byte, err error) { - defer handleErr(&err) - e := newEncoder() - defer e.destroy() - e.marshal("", reflect.ValueOf(in)) - e.finish() - out = e.out - return -} - -func handleErr(err *error) { - if v := recover(); v != nil { - if e, ok := v.(yamlError); ok { - *err = e.err - } else { - panic(v) - } - } -} - -type yamlError struct { - err error -} - -func fail(err error) { - panic(yamlError{err}) -} - -func failf(format string, args ...interface{}) { - panic(yamlError{fmt.Errorf("yaml: "+format, args...)}) -} - -// A TypeError is returned by Unmarshal when one or more fields in -// the YAML document cannot be properly decoded into the requested -// types. When this error is returned, the value is still -// unmarshaled partially. -type TypeError struct { - Errors []string -} - -func (e *TypeError) Error() string { - return fmt.Sprintf("yaml: unmarshal errors:\n %s", strings.Join(e.Errors, "\n ")) -} - -// -------------------------------------------------------------------------- -// Maintain a mapping of keys to structure field indexes - -// The code in this section was copied from mgo/bson. - -// structInfo holds details for the serialization of fields of -// a given struct. -type structInfo struct { - FieldsMap map[string]fieldInfo - FieldsList []fieldInfo - - // InlineMap is the number of the field in the struct that - // contains an ,inline map, or -1 if there's none. - InlineMap int -} - -type fieldInfo struct { - Key string - Num int - OmitEmpty bool - Flow bool - - // Inline holds the field index if the field is part of an inlined struct. - Inline []int -} - -var structMap = make(map[reflect.Type]*structInfo) -var fieldMapMutex sync.RWMutex - -func getStructInfo(st reflect.Type) (*structInfo, error) { - fieldMapMutex.RLock() - sinfo, found := structMap[st] - fieldMapMutex.RUnlock() - if found { - return sinfo, nil - } - - n := st.NumField() - fieldsMap := make(map[string]fieldInfo) - fieldsList := make([]fieldInfo, 0, n) - inlineMap := -1 - for i := 0; i != n; i++ { - field := st.Field(i) - if field.PkgPath != "" && !field.Anonymous { - continue // Private field - } - - info := fieldInfo{Num: i} - - tag := field.Tag.Get("yaml") - if tag == "" && strings.Index(string(field.Tag), ":") < 0 { - tag = string(field.Tag) - } - if tag == "-" { - continue - } - - inline := false - fields := strings.Split(tag, ",") - if len(fields) > 1 { - for _, flag := range fields[1:] { - switch flag { - case "omitempty": - info.OmitEmpty = true - case "flow": - info.Flow = true - case "inline": - inline = true - default: - return nil, errors.New(fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st)) - } - } - tag = fields[0] - } - - if inline { - switch field.Type.Kind() { - case reflect.Map: - if inlineMap >= 0 { - return nil, errors.New("Multiple ,inline maps in struct " + st.String()) - } - if field.Type.Key() != reflect.TypeOf("") { - return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String()) - } - inlineMap = info.Num - case reflect.Struct: - sinfo, err := getStructInfo(field.Type) - if err != nil { - return nil, err - } - for _, finfo := range sinfo.FieldsList { - if _, found := fieldsMap[finfo.Key]; found { - msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String() - return nil, errors.New(msg) - } - if finfo.Inline == nil { - finfo.Inline = []int{i, finfo.Num} - } else { - finfo.Inline = append([]int{i}, finfo.Inline...) - } - fieldsMap[finfo.Key] = finfo - fieldsList = append(fieldsList, finfo) - } - default: - //return nil, errors.New("Option ,inline needs a struct value or map field") - return nil, errors.New("Option ,inline needs a struct value field") - } - continue - } - - if tag != "" { - info.Key = tag - } else { - info.Key = strings.ToLower(field.Name) - } - - if _, found = fieldsMap[info.Key]; found { - msg := "Duplicated key '" + info.Key + "' in struct " + st.String() - return nil, errors.New(msg) - } - - fieldsList = append(fieldsList, info) - fieldsMap[info.Key] = info - } - - sinfo = &structInfo{fieldsMap, fieldsList, inlineMap} - - fieldMapMutex.Lock() - structMap[st] = sinfo - fieldMapMutex.Unlock() - return sinfo, nil -} - -func isZero(v reflect.Value) bool { - switch v.Kind() { - case reflect.String: - return len(v.String()) == 0 - case reflect.Interface, reflect.Ptr: - return v.IsNil() - case reflect.Slice: - return v.Len() == 0 - case reflect.Map: - return v.Len() == 0 - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return v.Int() == 0 - case reflect.Float32, reflect.Float64: - return v.Float() == 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return v.Uint() == 0 - case reflect.Bool: - return !v.Bool() - case reflect.Struct: - vt := v.Type() - for i := v.NumField() - 1; i >= 0; i-- { - if vt.Field(i).PkgPath != "" { - continue // Private field - } - if !isZero(v.Field(i)) { - return false - } - } - return true - } - return false -} diff --git a/dev-tools/vendor/gopkg.in/yaml.v2/yamlh.go b/dev-tools/vendor/gopkg.in/yaml.v2/yamlh.go deleted file mode 100644 index 3caeca0491b5..000000000000 --- a/dev-tools/vendor/gopkg.in/yaml.v2/yamlh.go +++ /dev/null @@ -1,716 +0,0 @@ -package yaml - -import ( - "io" -) - -// The version directive data. -type yaml_version_directive_t struct { - major int8 // The major version number. - minor int8 // The minor version number. -} - -// The tag directive data. -type yaml_tag_directive_t struct { - handle []byte // The tag handle. - prefix []byte // The tag prefix. -} - -type yaml_encoding_t int - -// The stream encoding. -const ( - // Let the parser choose the encoding. - yaml_ANY_ENCODING yaml_encoding_t = iota - - yaml_UTF8_ENCODING // The default UTF-8 encoding. - yaml_UTF16LE_ENCODING // The UTF-16-LE encoding with BOM. - yaml_UTF16BE_ENCODING // The UTF-16-BE encoding with BOM. -) - -type yaml_break_t int - -// Line break types. -const ( - // Let the parser choose the break type. - yaml_ANY_BREAK yaml_break_t = iota - - yaml_CR_BREAK // Use CR for line breaks (Mac style). - yaml_LN_BREAK // Use LN for line breaks (Unix style). - yaml_CRLN_BREAK // Use CR LN for line breaks (DOS style). -) - -type yaml_error_type_t int - -// Many bad things could happen with the parser and emitter. -const ( - // No error is produced. - yaml_NO_ERROR yaml_error_type_t = iota - - yaml_MEMORY_ERROR // Cannot allocate or reallocate a block of memory. - yaml_READER_ERROR // Cannot read or decode the input stream. - yaml_SCANNER_ERROR // Cannot scan the input stream. - yaml_PARSER_ERROR // Cannot parse the input stream. - yaml_COMPOSER_ERROR // Cannot compose a YAML document. - yaml_WRITER_ERROR // Cannot write to the output stream. - yaml_EMITTER_ERROR // Cannot emit a YAML stream. -) - -// The pointer position. -type yaml_mark_t struct { - index int // The position index. - line int // The position line. - column int // The position column. -} - -// Node Styles - -type yaml_style_t int8 - -type yaml_scalar_style_t yaml_style_t - -// Scalar styles. -const ( - // Let the emitter choose the style. - yaml_ANY_SCALAR_STYLE yaml_scalar_style_t = iota - - yaml_PLAIN_SCALAR_STYLE // The plain scalar style. - yaml_SINGLE_QUOTED_SCALAR_STYLE // The single-quoted scalar style. - yaml_DOUBLE_QUOTED_SCALAR_STYLE // The double-quoted scalar style. - yaml_LITERAL_SCALAR_STYLE // The literal scalar style. - yaml_FOLDED_SCALAR_STYLE // The folded scalar style. -) - -type yaml_sequence_style_t yaml_style_t - -// Sequence styles. -const ( - // Let the emitter choose the style. - yaml_ANY_SEQUENCE_STYLE yaml_sequence_style_t = iota - - yaml_BLOCK_SEQUENCE_STYLE // The block sequence style. - yaml_FLOW_SEQUENCE_STYLE // The flow sequence style. -) - -type yaml_mapping_style_t yaml_style_t - -// Mapping styles. -const ( - // Let the emitter choose the style. - yaml_ANY_MAPPING_STYLE yaml_mapping_style_t = iota - - yaml_BLOCK_MAPPING_STYLE // The block mapping style. - yaml_FLOW_MAPPING_STYLE // The flow mapping style. -) - -// Tokens - -type yaml_token_type_t int - -// Token types. -const ( - // An empty token. - yaml_NO_TOKEN yaml_token_type_t = iota - - yaml_STREAM_START_TOKEN // A STREAM-START token. - yaml_STREAM_END_TOKEN // A STREAM-END token. - - yaml_VERSION_DIRECTIVE_TOKEN // A VERSION-DIRECTIVE token. - yaml_TAG_DIRECTIVE_TOKEN // A TAG-DIRECTIVE token. - yaml_DOCUMENT_START_TOKEN // A DOCUMENT-START token. - yaml_DOCUMENT_END_TOKEN // A DOCUMENT-END token. - - yaml_BLOCK_SEQUENCE_START_TOKEN // A BLOCK-SEQUENCE-START token. - yaml_BLOCK_MAPPING_START_TOKEN // A BLOCK-SEQUENCE-END token. - yaml_BLOCK_END_TOKEN // A BLOCK-END token. - - yaml_FLOW_SEQUENCE_START_TOKEN // A FLOW-SEQUENCE-START token. - yaml_FLOW_SEQUENCE_END_TOKEN // A FLOW-SEQUENCE-END token. - yaml_FLOW_MAPPING_START_TOKEN // A FLOW-MAPPING-START token. - yaml_FLOW_MAPPING_END_TOKEN // A FLOW-MAPPING-END token. - - yaml_BLOCK_ENTRY_TOKEN // A BLOCK-ENTRY token. - yaml_FLOW_ENTRY_TOKEN // A FLOW-ENTRY token. - yaml_KEY_TOKEN // A KEY token. - yaml_VALUE_TOKEN // A VALUE token. - - yaml_ALIAS_TOKEN // An ALIAS token. - yaml_ANCHOR_TOKEN // An ANCHOR token. - yaml_TAG_TOKEN // A TAG token. - yaml_SCALAR_TOKEN // A SCALAR token. -) - -func (tt yaml_token_type_t) String() string { - switch tt { - case yaml_NO_TOKEN: - return "yaml_NO_TOKEN" - case yaml_STREAM_START_TOKEN: - return "yaml_STREAM_START_TOKEN" - case yaml_STREAM_END_TOKEN: - return "yaml_STREAM_END_TOKEN" - case yaml_VERSION_DIRECTIVE_TOKEN: - return "yaml_VERSION_DIRECTIVE_TOKEN" - case yaml_TAG_DIRECTIVE_TOKEN: - return "yaml_TAG_DIRECTIVE_TOKEN" - case yaml_DOCUMENT_START_TOKEN: - return "yaml_DOCUMENT_START_TOKEN" - case yaml_DOCUMENT_END_TOKEN: - return "yaml_DOCUMENT_END_TOKEN" - case yaml_BLOCK_SEQUENCE_START_TOKEN: - return "yaml_BLOCK_SEQUENCE_START_TOKEN" - case yaml_BLOCK_MAPPING_START_TOKEN: - return "yaml_BLOCK_MAPPING_START_TOKEN" - case yaml_BLOCK_END_TOKEN: - return "yaml_BLOCK_END_TOKEN" - case yaml_FLOW_SEQUENCE_START_TOKEN: - return "yaml_FLOW_SEQUENCE_START_TOKEN" - case yaml_FLOW_SEQUENCE_END_TOKEN: - return "yaml_FLOW_SEQUENCE_END_TOKEN" - case yaml_FLOW_MAPPING_START_TOKEN: - return "yaml_FLOW_MAPPING_START_TOKEN" - case yaml_FLOW_MAPPING_END_TOKEN: - return "yaml_FLOW_MAPPING_END_TOKEN" - case yaml_BLOCK_ENTRY_TOKEN: - return "yaml_BLOCK_ENTRY_TOKEN" - case yaml_FLOW_ENTRY_TOKEN: - return "yaml_FLOW_ENTRY_TOKEN" - case yaml_KEY_TOKEN: - return "yaml_KEY_TOKEN" - case yaml_VALUE_TOKEN: - return "yaml_VALUE_TOKEN" - case yaml_ALIAS_TOKEN: - return "yaml_ALIAS_TOKEN" - case yaml_ANCHOR_TOKEN: - return "yaml_ANCHOR_TOKEN" - case yaml_TAG_TOKEN: - return "yaml_TAG_TOKEN" - case yaml_SCALAR_TOKEN: - return "yaml_SCALAR_TOKEN" - } - return "" -} - -// The token structure. -type yaml_token_t struct { - // The token type. - typ yaml_token_type_t - - // The start/end of the token. - start_mark, end_mark yaml_mark_t - - // The stream encoding (for yaml_STREAM_START_TOKEN). - encoding yaml_encoding_t - - // The alias/anchor/scalar value or tag/tag directive handle - // (for yaml_ALIAS_TOKEN, yaml_ANCHOR_TOKEN, yaml_SCALAR_TOKEN, yaml_TAG_TOKEN, yaml_TAG_DIRECTIVE_TOKEN). - value []byte - - // The tag suffix (for yaml_TAG_TOKEN). - suffix []byte - - // The tag directive prefix (for yaml_TAG_DIRECTIVE_TOKEN). - prefix []byte - - // The scalar style (for yaml_SCALAR_TOKEN). - style yaml_scalar_style_t - - // The version directive major/minor (for yaml_VERSION_DIRECTIVE_TOKEN). - major, minor int8 -} - -// Events - -type yaml_event_type_t int8 - -// Event types. -const ( - // An empty event. - yaml_NO_EVENT yaml_event_type_t = iota - - yaml_STREAM_START_EVENT // A STREAM-START event. - yaml_STREAM_END_EVENT // A STREAM-END event. - yaml_DOCUMENT_START_EVENT // A DOCUMENT-START event. - yaml_DOCUMENT_END_EVENT // A DOCUMENT-END event. - yaml_ALIAS_EVENT // An ALIAS event. - yaml_SCALAR_EVENT // A SCALAR event. - yaml_SEQUENCE_START_EVENT // A SEQUENCE-START event. - yaml_SEQUENCE_END_EVENT // A SEQUENCE-END event. - yaml_MAPPING_START_EVENT // A MAPPING-START event. - yaml_MAPPING_END_EVENT // A MAPPING-END event. -) - -// The event structure. -type yaml_event_t struct { - - // The event type. - typ yaml_event_type_t - - // The start and end of the event. - start_mark, end_mark yaml_mark_t - - // The document encoding (for yaml_STREAM_START_EVENT). - encoding yaml_encoding_t - - // The version directive (for yaml_DOCUMENT_START_EVENT). - version_directive *yaml_version_directive_t - - // The list of tag directives (for yaml_DOCUMENT_START_EVENT). - tag_directives []yaml_tag_directive_t - - // The anchor (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_ALIAS_EVENT). - anchor []byte - - // The tag (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT). - tag []byte - - // The scalar value (for yaml_SCALAR_EVENT). - value []byte - - // Is the document start/end indicator implicit, or the tag optional? - // (for yaml_DOCUMENT_START_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_SCALAR_EVENT). - implicit bool - - // Is the tag optional for any non-plain style? (for yaml_SCALAR_EVENT). - quoted_implicit bool - - // The style (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT). - style yaml_style_t -} - -func (e *yaml_event_t) scalar_style() yaml_scalar_style_t { return yaml_scalar_style_t(e.style) } -func (e *yaml_event_t) sequence_style() yaml_sequence_style_t { return yaml_sequence_style_t(e.style) } -func (e *yaml_event_t) mapping_style() yaml_mapping_style_t { return yaml_mapping_style_t(e.style) } - -// Nodes - -const ( - yaml_NULL_TAG = "tag:yaml.org,2002:null" // The tag !!null with the only possible value: null. - yaml_BOOL_TAG = "tag:yaml.org,2002:bool" // The tag !!bool with the values: true and false. - yaml_STR_TAG = "tag:yaml.org,2002:str" // The tag !!str for string values. - yaml_INT_TAG = "tag:yaml.org,2002:int" // The tag !!int for integer values. - yaml_FLOAT_TAG = "tag:yaml.org,2002:float" // The tag !!float for float values. - yaml_TIMESTAMP_TAG = "tag:yaml.org,2002:timestamp" // The tag !!timestamp for date and time values. - - yaml_SEQ_TAG = "tag:yaml.org,2002:seq" // The tag !!seq is used to denote sequences. - yaml_MAP_TAG = "tag:yaml.org,2002:map" // The tag !!map is used to denote mapping. - - // Not in original libyaml. - yaml_BINARY_TAG = "tag:yaml.org,2002:binary" - yaml_MERGE_TAG = "tag:yaml.org,2002:merge" - - yaml_DEFAULT_SCALAR_TAG = yaml_STR_TAG // The default scalar tag is !!str. - yaml_DEFAULT_SEQUENCE_TAG = yaml_SEQ_TAG // The default sequence tag is !!seq. - yaml_DEFAULT_MAPPING_TAG = yaml_MAP_TAG // The default mapping tag is !!map. -) - -type yaml_node_type_t int - -// Node types. -const ( - // An empty node. - yaml_NO_NODE yaml_node_type_t = iota - - yaml_SCALAR_NODE // A scalar node. - yaml_SEQUENCE_NODE // A sequence node. - yaml_MAPPING_NODE // A mapping node. -) - -// An element of a sequence node. -type yaml_node_item_t int - -// An element of a mapping node. -type yaml_node_pair_t struct { - key int // The key of the element. - value int // The value of the element. -} - -// The node structure. -type yaml_node_t struct { - typ yaml_node_type_t // The node type. - tag []byte // The node tag. - - // The node data. - - // The scalar parameters (for yaml_SCALAR_NODE). - scalar struct { - value []byte // The scalar value. - length int // The length of the scalar value. - style yaml_scalar_style_t // The scalar style. - } - - // The sequence parameters (for YAML_SEQUENCE_NODE). - sequence struct { - items_data []yaml_node_item_t // The stack of sequence items. - style yaml_sequence_style_t // The sequence style. - } - - // The mapping parameters (for yaml_MAPPING_NODE). - mapping struct { - pairs_data []yaml_node_pair_t // The stack of mapping pairs (key, value). - pairs_start *yaml_node_pair_t // The beginning of the stack. - pairs_end *yaml_node_pair_t // The end of the stack. - pairs_top *yaml_node_pair_t // The top of the stack. - style yaml_mapping_style_t // The mapping style. - } - - start_mark yaml_mark_t // The beginning of the node. - end_mark yaml_mark_t // The end of the node. - -} - -// The document structure. -type yaml_document_t struct { - - // The document nodes. - nodes []yaml_node_t - - // The version directive. - version_directive *yaml_version_directive_t - - // The list of tag directives. - tag_directives_data []yaml_tag_directive_t - tag_directives_start int // The beginning of the tag directives list. - tag_directives_end int // The end of the tag directives list. - - start_implicit int // Is the document start indicator implicit? - end_implicit int // Is the document end indicator implicit? - - // The start/end of the document. - start_mark, end_mark yaml_mark_t -} - -// The prototype of a read handler. -// -// The read handler is called when the parser needs to read more bytes from the -// source. The handler should write not more than size bytes to the buffer. -// The number of written bytes should be set to the size_read variable. -// -// [in,out] data A pointer to an application data specified by -// yaml_parser_set_input(). -// [out] buffer The buffer to write the data from the source. -// [in] size The size of the buffer. -// [out] size_read The actual number of bytes read from the source. -// -// On success, the handler should return 1. If the handler failed, -// the returned value should be 0. On EOF, the handler should set the -// size_read to 0 and return 1. -type yaml_read_handler_t func(parser *yaml_parser_t, buffer []byte) (n int, err error) - -// This structure holds information about a potential simple key. -type yaml_simple_key_t struct { - possible bool // Is a simple key possible? - required bool // Is a simple key required? - token_number int // The number of the token. - mark yaml_mark_t // The position mark. -} - -// The states of the parser. -type yaml_parser_state_t int - -const ( - yaml_PARSE_STREAM_START_STATE yaml_parser_state_t = iota - - yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE // Expect the beginning of an implicit document. - yaml_PARSE_DOCUMENT_START_STATE // Expect DOCUMENT-START. - yaml_PARSE_DOCUMENT_CONTENT_STATE // Expect the content of a document. - yaml_PARSE_DOCUMENT_END_STATE // Expect DOCUMENT-END. - yaml_PARSE_BLOCK_NODE_STATE // Expect a block node. - yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE // Expect a block node or indentless sequence. - yaml_PARSE_FLOW_NODE_STATE // Expect a flow node. - yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a block sequence. - yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE // Expect an entry of a block sequence. - yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE // Expect an entry of an indentless sequence. - yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping. - yaml_PARSE_BLOCK_MAPPING_KEY_STATE // Expect a block mapping key. - yaml_PARSE_BLOCK_MAPPING_VALUE_STATE // Expect a block mapping value. - yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a flow sequence. - yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE // Expect an entry of a flow sequence. - yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE // Expect a key of an ordered mapping. - yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE // Expect a value of an ordered mapping. - yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE // Expect the and of an ordered mapping entry. - yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping. - yaml_PARSE_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping. - yaml_PARSE_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping. - yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE // Expect an empty value of a flow mapping. - yaml_PARSE_END_STATE // Expect nothing. -) - -func (ps yaml_parser_state_t) String() string { - switch ps { - case yaml_PARSE_STREAM_START_STATE: - return "yaml_PARSE_STREAM_START_STATE" - case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE: - return "yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE" - case yaml_PARSE_DOCUMENT_START_STATE: - return "yaml_PARSE_DOCUMENT_START_STATE" - case yaml_PARSE_DOCUMENT_CONTENT_STATE: - return "yaml_PARSE_DOCUMENT_CONTENT_STATE" - case yaml_PARSE_DOCUMENT_END_STATE: - return "yaml_PARSE_DOCUMENT_END_STATE" - case yaml_PARSE_BLOCK_NODE_STATE: - return "yaml_PARSE_BLOCK_NODE_STATE" - case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE: - return "yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE" - case yaml_PARSE_FLOW_NODE_STATE: - return "yaml_PARSE_FLOW_NODE_STATE" - case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE: - return "yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE" - case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE: - return "yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE" - case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE: - return "yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE" - case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE: - return "yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE" - case yaml_PARSE_BLOCK_MAPPING_KEY_STATE: - return "yaml_PARSE_BLOCK_MAPPING_KEY_STATE" - case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE: - return "yaml_PARSE_BLOCK_MAPPING_VALUE_STATE" - case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE: - return "yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE" - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE: - return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE" - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE: - return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE" - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE: - return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE" - case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE: - return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE" - case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE: - return "yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE" - case yaml_PARSE_FLOW_MAPPING_KEY_STATE: - return "yaml_PARSE_FLOW_MAPPING_KEY_STATE" - case yaml_PARSE_FLOW_MAPPING_VALUE_STATE: - return "yaml_PARSE_FLOW_MAPPING_VALUE_STATE" - case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE: - return "yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE" - case yaml_PARSE_END_STATE: - return "yaml_PARSE_END_STATE" - } - return "" -} - -// This structure holds aliases data. -type yaml_alias_data_t struct { - anchor []byte // The anchor. - index int // The node id. - mark yaml_mark_t // The anchor mark. -} - -// The parser structure. -// -// All members are internal. Manage the structure using the -// yaml_parser_ family of functions. -type yaml_parser_t struct { - - // Error handling - - error yaml_error_type_t // Error type. - - problem string // Error description. - - // The byte about which the problem occurred. - problem_offset int - problem_value int - problem_mark yaml_mark_t - - // The error context. - context string - context_mark yaml_mark_t - - // Reader stuff - - read_handler yaml_read_handler_t // Read handler. - - input_file io.Reader // File input data. - input []byte // String input data. - input_pos int - - eof bool // EOF flag - - buffer []byte // The working buffer. - buffer_pos int // The current position of the buffer. - - unread int // The number of unread characters in the buffer. - - raw_buffer []byte // The raw buffer. - raw_buffer_pos int // The current position of the buffer. - - encoding yaml_encoding_t // The input encoding. - - offset int // The offset of the current position (in bytes). - mark yaml_mark_t // The mark of the current position. - - // Scanner stuff - - stream_start_produced bool // Have we started to scan the input stream? - stream_end_produced bool // Have we reached the end of the input stream? - - flow_level int // The number of unclosed '[' and '{' indicators. - - tokens []yaml_token_t // The tokens queue. - tokens_head int // The head of the tokens queue. - tokens_parsed int // The number of tokens fetched from the queue. - token_available bool // Does the tokens queue contain a token ready for dequeueing. - - indent int // The current indentation level. - indents []int // The indentation levels stack. - - simple_key_allowed bool // May a simple key occur at the current position? - simple_keys []yaml_simple_key_t // The stack of simple keys. - - // Parser stuff - - state yaml_parser_state_t // The current parser state. - states []yaml_parser_state_t // The parser states stack. - marks []yaml_mark_t // The stack of marks. - tag_directives []yaml_tag_directive_t // The list of TAG directives. - - // Dumper stuff - - aliases []yaml_alias_data_t // The alias data. - - document *yaml_document_t // The currently parsed document. -} - -// Emitter Definitions - -// The prototype of a write handler. -// -// The write handler is called when the emitter needs to flush the accumulated -// characters to the output. The handler should write @a size bytes of the -// @a buffer to the output. -// -// @param[in,out] data A pointer to an application data specified by -// yaml_emitter_set_output(). -// @param[in] buffer The buffer with bytes to be written. -// @param[in] size The size of the buffer. -// -// @returns On success, the handler should return @c 1. If the handler failed, -// the returned value should be @c 0. -// -type yaml_write_handler_t func(emitter *yaml_emitter_t, buffer []byte) error - -type yaml_emitter_state_t int - -// The emitter states. -const ( - // Expect STREAM-START. - yaml_EMIT_STREAM_START_STATE yaml_emitter_state_t = iota - - yaml_EMIT_FIRST_DOCUMENT_START_STATE // Expect the first DOCUMENT-START or STREAM-END. - yaml_EMIT_DOCUMENT_START_STATE // Expect DOCUMENT-START or STREAM-END. - yaml_EMIT_DOCUMENT_CONTENT_STATE // Expect the content of a document. - yaml_EMIT_DOCUMENT_END_STATE // Expect DOCUMENT-END. - yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a flow sequence. - yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE // Expect an item of a flow sequence. - yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping. - yaml_EMIT_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping. - yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a flow mapping. - yaml_EMIT_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping. - yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a block sequence. - yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE // Expect an item of a block sequence. - yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping. - yaml_EMIT_BLOCK_MAPPING_KEY_STATE // Expect the key of a block mapping. - yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a block mapping. - yaml_EMIT_BLOCK_MAPPING_VALUE_STATE // Expect a value of a block mapping. - yaml_EMIT_END_STATE // Expect nothing. -) - -// The emitter structure. -// -// All members are internal. Manage the structure using the @c yaml_emitter_ -// family of functions. -type yaml_emitter_t struct { - - // Error handling - - error yaml_error_type_t // Error type. - problem string // Error description. - - // Writer stuff - - write_handler yaml_write_handler_t // Write handler. - - output_buffer *[]byte // String output data. - output_file io.Writer // File output data. - - buffer []byte // The working buffer. - buffer_pos int // The current position of the buffer. - - raw_buffer []byte // The raw buffer. - raw_buffer_pos int // The current position of the buffer. - - encoding yaml_encoding_t // The stream encoding. - - // Emitter stuff - - canonical bool // If the output is in the canonical style? - best_indent int // The number of indentation spaces. - best_width int // The preferred width of the output lines. - unicode bool // Allow unescaped non-ASCII characters? - line_break yaml_break_t // The preferred line break. - - state yaml_emitter_state_t // The current emitter state. - states []yaml_emitter_state_t // The stack of states. - - events []yaml_event_t // The event queue. - events_head int // The head of the event queue. - - indents []int // The stack of indentation levels. - - tag_directives []yaml_tag_directive_t // The list of tag directives. - - indent int // The current indentation level. - - flow_level int // The current flow level. - - root_context bool // Is it the document root context? - sequence_context bool // Is it a sequence context? - mapping_context bool // Is it a mapping context? - simple_key_context bool // Is it a simple mapping key context? - - line int // The current line. - column int // The current column. - whitespace bool // If the last character was a whitespace? - indention bool // If the last character was an indentation character (' ', '-', '?', ':')? - open_ended bool // If an explicit document end is required? - - // Anchor analysis. - anchor_data struct { - anchor []byte // The anchor value. - alias bool // Is it an alias? - } - - // Tag analysis. - tag_data struct { - handle []byte // The tag handle. - suffix []byte // The tag suffix. - } - - // Scalar analysis. - scalar_data struct { - value []byte // The scalar value. - multiline bool // Does the scalar contain line breaks? - flow_plain_allowed bool // Can the scalar be expessed in the flow plain style? - block_plain_allowed bool // Can the scalar be expressed in the block plain style? - single_quoted_allowed bool // Can the scalar be expressed in the single quoted style? - block_allowed bool // Can the scalar be expressed in the literal or folded styles? - style yaml_scalar_style_t // The output style. - } - - // Dumper stuff - - opened bool // If the stream was already opened? - closed bool // If the stream was already closed? - - // The information associated with the document nodes. - anchors *struct { - references int // The number of references. - anchor int // The anchor id. - serialized bool // If the node has been emitted? - } - - last_anchor_id int // The last assigned anchor id. - - document *yaml_document_t // The currently emitted document. -} diff --git a/dev-tools/vendor/gopkg.in/yaml.v2/yamlprivateh.go b/dev-tools/vendor/gopkg.in/yaml.v2/yamlprivateh.go deleted file mode 100644 index 8110ce3c37a6..000000000000 --- a/dev-tools/vendor/gopkg.in/yaml.v2/yamlprivateh.go +++ /dev/null @@ -1,173 +0,0 @@ -package yaml - -const ( - // The size of the input raw buffer. - input_raw_buffer_size = 512 - - // The size of the input buffer. - // It should be possible to decode the whole raw buffer. - input_buffer_size = input_raw_buffer_size * 3 - - // The size of the output buffer. - output_buffer_size = 128 - - // The size of the output raw buffer. - // It should be possible to encode the whole output buffer. - output_raw_buffer_size = (output_buffer_size*2 + 2) - - // The size of other stacks and queues. - initial_stack_size = 16 - initial_queue_size = 16 - initial_string_size = 16 -) - -// Check if the character at the specified position is an alphabetical -// character, a digit, '_', or '-'. -func is_alpha(b []byte, i int) bool { - return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'Z' || b[i] >= 'a' && b[i] <= 'z' || b[i] == '_' || b[i] == '-' -} - -// Check if the character at the specified position is a digit. -func is_digit(b []byte, i int) bool { - return b[i] >= '0' && b[i] <= '9' -} - -// Get the value of a digit. -func as_digit(b []byte, i int) int { - return int(b[i]) - '0' -} - -// Check if the character at the specified position is a hex-digit. -func is_hex(b []byte, i int) bool { - return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'F' || b[i] >= 'a' && b[i] <= 'f' -} - -// Get the value of a hex-digit. -func as_hex(b []byte, i int) int { - bi := b[i] - if bi >= 'A' && bi <= 'F' { - return int(bi) - 'A' + 10 - } - if bi >= 'a' && bi <= 'f' { - return int(bi) - 'a' + 10 - } - return int(bi) - '0' -} - -// Check if the character is ASCII. -func is_ascii(b []byte, i int) bool { - return b[i] <= 0x7F -} - -// Check if the character at the start of the buffer can be printed unescaped. -func is_printable(b []byte, i int) bool { - return ((b[i] == 0x0A) || // . == #x0A - (b[i] >= 0x20 && b[i] <= 0x7E) || // #x20 <= . <= #x7E - (b[i] == 0xC2 && b[i+1] >= 0xA0) || // #0xA0 <= . <= #xD7FF - (b[i] > 0xC2 && b[i] < 0xED) || - (b[i] == 0xED && b[i+1] < 0xA0) || - (b[i] == 0xEE) || - (b[i] == 0xEF && // #xE000 <= . <= #xFFFD - !(b[i+1] == 0xBB && b[i+2] == 0xBF) && // && . != #xFEFF - !(b[i+1] == 0xBF && (b[i+2] == 0xBE || b[i+2] == 0xBF)))) -} - -// Check if the character at the specified position is NUL. -func is_z(b []byte, i int) bool { - return b[i] == 0x00 -} - -// Check if the beginning of the buffer is a BOM. -func is_bom(b []byte, i int) bool { - return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF -} - -// Check if the character at the specified position is space. -func is_space(b []byte, i int) bool { - return b[i] == ' ' -} - -// Check if the character at the specified position is tab. -func is_tab(b []byte, i int) bool { - return b[i] == '\t' -} - -// Check if the character at the specified position is blank (space or tab). -func is_blank(b []byte, i int) bool { - //return is_space(b, i) || is_tab(b, i) - return b[i] == ' ' || b[i] == '\t' -} - -// Check if the character at the specified position is a line break. -func is_break(b []byte, i int) bool { - return (b[i] == '\r' || // CR (#xD) - b[i] == '\n' || // LF (#xA) - b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9) // PS (#x2029) -} - -func is_crlf(b []byte, i int) bool { - return b[i] == '\r' && b[i+1] == '\n' -} - -// Check if the character is a line break or NUL. -func is_breakz(b []byte, i int) bool { - //return is_break(b, i) || is_z(b, i) - return ( // is_break: - b[i] == '\r' || // CR (#xD) - b[i] == '\n' || // LF (#xA) - b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) - // is_z: - b[i] == 0) -} - -// Check if the character is a line break, space, or NUL. -func is_spacez(b []byte, i int) bool { - //return is_space(b, i) || is_breakz(b, i) - return ( // is_space: - b[i] == ' ' || - // is_breakz: - b[i] == '\r' || // CR (#xD) - b[i] == '\n' || // LF (#xA) - b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) - b[i] == 0) -} - -// Check if the character is a line break, space, tab, or NUL. -func is_blankz(b []byte, i int) bool { - //return is_blank(b, i) || is_breakz(b, i) - return ( // is_blank: - b[i] == ' ' || b[i] == '\t' || - // is_breakz: - b[i] == '\r' || // CR (#xD) - b[i] == '\n' || // LF (#xA) - b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) - b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) - b[i] == 0) -} - -// Determine the width of the character. -func width(b byte) int { - // Don't replace these by a switch without first - // confirming that it is being inlined. - if b&0x80 == 0x00 { - return 1 - } - if b&0xE0 == 0xC0 { - return 2 - } - if b&0xF0 == 0xE0 { - return 3 - } - if b&0xF8 == 0xF0 { - return 4 - } - return 0 - -} diff --git a/dev-tools/vendor/vendor.json b/dev-tools/vendor/vendor.json index 55de7c320507..05d976bc13ee 100644 --- a/dev-tools/vendor/vendor.json +++ b/dev-tools/vendor/vendor.json @@ -21,10 +21,6 @@ "revisionTime": "2017-01-17T14:01:51Z" }, { - "checksumSHA1": "yPWWiioidIJuDhVSDe+ogjTmJ18=", - "path": "github.com/tsg/gotpl", - "revision": "a4179fb207b3ef8a96681fc9c9b6e20f99a6d2ef", - "revisionTime": "2015-08-11T13:42:54Z" }, { "checksumSHA1": "TT1rac6kpQp2vz24m5yDGUNQ/QQ=", @@ -75,10 +71,6 @@ "revisionTime": "2017-03-30T16:02:45Z" }, { - "checksumSHA1": "qOmvuDm+F+2nQQecUZBVkZrTn6Y=", - "path": "gopkg.in/yaml.v2", - "revision": "d670f9405373e636a5a2765eea47fac0c9bc91a4", - "revisionTime": "2018-01-09T11:43:31Z" } ], "rootPath": "github.com/elastic/beats/dev-tools" From 413db90bcd84140617d81bdc55cf959055b05c1a Mon Sep 17 00:00:00 2001 From: Andrew Kroh Date: Thu, 7 Jun 2018 19:30:54 -0400 Subject: [PATCH 4/6] Add github.com/tsg/go-daemon to vendor The saves us from having to pull it from Github during builds so it will help with speed and reliability. --- .../vendor/github.com/tsg/go-daemon/LICENSE | 27 ++ .../vendor/github.com/tsg/go-daemon/god.c | 313 ++++++++++++++++++ dev-tools/vendor/vendor.json | 4 + 3 files changed, 344 insertions(+) create mode 100644 dev-tools/vendor/github.com/tsg/go-daemon/LICENSE create mode 100644 dev-tools/vendor/github.com/tsg/go-daemon/god.c diff --git a/dev-tools/vendor/github.com/tsg/go-daemon/LICENSE b/dev-tools/vendor/github.com/tsg/go-daemon/LICENSE new file mode 100644 index 000000000000..168a95e31ffd --- /dev/null +++ b/dev-tools/vendor/github.com/tsg/go-daemon/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2013-2014 Alexandre Fiori. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * The names of authors or contributors may NOT be used to endorse or +promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/dev-tools/vendor/github.com/tsg/go-daemon/god.c b/dev-tools/vendor/github.com/tsg/go-daemon/god.c new file mode 100644 index 000000000000..7f63e081efd9 --- /dev/null +++ b/dev-tools/vendor/github.com/tsg/go-daemon/god.c @@ -0,0 +1,313 @@ +// Copyright 2013-2014 Alexandre Fiori +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +void usage() { + printf( + "Use: god [options] [--] program [arguments]\n" + "Options:\n" + "-h --help show this help and exit\n" + "-v --version show version and exit\n" + "-f --foreground run in foreground\n" + "-n --nohup make the program immune to SIGHUP\n" + "-l --logfile FILE write the program's stdout and stderr to FILE\n" + "-p --pidfile FILE write pid to FILE\n" + "-r --rundir DIR switch to DIR before executing the program\n" + "-u --user USER switch to USER before executing the program\n" + "-g --group GROUP switch to GROUP before executing the program\n" + "\nThe program's output go to a blackhole if no logfile is set.\n" + "Log files are recycled on SIGHUP.\n" + ); + exit(1); +} + +static int nohup = 0; +static int logfd[2]; // pipe +static pid_t childpid = 0; +static FILE *logfp = NULL; +static FILE *pidfp = NULL; +static char logfile[PATH_MAX]; +static char pidfile[PATH_MAX]; +static char linebuf[1024]; +static struct passwd *pwd = NULL; +static struct group *grp = NULL; +static pthread_mutex_t logger_mutex; + +void daemon_main(int optind, char **argv); +void *logger_thread(void *cmdname); +void sighup(int signum); +void sigfwd(int signum); + +int main(int argc, char **argv) { + char rundir[PATH_MAX]; + char user[64]; + char group[64]; + int foreground = 0; + struct stat exec_stat; + + memset(logfile, 0, sizeof logfile); + memset(pidfile, 0, sizeof pidfile); + memset(rundir, 0, sizeof rundir); + memset(user, 0, sizeof user); + memset(group, 0, sizeof group); + + static struct option opts[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'v' }, + { "foreground", no_argument, NULL, 'f' }, + { "nohup", no_argument, NULL, 'n' }, + { "logfile", required_argument, NULL, 'l' }, + { "pidfile", required_argument, NULL, 'p' }, + { "rundir", required_argument, NULL, 'r' }, + { "user", required_argument, NULL, 'u' }, + { "group", required_argument, NULL, 'g' }, + { NULL, 0, NULL, 0 }, + }; + + int ch; + while (1) { + ch = getopt_long(argc, argv, "l:p:r:u:g:hvfns", opts, NULL); + if (ch == -1) + break; + + switch (ch) { + case 'v': + printf("Go daemon v1.2\n"); + printf("http://github.com/fiorix/go-daemon\n"); + return 0; + case 'f': + foreground = 1; + break; + case 'n': + nohup = 1; + break; + case 'l': + strncpy(logfile, optarg, sizeof logfile - 1); + break; + case 'p': + strncpy(pidfile, optarg, sizeof pidfile - 1); + break; + case 'r': + strncpy(rundir, optarg, sizeof rundir - 1); + break; + case 'u': + strncpy(user, optarg, sizeof user - 1); + break; + case 'g': + strncpy(group, optarg, sizeof group - 1); + break; + default: + usage(); + } + } + + // utility is expected to be argv's leftovers. + if (optind >= argc) + usage(); + + if (*rundir != 0 && chdir(rundir) == -1) { + perror("failed to switch to rundir"); + return 1; + } + + if (*user != 0 && (pwd = getpwnam(user)) == NULL) { + fprintf(stderr, "failed to switch to user %s: %s\n", + user, strerror(errno)); + return 1; + } + + if (*group != 0 && (grp = getgrnam(group)) == NULL) { + fprintf(stderr, "failed to switch to group %s: %s\n", + group, strerror(errno)); + return 1; + } + + if (*logfile != 0 && (logfp = fopen(logfile, "a")) == NULL) { + perror("failed to open logfile"); + return 1; + } + if (logfp) + setvbuf(logfp, linebuf, _IOLBF, sizeof linebuf); + + if (*pidfile != 0 && (pidfp = fopen(pidfile, "w+")) == NULL) { + perror("failed to open pidfile"); + return 1; + } + + if (grp != NULL && setegid(grp->gr_gid) == -1) { + fprintf(stderr, "failed to switch to group %s: %s\n", + group, strerror(errno)); + return 1; + } + + if (pwd != NULL && seteuid(pwd->pw_uid) == -1) { + fprintf(stderr, "failed to switch to user %s: %s\n", + user, strerror(errno)); + return 1; + } + + if (stat(argv[optind], &exec_stat) < 0) { + fprintf(stderr, "failed to stat %s: %s\n", + argv[optind], strerror(errno)); + return 1; + } + if (!(exec_stat.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) { + fprintf(stderr, "permission denied: %s\n", + argv[optind]); + return 1; + } + + if (foreground) { + daemon_main(optind, argv); + } else { + // Daemonize. + pid_t pid = fork(); + if (pid) { + waitpid(pid, NULL, 0); + } else if (!pid) { + if ((pid = fork())) { + exit(0); + } else if (!pid) { + close(0); + close(1); + close(2); + daemon_main(optind, argv); + } else { + perror("fork"); + exit(1); + } + } else { + perror("fork"); + exit(1); + } + } + + return 0; +} + +void daemon_main(int optind, char **argv) { + if (pidfp) { + fprintf(pidfp, "%d\n", getpid()); + fclose(pidfp); + } + // Fwd all signals to the child, except SIGHUP. + int signum; + for (signum = 1; signum < 33; signum++) { + if (signal(signum, sigfwd) == SIG_IGN) + signal(signum, SIG_IGN); + } + signal(SIGHUP, sighup); + pipe(logfd); + if ((childpid = fork())) { + close(logfd[1]); + pthread_t logth; + pthread_create(&logth, NULL, logger_thread, argv[optind]); + waitpid(childpid, NULL, 0); + pthread_join(logth, NULL); + } else if (!childpid) { + close(logfd[0]); + close(0); + close(1); + close(2); + dup2(logfd[1], 1); + dup2(logfd[1], 2); + execvp(argv[optind], argv + optind); + printf("\x1b%s", strerror(errno)); + fflush(stdout); + close(logfd[1]); + close(1); + close(2); + } else { + perror("fork"); + exit(1); + } + if (pidfp) + unlink(pidfile); +} + +void *logger_thread(void *cmdname) { + int n; + char buf[4096]; + int has_read = 0; + + while(1) { + // read() will fail when the child process fails + // to execute or dies, and closes its terminal. + // This is what terminates this thread and therefore + // the main thread can move along. + n = read(logfd[0], buf, sizeof buf); + if (n <= 0) + break; + + buf[n] = 0; + if (!has_read) { + has_read = 1; + if (*buf == '\x1b') { + char *p = buf; + printf("%s: %s\n", (char *) cmdname, ++p); + close(logfd[0]); + break; + } + } + + pthread_mutex_lock(&logger_mutex); + if (logfp) { + fwrite(buf, 1, n, logfp); + //fflush(logfp); + } + pthread_mutex_unlock(&logger_mutex); + } + + return NULL; +} + +void sighup(int signum) { + if (pwd != NULL) { + seteuid(getuid()); + } + if (grp != NULL) { + setegid(getgid()); + } + pthread_mutex_lock(&logger_mutex); + if (logfp) { + FILE *fp = fopen(logfile, "a"); + if (fp != NULL) { + fclose(logfp); + logfp = fp; + setvbuf(logfp, linebuf, _IOLBF, sizeof linebuf); + } + } + if (grp != NULL) { + setegid(grp->gr_gid); + } + if (pwd != NULL) { + seteuid(pwd->pw_uid); + } + pthread_mutex_unlock(&logger_mutex); + if (!nohup && childpid) // nonohup :~ + kill(childpid, signum); +} + +void sigfwd(int signum) { + if (childpid) + kill(childpid, signum); +} diff --git a/dev-tools/vendor/vendor.json b/dev-tools/vendor/vendor.json index 05d976bc13ee..8daf6125eeab 100644 --- a/dev-tools/vendor/vendor.json +++ b/dev-tools/vendor/vendor.json @@ -21,6 +21,10 @@ "revisionTime": "2017-01-17T14:01:51Z" }, { + "checksumSHA1": "nlhGP9VLnwbYrykVzBdJMppDrFs=", + "path": "github.com/tsg/go-daemon", + "revision": "c6e0d1a849861166320520e9bae9bbda5f2ecb03", + "revisionTime": "2016-04-14T21:23:35Z" }, { "checksumSHA1": "TT1rac6kpQp2vz24m5yDGUNQ/QQ=", From fe17304ae85dee1a455fb2fe791d2d667d192278 Mon Sep 17 00:00:00 2001 From: Andrew Kroh Date: Thu, 7 Jun 2018 19:31:22 -0400 Subject: [PATCH 5/6] Add golang.org/x/tools/go/vcs to dev-tools/vendor --- dev-tools/vendor/golang.org/x/tools/LICENSE | 27 + dev-tools/vendor/golang.org/x/tools/PATENTS | 22 + .../golang.org/x/tools/go/vcs/discovery.go | 76 ++ .../vendor/golang.org/x/tools/go/vcs/env.go | 39 + .../vendor/golang.org/x/tools/go/vcs/http.go | 80 ++ .../vendor/golang.org/x/tools/go/vcs/vcs.go | 755 ++++++++++++++++++ dev-tools/vendor/vendor.json | 4 + 7 files changed, 1003 insertions(+) create mode 100644 dev-tools/vendor/golang.org/x/tools/LICENSE create mode 100644 dev-tools/vendor/golang.org/x/tools/PATENTS create mode 100644 dev-tools/vendor/golang.org/x/tools/go/vcs/discovery.go create mode 100644 dev-tools/vendor/golang.org/x/tools/go/vcs/env.go create mode 100644 dev-tools/vendor/golang.org/x/tools/go/vcs/http.go create mode 100644 dev-tools/vendor/golang.org/x/tools/go/vcs/vcs.go diff --git a/dev-tools/vendor/golang.org/x/tools/LICENSE b/dev-tools/vendor/golang.org/x/tools/LICENSE new file mode 100644 index 000000000000..6a66aea5eafe --- /dev/null +++ b/dev-tools/vendor/golang.org/x/tools/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/dev-tools/vendor/golang.org/x/tools/PATENTS b/dev-tools/vendor/golang.org/x/tools/PATENTS new file mode 100644 index 000000000000..733099041f84 --- /dev/null +++ b/dev-tools/vendor/golang.org/x/tools/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google 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, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/dev-tools/vendor/golang.org/x/tools/go/vcs/discovery.go b/dev-tools/vendor/golang.org/x/tools/go/vcs/discovery.go new file mode 100644 index 000000000000..f431dc1c5bc3 --- /dev/null +++ b/dev-tools/vendor/golang.org/x/tools/go/vcs/discovery.go @@ -0,0 +1,76 @@ +// 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 vcs + +import ( + "encoding/xml" + "fmt" + "io" + "strings" +) + +// charsetReader returns a reader for the given charset. Currently +// it only supports UTF-8 and ASCII. Otherwise, it returns a meaningful +// error which is printed by go get, so the user can find why the package +// wasn't downloaded if the encoding is not supported. Note that, in +// order to reduce potential errors, ASCII is treated as UTF-8 (i.e. characters +// greater than 0x7f are not rejected). +func charsetReader(charset string, input io.Reader) (io.Reader, error) { + switch strings.ToLower(charset) { + case "ascii": + return input, nil + default: + return nil, fmt.Errorf("can't decode XML document using charset %q", charset) + } +} + +// parseMetaGoImports returns meta imports from the HTML in r. +// Parsing ends at the end of the section or the beginning of the . +func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) { + d := xml.NewDecoder(r) + d.CharsetReader = charsetReader + d.Strict = false + var t xml.Token + for { + t, err = d.Token() + if err != nil { + if err == io.EOF || len(imports) > 0 { + err = nil + } + return + } + if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") { + return + } + if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") { + return + } + e, ok := t.(xml.StartElement) + if !ok || !strings.EqualFold(e.Name.Local, "meta") { + continue + } + if attrValue(e.Attr, "name") != "go-import" { + continue + } + if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 { + imports = append(imports, metaImport{ + Prefix: f[0], + VCS: f[1], + RepoRoot: f[2], + }) + } + } +} + +// attrValue returns the attribute value for the case-insensitive key +// `name', or the empty string if nothing is found. +func attrValue(attrs []xml.Attr, name string) string { + for _, a := range attrs { + if strings.EqualFold(a.Name.Local, name) { + return a.Value + } + } + return "" +} diff --git a/dev-tools/vendor/golang.org/x/tools/go/vcs/env.go b/dev-tools/vendor/golang.org/x/tools/go/vcs/env.go new file mode 100644 index 000000000000..e846f5b3b866 --- /dev/null +++ b/dev-tools/vendor/golang.org/x/tools/go/vcs/env.go @@ -0,0 +1,39 @@ +// Copyright 2013 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 vcs + +import ( + "os" + "strings" +) + +// envForDir returns a copy of the environment +// suitable for running in the given directory. +// The environment is the current process's environment +// but with an updated $PWD, so that an os.Getwd in the +// child will be faster. +func envForDir(dir string) []string { + env := os.Environ() + // Internally we only use rooted paths, so dir is rooted. + // Even if dir is not rooted, no harm done. + return mergeEnvLists([]string{"PWD=" + dir}, env) +} + +// mergeEnvLists merges the two environment lists such that +// variables with the same name in "in" replace those in "out". +func mergeEnvLists(in, out []string) []string { +NextVar: + for _, inkv := range in { + k := strings.SplitAfterN(inkv, "=", 2)[0] + for i, outkv := range out { + if strings.HasPrefix(outkv, k) { + out[i] = inkv + continue NextVar + } + } + out = append(out, inkv) + } + return out +} diff --git a/dev-tools/vendor/golang.org/x/tools/go/vcs/http.go b/dev-tools/vendor/golang.org/x/tools/go/vcs/http.go new file mode 100644 index 000000000000..96188185cb62 --- /dev/null +++ b/dev-tools/vendor/golang.org/x/tools/go/vcs/http.go @@ -0,0 +1,80 @@ +// 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 vcs + +import ( + "fmt" + "io" + "io/ioutil" + "log" + "net/http" + "net/url" +) + +// httpClient is the default HTTP client, but a variable so it can be +// changed by tests, without modifying http.DefaultClient. +var httpClient = http.DefaultClient + +// httpGET returns the data from an HTTP GET request for the given URL. +func httpGET(url string) ([]byte, error) { + resp, err := httpClient.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + return nil, fmt.Errorf("%s: %s", url, resp.Status) + } + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("%s: %v", url, err) + } + return b, nil +} + +// httpsOrHTTP returns the body of either the importPath's +// https resource or, if unavailable, the http resource. +func httpsOrHTTP(importPath string) (urlStr string, body io.ReadCloser, err error) { + fetch := func(scheme string) (urlStr string, res *http.Response, err error) { + u, err := url.Parse(scheme + "://" + importPath) + if err != nil { + return "", nil, err + } + u.RawQuery = "go-get=1" + urlStr = u.String() + if Verbose { + log.Printf("Fetching %s", urlStr) + } + res, err = httpClient.Get(urlStr) + return + } + closeBody := func(res *http.Response) { + if res != nil { + res.Body.Close() + } + } + urlStr, res, err := fetch("https") + if err != nil || res.StatusCode != 200 { + if Verbose { + if err != nil { + log.Printf("https fetch failed.") + } else { + log.Printf("ignoring https fetch with status code %d", res.StatusCode) + } + } + closeBody(res) + urlStr, res, err = fetch("http") + } + if err != nil { + closeBody(res) + return "", nil, err + } + // Note: accepting a non-200 OK here, so people can serve a + // meta import in their http 404 page. + if Verbose { + log.Printf("Parsing meta tags from %s (status code %d)", urlStr, res.StatusCode) + } + return urlStr, res.Body, nil +} diff --git a/dev-tools/vendor/golang.org/x/tools/go/vcs/vcs.go b/dev-tools/vendor/golang.org/x/tools/go/vcs/vcs.go new file mode 100644 index 000000000000..89319be04b90 --- /dev/null +++ b/dev-tools/vendor/golang.org/x/tools/go/vcs/vcs.go @@ -0,0 +1,755 @@ +// 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 vcs exposes functions for resolving import paths +// and using version control systems, which can be used to +// implement behavior similar to the standard "go get" command. +// +// This package is a copy of internal code in package cmd/go/internal/get, +// modified to make the identifiers exported. It's provided here +// for developers who want to write tools with similar semantics. +// It needs to be manually kept in sync with upstream when changes are +// made to cmd/go/internal/get; see https://golang.org/issues/11490. +// +package vcs // import "golang.org/x/tools/go/vcs" + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "log" + "net/url" + "os" + "os/exec" + "path/filepath" + "regexp" + "strconv" + "strings" +) + +// Verbose enables verbose operation logging. +var Verbose bool + +// ShowCmd controls whether VCS commands are printed. +var ShowCmd bool + +// A Cmd describes how to use a version control system +// like Mercurial, Git, or Subversion. +type Cmd struct { + Name string + Cmd string // name of binary to invoke command + + CreateCmd string // command to download a fresh copy of a repository + DownloadCmd string // command to download updates into an existing repository + + TagCmd []TagCmd // commands to list tags + TagLookupCmd []TagCmd // commands to lookup tags before running tagSyncCmd + TagSyncCmd string // command to sync to specific tag + TagSyncDefault string // command to sync to default tag + + LogCmd string // command to list repository changelogs in an XML format + + Scheme []string + PingCmd string +} + +// A TagCmd describes a command to list available tags +// that can be passed to Cmd.TagSyncCmd. +type TagCmd struct { + Cmd string // command to list tags + Pattern string // regexp to extract tags from list +} + +// vcsList lists the known version control systems +var vcsList = []*Cmd{ + vcsHg, + vcsGit, + vcsSvn, + vcsBzr, +} + +// ByCmd returns the version control system for the given +// command name (hg, git, svn, bzr). +func ByCmd(cmd string) *Cmd { + for _, vcs := range vcsList { + if vcs.Cmd == cmd { + return vcs + } + } + return nil +} + +// vcsHg describes how to use Mercurial. +var vcsHg = &Cmd{ + Name: "Mercurial", + Cmd: "hg", + + CreateCmd: "clone -U {repo} {dir}", + DownloadCmd: "pull", + + // We allow both tag and branch names as 'tags' + // for selecting a version. This lets people have + // a go.release.r60 branch and a go1 branch + // and make changes in both, without constantly + // editing .hgtags. + TagCmd: []TagCmd{ + {"tags", `^(\S+)`}, + {"branches", `^(\S+)`}, + }, + TagSyncCmd: "update -r {tag}", + TagSyncDefault: "update default", + + LogCmd: "log --encoding=utf-8 --limit={limit} --template={template}", + + Scheme: []string{"https", "http", "ssh"}, + PingCmd: "identify {scheme}://{repo}", +} + +// vcsGit describes how to use Git. +var vcsGit = &Cmd{ + Name: "Git", + Cmd: "git", + + CreateCmd: "clone {repo} {dir}", + DownloadCmd: "pull --ff-only", + + TagCmd: []TagCmd{ + // tags/xxx matches a git tag named xxx + // origin/xxx matches a git branch named xxx on the default remote repository + {"show-ref", `(?:tags|origin)/(\S+)$`}, + }, + TagLookupCmd: []TagCmd{ + {"show-ref tags/{tag} origin/{tag}", `((?:tags|origin)/\S+)$`}, + }, + TagSyncCmd: "checkout {tag}", + TagSyncDefault: "checkout master", + + Scheme: []string{"git", "https", "http", "git+ssh"}, + PingCmd: "ls-remote {scheme}://{repo}", +} + +// vcsBzr describes how to use Bazaar. +var vcsBzr = &Cmd{ + Name: "Bazaar", + Cmd: "bzr", + + CreateCmd: "branch {repo} {dir}", + + // Without --overwrite bzr will not pull tags that changed. + // Replace by --overwrite-tags after http://pad.lv/681792 goes in. + DownloadCmd: "pull --overwrite", + + TagCmd: []TagCmd{{"tags", `^(\S+)`}}, + TagSyncCmd: "update -r {tag}", + TagSyncDefault: "update -r revno:-1", + + Scheme: []string{"https", "http", "bzr", "bzr+ssh"}, + PingCmd: "info {scheme}://{repo}", +} + +// vcsSvn describes how to use Subversion. +var vcsSvn = &Cmd{ + Name: "Subversion", + Cmd: "svn", + + CreateCmd: "checkout {repo} {dir}", + DownloadCmd: "update", + + // There is no tag command in subversion. + // The branch information is all in the path names. + + LogCmd: "log --xml --limit={limit}", + + Scheme: []string{"https", "http", "svn", "svn+ssh"}, + PingCmd: "info {scheme}://{repo}", +} + +func (v *Cmd) String() string { + return v.Name +} + +// run runs the command line cmd in the given directory. +// keyval is a list of key, value pairs. run expands +// instances of {key} in cmd into value, but only after +// splitting cmd into individual arguments. +// If an error occurs, run prints the command line and the +// command's combined stdout+stderr to standard error. +// Otherwise run discards the command's output. +func (v *Cmd) run(dir string, cmd string, keyval ...string) error { + _, err := v.run1(dir, cmd, keyval, true) + return err +} + +// runVerboseOnly is like run but only generates error output to standard error in verbose mode. +func (v *Cmd) runVerboseOnly(dir string, cmd string, keyval ...string) error { + _, err := v.run1(dir, cmd, keyval, false) + return err +} + +// runOutput is like run but returns the output of the command. +func (v *Cmd) runOutput(dir string, cmd string, keyval ...string) ([]byte, error) { + return v.run1(dir, cmd, keyval, true) +} + +// run1 is the generalized implementation of run and runOutput. +func (v *Cmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([]byte, error) { + m := make(map[string]string) + for i := 0; i < len(keyval); i += 2 { + m[keyval[i]] = keyval[i+1] + } + args := strings.Fields(cmdline) + for i, arg := range args { + args[i] = expand(m, arg) + } + + _, err := exec.LookPath(v.Cmd) + if err != nil { + fmt.Fprintf(os.Stderr, + "go: missing %s command. See http://golang.org/s/gogetcmd\n", + v.Name) + return nil, err + } + + cmd := exec.Command(v.Cmd, args...) + cmd.Dir = dir + cmd.Env = envForDir(cmd.Dir) + if ShowCmd { + fmt.Printf("cd %s\n", dir) + fmt.Printf("%s %s\n", v.Cmd, strings.Join(args, " ")) + } + var buf bytes.Buffer + cmd.Stdout = &buf + cmd.Stderr = &buf + err = cmd.Run() + out := buf.Bytes() + if err != nil { + if verbose || Verbose { + fmt.Fprintf(os.Stderr, "# cd %s; %s %s\n", dir, v.Cmd, strings.Join(args, " ")) + os.Stderr.Write(out) + } + return nil, err + } + return out, nil +} + +// Ping pings the repo to determine if scheme used is valid. +// This repo must be pingable with this scheme and VCS. +func (v *Cmd) Ping(scheme, repo string) error { + return v.runVerboseOnly(".", v.PingCmd, "scheme", scheme, "repo", repo) +} + +// Create creates a new copy of repo in dir. +// The parent of dir must exist; dir must not. +func (v *Cmd) Create(dir, repo string) error { + return v.run(".", v.CreateCmd, "dir", dir, "repo", repo) +} + +// CreateAtRev creates a new copy of repo in dir at revision rev. +// The parent of dir must exist; dir must not. +// rev must be a valid revision in repo. +func (v *Cmd) CreateAtRev(dir, repo, rev string) error { + if err := v.Create(dir, repo); err != nil { + return err + } + return v.run(dir, v.TagSyncCmd, "tag", rev) +} + +// Download downloads any new changes for the repo in dir. +// dir must be a valid VCS repo compatible with v. +func (v *Cmd) Download(dir string) error { + return v.run(dir, v.DownloadCmd) +} + +// Tags returns the list of available tags for the repo in dir. +// dir must be a valid VCS repo compatible with v. +func (v *Cmd) Tags(dir string) ([]string, error) { + var tags []string + for _, tc := range v.TagCmd { + out, err := v.runOutput(dir, tc.Cmd) + if err != nil { + return nil, err + } + re := regexp.MustCompile(`(?m-s)` + tc.Pattern) + for _, m := range re.FindAllStringSubmatch(string(out), -1) { + tags = append(tags, m[1]) + } + } + return tags, nil +} + +// TagSync syncs the repo in dir to the named tag, which is either a +// tag returned by Tags or the empty string (the default tag). +// dir must be a valid VCS repo compatible with v and the tag must exist. +func (v *Cmd) TagSync(dir, tag string) error { + if v.TagSyncCmd == "" { + return nil + } + if tag != "" { + for _, tc := range v.TagLookupCmd { + out, err := v.runOutput(dir, tc.Cmd, "tag", tag) + if err != nil { + return err + } + re := regexp.MustCompile(`(?m-s)` + tc.Pattern) + m := re.FindStringSubmatch(string(out)) + if len(m) > 1 { + tag = m[1] + break + } + } + } + if tag == "" && v.TagSyncDefault != "" { + return v.run(dir, v.TagSyncDefault) + } + return v.run(dir, v.TagSyncCmd, "tag", tag) +} + +// Log logs the changes for the repo in dir. +// dir must be a valid VCS repo compatible with v. +func (v *Cmd) Log(dir, logTemplate string) ([]byte, error) { + if err := v.Download(dir); err != nil { + return []byte{}, err + } + + const N = 50 // how many revisions to grab + return v.runOutput(dir, v.LogCmd, "limit", strconv.Itoa(N), "template", logTemplate) +} + +// LogAtRev logs the change for repo in dir at the rev revision. +// dir must be a valid VCS repo compatible with v. +// rev must be a valid revision for the repo in dir. +func (v *Cmd) LogAtRev(dir, rev, logTemplate string) ([]byte, error) { + if err := v.Download(dir); err != nil { + return []byte{}, err + } + + // Append revision flag to LogCmd. + logAtRevCmd := v.LogCmd + " --rev=" + rev + return v.runOutput(dir, logAtRevCmd, "limit", strconv.Itoa(1), "template", logTemplate) +} + +// A vcsPath describes how to convert an import path into a +// version control system and repository name. +type vcsPath struct { + prefix string // prefix this description applies to + re string // pattern for import path + repo string // repository to use (expand with match of re) + vcs string // version control system to use (expand with match of re) + check func(match map[string]string) error // additional checks + ping bool // ping for scheme to use to download repo + + regexp *regexp.Regexp // cached compiled form of re +} + +// FromDir inspects dir and its parents to determine the +// version control system and code repository to use. +// On return, root is the import path +// corresponding to the root of the repository. +func FromDir(dir, srcRoot string) (vcs *Cmd, root string, err error) { + // Clean and double-check that dir is in (a subdirectory of) srcRoot. + dir = filepath.Clean(dir) + srcRoot = filepath.Clean(srcRoot) + if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator { + return nil, "", fmt.Errorf("directory %q is outside source root %q", dir, srcRoot) + } + + var vcsRet *Cmd + var rootRet string + + origDir := dir + for len(dir) > len(srcRoot) { + for _, vcs := range vcsList { + if _, err := os.Stat(filepath.Join(dir, "."+vcs.Cmd)); err == nil { + root := filepath.ToSlash(dir[len(srcRoot)+1:]) + // Record first VCS we find, but keep looking, + // to detect mistakes like one kind of VCS inside another. + if vcsRet == nil { + vcsRet = vcs + rootRet = root + continue + } + // Allow .git inside .git, which can arise due to submodules. + if vcsRet == vcs && vcs.Cmd == "git" { + continue + } + // Otherwise, we have one VCS inside a different VCS. + return nil, "", fmt.Errorf("directory %q uses %s, but parent %q uses %s", + filepath.Join(srcRoot, rootRet), vcsRet.Cmd, filepath.Join(srcRoot, root), vcs.Cmd) + } + } + + // Move to parent. + ndir := filepath.Dir(dir) + if len(ndir) >= len(dir) { + // Shouldn't happen, but just in case, stop. + break + } + dir = ndir + } + + if vcsRet != nil { + return vcsRet, rootRet, nil + } + + return nil, "", fmt.Errorf("directory %q is not using a known version control system", origDir) +} + +// RepoRoot represents a version control system, a repo, and a root of +// where to put it on disk. +type RepoRoot struct { + VCS *Cmd + + // Repo is the repository URL, including scheme. + Repo string + + // Root is the import path corresponding to the root of the + // repository. + Root string +} + +// RepoRootForImportPath analyzes importPath to determine the +// version control system, and code repository to use. +func RepoRootForImportPath(importPath string, verbose bool) (*RepoRoot, error) { + rr, err := RepoRootForImportPathStatic(importPath, "") + if err == errUnknownSite { + rr, err = RepoRootForImportDynamic(importPath, verbose) + + // RepoRootForImportDynamic returns error detail + // that is irrelevant if the user didn't intend to use a + // dynamic import in the first place. + // Squelch it. + if err != nil { + if Verbose { + log.Printf("import %q: %v", importPath, err) + } + err = fmt.Errorf("unrecognized import path %q", importPath) + } + } + + if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.Root, "...") { + // Do not allow wildcards in the repo root. + rr = nil + err = fmt.Errorf("cannot expand ... in %q", importPath) + } + return rr, err +} + +var errUnknownSite = errors.New("dynamic lookup required to find mapping") + +// RepoRootForImportPathStatic attempts to map importPath to a +// RepoRoot using the commonly-used VCS hosting sites in vcsPaths +// (github.com/user/dir), or from a fully-qualified importPath already +// containing its VCS type (foo.com/repo.git/dir) +// +// If scheme is non-empty, that scheme is forced. +func RepoRootForImportPathStatic(importPath, scheme string) (*RepoRoot, error) { + if strings.Contains(importPath, "://") { + return nil, fmt.Errorf("invalid import path %q", importPath) + } + for _, srv := range vcsPaths { + if !strings.HasPrefix(importPath, srv.prefix) { + continue + } + m := srv.regexp.FindStringSubmatch(importPath) + if m == nil { + if srv.prefix != "" { + return nil, fmt.Errorf("invalid %s import path %q", srv.prefix, importPath) + } + continue + } + + // Build map of named subexpression matches for expand. + match := map[string]string{ + "prefix": srv.prefix, + "import": importPath, + } + for i, name := range srv.regexp.SubexpNames() { + if name != "" && match[name] == "" { + match[name] = m[i] + } + } + if srv.vcs != "" { + match["vcs"] = expand(match, srv.vcs) + } + if srv.repo != "" { + match["repo"] = expand(match, srv.repo) + } + if srv.check != nil { + if err := srv.check(match); err != nil { + return nil, err + } + } + vcs := ByCmd(match["vcs"]) + if vcs == nil { + return nil, fmt.Errorf("unknown version control system %q", match["vcs"]) + } + if srv.ping { + if scheme != "" { + match["repo"] = scheme + "://" + match["repo"] + } else { + for _, scheme := range vcs.Scheme { + if vcs.Ping(scheme, match["repo"]) == nil { + match["repo"] = scheme + "://" + match["repo"] + break + } + } + } + } + rr := &RepoRoot{ + VCS: vcs, + Repo: match["repo"], + Root: match["root"], + } + return rr, nil + } + return nil, errUnknownSite +} + +// RepoRootForImportDynamic finds a *RepoRoot for a custom domain that's not +// statically known by RepoRootForImportPathStatic. +// +// This handles custom import paths like "name.tld/pkg/foo" or just "name.tld". +func RepoRootForImportDynamic(importPath string, verbose bool) (*RepoRoot, error) { + slash := strings.Index(importPath, "/") + if slash < 0 { + slash = len(importPath) + } + host := importPath[:slash] + if !strings.Contains(host, ".") { + return nil, errors.New("import path doesn't contain a hostname") + } + urlStr, body, err := httpsOrHTTP(importPath) + if err != nil { + return nil, fmt.Errorf("http/https fetch: %v", err) + } + defer body.Close() + imports, err := parseMetaGoImports(body) + if err != nil { + return nil, fmt.Errorf("parsing %s: %v", importPath, err) + } + metaImport, err := matchGoImport(imports, importPath) + if err != nil { + if err != errNoMatch { + return nil, fmt.Errorf("parse %s: %v", urlStr, err) + } + return nil, fmt.Errorf("parse %s: no go-import meta tags", urlStr) + } + if verbose { + log.Printf("get %q: found meta tag %#v at %s", importPath, metaImport, urlStr) + } + // If the import was "uni.edu/bob/project", which said the + // prefix was "uni.edu" and the RepoRoot was "evilroot.com", + // make sure we don't trust Bob and check out evilroot.com to + // "uni.edu" yet (possibly overwriting/preempting another + // non-evil student). Instead, first verify the root and see + // if it matches Bob's claim. + if metaImport.Prefix != importPath { + if verbose { + log.Printf("get %q: verifying non-authoritative meta tag", importPath) + } + urlStr0 := urlStr + urlStr, body, err = httpsOrHTTP(metaImport.Prefix) + if err != nil { + return nil, fmt.Errorf("fetch %s: %v", urlStr, err) + } + imports, err := parseMetaGoImports(body) + if err != nil { + return nil, fmt.Errorf("parsing %s: %v", importPath, err) + } + if len(imports) == 0 { + return nil, fmt.Errorf("fetch %s: no go-import meta tag", urlStr) + } + metaImport2, err := matchGoImport(imports, importPath) + if err != nil || metaImport != metaImport2 { + return nil, fmt.Errorf("%s and %s disagree about go-import for %s", urlStr0, urlStr, metaImport.Prefix) + } + } + + if err := validateRepoRoot(metaImport.RepoRoot); err != nil { + return nil, fmt.Errorf("%s: invalid repo root %q: %v", urlStr, metaImport.RepoRoot, err) + } + rr := &RepoRoot{ + VCS: ByCmd(metaImport.VCS), + Repo: metaImport.RepoRoot, + Root: metaImport.Prefix, + } + if rr.VCS == nil { + return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, metaImport.VCS) + } + return rr, nil +} + +// validateRepoRoot returns an error if repoRoot does not seem to be +// a valid URL with scheme. +func validateRepoRoot(repoRoot string) error { + url, err := url.Parse(repoRoot) + if err != nil { + return err + } + if url.Scheme == "" { + return errors.New("no scheme") + } + return nil +} + +// metaImport represents the parsed tags from HTML files. +type metaImport struct { + Prefix, VCS, RepoRoot string +} + +// errNoMatch is returned from matchGoImport when there's no applicable match. +var errNoMatch = errors.New("no import match") + +// matchGoImport returns the metaImport from imports matching importPath. +// An error is returned if there are multiple matches. +// errNoMatch is returned if none match. +func matchGoImport(imports []metaImport, importPath string) (_ metaImport, err error) { + match := -1 + for i, im := range imports { + if !strings.HasPrefix(importPath, im.Prefix) { + continue + } + if match != -1 { + err = fmt.Errorf("multiple meta tags match import path %q", importPath) + return + } + match = i + } + if match == -1 { + err = errNoMatch + return + } + return imports[match], nil +} + +// expand rewrites s to replace {k} with match[k] for each key k in match. +func expand(match map[string]string, s string) string { + for k, v := range match { + s = strings.Replace(s, "{"+k+"}", v, -1) + } + return s +} + +// vcsPaths lists the known vcs paths. +var vcsPaths = []*vcsPath{ + // go.googlesource.com + { + prefix: "go.googlesource.com", + re: `^(?Pgo\.googlesource\.com/[A-Za-z0-9_.\-]+/?)$`, + vcs: "git", + repo: "https://{root}", + check: noVCSSuffix, + }, + + // Github + { + prefix: "github.com/", + re: `^(?Pgithub\.com/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(/[\p{L}0-9_.\-]+)*$`, + vcs: "git", + repo: "https://{root}", + check: noVCSSuffix, + }, + + // Bitbucket + { + prefix: "bitbucket.org/", + re: `^(?Pbitbucket\.org/(?P[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`, + repo: "https://{root}", + check: bitbucketVCS, + }, + + // Launchpad + { + prefix: "launchpad.net/", + re: `^(?Plaunchpad\.net/((?P[A-Za-z0-9_.\-]+)(?P/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`, + vcs: "bzr", + repo: "https://{root}", + check: launchpadVCS, + }, + + // Git at OpenStack + { + prefix: "git.openstack.org", + re: `^(?Pgit\.openstack\.org/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(\.git)?(/[A-Za-z0-9_.\-]+)*$`, + vcs: "git", + repo: "https://{root}", + check: noVCSSuffix, + }, + + // General syntax for any server. + { + re: `^(?P(?P([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?/[A-Za-z0-9_.\-/]*?)\.(?Pbzr|git|hg|svn))(/[A-Za-z0-9_.\-]+)*$`, + ping: true, + }, +} + +func init() { + // fill in cached regexps. + // Doing this eagerly discovers invalid regexp syntax + // without having to run a command that needs that regexp. + for _, srv := range vcsPaths { + srv.regexp = regexp.MustCompile(srv.re) + } +} + +// noVCSSuffix checks that the repository name does not +// end in .foo for any version control system foo. +// The usual culprit is ".git". +func noVCSSuffix(match map[string]string) error { + repo := match["repo"] + for _, vcs := range vcsList { + if strings.HasSuffix(repo, "."+vcs.Cmd) { + return fmt.Errorf("invalid version control suffix in %s path", match["prefix"]) + } + } + return nil +} + +// bitbucketVCS determines the version control system for a +// Bitbucket repository, by using the Bitbucket API. +func bitbucketVCS(match map[string]string) error { + if err := noVCSSuffix(match); err != nil { + return err + } + + var resp struct { + SCM string `json:"scm"` + } + url := expand(match, "https://api.bitbucket.org/1.0/repositories/{bitname}") + data, err := httpGET(url) + if err != nil { + return err + } + if err := json.Unmarshal(data, &resp); err != nil { + return fmt.Errorf("decoding %s: %v", url, err) + } + + if ByCmd(resp.SCM) != nil { + match["vcs"] = resp.SCM + if resp.SCM == "git" { + match["repo"] += ".git" + } + return nil + } + + return fmt.Errorf("unable to detect version control system for bitbucket.org/ path") +} + +// launchpadVCS solves the ambiguity for "lp.net/project/foo". In this case, +// "foo" could be a series name registered in Launchpad with its own branch, +// and it could also be the name of a directory within the main project +// branch one level up. +func launchpadVCS(match map[string]string) error { + if match["project"] == "" || match["series"] == "" { + return nil + } + _, err := httpGET(expand(match, "https://code.launchpad.net/{project}{series}/.bzr/branch-format")) + if err != nil { + match["root"] = expand(match, "launchpad.net/{project}") + match["repo"] = expand(match, "https://{root}") + } + return nil +} diff --git a/dev-tools/vendor/vendor.json b/dev-tools/vendor/vendor.json index 8daf6125eeab..28a187422a03 100644 --- a/dev-tools/vendor/vendor.json +++ b/dev-tools/vendor/vendor.json @@ -75,6 +75,10 @@ "revisionTime": "2017-03-30T16:02:45Z" }, { + "checksumSHA1": "DnH0WldhYTUVJnsx3vlNLP0Yh/A=", + "path": "golang.org/x/tools/go/vcs", + "revision": "a5b4c53f6e8bdcafa95a94671bf2d1203365858b", + "revisionTime": "2018-05-20T07:57:22Z" } ], "rootPath": "github.com/elastic/beats/dev-tools" From 23c4bc042758d5d3096c55d7284871f388387a0e Mon Sep 17 00:00:00 2001 From: Andrew Kroh Date: Thu, 7 Jun 2018 19:29:59 -0400 Subject: [PATCH 6/6] Refactor Beat packaging and cross-building MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This refactors Beat packaging to use a declarative YAML based packaging specification. This makes it easier to customize the contents of packages (e.g. adding additional X-Pack content or simply tailoring what's included for single Beat). The specification itself is pretty simple. It consists of package metadata and a list of files to include. The values can be templated which allows for a single package spec to be reused across Beats. Here's an example spec for an OSS Windows zip package. ``` spec: name: '{{.BeatName}}-oss' service_name: '{{.BeatServiceName}}' os: '{{.GOOS}}' arch: '{{.PackageArch}}' vendor: '{{.BeatVendor}}' version: '{{ beat_version }}' license: ASL 2.0 url: '{{.BeatURL}}' description: '{{.BeatDescription}}' files: '{{.BeatName}}{{.BinaryExt}}': source: build/golang-crossbuild/{{.BeatName}}-{{.GOOS}}-{{.Platform.Arch}}{{.BinaryExt}} mode: 0755 fields.yml: source: fields.yml mode: 0644 LICENSE.txt: source: '{{ repo.RootDir }}/licenses/APACHE-LICENSE-2.0.txt' mode: 0644 NOTICE.txt: source: '{{ repo.RootDir }}/NOTICE.txt' mode: 0644 README.md: template: '{{ elastic_beats_dir }}/dev-tools/mage/templates/common/README.md.tmpl' mode: 0644 .build_hash.txt: content: > {{ commit }} mode: 0644 '{{.BeatName}}.reference.yml': source: '{{.BeatName}}.reference.yml' mode: 0644 '{{.BeatName}}.yml': source: '{{.BeatName}}.yml' mode: 0600 config: true kibana: source: _meta/kibana.generated mode: 0644 install-service-{{.BeatName}}.ps1: template: '{{ elastic_beats_dir }}/dev-tools/mage/templates/windows/install-service.ps1.tmpl' mode: 0755 uninstall-service-{{.BeatName}}.ps1: template: '{{ elastic_beats_dir }}/dev-tools/mage/templates/windows/uninstall-service.ps1.tmpl' mode: 0755 ``` Each Beat has two build targets for packaging. - `make snapshot` - `make release` The set of target platforms can be influenced by the `PLATFORMS` environment variable which accepts an platform selection expression. For example to add ARMv7 (for your Raspberry Pi) to the default set of platforms you would use `PLATFORMS='+linux/armv7' make snapshot`. Or to only build for Windows set `PLATFORMS='windows'`. Full details can be found in the godocs for `NewPlatformList`. For the release manager there are two new top-level targets that take care of ensuring that the proper Go version is used. The naming here aligns with what several of the other projects are using for their release manager targets. - `make release-manager-snapshot` - `make release-manager-release` Build Process Details ---- Below is the command line output of building and packaging Packetbeat for linux/armv7 only. I'll describe each step in the build process. ``` $ PLATFORMS='+all linux/armv7' make snapshot Installing mage from vendor >> golangCrossBuild: Building for linux/armv7 >> buildGoDaemon: Building for linux/armv7 >> Building using: cmd='build/mage-linux-amd64 golangCrossBuild', env=[CC=arm-linux-gnueabihf-gcc, CXX=arm-linux-gnueabihf-g++, GOARCH=arm, GOARM=7, GOOS=linux, PLATFORM_ID=linux-armv7] >> Building using: cmd='build/mage-linux-amd64 buildGoDaemon', env=[CC=arm-linux-gnueabihf-gcc, CXX=arm-linux-gnueabihf-g++, GOARCH=arm, GOARM=7, GOOS=linux, PLATFORM_ID=linux-armv7] grammar.y: warning: 38 shift/reduce conflicts [-Wconflicts-sr] >> package: Building packetbeat type=tar.gz for platform=linux/armv7 >> package: Building packetbeat-oss type=deb for platform=linux/armv7 >> package: Building packetbeat type=rpm for platform=linux/armv7 >> package: Building packetbeat type=deb for platform=linux/armv7 >> package: Building packetbeat-oss type=tar.gz for platform=linux/armv7 >> package: Building packetbeat-oss type=rpm for platform=linux/armv7 >> Testing package contents package ran for 1m6.597416206s $ tree build/distributions/ build/distributions/ ├── packetbeat-oss-7.0.0-alpha1-SNAPSHOT-armhf.deb ├── packetbeat-oss-7.0.0-alpha1-SNAPSHOT-armhf.deb.sha512 ├── packetbeat-oss-7.0.0-alpha1-SNAPSHOT-armhfp.rpm ├── packetbeat-oss-7.0.0-alpha1-SNAPSHOT-armhfp.rpm.sha512 ├── packetbeat-oss-7.0.0-alpha1-SNAPSHOT-linux-armv7.tar.gz └── packetbeat-oss-7.0.0-alpha1-SNAPSHOT-linux-armv7.tar.gz.sha512 ``` 1. Install [mage](https://magefile.org/) from the vendor directory to `$GOPATH/bin`. Mage is used to provide a simple gmake like wrapper around build logic that's written in Go. Additionally it makes is possible to build and package without gmake by invoking mage directly [think Windows users]. For example: ``` $ mage -l Targets: build builds the Beat binary. buildGoDaemon builds the go-daemon binary (use crossBuildGoDaemon). clean cleans all generated files and build artifacts. crossBuild cross-builds the beat for all target platforms. crossBuildGoDaemon cross-builds the go-daemon binary using Docker. golangCrossBuild build the Beat binary inside of the golang-builder. package packages the Beat for distribution. testPackages tests the generated packages (i.e. update updates the generated files (aka make update). ``` 2. Cross-build Packetbeat for linux/armv7. Cross-building requires Docker and uses images hosted at `docker.elastic.co/beats-dev/golang-crossbuild`. The repo for these images is https://github.com/elastic/golang-crossbuild. These images give us wider platform support for cross-building than we had. `mage golangCrossBuild` is invoked inside of the container. This handles cross-compiling libpcap and then invoking `go build` with the proper args. 3. Cross-build go-daemon for linux/armv7. This is actually done in parallel with the other cross-builds. GOMAXPROCS determines the number of concurrent jobs. `mage buildGoDaemon` is invoked inside of the container. 4. After all cross-builds complete, packaging begins. The package types are decided based on the package specs that are registered for each OS. Zip and tar.gz files are built natively with Go. RPM and deb packages are first generated as tar.gz where we have full control over the target file names, ownership, and modes regardless of the underlying filesystem [think Windows]. Then FPM is invoked inside of Docker to translate the tar.gz file into a proper RPM or deb. 5. SHA512 side-car files are generated for each package. Go is used for this so no special command line tools are needed. 6. The generated packages are inspected with `dev-tools/package_test.go`. This looks at the contents of the packages to ensure the files have the expected ownership and modes (e.g. the config file should have 0600). Changes - Add Boot2Docker workaround for shared volume permissions - Mirror the libpcap source to S3 - Use MAX_PARALLEL to control the number of parallel jobs. The default value is the lesser of the NumCPU and NCPU from the Docker daemon. - Add jenkins_package.sh for Jenkins. --- CHANGELOG-developer.asciidoc | 1 + Makefile | 78 +- auditbeat/Makefile | 50 +- auditbeat/magefile.go | 212 +++++ .../_meta/{config.yml.tpl => config.yml.tmpl} | 16 +- .../_meta/{config.yml.tpl => config.yml.tmpl} | 12 +- auditbeat/scripts/generate_config.go | 33 +- dev-tools/common.bash | 4 + dev-tools/deploy | 4 +- dev-tools/jenkins_ci.ps1 | 4 + dev-tools/jenkins_release.sh | 18 + dev-tools/mage/.gitignore | 1 + dev-tools/mage/build.go | 144 ++++ dev-tools/mage/clean.go | 54 ++ dev-tools/mage/common.go | 690 ++++++++++++++++ dev-tools/mage/crossbuild.go | 239 ++++++ .../mage/files/linux/systemd-daemon-reload.sh | 4 + dev-tools/mage/files/packages.yml | 222 +++++ dev-tools/mage/godaemon.go | 72 ++ dev-tools/mage/pkg.go | 108 +++ dev-tools/mage/pkg_test.go | 120 +++ dev-tools/mage/pkgspecs.go | 100 +++ dev-tools/mage/pkgtypes.go | 764 ++++++++++++++++++ dev-tools/mage/platforms.go | 464 +++++++++++ dev-tools/mage/platforms_test.go | 158 ++++ dev-tools/mage/settings.go | 573 +++++++++++++ .../mage/templates/common/README.md.tmpl | 27 + .../mage/templates/common/magefile.go.tmpl | 72 ++ dev-tools/mage/templates/deb/init.sh.tmpl | 188 +++++ .../mage/templates/linux/beatname.sh.tmpl | 11 + .../mage/templates/linux/systemd.unit.tmpl | 12 + dev-tools/mage/templates/rpm/init.sh.tmpl | 119 +++ .../windows/install-service.ps1.tmpl | 14 + .../windows/uninstall-service.ps1.tmpl | 7 + dev-tools/mage/testdata/config.yml | 7 + dev-tools/package_test.go | 2 +- filebeat/Makefile | 6 - filebeat/magefile.go | 88 ++ .../beat/{beat}/{LICENSE => LICENSE.txt} | 0 generator/beat/{beat}/Makefile | 15 +- generator/beat/{beat}/{NOTICE => NOTICE.txt} | 0 generator/beat/{beat}/magefile.go | 91 +++ .../{beat}/{LICENSE => LICENSE.txt} | 0 generator/metricbeat/{beat}/Makefile | 22 +- .../metricbeat/{beat}/{NOTICE => NOTICE.txt} | 0 generator/metricbeat/{beat}/magefile.go | 91 +++ heartbeat/Makefile | 6 - heartbeat/magefile.go | 90 +++ libbeat/scripts/Makefile | 181 +---- magefile.go | 72 ++ metricbeat/Makefile | 12 - metricbeat/magefile.go | 155 ++++ packetbeat/Makefile | 19 - packetbeat/lib/windows-64/.gitignore | 1 + packetbeat/lib/windows-64/sha256 | 1 + packetbeat/lib/windows-64/wpcap.dll | Bin 0 -> 281104 bytes packetbeat/magefile.go | 405 ++++++++++ winlogbeat/Makefile | 11 - winlogbeat/magefile.go | 90 +++ 59 files changed, 5602 insertions(+), 358 deletions(-) create mode 100644 auditbeat/magefile.go rename auditbeat/module/auditd/_meta/{config.yml.tpl => config.yml.tmpl} (65%) rename auditbeat/module/file_integrity/_meta/{config.yml.tpl => config.yml.tmpl} (90%) create mode 100755 dev-tools/jenkins_release.sh create mode 100644 dev-tools/mage/.gitignore create mode 100644 dev-tools/mage/build.go create mode 100644 dev-tools/mage/clean.go create mode 100644 dev-tools/mage/common.go create mode 100644 dev-tools/mage/crossbuild.go create mode 100644 dev-tools/mage/files/linux/systemd-daemon-reload.sh create mode 100644 dev-tools/mage/files/packages.yml create mode 100644 dev-tools/mage/godaemon.go create mode 100644 dev-tools/mage/pkg.go create mode 100644 dev-tools/mage/pkg_test.go create mode 100644 dev-tools/mage/pkgspecs.go create mode 100644 dev-tools/mage/pkgtypes.go create mode 100644 dev-tools/mage/platforms.go create mode 100644 dev-tools/mage/platforms_test.go create mode 100644 dev-tools/mage/settings.go create mode 100644 dev-tools/mage/templates/common/README.md.tmpl create mode 100644 dev-tools/mage/templates/common/magefile.go.tmpl create mode 100644 dev-tools/mage/templates/deb/init.sh.tmpl create mode 100644 dev-tools/mage/templates/linux/beatname.sh.tmpl create mode 100644 dev-tools/mage/templates/linux/systemd.unit.tmpl create mode 100644 dev-tools/mage/templates/rpm/init.sh.tmpl create mode 100644 dev-tools/mage/templates/windows/install-service.ps1.tmpl create mode 100644 dev-tools/mage/templates/windows/uninstall-service.ps1.tmpl create mode 100644 dev-tools/mage/testdata/config.yml create mode 100644 filebeat/magefile.go rename generator/beat/{beat}/{LICENSE => LICENSE.txt} (100%) rename generator/beat/{beat}/{NOTICE => NOTICE.txt} (100%) create mode 100644 generator/beat/{beat}/magefile.go rename generator/metricbeat/{beat}/{LICENSE => LICENSE.txt} (100%) rename generator/metricbeat/{beat}/{NOTICE => NOTICE.txt} (100%) create mode 100644 generator/metricbeat/{beat}/magefile.go create mode 100644 heartbeat/magefile.go create mode 100644 magefile.go create mode 100644 metricbeat/magefile.go create mode 100644 packetbeat/lib/windows-64/.gitignore create mode 100644 packetbeat/lib/windows-64/sha256 create mode 100644 packetbeat/lib/windows-64/wpcap.dll create mode 100644 packetbeat/magefile.go create mode 100644 winlogbeat/magefile.go diff --git a/CHANGELOG-developer.asciidoc b/CHANGELOG-developer.asciidoc index 1f0e0f02e28c..2858f6674057 100644 --- a/CHANGELOG-developer.asciidoc +++ b/CHANGELOG-developer.asciidoc @@ -24,6 +24,7 @@ The list below covers the major changes between 6.3.0 and master only. - Port fields.yml collector to Golang {pull}6911[6911] - Dashboards under _meta/kibana are expected to be decoded. See https://github.com/elastic/beats/pull/7224 for a conversion script. {pull}7265[7265] - Constructor `(github.com/elastic/beats/libbeat/output/codec/json).New` expects a new `escapeHTML` parameter. {pull}7445[7445] +- Packaging has been refactored and updates are required. See the PR for migration details. {pull}7388[7388] ==== Bugfixes diff --git a/Makefile b/Makefile index 1fc93c8947ac..b339d3c819af 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,8 @@ BUILD_DIR=$(CURDIR)/build COVERAGE_DIR=$(BUILD_DIR)/coverage -BEATS=packetbeat filebeat winlogbeat metricbeat heartbeat auditbeat +BEATS?=auditbeat filebeat heartbeat metricbeat packetbeat winlogbeat PROJECTS=libbeat $(BEATS) PROJECTS_ENV=libbeat filebeat metricbeat -SNAPSHOT?=yes PYTHON_ENV?=$(BUILD_DIR)/python-env VIRTUALENV_PARAMS?= FIND=find . -type f -not -path "*/vendor/*" -not -path "*/build/*" -not -path "*/.git/*" @@ -62,6 +61,7 @@ clean: @rm -rf build @$(foreach var,$(PROJECTS),$(MAKE) -C $(var) clean || exit 1;) @$(MAKE) -C generator clean + @-mage -clean 2> /dev/null # Cleans up the vendor directory from unnecessary files # This should always be run after updating the dependencies @@ -109,51 +109,12 @@ lint: @go get $(GOLINT_REPO) $(REVIEWDOG_REPO) $(REVIEWDOG) $(REVIEWDOG_OPTIONS) -# Collects all dashboards and generates dashboard folder for https://github.com/elastic/beats-dashboards/tree/master/dashboards -.PHONY: beats-dashboards -beats-dashboards: - @mkdir -p build/dashboards - @$(foreach var,$(BEATS),cp -r $(var)/_meta/kibana.generated/ build/dashboards/$(var) || exit 1;) - # Builds the documents for each beat .PHONY: docs docs: @$(foreach var,$(PROJECTS),BUILD_DIR=${BUILD_DIR} $(MAKE) -C $(var) docs || exit 1;) sh ./script/build_docs.sh dev-guide github.com/elastic/beats/docs/devguide ${BUILD_DIR} -.PHONY: package-all -package-all: update beats-dashboards - @$(foreach var,$(BEATS),SNAPSHOT=$(SNAPSHOT) $(MAKE) -C $(var) package-all || exit 1;) - - @echo "Start building the dashboards package" - @mkdir -p build/upload/ - @BUILD_DIR=${BUILD_DIR} UPLOAD_DIR=${BUILD_DIR}/upload SNAPSHOT=$(SNAPSHOT) $(MAKE) -C dev-tools/packer package-dashboards ${BUILD_DIR}/upload/build_id.txt - @mv build/upload build/dashboards-upload - - @# Copy build files over to top build directory - @mkdir -p build/upload/ - @$(foreach var,$(BEATS),cp -r $(var)/build/upload/ build/upload/$(var) || exit 1;) - @cp -r build/dashboards-upload build/upload/dashboards - @# Run tests on the generated packages. - @go test ./dev-tools/package_test.go -files "${BUILD_DIR}/upload/*/*" - -# Upload nightly builds to S3 -.PHONY: upload-nightlies-s3 -upload-nightlies-s3: all - aws s3 cp --recursive --acl public-read build/upload s3://beats-nightlies - -# Run after building to sign packages and publish to APT and YUM repos. -.PHONY: package-upload -upload-package: - $(MAKE) -C dev-tools/packer deb-rpm-s3 - # You must export AWS_ACCESS_KEY= and export AWS_SECRET_KEY= - # before running this make target. - dev-tools/packer/docker/deb-rpm-s3/deb-rpm-s3.sh - -.PHONY: release-upload -upload-release: - aws s3 cp --recursive --acl public-read build/upload s3://download.elasticsearch.org/beats/ - .PHONY: notice notice: python-env @echo "Generating NOTICE" @@ -171,3 +132,38 @@ python-env: .PHONY: test-apm test-apm: sh ./script/test_apm.sh + +### Packaging targets #### + +# Builds a snapshot release. +.PHONY: snapshot +snapshot: + @$(MAKE) SNAPSHOT=true release + +# Builds a release. +.PHONY: release +release: beats-dashboards + @$(foreach var,$(BEATS),$(MAKE) -C $(var) release || exit 1;) + @$(foreach var,$(BEATS),mkdir -p build/distributions/$(var) && mv -f $(var)/build/distributions/* build/distributions/$(var)/ || exit 1;) + +# Builds a snapshot release. The Go version defined in .go-version will be +# installed and used for the build. +.PHONY: release-manager-snapshot +release-manager-snapshot: + ./dev-tools/run_with_go_ver $(MAKE) snapshot + +# Builds a snapshot release. The Go version defined in .go-version will be +# installed and used for the build. +.PHONY: release-manager-release +release-manager-release: + ./dev-tools/run_with_go_ver $(MAKE) release + +# Installs the mage build tool from the vendor directory. +.PHONY: mage +mage: + @go install github.com/elastic/beats/vendor/github.com/magefile/mage + +# Collects dashboards from all Beats and generates a zip file distribution. +.PHONY: beats-dashboards +beats-dashboards: mage update + @mage packageBeatDashboards diff --git a/auditbeat/Makefile b/auditbeat/Makefile index e453ca16cb0d..36c51fbf0e62 100644 --- a/auditbeat/Makefile +++ b/auditbeat/Makefile @@ -1,6 +1,5 @@ BEAT_NAME=auditbeat BEAT_TITLE=Auditbeat -BEAT_DESCRIPTION=Audit the activities of users and processes on your system. SYSTEM_TESTS=true TEST_ENVIRONMENT?=true GOX_OS?=linux windows ## @Building List of all OS to be supported by "make crosscompile". @@ -12,49 +11,6 @@ FIELDS_FILE_PATH=module # Path to the libbeat Makefile include ${ES_BEATS}/libbeat/scripts/Makefile -# This is called by the beats packer before building starts -.PHONY: before-build -before-build: - @cat ${ES_BEATS}/auditbeat/_meta/common.p1.yml \ - <(go run scripts/generate_config.go -os windows -concat) \ - ${ES_BEATS}/auditbeat/_meta/common.p2.yml \ - ${ES_BEATS}/libbeat/_meta/config.yml > \ - ${PREFIX}/${BEAT_NAME}-win.yml - @cat ${ES_BEATS}/auditbeat/_meta/common.reference.yml \ - <(go run scripts/generate_config.go -os windows -concat -ref) \ - ${ES_BEATS}/libbeat/_meta/config.reference.yml > \ - ${PREFIX}/${BEAT_NAME}-win.reference.yml - - @cat ${ES_BEATS}/auditbeat/_meta/common.p1.yml \ - <(go run scripts/generate_config.go -os darwin -concat) \ - ${ES_BEATS}/auditbeat/_meta/common.p2.yml \ - ${ES_BEATS}/libbeat/_meta/config.yml > \ - ${PREFIX}/${BEAT_NAME}-darwin.yml - @cat ${ES_BEATS}/auditbeat/_meta/common.reference.yml \ - <(go run scripts/generate_config.go -os darwin -concat -ref) \ - ${ES_BEATS}/libbeat/_meta/config.reference.yml > \ - ${PREFIX}/${BEAT_NAME}-darwin.reference.yml - - @cat ${ES_BEATS}/auditbeat/_meta/common.p1.yml \ - <(go run scripts/generate_config.go -os linux -arch amd64 -concat) \ - ${ES_BEATS}/auditbeat/_meta/common.p2.yml \ - ${ES_BEATS}/libbeat/_meta/config.yml > \ - ${PREFIX}/${BEAT_NAME}-linux.yml - @cat ${ES_BEATS}/auditbeat/_meta/common.reference.yml \ - <(go run scripts/generate_config.go -os linux -concat -ref) \ - ${ES_BEATS}/libbeat/_meta/config.reference.yml > \ - ${PREFIX}/${BEAT_NAME}-linux.reference.yml - - @cat ${ES_BEATS}/auditbeat/_meta/common.p1.yml \ - <(go run scripts/generate_config.go -os linux -arch i386 -concat) \ - ${ES_BEATS}/auditbeat/_meta/common.p2.yml \ - ${ES_BEATS}/libbeat/_meta/config.yml > \ - ${PREFIX}/${BEAT_NAME}-linux-386.yml - @cat ${ES_BEATS}/auditbeat/_meta/common.reference.yml \ - <(go run scripts/generate_config.go -os linux -concat -ref) \ - ${ES_BEATS}/libbeat/_meta/config.reference.yml > \ - ${PREFIX}/${BEAT_NAME}-linux-386.reference.yml - # Collects all dependencies and then calls update .PHONY: collect collect: fields collect-docs configs kibana @@ -63,10 +19,10 @@ collect: fields collect-docs configs kibana .PHONY: configs configs: python-env @cat ${ES_BEATS}/auditbeat/_meta/common.p1.yml \ - <(go run scripts/generate_config.go -os ${DEV_OS} -concat) \ - ${ES_BEATS}/auditbeat/_meta/common.p2.yml > _meta/beat.yml + <(go run scripts/generate_config.go -os ${DEV_OS} -concat) \ + ${ES_BEATS}/auditbeat/_meta/common.p2.yml > _meta/beat.yml @cat ${ES_BEATS}/auditbeat/_meta/common.reference.yml \ - <(go run scripts/generate_config.go -os ${DEV_OS} -ref -concat) > _meta/beat.reference.yml + <(go run scripts/generate_config.go -os ${DEV_OS} -ref -concat) > _meta/beat.reference.yml # Collects all module docs .PHONY: collect-docs diff --git a/auditbeat/magefile.go b/auditbeat/magefile.go new file mode 100644 index 000000000000..9f1723917d40 --- /dev/null +++ b/auditbeat/magefile.go @@ -0,0 +1,212 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +// +build mage + +package main + +import ( + "fmt" + "regexp" + "time" + + "github.com/magefile/mage/mg" + "github.com/magefile/mage/sh" + "github.com/pkg/errors" + + "github.com/elastic/beats/dev-tools/mage" +) + +func init() { + mage.BeatDescription = "Audit the activities of users and processes on your system." +} + +// Build builds the Beat binary. +func Build() error { + return mage.Build(mage.DefaultBuildArgs()) +} + +// GolangCrossBuild build the Beat binary inside of the golang-builder. +// Do not use directly, use crossBuild instead. +func GolangCrossBuild() error { + return mage.GolangCrossBuild(mage.DefaultGolangCrossBuildArgs()) +} + +// BuildGoDaemon builds the go-daemon binary (use crossBuildGoDaemon). +func BuildGoDaemon() error { + return mage.BuildGoDaemon() +} + +// CrossBuild cross-builds the beat for all target platforms. +func CrossBuild() error { + return mage.CrossBuild() +} + +// CrossBuildGoDaemon cross-builds the go-daemon binary using Docker. +func CrossBuildGoDaemon() error { + return mage.CrossBuildGoDaemon() +} + +// Clean cleans all generated files and build artifacts. +func Clean() error { + return mage.Clean() +} + +// Package packages the Beat for distribution. +// Use SNAPSHOT=true to build snapshots. +// Use PLATFORMS to control the target platforms. +func Package() { + start := time.Now() + defer func() { fmt.Println("package ran for", time.Since(start)) }() + + mage.UseElasticBeatPackaging() + customizePackaging() + + mg.Deps(Update) + mg.Deps(makeConfigTemplates, CrossBuild, CrossBuildGoDaemon) + mg.SerialDeps(mage.Package, TestPackages) +} + +// TestPackages tests the generated packages (i.e. file modes, owners, groups). +func TestPackages() error { + return mage.TestPackages() +} + +// Update updates the generated files (aka make update). +func Update() error { + return sh.Run("make", "update") +} + +// ----------------------------------------------------------------------------- +// Customizations specific to Auditbeat. +// - Config files are Go templates. + +const ( + configTemplateGlob = "module/*/_meta/config*.yml.tmpl" + shortConfigTemplate = "build/auditbeat.yml.tmpl" + referenceConfigTemplate = "build/auditbeat.reference.yml.tmpl" +) + +func makeConfigTemplates() error { + configFiles, err := mage.FindFiles(configTemplateGlob) + if err != nil { + return errors.Wrap(err, "failed to find config templates") + } + + var shortIn []string + shortIn = append(shortIn, "_meta/common.p1.yml") + shortIn = append(shortIn, configFiles...) + shortIn = append(shortIn, "_meta/common.p2.yml") + shortIn = append(shortIn, "../libbeat/_meta/config.yml") + if !mage.IsUpToDate(shortConfigTemplate, shortIn...) { + fmt.Println(">> Building", shortConfigTemplate) + mage.MustFileConcat(shortConfigTemplate, 0600, shortIn...) + mage.MustFindReplace(shortConfigTemplate, regexp.MustCompile("beatname"), "{{.BeatName}}") + mage.MustFindReplace(shortConfigTemplate, regexp.MustCompile("beat-index-prefix"), "{{.BeatIndexPrefix}}") + } + + var referenceIn []string + referenceIn = append(referenceIn, "_meta/common.reference.yml") + referenceIn = append(referenceIn, configFiles...) + referenceIn = append(referenceIn, "../libbeat/_meta/config.reference.yml") + if !mage.IsUpToDate(referenceConfigTemplate, referenceIn...) { + fmt.Println(">> Building", referenceConfigTemplate) + mage.MustFileConcat(referenceConfigTemplate, 0644, referenceIn...) + mage.MustFindReplace(referenceConfigTemplate, regexp.MustCompile("beatname"), "{{.BeatName}}") + mage.MustFindReplace(referenceConfigTemplate, regexp.MustCompile("beat-index-prefix"), "{{.BeatIndexPrefix}}") + } + + return nil +} + +// customizePackaging modifies the package specs to use templated config files +// instead of the defaults. +func customizePackaging() { + var ( + shortConfig = mage.PackageFile{ + Mode: 0600, + Source: "{{.PackageDir}}/auditbeat.yml", + Dep: generateShortConfig, + } + referenceConfig = mage.PackageFile{ + Mode: 0644, + Source: "{{.PackageDir}}/auditbeat.reference.yml", + Dep: generateReferenceConfig, + } + ) + + for _, args := range mage.Packages { + switch args.Types[0] { + case mage.TarGz, mage.Zip: + args.Spec.ReplaceFile("{{.BeatName}}.yml", shortConfig) + args.Spec.ReplaceFile("{{.BeatName}}.reference.yml", referenceConfig) + default: + args.Spec.ReplaceFile("/etc/{{.BeatName}}/{{.BeatName}}.yml", shortConfig) + args.Spec.ReplaceFile("/etc/{{.BeatName}}/{{.BeatName}}.reference.yml", referenceConfig) + } + } +} + +func generateReferenceConfig(spec mage.PackageSpec) error { + params := map[string]interface{}{ + "Reference": true, + "ArchBits": archBits, + } + return spec.ExpandFile(referenceConfigTemplate, + "{{.PackageDir}}/auditbeat.reference.yml", params) +} + +func generateShortConfig(spec mage.PackageSpec) error { + params := map[string]interface{}{ + "Reference": false, + "ArchBits": archBits, + } + return spec.ExpandFile(shortConfigTemplate, + "{{.PackageDir}}/auditbeat.yml", params) +} + +// archBits returns the number of bit width of the GOARCH architecture value. +// This function is used by the auditd module configuration templates to +// generate architecture specific audit rules. +func archBits(goarch string) int { + switch goarch { + case "386", "arm": + return 32 + default: + return 64 + } +} + +// Configs generates the auditbeat.yml and auditbeat.reference.yml config files. +// Set DEV_OS and DEV_ARCH to change the target host for the generated configs. +// Defaults to linux/amd64. +func Configs() { + mg.Deps(makeConfigTemplates) + + params := map[string]interface{}{ + "GOOS": mage.EnvOr("DEV_OS", "linux"), + "GOARCH": mage.EnvOr("DEV_ARCH", "amd64"), + "ArchBits": archBits, + "Reference": false, + } + fmt.Printf(">> Building auditbeat.yml for %v/%v\n", params["GOOS"], params["GOARCH"]) + mage.MustExpandFile(shortConfigTemplate, "auditbeat.yml", params) + + params["Reference"] = true + fmt.Printf(">> Building auditbeat.reference.yml for %v/%v\n", params["GOOS"], params["GOARCH"]) + mage.MustExpandFile(referenceConfigTemplate, "auditbeat.reference.yml", params) +} diff --git a/auditbeat/module/auditd/_meta/config.yml.tpl b/auditbeat/module/auditd/_meta/config.yml.tmpl similarity index 65% rename from auditbeat/module/auditd/_meta/config.yml.tpl rename to auditbeat/module/auditd/_meta/config.yml.tmpl index 30cb58df8423..ac1d21fa6cd0 100644 --- a/auditbeat/module/auditd/_meta/config.yml.tpl +++ b/auditbeat/module/auditd/_meta/config.yml.tmpl @@ -1,10 +1,10 @@ -{{ if eq .goos "linux" -}} -{{ if .reference -}} +{{ if eq .GOOS "linux" -}} +{{ if .Reference -}} # The auditd module collects events from the audit framework in the Linux # kernel. You need to specify audit rules for the events that you want to audit. {{ end -}} - module: auditd - {{ if .reference -}} + {{ if .Reference -}} resolve_ids: true failure_mode: silent backlog_limit: 8196 @@ -17,7 +17,7 @@ ## Create file watches (-w) or syscall audits (-a or -A). Uncomment these ## examples or add your own rules. - {{ if eq .goarch "amd64" -}} + {{ if eq .GOARCH "amd64" -}} ## If you are on a 64 bit platform, everything should be running ## in 64 bit mode. This rule will detect any use of the 32 bit syscalls ## because this might be a sign of someone exploiting a hole in the 32 @@ -26,10 +26,10 @@ {{ end -}} ## Executions. - #-a always,exit -F arch=b{{.arch_bits}} -S execve,execveat -k exec + #-a always,exit -F arch=b{{call .ArchBits .GOARCH}} -S execve,execveat -k exec ## External access (warning: these can be expensive to audit). - #-a always,exit -F arch=b{{.arch_bits}} -S accept,bind,connect -F key=external-access + #-a always,exit -F arch=b{{call .ArchBits .GOARCH}} -S accept,bind,connect -F key=external-access ## Identity changes. #-w /etc/group -p wa -k identity @@ -37,6 +37,6 @@ #-w /etc/gshadow -p wa -k identity ## Unauthorized access attempts. - #-a always,exit -F arch=b{{.arch_bits}} -S open,creat,truncate,ftruncate,openat,open_by_handle_at -F exit=-EACCES -k access - #-a always,exit -F arch=b{{.arch_bits}} -S open,creat,truncate,ftruncate,openat,open_by_handle_at -F exit=-EPERM -k access + #-a always,exit -F arch=b{{call .ArchBits .GOARCH}} -S open,creat,truncate,ftruncate,openat,open_by_handle_at -F exit=-EACCES -k access + #-a always,exit -F arch=b{{call .ArchBits .GOARCH}} -S open,creat,truncate,ftruncate,openat,open_by_handle_at -F exit=-EPERM -k access {{ end -}} diff --git a/auditbeat/module/file_integrity/_meta/config.yml.tpl b/auditbeat/module/file_integrity/_meta/config.yml.tmpl similarity index 90% rename from auditbeat/module/file_integrity/_meta/config.yml.tpl rename to auditbeat/module/file_integrity/_meta/config.yml.tmpl index 18f84a6f8a41..774a430eba32 100644 --- a/auditbeat/module/file_integrity/_meta/config.yml.tpl +++ b/auditbeat/module/file_integrity/_meta/config.yml.tmpl @@ -1,9 +1,9 @@ -{{ if .reference -}} +{{ if .Reference -}} # The file integrity module sends events when files are changed (created, # updated, deleted). The events contain file metadata and hashes. {{ end -}} - module: file_integrity - {{ if eq .goos "darwin" -}} + {{ if eq .GOOS "darwin" -}} paths: - /bin - /usr/bin @@ -11,7 +11,7 @@ - /sbin - /usr/sbin - /usr/local/sbin - {{ else if eq .goos "windows" -}} + {{ else if eq .GOOS "windows" -}} paths: - C:/windows - C:/windows/system32 @@ -25,15 +25,15 @@ - /usr/sbin - /etc {{- end }} -{{ if .reference }} +{{ if .Reference }} # List of regular expressions to filter out notifications for unwanted files. # Wrap in single quotes to workaround YAML escaping rules. By default no files # are ignored. - {{ if eq .goos "darwin" -}} + {{ if eq .GOOS "darwin" -}} exclude_files: - '\.DS_Store$' - '\.swp$' - {{ else if eq .goos "windows" -}} + {{ else if eq .GOOS "windows" -}} exclude_files: - '(?i)\.lnk$' - '(?i)\.swp$' diff --git a/auditbeat/scripts/generate_config.go b/auditbeat/scripts/generate_config.go index 60dc006eaa14..ef8f82928ff2 100644 --- a/auditbeat/scripts/generate_config.go +++ b/auditbeat/scripts/generate_config.go @@ -31,7 +31,7 @@ import ( "github.com/pkg/errors" ) -const defaultGlob = "module/*/_meta/config*.yml.tpl" +const defaultGlob = "module/*/_meta/config*.yml.tmpl" var ( goos = flag.String("os", runtime.GOOS, "generate config specific to the specified operating system") @@ -52,26 +52,29 @@ func findConfigFiles(globs []string) ([]string, error) { return configFiles, nil } +// archBits returns the number of bit width of the GOARCH architecture value. +// This function is used by the auditd module configuration templates to +// generate architecture specific audit rules. +func archBits(goarch string) int { + switch goarch { + case "386", "arm": + return 32 + default: + return 64 + } +} + func getConfig(file string) ([]byte, error) { tpl, err := template.ParseFiles(file) if err != nil { return nil, errors.Wrapf(err, "failed reading %v", file) } - var archBits string - switch *goarch { - case "i386": - archBits = "32" - case "amd64": - archBits = "64" - default: - return nil, fmt.Errorf("supporting only i386 and amd64 architecture") - } data := map[string]interface{}{ - "goarch": *goarch, - "goos": *goos, - "reference": *reference, - "arch_bits": archBits, + "GOARCH": *goarch, + "GOOS": *goos, + "Reference": *reference, + "ArchBits": archBits, } buf := new(bytes.Buffer) if err = tpl.Execute(buf, data); err != nil { @@ -126,7 +129,7 @@ func main() { if *concat { segments = append(segments, segment) } else { - output(segment, strings.TrimSuffix(file, ".tpl")) + output(segment, strings.TrimSuffix(file, ".tmpl")) } } diff --git a/dev-tools/common.bash b/dev-tools/common.bash index 048c835f2c00..cb8a8d5c0863 100644 --- a/dev-tools/common.bash +++ b/dev-tools/common.bash @@ -91,4 +91,8 @@ jenkins_setup() { # Workaround for Python virtualenv path being too long. export TEMP_PYTHON_ENV=$(mktemp -d) export PYTHON_ENV="${TEMP_PYTHON_ENV}/python-env" + + # Write cached magefile binaries to workspace to ensure + # each run starts from a clean slate. + export MAGEFILE_CACHE="${WORKSPACE}/.magefile" } diff --git a/dev-tools/deploy b/dev-tools/deploy index 812a003439d2..2b0de52e4c08 100755 --- a/dev-tools/deploy +++ b/dev-tools/deploy @@ -16,9 +16,9 @@ def main(): check_call("make clean", shell=True) print("Done building Docker images.") if args.no_snapshot: - check_call("make SNAPSHOT=no package-all", shell=True) + check_call("make release", shell=True) else: - check_call("make SNAPSHOT=yes package-all", shell=True) + check_call("make snapshot", shell=True) print("All done") if __name__ == "__main__": diff --git a/dev-tools/jenkins_ci.ps1 b/dev-tools/jenkins_ci.ps1 index 4db34c03bc8c..a27381a36e99 100755 --- a/dev-tools/jenkins_ci.ps1 +++ b/dev-tools/jenkins_ci.ps1 @@ -17,6 +17,10 @@ $env:GOPATH = $env:WORKSPACE $env:PATH = "$env:GOPATH\bin;C:\tools\mingw64\bin;$env:PATH" & gvm --format=powershell $(Get-Content .go-version) | Invoke-Expression +# Write cached magefile binaries to workspace to ensure +# each run starts from a clean slate. +$env:MAGEFILE_CACHE = "$env:WORKSPACE\.magefile" + if (Test-Path "$env:beat") { cd "$env:beat" } else { diff --git a/dev-tools/jenkins_release.sh b/dev-tools/jenkins_release.sh new file mode 100755 index 000000000000..a0915a7fe739 --- /dev/null +++ b/dev-tools/jenkins_release.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euox pipefail + +: "${HOME:?Need to set HOME to a non-empty value.}" +: "${WORKSPACE:?Need to set WORKSPACE to a non-empty value.}" + +source ./dev-tools/common.bash + +jenkins_setup + +cleanup() { + echo "Running cleanup..." + rm -rf $TEMP_PYTHON_ENV + echo "Cleanup complete." +} +trap cleanup EXIT + +make release diff --git a/dev-tools/mage/.gitignore b/dev-tools/mage/.gitignore new file mode 100644 index 000000000000..378eac25d311 --- /dev/null +++ b/dev-tools/mage/.gitignore @@ -0,0 +1 @@ +build diff --git a/dev-tools/mage/build.go b/dev-tools/mage/build.go new file mode 100644 index 000000000000..86bd420930c4 --- /dev/null +++ b/dev-tools/mage/build.go @@ -0,0 +1,144 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +package mage + +import ( + "fmt" + "go/build" + "log" + "os" + "path/filepath" + "strings" + + "github.com/magefile/mage/sh" + "github.com/pkg/errors" +) + +// BuildArgs are the arguments used for the "build" target and they define how +// "go build" is invoked. +type BuildArgs struct { + Name string // Name of binary. (On Windows '.exe' is appended.) + OutputDir string + CGO bool + Static bool + Env map[string]string + LDFlags []string + Vars map[string]string // Vars that are passed as -X key=value with the ldflags. + ExtraFlags []string +} + +// DefaultBuildArgs returns the default BuildArgs for use in builds. +func DefaultBuildArgs() BuildArgs { + args := BuildArgs{ + Name: BeatName, + CGO: build.Default.CgoEnabled, + Vars: map[string]string{ + "github.com/elastic/beats/libbeat/version.buildTime": "{{ date }}", + "github.com/elastic/beats/libbeat/version.commit": "{{ commit }}", + }, + } + + repo, err := GetProjectRepoInfo() + if err != nil { + panic(errors.Wrap(err, "failed to determine project repo info")) + } + + if !repo.IsElasticBeats() { + // Assume libbeat is vendored and prefix the variables. + prefix := repo.RootImportPath + "/vendor/" + prefixedVars := map[string]string{} + for k, v := range args.Vars { + prefixedVars[prefix+k] = v + } + args.Vars = prefixedVars + } + + return args +} + +// DefaultGolangCrossBuildArgs returns the default BuildArgs for use in +// cross-builds. +func DefaultGolangCrossBuildArgs() BuildArgs { + args := DefaultBuildArgs() + args.Name += "-" + Platform.GOOS + "-" + Platform.Arch + args.OutputDir = filepath.Join("build", "golang-crossbuild") + if bp, found := BuildPlatforms.Get(Platform.Name); found { + args.CGO = bp.Flags.SupportsCGO() + } + return args +} + +// GolangCrossBuild invokes "go build" inside of the golang-crossbuild Docker +// environment. +func GolangCrossBuild(params BuildArgs) error { + if os.Getenv("GOLANG_CROSSBUILD") != "1" { + return errors.New("Use the crossBuild target. golangCrossBuild can " + + "only be executed within the golang-crossbuild docker environment.") + } + + defer DockerChown(filepath.Join(params.OutputDir, params.Name+binaryExtension(GOOS))) + return Build(params) +} + +// Build invokes "go build" to produce a binary. +func Build(params BuildArgs) error { + fmt.Println(">> build: Building", params.Name) + + binaryName := params.Name + binaryExtension(GOOS) + + if params.OutputDir != "" { + if err := os.MkdirAll(params.OutputDir, 0755); err != nil { + return err + } + } + + // Environment + env := params.Env + if env == nil { + env = map[string]string{} + } + cgoEnabled := "0" + if params.CGO { + cgoEnabled = "1" + } + env["CGO_ENABLED"] = cgoEnabled + + // Spec + args := []string{ + "build", + "-o", + filepath.Join(params.OutputDir, binaryName), + } + args = append(args, params.ExtraFlags...) + + // ldflags + ldflags := params.LDFlags + if params.Static { + ldflags = append(ldflags, `-extldflags '-static'`) + } + for k, v := range params.Vars { + ldflags = append(ldflags, fmt.Sprintf("-X %v=%v", k, v)) + } + if len(ldflags) > 0 { + args = append(args, "-ldflags") + args = append(args, MustExpand(strings.Join(ldflags, " "))) + } + + log.Println("Adding build environment vars:", env) + return sh.RunWith(env, "go", args...) +} diff --git a/dev-tools/mage/clean.go b/dev-tools/mage/clean.go new file mode 100644 index 000000000000..912d372e1dff --- /dev/null +++ b/dev-tools/mage/clean.go @@ -0,0 +1,54 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +package mage + +import ( + "github.com/magefile/mage/sh" +) + +// DefaultCleanPaths specifies a list of files or paths to recursively delete. +// The values may contain variables and will be expanded at the time of use. +var DefaultCleanPaths = []string{ + "build", + "docker-compose.yml.lock", + "{{.BeatName}}", + "{{.BeatName}}.exe", + "{{.BeatName}}.test", + "{{.BeatName}}.test.exe", + "fields.yml", + "_meta/fields.generated.yml", + "_meta/kibana.generated", + "_meta/kibana/5/index-pattern/{{.BeatName}}.json", + "_meta/kibana/6/index-pattern/{{.BeatName}}.json", +} + +// Clean clean generated build artifacts. +func Clean(pathLists ...[]string) error { + if len(pathLists) == 0 { + pathLists = [][]string{DefaultCleanPaths} + } + for _, paths := range pathLists { + for _, f := range paths { + f = MustExpand(f) + if err := sh.Rm(f); err != nil { + return err + } + } + } + return nil +} diff --git a/dev-tools/mage/common.go b/dev-tools/mage/common.go new file mode 100644 index 000000000000..1ab47d6b5ded --- /dev/null +++ b/dev-tools/mage/common.go @@ -0,0 +1,690 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +package mage + +import ( + "archive/tar" + "archive/zip" + "bufio" + "bytes" + "compress/gzip" + "context" + "crypto/sha256" + "crypto/sha512" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "log" + "net/http" + "os" + "path/filepath" + "regexp" + "runtime" + "strconv" + "strings" + "sync" + "text/template" + "time" + "unicode" + + "github.com/magefile/mage/sh" + "github.com/magefile/mage/target" + "github.com/magefile/mage/types" + "github.com/pkg/errors" +) + +// Expand expands the given Go text/template string. +func Expand(in string, args ...map[string]interface{}) (string, error) { + return expandTemplate("inline", in, FuncMap, EnvMap(args...)) +} + +// MustExpand expands the given Go text/template string. It panics if there is +// an error. +func MustExpand(in string, args ...map[string]interface{}) string { + out, err := Expand(in, args...) + if err != nil { + panic(err) + } + return out +} + +// ExpandFile expands the Go text/template read from src and writes the output +// to dst. +func ExpandFile(src, dst string, args ...map[string]interface{}) error { + return expandFile(src, dst, EnvMap(args...)) +} + +// MustExpandFile expands the Go text/template read from src and writes the +// output to dst. It panics if there is an error. +func MustExpandFile(src, dst string, args ...map[string]interface{}) { + if err := ExpandFile(src, dst, args...); err != nil { + panic(err) + } +} + +func expandTemplate(name, tmpl string, funcs template.FuncMap, args ...map[string]interface{}) (string, error) { + t := template.New(name).Option("missingkey=error") + if len(funcs) > 0 { + t = t.Funcs(funcs) + } + + t, err := t.Parse(tmpl) + if err != nil { + if name == "inline" { + return "", errors.Wrapf(err, "failed to parse template '%v'", tmpl) + } + return "", errors.Wrap(err, "failed to parse template") + } + + buf := new(bytes.Buffer) + if err := t.Execute(buf, joinMaps(args...)); err != nil { + if name == "inline" { + return "", errors.Wrapf(err, "failed to expand template '%v'", tmpl) + } + return "", errors.Wrap(err, "failed to expand template") + } + + return buf.String(), nil +} + +func joinMaps(args ...map[string]interface{}) map[string]interface{} { + switch len(args) { + case 0: + return nil + case 1: + return args[0] + } + + var out map[string]interface{} + for _, m := range args { + for k, v := range m { + out[k] = v + } + } + return out +} + +func expandFile(src, dst string, args ...map[string]interface{}) error { + tmplData, err := ioutil.ReadFile(src) + if err != nil { + return errors.Wrapf(err, "failed reading from template %v", src) + } + + output, err := expandTemplate(src, string(tmplData), FuncMap, args...) + if err != nil { + return err + } + + dst, err = expandTemplate("inline", dst, FuncMap, args...) + if err != nil { + return err + } + + if err = ioutil.WriteFile(createDir(dst), []byte(output), 0644); err != nil { + return errors.Wrap(err, "failed to write rendered template") + } + + return nil +} + +// CWD return the current working directory. +func CWD() string { + wd, err := os.Getwd() + if err != nil { + panic(errors.Wrap(err, "failed to get the CWD")) + } + return wd +} + +// EnvOr returns the value of the specified environment variable if it is +// non-empty. Otherwise it return def. +func EnvOr(name, def string) string { + s := os.Getenv(name) + if s == "" { + return def + } + return s +} + +var ( + dockerInfoValue *DockerInfo + dockerInfoErr error + dockerInfoOnce sync.Once +) + +// DockerInfo contains information about the docker daemon. +type DockerInfo struct { + OperatingSystem string `json:"OperatingSystem"` + Labels []string `json:"Labels"` + NCPU int `json:"NCPU"` + MemTotal int `json:"MemTotal"` +} + +// IsBoot2Docker returns true if the Docker OS is boot2docker. +func (info *DockerInfo) IsBoot2Docker() bool { + return strings.Contains(strings.ToLower(info.OperatingSystem), "boot2docker") +} + +// HaveDocker returns an error if docker is unavailable. +func HaveDocker() error { + if _, err := GetDockerInfo(); err != nil { + return errors.Wrap(err, "docker is not available") + } + return nil +} + +// GetDockerInfo returns data from the docker info command. +func GetDockerInfo() (*DockerInfo, error) { + dockerInfoOnce.Do(func() { + dockerInfoValue, dockerInfoErr = dockerInfo() + }) + + return dockerInfoValue, dockerInfoErr +} + +func dockerInfo() (*DockerInfo, error) { + data, err := sh.Output("docker", "info", "-f", "{{ json .}}") + if err != nil { + return nil, err + } + + var info DockerInfo + if err = json.Unmarshal([]byte(data), &info); err != nil { + return nil, err + } + + return &info, nil +} + +// FindReplace reads a file, performs a find/replace operation, then writes the +// output to the same file path. +func FindReplace(file string, re *regexp.Regexp, repl string) error { + info, err := os.Stat(file) + if err != nil { + return err + } + + contents, err := ioutil.ReadFile(file) + if err != nil { + return err + } + + out := re.ReplaceAllString(string(contents), repl) + return ioutil.WriteFile(file, []byte(out), info.Mode().Perm()) +} + +// MustFindReplace invokes FindReplace and panics if an error occurs. +func MustFindReplace(file string, re *regexp.Regexp, repl string) { + if err := FindReplace(file, re, repl); err != nil { + panic(errors.Wrap(err, "failed to find and replace")) + } +} + +// Copy copies a file or a directory (recursively) and preserves the permissions. +func Copy(src, dest string) error { + info, err := os.Stat(src) + if err != nil { + return errors.Wrapf(err, "failed to stat source file %v", src) + } + return recursiveCopy(src, dest, info) +} + +func fileCopy(src, dest string, info os.FileInfo) error { + srcFile, err := os.Open(src) + if err != nil { + return err + } + defer srcFile.Close() + + if !info.Mode().IsRegular() { + return errors.Errorf("failed to copy source file because it is not a regular file") + } + + destFile, err := os.OpenFile(createDir(dest), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, info.Mode()&os.ModePerm) + if err != nil { + return err + } + defer destFile.Close() + + if _, err = io.Copy(destFile, srcFile); err != nil { + return err + } + return destFile.Close() +} + +func dirCopy(src, dest string, info os.FileInfo) error { + if err := os.MkdirAll(dest, info.Mode()); err != nil { + return errors.Wrap(err, "failed creating dirs") + } + + contents, err := ioutil.ReadDir(src) + if err != nil { + return errors.Wrapf(err, "failed to read dir %v", src) + } + + for _, info := range contents { + srcFile := filepath.Join(src, info.Name()) + destFile := filepath.Join(dest, info.Name()) + if err = recursiveCopy(srcFile, destFile, info); err != nil { + return errors.Wrapf(err, "failed to copy %v to %v", srcFile, destFile) + } + } + + return nil +} + +func recursiveCopy(src, dest string, info os.FileInfo) error { + if info.IsDir() { + return dirCopy(src, dest, info) + } + return fileCopy(src, dest, info) +} + +// DownloadFile downloads the given URL and writes the file to destinationDir. +// The path to the file is returned. +func DownloadFile(url, destinationDir string) (string, error) { + log.Println("Downloading", url) + + resp, err := http.Get(url) + if err != nil { + return "", errors.Wrap(err, "http get failed") + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return "", errors.Errorf("download failed with http status: %v", resp.StatusCode) + } + + name := filepath.Join(destinationDir, filepath.Base(url)) + f, err := os.Create(createDir(name)) + if err != nil { + return "", errors.Wrap(err, "failed to create output file") + } + defer f.Close() + + if _, err = io.Copy(f, resp.Body); err != nil { + return "", errors.Wrap(err, "failed to write file") + } + + return name, f.Close() +} + +// Extract extracts .zip, .tar.gz, or .tgz files to destinationDir. +func Extract(sourceFile, destinationDir string) error { + ext := filepath.Ext(sourceFile) + switch { + case strings.HasSuffix(sourceFile, ".tar.gz"), ext == ".tgz": + return untar(sourceFile, destinationDir) + case ext == ".zip": + return unzip(sourceFile, destinationDir) + default: + return errors.Errorf("failed to extract %v, unhandled file extension", sourceFile) + } +} + +func unzip(sourceFile, destinationDir string) error { + r, err := zip.OpenReader(sourceFile) + if err != nil { + return err + } + defer r.Close() + + if err = os.MkdirAll(destinationDir, 0755); err != nil { + return err + } + + extractAndWriteFile := func(f *zip.File) error { + innerFile, err := f.Open() + if err != nil { + return err + } + defer innerFile.Close() + + path := filepath.Join(destinationDir, f.Name) + if !strings.HasPrefix(path, destinationDir) { + return errors.Errorf("illegal file path in zip: %v", f.Name) + } + + if f.FileInfo().IsDir() { + return os.MkdirAll(path, f.Mode()) + } + + if err = os.MkdirAll(filepath.Dir(path), 0755); err != nil { + return err + } + + out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) + if err != nil { + return err + } + defer out.Close() + + if _, err = io.Copy(out, innerFile); err != nil { + return err + } + + return out.Close() + } + + for _, f := range r.File { + err := extractAndWriteFile(f) + if err != nil { + return err + } + } + + return nil +} + +func untar(sourceFile, destinationDir string) error { + file, err := os.Open(sourceFile) + if err != nil { + return err + } + defer file.Close() + + var fileReader io.ReadCloser = file + + if strings.HasSuffix(sourceFile, ".gz") { + if fileReader, err = gzip.NewReader(file); err != nil { + return err + } + defer fileReader.Close() + } + + tarReader := tar.NewReader(fileReader) + + for { + header, err := tarReader.Next() + if err != nil { + if err == io.EOF { + break + } + return err + } + + path := filepath.Join(destinationDir, header.Name) + if !strings.HasPrefix(path, destinationDir) { + return errors.Errorf("illegal file path in tar: %v", header.Name) + } + + switch header.Typeflag { + case tar.TypeDir: + if err = os.MkdirAll(path, os.FileMode(header.Mode)); err != nil { + return err + } + case tar.TypeReg: + writer, err := os.Create(path) + if err != nil { + return err + } + + if _, err = io.Copy(writer, tarReader); err != nil { + return err + } + + if err = os.Chmod(path, os.FileMode(header.Mode)); err != nil { + return err + } + + if err = writer.Close(); err != nil { + return err + } + default: + return errors.Errorf("unable to untar type=%c in file=%s", header.Typeflag, path) + } + } + + return nil +} + +func isSeparator(r rune) bool { + return unicode.IsSpace(r) || r == ',' || r == ';' +} + +// RunCmds runs the given commands and stops upon the first error. +func RunCmds(cmds ...[]string) error { + for _, cmd := range cmds { + if err := sh.Run(cmd[0], cmd[1:]...); err != nil { + return err + } + } + return nil +} + +var ( + parallelJobsLock sync.Mutex + parallelJobsSemaphore chan int +) + +func parallelJobs() chan int { + parallelJobsLock.Lock() + defer parallelJobsLock.Unlock() + + if parallelJobsSemaphore == nil { + max := numParallel() + parallelJobsSemaphore = make(chan int, max) + log.Println("Max parallel jobs =", max) + } + + return parallelJobsSemaphore +} + +func numParallel() int { + if maxParallel := os.Getenv("MAX_PARALLEL"); maxParallel != "" { + if num, err := strconv.Atoi(maxParallel); err == nil && num > 0 { + return num + } + } + + // To be conservative use the minimum of the number of CPUs between the host + // and the Docker host. + maxParallel := runtime.NumCPU() + + info, err := GetDockerInfo() + if err == nil && info.NCPU < maxParallel { + maxParallel = info.NCPU + } + + return maxParallel +} + +// ParallelCtx runs the given functions in parallel with an upper limit set +// based on GOMAXPROCS. The provided ctx is passed to the functions (if they +// accept it as a param). +func ParallelCtx(ctx context.Context, fns ...interface{}) { + var fnWrappers []func(context.Context) error + for _, f := range fns { + fnWrapper := types.FuncTypeWrap(f) + if fnWrapper == nil { + panic("attempted to add a dep that did not match required function type") + } + fnWrappers = append(fnWrappers, fnWrapper) + } + + var mu sync.Mutex + var errs []string + var wg sync.WaitGroup + + for _, fw := range fnWrappers { + wg.Add(1) + go func(fw func(context.Context) error) { + defer func() { + if v := recover(); v != nil { + mu.Lock() + errs = append(errs, fmt.Sprint(v)) + mu.Unlock() + } + wg.Done() + <-parallelJobs() + }() + waitStart := time.Now() + parallelJobs() <- 1 + log.Println("Parallel job waited", time.Since(waitStart), "before starting.") + if err := fw(ctx); err != nil { + mu.Lock() + errs = append(errs, fmt.Sprint(err)) + mu.Unlock() + } + }(fw) + } + + wg.Wait() + if len(errs) > 0 { + panic(errors.Errorf(strings.Join(errs, "\n"))) + } +} + +// Parallel runs the given functions in parallel with an upper limit set based +// on GOMAXPROCS. +func Parallel(fns ...interface{}) { + ParallelCtx(context.Background(), fns...) +} + +// FindFiles return a list of file matching the given glob patterns. +func FindFiles(globs ...string) ([]string, error) { + var configFiles []string + for _, glob := range globs { + files, err := filepath.Glob(glob) + if err != nil { + return nil, errors.Wrapf(err, "failed on glob %v", glob) + } + configFiles = append(configFiles, files...) + } + return configFiles, nil +} + +// FileConcat concatenates files and writes the output to out. +func FileConcat(out string, perm os.FileMode, files ...string) error { + f, err := os.OpenFile(createDir(out), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, perm) + if err != nil { + return errors.Wrap(err, "failed to create file") + } + defer f.Close() + + w := bufio.NewWriter(f) + + append := func(file string) error { + in, err := os.Open(file) + if err != nil { + return err + } + defer in.Close() + + if _, err := io.Copy(w, in); err != nil { + return err + } + + return nil + } + + for _, in := range files { + if err := append(in); err != nil { + return err + } + } + + if err = w.Flush(); err != nil { + return err + } + return f.Close() +} + +// MustFileConcat invokes FileConcat and panics if an error occurs. +func MustFileConcat(out string, perm os.FileMode, files ...string) { + if err := FileConcat(out, perm, files...); err != nil { + panic(err) + } +} + +// VerifySHA256 reads a file and verifies that its SHA256 sum matches the +// specified hash. +func VerifySHA256(file string, hash string) error { + f, err := os.Open(file) + if err != nil { + return errors.Wrap(err, "failed to open file for sha256 verification") + } + defer f.Close() + + sum := sha256.New() + if _, err := io.Copy(sum, f); err != nil { + return errors.Wrap(err, "failed reading from input file") + } + + computedHash := hex.EncodeToString(sum.Sum(nil)) + expectedHash := strings.TrimSpace(hash) + + if computedHash != expectedHash { + return errors.Errorf("SHA256 verification of %v failed. Expected=%v, "+ + "but computed=%v", f.Name(), expectedHash, computedHash) + } + log.Println("SHA256 OK:", f.Name()) + + return nil +} + +// CreateSHA512File computes the sha512 sum of the specified file the writes +// a sidecar file containing the hash and filename. +func CreateSHA512File(file string) error { + f, err := os.Open(file) + if err != nil { + return errors.Wrap(err, "failed to open file for sha512 summing") + } + defer f.Close() + + sum := sha512.New() + if _, err := io.Copy(sum, f); err != nil { + return errors.Wrap(err, "failed reading from input file") + } + + computedHash := hex.EncodeToString(sum.Sum(nil)) + out := fmt.Sprintf("%v %v", computedHash, filepath.Base(file)) + + return ioutil.WriteFile(file+".sha512", []byte(out), 0644) +} + +// IsUpToDate returns true iff dst exists and is older based on modtime than all +// of the sources. +func IsUpToDate(dst string, sources ...string) bool { + if len(sources) == 0 { + panic("No sources passed to IsUpToDate") + } + execute, err := target.Path(dst, sources...) + return err == nil && !execute +} + +// createDir creates the parent directory for the given file. +func createDir(file string) string { + // Create the output directory. + if dir := filepath.Dir(file); dir != "." { + if err := os.MkdirAll(dir, 0755); err != nil { + panic(errors.Wrapf(err, "failed to create parent dir for %v", file)) + } + } + return file +} + +// binaryExtension returns the appropriate file extension based on GOOS. +func binaryExtension(goos string) string { + if goos == "windows" { + return ".exe" + } + return "" +} diff --git a/dev-tools/mage/crossbuild.go b/dev-tools/mage/crossbuild.go new file mode 100644 index 000000000000..4a41cde08017 --- /dev/null +++ b/dev-tools/mage/crossbuild.go @@ -0,0 +1,239 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +package mage + +import ( + "fmt" + "log" + "os" + "path/filepath" + "runtime" + "strconv" + "strings" + + "github.com/magefile/mage/mg" + "github.com/magefile/mage/sh" + "github.com/pkg/errors" +) + +const defaultCrossBuildTarget = "golangCrossBuild" + +// Platforms contains the set of target platforms for cross-builds. It can be +// modified at runtime by setting the PLATFORMS environment variable. +// See NewPlatformList for details about platform filtering expressions. +var Platforms = BuildPlatforms.Defaults() + +func init() { + // Allow overriding via PLATFORMS. + if expression := os.Getenv("PLATFORMS"); len(expression) > 0 { + Platforms = NewPlatformList(expression) + } +} + +// CrossBuildOption defines a option to the CrossBuild target. +type CrossBuildOption func(params *crossBuildParams) + +// ForPlatforms filters the platforms based on the given expression. +func ForPlatforms(expr string) func(params *crossBuildParams) { + return func(params *crossBuildParams) { + params.Platforms = params.Platforms.Filter(expr) + } +} + +// WithTarget specifies the mage target to execute inside the golang-crossbuild +// container. +func WithTarget(target string) func(params *crossBuildParams) { + return func(params *crossBuildParams) { + params.Target = target + } +} + +// Serially causes each cross-build target to be executed serially instead of +// in parallel. +func Serially() func(params *crossBuildParams) { + return func(params *crossBuildParams) { + params.Serial = true + } +} + +type crossBuildParams struct { + Platforms BuildPlatformList + Target string + Serial bool +} + +// CrossBuild executes a given build target once for each target platform. +func CrossBuild(options ...CrossBuildOption) error { + params := crossBuildParams{Platforms: Platforms, Target: defaultCrossBuildTarget} + for _, opt := range options { + opt(¶ms) + } + + // Docker is required for this target. + if err := HaveDocker(); err != nil { + return err + } + + if len(params.Platforms) == 0 { + log.Printf("Skipping cross-build of target=%v because platforms list is empty.", params.Target) + return nil + } + + // Build the magefile for Linux so we can run it inside the container. + mg.Deps(buildMage) + + log.Println("crossBuild: Platform list =", params.Platforms) + var deps []interface{} + for _, buildPlatform := range params.Platforms { + if !buildPlatform.Flags.CanCrossBuild() { + return fmt.Errorf("unsupported cross build platform %v", buildPlatform.Name) + } + + builder := GolangCrossBuilder{buildPlatform.Name, params.Target} + if params.Serial { + if err := builder.Build(); err != nil { + return errors.Wrapf(err, "failed cross-building target=%v for platform=%v", + params.Target, buildPlatform.Name) + } + } else { + deps = append(deps, builder.Build) + } + } + + // Each build runs in parallel. + Parallel(deps...) + return nil +} + +// buildMage pre-compiles the magefile to a binary using the native GOOS/GOARCH +// values for Docker. This is required to so that we can later pass GOOS and +// GOARCH to mage for the cross-build. It has the benefit of speeding up the +// build because the mage -compile is done only once rather than in each Docker +// container. +func buildMage() error { + env := map[string]string{ + "GOOS": "linux", + "GOARCH": "amd64", + } + return sh.RunWith(env, "mage", "-f", "-compile", filepath.Join("build", "mage-linux-amd64")) +} + +func crossBuildImage(platform string) (string, error) { + tagSuffix := "main" + + switch { + case strings.HasPrefix(platform, "darwin"): + tagSuffix = "darwin" + case strings.HasPrefix(platform, "linux/arm"): + tagSuffix = "arm" + case strings.HasPrefix(platform, "linux/mips"): + tagSuffix = "mips" + case strings.HasPrefix(platform, "linux/ppc"): + tagSuffix = "ppc" + case platform == "linux/s390x": + tagSuffix = "s390x" + case strings.HasPrefix(platform, "linux"): + // Use an older version of libc to gain greater OS compatibility. + // Debian 7 uses glibc 2.13. + tagSuffix = "main-debian7" + } + + goVersion, err := GoVersion() + if err != nil { + return "", err + } + + return beatsCrossBuildImage + ":" + goVersion + "-" + tagSuffix, nil +} + +// GolangCrossBuilder executes the specified mage target inside of the +// associated golang-crossbuild container image for the platform. +type GolangCrossBuilder struct { + Platform string + Target string +} + +// Build executes the build inside of Docker. +func (b GolangCrossBuilder) Build() error { + fmt.Printf(">> %v: Building for %v\n", b.Target, b.Platform) + + repoInfo, err := GetProjectRepoInfo() + if err != nil { + return errors.Wrap(err, "failed to determine repo root and package sub dir") + } + + mountPoint := filepath.ToSlash(filepath.Join("/go", "src", repoInfo.RootImportPath)) + workDir := mountPoint + if repoInfo.SubDir != "" { + workDir = filepath.ToSlash(filepath.Join(workDir, repoInfo.SubDir)) + } + + dockerRun := sh.RunCmd("docker", "run") + image, err := crossBuildImage(b.Platform) + if err != nil { + return errors.Wrap(err, "failed to determine golang-crossbuild image tag") + } + verbose := "" + if mg.Verbose() { + verbose = "true" + } + var args []string + if runtime.GOOS != "windows" { + args = append(args, + "--env", "EXEC_UID="+strconv.Itoa(os.Getuid()), + "--env", "EXEC_GID="+strconv.Itoa(os.Getgid()), + ) + } + args = append(args, + "--rm", + "--env", "MAGEFILE_VERBOSE="+verbose, + "--env", "MAGEFILE_TIMEOUT="+EnvOr("MAGEFILE_TIMEOUT", ""), + "-v", repoInfo.RootDir+":"+mountPoint, + "-w", workDir, + image, + "--build-cmd", "build/mage-linux-amd64 "+b.Target, + "-p", b.Platform, + ) + + return dockerRun(args...) +} + +// DockerChown chowns files generated during build. EXEC_UID and EXEC_GID must +// be set in the containers environment otherwise this is a noop. +func DockerChown(file string) { + // Chown files generated during build that are root owned. + uid, _ := strconv.Atoi(EnvOr("EXEC_UID", "-1")) + gid, _ := strconv.Atoi(EnvOr("EXEC_GID", "-1")) + if uid > 0 && gid > 0 { + if err := chownPaths(uid, gid, file); err != nil { + log.Println(err) + } + } +} + +// chownPaths will chown the file and all of the dirs specified in the path. +func chownPaths(uid, gid int, file string) error { + pathParts := strings.Split(file, string(filepath.Separator)) + for i := range pathParts { + chownDir := filepath.Join(pathParts[:i+1]...) + if err := os.Chown(chownDir, uid, gid); err != nil { + return errors.Wrapf(err, "failed to chown path=%v", chownDir) + } + } + return nil +} diff --git a/dev-tools/mage/files/linux/systemd-daemon-reload.sh b/dev-tools/mage/files/linux/systemd-daemon-reload.sh new file mode 100644 index 000000000000..65589fb789c2 --- /dev/null +++ b/dev-tools/mage/files/linux/systemd-daemon-reload.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +systemctl daemon-reload 2> /dev/null +exit 0 diff --git a/dev-tools/mage/files/packages.yml b/dev-tools/mage/files/packages.yml new file mode 100644 index 000000000000..d57c3c982708 --- /dev/null +++ b/dev-tools/mage/files/packages.yml @@ -0,0 +1,222 @@ +--- + +# This file contains the package specifications for both Community Beats and +# Official Beats. The shared section contains YAML anchors that are used to +# define common parts of the package in order to not repeat ourselves. + +shared: +- &common + name: '{{.BeatName}}' + service_name: '{{.BeatServiceName}}' + os: '{{.GOOS}}' + arch: '{{.PackageArch}}' + vendor: '{{.BeatVendor}}' + version: '{{ beat_version }}' + license: '{{.BeatLicense}}' + url: '{{.BeatURL}}' + description: '{{.BeatDescription}}' + +- &deb_rpm_spec + <<: *common + post_install_script: '{{ elastic_beats_dir }}/dev-tools/mage/files/linux/systemd-daemon-reload.sh' + files: + /usr/share/{{.BeatName}}/bin/{{.BeatName}}{{.BinaryExt}}: + source: build/golang-crossbuild/{{.BeatName}}-{{.GOOS}}-{{.Platform.Arch}}{{.BinaryExt}} + mode: 0755 + /etc/{{.BeatName}}/fields.yml: + source: fields.yml + mode: 0644 + /usr/share/{{.BeatName}}/LICENSE.txt: + source: '{{ repo.RootDir }}/LICENSE.txt' + mode: 0644 + /usr/share/{{.BeatName}}/NOTICE.txt: + source: '{{ repo.RootDir }}/NOTICE.txt' + mode: 0644 + /usr/share/{{.BeatName}}/README.md: + template: '{{ elastic_beats_dir }}/dev-tools/mage/templates/common/README.md.tmpl' + mode: 0644 + /usr/share/{{.BeatName}}/.build_hash.txt: + content: > + {{ commit }} + mode: 0644 + /etc/{{.BeatName}}/{{.BeatName}}.reference.yml: + source: '{{.BeatName}}.reference.yml' + mode: 0644 + /etc/{{.BeatName}}/{{.BeatName}}.yml: + source: '{{.BeatName}}.yml' + mode: 0600 + config: true + /usr/share/{{.BeatName}}/kibana: + source: _meta/kibana.generated + mode: 0644 + /usr/share/{{.BeatName}}/bin/{{.BeatName}}-god: + source: build/golang-crossbuild/god-{{.GOOS}}-{{.Platform.Arch}} + mode: 0755 + /usr/bin/{{.BeatName}}: + template: '{{ elastic_beats_dir }}/dev-tools/mage/templates/linux/beatname.sh.tmpl' + mode: 0755 + /lib/systemd/system/{{.BeatServiceName}}.service: + template: '{{ elastic_beats_dir }}/dev-tools/mage/templates/linux/systemd.unit.tmpl' + mode: 0755 + /etc/init.d/{{.BeatServiceName}}: + template: '{{ elastic_beats_dir }}/dev-tools/mage/templates/{{.PackageType}}/init.sh.tmpl' + mode: 0755 + +- &binary_files + '{{.BeatName}}{{.BinaryExt}}': + source: build/golang-crossbuild/{{.BeatName}}-{{.GOOS}}-{{.Platform.Arch}}{{.BinaryExt}} + mode: 0755 + fields.yml: + source: fields.yml + mode: 0644 + LICENSE.txt: + source: '{{ repo.RootDir }}/LICENSE.txt' + mode: 0644 + NOTICE.txt: + source: '{{ repo.RootDir }}/NOTICE.txt' + mode: 0644 + README.md: + template: '{{ elastic_beats_dir }}/dev-tools/mage/templates/common/README.md.tmpl' + mode: 0644 + .build_hash.txt: + content: > + {{ commit }} + mode: 0644 + '{{.BeatName}}.reference.yml': + source: '{{.BeatName}}.reference.yml' + mode: 0644 + '{{.BeatName}}.yml': + source: '{{.BeatName}}.yml' + mode: 0600 + config: true + kibana: + source: _meta/kibana.generated + mode: 0644 + +- &binary_spec + <<: *common + files: + <<: *binary_files + +- &windows_binary_spec + <<: *common + files: + <<: *binary_files + install-service-{{.BeatName}}.ps1: + template: '{{ elastic_beats_dir }}/dev-tools/mage/templates/windows/install-service.ps1.tmpl' + mode: 0755 + uninstall-service-{{.BeatName}}.ps1: + template: '{{ elastic_beats_dir }}/dev-tools/mage/templates/windows/uninstall-service.ps1.tmpl' + mode: 0755 + +- &elastic_license_for_binaries + license: "Elastic License" + files: + LICENSE.txt: + source: '{{ repo.RootDir }}/licenses/ELASTIC-LICENSE.txt' + mode: 0644 + +- &elastic_license_for_deb_rpm + license: "Elastic License" + files: + /usr/share/{{.BeatName}}/LICENSE.txt: + source: '{{ repo.RootDir }}/licenses/ELASTIC-LICENSE.txt' + mode: 0644 + +- &apache_license_for_binaries + license: "ASL 2.0" + files: + LICENSE.txt: + source: '{{ repo.RootDir }}/licenses/APACHE-LICENSE-2.0.txt' + mode: 0644 + +- &apache_license_for_deb_rpm + license: "Elastic License" + files: + /usr/share/{{.BeatName}}/LICENSE.txt: + source: '{{ repo.RootDir }}/licenses/APACHE-LICENSE-2.0.txt' + mode: 0644 + +# specs is a list of named packaging "flavors". +specs: + # Community Beats + community_beat: + - os: windows + types: [zip] + spec: + <<: *windows_binary_spec + + - os: darwin + types: [tgz] + spec: + <<: *binary_spec + + - os: linux + types: [tgz] + spec: + <<: *binary_spec + + - os: linux + types: [deb, rpm] + spec: + <<: *deb_rpm_spec + + # Official Beats + elastic_beat: + ### + # OSS Packages + ### + - os: windows + types: [zip] + spec: + <<: *windows_binary_spec + <<: *apache_license_for_binaries + name: '{{.BeatName}}-oss' + + - os: darwin + types: [tgz] + spec: + <<: *binary_spec + <<: *apache_license_for_binaries + name: '{{.BeatName}}-oss' + + - os: linux + types: [tgz] + spec: + <<: *binary_spec + <<: *apache_license_for_binaries + name: '{{.BeatName}}-oss' + + - os: linux + types: [deb, rpm] + spec: + <<: *deb_rpm_spec + <<: *apache_license_for_deb_rpm + name: '{{.BeatName}}-oss' + + ### + # Elastic Licensed Packages + ### + - os: windows + types: [zip] + spec: + <<: *windows_binary_spec + <<: *elastic_license_for_binaries + + - os: darwin + types: [tgz] + spec: + <<: *binary_spec + <<: *elastic_license_for_binaries + + - os: linux + types: [tgz] + spec: + <<: *binary_spec + <<: *elastic_license_for_binaries + + - os: linux + types: [deb, rpm] + spec: + <<: *deb_rpm_spec + <<: *elastic_license_for_deb_rpm diff --git a/dev-tools/mage/godaemon.go b/dev-tools/mage/godaemon.go new file mode 100644 index 000000000000..0f4cb2c0ec1d --- /dev/null +++ b/dev-tools/mage/godaemon.go @@ -0,0 +1,72 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +package mage + +import ( + "errors" + "log" + "os" +) + +// BuildGoDaemon builds the go-deamon binary. +func BuildGoDaemon() error { + if GOOS != "linux" { + return errors.New("go-daemon only builds for linux") + } + + if os.Getenv("GOLANG_CROSSBUILD") != "1" { + return errors.New("Use the crossBuildGoDaemon target. buildGoDaemon can " + + "only be executed within the golang-crossbuild docker environment.") + } + + // Test if binaries are up-to-date. + output := MustExpand("build/golang-crossbuild/god-{{.Platform.GOOS}}-{{.Platform.Arch}}") + input := MustExpand("{{ elastic_beats_dir }}/dev-tools/vendor/github.com/tsg/go-daemon/god.c") + if IsUpToDate(output, input) { + log.Println(">>> buildGoDaemon is up-to-date for", Platform.Name) + return nil + } + + // Determine what compiler to use based on CC that is set by golang-crossbuild. + cc := os.Getenv("CC") + if cc == "" { + cc = "cc" + } + + compileCmd := []string{ + cc, + input, + "-o", createDir(output), + "-lpthread", "-static", + } + switch Platform.Name { + case "linux/amd64": + compileCmd = append(compileCmd, "-m64") + case "linux/386": + compileCmd = append(compileCmd, "-m32") + } + + defer DockerChown(output) + return RunCmds(compileCmd) +} + +// CrossBuildGoDaemon cross-build the go-daemon binary using the +// golang-crossbuild environment. +func CrossBuildGoDaemon() error { + return CrossBuild(ForPlatforms("linux"), WithTarget("buildGoDaemon")) +} diff --git a/dev-tools/mage/pkg.go b/dev-tools/mage/pkg.go new file mode 100644 index 000000000000..688e5c22118b --- /dev/null +++ b/dev-tools/mage/pkg.go @@ -0,0 +1,108 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +package mage + +import ( + "fmt" + "log" + + "github.com/magefile/mage/mg" + "github.com/magefile/mage/sh" + "github.com/pkg/errors" +) + +// Package packages the Beat for distribution. It generates packages based on +// the set of target plaforms and registered packaging specifications. +func Package() error { + if len(Platforms) == 0 { + return errors.New("PLATFORMS environment must be set to a list of " + + "GOOS/Arch values, but Platforms is empty") + } + + if len(Packages) == 0 { + return errors.New("no package specs are registered. Call " + + "UseCommunityBeatPackaging or UseElasticBeatPackaging first.") + } + + var tasks []interface{} + for _, target := range Platforms { + for _, pkg := range Packages { + if pkg.OS != target.GOOS() { + continue + } + + for _, pkgType := range pkg.Types { + packageArch, err := getOSArchName(target, pkgType) + if err != nil { + log.Printf("Skipping arch %v for package type %v: %v", target.Arch(), pkgType, err) + continue + } + + spec := pkg.Spec.Clone() + spec.OS = target.GOOS() + spec.Arch = packageArch + spec.Snapshot = Snapshot + spec.evalContext = map[string]interface{}{ + "GOOS": target.GOOS(), + "GOARCH": target.GOARCH(), + "GOARM": target.GOARM(), + "Platform": target, + "PackageType": pkgType.String(), + "BinaryExt": binaryExtension(target.GOOS()), + } + spec.packageDir = packageStagingDir + "/" + pkgType.AddFileExtension(spec.Name+"-"+target.GOOS()+"-"+target.Arch()) + spec = spec.Evaluate() + + tasks = append(tasks, packageBuilder{target, spec, pkgType}.Build) + } + } + } + + Parallel(tasks...) + return nil +} + +type packageBuilder struct { + Platform BuildPlatform + Spec PackageSpec + Type PackageType +} + +func (b packageBuilder) Build() error { + fmt.Printf(">> package: Building %v type=%v for platform=%v\n", b.Spec.Name, b.Type, b.Platform.Name) + log.Printf("Package spec: %+v", b.Spec) + return errors.Wrapf(b.Type.Build(b.Spec), "failed building %v type=%v for platform=%v", + b.Spec.Name, b.Type, b.Platform.Name) +} + +// TestPackages executes the package tests on the produced binaries. These tests +// inspect things like file ownership and mode. +func TestPackages() error { + fmt.Println(">> Testing package contents") + var args []string + if mg.Verbose() { + args = append(args, "-v") + } + args = append(args, + MustExpand("{{ elastic_beats_dir }}/dev-tools/package_test.go"), + "-files", + MustExpand("{{.PWD}}/build/distributions/*"), + ) + goTest := sh.RunCmd("go", "test") + return goTest(args...) +} diff --git a/dev-tools/mage/pkg_test.go b/dev-tools/mage/pkg_test.go new file mode 100644 index 000000000000..f9bd3a708eda --- /dev/null +++ b/dev-tools/mage/pkg_test.go @@ -0,0 +1,120 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +package mage + +import ( + "path/filepath" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v2" +) + +func testPackageSpec() PackageSpec { + return PackageSpec{ + Name: "brewbeat", + Version: "7.0.0", + Snapshot: true, + OS: "windows", + Arch: "x86_64", + Files: map[string]PackageFile{ + "brewbeat.yml": PackageFile{ + Source: "./testdata/config.yml", + Mode: 0644, + }, + "README.txt": PackageFile{ + Content: "Hello! {{.Version}}\n", + Mode: 0644, + }, + }, + } +} + +func TestPackageZip(t *testing.T) { + testPackage(t, PackageZip) +} + +func TestPackageTarGz(t *testing.T) { + testPackage(t, PackageTarGz) +} + +func TestPackageRPM(t *testing.T) { + if err := HaveDocker(); err != nil { + t.Skip("docker is required") + } + + testPackage(t, PackageRPM) +} + +func TestPackageDeb(t *testing.T) { + if err := HaveDocker(); err != nil { + t.Skip("docker is required") + } + + testPackage(t, PackageDeb) +} + +func testPackage(t testing.TB, pack func(PackageSpec) error) { + spec := testPackageSpec().Evaluate() + + readme := spec.Files["README.txt"] + readmePath := filepath.ToSlash(filepath.Clean(readme.Source)) + assert.True(t, strings.HasPrefix(readmePath, packageStagingDir)) + + if err := pack(spec); err != nil { + t.Fatal(err) + } +} + +func TestRepoRoot(t *testing.T) { + repo, err := GetProjectRepoInfo() + if err != nil { + t.Error(err) + } + + assert.Equal(t, "github.com/elastic/beats", repo.RootImportPath) + assert.True(t, filepath.IsAbs(repo.RootDir)) + cwd := filepath.Join(repo.RootDir, repo.SubDir) + assert.Equal(t, CWD(), cwd) +} + +func TestDumpVariables(t *testing.T) { + out, err := dumpVariables() + if err != nil { + t.Fatal(err) + } + t.Log(out) +} + +func TestLoadSpecs(t *testing.T) { + pkgs, err := LoadSpecs("files/packages.yml") + if err != nil { + t.Fatal(err) + } + + for flavor, s := range pkgs { + out, err := yaml.Marshal(s) + if err != nil { + t.Fatal(err) + } + if testing.Verbose() { + t.Log("Packaging flavor:", flavor, "\n", string(out)) + } + } +} diff --git a/dev-tools/mage/pkgspecs.go b/dev-tools/mage/pkgspecs.go new file mode 100644 index 000000000000..ee6c38a025a9 --- /dev/null +++ b/dev-tools/mage/pkgspecs.go @@ -0,0 +1,100 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +package mage + +import ( + "io/ioutil" + "log" + "path/filepath" + + "github.com/pkg/errors" + "gopkg.in/yaml.v2" +) + +const packageSpecFile = "dev-tools/mage/files/packages.yml" + +// Packages defines the set of packages to be built when the package target is +// executed. +var Packages []OSPackageArgs + +// UseCommunityBeatPackaging configures the package target to build packages for +// a community Beat. +func UseCommunityBeatPackaging() { + beatsDir, err := ElasticBeatsDir() + if err != nil { + panic(err) + } + + err = LoadNamedSpec("community_beat", filepath.Join(beatsDir, packageSpecFile)) + if err != nil { + panic(err) + } +} + +// UseElasticBeatPackaging configures the package target to build packages for +// an Elastic Beat. This means it will generate two sets of packages -- one +// that is purely OSS under Apache 2.0 and one that is licensed under the +// Elastic License and may contain additional X-Pack features. +func UseElasticBeatPackaging() { + beatsDir, err := ElasticBeatsDir() + if err != nil { + panic(err) + } + + err = LoadNamedSpec("elastic_beat", filepath.Join(beatsDir, packageSpecFile)) + if err != nil { + panic(err) + } +} + +// LoadNamedSpec loads a packaging specification with the given name from the +// specified YAML file. name should be a sub-key of 'specs'. +func LoadNamedSpec(name, file string) error { + specs, err := LoadSpecs(file) + if err != nil { + return errors.Wrap(err, "failed to load spec file") + } + + packages, found := specs[name] + if !found { + return errors.Errorf("%v not found in package specs", name) + } + + log.Printf("%v package spec loaded from %v", name, file) + Packages = packages + return nil +} + +// LoadSpecs loads the packaging specifications from the specified YAML file. +func LoadSpecs(file string) (map[string][]OSPackageArgs, error) { + data, err := ioutil.ReadFile(file) + if err != nil { + return nil, errors.Wrap(err, "failed to read from spec file") + } + + type PackageYAML struct { + Specs map[string][]OSPackageArgs `yaml:"specs"` + } + + var packages PackageYAML + if err = yaml.Unmarshal(data, &packages); err != nil { + return nil, errors.Wrap(err, "failed to unmarshal spec data") + } + + return packages.Specs, nil +} diff --git a/dev-tools/mage/pkgtypes.go b/dev-tools/mage/pkgtypes.go new file mode 100644 index 000000000000..4cf153315348 --- /dev/null +++ b/dev-tools/mage/pkgtypes.go @@ -0,0 +1,764 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +package mage + +import ( + "archive/tar" + "archive/zip" + "bytes" + "compress/gzip" + "fmt" + "io" + "io/ioutil" + "log" + "os" + "path/filepath" + "reflect" + "runtime" + "strconv" + "strings" + + "github.com/magefile/mage/mg" + "github.com/magefile/mage/sh" + "github.com/mitchellh/hashstructure" + "github.com/pkg/errors" +) + +const ( + // distributionsDir is the dir where packages are written. + distributionsDir = "build/distributions" + + // packageStagingDir is the staging directory for any temporary files that + // need to be written to disk for inclusion in a package. + packageStagingDir = "build/package" + + // defaultBinaryName specifies the output file for zip and tar.gz. + defaultBinaryName = "{{.Name}}-{{.Version}}{{if .Snapshot}}-SNAPSHOT{{end}}{{if .OS}}-{{.OS}}{{end}}{{if .Arch}}-{{.Arch}}{{end}}" +) + +// PackageType defines the file format of the package (e.g. zip, rpm, etc). +type PackageType int + +// List of possible package types. +const ( + RPM PackageType = iota + 1 + Deb + Zip + TarGz +) + +// OSPackageArgs define a set of package types to build for an operating +// system using the contained PackageSpec. +type OSPackageArgs struct { + OS string `yaml:"os"` + Types []PackageType `yaml:"types"` + Spec PackageSpec `yaml:"spec"` +} + +// PackageSpec specifies package metadata and the contents of the package. +type PackageSpec struct { + Name string `yaml:"name,omitempty"` + ServiceName string `yaml:"service_name,omitempty"` + OS string `yaml:"os,omitempty"` + Arch string `yaml:"arch,omitempty"` + Vendor string `yaml:"vendor,omitempty"` + Snapshot bool `yaml:"snapshot"` + Version string `yaml:"version,omitempty"` + License string `yaml:"license,omitempty"` + URL string `yaml:"url,omitempty"` + Description string `yaml:"description,omitempty"` + PostInstallScript string `yaml:"post_install_script,omitempty"` + Files map[string]PackageFile `yaml:"files"` + OutputFile string `yaml:"output_file,omitempty"` // Optional + + evalContext map[string]interface{} + packageDir string + localPostInstallScript string +} + +// PackageFile represents a file or directory within a package. +type PackageFile struct { + Source string `yaml:"source,omitempty"` // Regular source file or directory. + Content string `yaml:"content,omitempty"` // Inline template string. + Template string `yaml:"template,omitempty"` // Input template file. + Target string `yaml:"target,omitempty"` // Target location in package. Relative paths are added to a package specific directory (e.g. metricbeat-7.0.0-linux-x86_64). + Mode os.FileMode `yaml:"mode,omitempty"` // Target mode for file. Does not apply when source is a directory. + Config bool `yaml:"config"` // Mark file as config in the package (deb and rpm only). + Dep func(PackageSpec) error `yaml:"-" hash:"-" json:"-"` // Dependency to invoke during Evaluate. +} + +// OSArchNames defines the names of architectures for use in packages. +var OSArchNames = map[string]map[PackageType]map[string]string{ + "windows": map[PackageType]map[string]string{ + Zip: map[string]string{ + "386": "x86", + "amd64": "x86_64", + }, + }, + "darwin": map[PackageType]map[string]string{ + TarGz: map[string]string{ + "386": "x86", + "amd64": "x86_64", + }, + }, + "linux": map[PackageType]map[string]string{ + RPM: map[string]string{ + "386": "i686", + "amd64": "x86_64", + "armv7": "armhfp", + "arm64": "aarch64", + "mipsle": "mipsel", + "mips64le": "mips64el", + "ppc64": "ppc64", + "ppc64le": "ppc64le", + "s390x": "s390x", + }, + // https://www.debian.org/ports/ + Deb: map[string]string{ + "386": "i386", + "amd64": "amd64", + "armv5": "armel", + "armv6": "armel", + "armv7": "armhf", + "arm64": "arm64", + "mips": "mips", + "mipsle": "mipsel", + "mips64le": "mips64el", + "ppc64le": "ppc64el", + "s390x": "s390x", + }, + TarGz: map[string]string{ + "386": "x86", + "amd64": "x86_64", + "armv5": "armv5", + "armv6": "armv6", + "armv7": "armv7", + "arm64": "arm64", + "mips": "mips", + "mipsle": "mipsel", + "mips64": "mips64", + "mips64le": "mips64el", + "ppc64": "ppc64", + "ppc64le": "ppc64le", + "s390x": "s390x", + }, + }, +} + +// getOSArchName returns the architecture name to use in a package. +func getOSArchName(platform BuildPlatform, t PackageType) (string, error) { + names, found := OSArchNames[platform.GOOS()] + if !found { + return "", errors.Errorf("arch names for os=%v are not defined", + platform.GOOS()) + } + + archMap, found := names[t] + if !found { + return "", errors.Errorf("arch names for %v on os=%v are not defined", + t, platform.GOOS()) + } + + arch, found := archMap[platform.Arch()] + if !found { + return "", errors.Errorf("arch name associated with %v for %v on "+ + "os=%v is not defined", platform.Arch(), t, platform.GOOS()) + } + + return arch, nil +} + +// String returns the name of the package type. +func (typ PackageType) String() string { + switch typ { + case RPM: + return "rpm" + case Deb: + return "deb" + case Zip: + return "zip" + case TarGz: + return "tar.gz" + default: + return "invalid" + } +} + +// MarshalText returns the text representation of PackageType. +func (typ PackageType) MarshalText() ([]byte, error) { + return []byte(typ.String()), nil +} + +// UnmarshalText returns a PackageType based on the given text. +func (typ *PackageType) UnmarshalText(text []byte) error { + switch strings.ToLower(string(text)) { + case "rpm": + *typ = RPM + case "deb": + *typ = Deb + case "tar.gz", "tgz", "targz": + *typ = TarGz + case "zip": + *typ = Zip + default: + return errors.Errorf("unknown package type: %v", string(text)) + } + return nil +} + +// AddFileExtension returns a filename with the file extension added. If the +// filename already has the extension then it becomes a pass-through. +func (typ PackageType) AddFileExtension(file string) string { + ext := "." + strings.ToLower(typ.String()) + if !strings.HasSuffix(file, ext) { + return file + ext + } + return file +} + +// Build builds a package based on the provided spec. +func (typ PackageType) Build(spec PackageSpec) error { + switch typ { + case RPM: + return PackageRPM(spec) + case Deb: + return PackageDeb(spec) + case Zip: + return PackageZip(spec) + case TarGz: + return PackageTarGz(spec) + default: + return errors.Errorf("unknown package type: %v", typ) + } +} + +// Clone returns a deep clone of the spec. +func (s PackageSpec) Clone() PackageSpec { + clone := s + clone.Files = make(map[string]PackageFile, len(s.Files)) + for k, v := range s.Files { + clone.Files[k] = v + } + return clone +} + +// ReplaceFile replaces an existing file defined in the spec. The target must +// exist other it will panic. +func (s PackageSpec) ReplaceFile(target string, file PackageFile) { + _, found := s.Files[target] + if !found { + panic(errors.Errorf("failed to ReplaceFile because target=%v does not exist", target)) + } + + s.Files[target] = file +} + +// Expand expands a templated string using data from the spec. +func (s PackageSpec) Expand(in string, args ...map[string]interface{}) (string, error) { + return expandTemplate("inline", in, FuncMap, + EnvMap(append([]map[string]interface{}{s.evalContext, s.toMap()}, args...)...)) +} + +// MustExpand expands a templated string using data from the spec. It panics if +// an error occurs. +func (s PackageSpec) MustExpand(in string, args ...map[string]interface{}) string { + v, err := s.Expand(in, args...) + if err != nil { + panic(err) + } + return v +} + +// ExpandFile expands a template file using data from the spec. +func (s PackageSpec) ExpandFile(src, dst string, args ...map[string]interface{}) error { + return expandFile(src, dst, + EnvMap(append([]map[string]interface{}{s.evalContext, s.toMap()}, args...)...)) +} + +// MustExpandFile expands a template file using data from the spec. It panics if +// an error occurs. +func (s PackageSpec) MustExpandFile(src, dst string, args ...map[string]interface{}) error { + return s.ExpandFile(src, dst, args...) +} + +// Evaluate expands all variables used in the spec definition and writes any +// templated files used in the spec to disk. It panics if there is an error. +func (s PackageSpec) Evaluate(args ...map[string]interface{}) PackageSpec { + args = append([]map[string]interface{}{s.toMap(), s.evalContext}, args...) + mustExpand := func(in string) string { + if in == "" { + return "" + } + return MustExpand(in, args...) + } + + s.Name = mustExpand(s.Name) + s.ServiceName = mustExpand(s.ServiceName) + s.OS = mustExpand(s.OS) + s.Arch = mustExpand(s.Arch) + s.Vendor = mustExpand(s.Vendor) + s.Version = mustExpand(s.Version) + s.License = mustExpand(s.License) + s.URL = mustExpand(s.URL) + s.Description = mustExpand(s.Description) + s.PostInstallScript = mustExpand(s.PostInstallScript) + s.OutputFile = mustExpand(s.OutputFile) + + if s.ServiceName == "" { + s.ServiceName = s.Name + } + + if s.packageDir == "" { + outputFileName := filepath.Base(s.OutputFile) + + if outputFileName != "." { + s.packageDir = filepath.Join(packageStagingDir, outputFileName) + } else { + s.packageDir = filepath.Join(packageStagingDir, strings.Join([]string{s.Name, s.OS, s.Arch, s.hash()}, "-")) + } + } else { + s.packageDir = filepath.Clean(mustExpand(s.packageDir)) + } + if s.evalContext == nil { + s.evalContext = map[string]interface{}{} + } + s.evalContext["PackageDir"] = s.packageDir + + evaluatedFiles := make(map[string]PackageFile, len(s.Files)) + for target, f := range s.Files { + // Execute the dependency if it exists. + if f.Dep != nil { + if err := f.Dep(s); err != nil { + panic(errors.Wrapf(err, "failed executing package file dependency for target=%v", target)) + } + } + + f.Source = s.MustExpand(f.Source) + f.Template = s.MustExpand(f.Template) + f.Target = s.MustExpand(target) + target = f.Target + + // Expand templates. + switch { + case f.Source != "": + case f.Content != "": + content, err := s.Expand(f.Content) + if err != nil { + panic(errors.Wrapf(err, "failed to expand content template for target=%v", target)) + } + + f.Source = filepath.Join(s.packageDir, filepath.Base(f.Target)) + if err = ioutil.WriteFile(createDir(f.Source), []byte(content), 0644); err != nil { + panic(errors.Wrapf(err, "failed to write file containing content for target=%v", target)) + } + case f.Template != "": + f.Source = filepath.Join(s.packageDir, filepath.Base(f.Template)) + if err := s.ExpandFile(createDir(f.Template), f.Source); err != nil { + panic(errors.Wrapf(err, "failed to expand template file for target=%v", target)) + } + default: + panic(errors.Errorf("package file with target=%v must have either source, content, or template", target)) + } + + evaluatedFiles[f.Target] = f + } + // Replace the map instead of modifying the source. + s.Files = evaluatedFiles + + if s.PostInstallScript != "" { + // Copy the inside the build dir so that it's available inside of Docker for FPM. + s.localPostInstallScript = filepath.Join(s.packageDir, filepath.Base(s.PostInstallScript)) + if err := Copy(s.PostInstallScript, s.localPostInstallScript); err != nil { + panic(errors.Wrap(err, "failed to copy post install script to build dir")) + } + } + + return s +} + +func (s PackageSpec) hash() string { + h, err := hashstructure.Hash(s, nil) + if err != nil { + panic(errors.Wrap(err, "failed to compute hash of spec")) + } + + hash := strconv.FormatUint(h, 10) + if len(hash) > 10 { + hash = hash[0:10] + } + return hash +} + +// toMap returns a map containing the exported field names and their values. +func (s PackageSpec) toMap() map[string]interface{} { + out := make(map[string]interface{}) + v := reflect.ValueOf(s) + typ := v.Type() + + for i := 0; i < v.NumField(); i++ { + structField := typ.Field(i) + if !structField.Anonymous && structField.PkgPath == "" { + out[structField.Name] = v.Field(i).Interface() + } + } + + return out +} + +// rootDir returns the name of the root directory contained inside of zip and +// tar.gz packages. +func (s PackageSpec) rootDir() string { + if s.OutputFile != "" { + return filepath.Base(s.OutputFile) + } + + // NOTE: This uses .BeatName instead of .Name because we wanted the internal + // directory to not include "-oss". + return s.MustExpand("{{.BeatName}}-{{.Version}}{{if .Snapshot}}-SNAPSHOT{{end}}{{if .OS}}-{{.OS}}{{end}}{{if .Arch}}-{{.Arch}}{{end}}") +} + +// PackageZip packages a zip file. +func PackageZip(spec PackageSpec) error { + // Create a buffer to write our archive to. + buf := new(bytes.Buffer) + + // Create a new zip archive. + w := zip.NewWriter(buf) + baseDir := spec.rootDir() + + // Add files to zip. + for _, pkgFile := range spec.Files { + if err := addFileToZip(w, baseDir, pkgFile); err != nil { + return errors.Wrapf(err, "failed adding file=%+v to zip", pkgFile) + } + } + + if err := w.Close(); err != nil { + return err + } + + // Output the zip file. + if spec.OutputFile == "" { + outputZip, err := spec.Expand(defaultBinaryName + ".zip") + if err != nil { + return err + } + spec.OutputFile = filepath.Join(distributionsDir, outputZip) + } + spec.OutputFile = Zip.AddFileExtension(spec.OutputFile) + + // Write the zip file. + if err := ioutil.WriteFile(createDir(spec.OutputFile), buf.Bytes(), 0644); err != nil { + return errors.Wrap(err, "failed to write zip file") + } + + // Any packages beginning with "tmp-" are temporary by nature so don't have + // them a .sha512 file. + if strings.HasPrefix(filepath.Base(spec.OutputFile), "tmp-") { + return nil + } + + return errors.Wrap(CreateSHA512File(spec.OutputFile), "failed to create .sha512 file") +} + +// PackageTarGz packages a gzipped tar file. +func PackageTarGz(spec PackageSpec) error { + // Create a buffer to write our archive to. + buf := new(bytes.Buffer) + + // Create a new tar archive. + w := tar.NewWriter(buf) + baseDir := spec.rootDir() + + // Add files to tar. + for _, pkgFile := range spec.Files { + if err := addFileToTar(w, baseDir, pkgFile); err != nil { + return errors.Wrapf(err, "failed adding file=%+v to tar", pkgFile) + } + } + + if err := w.Close(); err != nil { + return err + } + + // Output tar.gz to disk. + if spec.OutputFile == "" { + outputTarGz, err := spec.Expand(defaultBinaryName + ".tar.gz") + if err != nil { + return err + } + spec.OutputFile = filepath.Join(distributionsDir, outputTarGz) + } + spec.OutputFile = TarGz.AddFileExtension(spec.OutputFile) + + // Open the output file. + log.Println("Creating output file at", spec.OutputFile) + outFile, err := os.Create(createDir(spec.OutputFile)) + if err != nil { + return err + } + defer outFile.Close() + + // Gzip compress the data. + gzWriter := gzip.NewWriter(outFile) + if _, err = gzWriter.Write(buf.Bytes()); err != nil { + return err + } + + // Close and flush. + if err = gzWriter.Close(); err != nil { + return err + } + + // Any packages beginning with "tmp-" are temporary by nature so don't have + // them a .sha512 file. + if strings.HasPrefix(filepath.Base(spec.OutputFile), "tmp-") { + return nil + } + + return errors.Wrap(CreateSHA512File(spec.OutputFile), "failed to create .sha512 file") +} + +// PackageDeb packages a deb file. This requires Docker to execute FPM. +func PackageDeb(spec PackageSpec) error { + return runFPM(spec, Deb) +} + +// PackageRPM packages a RPM file. This requires Docker to execute FPM. +func PackageRPM(spec PackageSpec) error { + return runFPM(spec, RPM) +} + +func runFPM(spec PackageSpec, packageType PackageType) error { + var fpmPackageType string + switch packageType { + case RPM, Deb: + fpmPackageType = packageType.String() + default: + return errors.Errorf("unsupported package type=%v for runFPM", fpmPackageType) + } + + if err := HaveDocker(); err != nil { + return fmt.Errorf("packaging %v files requires docker: %v", fpmPackageType, err) + } + + // Build a tar file as the input to FPM. + inputTar := filepath.Join(distributionsDir, "tmp-"+fpmPackageType+"-"+spec.rootDir()+"-"+spec.hash()+".tar.gz") + spec.OutputFile = inputTar + if err := PackageTarGz(spec); err != nil { + return err + } + defer os.Remove(inputTar) + + outputFile, err := spec.Expand("{{.Name}}-{{.Version}}{{if .Snapshot}}-SNAPSHOT{{end}}-{{.Arch}}") + if err != nil { + return err + } + spec.OutputFile = packageType.AddFileExtension(filepath.Join(distributionsDir, outputFile)) + + dockerRun := sh.RunCmd("docker", "run") + var args []string + + args, err = addUidGidEnvArgs(args) + if err != nil { + return err + } + + args = append(args, + "--rm", + "-w", "/app", + "-v", CWD()+":/app", + beatsFPMImage+":"+fpmVersion, + "fpm", "--force", + "--input-type", "tar", + "--output-type", fpmPackageType, + "--name", spec.ServiceName, + "--architecture", spec.Arch, + ) + if spec.Version != "" { + args = append(args, "--version", spec.Version) + } + if spec.Vendor != "" { + args = append(args, "--vendor", spec.Vendor) + } + if spec.License != "" { + args = append(args, "--license", strings.Replace(spec.License, " ", "-", -1)) + } + if spec.Description != "" { + args = append(args, "--description", spec.Description) + } + if spec.URL != "" { + args = append(args, "--url", spec.URL) + } + if spec.localPostInstallScript != "" { + args = append(args, "--after-install", spec.localPostInstallScript) + } + args = append(args, + "-p", spec.OutputFile, + inputTar, + ) + + if err = dockerRun(args...); err != nil { + return errors.Wrap(err, "failed while running FPM in docker") + } + + return errors.Wrap(CreateSHA512File(spec.OutputFile), "failed to create .sha512 file") +} + +func addUidGidEnvArgs(args []string) ([]string, error) { + if runtime.GOOS == "windows" { + return args, nil + } + + info, err := GetDockerInfo() + if err != nil { + return args, errors.Wrap(err, "failed to get docker info") + } + + uid, gid := os.Getuid(), os.Getgid() + if info.IsBoot2Docker() { + // Boot2Docker mounts vboxfs using 1000:50. + uid, gid = 1000, 50 + log.Printf("Boot2Docker is in use. Deploying workaround. "+ + "Using UID=%d GID=%d", uid, gid) + } + + return append(args, + "--env", "EXEC_UID="+strconv.Itoa(uid), + "--env", "EXEC_GID="+strconv.Itoa(gid), + ), nil +} + +// addFileToZip adds a file (or directory) to a zip archive. +func addFileToZip(ar *zip.Writer, baseDir string, pkgFile PackageFile) error { + return filepath.Walk(pkgFile.Source, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + header, err := zip.FileInfoHeader(info) + if err != nil { + return err + } + + if info.Mode().IsRegular() && pkgFile.Mode > 0 { + header.SetMode(pkgFile.Mode & os.ModePerm) + } else if info.IsDir() { + header.SetMode(0755) + } + + if filepath.IsAbs(pkgFile.Target) { + baseDir = "" + } + + relPath, err := filepath.Rel(pkgFile.Source, path) + if err != nil { + return err + } + + header.Name = filepath.Join(baseDir, pkgFile.Target, relPath) + + if info.IsDir() { + header.Name += string(filepath.Separator) + } else { + header.Method = zip.Deflate + } + + if mg.Verbose() { + log.Println("Adding", header.Mode(), header.Name) + } + + w, err := ar.CreateHeader(header) + if err != nil { + return err + } + + if info.IsDir() { + return nil + } + + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + + if _, err = io.Copy(w, file); err != nil { + return err + } + return file.Close() + }) +} + +// addFileToTar adds a file (or directory) to a tar archive. +func addFileToTar(ar *tar.Writer, baseDir string, pkgFile PackageFile) error { + return filepath.Walk(pkgFile.Source, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + header, err := tar.FileInfoHeader(info, info.Name()) + if err != nil { + return err + } + header.Uname, header.Gname = "root", "root" + header.Uid, header.Gid = 0, 0 + + if info.Mode().IsRegular() && pkgFile.Mode > 0 { + header.Mode = int64(pkgFile.Mode & os.ModePerm) + } else if info.IsDir() { + header.Mode = int64(0755) + } + + if filepath.IsAbs(pkgFile.Target) { + baseDir = "" + } + + relPath, err := filepath.Rel(pkgFile.Source, path) + if err != nil { + return err + } + + header.Name = filepath.Join(baseDir, pkgFile.Target, relPath) + if info.IsDir() { + header.Name += string(filepath.Separator) + } + + if mg.Verbose() { + log.Println("Adding", os.FileMode(header.Mode), header.Name) + } + if err := ar.WriteHeader(header); err != nil { + return err + } + + if info.IsDir() { + return nil + } + + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + + if _, err = io.Copy(ar, file); err != nil { + return err + } + return file.Close() + }) +} diff --git a/dev-tools/mage/platforms.go b/dev-tools/mage/platforms.go new file mode 100644 index 000000000000..c6039c55abac --- /dev/null +++ b/dev-tools/mage/platforms.go @@ -0,0 +1,464 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +package mage + +import ( + "sort" + "strings" + + "github.com/pkg/errors" +) + +// BuildPlatforms is a list of GOOS/GOARCH pairs supported by Go. +// The list originated from 'go tool dist list -json'. +var BuildPlatforms = BuildPlatformList{ + {"android/386", CGOSupported}, + {"android/amd64", CGOSupported}, + {"android/arm", CGOSupported}, + {"android/arm64", CGOSupported}, + {"darwin/386", CGOSupported | CrossBuildSupported}, + {"darwin/amd64", CGOSupported | CrossBuildSupported | Default}, + {"darwin/arm", CGOSupported}, + {"darwin/arm64", CGOSupported}, + {"dragonfly/amd64", CGOSupported}, + {"freebsd/386", CGOSupported}, + {"freebsd/amd64", CGOSupported}, + {"freebsd/arm", 0}, + {"linux/386", CGOSupported | CrossBuildSupported | Default}, + {"linux/amd64", CGOSupported | CrossBuildSupported | Default}, + {"linux/armv5", CGOSupported | CrossBuildSupported}, + {"linux/armv6", CGOSupported | CrossBuildSupported}, + {"linux/armv7", CGOSupported | CrossBuildSupported}, + {"linux/arm64", CGOSupported | CrossBuildSupported}, + {"linux/mips", CGOSupported | CrossBuildSupported}, + {"linux/mips64", CGOSupported | CrossBuildSupported}, + {"linux/mips64le", CGOSupported | CrossBuildSupported}, + {"linux/mipsle", CGOSupported | CrossBuildSupported}, + {"linux/ppc64", CrossBuildSupported}, + {"linux/ppc64le", CGOSupported | CrossBuildSupported}, + {"linux/s390x", CGOSupported | CrossBuildSupported}, + {"nacl/386", 0}, + {"nacl/amd64p32", 0}, + {"nacl/arm", 0}, + {"netbsd/386", CGOSupported}, + {"netbsd/amd64", CGOSupported}, + {"netbsd/arm", CGOSupported}, + {"openbsd/386", CGOSupported}, + {"openbsd/amd64", CGOSupported}, + {"openbsd/arm", 0}, + {"plan9/386", 0}, + {"plan9/amd64", 0}, + {"plan9/arm", 0}, + {"solaris/amd64", CGOSupported}, + {"windows/386", CGOSupported | CrossBuildSupported | Default}, + {"windows/amd64", CGOSupported | CrossBuildSupported | Default}, +} + +// PlatformFeature specifies features that are supported for a platform. +type PlatformFeature uint8 + +// List of PlatformFeature types. +const ( + CGOSupported PlatformFeature = 1 << iota // CGO is supported. + CrossBuildSupported // Cross-build supported by golang-crossbuild. + Default // Built by default on crossBuild and package. +) + +var platformFlagNames = map[PlatformFeature]string{ + CGOSupported: "cgo", + CrossBuildSupported: "xbuild", + Default: "default", +} + +// String returns a string representation of the platform features. +func (f PlatformFeature) String() string { + if f == 0 { + return "none" + } + + var names []string + for value, name := range platformFlagNames { + if f&value > 0 { + names = append(names, name) + } + } + + return strings.Join(names, "|") +} + +// CanCrossBuild returns true if cross-building is supported by +// golang-crossbuild. +func (f PlatformFeature) CanCrossBuild() bool { + return f&CrossBuildSupported > 0 +} + +// SupportsCGO returns true if CGO is supported. +func (f PlatformFeature) SupportsCGO() bool { + return f&CGOSupported > 0 +} + +// BuildPlatform represents a target platform for builds. +type BuildPlatform struct { + Name string + Flags PlatformFeature +} + +// GOOS returns the GOOS value contained in the name. +func (p BuildPlatform) GOOS() string { + idx := strings.IndexByte(p.Name, '/') + if idx == -1 { + return p.Name + } + return p.Name[:idx] +} + +// Arch returns the architecture value contained in the name. +func (p BuildPlatform) Arch() string { + idx := strings.IndexByte(p.Name, '/') + if idx == -1 { + return "" + } + return p.Name[strings.IndexByte(p.Name, '/')+1:] +} + +// GOARCH returns the GOARCH value associated with the architecture contained +// in the name. For ARM the Arch and GOARCH can differ because the GOARM value +// is encoded in the Arch value. +func (p BuildPlatform) GOARCH() string { + // Allow armv7 to be interpreted as GOARCH=arm GOARM=7. + arch := p.Arch() + if strings.HasPrefix(arch, "armv") { + return "arm" + } + return arch +} + +// GOARM returns the ARM version. +func (p BuildPlatform) GOARM() string { + arch := p.Arch() + if strings.HasPrefix(arch, "armv") { + return strings.TrimPrefix(arch, "armv") + } + return "" +} + +// Attributes returns a new PlatformAttributes. +func (p BuildPlatform) Attributes() PlatformAttributes { + return MakePlatformAttributes(p.GOOS(), p.GOARCH(), p.GOARM()) +} + +// PlatformAttributes contains all of the data that can be extracted from a +// BuildPlatform name. +type PlatformAttributes struct { + Name string + GOOS string + GOARCH string + GOARM string + Arch string +} + +// MakePlatformAttributes returns a new PlatformAttributes. +func MakePlatformAttributes(goos, goarch, goarm string) PlatformAttributes { + arch := goarch + if goarch == "arm" && goarm != "" { + arch += "v" + goarm + } + + name := goos + if arch != "" { + name += "/" + arch + } + + return PlatformAttributes{ + Name: name, + GOOS: goos, + GOARCH: goarch, + GOARM: goarm, + Arch: arch, + } +} + +// String returns the string representation of the platform which has the format +// of "GOOS/Arch". +func (p PlatformAttributes) String() string { + return p.Name +} + +// BuildPlatformList is a list of BuildPlatforms that supports filtering. +type BuildPlatformList []BuildPlatform + +// Get returns the BuildPlatform matching the given name. +func (list BuildPlatformList) Get(name string) (BuildPlatform, bool) { + for _, bp := range list { + if bp.Name == name { + return bp, true + } + } + return BuildPlatform{}, false +} + +// Defaults returns the default platforms contained in the list. +func (list BuildPlatformList) Defaults() BuildPlatformList { + return list.filter(func(p BuildPlatform) bool { + return p.Flags&Default > 0 + }) +} + +// CrossBuild returns the platforms that support cross-building. +func (list BuildPlatformList) CrossBuild() BuildPlatformList { + return list.filter(func(p BuildPlatform) bool { + return p.Flags&CrossBuildSupported > 0 + }) +} + +// filter returns the platforms that match the given predicate. +func (list BuildPlatformList) filter(pred func(p BuildPlatform) bool) BuildPlatformList { + var out BuildPlatformList + for _, item := range list { + if pred(item) { + out = append(out, item) + } + } + return out +} + +// Remove returns a copy of list without platforms matching name. +func (list BuildPlatformList) Remove(name string) BuildPlatformList { + attrs := BuildPlatform{Name: name}.Attributes() + + if attrs.Arch == "" { + // Filter by GOOS only. + return list.filter(func(bp BuildPlatform) bool { + return bp.GOOS() != attrs.GOOS + }) + } + + return list.filter(func(bp BuildPlatform) bool { + return !(bp.GOOS() == attrs.GOOS && bp.Arch() == attrs.Arch) + }) +} + +// Select returns a new list containing the platforms that match name. +func (list BuildPlatformList) Select(name string) BuildPlatformList { + attrs := BuildPlatform{Name: name}.Attributes() + + if attrs.Arch == "" { + // Filter by GOOS only. + return list.filter(func(bp BuildPlatform) bool { + return bp.GOOS() == attrs.GOOS + }) + } + + return list.filter(func(bp BuildPlatform) bool { + return bp.GOOS() == attrs.GOOS && bp.Arch() == attrs.Arch + }) +} + +type platformExpression struct { + Add []string + Select []string + SelectCrossBuild bool + Remove []string +} + +func newPlatformExpression(expr string) (*platformExpression, error) { + if strings.TrimSpace(expr) == "" { + return nil, nil + } + + pe := &platformExpression{} + + // Parse the expression. + words := strings.FieldsFunc(expr, isSeparator) + for _, w := range words { + if strings.HasPrefix(w, "+") { + pe.Add = append(pe.Add, strings.TrimPrefix(w, "+")) + } else if strings.HasPrefix(w, "!") { + pe.Remove = append(pe.Remove, strings.TrimPrefix(w, "!")) + } else if w == "xbuild" { + pe.SelectCrossBuild = true + } else { + pe.Select = append(pe.Select, w) + } + } + + // Validate the names used. + checks := make([]string, 0, len(pe.Add)+len(pe.Select)+len(pe.Remove)) + checks = append(checks, pe.Add...) + checks = append(checks, pe.Select...) + checks = append(checks, pe.Remove...) + + for _, name := range checks { + if name == "all" || name == "defaults" { + continue + } + + var valid bool + for _, bp := range BuildPlatforms { + if bp.Name == name || bp.GOOS() == name { + valid = true + break + } + } + + if !valid { + return nil, errors.Errorf("invalid platform in expression: %v", name) + } + } + + return pe, nil +} + +// NewPlatformList returns a new BuildPlatformList based on given expression. +// +// By default the initial set include only the platforms designated as defaults. +// To add additional platforms to list use an addition term that is designated +// with a plug sign (e.g. "+netbsd" or "+linux/armv7"). Or you may use "+all" +// to change the initial set to include all possible platforms then filter +// from there (e.g. "+all linux windows"). +// +// The expression can consists of selections (e.g. "linux") and/or +// removals (e.g."!windows"). Each term can be valid GOOS or a valid GOOS/Arch +// pair. +// +// "xbuild" is a special selection term used to select all platforms that are +// cross-build eligible. +// "defaults" is a special selection or removal term that contains all platforms +// designated as a default. +// "all" is a special addition term for adding all valid GOOS/Arch pairs to the +// set. +func NewPlatformList(expr string) BuildPlatformList { + pe, err := newPlatformExpression(expr) + if err != nil { + panic(err) + } + if pe == nil { + return BuildPlatforms.Defaults() + } + + var out BuildPlatformList + if len(pe.Add) == 0 || (len(pe.Select) == 0 && len(pe.Remove) == 0) { + // Bootstrap list with default platforms when the expression is + // exclusively adds OR exclusively selects and removes. + out = BuildPlatforms.Defaults() + } + + all := BuildPlatforms + for _, name := range pe.Add { + if name == "all" { + out = make(BuildPlatformList, len(all)) + copy(out, all) + break + } + out = append(out, all.Select(name)...) + } + + if len(pe.Select) > 0 { + var selected BuildPlatformList + for _, name := range pe.Select { + selected = append(selected, out.Select(name)...) + } + out = selected + } + + for _, name := range pe.Remove { + if name == "defaults" { + for _, defaultBP := range all.Defaults() { + out = out.Remove(defaultBP.Name) + } + continue + } + out = out.Remove(name) + } + + if pe.SelectCrossBuild { + out = out.CrossBuild() + } + return out.deduplicate() +} + +// Filter creates a new list based on the provided expression. +// +// The expression can consists of selections (e.g. "linux") and/or +// removals (e.g."!windows"). Each term can be valid GOOS or a valid GOOS/Arch +// pair. +// +// "xbuild" is a special selection term used to select all platforms that are +// cross-build eligible. +// "defaults" is a special selection or removal term that contains all platforms +// designated as a default. +func (list BuildPlatformList) Filter(expr string) BuildPlatformList { + pe, err := newPlatformExpression(expr) + if err != nil { + panic(err) + } + if pe == nil { + return list + } + if len(pe.Add) > 0 { + panic(errors.Errorf("adds (%v) cannot be used in filter expressions", + strings.Join(pe.Add, ", "))) + } + + var out BuildPlatformList + if len(pe.Select) == 0 && !pe.SelectCrossBuild { + // Filter is only removals so clone the original list. + out = append(out, list...) + } + + if pe.SelectCrossBuild { + out = append(out, list.CrossBuild()...) + } + for _, name := range pe.Select { + if name == "defaults" { + out = append(out, list.Defaults()...) + continue + } + out = append(out, list.Select(name)...) + } + + for _, name := range pe.Remove { + if name == "defaults" { + for _, defaultBP := range BuildPlatforms.Defaults() { + out = out.Remove(defaultBP.Name) + } + continue + } + out = out.Remove(name) + } + + return out.deduplicate() +} + +// deduplicate removes duplicate platforms and sorts the list. +func (list BuildPlatformList) deduplicate() BuildPlatformList { + set := map[string]BuildPlatform{} + for _, item := range list { + set[item.Name] = item + } + + var out BuildPlatformList + for _, v := range set { + out = append(out, v) + } + + sort.Slice(out, func(i, j int) bool { + return out[i].Name < out[j].Name + }) + return out +} diff --git a/dev-tools/mage/platforms_test.go b/dev-tools/mage/platforms_test.go new file mode 100644 index 000000000000..76b568a48cff --- /dev/null +++ b/dev-tools/mage/platforms_test.go @@ -0,0 +1,158 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +package mage + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBuildPlatform(t *testing.T) { + bp := BuildPlatform{"windows/amd64", 0} + assert.Equal(t, "windows", bp.GOOS()) + assert.Equal(t, "amd64", bp.GOARCH()) + assert.Equal(t, "", bp.GOARM()) + assert.Equal(t, "amd64", bp.Arch()) + + bp = BuildPlatform{"linux/armv7", 0} + assert.Equal(t, "linux", bp.GOOS()) + assert.Equal(t, "arm", bp.GOARCH()) + assert.Equal(t, "7", bp.GOARM()) + assert.Equal(t, "armv7", bp.Arch()) + attrs := bp.Attributes() + assert.Equal(t, bp.Name, attrs.Name) + assert.Equal(t, "linux", attrs.GOOS) + assert.Equal(t, "arm", attrs.GOARCH) + assert.Equal(t, "7", attrs.GOARM) + assert.Equal(t, "armv7", attrs.Arch) + + bp = BuildPlatform{"linux", 0} + assert.Equal(t, "linux", bp.GOOS()) + assert.Equal(t, "", bp.GOARCH()) + assert.Equal(t, "", bp.GOARM()) + assert.Equal(t, "", bp.Arch()) + attrs = bp.Attributes() + assert.Equal(t, bp.Name, attrs.Name) + assert.Equal(t, "linux", attrs.GOOS) + assert.Equal(t, "", attrs.GOARCH) + assert.Equal(t, "", attrs.GOARM) + assert.Equal(t, "", attrs.Arch) +} + +func TestBuildPlatformsListRemove(t *testing.T) { + list := BuildPlatformList{ + {"linux/amd64", 0}, + {"linux/386", 0}, + } + + assert.ElementsMatch(t, + list.Remove("linux/386"), + BuildPlatformList{{"linux/amd64", 0}}, + ) +} + +func TestBuildPlatformsListRemoveOS(t *testing.T) { + list := BuildPlatformList{ + {"linux/amd64", 0}, + {"linux/386", 0}, + {"windows/amd64", 0}, + } + + assert.ElementsMatch(t, + list.Remove("linux"), + BuildPlatformList{{"windows/amd64", 0}}, + ) +} + +func TestBuildPlatformsListSelect(t *testing.T) { + list := BuildPlatformList{ + {"linux/amd64", 0}, + {"linux/386", 0}, + } + + assert.ElementsMatch(t, + list.Select("linux/386"), + BuildPlatformList{{"linux/386", 0}}, + ) +} + +func TestBuildPlatformsListDefaults(t *testing.T) { + list := BuildPlatformList{ + {"linux/amd64", Default}, + {"linux/386", 0}, + } + + assert.ElementsMatch(t, + list.Defaults(), + BuildPlatformList{{"linux/amd64", Default}}, + ) +} + +func TestBuildPlatformsListFilter(t *testing.T) { + assert.Len(t, BuildPlatforms.Filter("!linux/armv7"), len(BuildPlatforms)-1) + + assert.Len(t, BuildPlatforms.Filter("solaris"), 1) + assert.Len(t, BuildPlatforms.Defaults().Filter("solaris"), 0) + + assert.Len(t, BuildPlatforms.Filter("windows"), 2) + assert.Len(t, BuildPlatforms.Filter("windows/386"), 1) + assert.Len(t, BuildPlatforms.Filter("!defaults"), len(BuildPlatforms)-len(BuildPlatforms.Defaults())) + + defaults := BuildPlatforms.Defaults() + assert.ElementsMatch(t, + defaults.Filter("darwin"), + defaults.Filter("!windows !linux")) + assert.ElementsMatch(t, + defaults, + defaults.Filter("windows linux darwin")) + assert.ElementsMatch(t, + defaults, + append(defaults.Filter("darwin"), defaults.Filter("!darwin")...)) + assert.ElementsMatch(t, + BuildPlatforms, + BuildPlatforms.Filter("")) + assert.ElementsMatch(t, + BuildPlatforms.Filter("defaults"), + BuildPlatforms.Defaults()) +} + +func TestNewPlatformList(t *testing.T) { + assert.Len(t, NewPlatformList("+all !linux/armv7"), len(BuildPlatforms)-1) + assert.Len(t, NewPlatformList("+solaris"), len(BuildPlatforms.Defaults())+1) + assert.Len(t, NewPlatformList("solaris"), 0) + assert.Len(t, NewPlatformList("+all solaris"), 1) + assert.Len(t, NewPlatformList("+windows"), len(BuildPlatforms.Defaults())) + assert.Len(t, NewPlatformList("+linux/ppc64 !defaults"), 1) + + assert.ElementsMatch(t, + NewPlatformList("darwin"), + NewPlatformList("!windows !linux")) + assert.ElementsMatch(t, + BuildPlatforms.Defaults(), + NewPlatformList("windows linux darwin")) + assert.ElementsMatch(t, + BuildPlatforms.Defaults(), + append(NewPlatformList("darwin"), NewPlatformList("!darwin")...)) + assert.ElementsMatch(t, + BuildPlatforms.Defaults(), + NewPlatformList("")) + assert.ElementsMatch(t, + BuildPlatforms, + NewPlatformList("+all")) +} diff --git a/dev-tools/mage/settings.go b/dev-tools/mage/settings.go new file mode 100644 index 000000000000..dc66bdd33ea6 --- /dev/null +++ b/dev-tools/mage/settings.go @@ -0,0 +1,573 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +package mage + +import ( + "fmt" + "go/build" + "io/ioutil" + "log" + "os" + "path/filepath" + "regexp" + "strconv" + "strings" + "sync" + "time" + + "github.com/magefile/mage/sh" + "github.com/pkg/errors" + "golang.org/x/tools/go/vcs" +) + +const ( + fpmVersion = "1.10.0" + + // Docker images. See https://github.com/elastic/golang-crossbuild. + beatsFPMImage = "docker.elastic.co/beats-dev/fpm" + beatsCrossBuildImage = "docker.elastic.co/beats-dev/golang-crossbuild" + + elasticBeatsImportPath = "github.com/elastic/beats" +) + +// Common settings with defaults derived from files, CWD, and environment. +var ( + GOOS = build.Default.GOOS + GOARCH = build.Default.GOARCH + GOARM = EnvOr("GOARM", "") + Platform = MakePlatformAttributes(GOOS, GOARCH, GOARM) + BinaryExt = "" + + BeatName = EnvOr("BEAT_NAME", filepath.Base(CWD())) + BeatServiceName = EnvOr("BEAT_SERVICE_NAME", BeatName) + BeatIndexPrefix = EnvOr("BEAT_INDEX_PREFIX", BeatName) + BeatDescription = EnvOr("BEAT_DESCRIPTION", "") + BeatVendor = EnvOr("BEAT_VENDOR", "Elastic") + BeatLicense = EnvOr("BEAT_LICENSE", "ASL 2.0") + BeatURL = EnvOr("BEAT_URL", "https://www.elastic.co/products/beats/"+BeatName) + + Snapshot bool + + FuncMap = map[string]interface{}{ + "beat_doc_branch": BeatDocBranch, + "beat_version": BeatVersion, + "commit": CommitHash, + "date": BuildDate, + "elastic_beats_dir": ElasticBeatsDir, + "go_version": GoVersion, + "repo": GetProjectRepoInfo, + "title": strings.Title, + } +) + +func init() { + if GOOS == "windows" { + BinaryExt = ".exe" + } + + var err error + Snapshot, err = strconv.ParseBool(EnvOr("SNAPSHOT", "false")) + if err != nil { + panic(errors.Errorf("failed to parse SNAPSHOT value", err)) + } +} + +// EnvMap returns map containing the common settings variables and all variables +// from the environment. args are appended to the output prior to adding the +// environment variables (so env vars have the highest precedence). +func EnvMap(args ...map[string]interface{}) map[string]interface{} { + envMap := varMap(args...) + + // Add the environment (highest precedence). + for _, e := range os.Environ() { + env := strings.SplitN(e, "=", 2) + envMap[env[0]] = env[1] + } + + return envMap +} + +func varMap(args ...map[string]interface{}) map[string]interface{} { + data := map[string]interface{}{ + "GOOS": GOOS, + "GOARCH": GOARCH, + "GOARM": GOARM, + "Platform": Platform, + "BinaryExt": BinaryExt, + "BeatName": BeatName, + "BeatServiceName": BeatServiceName, + "BeatIndexPrefix": BeatIndexPrefix, + "BeatDescription": BeatDescription, + "BeatVendor": BeatVendor, + "BeatLicense": BeatLicense, + "BeatURL": BeatURL, + "Snapshot": Snapshot, + } + + // Add the extra args to the map. + for _, m := range args { + for k, v := range m { + data[k] = v + } + } + + return data +} + +func dumpVariables() (string, error) { + var dumpTemplate = `## Variables + +GOOS = {{.GOOS}} +GOARCH = {{.GOARCH}} +GOARM = {{.GOARM}} +Platform = {{.Platform}} +BinaryExt = {{.BinaryExt}} +BeatName = {{.BeatName}} +BeatServiceName = {{.BeatServiceName}} +BeatIndexPrefix = {{.BeatIndexPrefix}} +BeatDescription = {{.BeatDescription}} +BeatVendor = {{.BeatVendor}} +BeatLicense = {{.BeatLicense}} +BeatURL = {{.BeatURL}} + +## Functions + +beat_doc_branch = {{ beat_doc_branch }} +beat_version = {{ beat_version }} +commit = {{ commit }} +date = {{ date }} +elastic_beats_dir = {{ elastic_beats_dir }} +go_version = {{ go_version }} +repo.RootImportPath = {{ repo.RootImportPath }} +repo.RootDir = {{ repo.RootDir }} +repo.ImportPath = {{ repo.ImportPath }} +repo.SubDir = {{ repo.SubDir }} +` + + return Expand(dumpTemplate) +} + +// DumpVariables writes the template variables and values to stdout. +func DumpVariables() error { + out, err := dumpVariables() + if err != nil { + return err + } + + fmt.Println(out) + return nil +} + +var ( + commitHash string + commitHashOnce sync.Once +) + +// CommitHash returns the full length git commit hash. +func CommitHash() (string, error) { + var err error + commitHashOnce.Do(func() { + commitHash, err = sh.Output("git", "rev-parse", "HEAD") + }) + return commitHash, err +} + +var ( + elasticBeatsDirValue string + elasticBeatsDirErr error + elasticBeatsDirLock sync.Mutex +) + +// ElasticBeatsDir returns the path to Elastic beats dir. +func ElasticBeatsDir() (string, error) { + elasticBeatsDirLock.Lock() + defer elasticBeatsDirLock.Unlock() + + if elasticBeatsDirValue != "" || elasticBeatsDirErr != nil { + return elasticBeatsDirValue, elasticBeatsDirErr + } + + elasticBeatsDirValue, elasticBeatsDirErr = findElasticBeatsDir() + if elasticBeatsDirErr == nil { + log.Println("Found Elastic Beats dir at", elasticBeatsDirValue) + } + return elasticBeatsDirValue, elasticBeatsDirErr +} + +// findElasticBeatsDir attempts to find the root of the Elastic Beats directory. +// It checks to see if the current project is elastic/beats, and then if not +// checks the vendor directory. +// +// If your project places the Beats files in a different location (specifically +// the dev-tools/ contents) then you can use SetElasticBeatsDir(). +func findElasticBeatsDir() (string, error) { + repo, err := GetProjectRepoInfo() + if err != nil { + return "", err + } + + if repo.IsElasticBeats() { + return repo.RootDir, nil + } + + const devToolsImportPath = elasticBeatsImportPath + "/dev-tools/mage" + + // Search in project vendor directories. + searchPaths := []string{ + filepath.Join(repo.RootDir, repo.SubDir, "vendor", devToolsImportPath), + filepath.Join(repo.RootDir, "vendor", devToolsImportPath), + } + + for _, path := range searchPaths { + if _, err := os.Stat(path); err == nil { + return filepath.Join(path, "../.."), nil + } + } + + return "", errors.Errorf("failed to find %v in the project's vendor", devToolsImportPath) +} + +// SetElasticBeatsDir explicilty sets the location of the Elastic Beats +// directory. If not set then it will attempt to locate it. +func SetElasticBeatsDir(dir string) { + elasticBeatsDirLock.Lock() + defer elasticBeatsDirLock.Unlock() + + info, err := os.Stat(dir) + if err != nil { + panic(errors.Wrapf(err, "failed to read elastic beats dir at %v", dir)) + } + + if !info.IsDir() { + panic(errors.Errorf("elastic beats dir=%v is not a directory", dir)) + } + + elasticBeatsDirValue = filepath.Clean(dir) +} + +var ( + buildDate = time.Now().UTC().Format(time.RFC3339) +) + +// BuildDate returns the time that the build started. +func BuildDate() string { + return buildDate +} + +var ( + goVersionValue string + goVersionErr error + goVersionOnce sync.Once +) + +// GoVersion returns the version of Go defined in the project's .go-version +// file. +func GoVersion() (string, error) { + goVersionOnce.Do(func() { + goVersionValue = os.Getenv("BEAT_GO_VERSION") + if goVersionValue != "" { + return + } + + goVersionValue, goVersionErr = getBuildVariableSources().GetGoVersion() + }) + + return goVersionValue, goVersionErr +} + +var ( + beatVersionRegex = regexp.MustCompile(`(?m)^const defaultBeatVersion = "(.+)"\r?$`) + beatVersionValue string + beatVersionErr error + beatVersionOnce sync.Once +) + +// BeatVersion returns the Beat's version. The value can be overridden by +// setting BEAT_VERSION in the environment. +func BeatVersion() (string, error) { + beatVersionOnce.Do(func() { + beatVersionValue = os.Getenv("BEAT_VERSION") + if beatVersionValue != "" { + return + } + + beatVersionValue, beatVersionErr = getBuildVariableSources().GetBeatVersion() + }) + + return beatVersionValue, beatVersionErr +} + +var ( + beatDocBranchRegex = regexp.MustCompile(`(?m)doc-branch:\s*([^\s]+)\r?$`) + beatDocBranchValue string + beatDocBranchErr error + beatDocBranchOnce sync.Once +) + +// BeatDocBranch returns the documentation branch name associated with the +// Beat branch. +func BeatDocBranch() (string, error) { + beatDocBranchOnce.Do(func() { + beatDocBranchValue = os.Getenv("BEAT_DOC_BRANCH") + if beatDocBranchValue != "" { + return + } + + beatDocBranchValue, beatDocBranchErr = getBuildVariableSources().GetDocBranch() + }) + + return beatDocBranchValue, beatDocBranchErr +} + +// --- BuildVariableSources + +var ( + // DefaultBeatBuildVariableSources contains the default locations build + // variables are read from by Elastic Beats. + DefaultBeatBuildVariableSources = &BuildVariableSources{ + BeatVersion: "{{ elastic_beats_dir }}/libbeat/version/version.go", + GoVersion: "{{ elastic_beats_dir }}/.go-version", + DocBranch: "{{ elastic_beats_dir }}/libbeat/docs/version.asciidoc", + } + + buildVariableSources *BuildVariableSources + buildVariableSourcesLock sync.Mutex +) + +// SetBuildVariableSources sets the BuildVariableSources that defines where +// certain build data should be sourced from. Community Beats must call this. +func SetBuildVariableSources(s *BuildVariableSources) { + buildVariableSourcesLock.Lock() + defer buildVariableSourcesLock.Unlock() + + buildVariableSources = s +} + +func getBuildVariableSources() *BuildVariableSources { + buildVariableSourcesLock.Lock() + defer buildVariableSourcesLock.Unlock() + + if buildVariableSources != nil { + return buildVariableSources + } + + repo, err := GetProjectRepoInfo() + if err != nil { + panic(err) + } + if repo.IsElasticBeats() { + buildVariableSources = DefaultBeatBuildVariableSources + return buildVariableSources + } + + panic(errors.Errorf("magefile must call mage.SetBuildVariableSources() "+ + "because it is not an elastic beat (repo=%+v)", repo.RootImportPath)) +} + +// BuildVariableSources is used to explicitly define what files contain build +// variables and how to parse the values from that file. This removes ambiguity +// about where the data is sources and allows a degree of customization for +// community Beats. +// +// Default parsers are used if one is not defined. +type BuildVariableSources struct { + // File containing the Beat version. + BeatVersion string + + // Parses the Beat version from the BeatVersion file. + BeatVersionParser func(data []byte) (string, error) + + // File containing the Go version to be used in cross-builds. + GoVersion string + + // Parses the Go version from the GoVersion file. + GoVersionParser func(data []byte) (string, error) + + // File containing the documentation branch. + DocBranch string + + // Parses the documentation branch from the DocBranch file. + DocBranchParser func(data []byte) (string, error) +} + +func (s *BuildVariableSources) expandVar(in string) (string, error) { + return expandTemplate("inline", in, map[string]interface{}{ + "elastic_beats_dir": ElasticBeatsDir, + }) +} + +// GetBeatVersion reads the BeatVersion file and parses the version from it. +func (s *BuildVariableSources) GetBeatVersion() (string, error) { + file, err := s.expandVar(s.BeatVersion) + if err != nil { + return "", err + } + + data, err := ioutil.ReadFile(file) + if err != nil { + return "", errors.Wrapf(err, "failed to read beat version file=%v", file) + } + + if s.BeatVersionParser == nil { + s.BeatVersionParser = parseBeatVersion + } + return s.BeatVersionParser(data) +} + +// GetGoVersion reads the GoVersion file and parses the version from it. +func (s *BuildVariableSources) GetGoVersion() (string, error) { + file, err := s.expandVar(s.GoVersion) + if err != nil { + return "", err + } + + data, err := ioutil.ReadFile(file) + if err != nil { + return "", errors.Wrapf(err, "failed to read go version file=%v", file) + } + + if s.GoVersionParser == nil { + s.GoVersionParser = parseGoVersion + } + return s.GoVersionParser(data) +} + +// GetDocBranch reads the DocBranch file and parses the branch from it. +func (s *BuildVariableSources) GetDocBranch() (string, error) { + file, err := s.expandVar(s.DocBranch) + if err != nil { + return "", err + } + + data, err := ioutil.ReadFile(file) + if err != nil { + return "", errors.Wrapf(err, "failed to read doc branch file=%v", file) + } + + if s.DocBranchParser == nil { + s.DocBranchParser = parseDocBranch + } + return s.DocBranchParser(data) +} + +func parseBeatVersion(data []byte) (string, error) { + matches := beatVersionRegex.FindSubmatch(data) + if len(matches) == 2 { + return string(matches[1]), nil + } + + return "", errors.New("failed to parse beat version file") +} + +func parseGoVersion(data []byte) (string, error) { + return strings.TrimSpace(string(data)), nil +} + +func parseDocBranch(data []byte) (string, error) { + matches := beatDocBranchRegex.FindSubmatch(data) + if len(matches) == 2 { + return string(matches[1]), nil + } + + return "", errors.New("failed to parse beat doc branch") +} + +// --- ProjectRepoInfo + +// ProjectRepoInfo contains information about the project's repo. +type ProjectRepoInfo struct { + RootImportPath string // Import path at the project root. + RootDir string // Root directory of the project. + ImportPath string // Import path of the current directory. + SubDir string // Relative path from the root dir to the current dir. +} + +// IsElasticBeats returns true if the current project is +// github.com/elastic/beats. +func (r *ProjectRepoInfo) IsElasticBeats() bool { + return r.RootImportPath == elasticBeatsImportPath +} + +var ( + repoInfoValue *ProjectRepoInfo + repoInfoErr error + repoInfoOnce sync.Once +) + +// GetProjectRepoInfo returns information about the repo including the root +// import path and the current directory's import path. +func GetProjectRepoInfo() (*ProjectRepoInfo, error) { + repoInfoOnce.Do(func() { + repoInfoValue, repoInfoErr = getProjectRepoInfo() + }) + + return repoInfoValue, repoInfoErr +} + +func getProjectRepoInfo() (*ProjectRepoInfo, error) { + var ( + cwd = CWD() + rootImportPath string + srcDir string + ) + + // Search upward from the CWD to determine the project root based on VCS. + var errs []string + for _, gopath := range filepath.SplitList(build.Default.GOPATH) { + gopath = filepath.Clean(gopath) + + if !strings.HasPrefix(cwd, gopath) { + // Fixes an issue on macOS when /var is actually /private/var. + var err error + gopath, err = filepath.EvalSymlinks(gopath) + if err != nil { + errs = append(errs, err.Error()) + continue + } + } + + srcDir = filepath.Join(gopath, "src") + _, root, err := vcs.FromDir(cwd, srcDir) + if err != nil { + // Try the next gopath. + errs = append(errs, err.Error()) + continue + } + rootImportPath = root + break + } + if rootImportPath == "" { + return nil, errors.Errorf("failed to determine root import path (Did "+ + "you git init?, Is the project in the GOPATH? GOPATH=%v, CWD=%v?): %v", + build.Default.GOPATH, cwd, errs) + } + + rootDir := filepath.Join(srcDir, rootImportPath) + subDir, err := filepath.Rel(rootDir, cwd) + if err != nil { + return nil, errors.Wrap(err, "failed to get relative path to repo root") + } + importPath := filepath.ToSlash(filepath.Join(rootImportPath, subDir)) + + return &ProjectRepoInfo{ + RootImportPath: rootImportPath, + RootDir: rootDir, + SubDir: subDir, + ImportPath: importPath, + }, nil +} diff --git a/dev-tools/mage/templates/common/README.md.tmpl b/dev-tools/mage/templates/common/README.md.tmpl new file mode 100644 index 000000000000..5754ce7f87f3 --- /dev/null +++ b/dev-tools/mage/templates/common/README.md.tmpl @@ -0,0 +1,27 @@ +# Welcome to {{.BeatName | title}} {{.Version}}{{if .Snapshot}}-SNAPSHOT{{end}} + +{{.Description}} + +## Getting Started + +To get started with {{.BeatName | title}}, you need to set up Elasticsearch on +your localhost first. After that, start {{.BeatName | title}} with: + + ./{{.BeatName}} -c {{.BeatName}}.yml -e + +This will start {{.BeatName | title }} and send the data to your Elasticsearch +instance. To load the dashboards for {{.BeatName | title}} into Kibana, run: + + ./{{.BeatName}} setup -e + +For further steps visit the +[Getting started](https://www.elastic.co/guide/en/beats/{{.BeatName}}/{{ beat_doc_branch }}/{{.BeatName}}-getting-started.html) guide. + +## Documentation + +Visit [Elastic.co Docs](https://www.elastic.co/guide/en/beats/{{.BeatName}}/{{ beat_doc_branch }}/index.html) +for the full {{.BeatName | title}} documentation. + +## Release notes + +https://www.elastic.co/guide/en/beats/libbeat/{{ beat_doc_branch }}/release-notes-{{.Version}}.html diff --git a/dev-tools/mage/templates/common/magefile.go.tmpl b/dev-tools/mage/templates/common/magefile.go.tmpl new file mode 100644 index 000000000000..1a9822d2491c --- /dev/null +++ b/dev-tools/mage/templates/common/magefile.go.tmpl @@ -0,0 +1,72 @@ +// +build mage + +package main + +import ( + "fmt" + "time" + + "github.com/magefile/mage/mg" + "github.com/magefile/mage/sh" + + "github.com/elastic/beats/dev-tools/mage" +) + +func init() { + mage.BeatDescription = "One sentence description of the Beat." +} + +// Build builds the Beat binary. +func Build() error { + return mage.Build(mage.DefaultBuildArgs()) +} + +// GolangCrossBuild build the Beat binary inside of the golang-builder. +// Do not use directly, use crossBuild instead. +func GolangCrossBuild() error { + return mage.GolangCrossBuild(mage.DefaultGolangCrossBuildArgs()) +} + +// BuildGoDaemon builds the go-daemon binary (use crossBuildGoDaemon). +func BuildGoDaemon() error { + return mage.BuildGoDaemon() +} + +// CrossBuild cross-builds the beat for all target platforms. +func CrossBuild() error { + return mage.CrossBuild() +} + +// CrossBuildGoDaemon cross-builds the go-daemon binary using Docker. +func CrossBuildGoDaemon() error { + return mage.CrossBuildGoDaemon() +} + +// Clean cleans all generated files and build artifacts. +func Clean() error { + return mage.Clean() +} + +// Package packages the Beat for distribution. +// Use SNAPSHOT=true to build snapshots. +// Use PLATFORMS to control the target platforms. +func Package() { + start := time.Now() + defer func() { fmt.Println("package ran for", time.Since(start)) }() + + mage.UseCommunityBeatPackaging() + + mg.Deps(Update) + mg.Deps(CrossBuild, CrossBuildGoDaemon) + mg.SerialDeps(mage.Package, TestPackages) +} + +// TestPackages tests the generated packages (i.e. file modes, owners, groups). +func TestPackages() error { + return mage.TestPackages() +} + +// Update updates the generated files (aka make update). +func Update() error { + return sh.Run("make", "update") +} diff --git a/dev-tools/mage/templates/deb/init.sh.tmpl b/dev-tools/mage/templates/deb/init.sh.tmpl new file mode 100644 index 000000000000..1e793c9184da --- /dev/null +++ b/dev-tools/mage/templates/deb/init.sh.tmpl @@ -0,0 +1,188 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: {{.ServiceName}} +# Required-Start: $local_fs $network $syslog +# Required-Stop: $local_fs $network $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: {{.Description}} +# Description: {{.BeatName | title}} is a shipper part of the Elastic Beats +# family. Please see: https://www.elastic.co/products/beats +### END INIT INFO + +# Do NOT "set -e" + +# PATH should only include /usr/* if it runs after the mountnfs.sh script +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC="{{.Description}}" +NAME="{{.BeatName}}" +DAEMON=/usr/share/${NAME}/bin/${NAME} +DAEMON_ARGS="-c /etc/${NAME}/${NAME}.yml -path.home /usr/share/${NAME} -path.config /etc/${NAME} -path.data /var/lib/${NAME} -path.logs /var/log/${NAME}" +TEST_ARGS="-e test config" +PIDFILE=/var/run/{{.ServiceName}}.pid +WRAPPER="/usr/share/${NAME}/bin/${NAME}-god" +BEAT_USER="root" +WRAPPER_ARGS="-r / -n -p $PIDFILE" +SCRIPTNAME=/etc/init.d/{{.ServiceName}} + +# Exit if the package is not installed +[ -x "$DAEMON" ] || exit 0 + +# Read configuration variable file if it is present +[ -r /etc/default/{{.ServiceName}} ] && . /etc/default/{{.ServiceName}} + +[ "$BEAT_USER" != "root" ] && WRAPPER_ARGS="$WRAPPER_ARGS -u $BEAT_USER" +USER_WRAPPER="su" +USER_WRAPPER_ARGS="$BEAT_USER -c" + +if command -v runuser >/dev/null 2>&1; then + USER_WRAPPER="runuser" +fi + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.2-14) to ensure that this file is present +# and status_of_proc is working. +. /lib/lsb/init-functions + +# +# Function that calls runs the service in foreground +# to test its configuration. +# +do_test() +{ + $USER_WRAPPER $USER_WRAPPER_ARGS "$DAEMON $DAEMON_ARGS $TEST_ARGS" +} + +# +# Function that starts the daemon/service +# +do_start() +{ + # Return + # 0 if daemon has been started + # 1 if daemon was already running + # 2 if daemon could not be started + start-stop-daemon --start \ + --pidfile $PIDFILE \ + --exec $WRAPPER -- $WRAPPER_ARGS -- $DAEMON $DAEMON_ARGS \ + || return 2 +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + # Return + # 0 if daemon has been stopped + # 1 if daemon was already stopped + # 2 if daemon could not be stopped + # other if a failure occurred + start-stop-daemon --stop --quiet --retry=TERM/5/KILL/5 --pidfile $PIDFILE --exec $WRAPPER + RETVAL="$?" + [ "$RETVAL" = 2 ] && return 2 + # Wait for children to finish too if this is a daemon that forks + # and if the daemon is only ever run from this initscript. + # If the above conditions are not satisfied then add some other code + # that waits for the process to drop all resources that could be + # needed by services started subsequently. A last resort is to + # sleep for some time. + start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON + [ "$?" = 2 ] && return 2 + # Many daemons don't delete their pidfiles when they exit. + rm -f $PIDFILE + return "$RETVAL" +} + +# +# Function that sends a SIGHUP to the daemon/service +# +do_reload() { + # + # If the daemon can reload its configuration without + # restarting (for example, when it is sent a SIGHUP), + # then implement that here. + # + start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --exec $DAEMON + return 0 +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_test + case "$?" in + 0) ;; + *) + log_end_msg 1 + exit 1 + ;; + esac + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + status) + status_of_proc "$WRAPPER" "$NAME" && exit 0 || exit $? + ;; + #reload|force-reload) + # + # If do_reload() is not implemented then leave this commented out + # and leave 'force-reload' as an alias for 'restart'. + # + #log_daemon_msg "Reloading $DESC" "$NAME" + #do_reload + #log_end_msg $? + #;; + restart|force-reload) + # + # If the "reload" option is implemented then remove the + # 'force-reload' alias + # + log_daemon_msg "Restarting $DESC" "$NAME" + do_test + case "$?" in + 0) ;; + *) + log_end_msg 1 # Old process is still running + exit 1 + ;; + esac + + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 + echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 + exit 3 + ;; +esac + +: diff --git a/dev-tools/mage/templates/linux/beatname.sh.tmpl b/dev-tools/mage/templates/linux/beatname.sh.tmpl new file mode 100644 index 000000000000..fce8cfb62591 --- /dev/null +++ b/dev-tools/mage/templates/linux/beatname.sh.tmpl @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +# Script to run {{.BeatName | title}} in foreground with the same path settings that +# the init script / systemd unit file would do. + +exec /usr/share/{{.BeatName}}/bin/{{.BeatName}} \ + -path.home /usr/share/{{.BeatName}} \ + -path.config /etc/{{.BeatName}} \ + -path.data /var/lib/{{.BeatName}} \ + -path.logs /var/log/{{.BeatName}} \ + "$@" diff --git a/dev-tools/mage/templates/linux/systemd.unit.tmpl b/dev-tools/mage/templates/linux/systemd.unit.tmpl new file mode 100644 index 000000000000..5725ba3e2a37 --- /dev/null +++ b/dev-tools/mage/templates/linux/systemd.unit.tmpl @@ -0,0 +1,12 @@ +[Unit] +Description={{.Description}} +Documentation={{.URL}} +Wants=network-online.target +After=network-online.target + +[Service] +ExecStart=/usr/share/{{.BeatName}}/bin/{{.BeatName}} -c /etc/{{.BeatName}}/{{.BeatName}}.yml -path.home /usr/share/{{.BeatName}} -path.config /etc/{{.BeatName}} -path.data /var/lib/{{.BeatName}} -path.logs /var/log/{{.BeatName}} +Restart=always + +[Install] +WantedBy=multi-user.target diff --git a/dev-tools/mage/templates/rpm/init.sh.tmpl b/dev-tools/mage/templates/rpm/init.sh.tmpl new file mode 100644 index 000000000000..e9a32ae74a5f --- /dev/null +++ b/dev-tools/mage/templates/rpm/init.sh.tmpl @@ -0,0 +1,119 @@ +#!/bin/bash +# +# {{.ServiceName}} {{.BeatName}} shipper +# +# chkconfig: 2345 98 02 +# description: Starts and stops a single {{.BeatName}} instance on this system +# + +### BEGIN INIT INFO +# Provides: {{.ServiceName}} +# Required-Start: $local_fs $network $syslog +# Required-Stop: $local_fs $network $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: {{.Description}} +# Description: {{.BeatName | title}} is a shipper part of the Elastic Beats +# family. Please see: https://www.elastic.co/products/beats +### END INIT INFO + + + +PATH=/usr/bin:/sbin:/bin:/usr/sbin +export PATH + +[ -f /etc/sysconfig/{{.ServiceName}} ] && . /etc/sysconfig/{{.ServiceName}} +pidfile=${PIDFILE-/var/run/{{.ServiceName}}.pid} +agent=${BEATS_AGENT-/usr/share/{{.BeatName}}/bin/{{.BeatName}}} +args="-c /etc/{{.BeatName}}/{{.BeatName}}.yml -path.home /usr/share/{{.BeatName}} -path.config /etc/{{.BeatName}} -path.data /var/lib/{{.BeatName}} -path.logs /var/log/{{.BeatName}}" +test_args="-e test config" +beat_user="${BEAT_USER:-root}" +wrapper="/usr/share/{{.BeatName}}/bin/{{.BeatName}}-god" +wrapperopts="-r / -n -p $pidfile" +user_wrapper="su" +user_wrapperopts="$beat_user -c" +RETVAL=0 + +# Source function library. +. /etc/rc.d/init.d/functions + +# Determine if we can use the -p option to daemon, killproc, and status. +# RHEL < 5 can't. +if status | grep -q -- '-p' 2>/dev/null; then + daemonopts="--pidfile $pidfile" + pidopts="-p $pidfile" +fi + +if command -v runuser >/dev/null 2>&1; then + user_wrapper="runuser" +fi + +[ "$beat_user" != "root" ] && wrapperopts="$wrapperopts -u $beat_user" + +test() { + $user_wrapper $user_wrapperopts "$agent $args $test_args" +} + +start() { + echo -n $"Starting {{.BeatName}}: " + test + if [ $? -ne 0 ]; then + echo + exit 1 + fi + daemon $daemonopts $wrapper $wrapperopts -- $agent $args + RETVAL=$? + echo + return $RETVAL +} + +stop() { + echo -n $"Stopping {{.BeatName}}: " + killproc $pidopts $wrapper + RETVAL=$? + echo + [ $RETVAL = 0 ] && rm -f ${pidfile} +} + +restart() { + test + if [ $? -ne 0 ]; then + return 1 + fi + stop + start +} + +rh_status() { + status $pidopts $wrapper + RETVAL=$? + return $RETVAL +} + +rh_status_q() { + rh_status >/dev/null 2>&1 +} + +case "$1" in + start) + start + ;; + stop) + stop + ;; + restart) + restart + ;; + condrestart|try-restart) + rh_status_q || exit 0 + restart + ;; + status) + rh_status + ;; + *) + echo $"Usage: $0 {start|stop|status|restart|condrestart}" + exit 1 +esac + +exit $RETVAL diff --git a/dev-tools/mage/templates/windows/install-service.ps1.tmpl b/dev-tools/mage/templates/windows/install-service.ps1.tmpl new file mode 100644 index 000000000000..c4b4f682f3c7 --- /dev/null +++ b/dev-tools/mage/templates/windows/install-service.ps1.tmpl @@ -0,0 +1,14 @@ +# Delete and stop the service if it already exists. +if (Get-Service {{.BeatName}} -ErrorAction SilentlyContinue) { + $service = Get-WmiObject -Class Win32_Service -Filter "name='{{.BeatName}}'" + $service.StopService() + Start-Sleep -s 1 + $service.delete() +} + +$workdir = Split-Path $MyInvocation.MyCommand.Path + +# Create the new service. +New-Service -name {{.BeatName}} ` + -displayName {{.BeatName | title}} ` + -binaryPathName "`"$workdir\{{.BeatName}}.exe`" -c `"$workdir\{{.BeatName}}.yml`" -path.home `"$workdir`" -path.data `"C:\ProgramData\{{.BeatName}}`" -path.logs `"C:\ProgramData\{{.BeatName}}\logs`"" diff --git a/dev-tools/mage/templates/windows/uninstall-service.ps1.tmpl b/dev-tools/mage/templates/windows/uninstall-service.ps1.tmpl new file mode 100644 index 000000000000..902a13a885c6 --- /dev/null +++ b/dev-tools/mage/templates/windows/uninstall-service.ps1.tmpl @@ -0,0 +1,7 @@ +# Delete and stop the service if it already exists. +if (Get-Service {{.BeatName}} -ErrorAction SilentlyContinue) { + $service = Get-WmiObject -Class Win32_Service -Filter "name='{{.BeatName}}'" + $service.StopService() + Start-Sleep -s 1 + $service.delete() +} diff --git a/dev-tools/mage/testdata/config.yml b/dev-tools/mage/testdata/config.yml new file mode 100644 index 000000000000..3b5bf4a1dabd --- /dev/null +++ b/dev-tools/mage/testdata/config.yml @@ -0,0 +1,7 @@ +brewbeat.modules: +- module: milling +- module: mashing +- module: lautering +- module: boil +- module: fermenting +- module: bottle diff --git a/dev-tools/package_test.go b/dev-tools/package_test.go index 4b4dd7e75367..2021a42a4a29 100644 --- a/dev-tools/package_test.go +++ b/dev-tools/package_test.go @@ -47,7 +47,7 @@ const ( ) var ( - configFilePattern = regexp.MustCompile(`.*beat\.yml`) + configFilePattern = regexp.MustCompile(`.*beat\.yml|apm-server\.yml`) manifestFilePattern = regexp.MustCompile(`manifest.yml`) modulesDirPattern = regexp.MustCompile(`modules.d/$`) modulesFilePattern = regexp.MustCompile(`modules.d/.+`) diff --git a/filebeat/Makefile b/filebeat/Makefile index 78b897e54fba..1c2c6f8d47b9 100644 --- a/filebeat/Makefile +++ b/filebeat/Makefile @@ -1,19 +1,13 @@ BEAT_NAME?=filebeat BEAT_TITLE?=Filebeat -BEAT_DESCRIPTION?=Filebeat sends log files to Logstash or directly to Elasticsearch. SYSTEM_TESTS?=true TEST_ENVIRONMENT?=true GOX_FLAGS=-arch="amd64 386 arm ppc64 ppc64le" ES_BEATS?=.. FIELDS_FILE_PATH=module - include ${ES_BEATS}/libbeat/scripts/Makefile -# This is called by the beats packer before building starts -.PHONY: before-build -before-build: - # Collects all module dashboards .PHONY: kibana kibana: diff --git a/filebeat/magefile.go b/filebeat/magefile.go new file mode 100644 index 000000000000..a5c378e3d993 --- /dev/null +++ b/filebeat/magefile.go @@ -0,0 +1,88 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +// +build mage + +package main + +import ( + "fmt" + "time" + + "github.com/magefile/mage/mg" + "github.com/magefile/mage/sh" + + "github.com/elastic/beats/dev-tools/mage" +) + +func init() { + mage.BeatDescription = "Filebeat sends log files to Logstash or directly to Elasticsearch." +} + +// Build builds the Beat binary. +func Build() error { + return mage.Build(mage.DefaultBuildArgs()) +} + +// GolangCrossBuild build the Beat binary inside of the golang-builder. +// Do not use directly, use crossBuild instead. +func GolangCrossBuild() error { + return mage.GolangCrossBuild(mage.DefaultGolangCrossBuildArgs()) +} + +// BuildGoDaemon builds the go-daemon binary (use crossBuildGoDaemon). +func BuildGoDaemon() error { + return mage.BuildGoDaemon() +} + +// CrossBuild cross-builds the beat for all target platforms. +func CrossBuild() error { + return mage.CrossBuild() +} + +// CrossBuildGoDaemon cross-builds the go-daemon binary using Docker. +func CrossBuildGoDaemon() error { + return mage.CrossBuildGoDaemon() +} + +// Clean cleans all generated files and build artifacts. +func Clean() error { + return mage.Clean() +} + +// Package packages the Beat for distribution. +// Use SNAPSHOT=true to build snapshots. +// Use PLATFORMS to control the target platforms. +func Package() { + start := time.Now() + defer func() { fmt.Println("package ran for", time.Since(start)) }() + + mage.UseElasticBeatPackaging() + mg.Deps(Update) + mg.Deps(CrossBuild, CrossBuildGoDaemon) + mg.SerialDeps(mage.Package, TestPackages) +} + +// TestPackages tests the generated packages (i.e. file modes, owners, groups). +func TestPackages() error { + return mage.TestPackages() +} + +// Update updates the generated files (aka make update). +func Update() error { + return sh.Run("make", "update") +} diff --git a/generator/beat/{beat}/LICENSE b/generator/beat/{beat}/LICENSE.txt similarity index 100% rename from generator/beat/{beat}/LICENSE rename to generator/beat/{beat}/LICENSE.txt diff --git a/generator/beat/{beat}/Makefile b/generator/beat/{beat}/Makefile index 4d5248b74d82..911884af2844 100644 --- a/generator/beat/{beat}/Makefile +++ b/generator/beat/{beat}/Makefile @@ -1,29 +1,28 @@ BEAT_NAME={beat} BEAT_PATH={beat_path} BEAT_GOPATH=$(firstword $(subst :, ,${GOPATH})) -BEAT_URL=https://${BEAT_PATH} SYSTEM_TESTS=false TEST_ENVIRONMENT=false ES_BEATS?=./vendor/github.com/elastic/beats GOPACKAGES=$(shell govendor list -no-status +local) -PREFIX?=. -NOTICE_FILE=NOTICE GOBUILD_FLAGS=-i -ldflags "-X $(BEAT_PATH)/vendor/github.com/elastic/beats/libbeat/version.buildTime=$(NOW) -X $(BEAT_PATH)/vendor/github.com/elastic/beats/libbeat/version.commit=$(COMMIT_ID)" +MAGE_IMPORT_PATH=${BEAT_PATH}/vendor/github.com/magefile/mage # Path to the libbeat Makefile -include $(ES_BEATS)/libbeat/scripts/Makefile # Initial beat setup .PHONY: setup -setup: copy-vendor - $(MAKE) update +setup: copy-vendor update git-init # Copy beats into vendor directory .PHONY: copy-vendor copy-vendor: - mkdir -p vendor/github.com/elastic/ + mkdir -p vendor/github.com/elastic cp -R ${BEAT_GOPATH}/src/github.com/elastic/beats vendor/github.com/elastic/ rm -rf vendor/github.com/elastic/beats/.git vendor/github.com/elastic/beats/x-pack + mkdir -p vendor/github.com/magefile + cp -R ${BEAT_GOPATH}/src/github.com/elastic/beats/vendor/github.com/magefile/mage vendor/github.com/magefile .PHONY: git-init git-init: @@ -40,10 +39,6 @@ git-init: git add .travis.yml git commit -m "Add Travis CI" -# This is called by the beats packer before building starts -.PHONY: before-build -before-build: - # Collects all dependencies and then calls update .PHONY: collect collect: fields diff --git a/generator/beat/{beat}/NOTICE b/generator/beat/{beat}/NOTICE.txt similarity index 100% rename from generator/beat/{beat}/NOTICE rename to generator/beat/{beat}/NOTICE.txt diff --git a/generator/beat/{beat}/magefile.go b/generator/beat/{beat}/magefile.go new file mode 100644 index 000000000000..545af4c3d106 --- /dev/null +++ b/generator/beat/{beat}/magefile.go @@ -0,0 +1,91 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +// +build mage + +package main + +import ( + "fmt" + "time" + + "github.com/magefile/mage/mg" + "github.com/magefile/mage/sh" + + "github.com/elastic/beats/dev-tools/mage" +) + +func init() { + mage.SetBuildVariableSources(mage.DefaultBeatBuildVariableSources) + + mage.BeatDescription = "One sentence description of the Beat." +} + +// Build builds the Beat binary. +func Build() error { + return mage.Build(mage.DefaultBuildArgs()) +} + +// GolangCrossBuild build the Beat binary inside of the golang-builder. +// Do not use directly, use crossBuild instead. +func GolangCrossBuild() error { + return mage.GolangCrossBuild(mage.DefaultGolangCrossBuildArgs()) +} + +// BuildGoDaemon builds the go-daemon binary (use crossBuildGoDaemon). +func BuildGoDaemon() error { + return mage.BuildGoDaemon() +} + +// CrossBuild cross-builds the beat for all target platforms. +func CrossBuild() error { + return mage.CrossBuild() +} + +// CrossBuildGoDaemon cross-builds the go-daemon binary using Docker. +func CrossBuildGoDaemon() error { + return mage.CrossBuildGoDaemon() +} + +// Clean cleans all generated files and build artifacts. +func Clean() error { + return mage.Clean() +} + +// Package packages the Beat for distribution. +// Use SNAPSHOT=true to build snapshots. +// Use PLATFORMS to control the target platforms. +func Package() { + start := time.Now() + defer func() { fmt.Println("package ran for", time.Since(start)) }() + + mage.UseCommunityBeatPackaging() + + mg.Deps(Update) + mg.Deps(CrossBuild, CrossBuildGoDaemon) + mg.SerialDeps(mage.Package, TestPackages) +} + +// TestPackages tests the generated packages (i.e. file modes, owners, groups). +func TestPackages() error { + return mage.TestPackages() +} + +// Update updates the generated files (aka make update). +func Update() error { + return sh.Run("make", "update") +} diff --git a/generator/metricbeat/{beat}/LICENSE b/generator/metricbeat/{beat}/LICENSE.txt similarity index 100% rename from generator/metricbeat/{beat}/LICENSE rename to generator/metricbeat/{beat}/LICENSE.txt diff --git a/generator/metricbeat/{beat}/Makefile b/generator/metricbeat/{beat}/Makefile index c50dc3c3b4d3..29e060caecfc 100644 --- a/generator/metricbeat/{beat}/Makefile +++ b/generator/metricbeat/{beat}/Makefile @@ -1,30 +1,32 @@ BEAT_NAME={beat} BEAT_PATH={beat_path} -BEAT_URL=https://${BEAT_PATH} +BEAT_GOPATH=$(firstword $(subst :, ,${GOPATH})) SYSTEM_TESTS=false TEST_ENVIRONMENT=false ES_BEATS?=./vendor/github.com/elastic/beats GOPACKAGES=$(shell govendor list -no-status +local) -PREFIX?=. -NOTICE_FILE=NOTICE +GOBUILD_FLAGS=-i -ldflags "-X $(BEAT_PATH)/vendor/github.com/elastic/beats/libbeat/version.buildTime=$(NOW) -X $(BEAT_PATH)/vendor/github.com/elastic/beats/libbeat/version.commit=$(COMMIT_ID)" +MAGE_IMPORT_PATH=${BEAT_PATH}/vendor/github.com/magefile/mage # Path to the libbeat Makefile -include $(ES_BEATS)/metricbeat/Makefile # Initial beat setup .PHONY: setup -setup: copy-vendor - $(MAKE) create-metricset - $(MAKE) collect +setup: copy-vendor create-metricset collect git-init # Copy beats into vendor directory .PHONY: copy-vendor copy-vendor: - mkdir -p vendor/github.com/elastic/ + mkdir -p vendor/github.com/elastic cp -R ${GOPATH}/src/github.com/elastic/beats vendor/github.com/elastic/ ln -s ${PWD}/vendor/github.com/elastic/beats/metricbeat/scripts/generate_imports_helper.py ${PWD}/vendor/github.com/elastic/beats/script/generate_imports_helper.py rm -rf vendor/github.com/elastic/beats/.git vendor/github.com/elastic/beats/x-pack + mkdir -p vendor/github.com/magefile + cp -R ${BEAT_GOPATH}/src/github.com/elastic/beats/vendor/github.com/magefile/mage vendor/github.com/magefile -# This is called by the beats packer before building starts -.PHONY: before-build -before-build: +.PHONY: git-init +git-init: + git init + git add --all + git commit -m 'Initial add by Beat generator' diff --git a/generator/metricbeat/{beat}/NOTICE b/generator/metricbeat/{beat}/NOTICE.txt similarity index 100% rename from generator/metricbeat/{beat}/NOTICE rename to generator/metricbeat/{beat}/NOTICE.txt diff --git a/generator/metricbeat/{beat}/magefile.go b/generator/metricbeat/{beat}/magefile.go new file mode 100644 index 000000000000..545af4c3d106 --- /dev/null +++ b/generator/metricbeat/{beat}/magefile.go @@ -0,0 +1,91 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +// +build mage + +package main + +import ( + "fmt" + "time" + + "github.com/magefile/mage/mg" + "github.com/magefile/mage/sh" + + "github.com/elastic/beats/dev-tools/mage" +) + +func init() { + mage.SetBuildVariableSources(mage.DefaultBeatBuildVariableSources) + + mage.BeatDescription = "One sentence description of the Beat." +} + +// Build builds the Beat binary. +func Build() error { + return mage.Build(mage.DefaultBuildArgs()) +} + +// GolangCrossBuild build the Beat binary inside of the golang-builder. +// Do not use directly, use crossBuild instead. +func GolangCrossBuild() error { + return mage.GolangCrossBuild(mage.DefaultGolangCrossBuildArgs()) +} + +// BuildGoDaemon builds the go-daemon binary (use crossBuildGoDaemon). +func BuildGoDaemon() error { + return mage.BuildGoDaemon() +} + +// CrossBuild cross-builds the beat for all target platforms. +func CrossBuild() error { + return mage.CrossBuild() +} + +// CrossBuildGoDaemon cross-builds the go-daemon binary using Docker. +func CrossBuildGoDaemon() error { + return mage.CrossBuildGoDaemon() +} + +// Clean cleans all generated files and build artifacts. +func Clean() error { + return mage.Clean() +} + +// Package packages the Beat for distribution. +// Use SNAPSHOT=true to build snapshots. +// Use PLATFORMS to control the target platforms. +func Package() { + start := time.Now() + defer func() { fmt.Println("package ran for", time.Since(start)) }() + + mage.UseCommunityBeatPackaging() + + mg.Deps(Update) + mg.Deps(CrossBuild, CrossBuildGoDaemon) + mg.SerialDeps(mage.Package, TestPackages) +} + +// TestPackages tests the generated packages (i.e. file modes, owners, groups). +func TestPackages() error { + return mage.TestPackages() +} + +// Update updates the generated files (aka make update). +func Update() error { + return sh.Run("make", "update") +} diff --git a/heartbeat/Makefile b/heartbeat/Makefile index bc151e77cc12..16053181ce5f 100644 --- a/heartbeat/Makefile +++ b/heartbeat/Makefile @@ -1,7 +1,5 @@ BEAT_NAME=heartbeat BEAT_TITLE=Heartbeat -BEAT_PACKAGE_NAME=heartbeat-elastic -BEAT_DESCRIPTION?=Ping remote services for availability and log results to Elasticsearch or send to Logstash. SYSTEM_TESTS=true TEST_ENVIRONMENT=false FIELDS_FILE_PATH=monitors/active @@ -9,10 +7,6 @@ FIELDS_FILE_PATH=monitors/active # Path to the libbeat Makefile -include ../libbeat/scripts/Makefile -# This is called by the beats packer before building starts -.PHONY: before-build -before-build: - # Collects all dependencies and then calls update .PHONY: collect collect: fields imports kibana diff --git a/heartbeat/magefile.go b/heartbeat/magefile.go new file mode 100644 index 000000000000..f52d0935da9d --- /dev/null +++ b/heartbeat/magefile.go @@ -0,0 +1,90 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +// +build mage + +package main + +import ( + "fmt" + "time" + + "github.com/magefile/mage/mg" + "github.com/magefile/mage/sh" + + "github.com/elastic/beats/dev-tools/mage" +) + +func init() { + mage.BeatDescription = "Ping remote services for availability and log " + + "results to Elasticsearch or send to Logstash." + mage.BeatServiceName = "heartbeat-elastic" +} + +// Build builds the Beat binary. +func Build() error { + return mage.Build(mage.DefaultBuildArgs()) +} + +// GolangCrossBuild build the Beat binary inside of the golang-builder. +// Do not use directly, use crossBuild instead. +func GolangCrossBuild() error { + return mage.GolangCrossBuild(mage.DefaultGolangCrossBuildArgs()) +} + +// BuildGoDaemon builds the go-daemon binary (use crossBuildGoDaemon). +func BuildGoDaemon() error { + return mage.BuildGoDaemon() +} + +// CrossBuild cross-builds the beat for all target platforms. +func CrossBuild() error { + return mage.CrossBuild() +} + +// CrossBuildGoDaemon cross-builds the go-daemon binary using Docker. +func CrossBuildGoDaemon() error { + return mage.CrossBuildGoDaemon() +} + +// Clean cleans all generated files and build artifacts. +func Clean() error { + return mage.Clean() +} + +// Package packages the Beat for distribution. +// Use SNAPSHOT=true to build snapshots. +// Use PLATFORMS to control the target platforms. +func Package() { + start := time.Now() + defer func() { fmt.Println("package ran for", time.Since(start)) }() + + mage.UseElasticBeatPackaging() + mg.Deps(Update) + mg.Deps(CrossBuild, CrossBuildGoDaemon) + mg.SerialDeps(mage.Package, TestPackages) +} + +// TestPackages tests the generated packages (i.e. file modes, owners, groups). +func TestPackages() error { + return mage.TestPackages() +} + +// Update updates the generated files (aka make update). +func Update() error { + return sh.Run("make", "update") +} diff --git a/libbeat/scripts/Makefile b/libbeat/scripts/Makefile index 0ba105e9b604..73e839179660 100755 --- a/libbeat/scripts/Makefile +++ b/libbeat/scripts/Makefile @@ -2,7 +2,6 @@ ### Application using libbeat may override the following variables in their Makefile BEAT_NAME?=libbeat## @packaging Name of the binary BEAT_TITLE?=${BEAT_NAME}## @packaging Title of the application -BEAT_DESCRIPTION?=Sends events to Elasticsearch or Logstash ## @packaging Description of the application BEAT_PATH?=github.com/elastic/beats/${BEAT_NAME} BEAT_PACKAGE_NAME?=${BEAT_NAME} BEAT_INDEX_PREFIX?=${BEAT_NAME} @@ -21,6 +20,7 @@ ELASTIC_LICENSE_FILE?=../licenses/ELASTIC-LICENSE.txt SECCOMP_BINARY?=${BEAT_NAME} SECCOMP_BLACKLIST?=${ES_BEATS}/libbeat/common/seccomp/seccomp-profiler-blacklist.txt SECCOMP_ALLOWLIST?=${ES_BEATS}/libbeat/common/seccomp/seccomp-profiler-allow.txt +MAGE_IMPORT_PATH?=github.com/elastic/beats/vendor/github.com/magefile/mage space:=$() # comma:=, @@ -81,16 +81,6 @@ INTEGRATION_TESTS?= FIND=. ${PYTHON_ENV}/bin/activate; find . -type f -not -path "*/vendor/*" -not -path "*/build/*" -not -path "*/.git/*" PERM_EXEC?=$(shell [ `uname -s` = "Darwin" ] && echo "+111" || echo "/a+x") -# Cross compiling targets -CGO?=true ## @building if true, Build with C Go support -TARGETS?="windows/amd64 windows/386 darwin/amd64 linux/arm" ## @building list of platforms/architecture to be built by "make package" -TARGETS_OLD?="linux/amd64 linux/386" ## @building list of Debian6 architecture to be built by "make package" when CGO is true -PACKAGES?=${BEAT_NAME}/deb ${BEAT_NAME}/rpm ${BEAT_NAME}/darwin ${BEAT_NAME}/win ${BEAT_NAME}/bin ## @Building List of OS to be supported by "make package" -PACKAGES_EXPERIMENTAL?=${BEAT_NAME}/arm ## @Building List of experimental OS by "make package". Only build when SNAPSHOT=yes -SNAPSHOT?=yes ## @Building If yes, builds a snapshot version -BEATS_BUILDER_IMAGE?=tudorg/beats-builder ## @Building Name of the docker image to use when packaging the application -BEATS_BUILDER_DEB_IMAGE?=tudorg/beats-builder-deb7 ## @Building Name of the docker image to use when packaging the application for Debian 7 - ifeq ($(DOCKER_CACHE),0) DOCKER_NOCACHE=--no-cache endif @@ -100,11 +90,6 @@ ifeq ($(RACE_DETECTOR),1) RACE=-race endif -# Only build experimental targets for snapshots -ifneq ($(SNAPSHOT),yes) - PACKAGES_EXPERIMENTAL= -endif - ### BUILDING ### @@ -163,8 +148,9 @@ clean:: ## @build Cleans up all files generated by the build steps @rm -f docker-compose.yml.lock @rm -f ${BEAT_NAME} ${BEAT_NAME}.test ${BEAT_NAME}.exe ${BEAT_NAME}.test.exe @rm -f _meta/fields.generated.yml fields.yml - @rm -fr $(PWD)/_meta/kibana.generated + @rm -rf $(PWD)/_meta/kibana.generated @rm -f ${BEAT_NAME}.template*.json + @-mage -clean 2> /dev/null .PHONY: ci ci: ## @build Shortcut for continuous integration. This should always run before merging. @@ -370,7 +356,6 @@ endif docs: ## @build Builds the documents for the beat sh ${ES_BEATS}/script/build_docs.sh ${BEAT_NAME} ${BEAT_PATH}/docs ${BUILD_DIR} - .PHONY: docs-preview docs-preview: ## @build Preview the documents for the beat in the browser PREVIEW=1 $(MAKE) docs @@ -417,152 +402,6 @@ write-environment: env-logs: ${DOCKER_COMPOSE} logs -f - -### Packaging targets #### - -# Installs the files that need to get to the home path on installations -HOME_PREFIX?=/tmp/${BEAT_NAME} -.PHONY: install-home -install-home: - if [ -a ${NOTICE_FILE} ]; then \ - install -m 644 ${NOTICE_FILE} ${HOME_PREFIX}/; \ - fi - if [ -a ${LICENSE_FILE} ]; then \ - install -m 644 ${LICENSE_FILE} ${HOME_PREFIX}/LICENSE.txt; \ - fi - if [ -d _meta/module.generated ]; then \ - install -d -m 755 ${HOME_PREFIX}/module; \ - rsync -av _meta/module.generated/ ${HOME_PREFIX}/module/; \ - chmod -R go-w ${HOME_PREFIX}/module/; \ - fi - if [ -d _meta/kibana.generated ]; then \ - install -d -m 755 ${HOME_PREFIX}/kibana; \ - rsync -av _meta/kibana.generated/ ${HOME_PREFIX}/kibana/; \ - fi - -# Prepares for packaging. Builds binaries and creates homedir data -.PHONY: prepare-package -prepare-package: - # cross compile on ubuntu - docker run --rm \ - -v $(abspath ${ES_BEATS}/dev-tools/packer/xgo-scripts):/scripts \ - -v $(abspath ${PACKER_TEMPLATES_DIR}):/templates \ - -v $(abspath ../):/source \ - -v $(PKG_BUILD_DIR):/build \ - -e PUREGO="yes" \ - -e PACK=${BEAT_NAME} \ - -e BEFORE_BUILD=before_build.sh \ - -e SOURCE=/source \ - -e TARGETS=${TARGETS} \ - -e BUILDID=${BUILDID} \ - -e ES_BEATS=${ES_BEATS} \ - -e BEAT_PATH=${BEAT_PATH} \ - -e BEAT_NAME=${BEAT_NAME} \ - -e LICENSE_FILE=${LICENSE_FILE} \ - -e BEAT_REF_YAML=${BEAT_REF_YAML} \ - ${BEATS_BUILDER_IMAGE} - -# Prepares for packaging. Builds binaries with cgo -.PHONY: prepare-package-cgo -prepare-package-cgo: - - # cross compile on ubuntu - docker run --rm \ - -v $(abspath ${ES_BEATS}/dev-tools/packer/xgo-scripts):/scripts \ - -v $(abspath ${PACKER_TEMPLATES_DIR}):/templates \ - -v $(abspath ../):/source \ - -v $(PKG_BUILD_DIR):/build \ - -e PACK=${BEAT_NAME} \ - -e BEFORE_BUILD=before_build.sh \ - -e SOURCE=/source \ - -e TARGETS=${TARGETS} \ - -e BUILDID=${BUILDID} \ - -e ES_BEATS=${ES_BEATS} \ - -e BEAT_PATH=${BEAT_PATH} \ - -e BEAT_NAME=${BEAT_NAME} \ - -e LICENSE_FILE=${LICENSE_FILE} \ - -e BEAT_REF_YAML=${BEAT_REF_YAML} \ - ${BEATS_BUILDER_IMAGE} - - # linux builds on older debian for compatibility - docker run --rm \ - -v $(abspath ${ES_BEATS}/dev-tools/packer/xgo-scripts):/scripts \ - -v $(abspath ${PACKER_TEMPLATES_DIR}):/templates \ - -v $(abspath ..):/source \ - -v ${PKG_BUILD_DIR}:/build \ - -e PACK=${BEAT_NAME} \ - -e BEFORE_BUILD=before_build.sh \ - -e SOURCE=/source \ - -e TARGETS=${TARGETS_OLD} \ - -e BUILDID=${BUILDID} \ - -e ES_BEATS=${ES_BEATS} \ - -e BEAT_PATH=${BEAT_PATH} \ - -e BEAT_NAME=${BEAT_NAME} \ - -e LICENSE_FILE=${LICENSE_FILE} \ - -e BEAT_REF_YAML=${BEAT_REF_YAML} \ - ${BEATS_BUILDER_DEB_IMAGE} - -# Prepares images for packaging -.PHONY: package-setup -package-setup: - $(MAKE) -C ${ES_BEATS}/dev-tools/packer deps images - -.PHONY: package -package: ## @packaging Create binary packages for the beat. -package: update package-setup - echo "Start building packages for ${BEAT_NAME}" - - rm -rf ${PKG_BUILD_DIR} - mkdir -p ${PKG_BUILD_DIR} - mkdir -p ${PKG_UPLOAD_DIR} - - # Generates the package.yml file with all information needed to create packages - echo "beat_name: ${BEAT_NAME}" > ${PKG_BUILD_DIR}/package.yml - echo "beat_url: ${BEAT_URL}" >> ${PKG_BUILD_DIR}/package.yml - echo "beat_repo: ${BEAT_PATH}" >> ${PKG_BUILD_DIR}/package.yml - echo "beat_pkg_name: ${BEAT_PACKAGE_NAME}" >> ${PKG_BUILD_DIR}/package.yml - echo "beat_pkg_suffix: '${PKG_SUFFIX}'" >> ${PKG_BUILD_DIR}/package.yml - echo "beat_description: ${BEAT_DESCRIPTION}" >> ${PKG_BUILD_DIR}/package.yml - echo "beat_vendor: ${BEAT_VENDOR}" >> ${PKG_BUILD_DIR}/package.yml - echo "beat_license: ${BEAT_LICENSE}" >> ${PKG_BUILD_DIR}/package.yml - echo "beat_doc_url: ${BEAT_DOC_URL}" >> ${PKG_BUILD_DIR}/package.yml - - if [ -a version.yml ]; then \ - cat version.yml >> ${PKG_BUILD_DIR}/package.yml; \ - else \ - cat ${ES_BEATS}/dev-tools/packer/version.yml >> ${PKG_BUILD_DIR}/package.yml; \ - fi - - if [ $(CGO) = true ]; then \ - $(MAKE) prepare-package-cgo; \ - else \ - $(MAKE) prepare-package; \ - fi - - SNAPSHOT=${SNAPSHOT} BUILDID=${BUILDID} BEAT_PATH=${BEAT_PATH} BUILD_DIR=${PKG_BUILD_DIR} UPLOAD_DIR=${PKG_UPLOAD_DIR} $(MAKE) BEAT_REF_YAML=${BEAT_REF_YAML} -C ${ES_BEATS}/dev-tools/packer ${PACKAGES} ${PACKAGES_EXPERIMENTAL} ${BUILD_DIR}/upload/build_id.txt - - $(MAKE) fix-permissions - echo "Finished packages for ${BEAT_NAME}" - -# Packages the Beat without Elastic X-Pack content (OSS only). -.PHONY: package-oss -package-oss: - @$(MAKE) PKG_SUFFIX=-oss package - -# Packages the Beat with Elastic X-Pack content. -.PHONY: package-elastic -package-elastic: - @$(MAKE) BEAT_LICENSE="Elastic License" LICENSE_FILE=$(ELASTIC_LICENSE_FILE) package - -.PHONY: package-all -package-all: package-elastic package-oss - -package-dashboards: package-setup - mkdir -p ${BUILD_DIR} - cp -r _meta/kibana.generated ${BUILD_DIR}/dashboards - # build the dashboards package - BEAT_NAME=${BEAT_NAME} BUILD_DIR=${BUILD_DIR} SNAPSHOT=$(SNAPSHOT) $(MAKE) -C ${ES_BEATS}/dev-tools/packer package-dashboards ${shell pwd}/build/upload/build_id.txt - fix-permissions: # Change ownership of all files inside /build folder from root/root to current user/group docker run -v ${PWD}:/beat alpine:3.4 sh -c "find /beat -user 0 -exec chown -h $(shell id -u):$(shell id -g) {} \;" @@ -598,3 +437,17 @@ seccomp: seccomp-package: SECCOMP_BINARY=build/package/${BEAT_NAME}-linux-386 $(MAKE) seccomp SECCOMP_BINARY=build/package/${BEAT_NAME}-linux-amd64 $(MAKE) seccomp + +### Packaging targets #### + +.PHONY: mage +mage: + @go install ${MAGE_IMPORT_PATH} + +.PHONY: release +release: mage + @mage package + +.PHONY: package +snapshot: mage + @SNAPSHOT=true mage package diff --git a/magefile.go b/magefile.go new file mode 100644 index 000000000000..c4f9825d8630 --- /dev/null +++ b/magefile.go @@ -0,0 +1,72 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +// +build mage + +package main + +import ( + "path/filepath" + + "github.com/elastic/beats/dev-tools/mage" +) + +var ( + // Beats is a list of Beats to collect dashboards from. + Beats = []string{ + "auditbeat", + "filebeat", + "heartbeat", + "metricbeat", + "packetbeat", + "winlogbeat", + } +) + +// PackageBeatDashboards packages the dashboards from all Beats into a zip +// file. The dashboards must be generated first. +func PackageBeatDashboards() error { + version, err := mage.BeatVersion() + if err != nil { + return err + } + + spec := mage.PackageSpec{ + Name: "beat-dashboards", + Version: version, + Snapshot: mage.Snapshot, + Files: map[string]mage.PackageFile{ + ".build_hash.txt": mage.PackageFile{ + Content: "{{ commit }}\n", + }, + }, + OutputFile: "build/distributions/dashboards/{{.Name}}-{{.Version}}{{if .Snapshot}}-SNAPSHOT{{end}}", + } + + for _, beat := range Beats { + spec.Files[beat] = mage.PackageFile{ + Source: filepath.Join(beat, "_meta/kibana.generated"), + } + } + + return mage.PackageZip(spec.Evaluate()) +} + +// DumpVariables writes the template variables and values to stdout. +func DumpVariables() error { + return mage.DumpVariables() +} diff --git a/metricbeat/Makefile b/metricbeat/Makefile index 066869afedc5..9bc8621c46f6 100644 --- a/metricbeat/Makefile +++ b/metricbeat/Makefile @@ -1,7 +1,6 @@ # Name can be overwritten, as Metricbeat is also a library BEAT_NAME?=metricbeat BEAT_TITLE?=Metricbeat -BEAT_DESCRIPTION?=Metricbeat is a lightweight shipper for metrics. SYSTEM_TESTS?=true TEST_ENVIRONMENT?=true ES_BEATS?=.. @@ -48,17 +47,6 @@ imports: python-env @mkdir -p include @${PYTHON_ENV}/bin/python ${ES_BEATS}/script/generate_imports.py ${BEAT_PATH} -# This is called by the beats packer before building starts -.PHONY: before-build -before-build: -ifeq ($(BEAT_NAME), metricbeat) - # disable the system/load metricset on windows - sed -i.bk 's/- load/#- load/' $(PREFIX)/modules.d-win/system.yml - rm $(PREFIX)/modules.d-win/system.yml.bk - sed -i.bk 's/- load/#- load/' $(PREFIX)/metricbeat-win.reference.yml - rm $(PREFIX)/metricbeat-win.reference.yml.bk -endif - # Runs all collection steps and updates afterwards .PHONY: collect collect: fields collect-docs configs kibana imports diff --git a/metricbeat/magefile.go b/metricbeat/magefile.go new file mode 100644 index 000000000000..39f3245d2375 --- /dev/null +++ b/metricbeat/magefile.go @@ -0,0 +1,155 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +// +build mage + +package main + +import ( + "fmt" + "regexp" + "time" + + "github.com/magefile/mage/mg" + "github.com/magefile/mage/sh" + "github.com/pkg/errors" + + "github.com/elastic/beats/dev-tools/mage" +) + +func init() { + mage.BeatDescription = "Metricbeat is a lightweight shipper for metrics." +} + +// Build builds the Beat binary. +func Build() error { + return mage.Build(mage.DefaultBuildArgs()) +} + +// GolangCrossBuild build the Beat binary inside of the golang-builder. +// Do not use directly, use crossBuild instead. +func GolangCrossBuild() error { + return mage.GolangCrossBuild(mage.DefaultGolangCrossBuildArgs()) +} + +// BuildGoDaemon builds the go-daemon binary (use crossBuildGoDaemon). +func BuildGoDaemon() error { + return mage.BuildGoDaemon() +} + +// CrossBuild cross-builds the beat for all target platforms. +func CrossBuild() error { + return mage.CrossBuild() +} + +// CrossBuildGoDaemon cross-builds the go-daemon binary using Docker. +func CrossBuildGoDaemon() error { + return mage.CrossBuildGoDaemon() +} + +// Clean cleans all generated files and build artifacts. +func Clean() error { + return mage.Clean() +} + +// Package packages the Beat for distribution. +// Use SNAPSHOT=true to build snapshots. +// Use PLATFORMS to control the target platforms. +func Package() { + start := time.Now() + defer func() { fmt.Println("package ran for", time.Since(start)) }() + + mage.UseElasticBeatPackaging() + customizePackaging() + + mg.Deps(Update) + mg.Deps(CrossBuild, CrossBuildGoDaemon) + mg.SerialDeps(mage.Package, TestPackages) +} + +// TestPackages tests the generated packages (i.e. file modes, owners, groups). +func TestPackages() error { + return mage.TestPackages() +} + +// Update updates the generated files (aka make update). +func Update() error { + return sh.Run("make", "update") +} + +// ----------------------------------------------------------------------------- +// Customizations specific to Metricbeat. +// - Include modules.d directory in packages. +// - Disable system/load metricset for Windows. + +// customizePackaging modifies the package specs to add the modules.d directory. +// And for Windows it comments out the system/load metricset because it's +// not supported. +func customizePackaging() { + var ( + archiveModulesDir = "modules.d" + linuxPkgModulesDir = "/usr/share/{{.BeatName}}/modules.d" + + modulesDir = mage.PackageFile{ + Mode: 0644, + Source: "modules.d", + } + windowsModulesDir = mage.PackageFile{ + Mode: 0644, + Source: "{{.PackageDir}}/modules.d", + Dep: func(spec mage.PackageSpec) error { + if err := mage.Copy("modules.d", spec.MustExpand("{{.PackageDir}}/modules.d")); err != nil { + return errors.Wrap(err, "failed to copy modules.d dir") + } + + return mage.FindReplace( + spec.MustExpand("{{.PackageDir}}/modules.d/system.yml"), + regexp.MustCompile(`- load`), `#- load`) + }, + } + windowsReferenceConfig = mage.PackageFile{ + Mode: 0644, + Source: "{{.PackageDir}}/metricbeat.reference.yml", + Dep: func(spec mage.PackageSpec) error { + err := mage.Copy("metricbeat.reference.yml", + spec.MustExpand("{{.PackageDir}}/metricbeat.reference.yml")) + if err != nil { + return errors.Wrap(err, "failed to copy reference config") + } + + return mage.FindReplace( + spec.MustExpand("{{.PackageDir}}/metricbeat.reference.yml"), + regexp.MustCompile(`- load`), `#- load`) + }, + } + ) + + for _, args := range mage.Packages { + switch args.OS { + case "windows": + args.Spec.Files[archiveModulesDir] = windowsModulesDir + args.Spec.ReplaceFile("{{.BeatName}}.reference.yml", windowsReferenceConfig) + default: + switch args.Types[0] { + case mage.TarGz, mage.Zip: + args.Spec.Files[archiveModulesDir] = modulesDir + case mage.Deb, mage.RPM: + args.Spec.Files[linuxPkgModulesDir] = modulesDir + } + } + } +} diff --git a/packetbeat/Makefile b/packetbeat/Makefile index 1e0922f64264..7c0b53258343 100644 --- a/packetbeat/Makefile +++ b/packetbeat/Makefile @@ -1,31 +1,12 @@ BEAT_NAME?=packetbeat BEAT_TITLE?=Packetbeat -BEAT_DESCRIPTION?=Packetbeat analyzes network traffic and sends the data to Elasticsearch. SYSTEM_TESTS?=true TEST_ENVIRONMENT=false ES_BEATS?=.. FIELDS_FILE_PATH=protos -TARGETS?="windows/amd64 windows/386 darwin/amd64"## @building list of platforms/architecture to be built by "make package" -PACKAGES?=${BEAT_NAME}/deb ${BEAT_NAME}/rpm ${BEAT_NAME}/darwin ${BEAT_NAME}/win ${BEAT_NAME}/bin ## @Building List of OS to be supported by "make package" -PACKAGES_EXPERIMENTAL= - include ${ES_BEATS}/libbeat/scripts/Makefile - -# This is called by the beats packer before building starts -.PHONY: before-build -before-build: - sed -i.bk 's/device: any/device: en0/' $(PREFIX)/packetbeat-darwin.yml - rm $(PREFIX)/packetbeat-darwin.yml.bk - sed -i.bk 's/device: any/device: en0/' $(PREFIX)/packetbeat-darwin.reference.yml - rm $(PREFIX)/packetbeat-darwin.reference.yml.bk - # win - sed -i.bk 's/device: any/device: 0/' $(PREFIX)/packetbeat-win.yml - rm $(PREFIX)/packetbeat-win.yml.bk - sed -i.bk 's/device: any/device: 0/' $(PREFIX)/packetbeat-win.reference.yml - rm $(PREFIX)/packetbeat-win.reference.yml.bk - # Collects all dependencies and then calls update .PHONY: collect collect: fields imports diff --git a/packetbeat/lib/windows-64/.gitignore b/packetbeat/lib/windows-64/.gitignore new file mode 100644 index 000000000000..ad7fad347cd3 --- /dev/null +++ b/packetbeat/lib/windows-64/.gitignore @@ -0,0 +1 @@ +wpcap.def diff --git a/packetbeat/lib/windows-64/sha256 b/packetbeat/lib/windows-64/sha256 new file mode 100644 index 000000000000..7e8c15523dd1 --- /dev/null +++ b/packetbeat/lib/windows-64/sha256 @@ -0,0 +1 @@ +0948518b229fb502b9c063966fc3afafbb749241a1c184f6eb7d532e00bce1d8 wpcap.dll diff --git a/packetbeat/lib/windows-64/wpcap.dll b/packetbeat/lib/windows-64/wpcap.dll new file mode 100644 index 0000000000000000000000000000000000000000..ebb17ad55c754a57be4cf1916d729d1f804ed930 GIT binary patch literal 281104 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�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 literal 0 HcmV?d00001 diff --git a/packetbeat/magefile.go b/packetbeat/magefile.go new file mode 100644 index 000000000000..f1ff4723117e --- /dev/null +++ b/packetbeat/magefile.go @@ -0,0 +1,405 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +// +build mage + +package main + +import ( + "fmt" + "log" + "regexp" + "strings" + "time" + + "github.com/magefile/mage/mg" + "github.com/magefile/mage/sh" + "github.com/pkg/errors" + + "github.com/elastic/beats/dev-tools/mage" +) + +func init() { + mage.BeatDescription = "Packetbeat analyzes network traffic and sends the data to Elasticsearch." +} + +// Build builds the Beat binary. +func Build() error { + return mage.Build(mage.DefaultBuildArgs()) +} + +// GolangCrossBuild build the Beat binary inside of the golang-builder. +// Do not use directly, use crossBuild instead. +func GolangCrossBuild() error { + if dep, found := crossBuildDeps[mage.Platform.Name]; found { + mg.Deps(dep) + } + + params := mage.DefaultGolangCrossBuildArgs() + if flags, found := libpcapLDFLAGS[mage.Platform.Name]; found { + params.Env = map[string]string{ + "CGO_LDFLAGS": flags, + } + } + if flags, found := libpcapCFLAGS[mage.Platform.Name]; found { + params.Env["CGO_CFLAGS"] = flags + } + + return mage.GolangCrossBuild(params) +} + +// BuildGoDaemon builds the go-daemon binary (use crossBuildGoDaemon). +func BuildGoDaemon() error { + return mage.BuildGoDaemon() +} + +// CrossBuild cross-builds the beat for all target platforms. +func CrossBuild() error { + mg.Deps(patchCGODirectives) + defer undoPatchCGODirectives() + + // These Windows builds write temporary .s and .o files into the packetbeat + // dir so they cannot be run in parallel. Changing to a different CWD does + // not change where the temp files get written so that cannot be used as a + // fix. + if err := mage.CrossBuild(mage.ForPlatforms("windows"), mage.Serially()); err != nil { + return err + } + + return mage.CrossBuild(mage.ForPlatforms("!windows")) +} + +// CrossBuildGoDaemon cross-builds the go-daemon binary using Docker. +func CrossBuildGoDaemon() error { + return mage.CrossBuildGoDaemon() +} + +// Clean cleans all generated files and build artifacts. +func Clean() error { + return mage.Clean() +} + +// Package packages the Beat for distribution. +// Use SNAPSHOT=true to build snapshots. +// Use PLATFORMS to control the target platforms. +func Package() { + start := time.Now() + defer func() { fmt.Println("package ran for", time.Since(start)) }() + + mage.UseElasticBeatPackaging() + customizePackaging() + + mg.Deps(Update) + mg.Deps(CrossBuild, CrossBuildGoDaemon) + mg.SerialDeps(mage.Package, TestPackages) +} + +// TestPackages tests the generated packages (i.e. file modes, owners, groups). +func TestPackages() error { + return mage.TestPackages() +} + +// Update updates the generated files (aka make update). +func Update() error { + return sh.Run("make", "update") +} + +// ----------------------------------------------------------------------------- +// Customizations specific to Packetbeat. +// - Config file contains an OS specific device name (affects darwin, windows). +// - Must compile libpcap or winpcap during cross-compilation. +// - On Linux libpcap is statically linked. Darwin and Windows are dynamic. + +const ( + libpcapURL = "https://s3.amazonaws.com/beats-files/deps/libpcap-1.8.1.tar.gz" + libpcapSHA256 = "673dbc69fdc3f5a86fb5759ab19899039a8e5e6c631749e48dcd9c6f0c83541e" +) + +const ( + linuxPcapLDFLAGS = "-L/libpcap/libpcap-1.8.1 -lpcap" + linuxPcapCFLAGS = "-I /libpcap/libpcap-1.8.1" +) + +var libpcapLDFLAGS = map[string]string{ + "linux/386": linuxPcapLDFLAGS, + "linux/amd64": linuxPcapLDFLAGS, + "linux/arm64": linuxPcapLDFLAGS, + "linux/armv5": linuxPcapLDFLAGS, + "linux/armv6": linuxPcapLDFLAGS, + "linux/armv7": linuxPcapLDFLAGS, + "linux/mips": linuxPcapLDFLAGS, + "linux/mipsle": linuxPcapLDFLAGS, + "linux/mips64": linuxPcapLDFLAGS, + "linux/mips64le": linuxPcapLDFLAGS, + "linux/ppc64le": linuxPcapLDFLAGS, + "linux/s390x": linuxPcapLDFLAGS, + "darwin/amd64": "-lpcap", + "windows/amd64": "-L /libpcap/win/WpdPack/Lib/x64 -lwpcap", + "windows/386": "-L /libpcap/win/WpdPack/Lib -lwpcap", +} + +var libpcapCFLAGS = map[string]string{ + "linux/386": linuxPcapCFLAGS, + "linux/amd64": linuxPcapCFLAGS, + "linux/armv5": linuxPcapCFLAGS, + "linux/armv6": linuxPcapCFLAGS, + "linux/armv7": linuxPcapCFLAGS, + "linux/mips": linuxPcapCFLAGS, + "linux/mipsle": linuxPcapCFLAGS, + "linux/mips64": linuxPcapCFLAGS, + "linux/mips64le": linuxPcapCFLAGS, + "linux/ppc64le": linuxPcapCFLAGS, + "linux/s390x": linuxPcapCFLAGS, + "windows/amd64": "-I /libpcap/win/WpdPack/Include", + "windows/386": "-I /libpcap/win/WpdPack/Include", +} + +var crossBuildDeps = map[string]func() error{ + "linux/amd64": buildLibpcapLinuxAMD64, + "linux/386": buildLibpcapLinux386, + "linux/arm64": buildLibpcapLinuxARM64, + "linux/armv5": buildLibpcapLinuxARMv5, + "linux/armv6": buildLibpcapLinuxARMv6, + "linux/armv7": buildLibpcapLinuxARMv7, + "linux/mips": buildLibpcapLinuxMIPS, + "linux/mipsle": buildLibpcapLinuxMIPSLE, + "linux/mips64": buildLibpcapLinuxMIPS64, + "linux/mips64le": buildLibpcapLinuxMIPS64LE, + "linux/ppc64le": buildLibpcapLinuxPPC64LE, + "linux/s390x": buildLibpcapLinuxS390x, + "windows/amd64": installLibpcapWindowsAMD64, + "windows/386": installLibpcapWindows386, +} + +// buildLibpcapFromSource builds libpcap from source because the library needs +// to be compiled with -fPIC. +// See https://github.com/elastic/beats/pull/4217. +func buildLibpcapFromSource(params map[string]string) error { + tarFile, err := mage.DownloadFile(libpcapURL, "/libpcap") + if err != nil { + return errors.Wrap(err, "failed to download libpcap source") + } + + if err = mage.VerifySHA256(tarFile, libpcapSHA256); err != nil { + return err + } + + if err = mage.Extract(tarFile, "/libpcap"); err != nil { + return errors.Wrap(err, "failed to extract libpcap") + } + + var configureArgs []string + for k, v := range params { + if strings.HasPrefix(k, "-") { + delete(params, k) + configureArgs = append(configureArgs, k+"="+v) + } + } + + // Use sh -c here because sh.Run does not expose a way to change the CWD. + // This command only runs in Linux so this is fine. + return sh.RunWith(params, "sh", "-c", + "cd /libpcap/libpcap-1.8.1 && "+ + "./configure --enable-usb=no --enable-bluetooth=no --enable-dbus=no "+strings.Join(configureArgs, " ")+"&& "+ + "make") +} + +func buildLibpcapLinux386() error { + return buildLibpcapFromSource(map[string]string{ + "CFLAGS": "-m32", + "LDFLAGS": "-m32", + }) +} + +func buildLibpcapLinuxAMD64() error { + return buildLibpcapFromSource(map[string]string{}) +} + +func buildLibpcapLinuxARM64() error { + return buildLibpcapFromSource(map[string]string{ + "--host": "aarch64-unknown-linux-gnu", + "--with-pcap": "linux", + }) +} + +func buildLibpcapLinuxARMv5() error { + return buildLibpcapFromSource(map[string]string{ + "--host": "arm-linux-gnueabi", + "--with-pcap": "linux", + }) +} + +func buildLibpcapLinuxARMv6() error { + return buildLibpcapFromSource(map[string]string{ + "--host": "arm-linux-gnueabi", + "--with-pcap": "linux", + }) +} + +func buildLibpcapLinuxARMv7() error { + return buildLibpcapFromSource(map[string]string{ + "--host": "arm-linux-gnueabihf", + "--with-pcap": "linux", + }) +} + +func buildLibpcapLinuxMIPS() error { + return buildLibpcapFromSource(map[string]string{ + "--host": "mips-unknown-linux-gnu", + "--with-pcap": "linux", + }) +} + +func buildLibpcapLinuxMIPSLE() error { + return buildLibpcapFromSource(map[string]string{ + "--host": "mipsle-unknown-linux-gnu", + "--with-pcap": "linux", + }) +} + +func buildLibpcapLinuxMIPS64() error { + return buildLibpcapFromSource(map[string]string{ + "--host": "mips64-unknown-linux-gnu", + "--with-pcap": "linux", + }) +} + +func buildLibpcapLinuxMIPS64LE() error { + return buildLibpcapFromSource(map[string]string{ + "--host": "mips64le-unknown-linux-gnu", + "--with-pcap": "linux", + }) +} + +func buildLibpcapLinuxPPC64LE() error { + return buildLibpcapFromSource(map[string]string{ + "--host": "powerpc64le-linux-gnu", + "--with-pcap": "linux", + }) +} + +func buildLibpcapLinuxS390x() error { + return buildLibpcapFromSource(map[string]string{ + "--host": "s390x-ibm-linux-gnu", + "--with-pcap": "linux", + }) +} + +func installLibpcapWindowsAMD64() error { + mg.SerialDeps(installWinpcap, generateWin64StaticWinpcap) + return nil +} + +func installLibpcapWindows386() error { + return installWinpcap() +} + +func installWinpcap() error { + log.Println("Install Winpcap") + const wpdpackURL = "https://www.winpcap.org/install/bin/WpdPack_4_1_2.zip" + + winpcapZip, err := mage.DownloadFile(wpdpackURL, "/") + if err != nil { + return err + } + + if err = mage.Extract(winpcapZip, "/libpcap/win"); err != nil { + return err + } + + return nil +} + +func generateWin64StaticWinpcap() error { + log.Println(">> Generating 64-bit winpcap static lib") + + // Ref: https://github.com/elastic/beats/issues/1259 + defer mage.DockerChown("lib/windows-64/wpcap.def") + return mage.RunCmds( + // Requires mingw-w64-tools. + []string{"gendef", "lib/windows-64/wpcap.dll"}, + []string{"mv", "wpcap.def", "lib/windows-64/wpcap.def"}, + []string{"x86_64-w64-mingw32-dlltool", "--as-flags=--64", + "-m", "i386:x86-64", "-k", + "--output-lib", "/libpcap/win/WpdPack/Lib/x64/libwpcap.a", + "--input-def", "lib/windows-64/wpcap.def"}, + ) +} + +const pcapGoFile = "../vendor/github.com/tsg/gopacket/pcap/pcap.go" + +var cgoDirectiveRegex = regexp.MustCompile(`(?m)#cgo .*(?:LDFLAGS|CFLAGS).*$`) + +func patchCGODirectives() error { + // cgo directives do not support GOARM tags so we will clear the tags + // and set them via CGO_LDFLAGS and CGO_CFLAGS. + // Ref: https://github.com/golang/go/issues/7211 + log.Println("Patching", pcapGoFile, cgoDirectiveRegex.String()) + return mage.FindReplace(pcapGoFile, cgoDirectiveRegex, "") +} + +func undoPatchCGODirectives() error { + return sh.Run("git", "checkout", pcapGoFile) +} + +// customizePackaging modifies the device in the configuration files based on +// the target OS. +func customizePackaging() { + var ( + defaultDevice = map[string]string{ + "darwin": "en0", + "windows": "0", + } + + configYml = mage.PackageFile{ + Mode: 0600, + Source: "{{.PackageDir}}/{{.BeatName}}.yml", + Dep: func(spec mage.PackageSpec) error { + if err := mage.Copy("packetbeat.yml", + spec.MustExpand("{{.PackageDir}}/packetbeat.yml")); err != nil { + return errors.Wrap(err, "failed to copy config") + } + + return mage.FindReplace( + spec.MustExpand("{{.PackageDir}}/packetbeat.yml"), + regexp.MustCompile(`device: any`), "device: "+defaultDevice[spec.OS]) + }, + } + referenceConfigYml = mage.PackageFile{ + Mode: 0644, + Source: "{{.PackageDir}}/{{.BeatName}}.reference.yml", + Dep: func(spec mage.PackageSpec) error { + if err := mage.Copy("packetbeat.yml", + spec.MustExpand("{{.PackageDir}}/packetbeat.reference.yml")); err != nil { + return errors.Wrap(err, "failed to copy config") + } + + return mage.FindReplace( + spec.MustExpand("{{.PackageDir}}/packetbeat.reference.yml"), + regexp.MustCompile(`device: any`), "device: "+defaultDevice[spec.OS]) + }, + } + ) + + for _, args := range mage.Packages { + switch args.OS { + case "windows", "darwin": + args.Spec.ReplaceFile("{{.BeatName}}.yml", configYml) + args.Spec.ReplaceFile("{{.BeatName}}.reference.yml", referenceConfigYml) + } + } +} diff --git a/winlogbeat/Makefile b/winlogbeat/Makefile index 3b533836cd74..4d53434f531e 100644 --- a/winlogbeat/Makefile +++ b/winlogbeat/Makefile @@ -1,15 +1,8 @@ BEAT_NAME=winlogbeat BEAT_TITLE=Winlogbeat -BEAT_DESCRIPTION=Winlogbeat ships Windows event logs to Elasticsearch or Logstash. SYSTEM_TESTS=true TEST_ENVIRONMENT=false - GOX_OS=windows -TARGETS?="windows/amd64 windows/386" -PACKAGES=winlogbeat/win -PACKAGES_EXPERIMENTAL= - -CGO=false # don't need Cgo in Winlogbeat include ../libbeat/scripts/Makefile @@ -17,10 +10,6 @@ include ../libbeat/scripts/Makefile gen: GOOS=windows GOARCH=386 go generate -v -x ./... -# This is called by the beats packer before building starts -.PHONY: before-build -before-build: - # Collects all dependencies and then calls update .PHONY: collect collect: fields diff --git a/winlogbeat/magefile.go b/winlogbeat/magefile.go new file mode 100644 index 000000000000..5500f9fdca8e --- /dev/null +++ b/winlogbeat/magefile.go @@ -0,0 +1,90 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +// +build mage + +package main + +import ( + "fmt" + "time" + + "github.com/magefile/mage/mg" + "github.com/magefile/mage/sh" + + "github.com/elastic/beats/dev-tools/mage" +) + +func init() { + mage.BeatDescription = "Winlogbeat ships Windows event logs to Elasticsearch or Logstash." + + mage.Platforms = mage.Platforms.Filter("windows") +} + +// Build builds the Beat binary. +func Build() error { + return mage.Build(mage.DefaultBuildArgs()) +} + +// GolangCrossBuild build the Beat binary inside of the golang-builder. +// Do not use directly, use crossBuild instead. +func GolangCrossBuild() error { + return mage.GolangCrossBuild(mage.DefaultGolangCrossBuildArgs()) +} + +// BuildGoDaemon builds the go-daemon binary (use crossBuildGoDaemon). +func BuildGoDaemon() error { + return mage.BuildGoDaemon() +} + +// CrossBuild cross-builds the beat for all target platforms. +func CrossBuild() error { + return mage.CrossBuild() +} + +// CrossBuildGoDaemon cross-builds the go-daemon binary using Docker. +func CrossBuildGoDaemon() error { + return mage.CrossBuildGoDaemon() +} + +// Clean cleans all generated files and build artifacts. +func Clean() error { + return mage.Clean() +} + +// Package packages the Beat for distribution. +// Use SNAPSHOT=true to build snapshots. +// Use PLATFORMS to control the target platforms. +func Package() { + start := time.Now() + defer func() { fmt.Println("package ran for", time.Since(start)) }() + + mage.UseElasticBeatPackaging() + mg.Deps(Update) + mg.Deps(CrossBuild, CrossBuildGoDaemon) + mg.SerialDeps(mage.Package, TestPackages) +} + +// TestPackages tests the generated packages (i.e. file modes, owners, groups). +func TestPackages() error { + return mage.TestPackages() +} + +// Update updates the generated files (aka make update). +func Update() error { + return sh.Run("make", "update") +}