main: Use configuration file instead of flags and simplify app extension.
Clair will now use a YAML configuration file instead of command line arguments as the number of parameters grows. Also, Clair now exposes a Boot() func that allows everyone to easily create their own project and load dynamically their own fetchers/updaters.
This commit is contained in:
parent
a4dcd3c13a
commit
eb7e5d5c74
@ -5,6 +5,7 @@ RUN apt-get update && apt-get install -y bzr rpm && apt-get autoremove -y && apt
|
|||||||
|
|
||||||
RUN mkdir /db
|
RUN mkdir /db
|
||||||
VOLUME /db
|
VOLUME /db
|
||||||
|
VOLUME /config
|
||||||
|
|
||||||
EXPOSE 6060 6061
|
EXPOSE 6060 6061
|
||||||
|
|
||||||
@ -12,7 +13,7 @@ ADD . /go/src/github.com/coreos/clair/
|
|||||||
WORKDIR /go/src/github.com/coreos/clair/
|
WORKDIR /go/src/github.com/coreos/clair/
|
||||||
|
|
||||||
ENV GO15VENDOREXPERIMENT 1
|
ENV GO15VENDOREXPERIMENT 1
|
||||||
RUN go install -v
|
RUN go install -v github.com/coreos/clair/cmd/clair
|
||||||
RUN go test $(go list ./... | grep -v /vendor/) # https://github.com/golang/go/issues/11659
|
RUN go test $(go list ./... | grep -v /vendor/) # https://github.com/golang/go/issues/11659
|
||||||
|
|
||||||
ENTRYPOINT ["clair"]
|
ENTRYPOINT ["clair"]
|
||||||
|
9
Godeps/Godeps.json
generated
9
Godeps/Godeps.json
generated
@ -79,15 +79,14 @@
|
|||||||
"ImportPath": "golang.org/x/net/netutil",
|
"ImportPath": "golang.org/x/net/netutil",
|
||||||
"Rev": "7654728e381988afd88e58cabfd6363a5ea91810"
|
"Rev": "7654728e381988afd88e58cabfd6363a5ea91810"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"ImportPath": "gopkg.in/alecthomas/kingpin.v2",
|
|
||||||
"Comment": "v2.0.10",
|
|
||||||
"Rev": "e1f37920c1d0ced4d1c92f9526a2a433183f02e9"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"ImportPath": "gopkg.in/mgo.v2",
|
"ImportPath": "gopkg.in/mgo.v2",
|
||||||
"Comment": "r2015.05.29",
|
"Comment": "r2015.05.29",
|
||||||
"Rev": "01ee097136da162d1dd3c9b44fbdf3abf4fd6552"
|
"Rev": "01ee097136da162d1dd3c9b44fbdf3abf4fd6552"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "gopkg.in/yaml.v2",
|
||||||
|
"Rev": "f7716cbe52baa25d2e9b0d0da546fcf909fc16b4"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
56
api/api.go
56
api/api.go
@ -25,66 +25,68 @@ import (
|
|||||||
"github.com/coreos/pkg/capnslog"
|
"github.com/coreos/pkg/capnslog"
|
||||||
"github.com/tylerb/graceful"
|
"github.com/tylerb/graceful"
|
||||||
|
|
||||||
|
"github.com/coreos/clair/config"
|
||||||
"github.com/coreos/clair/utils"
|
"github.com/coreos/clair/utils"
|
||||||
httputils "github.com/coreos/clair/utils/http"
|
httputils "github.com/coreos/clair/utils/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
var log = capnslog.NewPackageLogger("github.com/coreos/clair", "api")
|
var log = capnslog.NewPackageLogger("github.com/coreos/clair", "api")
|
||||||
|
|
||||||
// Config represents the configuration for the Main API.
|
// Run launches the main API, which exposes every possible interactions
|
||||||
type Config struct {
|
|
||||||
Port int
|
|
||||||
TimeOut time.Duration
|
|
||||||
CertFile, KeyFile, CAFile string
|
|
||||||
}
|
|
||||||
|
|
||||||
// RunMain launches the main API, which exposes every possible interactions
|
|
||||||
// with clair.
|
// with clair.
|
||||||
func RunMain(conf *Config, st *utils.Stopper) {
|
func Run(config *config.APIConfig, st *utils.Stopper) {
|
||||||
log.Infof("starting API on port %d.", conf.Port)
|
defer st.End()
|
||||||
defer func() {
|
|
||||||
log.Info("API stopped")
|
|
||||||
st.End()
|
|
||||||
}()
|
|
||||||
|
|
||||||
tlsConfig, err := httputils.LoadTLSClientConfigForServer(conf.CAFile)
|
// Do not run the API service if there is no config.
|
||||||
|
if config == nil {
|
||||||
|
log.Infof("main API service is disabled.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Infof("starting main API on port %d.", config.Port)
|
||||||
|
|
||||||
|
tlsConfig, err := httputils.LoadTLSClientConfigForServer(config.CAFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("could not initialize client cert authentification: %s\n", err)
|
log.Fatalf("could not initialize client cert authentification: %s\n", err)
|
||||||
}
|
}
|
||||||
if tlsConfig != nil {
|
if tlsConfig != nil {
|
||||||
log.Info("api configured with client certificate authentification")
|
log.Info("main API configured with client certificate authentification")
|
||||||
}
|
}
|
||||||
|
|
||||||
srv := &graceful.Server{
|
srv := &graceful.Server{
|
||||||
Timeout: 0, // Already handled by our TimeOut middleware
|
Timeout: 0, // Already handled by our TimeOut middleware
|
||||||
NoSignalHandling: true, // We want to use our own Stopper
|
NoSignalHandling: true, // We want to use our own Stopper
|
||||||
Server: &http.Server{
|
Server: &http.Server{
|
||||||
Addr: ":" + strconv.Itoa(conf.Port),
|
Addr: ":" + strconv.Itoa(config.Port),
|
||||||
TLSConfig: tlsConfig,
|
TLSConfig: tlsConfig,
|
||||||
Handler: NewVersionRouter(conf.TimeOut),
|
Handler: NewVersionRouter(config.Timeout),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
listenAndServeWithStopper(srv, st, conf.CertFile, conf.KeyFile)
|
listenAndServeWithStopper(srv, st, config.CertFile, config.KeyFile)
|
||||||
|
log.Info("main API stopped")
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunHealth launches the Health API, which only exposes a method to fetch
|
// RunHealth launches the Health API, which only exposes a method to fetch
|
||||||
// clair's health without any security or authentification mechanism.
|
// Clair's health without any security or authentification mechanism.
|
||||||
func RunHealth(port int, st *utils.Stopper) {
|
func RunHealth(config *config.APIConfig, st *utils.Stopper) {
|
||||||
log.Infof("starting Health API on port %d.", port)
|
defer st.End()
|
||||||
defer func() {
|
|
||||||
log.Info("Health API stopped")
|
// Do not run the API service if there is no config.
|
||||||
st.End()
|
if config == nil {
|
||||||
}()
|
log.Infof("health API service is disabled.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Infof("starting health API on port %d.", config.HealthPort)
|
||||||
|
|
||||||
srv := &graceful.Server{
|
srv := &graceful.Server{
|
||||||
Timeout: 10 * time.Second, // Interrupt health checks when stopping
|
Timeout: 10 * time.Second, // Interrupt health checks when stopping
|
||||||
NoSignalHandling: true, // We want to use our own Stopper
|
NoSignalHandling: true, // We want to use our own Stopper
|
||||||
Server: &http.Server{
|
Server: &http.Server{
|
||||||
Addr: ":" + strconv.Itoa(port),
|
Addr: ":" + strconv.Itoa(config.HealthPort),
|
||||||
Handler: NewHealthRouter(),
|
Handler: NewHealthRouter(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
listenAndServeWithStopper(srv, st, "", "")
|
listenAndServeWithStopper(srv, st, "", "")
|
||||||
|
log.Info("health API stopped")
|
||||||
}
|
}
|
||||||
|
|
||||||
// listenAndServeWithStopper wraps graceful.Server's
|
// listenAndServeWithStopper wraps graceful.Server's
|
||||||
|
@ -52,7 +52,7 @@ func POSTLayers(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
|||||||
httputils.WriteHTTP(w, http.StatusCreated, struct{ Version string }{Version: strconv.Itoa(worker.Version)})
|
httputils.WriteHTTP(w, http.StatusCreated, struct{ Version string }{Version: strconv.Itoa(worker.Version)})
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteLayer deletes the specified layer and any child layers that are
|
// DELETELayers deletes the specified layer and any child layers that are
|
||||||
// dependent on the specified layer.
|
// dependent on the specified layer.
|
||||||
func DELETELayers(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
func DELETELayers(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
||||||
err := database.DeleteLayer(p.ByName("id"))
|
err := database.DeleteLayer(p.ByName("id"))
|
||||||
|
@ -12,9 +12,6 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
// Package logic implements all the available API methods.
|
|
||||||
// Every methods are documented in docs/API.md.
|
|
||||||
|
|
||||||
// Package wrappers contains httprouter.Handle wrappers that are used in the API.
|
// Package wrappers contains httprouter.Handle wrappers that are used in the API.
|
||||||
package wrappers
|
package wrappers
|
||||||
|
|
||||||
|
@ -12,9 +12,6 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
// Package logic implements all the available API methods.
|
|
||||||
// Every methods are documented in docs/API.md.
|
|
||||||
|
|
||||||
package wrappers
|
package wrappers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
74
clair.go
Normal file
74
clair.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// Copyright 2015 clair authors
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// Package clair implements the ability to boot Clair with your own imports
|
||||||
|
// that can dynamically register additional functionality.
|
||||||
|
package clair
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/coreos/clair/api"
|
||||||
|
"github.com/coreos/clair/config"
|
||||||
|
"github.com/coreos/clair/database"
|
||||||
|
"github.com/coreos/clair/notifier"
|
||||||
|
"github.com/coreos/clair/updater"
|
||||||
|
"github.com/coreos/clair/utils"
|
||||||
|
"github.com/coreos/pkg/capnslog"
|
||||||
|
)
|
||||||
|
|
||||||
|
var log = capnslog.NewPackageLogger("github.com/coreos/clair", "main")
|
||||||
|
|
||||||
|
// Boot starts Clair. By exporting this function, anyone can import their own
|
||||||
|
// custom fetchers/updaters into their own package and then call clair.Boot.
|
||||||
|
func Boot(config *config.Config) {
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
st := utils.NewStopper()
|
||||||
|
|
||||||
|
// Open database
|
||||||
|
err := database.Open(config.Database)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer database.Close()
|
||||||
|
|
||||||
|
// Start notifier
|
||||||
|
st.Begin()
|
||||||
|
notifier := notifier.New(config.Notifier)
|
||||||
|
go notifier.Serve(st)
|
||||||
|
|
||||||
|
// Start API
|
||||||
|
st.Begin()
|
||||||
|
go api.Run(config.API, st)
|
||||||
|
st.Begin()
|
||||||
|
go api.RunHealth(config.API, st)
|
||||||
|
|
||||||
|
// Start updater
|
||||||
|
st.Begin()
|
||||||
|
go updater.Run(config.Updater, st)
|
||||||
|
|
||||||
|
// Wait for interruption and shutdown gracefully.
|
||||||
|
waitForSignals(os.Interrupt)
|
||||||
|
log.Info("Received interruption, gracefully stopping ...")
|
||||||
|
st.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitForSignals(signals ...os.Signal) {
|
||||||
|
interrupts := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(interrupts, signals...)
|
||||||
|
<-interrupts
|
||||||
|
}
|
77
cmd/clair/main.go
Normal file
77
cmd/clair/main.go
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// Copyright 2015 clair authors
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"os"
|
||||||
|
"runtime/pprof"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/coreos/clair"
|
||||||
|
"github.com/coreos/clair/config"
|
||||||
|
|
||||||
|
"github.com/coreos/pkg/capnslog"
|
||||||
|
|
||||||
|
// Register components
|
||||||
|
_ "github.com/coreos/clair/updater/fetchers"
|
||||||
|
_ "github.com/coreos/clair/worker/detectors/os"
|
||||||
|
_ "github.com/coreos/clair/worker/detectors/packages"
|
||||||
|
)
|
||||||
|
|
||||||
|
var log = capnslog.NewPackageLogger("github.com/coreos/clair/cmd/clair", "main")
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Parse command-line arguments
|
||||||
|
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
|
||||||
|
flagConfigPath := flag.String("config", "", "Load configuration from the specified file.")
|
||||||
|
flagCPUProfilePath := flag.String("cpu-profile", "", "Write a CPU profile to the specified file before exiting.")
|
||||||
|
flagLogLevel := flag.String("log-level", "info", "Define the logging level.")
|
||||||
|
flag.Parse()
|
||||||
|
// Load configuration
|
||||||
|
config, err := config.Load(*flagConfigPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to load configuration: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize logging system
|
||||||
|
logLevel, err := capnslog.ParseLevel(strings.ToUpper(*flagLogLevel))
|
||||||
|
capnslog.SetGlobalLogLevel(logLevel)
|
||||||
|
capnslog.SetFormatter(capnslog.NewPrettyFormatter(os.Stdout, false))
|
||||||
|
|
||||||
|
// Enable CPU Profiling if specified
|
||||||
|
if *flagCPUProfilePath != "" {
|
||||||
|
startCPUProfiling(*flagCPUProfilePath)
|
||||||
|
defer stopCPUProfiling()
|
||||||
|
}
|
||||||
|
|
||||||
|
clair.Boot(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func startCPUProfiling(path string) {
|
||||||
|
f, err := os.Create(path)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to create profile file: %s", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
pprof.StartCPUProfile(f)
|
||||||
|
log.Info("started CPU profiling")
|
||||||
|
}
|
||||||
|
|
||||||
|
func stopCPUProfiling() {
|
||||||
|
pprof.StopCPUProfile()
|
||||||
|
log.Info("stopped CPU profiling")
|
||||||
|
}
|
37
config.example.yaml
Normal file
37
config.example.yaml
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# The values specified here are the default values that Clair uses if no configuration file
|
||||||
|
# is specified or if the keys are not defined.
|
||||||
|
---
|
||||||
|
database:
|
||||||
|
# Database backend.
|
||||||
|
#
|
||||||
|
# Possible values are "bolt", "leveldb", "memstore", "mongo", "sql".
|
||||||
|
#
|
||||||
|
# When running multiple instances is not desired, using BoltDB backend is the best choice as it is
|
||||||
|
# lightning fast. However, using PostgreSQL enables running multiple instances concurrently.
|
||||||
|
# The default is just an ephemeral database.
|
||||||
|
type: memstore
|
||||||
|
# Path to the database.
|
||||||
|
#
|
||||||
|
# Can be a file or a connection string.
|
||||||
|
path:
|
||||||
|
api:
|
||||||
|
# Port on which the main API and the health API will listen on.
|
||||||
|
port: 6060
|
||||||
|
healthport: 6061
|
||||||
|
# Maximum time that API requests may take before they time-out with a HTTP 503 error.
|
||||||
|
timeout: 900s
|
||||||
|
# Paths to certificates to secure the main API with TLS and client certificate auth.
|
||||||
|
cafile:
|
||||||
|
keyfile:
|
||||||
|
certfile:
|
||||||
|
updater:
|
||||||
|
# Frequency at which the vulnerability updater will run.
|
||||||
|
# Use 0 to disable the updater entirely.
|
||||||
|
interval: 2h
|
||||||
|
notifier:
|
||||||
|
# HTTP endpoint that will receive notifications with POST requests.
|
||||||
|
endpoint:
|
||||||
|
# Path to certificates to call the endpoint securely with TLS and client certificate auth.
|
||||||
|
cafile:
|
||||||
|
keyfile:
|
||||||
|
certfile:
|
95
config/config.go
Normal file
95
config/config.go
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
// Copyright 2015 clair authors
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config is the global configuration for an instance of Clair.
|
||||||
|
type Config struct {
|
||||||
|
Database *DatabaseConfig
|
||||||
|
Updater *UpdaterConfig
|
||||||
|
Notifier *NotifierConfig
|
||||||
|
API *APIConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// DatabaseConfig is the configuration used to specify how Clair connects
|
||||||
|
// to a database.
|
||||||
|
type DatabaseConfig struct {
|
||||||
|
Type string
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdaterConfig is the configuration for the Updater service.
|
||||||
|
type UpdaterConfig struct {
|
||||||
|
Interval time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotifierConfig is the configuration for the Notifier service.
|
||||||
|
type NotifierConfig struct {
|
||||||
|
Endpoint string
|
||||||
|
CertFile, KeyFile, CAFile string
|
||||||
|
}
|
||||||
|
|
||||||
|
// APIConfig is the configuration for the API service.
|
||||||
|
type APIConfig struct {
|
||||||
|
Port int
|
||||||
|
HealthPort int
|
||||||
|
Timeout time.Duration
|
||||||
|
CertFile, KeyFile, CAFile string
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultConfig is a configuration that can be used as a fallback value.
|
||||||
|
var DefaultConfig = Config{
|
||||||
|
Database: &DatabaseConfig{
|
||||||
|
Type: "memstore",
|
||||||
|
},
|
||||||
|
Updater: &UpdaterConfig{
|
||||||
|
Interval: 1 * time.Hour,
|
||||||
|
},
|
||||||
|
API: &APIConfig{
|
||||||
|
Port: 6060,
|
||||||
|
HealthPort: 6061,
|
||||||
|
Timeout: 900 * time.Second,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load is a shortcut to open a file, read it, and generate a Config.
|
||||||
|
// It supports relative and absolute paths. Given "", it returns DefaultConfig.
|
||||||
|
func Load(path string) (config *Config, err error) {
|
||||||
|
config = &DefaultConfig
|
||||||
|
if path == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Open(os.ExpandEnv(path))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
d, err := ioutil.ReadAll(f)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = yaml.Unmarshal(d, config)
|
||||||
|
return
|
||||||
|
}
|
@ -21,6 +21,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/barakmich/glog"
|
"github.com/barakmich/glog"
|
||||||
|
"github.com/coreos/clair/config"
|
||||||
"github.com/coreos/clair/health"
|
"github.com/coreos/clair/health"
|
||||||
"github.com/coreos/clair/utils"
|
"github.com/coreos/clair/utils"
|
||||||
"github.com/coreos/pkg/capnslog"
|
"github.com/coreos/pkg/capnslog"
|
||||||
@ -63,23 +64,27 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Open opens a Cayley database, creating it if necessary and return its handle
|
// Open opens a Cayley database, creating it if necessary and return its handle
|
||||||
func Open(dbType, dbPath string) error {
|
func Open(config *config.DatabaseConfig) error {
|
||||||
if store != nil {
|
if store != nil {
|
||||||
log.Errorf("could not open database at %s : a database is already opened", dbPath)
|
log.Errorf("could not open database at %s : a database is already opened", config.Path)
|
||||||
|
return ErrCantOpen
|
||||||
|
}
|
||||||
|
if config.Type != "memstore" && config.Path == "" {
|
||||||
|
log.Errorf("could not open database : no path provided.")
|
||||||
return ErrCantOpen
|
return ErrCantOpen
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
options := make(graph.Options)
|
options := make(graph.Options)
|
||||||
|
|
||||||
switch dbType {
|
switch config.Type {
|
||||||
case "bolt", "leveldb":
|
case "bolt", "leveldb":
|
||||||
if _, err := os.Stat(dbPath); os.IsNotExist(err) {
|
if _, err := os.Stat(config.Path); os.IsNotExist(err) {
|
||||||
log.Infof("database at %s does not exist yet, creating it", dbPath)
|
log.Infof("database at %s does not exist yet, creating it", config.Path)
|
||||||
|
|
||||||
err = graph.InitQuadStore(dbType, dbPath, options)
|
err = graph.InitQuadStore(config.Type, config.Path, options)
|
||||||
if err != nil && err != graph.ErrDatabaseExists {
|
if err != nil && err != graph.ErrDatabaseExists {
|
||||||
log.Errorf("could not create database at %s : %s", dbPath, err)
|
log.Errorf("could not create database at %s : %s", config.Path, err)
|
||||||
return ErrCantOpen
|
return ErrCantOpen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,16 +93,16 @@ func Open(dbType, dbPath string) error {
|
|||||||
// Ref: https://wiki.postgresql.org/wiki/Count_estimate
|
// Ref: https://wiki.postgresql.org/wiki/Count_estimate
|
||||||
options["use_estimates"] = true
|
options["use_estimates"] = true
|
||||||
|
|
||||||
err := graph.InitQuadStore(dbType, dbPath, options)
|
err := graph.InitQuadStore(config.Type, config.Path, options)
|
||||||
if err != nil && err != graph.ErrDatabaseExists {
|
if err != nil && err != graph.ErrDatabaseExists {
|
||||||
log.Errorf("could not create database at %s : %s", dbPath, err)
|
log.Errorf("could not create database at %s : %s", config.Path, err)
|
||||||
return ErrCantOpen
|
return ErrCantOpen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
store, err = cayley.NewGraph(dbType, dbPath, options)
|
store, err = cayley.NewGraph(config.Type, config.Path, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("could not open database at %s : %s", dbPath, err)
|
log.Errorf("could not open database at %s : %s", config.Path, err)
|
||||||
return ErrCantOpen
|
return ErrCantOpen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,12 +17,13 @@ package database
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/coreos/clair/config"
|
||||||
"github.com/google/cayley"
|
"github.com/google/cayley"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHealthcheck(t *testing.T) {
|
func TestHealthcheck(t *testing.T) {
|
||||||
Open("memstore", "")
|
Open(&config.DatabaseConfig{Type: "memstore"})
|
||||||
defer Close()
|
defer Close()
|
||||||
|
|
||||||
b := Healthcheck()
|
b := Healthcheck()
|
||||||
@ -30,7 +31,7 @@ func TestHealthcheck(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestToValue(t *testing.T) {
|
func TestToValue(t *testing.T) {
|
||||||
Open("memstore", "")
|
Open(&config.DatabaseConfig{Type: "memstore"})
|
||||||
defer Close()
|
defer Close()
|
||||||
|
|
||||||
// toValue()
|
// toValue()
|
||||||
|
@ -17,11 +17,12 @@ package database
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/coreos/clair/config"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFlag(t *testing.T) {
|
func TestFlag(t *testing.T) {
|
||||||
Open("memstore", "")
|
Open(&config.DatabaseConfig{Type: "memstore"})
|
||||||
defer Close()
|
defer Close()
|
||||||
|
|
||||||
// Get non existing flag
|
// Get non existing flag
|
||||||
|
@ -17,6 +17,7 @@ package database
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/coreos/clair/config"
|
||||||
"github.com/coreos/clair/utils"
|
"github.com/coreos/clair/utils"
|
||||||
cerrors "github.com/coreos/clair/utils/errors"
|
cerrors "github.com/coreos/clair/utils/errors"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -24,7 +25,7 @@ import (
|
|||||||
|
|
||||||
// TestInvalidLayers tries to insert invalid layers
|
// TestInvalidLayers tries to insert invalid layers
|
||||||
func TestInvalidLayers(t *testing.T) {
|
func TestInvalidLayers(t *testing.T) {
|
||||||
Open("memstore", "")
|
Open(&config.DatabaseConfig{Type: "memstore"})
|
||||||
defer Close()
|
defer Close()
|
||||||
|
|
||||||
assert.Error(t, InsertLayer(&Layer{ID: ""})) // No ID
|
assert.Error(t, InsertLayer(&Layer{ID: ""})) // No ID
|
||||||
@ -33,7 +34,7 @@ func TestInvalidLayers(t *testing.T) {
|
|||||||
// TestLayerSimple inserts a single layer and ensures it can be retrieved and
|
// TestLayerSimple inserts a single layer and ensures it can be retrieved and
|
||||||
// that methods works
|
// that methods works
|
||||||
func TestLayerSimple(t *testing.T) {
|
func TestLayerSimple(t *testing.T) {
|
||||||
Open("memstore", "")
|
Open(&config.DatabaseConfig{Type: "memstore"})
|
||||||
defer Close()
|
defer Close()
|
||||||
|
|
||||||
// Insert a layer and find it back
|
// Insert a layer and find it back
|
||||||
@ -78,7 +79,7 @@ func TestLayerSimple(t *testing.T) {
|
|||||||
|
|
||||||
// TestLayerTree inserts a tree of layers and ensure that the tree lgoic works
|
// TestLayerTree inserts a tree of layers and ensure that the tree lgoic works
|
||||||
func TestLayerTree(t *testing.T) {
|
func TestLayerTree(t *testing.T) {
|
||||||
Open("memstore", "")
|
Open(&config.DatabaseConfig{Type: "memstore"})
|
||||||
defer Close()
|
defer Close()
|
||||||
|
|
||||||
var layers []*Layer
|
var layers []*Layer
|
||||||
@ -138,7 +139,7 @@ func TestLayerTree(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLayerUpdate(t *testing.T) {
|
func TestLayerUpdate(t *testing.T) {
|
||||||
Open("memstore", "")
|
Open(&config.DatabaseConfig{Type: "memstore"})
|
||||||
defer Close()
|
defer Close()
|
||||||
|
|
||||||
l1 := &Layer{ID: "l1", OS: "os1", InstalledPackagesNodes: []string{"p1", "p2"}, RemovedPackagesNodes: []string{"p3", "p4"}, EngineVersion: 1}
|
l1 := &Layer{ID: "l1", OS: "os1", InstalledPackagesNodes: []string{"p1", "p2"}, RemovedPackagesNodes: []string{"p3", "p4"}, EngineVersion: 1}
|
||||||
|
@ -18,11 +18,12 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/coreos/clair/config"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLock(t *testing.T) {
|
func TestLock(t *testing.T) {
|
||||||
Open("memstore", "")
|
Open(&config.DatabaseConfig{Type: "memstore"})
|
||||||
defer Close()
|
defer Close()
|
||||||
|
|
||||||
var l bool
|
var l bool
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/coreos/clair/config"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -84,7 +85,7 @@ func (n NotificationTest2) GetContent() (interface{}, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNotification(t *testing.T) {
|
func TestNotification(t *testing.T) {
|
||||||
Open("memstore", "")
|
Open(&config.DatabaseConfig{Type: "memstore"})
|
||||||
defer Close()
|
defer Close()
|
||||||
|
|
||||||
wrapper := &TestWrapper{}
|
wrapper := &TestWrapper{}
|
||||||
|
@ -20,12 +20,13 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/coreos/clair/config"
|
||||||
"github.com/coreos/clair/utils/types"
|
"github.com/coreos/clair/utils/types"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPackage(t *testing.T) {
|
func TestPackage(t *testing.T) {
|
||||||
Open("memstore", "")
|
Open(&config.DatabaseConfig{Type: "memstore"})
|
||||||
defer Close()
|
defer Close()
|
||||||
|
|
||||||
// Try to insert invalid packages
|
// Try to insert invalid packages
|
||||||
|
@ -17,13 +17,14 @@ package database
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/coreos/clair/config"
|
||||||
cerrors "github.com/coreos/clair/utils/errors"
|
cerrors "github.com/coreos/clair/utils/errors"
|
||||||
"github.com/coreos/clair/utils/types"
|
"github.com/coreos/clair/utils/types"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestVulnerability(t *testing.T) {
|
func TestVulnerability(t *testing.T) {
|
||||||
Open("memstore", "")
|
Open(&config.DatabaseConfig{Type: "memstore"})
|
||||||
defer Close()
|
defer Close()
|
||||||
|
|
||||||
// Insert invalid vulnerabilities
|
// Insert invalid vulnerabilities
|
||||||
@ -176,7 +177,7 @@ func TestVulnerability(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestInsertVulnerabilityNotifications(t *testing.T) {
|
func TestInsertVulnerabilityNotifications(t *testing.T) {
|
||||||
Open("memstore", "")
|
Open(&config.DatabaseConfig{Type: "memstore"})
|
||||||
defer Close()
|
defer Close()
|
||||||
|
|
||||||
pkg1 := &Package{OS: "testOS", Name: "testpkg1", Version: types.NewVersionUnsafe("1.0")}
|
pkg1 := &Package{OS: "testOS", Name: "testpkg1", Version: types.NewVersionUnsafe("1.0")}
|
||||||
|
32
docs/Run.md
32
docs/Run.md
@ -1,21 +1,27 @@
|
|||||||
# Build and Run with Docker
|
# Running Clair
|
||||||
|
|
||||||
The easiest way to run this tool is to deploy it using Docker.
|
## Configuration
|
||||||
If you prefer to run it locally, reading the Dockerfile will tell you how.
|
|
||||||
|
|
||||||
To deploy it from the latest sources, follow this procedure:
|
Clair makes uses of a configuration file in YAML.
|
||||||
* Clone the repository and change your current directory
|
|
||||||
* Build the container: `docker build -t <TAG> .`
|
|
||||||
* Run it like this to see the available commands: `docker run -it <TAG>`. To get help about a specific command, use `docker run -it <TAG> help <COMMAND>`
|
|
||||||
|
|
||||||
## Command-Line examples
|
Copy [`config.example.yaml`](../config.example.yaml) to your choice of location, and update the values as required.
|
||||||
|
The example configuration file is commented and explains every available key.
|
||||||
|
|
||||||
When running multiple instances is not desired, using BoltDB backend is the best choice as it is lightning fast:
|
## Docker
|
||||||
|
|
||||||
docker run -it <TAG> --db-type=bolt --db-path=/db/database
|
The easiest way to run Clair is with Docker.
|
||||||
|
|
||||||
Using PostgreSQL enables running multiple instances concurrently. Here is a command line example:
|
```
|
||||||
|
$ docker pull quay.io/coreos/clair:latest
|
||||||
|
$ docker run -p 6060:6060 -p 6061:6061 -v <DIR_WITH_CONFIG>:/config:ro quay.io/coreos/clair:latest --config=/config/<CONFIG_FILENAME>.yaml
|
||||||
|
```
|
||||||
|
|
||||||
docker run -it <TAG> --db-type=sql --db-path='host=awesome-database.us-east-1.rds.amazonaws.com port=5432 user=SuperSheep password=SuperSecret' --update-interval=2h --notifier-type=http --notifier-http-url="http://your-notification-endpoint"
|
## Initial update & API
|
||||||
|
|
||||||
The default API port is 6060, read the [API Documentation](API.md) to learn more.
|
Right after Clair starts, it will update its vulnerability database.
|
||||||
|
The initial update can take quite a long time depending on the database backend in use.
|
||||||
|
Clair will announce the update completion.
|
||||||
|
|
||||||
|
As soon as Clair has started, you can start querying the API to interact with it.
|
||||||
|
Read the [API Documentation](API.md) to learn more.
|
||||||
|
The [`contrib`](../contrib) folder contains some tools that may help you to get started.
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
# Security
|
# Security
|
||||||
|
|
||||||
# Enabling HTTPS
|
# Enabling HTTPS on the API
|
||||||
|
|
||||||
HTTPS provides clients the ability to verify the server identity and provide transport security.
|
HTTPS provides clients the ability to verify the server identity and provide transport security.
|
||||||
|
|
||||||
For this you need your CA certificate (ca.crt) and signed key pair (server.crt, server.key) ready.
|
For this you need your CA certificate (ca.crt) and signed key pair (server.crt, server.key) ready.
|
||||||
To enable it, provide signed key pair using `--api-cert-file` and `--api-key-file` arguments.
|
To enable it, provide the signed key pair files in the configuration under `api/keyfile` and `api/certfile` keys.
|
||||||
|
|
||||||
To test it, you want to use curl like this:
|
To test it, you want to use curl like this:
|
||||||
|
|
||||||
@ -14,13 +15,13 @@ You should be able to see the handshake succeed. Because we use self-signed cert
|
|||||||
|
|
||||||
**OSX 10.9+ Users**: curl 7.30.0 on OSX 10.9+ doesn't understand certificates passed in on the command line. Instead you must import the dummy ca.crt directly into the keychain or add the -k flag to curl to ignore errors. If you want to test without the -k flag run open ca.crt and follow the prompts. Please remove this certificate after you are done testing!
|
**OSX 10.9+ Users**: curl 7.30.0 on OSX 10.9+ doesn't understand certificates passed in on the command line. Instead you must import the dummy ca.crt directly into the keychain or add the -k flag to curl to ignore errors. If you want to test without the -k flag run open ca.crt and follow the prompts. Please remove this certificate after you are done testing!
|
||||||
|
|
||||||
# Enabling Client Certificate Auth
|
# Enabling Client Certificate Auth on the API
|
||||||
|
|
||||||
We can also use client certificates to prevent unauthorized access to the API.
|
We can also use client certificates to prevent unauthorized access to the API.
|
||||||
|
|
||||||
The clients will provide their certificates to the server and the server will check whether the cert is signed by the supplied CA and decide whether to serve the request.
|
The clients will provide their certificates to the server and the server will check whether the cert is signed by the supplied CA and decide whether to serve the request.
|
||||||
|
|
||||||
You need the same files mentioned in the HTTPS section, as well as a key pair for the client (client.crt, client.key) signed by the same certificate authority. To enable it, use the same arguments as above for HTTPS and the additional `--api-ca-file` parameter with the CA certificate.
|
You need the same files mentioned in the HTTPS section, as well as a key pair for the client (client.crt, client.key) signed by the same certificate authority. To enable it, use the same configuration as above for HTTPS and the additional `api/cafile` key parameter with the CA certificate path.
|
||||||
|
|
||||||
The test command from the HTTPS section should be rejected, instead we need to provide the client key pair:
|
The test command from the HTTPS section should be rejected, instead we need to provide the client key pair:
|
||||||
|
|
||||||
|
145
main.go
145
main.go
@ -1,145 +0,0 @@
|
|||||||
// Copyright 2015 clair authors
|
|
||||||
//
|
|
||||||
// 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.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/rand"
|
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"runtime/pprof"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/coreos/clair/api"
|
|
||||||
"github.com/coreos/clair/database"
|
|
||||||
"github.com/coreos/clair/notifier"
|
|
||||||
"github.com/coreos/clair/updater"
|
|
||||||
"github.com/coreos/clair/utils"
|
|
||||||
|
|
||||||
"github.com/coreos/pkg/capnslog"
|
|
||||||
"gopkg.in/alecthomas/kingpin.v2"
|
|
||||||
|
|
||||||
// Register components
|
|
||||||
_ "github.com/coreos/clair/updater/fetchers"
|
|
||||||
_ "github.com/coreos/clair/worker/detectors/os"
|
|
||||||
_ "github.com/coreos/clair/worker/detectors/packages"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
log = capnslog.NewPackageLogger("github.com/coreos/clair", "main")
|
|
||||||
|
|
||||||
// Database configuration
|
|
||||||
cfgDbType = kingpin.Flag("db-type", "Type of the database to use").Default("bolt").Enum("bolt", "leveldb", "memstore", "mongo", "sql")
|
|
||||||
cfgDbPath = kingpin.Flag("db-path", "Path to the database to use").String()
|
|
||||||
|
|
||||||
// Notifier configuration
|
|
||||||
cfgNotifierEndpoint = kingpin.Flag("notifier-endpoint", "URL that will receive POST notifications").String()
|
|
||||||
cfgNotifierCertFile = kingpin.Flag("notifier-cert-file", "Path to TLS Cert file").ExistingFile()
|
|
||||||
cfgNotifierKeyFile = kingpin.Flag("notifier-key-file", "Path to TLS Key file").ExistingFile()
|
|
||||||
cfgNotifierCAFile = kingpin.Flag("notifier-ca-file", "Path to CA for verifying TLS client certs").ExistingFile()
|
|
||||||
|
|
||||||
// Updater configuration
|
|
||||||
cfgUpdateInterval = kingpin.Flag("update-interval", "Frequency at which the vulnerability updater will run. Use 0 to disable the updater entirely.").Default("1h").Duration()
|
|
||||||
|
|
||||||
// API configuration
|
|
||||||
cfgAPIPort = kingpin.Flag("api-port", "Port on which the API will listen").Default("6060").Int()
|
|
||||||
cfgAPITimeout = kingpin.Flag("api-timeout", "Timeout of API calls").Default("900s").Duration()
|
|
||||||
cfgAPICertFile = kingpin.Flag("api-cert-file", "Path to TLS Cert file").ExistingFile()
|
|
||||||
cfgAPIKeyFile = kingpin.Flag("api-key-file", "Path to TLS Key file").ExistingFile()
|
|
||||||
cfgAPICAFile = kingpin.Flag("api-ca-file", "Path to CA for verifying TLS client certs").ExistingFile()
|
|
||||||
|
|
||||||
// Other flags
|
|
||||||
cfgCPUProfilePath = kingpin.Flag("cpu-profile-path", "Path to a write CPU profiling data").String()
|
|
||||||
cfgLogLevel = kingpin.Flag("log-level", "How much console-spam do you want globally").Default("info").Enum("trace", "debug", "info", "notice", "warning", "error", "critical")
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
rand.Seed(time.Now().UTC().UnixNano())
|
|
||||||
|
|
||||||
var err error
|
|
||||||
st := utils.NewStopper()
|
|
||||||
|
|
||||||
// Parse command-line arguments
|
|
||||||
kingpin.Parse()
|
|
||||||
if *cfgDbType != "memstore" && *cfgDbPath == "" {
|
|
||||||
kingpin.Errorf("required flag --db-path not provided, try --help")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize error/logging system
|
|
||||||
logLevel, err := capnslog.ParseLevel(strings.ToUpper(*cfgLogLevel))
|
|
||||||
capnslog.SetGlobalLogLevel(logLevel)
|
|
||||||
capnslog.SetFormatter(capnslog.NewPrettyFormatter(os.Stdout, false))
|
|
||||||
|
|
||||||
// Enable CPU Profiling if specified
|
|
||||||
if *cfgCPUProfilePath != "" {
|
|
||||||
f, err := os.Create(*cfgCPUProfilePath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("failed to create profile file: %s", err)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
pprof.StartCPUProfile(f)
|
|
||||||
log.Info("started profiling")
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
pprof.StopCPUProfile()
|
|
||||||
log.Info("stopped profiling")
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open database
|
|
||||||
err = database.Open(*cfgDbType, *cfgDbPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer database.Close()
|
|
||||||
|
|
||||||
// Start notifier
|
|
||||||
if len(*cfgNotifierEndpoint) > 0 {
|
|
||||||
notifier := notifier.New(notifier.Config{
|
|
||||||
Endpoint: *cfgNotifierEndpoint,
|
|
||||||
CertFile: *cfgNotifierCertFile,
|
|
||||||
KeyFile: *cfgNotifierKeyFile,
|
|
||||||
CAFile: *cfgNotifierCAFile,
|
|
||||||
})
|
|
||||||
|
|
||||||
st.Begin()
|
|
||||||
go notifier.Serve(st)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start Main API and Health API
|
|
||||||
st.Begin()
|
|
||||||
go api.RunMain(&api.Config{
|
|
||||||
Port: *cfgAPIPort,
|
|
||||||
TimeOut: *cfgAPITimeout,
|
|
||||||
CertFile: *cfgAPICertFile,
|
|
||||||
KeyFile: *cfgAPIKeyFile,
|
|
||||||
CAFile: *cfgAPICAFile,
|
|
||||||
}, st)
|
|
||||||
st.Begin()
|
|
||||||
go api.RunHealth(*cfgAPIPort+1, st)
|
|
||||||
|
|
||||||
// Start updater
|
|
||||||
st.Begin()
|
|
||||||
go updater.Run(*cfgUpdateInterval, st)
|
|
||||||
|
|
||||||
// This blocks the main goroutine which is required to keep all the other goroutines running
|
|
||||||
interrupts := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(interrupts, os.Interrupt)
|
|
||||||
<-interrupts
|
|
||||||
log.Info("Received interruption, gracefully stopping ...")
|
|
||||||
st.Stop()
|
|
||||||
}
|
|
@ -26,6 +26,7 @@ import (
|
|||||||
"github.com/coreos/pkg/capnslog"
|
"github.com/coreos/pkg/capnslog"
|
||||||
"github.com/pborman/uuid"
|
"github.com/pborman/uuid"
|
||||||
|
|
||||||
|
"github.com/coreos/clair/config"
|
||||||
"github.com/coreos/clair/database"
|
"github.com/coreos/clair/database"
|
||||||
"github.com/coreos/clair/health"
|
"github.com/coreos/clair/health"
|
||||||
"github.com/coreos/clair/utils"
|
"github.com/coreos/clair/utils"
|
||||||
@ -41,6 +42,8 @@ const (
|
|||||||
lockDuration = time.Minute*8 + refreshLockDuration
|
lockDuration = time.Minute*8 + refreshLockDuration
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO(Quentin-M): Allow registering custom notification handlers.
|
||||||
|
|
||||||
// A Notification represents the structure of the notifications that are sent by a Notifier.
|
// A Notification represents the structure of the notifications that are sent by a Notifier.
|
||||||
type Notification struct {
|
type Notification struct {
|
||||||
Name, Type string
|
Name, Type string
|
||||||
@ -54,21 +57,20 @@ type Notifier struct {
|
|||||||
client *http.Client
|
client *http.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config represents the configuration of a Notifier.
|
|
||||||
// The certificates are optionnal and enable client certificate authentification.
|
|
||||||
type Config struct {
|
|
||||||
Endpoint string
|
|
||||||
CertFile, KeyFile, CAFile string
|
|
||||||
}
|
|
||||||
|
|
||||||
// New initializes a new Notifier from the specified configuration.
|
// New initializes a new Notifier from the specified configuration.
|
||||||
func New(cfg Config) *Notifier {
|
func New(config *config.NotifierConfig) *Notifier {
|
||||||
if _, err := url.Parse(cfg.Endpoint); err != nil {
|
if config == nil {
|
||||||
log.Fatal("could not create a notifier with an invalid endpoint URL")
|
return &Notifier{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize TLS
|
// Validate endpoint URL.
|
||||||
tlsConfig, err := httputils.LoadTLSClientConfig(cfg.CertFile, cfg.KeyFile, cfg.CAFile)
|
if _, err := url.Parse(config.Endpoint); err != nil {
|
||||||
|
log.Error("could not create a notifier with an invalid endpoint URL")
|
||||||
|
return &Notifier{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize TLS.
|
||||||
|
tlsConfig, err := httputils.LoadTLSClientConfig(config.CertFile, config.KeyFile, config.CAFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("could not initialize client cert authentification: %s\n", err)
|
log.Fatalf("could not initialize client cert authentification: %s\n", err)
|
||||||
}
|
}
|
||||||
@ -84,7 +86,7 @@ func New(cfg Config) *Notifier {
|
|||||||
|
|
||||||
return &Notifier{
|
return &Notifier{
|
||||||
lockIdentifier: uuid.New(),
|
lockIdentifier: uuid.New(),
|
||||||
endpoint: cfg.Endpoint,
|
endpoint: config.Endpoint,
|
||||||
client: httpClient,
|
client: httpClient,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,6 +94,14 @@ func New(cfg Config) *Notifier {
|
|||||||
// Serve starts the Notifier.
|
// Serve starts the Notifier.
|
||||||
func (n *Notifier) Serve(stopper *utils.Stopper) {
|
func (n *Notifier) Serve(stopper *utils.Stopper) {
|
||||||
defer stopper.End()
|
defer stopper.End()
|
||||||
|
|
||||||
|
// Do not run the updater if the endpoint is empty.
|
||||||
|
if n.endpoint == "" {
|
||||||
|
log.Infof("notifier service is disabled.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register healthchecker.
|
||||||
health.RegisterHealthchecker("notifier", n.Healthcheck)
|
health.RegisterHealthchecker("notifier", n.Healthcheck)
|
||||||
|
|
||||||
log.Infof("notifier service started. endpoint: %s. lock identifier: %s\n", n.endpoint, n.lockIdentifier)
|
log.Infof("notifier service started. endpoint: %s. lock identifier: %s\n", n.endpoint, n.lockIdentifier)
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/coreos/clair/config"
|
||||||
"github.com/coreos/clair/database"
|
"github.com/coreos/clair/database"
|
||||||
"github.com/coreos/clair/health"
|
"github.com/coreos/clair/health"
|
||||||
"github.com/coreos/clair/utils"
|
"github.com/coreos/clair/utils"
|
||||||
@ -39,30 +40,29 @@ const (
|
|||||||
|
|
||||||
var log = capnslog.NewPackageLogger("github.com/coreos/clair", "updater")
|
var log = capnslog.NewPackageLogger("github.com/coreos/clair", "updater")
|
||||||
|
|
||||||
func init() {
|
// Run updates the vulnerability database at regular intervals.
|
||||||
health.RegisterHealthchecker("updater", Healthcheck)
|
func Run(config *config.UpdaterConfig, st *utils.Stopper) {
|
||||||
}
|
|
||||||
|
|
||||||
// Run updates the vulnerability database at regular intervals
|
|
||||||
func Run(interval time.Duration, st *utils.Stopper) {
|
|
||||||
defer st.End()
|
defer st.End()
|
||||||
|
|
||||||
// Do not run the updater if the interval is 0
|
// Do not run the updater if there is no config or if the interval is 0.
|
||||||
if interval == 0 {
|
if config == nil || config.Interval == 0 {
|
||||||
log.Infof("updater service is disabled.")
|
log.Infof("updater service is disabled.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register healthchecker.
|
||||||
|
health.RegisterHealthchecker("updater", Healthcheck)
|
||||||
|
|
||||||
whoAmI := uuid.New()
|
whoAmI := uuid.New()
|
||||||
log.Infof("updater service started. lock identifier: %s", whoAmI)
|
log.Infof("updater service started. lock identifier: %s", whoAmI)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
// Set the next update time to (last update time + interval) or now if there
|
// Set the next update time to (last update time + interval) or now if there
|
||||||
// is no last update time stored in database (first update) or if an error
|
// is no last update time stored in database (first update) or if an error
|
||||||
// occurs
|
// occurs.
|
||||||
var nextUpdate time.Time
|
var nextUpdate time.Time
|
||||||
if lastUpdate := getLastUpdate(); !lastUpdate.IsZero() {
|
if lastUpdate := getLastUpdate(); !lastUpdate.IsZero() {
|
||||||
nextUpdate = lastUpdate.Add(interval)
|
nextUpdate = lastUpdate.Add(config.Interval)
|
||||||
} else {
|
} else {
|
||||||
nextUpdate = time.Now().UTC()
|
nextUpdate = time.Now().UTC()
|
||||||
}
|
}
|
||||||
|
3
vendor/gopkg.in/alecthomas/kingpin.v2/.travis.yml
generated
vendored
3
vendor/gopkg.in/alecthomas/kingpin.v2/.travis.yml
generated
vendored
@ -1,3 +0,0 @@
|
|||||||
language: go
|
|
||||||
install: go get -t -v ./...
|
|
||||||
go: 1.2
|
|
538
vendor/gopkg.in/alecthomas/kingpin.v2/README.md
generated
vendored
538
vendor/gopkg.in/alecthomas/kingpin.v2/README.md
generated
vendored
@ -1,538 +0,0 @@
|
|||||||
# Kingpin - A Go (golang) command line and flag parser [![Build Status](https://travis-ci.org/alecthomas/kingpin.png)](https://travis-ci.org/alecthomas/kingpin)
|
|
||||||
|
|
||||||
<!-- MarkdownTOC -->
|
|
||||||
|
|
||||||
- [Overview](#overview)
|
|
||||||
- [Features](#features)
|
|
||||||
- [User-visible changes between v1 and v2](#user-visible-changes-between-v1-and-v2)
|
|
||||||
- [Flags can be used at any point after their definition.](#flags-can-be-used-at-any-point-after-their-definition)
|
|
||||||
- [Short flags can be combined with their parameters](#short-flags-can-be-combined-with-their-parameters)
|
|
||||||
- [API changes between v1 and v2](#api-changes-between-v1-and-v2)
|
|
||||||
- [Versions](#versions)
|
|
||||||
- [V2 is the current stable version](#v2-is-the-current-stable-version)
|
|
||||||
- [V1 is the OLD stable version](#v1-is-the-old-stable-version)
|
|
||||||
- [Change History](#change-history)
|
|
||||||
- [Examples](#examples)
|
|
||||||
- [Simple Example](#simple-example)
|
|
||||||
- [Complex Example](#complex-example)
|
|
||||||
- [Reference Documentation](#reference-documentation)
|
|
||||||
- [Displaying errors and usage information](#displaying-errors-and-usage-information)
|
|
||||||
- [Sub-commands](#sub-commands)
|
|
||||||
- [Custom Parsers](#custom-parsers)
|
|
||||||
- [Default Values](#default-values)
|
|
||||||
- [Place-holders in Help](#place-holders-in-help)
|
|
||||||
- [Consuming all remaining arguments](#consuming-all-remaining-arguments)
|
|
||||||
- [Custom help](#custom-help)
|
|
||||||
|
|
||||||
<!-- /MarkdownTOC -->
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
Kingpin is a [fluent-style](http://en.wikipedia.org/wiki/Fluent_interface),
|
|
||||||
type-safe command-line parser. It supports flags, nested commands, and
|
|
||||||
positional arguments.
|
|
||||||
|
|
||||||
Install it with:
|
|
||||||
|
|
||||||
$ go get gopkg.in/alecthomas/kingpin.v2
|
|
||||||
|
|
||||||
It looks like this:
|
|
||||||
|
|
||||||
```go
|
|
||||||
var (
|
|
||||||
verbose = kingpin.Flag("verbose", "Verbose mode.").Short('v').Bool()
|
|
||||||
name = kingpin.Arg("name", "Name of user.").Required().String()
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
kingpin.Parse()
|
|
||||||
fmt.Printf("%v, %s\n", *verbose, *name)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
More [examples](https://github.com/alecthomas/kingpin/tree/master/examples) are available.
|
|
||||||
|
|
||||||
Second to parsing, providing the user with useful help is probably the most
|
|
||||||
important thing a command-line parser does. Kingpin tries to provide detailed
|
|
||||||
contextual help if `--help` is encountered at any point in the command line
|
|
||||||
(excluding after `--`).
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- Help output that isn't as ugly as sin.
|
|
||||||
- Fully [customisable help](#custom-help), via Go templates.
|
|
||||||
- Parsed, type-safe flags (`kingpin.Flag("f", "help").Int()`)
|
|
||||||
- Parsed, type-safe positional arguments (`kingpin.Arg("a", "help").Int()`).
|
|
||||||
- Support for required flags and required positional arguments (`kingpin.Flag("f", "").Required().Int()`).
|
|
||||||
- Callbacks per command, flag and argument (`kingpin.Command("c", "").Action(myAction)`).
|
|
||||||
- POSIX-style short flag combining (`-a -b` -> `-ab`).
|
|
||||||
- Short-flag+parameter combining (`-a parm` -> `-aparm`).
|
|
||||||
- Read command-line from files (`@<file>`).
|
|
||||||
- Automatically generate man pages (`--man-page`).
|
|
||||||
|
|
||||||
## User-visible changes between v1 and v2
|
|
||||||
|
|
||||||
### Flags can be used at any point after their definition.
|
|
||||||
|
|
||||||
Flags can be specified at any point after their definition, not just
|
|
||||||
*immediately after their associated command*. From the chat example below, the
|
|
||||||
following used to be required:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ chat --server=chat.server.com:8080 post --image=~/Downloads/owls.jpg pics
|
|
||||||
```
|
|
||||||
|
|
||||||
But the following will now work:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ chat post --server=chat.server.com:8080 --image=~/Downloads/owls.jpg pics
|
|
||||||
```
|
|
||||||
|
|
||||||
### Short flags can be combined with their parameters
|
|
||||||
|
|
||||||
Previously, if a short flag was used, any argument to that flag would have to
|
|
||||||
be separated by a space. That is no longer the case.
|
|
||||||
|
|
||||||
## API changes between v1 and v2
|
|
||||||
|
|
||||||
- `ParseWithFileExpansion()` is gone. The new parser directly supports expanding `@<file>`.
|
|
||||||
- Added `FatalUsage()` and `FatalUsageContext()` for displaying an error + usage and terminating.
|
|
||||||
- `Dispatch()` renamed to `Action()`.
|
|
||||||
- Added `ParseContext()` for parsing a command line into its intermediate context form without executing.
|
|
||||||
- Added `Terminate()` function to override the termination function.
|
|
||||||
- Added `UsageForContextWithTemplate()` for printing usage via a custom template.
|
|
||||||
- Added `UsageTemplate()` for overriding the default template to use. Two templates are included:
|
|
||||||
1. `DefaultUsageTemplate` - default template.
|
|
||||||
2. `CompactUsageTemplate` - compact command template for larger applications.
|
|
||||||
|
|
||||||
## Versions
|
|
||||||
|
|
||||||
Kingpin uses [gopkg.in](https://gopkg.in/alecthomas/kingpin) for versioning.
|
|
||||||
|
|
||||||
The current stable version is [gopkg.in/alecthomas/kingpin.v2](https://gopkg.in/alecthomas/kingpin.v2). The previous version, [gopkg.in/alecthomas/kingpin.v1](https://gopkg.in/alecthomas/kingpin.v1), is deprecated and in maintenance mode.
|
|
||||||
|
|
||||||
### [V2](https://gopkg.in/alecthomas/kingpin.v2) is the current stable version
|
|
||||||
|
|
||||||
Installation:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ go get gopkg.in/alecthomas/kingpin.v2
|
|
||||||
```
|
|
||||||
|
|
||||||
### [V1](https://gopkg.in/alecthomas/kingpin.v1) is the OLD stable version
|
|
||||||
|
|
||||||
Installation:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ go get gopkg.in/alecthomas/kingpin.v1
|
|
||||||
```
|
|
||||||
|
|
||||||
## Change History
|
|
||||||
|
|
||||||
- *2015-05-22* -- Stable v2.0.0 release.
|
|
||||||
- Initial stable release of v2.0.0.
|
|
||||||
- Fully supports interspersed flags, commands and arguments.
|
|
||||||
- Flags can be present at any point after their logical definition.
|
|
||||||
- Application.Parse() terminates if commands are present and a command is not parsed.
|
|
||||||
- Dispatch() -> Action().
|
|
||||||
- Actions are dispatched after all values are populated.
|
|
||||||
- Override termination function (defaults to os.Exit).
|
|
||||||
- Override output stream (defaults to os.Stderr).
|
|
||||||
- Templatised usage help, with default and compact templates.
|
|
||||||
- Make error/usage functions more consistent.
|
|
||||||
- Support argument expansion from files by default (with @<file>).
|
|
||||||
- Fully public data model is available via .Model().
|
|
||||||
- Parser has been completely refactored.
|
|
||||||
- Parsing and execution has been split into distinct stages.
|
|
||||||
- Use `go generate` to generate repeated flags.
|
|
||||||
- Support combined short-flag+argument: -fARG.
|
|
||||||
|
|
||||||
- *2015-01-23* -- Stable v1.3.4 release.
|
|
||||||
- Support "--" for separating flags from positional arguments.
|
|
||||||
- Support loading flags from files (ParseWithFileExpansion()). Use @FILE as an argument.
|
|
||||||
- Add post-app and post-cmd validation hooks. This allows arbitrary validation to be added.
|
|
||||||
- A bunch of improvements to help usage and formatting.
|
|
||||||
- Support arbitrarily nested sub-commands.
|
|
||||||
|
|
||||||
- *2014-07-08* -- Stable v1.2.0 release.
|
|
||||||
- Pass any value through to `Strings()` when final argument.
|
|
||||||
Allows for values that look like flags to be processed.
|
|
||||||
- Allow `--help` to be used with commands.
|
|
||||||
- Support `Hidden()` flags.
|
|
||||||
- Parser for [units.Base2Bytes](https://github.com/alecthomas/units)
|
|
||||||
type. Allows for flags like `--ram=512MB` or `--ram=1GB`.
|
|
||||||
- Add an `Enum()` value, allowing only one of a set of values
|
|
||||||
to be selected. eg. `Flag(...).Enum("debug", "info", "warning")`.
|
|
||||||
|
|
||||||
- *2014-06-27* -- Stable v1.1.0 release.
|
|
||||||
- Bug fixes.
|
|
||||||
- Always return an error (rather than panicing) when misconfigured.
|
|
||||||
- `OpenFile(flag, perm)` value type added, for finer control over opening files.
|
|
||||||
- Significantly improved usage formatting.
|
|
||||||
|
|
||||||
- *2014-06-19* -- Stable v1.0.0 release.
|
|
||||||
- Support [cumulative positional](#consuming-all-remaining-arguments) arguments.
|
|
||||||
- Return error rather than panic when there are fatal errors not caught by
|
|
||||||
the type system. eg. when a default value is invalid.
|
|
||||||
- Use gokpg.in.
|
|
||||||
|
|
||||||
- *2014-06-10* -- Place-holder streamlining.
|
|
||||||
- Renamed `MetaVar` to `PlaceHolder`.
|
|
||||||
- Removed `MetaVarFromDefault`. Kingpin now uses [heuristics](#place-holders-in-help)
|
|
||||||
to determine what to display.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
### Simple Example
|
|
||||||
|
|
||||||
Kingpin can be used for simple flag+arg applications like so:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ ping --help
|
|
||||||
usage: ping [<flags>] <ip> [<count>]
|
|
||||||
|
|
||||||
Flags:
|
|
||||||
--debug Enable debug mode.
|
|
||||||
--help Show help.
|
|
||||||
-t, --timeout=5s Timeout waiting for ping.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
<ip> IP address to ping.
|
|
||||||
[<count>] Number of packets to send
|
|
||||||
$ ping 1.2.3.4 5
|
|
||||||
Would ping: 1.2.3.4 with timeout 5s and count 0
|
|
||||||
```
|
|
||||||
|
|
||||||
From the following source:
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"gopkg.in/alecthomas/kingpin.v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
debug = kingpin.Flag("debug", "Enable debug mode.").Bool()
|
|
||||||
timeout = kingpin.Flag("timeout", "Timeout waiting for ping.").Default("5s").OverrideDefaultFromEnvar("PING_TIMEOUT").Short('t').Duration()
|
|
||||||
ip = kingpin.Arg("ip", "IP address to ping.").Required().IP()
|
|
||||||
count = kingpin.Arg("count", "Number of packets to send").Int()
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
kingpin.Version("0.0.1")
|
|
||||||
kingpin.Parse()
|
|
||||||
fmt.Printf("Would ping: %s with timeout %s and count %d", *ip, *timeout, *count)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Complex Example
|
|
||||||
|
|
||||||
Kingpin can also produce complex command-line applications with global flags,
|
|
||||||
subcommands, and per-subcommand flags, like this:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ chat --help
|
|
||||||
usage: chat [<flags>] <command> [<flags>] [<args> ...]
|
|
||||||
|
|
||||||
A command-line chat application.
|
|
||||||
|
|
||||||
Flags:
|
|
||||||
--help Show help.
|
|
||||||
--debug Enable debug mode.
|
|
||||||
--server=127.0.0.1 Server address.
|
|
||||||
|
|
||||||
Commands:
|
|
||||||
help [<command>]
|
|
||||||
Show help for a command.
|
|
||||||
|
|
||||||
register <nick> <name>
|
|
||||||
Register a new user.
|
|
||||||
|
|
||||||
post [<flags>] <channel> [<text>]
|
|
||||||
Post a message to a channel.
|
|
||||||
|
|
||||||
$ chat help post
|
|
||||||
usage: chat [<flags>] post [<flags>] <channel> [<text>]
|
|
||||||
|
|
||||||
Post a message to a channel.
|
|
||||||
|
|
||||||
Flags:
|
|
||||||
--image=IMAGE Image to post.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
<channel> Channel to post to.
|
|
||||||
[<text>] Text to post.
|
|
||||||
|
|
||||||
$ chat post --image=~/Downloads/owls.jpg pics
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
From this code:
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"gopkg.in/alecthomas/kingpin.v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
app = kingpin.New("chat", "A command-line chat application.")
|
|
||||||
debug = app.Flag("debug", "Enable debug mode.").Bool()
|
|
||||||
serverIP = app.Flag("server", "Server address.").Default("127.0.0.1").IP()
|
|
||||||
|
|
||||||
register = app.Command("register", "Register a new user.")
|
|
||||||
registerNick = register.Arg("nick", "Nickname for user.").Required().String()
|
|
||||||
registerName = register.Arg("name", "Name of user.").Required().String()
|
|
||||||
|
|
||||||
post = app.Command("post", "Post a message to a channel.")
|
|
||||||
postImage = post.Flag("image", "Image to post.").File()
|
|
||||||
postChannel = post.Arg("channel", "Channel to post to.").Required().String()
|
|
||||||
postText = post.Arg("text", "Text to post.").Strings()
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
switch kingpin.MustParse(app.Parse(os.Args[1:])) {
|
|
||||||
// Register user
|
|
||||||
case register.FullCommand():
|
|
||||||
println(*registerNick)
|
|
||||||
|
|
||||||
// Post message
|
|
||||||
case post.FullCommand():
|
|
||||||
if *postImage != nil {
|
|
||||||
}
|
|
||||||
text := strings.Join(*postText, " ")
|
|
||||||
println("Post:", text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Reference Documentation
|
|
||||||
|
|
||||||
### Displaying errors and usage information
|
|
||||||
|
|
||||||
Kingpin exports a set of functions to provide consistent errors and usage
|
|
||||||
information to the user.
|
|
||||||
|
|
||||||
Error messages look something like this:
|
|
||||||
|
|
||||||
<app>: error: <message>
|
|
||||||
|
|
||||||
The functions on `Application` are:
|
|
||||||
|
|
||||||
Function | Purpose
|
|
||||||
---------|--------------
|
|
||||||
`Errorf(format, args)` | Display a printf formatted error to the user.
|
|
||||||
`Fatalf(format, args)` | As with Errorf, but also call the termination handler.
|
|
||||||
`FatalUsage(format, args)` | As with Fatalf, but also print contextual usage information.
|
|
||||||
`FatalUsageContext(context, format, args)` | As with Fatalf, but also print contextual usage information from a `ParseContext`.
|
|
||||||
`FatalIfError(err, format, args)` | Conditionally print an error prefixed with format+args, then call the termination handler
|
|
||||||
|
|
||||||
There are equivalent global functions in the kingpin namespace for the default
|
|
||||||
`kingpin.CommandLine` instance.
|
|
||||||
|
|
||||||
### Sub-commands
|
|
||||||
|
|
||||||
Kingpin supports nested sub-commands, with separate flag and positional
|
|
||||||
arguments per sub-command. Note that positional arguments may only occur after
|
|
||||||
sub-commands.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
```go
|
|
||||||
var (
|
|
||||||
deleteCommand = kingpin.Command("delete", "Delete an object.")
|
|
||||||
deleteUserCommand = deleteCommand.Command("user", "Delete a user.")
|
|
||||||
deleteUserUIDFlag = deleteUserCommand.Flag("uid", "Delete user by UID rather than username.")
|
|
||||||
deleteUserUsername = deleteUserCommand.Arg("username", "Username to delete.")
|
|
||||||
deletePostCommand = deleteCommand.Command("post", "Delete a post.")
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
switch kingpin.Parse() {
|
|
||||||
case "delete user":
|
|
||||||
case "delete post":
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Custom Parsers
|
|
||||||
|
|
||||||
Kingpin supports both flag and positional argument parsers for converting to
|
|
||||||
Go types. For example, some included parsers are `Int()`, `Float()`,
|
|
||||||
`Duration()` and `ExistingFile()`.
|
|
||||||
|
|
||||||
Parsers conform to Go's [`flag.Value`](http://godoc.org/flag#Value)
|
|
||||||
interface, so any existing implementations will work.
|
|
||||||
|
|
||||||
For example, a parser for accumulating HTTP header values might look like this:
|
|
||||||
|
|
||||||
```go
|
|
||||||
type HTTPHeaderValue http.Header
|
|
||||||
|
|
||||||
func (h *HTTPHeaderValue) Set(value string) error {
|
|
||||||
parts := strings.SplitN(value, ":", 2)
|
|
||||||
if len(parts) != 2 {
|
|
||||||
return fmt.Errorf("expected HEADER:VALUE got '%s'", value)
|
|
||||||
}
|
|
||||||
(*http.Header)(h).Add(parts[0], parts[1])
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HTTPHeaderValue) String() string {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
As a convenience, I would recommend something like this:
|
|
||||||
|
|
||||||
```go
|
|
||||||
func HTTPHeader(s Settings) (target *http.Header) {
|
|
||||||
target = new(http.Header)
|
|
||||||
s.SetValue((*HTTPHeaderValue)(target))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You would use it like so:
|
|
||||||
|
|
||||||
```go
|
|
||||||
headers = HTTPHeader(kingpin.Flag("header", "Add a HTTP header to the request.").Short('H'))
|
|
||||||
```
|
|
||||||
|
|
||||||
### Default Values
|
|
||||||
|
|
||||||
The default value is the zero value for a type. This can be overridden with
|
|
||||||
the `Default(value)` function on flags and arguments. This function accepts a
|
|
||||||
string, which is parsed by the value itself, so it *must* be compliant with
|
|
||||||
the format expected.
|
|
||||||
|
|
||||||
### Place-holders in Help
|
|
||||||
|
|
||||||
The place-holder value for a flag is the value used in the help to describe
|
|
||||||
the value of a non-boolean flag.
|
|
||||||
|
|
||||||
The value provided to PlaceHolder() is used if provided, then the value
|
|
||||||
provided by Default() if provided, then finally the capitalised flag name is
|
|
||||||
used.
|
|
||||||
|
|
||||||
Here are some examples of flags with various permutations:
|
|
||||||
|
|
||||||
--name=NAME // Flag(...).String()
|
|
||||||
--name="Harry" // Flag(...).Default("Harry").String()
|
|
||||||
--name=FULL-NAME // flag(...).PlaceHolder("FULL-NAME").Default("Harry").String()
|
|
||||||
|
|
||||||
### Consuming all remaining arguments
|
|
||||||
|
|
||||||
A common command-line idiom is to use all remaining arguments for some
|
|
||||||
purpose. eg. The following command accepts an arbitrary number of
|
|
||||||
IP addresses as positional arguments:
|
|
||||||
|
|
||||||
./cmd ping 10.1.1.1 192.168.1.1
|
|
||||||
|
|
||||||
Kingpin supports this by having `Value` provide a `IsCumulative() bool`
|
|
||||||
function. If this function exists and returns true, the value parser will be
|
|
||||||
called repeatedly for every remaining argument.
|
|
||||||
|
|
||||||
Examples of this are the `Strings()` and `StringMap()` values.
|
|
||||||
|
|
||||||
To implement the above example we might do something like this:
|
|
||||||
|
|
||||||
```go
|
|
||||||
type ipList []net.IP
|
|
||||||
|
|
||||||
func (i *ipList) Set(value string) error {
|
|
||||||
if ip := net.ParseIP(value); ip == nil {
|
|
||||||
return fmt.Errorf("'%s' is not an IP address", value)
|
|
||||||
} else {
|
|
||||||
*i = append(*i, ip)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *ipList) String() string {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *ipList) IsCumulative() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func IPList(s Settings) (target *[]net.IP) {
|
|
||||||
target = new([]net.IP)
|
|
||||||
s.SetValue((*ipList)(target))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
And use it like so:
|
|
||||||
|
|
||||||
```go
|
|
||||||
ips := IPList(kingpin.Arg("ips", "IP addresses to ping."))
|
|
||||||
```
|
|
||||||
|
|
||||||
### Custom help
|
|
||||||
|
|
||||||
Kingpin v2 supports templatised help using the text/template library (actually, [a fork](https://github.com/alecthomas/template)).
|
|
||||||
|
|
||||||
You can specify the template to use with the [Application.UsageTemplate()](http://godoc.org/gopkg.in/alecthomas/kingpin.v2#Application.UsageTemplate) function.
|
|
||||||
|
|
||||||
There are three included templates: `kingpin.DefaultUsageTemplate` is the default,
|
|
||||||
`kingpin.CompactUsageTemplate` provides a more compact representation for more complex command-line structures, and `kingpin.ManPageTemplate` is used to generate man pages.
|
|
||||||
|
|
||||||
See the above templates for examples of usage, and the the function [UsageForContextWithTemplate()](https://github.com/alecthomas/kingpin/blob/master/usage.go#L198) method for details on the context.
|
|
||||||
|
|
||||||
#### Default help template
|
|
||||||
|
|
||||||
```
|
|
||||||
$ go run ./examples/curl/curl.go --help
|
|
||||||
usage: curl [<flags>] <command> [<args> ...]
|
|
||||||
|
|
||||||
An example implementation of curl.
|
|
||||||
|
|
||||||
Flags:
|
|
||||||
--help Show help.
|
|
||||||
-t, --timeout=5s Set connection timeout.
|
|
||||||
-H, --headers=HEADER=VALUE
|
|
||||||
Add HTTP headers to the request.
|
|
||||||
|
|
||||||
Commands:
|
|
||||||
help [<command>...]
|
|
||||||
Show help.
|
|
||||||
|
|
||||||
get url <url>
|
|
||||||
Retrieve a URL.
|
|
||||||
|
|
||||||
get file <file>
|
|
||||||
Retrieve a file.
|
|
||||||
|
|
||||||
post [<flags>] <url>
|
|
||||||
POST a resource.
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Compact help template
|
|
||||||
|
|
||||||
```
|
|
||||||
$ go run ./examples/curl/curl.go --help
|
|
||||||
usage: curl [<flags>] <command> [<args> ...]
|
|
||||||
|
|
||||||
An example implementation of curl.
|
|
||||||
|
|
||||||
Flags:
|
|
||||||
--help Show help.
|
|
||||||
-t, --timeout=5s Set connection timeout.
|
|
||||||
-H, --headers=HEADER=VALUE
|
|
||||||
Add HTTP headers to the request.
|
|
||||||
|
|
||||||
Commands:
|
|
||||||
help [<command>...]
|
|
||||||
get [<flags>]
|
|
||||||
url <url>
|
|
||||||
file <file>
|
|
||||||
post [<flags>] <url>
|
|
||||||
```
|
|
564
vendor/gopkg.in/alecthomas/kingpin.v2/app.go
generated
vendored
564
vendor/gopkg.in/alecthomas/kingpin.v2/app.go
generated
vendored
@ -1,564 +0,0 @@
|
|||||||
package kingpin
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrCommandNotSpecified = fmt.Errorf("command not specified")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Action callback executed at various stages after all values are populated.
|
|
||||||
// The application, commands, arguments and flags all have corresponding
|
|
||||||
// actions.
|
|
||||||
type Action func(*ParseContext) error
|
|
||||||
|
|
||||||
type ApplicationValidator func(*Application) error
|
|
||||||
|
|
||||||
// An Application contains the definitions of flags, arguments and commands
|
|
||||||
// for an application.
|
|
||||||
type Application struct {
|
|
||||||
*flagGroup
|
|
||||||
*argGroup
|
|
||||||
*cmdGroup
|
|
||||||
initialized bool
|
|
||||||
Name string
|
|
||||||
Help string
|
|
||||||
author string
|
|
||||||
version string
|
|
||||||
writer io.Writer // Destination for usage and errors.
|
|
||||||
usageTemplate string
|
|
||||||
action Action
|
|
||||||
preAction Action
|
|
||||||
validator ApplicationValidator
|
|
||||||
terminate func(status int) // See Terminate()
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new Kingpin application instance.
|
|
||||||
func New(name, help string) *Application {
|
|
||||||
a := &Application{
|
|
||||||
flagGroup: newFlagGroup(),
|
|
||||||
argGroup: newArgGroup(),
|
|
||||||
Name: name,
|
|
||||||
Help: help,
|
|
||||||
writer: os.Stderr,
|
|
||||||
usageTemplate: DefaultUsageTemplate,
|
|
||||||
terminate: os.Exit,
|
|
||||||
}
|
|
||||||
a.cmdGroup = newCmdGroup(a)
|
|
||||||
a.Flag("help", "Show help (also see --help-long and --help-man).").Bool()
|
|
||||||
a.Flag("help-long", "Generate long help.").Hidden().PreAction(a.generateLongHelp).Bool()
|
|
||||||
a.Flag("help-man", "Generate a man page.").Hidden().PreAction(a.generateManPage).Bool()
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Application) generateLongHelp(c *ParseContext) error {
|
|
||||||
a.Writer(os.Stdout)
|
|
||||||
if err := a.UsageForContextWithTemplate(c, 2, LongHelpTemplate); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
a.terminate(0)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Application) generateManPage(c *ParseContext) error {
|
|
||||||
a.Writer(os.Stdout)
|
|
||||||
if err := a.UsageForContextWithTemplate(c, 2, ManPageTemplate); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
a.terminate(0)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Terminate specifies the termination handler. Defaults to os.Exit(status).
|
|
||||||
// If nil is passed, a no-op function will be used.
|
|
||||||
func (a *Application) Terminate(terminate func(int)) *Application {
|
|
||||||
if terminate == nil {
|
|
||||||
terminate = func(int) {}
|
|
||||||
}
|
|
||||||
a.terminate = terminate
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
// Specify the writer to use for usage and errors. Defaults to os.Stderr.
|
|
||||||
func (a *Application) Writer(w io.Writer) *Application {
|
|
||||||
a.writer = w
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
// UsageTemplate specifies the text template to use when displaying usage
|
|
||||||
// information. The default is UsageTemplate.
|
|
||||||
func (a *Application) UsageTemplate(template string) *Application {
|
|
||||||
a.usageTemplate = template
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate sets a validation function to run when parsing.
|
|
||||||
func (a *Application) Validate(validator ApplicationValidator) *Application {
|
|
||||||
a.validator = validator
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseContext parses the given command line and returns the fully populated
|
|
||||||
// ParseContext.
|
|
||||||
func (a *Application) ParseContext(args []string) (*ParseContext, error) {
|
|
||||||
if err := a.init(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
context := tokenize(args)
|
|
||||||
_, err := parse(context, a)
|
|
||||||
return context, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse parses command-line arguments. It returns the selected command and an
|
|
||||||
// error. The selected command will be a space separated subcommand, if
|
|
||||||
// subcommands have been configured.
|
|
||||||
//
|
|
||||||
// This will populate all flag and argument values, call all callbacks, and so
|
|
||||||
// on.
|
|
||||||
func (a *Application) Parse(args []string) (command string, err error) {
|
|
||||||
context, err := a.ParseContext(args)
|
|
||||||
if err != nil {
|
|
||||||
if a.hasHelp(args) {
|
|
||||||
a.writeUsage(context, err)
|
|
||||||
}
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
a.maybeHelp(context)
|
|
||||||
if !context.EOL() {
|
|
||||||
return "", fmt.Errorf("unexpected argument '%s'", context.Peek())
|
|
||||||
}
|
|
||||||
command, err = a.execute(context)
|
|
||||||
if err == ErrCommandNotSpecified {
|
|
||||||
a.writeUsage(context, nil)
|
|
||||||
}
|
|
||||||
return command, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Application) writeUsage(context *ParseContext, err error) {
|
|
||||||
if err != nil {
|
|
||||||
a.Errorf("%s", err)
|
|
||||||
}
|
|
||||||
if err := a.UsageForContext(context); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
a.terminate(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Application) hasHelp(args []string) bool {
|
|
||||||
for _, arg := range args {
|
|
||||||
if arg == "--help" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Application) maybeHelp(context *ParseContext) {
|
|
||||||
for _, element := range context.Elements {
|
|
||||||
if flag, ok := element.Clause.(*FlagClause); ok && flag.name == "help" {
|
|
||||||
a.writeUsage(context, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// findCommandFromArgs finds a command (if any) from the given command line arguments.
|
|
||||||
func (a *Application) findCommandFromArgs(args []string) (command string, err error) {
|
|
||||||
if err := a.init(); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
context := tokenize(args)
|
|
||||||
if err := a.parse(context); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return a.findCommandFromContext(context), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// findCommandFromContext finds a command (if any) from a parsed context.
|
|
||||||
func (a *Application) findCommandFromContext(context *ParseContext) string {
|
|
||||||
commands := []string{}
|
|
||||||
for _, element := range context.Elements {
|
|
||||||
if c, ok := element.Clause.(*CmdClause); ok {
|
|
||||||
commands = append(commands, c.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return strings.Join(commands, " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Version adds a --version flag for displaying the application version.
|
|
||||||
func (a *Application) Version(version string) *Application {
|
|
||||||
a.version = version
|
|
||||||
a.Flag("version", "Show application version.").Action(func(*ParseContext) error {
|
|
||||||
fmt.Println(version)
|
|
||||||
a.terminate(0)
|
|
||||||
return nil
|
|
||||||
}).Bool()
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Application) Author(author string) *Application {
|
|
||||||
a.author = author
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
// Action callback to call when all values are populated and parsing is
|
|
||||||
// complete, but before any command, flag or argument actions.
|
|
||||||
//
|
|
||||||
// All Action() callbacks are called in the order they are encountered on the
|
|
||||||
// command line.
|
|
||||||
func (a *Application) Action(action Action) *Application {
|
|
||||||
a.action = action
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
// Action called after parsing completes but before validation and execution.
|
|
||||||
func (a *Application) PreAction(action Action) *Application {
|
|
||||||
a.preAction = action
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command adds a new top-level command.
|
|
||||||
func (a *Application) Command(name, help string) *CmdClause {
|
|
||||||
return a.addCommand(name, help)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Application) init() error {
|
|
||||||
if a.initialized {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if a.cmdGroup.have() && a.argGroup.have() {
|
|
||||||
return fmt.Errorf("can't mix top-level Arg()s with Command()s")
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have subcommands, add a help command at the top-level.
|
|
||||||
if a.cmdGroup.have() {
|
|
||||||
var command []string
|
|
||||||
help := a.Command("help", "Show help.").Action(func(c *ParseContext) error {
|
|
||||||
a.Usage(command)
|
|
||||||
a.terminate(0)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
help.Arg("command", "Show help on command.").StringsVar(&command)
|
|
||||||
// Make help first command.
|
|
||||||
l := len(a.commandOrder)
|
|
||||||
a.commandOrder = append(a.commandOrder[l-1:l], a.commandOrder[:l-1]...)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := a.flagGroup.init(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := a.cmdGroup.init(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := a.argGroup.init(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, cmd := range a.commands {
|
|
||||||
if err := cmd.init(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
flagGroups := []*flagGroup{a.flagGroup}
|
|
||||||
for _, cmd := range a.commandOrder {
|
|
||||||
if err := checkDuplicateFlags(cmd, flagGroups); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
a.initialized = true
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recursively check commands for duplicate flags.
|
|
||||||
func checkDuplicateFlags(current *CmdClause, flagGroups []*flagGroup) error {
|
|
||||||
// Check for duplicates.
|
|
||||||
for _, flags := range flagGroups {
|
|
||||||
for _, flag := range current.flagOrder {
|
|
||||||
if flag.shorthand != 0 {
|
|
||||||
if _, ok := flags.short[string(flag.shorthand)]; ok {
|
|
||||||
return fmt.Errorf("duplicate short flag -%c", flag.shorthand)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if _, ok := flags.long[flag.name]; ok {
|
|
||||||
return fmt.Errorf("duplicate long flag --%s", flag.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
flagGroups = append(flagGroups, current.flagGroup)
|
|
||||||
// Check subcommands.
|
|
||||||
for _, subcmd := range current.commandOrder {
|
|
||||||
if err := checkDuplicateFlags(subcmd, flagGroups); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Application) execute(context *ParseContext) (string, error) {
|
|
||||||
var err error
|
|
||||||
selected := []string{}
|
|
||||||
|
|
||||||
if err = a.setDefaults(context); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
selected, err = a.setValues(context)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = a.applyPreActions(context); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = a.validateRequired(context); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = a.applyValidators(context); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = a.applyActions(context); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
command := strings.Join(selected, " ")
|
|
||||||
if command == "" && a.cmdGroup.have() {
|
|
||||||
return "", ErrCommandNotSpecified
|
|
||||||
}
|
|
||||||
return command, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Application) setDefaults(context *ParseContext) error {
|
|
||||||
flagElements := map[string]*ParseElement{}
|
|
||||||
for _, element := range context.Elements {
|
|
||||||
if flag, ok := element.Clause.(*FlagClause); ok {
|
|
||||||
flagElements[flag.name] = element
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
argElements := map[string]*ParseElement{}
|
|
||||||
for _, element := range context.Elements {
|
|
||||||
if arg, ok := element.Clause.(*ArgClause); ok {
|
|
||||||
argElements[arg.name] = element
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check required flags and set defaults.
|
|
||||||
for _, flag := range context.flags.long {
|
|
||||||
if flagElements[flag.name] == nil {
|
|
||||||
// Set defaults, if any.
|
|
||||||
if flag.defaultValue != "" {
|
|
||||||
if err := flag.value.Set(flag.defaultValue); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, arg := range context.arguments.args {
|
|
||||||
if argElements[arg.name] == nil {
|
|
||||||
// Set defaults, if any.
|
|
||||||
if arg.defaultValue != "" {
|
|
||||||
if err := arg.value.Set(arg.defaultValue); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Application) validateRequired(context *ParseContext) error {
|
|
||||||
flagElements := map[string]*ParseElement{}
|
|
||||||
for _, element := range context.Elements {
|
|
||||||
if flag, ok := element.Clause.(*FlagClause); ok {
|
|
||||||
flagElements[flag.name] = element
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
argElements := map[string]*ParseElement{}
|
|
||||||
for _, element := range context.Elements {
|
|
||||||
if arg, ok := element.Clause.(*ArgClause); ok {
|
|
||||||
argElements[arg.name] = element
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check required flags and set defaults.
|
|
||||||
for _, flag := range context.flags.long {
|
|
||||||
if flagElements[flag.name] == nil {
|
|
||||||
// Check required flags were provided.
|
|
||||||
if flag.needsValue() {
|
|
||||||
return fmt.Errorf("required flag --%s not provided", flag.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, arg := range context.arguments.args {
|
|
||||||
if argElements[arg.name] == nil {
|
|
||||||
if arg.required {
|
|
||||||
return fmt.Errorf("required argument '%s' not provided", arg.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Application) setValues(context *ParseContext) (selected []string, err error) {
|
|
||||||
// Set all arg and flag values.
|
|
||||||
var lastCmd *CmdClause
|
|
||||||
for _, element := range context.Elements {
|
|
||||||
switch clause := element.Clause.(type) {
|
|
||||||
case *FlagClause:
|
|
||||||
if err = clause.value.Set(*element.Value); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
case *ArgClause:
|
|
||||||
if err = clause.value.Set(*element.Value); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
case *CmdClause:
|
|
||||||
if clause.validator != nil {
|
|
||||||
if err = clause.validator(clause); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
selected = append(selected, clause.name)
|
|
||||||
lastCmd = clause
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if lastCmd != nil && len(lastCmd.commands) > 0 {
|
|
||||||
return nil, fmt.Errorf("must select a subcommand of '%s'", lastCmd.FullCommand())
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Application) applyValidators(context *ParseContext) (err error) {
|
|
||||||
// Call command validation functions.
|
|
||||||
for _, element := range context.Elements {
|
|
||||||
if cmd, ok := element.Clause.(*CmdClause); ok && cmd.validator != nil {
|
|
||||||
if err = cmd.validator(cmd); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if a.validator != nil {
|
|
||||||
err = a.validator(a)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Application) applyPreActions(context *ParseContext) error {
|
|
||||||
if a.preAction != nil {
|
|
||||||
if err := a.preAction(context); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Dispatch to actions.
|
|
||||||
for _, element := range context.Elements {
|
|
||||||
switch clause := element.Clause.(type) {
|
|
||||||
case *ArgClause:
|
|
||||||
if clause.preAction != nil {
|
|
||||||
if err := clause.preAction(context); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case *CmdClause:
|
|
||||||
if clause.preAction != nil {
|
|
||||||
if err := clause.preAction(context); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case *FlagClause:
|
|
||||||
if clause.preAction != nil {
|
|
||||||
if err := clause.preAction(context); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Application) applyActions(context *ParseContext) error {
|
|
||||||
if a.action != nil {
|
|
||||||
if err := a.action(context); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Dispatch to actions.
|
|
||||||
for _, element := range context.Elements {
|
|
||||||
switch clause := element.Clause.(type) {
|
|
||||||
case *ArgClause:
|
|
||||||
if clause.action != nil {
|
|
||||||
if err := clause.action(context); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case *CmdClause:
|
|
||||||
if clause.action != nil {
|
|
||||||
if err := clause.action(context); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case *FlagClause:
|
|
||||||
if clause.action != nil {
|
|
||||||
if err := clause.action(context); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Errorf prints an error message to w in the format "<appname>: error: <message>".
|
|
||||||
func (a *Application) Errorf(format string, args ...interface{}) {
|
|
||||||
fmt.Fprintf(a.writer, a.Name+": error: "+format+"\n", args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fatalf writes a formatted error to w then terminates with exit status 1.
|
|
||||||
func (a *Application) Fatalf(format string, args ...interface{}) {
|
|
||||||
a.Errorf(format, args...)
|
|
||||||
a.terminate(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FatalUsage prints an error message followed by usage information, then
|
|
||||||
// exits with a non-zero status.
|
|
||||||
func (a *Application) FatalUsage(format string, args ...interface{}) {
|
|
||||||
a.Errorf(format, args...)
|
|
||||||
a.Usage([]string{})
|
|
||||||
a.terminate(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FatalUsageContext writes a printf formatted error message to w, then usage
|
|
||||||
// information for the given ParseContext, before exiting.
|
|
||||||
func (a *Application) FatalUsageContext(context *ParseContext, format string, args ...interface{}) {
|
|
||||||
a.Errorf(format, args...)
|
|
||||||
if err := a.UsageForContext(context); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
a.terminate(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FatalIfError prints an error and exits if err is not nil. The error is printed
|
|
||||||
// with the given formatted string, if any.
|
|
||||||
func (a *Application) FatalIfError(err error, format string, args ...interface{}) {
|
|
||||||
if err != nil {
|
|
||||||
prefix := ""
|
|
||||||
if format != "" {
|
|
||||||
prefix = fmt.Sprintf(format, args...) + ": "
|
|
||||||
}
|
|
||||||
a.Errorf(prefix+"%s", err)
|
|
||||||
a.terminate(1)
|
|
||||||
}
|
|
||||||
}
|
|
106
vendor/gopkg.in/alecthomas/kingpin.v2/args.go
generated
vendored
106
vendor/gopkg.in/alecthomas/kingpin.v2/args.go
generated
vendored
@ -1,106 +0,0 @@
|
|||||||
package kingpin
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
type argGroup struct {
|
|
||||||
args []*ArgClause
|
|
||||||
}
|
|
||||||
|
|
||||||
func newArgGroup() *argGroup {
|
|
||||||
return &argGroup{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *argGroup) have() bool {
|
|
||||||
return len(a.args) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *argGroup) Arg(name, help string) *ArgClause {
|
|
||||||
arg := newArg(name, help)
|
|
||||||
a.args = append(a.args, arg)
|
|
||||||
return arg
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *argGroup) init() error {
|
|
||||||
required := 0
|
|
||||||
seen := map[string]struct{}{}
|
|
||||||
previousArgMustBeLast := false
|
|
||||||
for i, arg := range a.args {
|
|
||||||
if previousArgMustBeLast {
|
|
||||||
return fmt.Errorf("Args() can't be followed by another argument '%s'", arg.name)
|
|
||||||
}
|
|
||||||
if arg.consumesRemainder() {
|
|
||||||
previousArgMustBeLast = true
|
|
||||||
}
|
|
||||||
if _, ok := seen[arg.name]; ok {
|
|
||||||
return fmt.Errorf("duplicate argument '%s'", arg.name)
|
|
||||||
}
|
|
||||||
seen[arg.name] = struct{}{}
|
|
||||||
if arg.required && required != i {
|
|
||||||
return fmt.Errorf("required arguments found after non-required")
|
|
||||||
}
|
|
||||||
if arg.required {
|
|
||||||
required++
|
|
||||||
}
|
|
||||||
if err := arg.init(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type ArgClause struct {
|
|
||||||
parserMixin
|
|
||||||
name string
|
|
||||||
help string
|
|
||||||
defaultValue string
|
|
||||||
required bool
|
|
||||||
action Action
|
|
||||||
preAction Action
|
|
||||||
}
|
|
||||||
|
|
||||||
func newArg(name, help string) *ArgClause {
|
|
||||||
a := &ArgClause{
|
|
||||||
name: name,
|
|
||||||
help: help,
|
|
||||||
}
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ArgClause) consumesRemainder() bool {
|
|
||||||
if r, ok := a.value.(remainderArg); ok {
|
|
||||||
return r.IsCumulative()
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Required arguments must be input by the user. They can not have a Default() value provided.
|
|
||||||
func (a *ArgClause) Required() *ArgClause {
|
|
||||||
a.required = true
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default value for this argument. It *must* be parseable by the value of the argument.
|
|
||||||
func (a *ArgClause) Default(value string) *ArgClause {
|
|
||||||
a.defaultValue = value
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ArgClause) Action(action Action) *ArgClause {
|
|
||||||
a.action = action
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ArgClause) PreAction(action Action) *ArgClause {
|
|
||||||
a.preAction = action
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ArgClause) init() error {
|
|
||||||
if a.required && a.defaultValue != "" {
|
|
||||||
return fmt.Errorf("required argument '%s' with unusable default value", a.name)
|
|
||||||
}
|
|
||||||
if a.value == nil {
|
|
||||||
return fmt.Errorf("no parser defined for arg '%s'", a.name)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
129
vendor/gopkg.in/alecthomas/kingpin.v2/cmd.go
generated
vendored
129
vendor/gopkg.in/alecthomas/kingpin.v2/cmd.go
generated
vendored
@ -1,129 +0,0 @@
|
|||||||
package kingpin
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type cmdGroup struct {
|
|
||||||
app *Application
|
|
||||||
parent *CmdClause
|
|
||||||
commands map[string]*CmdClause
|
|
||||||
commandOrder []*CmdClause
|
|
||||||
}
|
|
||||||
|
|
||||||
func newCmdGroup(app *Application) *cmdGroup {
|
|
||||||
return &cmdGroup{
|
|
||||||
app: app,
|
|
||||||
commands: make(map[string]*CmdClause),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cmdGroup) flattenedCommands() (out []*CmdClause) {
|
|
||||||
for _, cmd := range c.commandOrder {
|
|
||||||
if len(cmd.commands) == 0 {
|
|
||||||
out = append(out, cmd)
|
|
||||||
}
|
|
||||||
out = append(out, cmd.flattenedCommands()...)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cmdGroup) addCommand(name, help string) *CmdClause {
|
|
||||||
cmd := newCommand(c.app, name, help)
|
|
||||||
c.commands[name] = cmd
|
|
||||||
c.commandOrder = append(c.commandOrder, cmd)
|
|
||||||
return cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cmdGroup) init() error {
|
|
||||||
seen := map[string]bool{}
|
|
||||||
for _, cmd := range c.commandOrder {
|
|
||||||
if seen[cmd.name] {
|
|
||||||
return fmt.Errorf("duplicate command '%s'", cmd.name)
|
|
||||||
}
|
|
||||||
seen[cmd.name] = true
|
|
||||||
if err := cmd.init(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func (c *cmdGroup) have() bool {
|
|
||||||
return len(c.commands) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type CmdClauseValidator func(*CmdClause) error
|
|
||||||
|
|
||||||
// A CmdClause is a single top-level command. It encapsulates a set of flags
|
|
||||||
// and either subcommands or positional arguments.
|
|
||||||
type CmdClause struct {
|
|
||||||
*flagGroup
|
|
||||||
*argGroup
|
|
||||||
*cmdGroup
|
|
||||||
app *Application
|
|
||||||
name string
|
|
||||||
help string
|
|
||||||
action Action
|
|
||||||
preAction Action
|
|
||||||
validator CmdClauseValidator
|
|
||||||
}
|
|
||||||
|
|
||||||
func newCommand(app *Application, name, help string) *CmdClause {
|
|
||||||
c := &CmdClause{
|
|
||||||
flagGroup: newFlagGroup(),
|
|
||||||
argGroup: newArgGroup(),
|
|
||||||
cmdGroup: newCmdGroup(app),
|
|
||||||
app: app,
|
|
||||||
name: name,
|
|
||||||
help: help,
|
|
||||||
}
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate sets a validation function to run when parsing.
|
|
||||||
func (c *CmdClause) Validate(validator CmdClauseValidator) *CmdClause {
|
|
||||||
c.validator = validator
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CmdClause) FullCommand() string {
|
|
||||||
out := []string{c.name}
|
|
||||||
for p := c.parent; p != nil; p = p.parent {
|
|
||||||
out = append([]string{p.name}, out...)
|
|
||||||
}
|
|
||||||
return strings.Join(out, " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command adds a new sub-command.
|
|
||||||
func (c *CmdClause) Command(name, help string) *CmdClause {
|
|
||||||
cmd := c.addCommand(name, help)
|
|
||||||
cmd.parent = c
|
|
||||||
return cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CmdClause) Action(action Action) *CmdClause {
|
|
||||||
c.action = action
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CmdClause) PreAction(action Action) *CmdClause {
|
|
||||||
c.preAction = action
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CmdClause) init() error {
|
|
||||||
if err := c.flagGroup.init(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if c.argGroup.have() && c.cmdGroup.have() {
|
|
||||||
return fmt.Errorf("can't mix Arg()s with Command()s")
|
|
||||||
}
|
|
||||||
if err := c.argGroup.init(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := c.cmdGroup.init(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
68
vendor/gopkg.in/alecthomas/kingpin.v2/doc.go
generated
vendored
68
vendor/gopkg.in/alecthomas/kingpin.v2/doc.go
generated
vendored
@ -1,68 +0,0 @@
|
|||||||
// Package kingpin provides command line interfaces like this:
|
|
||||||
//
|
|
||||||
// $ chat
|
|
||||||
// usage: chat [<flags>] <command> [<flags>] [<args> ...]
|
|
||||||
//
|
|
||||||
// Flags:
|
|
||||||
// --debug enable debug mode
|
|
||||||
// --help Show help.
|
|
||||||
// --server=127.0.0.1 server address
|
|
||||||
//
|
|
||||||
// Commands:
|
|
||||||
// help <command>
|
|
||||||
// Show help for a command.
|
|
||||||
//
|
|
||||||
// post [<flags>] <channel>
|
|
||||||
// Post a message to a channel.
|
|
||||||
//
|
|
||||||
// register <nick> <name>
|
|
||||||
// Register a new user.
|
|
||||||
//
|
|
||||||
// $ chat help post
|
|
||||||
// usage: chat [<flags>] post [<flags>] <channel> [<text>]
|
|
||||||
//
|
|
||||||
// Post a message to a channel.
|
|
||||||
//
|
|
||||||
// Flags:
|
|
||||||
// --image=IMAGE image to post
|
|
||||||
//
|
|
||||||
// Args:
|
|
||||||
// <channel> channel to post to
|
|
||||||
// [<text>] text to post
|
|
||||||
// $ chat post --image=~/Downloads/owls.jpg pics
|
|
||||||
//
|
|
||||||
// From code like this:
|
|
||||||
//
|
|
||||||
// package main
|
|
||||||
//
|
|
||||||
// import "gopkg.in/alecthomas/kingpin.v1"
|
|
||||||
//
|
|
||||||
// var (
|
|
||||||
// debug = kingpin.Flag("debug", "enable debug mode").Default("false").Bool()
|
|
||||||
// serverIP = kingpin.Flag("server", "server address").Default("127.0.0.1").IP()
|
|
||||||
//
|
|
||||||
// register = kingpin.Command("register", "Register a new user.")
|
|
||||||
// registerNick = register.Arg("nick", "nickname for user").Required().String()
|
|
||||||
// registerName = register.Arg("name", "name of user").Required().String()
|
|
||||||
//
|
|
||||||
// post = kingpin.Command("post", "Post a message to a channel.")
|
|
||||||
// postImage = post.Flag("image", "image to post").ExistingFile()
|
|
||||||
// postChannel = post.Arg("channel", "channel to post to").Required().String()
|
|
||||||
// postText = post.Arg("text", "text to post").String()
|
|
||||||
// )
|
|
||||||
//
|
|
||||||
// func main() {
|
|
||||||
// switch kingpin.Parse() {
|
|
||||||
// // Register user
|
|
||||||
// case "register":
|
|
||||||
// println(*registerNick)
|
|
||||||
//
|
|
||||||
// // Post message
|
|
||||||
// case "post":
|
|
||||||
// if *postImage != nil {
|
|
||||||
// }
|
|
||||||
// if *postText != "" {
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
package kingpin
|
|
20
vendor/gopkg.in/alecthomas/kingpin.v2/examples/chat1/main.go
generated
vendored
20
vendor/gopkg.in/alecthomas/kingpin.v2/examples/chat1/main.go
generated
vendored
@ -1,20 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
debug = kingpin.Flag("debug", "Enable debug mode.").Bool()
|
|
||||||
timeout = kingpin.Flag("timeout", "Timeout waiting for ping.").Default("5s").OverrideDefaultFromEnvar("PING_TIMEOUT").Short('t').Duration()
|
|
||||||
ip = kingpin.Arg("ip", "IP address to ping.").Required().IP()
|
|
||||||
count = kingpin.Arg("count", "Number of packets to send").Int()
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
kingpin.Version("0.0.1")
|
|
||||||
kingpin.Parse()
|
|
||||||
fmt.Printf("Would ping: %s with timeout %s and count %d", *ip, *timeout, *count)
|
|
||||||
}
|
|
38
vendor/gopkg.in/alecthomas/kingpin.v2/examples/chat2/main.go
generated
vendored
38
vendor/gopkg.in/alecthomas/kingpin.v2/examples/chat2/main.go
generated
vendored
@ -1,38 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
app = kingpin.New("chat", "A command-line chat application.")
|
|
||||||
debug = app.Flag("debug", "Enable debug mode.").Bool()
|
|
||||||
serverIP = app.Flag("server", "Server address.").Default("127.0.0.1").IP()
|
|
||||||
|
|
||||||
register = app.Command("register", "Register a new user.")
|
|
||||||
registerNick = register.Arg("nick", "Nickname for user.").Required().String()
|
|
||||||
registerName = register.Arg("name", "Name of user.").Required().String()
|
|
||||||
|
|
||||||
post = app.Command("post", "Post a message to a channel.")
|
|
||||||
postImage = post.Flag("image", "Image to post.").File()
|
|
||||||
postChannel = post.Arg("channel", "Channel to post to.").Required().String()
|
|
||||||
postText = post.Arg("text", "Text to post.").Strings()
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
switch kingpin.MustParse(app.Parse(os.Args[1:])) {
|
|
||||||
// Register user
|
|
||||||
case register.FullCommand():
|
|
||||||
println(*registerNick)
|
|
||||||
|
|
||||||
// Post message
|
|
||||||
case post.FullCommand():
|
|
||||||
if *postImage != nil {
|
|
||||||
}
|
|
||||||
text := strings.Join(*postText, " ")
|
|
||||||
println("Post:", text)
|
|
||||||
}
|
|
||||||
}
|
|
105
vendor/gopkg.in/alecthomas/kingpin.v2/examples/curl/main.go
generated
vendored
105
vendor/gopkg.in/alecthomas/kingpin.v2/examples/curl/main.go
generated
vendored
@ -1,105 +0,0 @@
|
|||||||
// A curl-like HTTP command-line client.
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
timeout = kingpin.Flag("timeout", "Set connection timeout.").Short('t').Default("5s").Duration()
|
|
||||||
headers = HTTPHeader(kingpin.Flag("headers", "Add HTTP headers to the request.").Short('H').PlaceHolder("HEADER=VALUE"))
|
|
||||||
|
|
||||||
get = kingpin.Command("get", "GET a resource.")
|
|
||||||
getFlag = get.Flag("test", "Test flag").Bool()
|
|
||||||
getURL = get.Command("url", "Retrieve a URL.")
|
|
||||||
getURLURL = getURL.Arg("url", "URL to GET.").Required().URL()
|
|
||||||
getFile = get.Command("file", "Retrieve a file.")
|
|
||||||
getFileFile = getFile.Arg("file", "File to retrieve.").Required().ExistingFile()
|
|
||||||
|
|
||||||
post = kingpin.Command("post", "POST a resource.")
|
|
||||||
postData = post.Flag("data", "Key-value data to POST").Short('d').PlaceHolder("KEY:VALUE").StringMap()
|
|
||||||
postBinaryFile = post.Flag("data-binary", "File with binary data to POST.").File()
|
|
||||||
postURL = post.Arg("url", "URL to POST to.").Required().URL()
|
|
||||||
)
|
|
||||||
|
|
||||||
type HTTPHeaderValue http.Header
|
|
||||||
|
|
||||||
func (h HTTPHeaderValue) Set(value string) error {
|
|
||||||
parts := strings.SplitN(value, "=", 2)
|
|
||||||
if len(parts) != 2 {
|
|
||||||
return fmt.Errorf("expected HEADER=VALUE got '%s'", value)
|
|
||||||
}
|
|
||||||
(http.Header)(h).Add(parts[0], parts[1])
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h HTTPHeaderValue) String() string {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func HTTPHeader(s kingpin.Settings) (target *http.Header) {
|
|
||||||
target = &http.Header{}
|
|
||||||
s.SetValue((*HTTPHeaderValue)(target))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func applyRequest(req *http.Request) error {
|
|
||||||
req.Header = *headers
|
|
||||||
resp, err := http.DefaultClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
if resp.StatusCode < 200 || resp.StatusCode > 299 {
|
|
||||||
return fmt.Errorf("HTTP request failed: %s", resp.Status)
|
|
||||||
}
|
|
||||||
_, err = io.Copy(os.Stdout, resp.Body)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func apply(method string, url string) error {
|
|
||||||
req, err := http.NewRequest(method, url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return applyRequest(req)
|
|
||||||
}
|
|
||||||
|
|
||||||
func applyPOST() error {
|
|
||||||
req, err := http.NewRequest("POST", (*postURL).String(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if len(*postData) > 0 {
|
|
||||||
for key, value := range *postData {
|
|
||||||
req.Form.Set(key, value)
|
|
||||||
}
|
|
||||||
} else if postBinaryFile != nil {
|
|
||||||
if headers.Get("Content-Type") != "" {
|
|
||||||
headers.Set("Content-Type", "application/octet-stream")
|
|
||||||
}
|
|
||||||
req.Body = *postBinaryFile
|
|
||||||
} else {
|
|
||||||
return errors.New("--data or --data-binary must be provided to POST")
|
|
||||||
}
|
|
||||||
return applyRequest(req)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
kingpin.UsageTemplate(kingpin.CompactUsageTemplate).Version("1.0").Author("Alec Thomas")
|
|
||||||
kingpin.CommandLine.Help = "An example implementation of curl."
|
|
||||||
switch kingpin.Parse() {
|
|
||||||
case "get url":
|
|
||||||
kingpin.FatalIfError(apply("GET", (*getURLURL).String()), "GET failed")
|
|
||||||
|
|
||||||
case "post":
|
|
||||||
kingpin.FatalIfError(applyPOST(), "POST failed")
|
|
||||||
}
|
|
||||||
}
|
|
30
vendor/gopkg.in/alecthomas/kingpin.v2/examples/modular/main.go
generated
vendored
30
vendor/gopkg.in/alecthomas/kingpin.v2/examples/modular/main.go
generated
vendored
@ -1,30 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Context for "ls" command
|
|
||||||
type LsCommand struct {
|
|
||||||
All bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *LsCommand) run(c *kingpin.ParseContext) error {
|
|
||||||
fmt.Printf("all=%v\n", l.All)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func configureLsCommand(app *kingpin.Application) {
|
|
||||||
c := &LsCommand{}
|
|
||||||
ls := app.Command("ls", "List files.").Action(c.run)
|
|
||||||
ls.Flag("all", "List all files.").Short('a').BoolVar(&c.All)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
app := kingpin.New("modular", "My modular application.")
|
|
||||||
configureLsCommand(app)
|
|
||||||
kingpin.MustParse(app.Parse(os.Args[1:]))
|
|
||||||
}
|
|
20
vendor/gopkg.in/alecthomas/kingpin.v2/examples/ping/main.go
generated
vendored
20
vendor/gopkg.in/alecthomas/kingpin.v2/examples/ping/main.go
generated
vendored
@ -1,20 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
debug = kingpin.Flag("debug", "Enable debug mode.").Bool()
|
|
||||||
timeout = kingpin.Flag("timeout", "Timeout waiting for ping.").OverrideDefaultFromEnvar("PING_TIMEOUT").Required().Short('t').Duration()
|
|
||||||
ip = kingpin.Arg("ip", "IP address to ping.").Required().IP()
|
|
||||||
count = kingpin.Arg("count", "Number of packets to send").Int()
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
kingpin.Version("0.0.1")
|
|
||||||
kingpin.Parse()
|
|
||||||
fmt.Printf("Would ping: %s with timeout %s and count %d", *ip, *timeout, *count)
|
|
||||||
}
|
|
235
vendor/gopkg.in/alecthomas/kingpin.v2/flags.go
generated
vendored
235
vendor/gopkg.in/alecthomas/kingpin.v2/flags.go
generated
vendored
@ -1,235 +0,0 @@
|
|||||||
package kingpin
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type flagGroup struct {
|
|
||||||
short map[string]*FlagClause
|
|
||||||
long map[string]*FlagClause
|
|
||||||
flagOrder []*FlagClause
|
|
||||||
}
|
|
||||||
|
|
||||||
func newFlagGroup() *flagGroup {
|
|
||||||
return &flagGroup{
|
|
||||||
short: make(map[string]*FlagClause),
|
|
||||||
long: make(map[string]*FlagClause),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *flagGroup) merge(o *flagGroup) {
|
|
||||||
for _, flag := range o.flagOrder {
|
|
||||||
if flag.shorthand != 0 {
|
|
||||||
f.short[string(flag.shorthand)] = flag
|
|
||||||
}
|
|
||||||
f.long[flag.name] = flag
|
|
||||||
f.flagOrder = append(f.flagOrder, flag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flag defines a new flag with the given long name and help.
|
|
||||||
func (f *flagGroup) Flag(name, help string) *FlagClause {
|
|
||||||
flag := newFlag(name, help)
|
|
||||||
f.long[name] = flag
|
|
||||||
f.flagOrder = append(f.flagOrder, flag)
|
|
||||||
return flag
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *flagGroup) init() error {
|
|
||||||
for _, flag := range f.long {
|
|
||||||
if err := flag.init(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if flag.shorthand != 0 {
|
|
||||||
f.short[string(flag.shorthand)] = flag
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *flagGroup) parse(context *ParseContext) error {
|
|
||||||
var token *Token
|
|
||||||
|
|
||||||
loop:
|
|
||||||
for {
|
|
||||||
token = context.Peek()
|
|
||||||
switch token.Type {
|
|
||||||
case TokenEOL:
|
|
||||||
break loop
|
|
||||||
|
|
||||||
case TokenLong, TokenShort:
|
|
||||||
flagToken := token
|
|
||||||
defaultValue := ""
|
|
||||||
var flag *FlagClause
|
|
||||||
var ok bool
|
|
||||||
invert := false
|
|
||||||
|
|
||||||
name := token.Value
|
|
||||||
if token.Type == TokenLong {
|
|
||||||
if strings.HasPrefix(name, "no-") {
|
|
||||||
name = name[3:]
|
|
||||||
invert = true
|
|
||||||
}
|
|
||||||
flag, ok = f.long[name]
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("unknown long flag '%s'", flagToken)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
flag, ok = f.short[name]
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("unknown short flag '%s'", flagToken)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context.Next()
|
|
||||||
|
|
||||||
fb, ok := flag.value.(boolFlag)
|
|
||||||
if ok && fb.IsBoolFlag() {
|
|
||||||
if invert {
|
|
||||||
defaultValue = "false"
|
|
||||||
} else {
|
|
||||||
defaultValue = "true"
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if invert {
|
|
||||||
return fmt.Errorf("unknown long flag '%s'", flagToken)
|
|
||||||
}
|
|
||||||
token = context.Peek()
|
|
||||||
if token.Type != TokenArg {
|
|
||||||
return fmt.Errorf("expected argument for flag '%s'", flagToken)
|
|
||||||
}
|
|
||||||
context.Next()
|
|
||||||
defaultValue = token.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
context.matchedFlag(flag, defaultValue)
|
|
||||||
|
|
||||||
default:
|
|
||||||
break loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *flagGroup) visibleFlags() int {
|
|
||||||
count := 0
|
|
||||||
for _, flag := range f.long {
|
|
||||||
if !flag.hidden {
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count
|
|
||||||
}
|
|
||||||
|
|
||||||
// FlagClause is a fluid interface used to build flags.
|
|
||||||
type FlagClause struct {
|
|
||||||
parserMixin
|
|
||||||
name string
|
|
||||||
shorthand byte
|
|
||||||
help string
|
|
||||||
envar string
|
|
||||||
defaultValue string
|
|
||||||
placeholder string
|
|
||||||
action Action
|
|
||||||
preAction Action
|
|
||||||
hidden bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func newFlag(name, help string) *FlagClause {
|
|
||||||
f := &FlagClause{
|
|
||||||
name: name,
|
|
||||||
help: help,
|
|
||||||
}
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FlagClause) needsValue() bool {
|
|
||||||
return f.required && f.defaultValue == ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FlagClause) formatPlaceHolder() string {
|
|
||||||
if f.placeholder != "" {
|
|
||||||
return f.placeholder
|
|
||||||
}
|
|
||||||
if f.defaultValue != "" {
|
|
||||||
if _, ok := f.value.(*stringValue); ok {
|
|
||||||
return fmt.Sprintf("%q", f.defaultValue)
|
|
||||||
}
|
|
||||||
return f.defaultValue
|
|
||||||
}
|
|
||||||
return strings.ToUpper(f.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FlagClause) init() error {
|
|
||||||
if f.required && f.defaultValue != "" {
|
|
||||||
return fmt.Errorf("required flag '--%s' with default value that will never be used", f.name)
|
|
||||||
}
|
|
||||||
if f.value == nil {
|
|
||||||
return fmt.Errorf("no type defined for --%s (eg. .String())", f.name)
|
|
||||||
}
|
|
||||||
if f.envar != "" {
|
|
||||||
if v := os.Getenv(f.envar); v != "" {
|
|
||||||
f.defaultValue = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dispatch to the given function after the flag is parsed and validated.
|
|
||||||
func (f *FlagClause) Action(action Action) *FlagClause {
|
|
||||||
f.action = action
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FlagClause) PreAction(action Action) *FlagClause {
|
|
||||||
f.preAction = action
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default value for this flag. It *must* be parseable by the value of the flag.
|
|
||||||
func (f *FlagClause) Default(value string) *FlagClause {
|
|
||||||
f.defaultValue = value
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
|
|
||||||
// OverrideDefaultFromEnvar overrides the default value for a flag from an
|
|
||||||
// environment variable, if available.
|
|
||||||
func (f *FlagClause) OverrideDefaultFromEnvar(envar string) *FlagClause {
|
|
||||||
f.envar = envar
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
|
|
||||||
// PlaceHolder sets the place-holder string used for flag values in the help. The
|
|
||||||
// default behaviour is to use the value provided by Default() if provided,
|
|
||||||
// then fall back on the capitalized flag name.
|
|
||||||
func (f *FlagClause) PlaceHolder(placeholder string) *FlagClause {
|
|
||||||
f.placeholder = placeholder
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hidden hides a flag from usage but still allows it to be used.
|
|
||||||
func (f *FlagClause) Hidden() *FlagClause {
|
|
||||||
f.hidden = true
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
|
|
||||||
// Required makes the flag required. You can not provide a Default() value to a Required() flag.
|
|
||||||
func (f *FlagClause) Required() *FlagClause {
|
|
||||||
f.required = true
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
|
|
||||||
// Short sets the short flag name.
|
|
||||||
func (f *FlagClause) Short(name byte) *FlagClause {
|
|
||||||
f.shorthand = name
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bool makes this flag a boolean flag.
|
|
||||||
func (f *FlagClause) Bool() (target *bool) {
|
|
||||||
target = new(bool)
|
|
||||||
f.SetValue(newBoolValue(target))
|
|
||||||
return
|
|
||||||
}
|
|
75
vendor/gopkg.in/alecthomas/kingpin.v2/genrepeated/main.go
generated
vendored
75
vendor/gopkg.in/alecthomas/kingpin.v2/genrepeated/main.go
generated
vendored
@ -1,75 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
tmpl = `package kingpin
|
|
||||||
|
|
||||||
// This file is autogenerated by "go generate .". Do not modify.
|
|
||||||
|
|
||||||
{{range .}}
|
|
||||||
// {{if .Comment}}{{.Comment}}{{else}}{{.|Name}} accumulates {{.Type}} values into a slice.{{end}}
|
|
||||||
func (p *parserMixin) {{.|Name}}() (target *[]{{.Type}}) {
|
|
||||||
target = new([]{{.Type}})
|
|
||||||
p.{{.|Name}}Var(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *parserMixin) {{.|Name}}Var(target *[]{{.Type}}) {
|
|
||||||
p.SetValue(newAccumulator(target, func(v interface{}) Value { return new{{.Name}}Value(v.(*{{.Type}})) }))
|
|
||||||
}
|
|
||||||
|
|
||||||
{{end}}
|
|
||||||
`
|
|
||||||
)
|
|
||||||
|
|
||||||
type Repeated struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Comment string `json:"comment"`
|
|
||||||
Plural string `json:"plural"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func fatalIfError(err error) {
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
r, err := os.Open("repeated.json")
|
|
||||||
fatalIfError(err)
|
|
||||||
defer r.Close()
|
|
||||||
|
|
||||||
v := []Repeated{}
|
|
||||||
err = json.NewDecoder(r).Decode(&v)
|
|
||||||
fatalIfError(err)
|
|
||||||
|
|
||||||
t, err := template.New("genrepeated").Funcs(template.FuncMap{
|
|
||||||
"Lower": strings.ToLower,
|
|
||||||
"Name": func(v *Repeated) string {
|
|
||||||
if v.Plural != "" {
|
|
||||||
return v.Plural
|
|
||||||
}
|
|
||||||
return v.Name + "List"
|
|
||||||
},
|
|
||||||
}).Parse(tmpl)
|
|
||||||
fatalIfError(err)
|
|
||||||
|
|
||||||
w, err := os.Create("repeated.go")
|
|
||||||
fatalIfError(err)
|
|
||||||
defer w.Close()
|
|
||||||
|
|
||||||
err = t.Execute(w, v)
|
|
||||||
fatalIfError(err)
|
|
||||||
|
|
||||||
err = exec.Command("goimports", "-w", "repeated.go").Run()
|
|
||||||
fatalIfError(err)
|
|
||||||
}
|
|
88
vendor/gopkg.in/alecthomas/kingpin.v2/global.go
generated
vendored
88
vendor/gopkg.in/alecthomas/kingpin.v2/global.go
generated
vendored
@ -1,88 +0,0 @@
|
|||||||
package kingpin
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// CommandLine is the default Kingpin parser.
|
|
||||||
CommandLine = New(filepath.Base(os.Args[0]), "")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Command adds a new command to the default parser.
|
|
||||||
func Command(name, help string) *CmdClause {
|
|
||||||
return CommandLine.Command(name, help)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flag adds a new flag to the default parser.
|
|
||||||
func Flag(name, help string) *FlagClause {
|
|
||||||
return CommandLine.Flag(name, help)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Arg adds a new argument to the top-level of the default parser.
|
|
||||||
func Arg(name, help string) *ArgClause {
|
|
||||||
return CommandLine.Arg(name, help)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse and return the selected command. Will call the termination handler if
|
|
||||||
// an error is encountered.
|
|
||||||
func Parse() string {
|
|
||||||
selected := MustParse(CommandLine.Parse(os.Args[1:]))
|
|
||||||
if selected == "" && CommandLine.cmdGroup.have() {
|
|
||||||
Usage()
|
|
||||||
CommandLine.terminate(0)
|
|
||||||
}
|
|
||||||
return selected
|
|
||||||
}
|
|
||||||
|
|
||||||
// Errorf prints an error message to stderr.
|
|
||||||
func Errorf(format string, args ...interface{}) {
|
|
||||||
CommandLine.Errorf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fatalf prints an error message to stderr and exits.
|
|
||||||
func Fatalf(format string, args ...interface{}) {
|
|
||||||
CommandLine.Fatalf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FatalIfError prints an error and exits if err is not nil. The error is printed
|
|
||||||
// with the given prefix.
|
|
||||||
func FatalIfError(err error, format string, args ...interface{}) {
|
|
||||||
CommandLine.FatalIfError(err, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FatalUsage prints an error message followed by usage information, then
|
|
||||||
// exits with a non-zero status.
|
|
||||||
func FatalUsage(format string, args ...interface{}) {
|
|
||||||
CommandLine.FatalUsage(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FatalUsageContext writes a printf formatted error message to stderr, then
|
|
||||||
// usage information for the given ParseContext, before exiting.
|
|
||||||
func FatalUsageContext(context *ParseContext, format string, args ...interface{}) {
|
|
||||||
CommandLine.FatalUsageContext(context, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Usage prints usage to stderr.
|
|
||||||
func Usage() {
|
|
||||||
CommandLine.Usage(os.Args[1:])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set global usage template to use (defaults to DefaultUsageTemplate).
|
|
||||||
func UsageTemplate(template string) *Application {
|
|
||||||
return CommandLine.UsageTemplate(template)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MustParse can be used with app.Parse(args) to exit with an error if parsing fails.
|
|
||||||
func MustParse(command string, err error) string {
|
|
||||||
if err != nil {
|
|
||||||
Fatalf("%s, try --help", err)
|
|
||||||
}
|
|
||||||
return command
|
|
||||||
}
|
|
||||||
|
|
||||||
// Version adds a flag for displaying the application version number.
|
|
||||||
func Version(version string) *Application {
|
|
||||||
return CommandLine.Version(version)
|
|
||||||
}
|
|
9
vendor/gopkg.in/alecthomas/kingpin.v2/guesswidth.go
generated
vendored
9
vendor/gopkg.in/alecthomas/kingpin.v2/guesswidth.go
generated
vendored
@ -1,9 +0,0 @@
|
|||||||
// +build !linux,!freebsd,!darwin,!dragonfly,!netbsd,!openbsd
|
|
||||||
|
|
||||||
package kingpin
|
|
||||||
|
|
||||||
import "io"
|
|
||||||
|
|
||||||
func guessWidth(w io.Writer) int {
|
|
||||||
return 80
|
|
||||||
}
|
|
38
vendor/gopkg.in/alecthomas/kingpin.v2/guesswidth_unix.go
generated
vendored
38
vendor/gopkg.in/alecthomas/kingpin.v2/guesswidth_unix.go
generated
vendored
@ -1,38 +0,0 @@
|
|||||||
// +build linux freebsd darwin dragonfly netbsd openbsd
|
|
||||||
|
|
||||||
package kingpin
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
func guessWidth(w io.Writer) int {
|
|
||||||
// check if COLUMNS env is set to comply with
|
|
||||||
// http://pubs.opengroup.org/onlinepubs/009604499/basedefs/xbd_chap08.html
|
|
||||||
colsStr := os.Getenv("COLUMNS")
|
|
||||||
if colsStr != "" {
|
|
||||||
if cols, err := strconv.Atoi(colsStr); err == nil {
|
|
||||||
return cols
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if t, ok := w.(*os.File); ok {
|
|
||||||
fd := t.Fd()
|
|
||||||
var dimensions [4]uint16
|
|
||||||
|
|
||||||
if _, _, err := syscall.Syscall6(
|
|
||||||
syscall.SYS_IOCTL,
|
|
||||||
uintptr(fd),
|
|
||||||
uintptr(syscall.TIOCGWINSZ),
|
|
||||||
uintptr(unsafe.Pointer(&dimensions)),
|
|
||||||
0, 0, 0,
|
|
||||||
); err == 0 {
|
|
||||||
return int(dimensions[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 80
|
|
||||||
}
|
|
215
vendor/gopkg.in/alecthomas/kingpin.v2/model.go
generated
vendored
215
vendor/gopkg.in/alecthomas/kingpin.v2/model.go
generated
vendored
@ -1,215 +0,0 @@
|
|||||||
package kingpin
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Data model for Kingpin command-line structure.
|
|
||||||
|
|
||||||
type FlagGroupModel struct {
|
|
||||||
Flags []*FlagModel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FlagGroupModel) FlagSummary() string {
|
|
||||||
out := []string{}
|
|
||||||
count := 0
|
|
||||||
for _, flag := range f.Flags {
|
|
||||||
if flag.Name != "help" {
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
if flag.Required {
|
|
||||||
if flag.IsBoolFlag() {
|
|
||||||
out = append(out, fmt.Sprintf("--[no-]%s", flag.Name))
|
|
||||||
} else {
|
|
||||||
out = append(out, fmt.Sprintf("--%s=%s", flag.Name, flag.FormatPlaceHolder()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if count != len(out) {
|
|
||||||
out = append(out, "[<flags>]")
|
|
||||||
}
|
|
||||||
return strings.Join(out, " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
type FlagModel struct {
|
|
||||||
Name string
|
|
||||||
Help string
|
|
||||||
Short rune
|
|
||||||
Default string
|
|
||||||
Envar string
|
|
||||||
PlaceHolder string
|
|
||||||
Required bool
|
|
||||||
Hidden bool
|
|
||||||
Value Value
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FlagModel) String() string {
|
|
||||||
return f.Value.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FlagModel) IsBoolFlag() bool {
|
|
||||||
if fl, ok := f.Value.(boolFlag); ok {
|
|
||||||
return fl.IsBoolFlag()
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FlagModel) FormatPlaceHolder() string {
|
|
||||||
if f.PlaceHolder != "" {
|
|
||||||
return f.PlaceHolder
|
|
||||||
}
|
|
||||||
if f.Default != "" {
|
|
||||||
if _, ok := f.Value.(*stringValue); ok {
|
|
||||||
return strconv.Quote(f.Default)
|
|
||||||
}
|
|
||||||
return f.Default
|
|
||||||
}
|
|
||||||
return strings.ToUpper(f.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ArgGroupModel struct {
|
|
||||||
Args []*ArgModel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ArgGroupModel) ArgSummary() string {
|
|
||||||
depth := 0
|
|
||||||
out := []string{}
|
|
||||||
for _, arg := range a.Args {
|
|
||||||
h := "<" + arg.Name + ">"
|
|
||||||
if !arg.Required {
|
|
||||||
h = "[" + h
|
|
||||||
depth++
|
|
||||||
}
|
|
||||||
out = append(out, h)
|
|
||||||
}
|
|
||||||
out[len(out)-1] = out[len(out)-1] + strings.Repeat("]", depth)
|
|
||||||
return strings.Join(out, " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
type ArgModel struct {
|
|
||||||
Name string
|
|
||||||
Help string
|
|
||||||
Default string
|
|
||||||
Required bool
|
|
||||||
Value Value
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ArgModel) String() string {
|
|
||||||
return a.Value.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
type CmdGroupModel struct {
|
|
||||||
Commands []*CmdModel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CmdGroupModel) FlattenedCommands() (out []*CmdModel) {
|
|
||||||
for _, cmd := range c.Commands {
|
|
||||||
if len(cmd.Commands) == 0 {
|
|
||||||
out = append(out, cmd)
|
|
||||||
}
|
|
||||||
out = append(out, cmd.FlattenedCommands()...)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type CmdModel struct {
|
|
||||||
Name string
|
|
||||||
Help string
|
|
||||||
FullCommand string
|
|
||||||
Depth int
|
|
||||||
*FlagGroupModel
|
|
||||||
*ArgGroupModel
|
|
||||||
*CmdGroupModel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CmdModel) String() string {
|
|
||||||
return c.FullCommand
|
|
||||||
}
|
|
||||||
|
|
||||||
type ApplicationModel struct {
|
|
||||||
Name string
|
|
||||||
Help string
|
|
||||||
Version string
|
|
||||||
Author string
|
|
||||||
*ArgGroupModel
|
|
||||||
*CmdGroupModel
|
|
||||||
*FlagGroupModel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Application) Model() *ApplicationModel {
|
|
||||||
return &ApplicationModel{
|
|
||||||
Name: a.Name,
|
|
||||||
Help: a.Help,
|
|
||||||
Version: a.version,
|
|
||||||
Author: a.author,
|
|
||||||
FlagGroupModel: a.flagGroup.Model(),
|
|
||||||
ArgGroupModel: a.argGroup.Model(),
|
|
||||||
CmdGroupModel: a.cmdGroup.Model(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *argGroup) Model() *ArgGroupModel {
|
|
||||||
m := &ArgGroupModel{}
|
|
||||||
for _, arg := range a.args {
|
|
||||||
m.Args = append(m.Args, arg.Model())
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ArgClause) Model() *ArgModel {
|
|
||||||
return &ArgModel{
|
|
||||||
Name: a.name,
|
|
||||||
Help: a.help,
|
|
||||||
Default: a.defaultValue,
|
|
||||||
Required: a.required,
|
|
||||||
Value: a.value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *flagGroup) Model() *FlagGroupModel {
|
|
||||||
m := &FlagGroupModel{}
|
|
||||||
for _, fl := range f.flagOrder {
|
|
||||||
m.Flags = append(m.Flags, fl.Model())
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FlagClause) Model() *FlagModel {
|
|
||||||
return &FlagModel{
|
|
||||||
Name: f.name,
|
|
||||||
Help: f.help,
|
|
||||||
Short: rune(f.shorthand),
|
|
||||||
Default: f.defaultValue,
|
|
||||||
Envar: f.envar,
|
|
||||||
PlaceHolder: f.placeholder,
|
|
||||||
Required: f.required,
|
|
||||||
Hidden: f.hidden,
|
|
||||||
Value: f.value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cmdGroup) Model() *CmdGroupModel {
|
|
||||||
m := &CmdGroupModel{}
|
|
||||||
for _, cm := range c.commandOrder {
|
|
||||||
m.Commands = append(m.Commands, cm.Model())
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CmdClause) Model() *CmdModel {
|
|
||||||
depth := 0
|
|
||||||
for i := c; i != nil; i = i.parent {
|
|
||||||
depth++
|
|
||||||
}
|
|
||||||
return &CmdModel{
|
|
||||||
Name: c.name,
|
|
||||||
Help: c.help,
|
|
||||||
Depth: depth,
|
|
||||||
FullCommand: c.FullCommand(),
|
|
||||||
FlagGroupModel: c.flagGroup.Model(),
|
|
||||||
ArgGroupModel: c.argGroup.Model(),
|
|
||||||
CmdGroupModel: c.cmdGroup.Model(),
|
|
||||||
}
|
|
||||||
}
|
|
335
vendor/gopkg.in/alecthomas/kingpin.v2/parser.go
generated
vendored
335
vendor/gopkg.in/alecthomas/kingpin.v2/parser.go
generated
vendored
@ -1,335 +0,0 @@
|
|||||||
package kingpin
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TokenType int
|
|
||||||
|
|
||||||
// Token types.
|
|
||||||
const (
|
|
||||||
TokenShort TokenType = iota
|
|
||||||
TokenLong
|
|
||||||
TokenArg
|
|
||||||
TokenError
|
|
||||||
TokenEOL
|
|
||||||
)
|
|
||||||
|
|
||||||
func (t TokenType) String() string {
|
|
||||||
switch t {
|
|
||||||
case TokenShort:
|
|
||||||
return "short flag"
|
|
||||||
case TokenLong:
|
|
||||||
return "long flag"
|
|
||||||
case TokenArg:
|
|
||||||
return "argument"
|
|
||||||
case TokenError:
|
|
||||||
return "error"
|
|
||||||
case TokenEOL:
|
|
||||||
return "<EOL>"
|
|
||||||
}
|
|
||||||
return "?"
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
TokenEOLMarker = Token{-1, TokenEOL, ""}
|
|
||||||
)
|
|
||||||
|
|
||||||
type Token struct {
|
|
||||||
Index int
|
|
||||||
Type TokenType
|
|
||||||
Value string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Token) Equal(o *Token) bool {
|
|
||||||
return t.Index == o.Index
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Token) IsFlag() bool {
|
|
||||||
return t.Type == TokenShort || t.Type == TokenLong
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Token) IsEOF() bool {
|
|
||||||
return t.Type == TokenEOL
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Token) String() string {
|
|
||||||
switch t.Type {
|
|
||||||
case TokenShort:
|
|
||||||
return "-" + t.Value
|
|
||||||
case TokenLong:
|
|
||||||
return "--" + t.Value
|
|
||||||
case TokenArg:
|
|
||||||
return t.Value
|
|
||||||
case TokenError:
|
|
||||||
return "error: " + t.Value
|
|
||||||
case TokenEOL:
|
|
||||||
return "<EOL>"
|
|
||||||
default:
|
|
||||||
panic("unhandled type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A union of possible elements in a parse stack.
|
|
||||||
type ParseElement struct {
|
|
||||||
// Clause is either *CmdClause, *ArgClause or *FlagClause.
|
|
||||||
Clause interface{}
|
|
||||||
// Value is corresponding value for an ArgClause or FlagClause (if any).
|
|
||||||
Value *string
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseContext holds the current context of the parser. When passed to
|
|
||||||
// Action() callbacks Elements will be fully populated with *FlagClause,
|
|
||||||
// *ArgClause and *CmdClause values and their corresponding arguments (if
|
|
||||||
// any).
|
|
||||||
type ParseContext struct {
|
|
||||||
SelectedCommand *CmdClause
|
|
||||||
argsOnly bool
|
|
||||||
peek []*Token
|
|
||||||
argi int // Index of current command-line arg we're processing.
|
|
||||||
args []string
|
|
||||||
flags *flagGroup
|
|
||||||
arguments *argGroup
|
|
||||||
argumenti int // Cursor into arguments
|
|
||||||
// Flags, arguments and commands encountered and collected during parse.
|
|
||||||
Elements []*ParseElement
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ParseContext) nextArg() *ArgClause {
|
|
||||||
if p.argumenti >= len(p.arguments.args) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
arg := p.arguments.args[p.argumenti]
|
|
||||||
if !arg.consumesRemainder() {
|
|
||||||
p.argumenti++
|
|
||||||
}
|
|
||||||
return arg
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ParseContext) next() {
|
|
||||||
p.argi++
|
|
||||||
p.args = p.args[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasTrailingArgs returns true if there are unparsed command-line arguments.
|
|
||||||
// This can occur if the parser can not match remaining arguments.
|
|
||||||
func (p *ParseContext) HasTrailingArgs() bool {
|
|
||||||
return len(p.args) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func tokenize(args []string) *ParseContext {
|
|
||||||
return &ParseContext{
|
|
||||||
args: args,
|
|
||||||
flags: newFlagGroup(),
|
|
||||||
arguments: newArgGroup(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ParseContext) mergeFlags(flags *flagGroup) {
|
|
||||||
for _, flag := range flags.flagOrder {
|
|
||||||
if flag.shorthand != 0 {
|
|
||||||
p.flags.short[string(flag.shorthand)] = flag
|
|
||||||
}
|
|
||||||
p.flags.long[flag.name] = flag
|
|
||||||
p.flags.flagOrder = append(p.flags.flagOrder, flag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ParseContext) mergeArgs(args *argGroup) {
|
|
||||||
for _, arg := range args.args {
|
|
||||||
p.arguments.args = append(p.arguments.args, arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ParseContext) EOL() bool {
|
|
||||||
return p.Peek().Type == TokenEOL
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next token in the parse context.
|
|
||||||
func (p *ParseContext) Next() *Token {
|
|
||||||
if len(p.peek) > 0 {
|
|
||||||
return p.pop()
|
|
||||||
}
|
|
||||||
|
|
||||||
// End of tokens.
|
|
||||||
if len(p.args) == 0 {
|
|
||||||
return &Token{Index: p.argi, Type: TokenEOL}
|
|
||||||
}
|
|
||||||
|
|
||||||
arg := p.args[0]
|
|
||||||
p.next()
|
|
||||||
|
|
||||||
if p.argsOnly {
|
|
||||||
return &Token{p.argi, TokenArg, arg}
|
|
||||||
}
|
|
||||||
|
|
||||||
// All remaining args are passed directly.
|
|
||||||
if arg == "--" {
|
|
||||||
p.argsOnly = true
|
|
||||||
return p.Next()
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(arg, "--") {
|
|
||||||
parts := strings.SplitN(arg[2:], "=", 2)
|
|
||||||
token := &Token{p.argi, TokenLong, parts[0]}
|
|
||||||
if len(parts) == 2 {
|
|
||||||
p.push(&Token{p.argi, TokenArg, parts[1]})
|
|
||||||
}
|
|
||||||
return token
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(arg, "-") {
|
|
||||||
if len(arg) == 1 {
|
|
||||||
return &Token{Index: p.argi, Type: TokenShort}
|
|
||||||
}
|
|
||||||
short := arg[1:2]
|
|
||||||
flag, ok := p.flags.short[short]
|
|
||||||
// Not a known short flag, we'll just return it anyway.
|
|
||||||
if !ok {
|
|
||||||
} else if fb, ok := flag.value.(boolFlag); ok && fb.IsBoolFlag() {
|
|
||||||
// Bool short flag.
|
|
||||||
} else {
|
|
||||||
// Short flag with combined argument: -fARG
|
|
||||||
token := &Token{p.argi, TokenShort, short}
|
|
||||||
if len(arg) > 2 {
|
|
||||||
p.push(&Token{p.argi, TokenArg, arg[2:]})
|
|
||||||
}
|
|
||||||
return token
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(arg) > 2 {
|
|
||||||
p.args = append([]string{"-" + arg[2:]}, p.args...)
|
|
||||||
}
|
|
||||||
return &Token{p.argi, TokenShort, short}
|
|
||||||
} else if strings.HasPrefix(arg, "@") {
|
|
||||||
expanded, err := ExpandArgsFromFile(arg[1:])
|
|
||||||
if err != nil {
|
|
||||||
return &Token{p.argi, TokenError, err.Error()}
|
|
||||||
}
|
|
||||||
if p.argi >= len(p.args) {
|
|
||||||
p.args = append(p.args[:p.argi-1], expanded...)
|
|
||||||
} else {
|
|
||||||
p.args = append(p.args[:p.argi-1], append(expanded, p.args[p.argi+1:]...)...)
|
|
||||||
}
|
|
||||||
return p.Next()
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Token{p.argi, TokenArg, arg}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ParseContext) Peek() *Token {
|
|
||||||
if len(p.peek) == 0 {
|
|
||||||
return p.push(p.Next())
|
|
||||||
}
|
|
||||||
return p.peek[len(p.peek)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ParseContext) push(token *Token) *Token {
|
|
||||||
p.peek = append(p.peek, token)
|
|
||||||
return token
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ParseContext) pop() *Token {
|
|
||||||
end := len(p.peek) - 1
|
|
||||||
token := p.peek[end]
|
|
||||||
p.peek = p.peek[0:end]
|
|
||||||
return token
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ParseContext) String() string {
|
|
||||||
return p.SelectedCommand.FullCommand()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ParseContext) matchedFlag(flag *FlagClause, value string) {
|
|
||||||
p.Elements = append(p.Elements, &ParseElement{Clause: flag, Value: &value})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ParseContext) matchedArg(arg *ArgClause, value string) {
|
|
||||||
p.Elements = append(p.Elements, &ParseElement{Clause: arg, Value: &value})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ParseContext) matchedCmd(cmd *CmdClause) {
|
|
||||||
p.Elements = append(p.Elements, &ParseElement{Clause: cmd})
|
|
||||||
p.mergeFlags(cmd.flagGroup)
|
|
||||||
p.mergeArgs(cmd.argGroup)
|
|
||||||
p.SelectedCommand = cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expand arguments from a file. Lines starting with # will be treated as comments.
|
|
||||||
func ExpandArgsFromFile(filename string) (out []string, err error) {
|
|
||||||
r, err := os.Open(filename)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer r.Close()
|
|
||||||
scanner := bufio.NewScanner(r)
|
|
||||||
for scanner.Scan() {
|
|
||||||
line := scanner.Text()
|
|
||||||
if strings.HasPrefix(line, "#") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
out = append(out, line)
|
|
||||||
}
|
|
||||||
err = scanner.Err()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func parse(context *ParseContext, app *Application) (selected []string, err error) {
|
|
||||||
context.mergeFlags(app.flagGroup)
|
|
||||||
context.mergeArgs(app.argGroup)
|
|
||||||
|
|
||||||
cmds := app.cmdGroup
|
|
||||||
|
|
||||||
loop:
|
|
||||||
for !context.EOL() {
|
|
||||||
token := context.Peek()
|
|
||||||
switch token.Type {
|
|
||||||
case TokenLong, TokenShort:
|
|
||||||
if err := context.flags.parse(context); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
case TokenArg:
|
|
||||||
if cmds.have() {
|
|
||||||
cmd, ok := cmds.commands[token.String()]
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("expected command but got %s", token)
|
|
||||||
}
|
|
||||||
context.matchedCmd(cmd)
|
|
||||||
selected = append([]string{token.String()}, selected...)
|
|
||||||
cmds = cmd.cmdGroup
|
|
||||||
context.Next()
|
|
||||||
} else if context.arguments.have() {
|
|
||||||
arg := context.nextArg()
|
|
||||||
if arg == nil {
|
|
||||||
break loop
|
|
||||||
}
|
|
||||||
context.matchedArg(arg, token.String())
|
|
||||||
context.Next()
|
|
||||||
} else {
|
|
||||||
break loop
|
|
||||||
}
|
|
||||||
|
|
||||||
case TokenEOL:
|
|
||||||
break loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !context.EOL() {
|
|
||||||
return nil, fmt.Errorf("unexpected %s", context.Peek())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set defaults for all remaining args.
|
|
||||||
for arg := context.nextArg(); arg != nil && !arg.consumesRemainder(); arg = context.nextArg() {
|
|
||||||
if arg.defaultValue != "" {
|
|
||||||
if err := arg.value.Set(arg.defaultValue); err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid default value '%s' for argument '%s'", arg.defaultValue, arg.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
265
vendor/gopkg.in/alecthomas/kingpin.v2/parsers.go
generated
vendored
265
vendor/gopkg.in/alecthomas/kingpin.v2/parsers.go
generated
vendored
@ -1,265 +0,0 @@
|
|||||||
package kingpin
|
|
||||||
|
|
||||||
//go:generate go run ./genrepeated/main.go
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/alecthomas/units"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Settings interface {
|
|
||||||
SetValue(value Value)
|
|
||||||
}
|
|
||||||
|
|
||||||
type parserMixin struct {
|
|
||||||
value Value
|
|
||||||
required bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *parserMixin) SetValue(value Value) {
|
|
||||||
p.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
// String sets the parser to a string parser.
|
|
||||||
func (p *parserMixin) String() (target *string) {
|
|
||||||
target = new(string)
|
|
||||||
p.StringVar(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// StringMap provides key=value parsing into a map.
|
|
||||||
func (p *parserMixin) StringMap() (target *map[string]string) {
|
|
||||||
target = &(map[string]string{})
|
|
||||||
p.StringMapVar(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bool sets the parser to a boolean parser. Supports --no-<X> to disable the flag.
|
|
||||||
func (p *parserMixin) Bool() (target *bool) {
|
|
||||||
target = new(bool)
|
|
||||||
p.BoolVar(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Int sets the parser to an int parser.
|
|
||||||
func (p *parserMixin) Int() (target *int) {
|
|
||||||
target = new(int)
|
|
||||||
p.IntVar(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Int64 parses an int64
|
|
||||||
func (p *parserMixin) Int64() (target *int64) {
|
|
||||||
target = new(int64)
|
|
||||||
p.Int64Var(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uint64 parses a uint64
|
|
||||||
func (p *parserMixin) Uint64() (target *uint64) {
|
|
||||||
target = new(uint64)
|
|
||||||
p.Uint64Var(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float sets the parser to a float64 parser.
|
|
||||||
func (p *parserMixin) Float() (target *float64) {
|
|
||||||
target = new(float64)
|
|
||||||
p.FloatVar(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Duration sets the parser to a time.Duration parser.
|
|
||||||
func (p *parserMixin) Duration() (target *time.Duration) {
|
|
||||||
target = new(time.Duration)
|
|
||||||
p.DurationVar(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bytes parses numeric byte units. eg. 1.5KB
|
|
||||||
func (p *parserMixin) Bytes() (target *units.Base2Bytes) {
|
|
||||||
target = new(units.Base2Bytes)
|
|
||||||
p.BytesVar(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// IP sets the parser to a net.IP parser.
|
|
||||||
func (p *parserMixin) IP() (target *net.IP) {
|
|
||||||
target = new(net.IP)
|
|
||||||
p.IPVar(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// TCP (host:port) address.
|
|
||||||
func (p *parserMixin) TCP() (target **net.TCPAddr) {
|
|
||||||
target = new(*net.TCPAddr)
|
|
||||||
p.TCPVar(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// TCPVar (host:port) address.
|
|
||||||
func (p *parserMixin) TCPVar(target **net.TCPAddr) {
|
|
||||||
p.SetValue(newTCPAddrValue(target))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExistingFile sets the parser to one that requires and returns an existing file.
|
|
||||||
func (p *parserMixin) ExistingFile() (target *string) {
|
|
||||||
target = new(string)
|
|
||||||
p.ExistingFileVar(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExistingDir sets the parser to one that requires and returns an existing directory.
|
|
||||||
func (p *parserMixin) ExistingDir() (target *string) {
|
|
||||||
target = new(string)
|
|
||||||
p.ExistingDirVar(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExistingFileOrDir sets the parser to one that requires and returns an existing file OR directory.
|
|
||||||
func (p *parserMixin) ExistingFileOrDir() (target *string) {
|
|
||||||
target = new(string)
|
|
||||||
p.ExistingFileOrDirVar(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// File returns an os.File against an existing file.
|
|
||||||
func (p *parserMixin) File() (target **os.File) {
|
|
||||||
target = new(*os.File)
|
|
||||||
p.FileVar(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// File attempts to open a File with os.OpenFile(flag, perm).
|
|
||||||
func (p *parserMixin) OpenFile(flag int, perm os.FileMode) (target **os.File) {
|
|
||||||
target = new(*os.File)
|
|
||||||
p.OpenFileVar(target, flag, perm)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// URL provides a valid, parsed url.URL.
|
|
||||||
func (p *parserMixin) URL() (target **url.URL) {
|
|
||||||
target = new(*url.URL)
|
|
||||||
p.URLVar(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// String sets the parser to a string parser.
|
|
||||||
func (p *parserMixin) StringVar(target *string) {
|
|
||||||
p.SetValue(newStringValue(target))
|
|
||||||
}
|
|
||||||
|
|
||||||
// StringMap provides key=value parsing into a map.
|
|
||||||
func (p *parserMixin) StringMapVar(target *map[string]string) {
|
|
||||||
p.SetValue(newStringMapValue(target))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bool sets the parser to a boolean parser. Supports --no-<X> to disable the flag.
|
|
||||||
func (p *parserMixin) BoolVar(target *bool) {
|
|
||||||
p.SetValue(newBoolValue(target))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Int sets the parser to an int parser.
|
|
||||||
func (p *parserMixin) IntVar(target *int) {
|
|
||||||
p.SetValue(newIntValue(target))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Int64 parses an int64
|
|
||||||
func (p *parserMixin) Int64Var(target *int64) {
|
|
||||||
p.SetValue(newInt64Value(target))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uint64 parses a uint64
|
|
||||||
func (p *parserMixin) Uint64Var(target *uint64) {
|
|
||||||
p.SetValue(newUint64Value(target))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float sets the parser to a float64 parser.
|
|
||||||
func (p *parserMixin) FloatVar(target *float64) {
|
|
||||||
p.SetValue(newFloat64Value(target))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Duration sets the parser to a time.Duration parser.
|
|
||||||
func (p *parserMixin) DurationVar(target *time.Duration) {
|
|
||||||
p.SetValue(newDurationValue(target))
|
|
||||||
}
|
|
||||||
|
|
||||||
// BytesVar parses numeric byte units. eg. 1.5KB
|
|
||||||
func (p *parserMixin) BytesVar(target *units.Base2Bytes) {
|
|
||||||
p.SetValue(newBytesValue(target))
|
|
||||||
}
|
|
||||||
|
|
||||||
// IP sets the parser to a net.IP parser.
|
|
||||||
func (p *parserMixin) IPVar(target *net.IP) {
|
|
||||||
p.SetValue(newIPValue(target))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExistingFile sets the parser to one that requires and returns an existing file.
|
|
||||||
func (p *parserMixin) ExistingFileVar(target *string) {
|
|
||||||
p.SetValue(newExistingFileValue(target))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExistingDir sets the parser to one that requires and returns an existing directory.
|
|
||||||
func (p *parserMixin) ExistingDirVar(target *string) {
|
|
||||||
p.SetValue(newExistingDirValue(target))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExistingDir sets the parser to one that requires and returns an existing directory.
|
|
||||||
func (p *parserMixin) ExistingFileOrDirVar(target *string) {
|
|
||||||
p.SetValue(newExistingFileOrDirValue(target))
|
|
||||||
}
|
|
||||||
|
|
||||||
// FileVar opens an existing file.
|
|
||||||
func (p *parserMixin) FileVar(target **os.File) {
|
|
||||||
p.SetValue(newFileValue(target, os.O_RDONLY, 0))
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenFileVar calls os.OpenFile(flag, perm)
|
|
||||||
func (p *parserMixin) OpenFileVar(target **os.File, flag int, perm os.FileMode) {
|
|
||||||
p.SetValue(newFileValue(target, flag, perm))
|
|
||||||
}
|
|
||||||
|
|
||||||
// URL provides a valid, parsed url.URL.
|
|
||||||
func (p *parserMixin) URLVar(target **url.URL) {
|
|
||||||
p.SetValue(newURLValue(target))
|
|
||||||
}
|
|
||||||
|
|
||||||
// URLList provides a parsed list of url.URL values.
|
|
||||||
func (p *parserMixin) URLList() (target *[]*url.URL) {
|
|
||||||
target = new([]*url.URL)
|
|
||||||
p.URLListVar(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// URLListVar provides a parsed list of url.URL values.
|
|
||||||
func (p *parserMixin) URLListVar(target *[]*url.URL) {
|
|
||||||
p.SetValue(newURLListValue(target))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enum allows a value from a set of options.
|
|
||||||
func (p *parserMixin) Enum(options ...string) (target *string) {
|
|
||||||
target = new(string)
|
|
||||||
p.EnumVar(&target, options...)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// EnumVar allows a value from a set of options.
|
|
||||||
func (p *parserMixin) EnumVar(target **string, options ...string) {
|
|
||||||
p.SetValue(newEnumFlag(target, options...))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enums allows a set of values from a set of options.
|
|
||||||
func (p *parserMixin) Enums(options ...string) (target *[]string) {
|
|
||||||
target = new([]string)
|
|
||||||
p.EnumsVar(target, options...)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// EnumVar allows a value from a set of options.
|
|
||||||
func (p *parserMixin) EnumsVar(target *[]string, options ...string) {
|
|
||||||
p.SetValue(newEnumsFlag(target, options...))
|
|
||||||
}
|
|
107
vendor/gopkg.in/alecthomas/kingpin.v2/repeated.go
generated
vendored
107
vendor/gopkg.in/alecthomas/kingpin.v2/repeated.go
generated
vendored
@ -1,107 +0,0 @@
|
|||||||
package kingpin
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This file is autogenerated by "go generate .". Do not modify.
|
|
||||||
|
|
||||||
// Strings accumulates string values into a slice.
|
|
||||||
func (p *parserMixin) Strings() (target *[]string) {
|
|
||||||
target = new([]string)
|
|
||||||
p.StringsVar(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *parserMixin) StringsVar(target *[]string) {
|
|
||||||
p.SetValue(newAccumulator(target, func(v interface{}) Value { return newStringValue(v.(*string)) }))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uint64List accumulates uint64 values into a slice.
|
|
||||||
func (p *parserMixin) Uint64List() (target *[]uint64) {
|
|
||||||
target = new([]uint64)
|
|
||||||
p.Uint64ListVar(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *parserMixin) Uint64ListVar(target *[]uint64) {
|
|
||||||
p.SetValue(newAccumulator(target, func(v interface{}) Value { return newUint64Value(v.(*uint64)) }))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Int64List accumulates int64 values into a slice.
|
|
||||||
func (p *parserMixin) Int64List() (target *[]int64) {
|
|
||||||
target = new([]int64)
|
|
||||||
p.Int64ListVar(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *parserMixin) Int64ListVar(target *[]int64) {
|
|
||||||
p.SetValue(newAccumulator(target, func(v interface{}) Value { return newInt64Value(v.(*int64)) }))
|
|
||||||
}
|
|
||||||
|
|
||||||
// DurationList accumulates time.Duration values into a slice.
|
|
||||||
func (p *parserMixin) DurationList() (target *[]time.Duration) {
|
|
||||||
target = new([]time.Duration)
|
|
||||||
p.DurationListVar(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *parserMixin) DurationListVar(target *[]time.Duration) {
|
|
||||||
p.SetValue(newAccumulator(target, func(v interface{}) Value { return newDurationValue(v.(*time.Duration)) }))
|
|
||||||
}
|
|
||||||
|
|
||||||
// IPList accumulates net.IP values into a slice.
|
|
||||||
func (p *parserMixin) IPList() (target *[]net.IP) {
|
|
||||||
target = new([]net.IP)
|
|
||||||
p.IPListVar(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *parserMixin) IPListVar(target *[]net.IP) {
|
|
||||||
p.SetValue(newAccumulator(target, func(v interface{}) Value { return newIPValue(v.(*net.IP)) }))
|
|
||||||
}
|
|
||||||
|
|
||||||
// TCPList accumulates *net.TCPAddr values into a slice.
|
|
||||||
func (p *parserMixin) TCPList() (target *[]*net.TCPAddr) {
|
|
||||||
target = new([]*net.TCPAddr)
|
|
||||||
p.TCPListVar(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *parserMixin) TCPListVar(target *[]*net.TCPAddr) {
|
|
||||||
p.SetValue(newAccumulator(target, func(v interface{}) Value { return newTCPAddrValue(v.(**net.TCPAddr)) }))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExistingFiles accumulates string values into a slice.
|
|
||||||
func (p *parserMixin) ExistingFiles() (target *[]string) {
|
|
||||||
target = new([]string)
|
|
||||||
p.ExistingFilesVar(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *parserMixin) ExistingFilesVar(target *[]string) {
|
|
||||||
p.SetValue(newAccumulator(target, func(v interface{}) Value { return newExistingFileValue(v.(*string)) }))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExistingDirs accumulates string values into a slice.
|
|
||||||
func (p *parserMixin) ExistingDirs() (target *[]string) {
|
|
||||||
target = new([]string)
|
|
||||||
p.ExistingDirsVar(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *parserMixin) ExistingDirsVar(target *[]string) {
|
|
||||||
p.SetValue(newAccumulator(target, func(v interface{}) Value { return newExistingDirValue(v.(*string)) }))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExistingFilesOrDirs accumulates string values into a slice.
|
|
||||||
func (p *parserMixin) ExistingFilesOrDirs() (target *[]string) {
|
|
||||||
target = new([]string)
|
|
||||||
p.ExistingFilesOrDirsVar(target)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *parserMixin) ExistingFilesOrDirsVar(target *[]string) {
|
|
||||||
p.SetValue(newAccumulator(target, func(v interface{}) Value { return newExistingFileOrDirValue(v.(*string)) }))
|
|
||||||
}
|
|
11
vendor/gopkg.in/alecthomas/kingpin.v2/repeated.json
generated
vendored
11
vendor/gopkg.in/alecthomas/kingpin.v2/repeated.json
generated
vendored
@ -1,11 +0,0 @@
|
|||||||
[
|
|
||||||
{"name": "String", "type": "string", "plural": "Strings"},
|
|
||||||
{"name": "Uint64", "type": "uint64"},
|
|
||||||
{"name": "Int64", "type": "int64"},
|
|
||||||
{"name": "Duration", "type": "time.Duration"},
|
|
||||||
{"name": "IP", "type": "net.IP"},
|
|
||||||
{"name": "TCPAddr", "Type": "*net.TCPAddr", "plural": "TCPList"},
|
|
||||||
{"name": "ExistingFile", "Type": "string", "plural": "ExistingFiles"},
|
|
||||||
{"name": "ExistingDir", "Type": "string", "plural": "ExistingDirs"},
|
|
||||||
{"name": "ExistingFileOrDir", "Type": "string", "plural": "ExistingFilesOrDirs"}
|
|
||||||
]
|
|
174
vendor/gopkg.in/alecthomas/kingpin.v2/templates.go
generated
vendored
174
vendor/gopkg.in/alecthomas/kingpin.v2/templates.go
generated
vendored
@ -1,174 +0,0 @@
|
|||||||
package kingpin
|
|
||||||
|
|
||||||
// Default usage template.
|
|
||||||
var DefaultUsageTemplate = `{{define "FormatCommand"}}\
|
|
||||||
{{if .FlagSummary}} {{.FlagSummary}}{{end}}\
|
|
||||||
{{range .Args}} {{if not .Required}}[{{end}}<{{.Name}}>{{if .Value|IsCumulative}}...{{end}}{{if not .Required}}]{{end}}{{end}}\
|
|
||||||
{{end}}\
|
|
||||||
|
|
||||||
{{define "FormatCommands"}}\
|
|
||||||
{{range .FlattenedCommands}}\
|
|
||||||
{{.FullCommand}}{{template "FormatCommand" .}}
|
|
||||||
{{.Help|Wrap 4}}
|
|
||||||
{{end}}\
|
|
||||||
{{end}}\
|
|
||||||
|
|
||||||
{{define "FormatUsage"}}\
|
|
||||||
{{template "FormatCommand" .}}{{if .Commands}} <command> [<args> ...]{{end}}
|
|
||||||
{{if .Help}}
|
|
||||||
{{.Help|Wrap 0}}\
|
|
||||||
{{end}}\
|
|
||||||
|
|
||||||
{{end}}\
|
|
||||||
|
|
||||||
{{if .Context.SelectedCommand}}\
|
|
||||||
usage: {{.App.Name}} {{.Context.SelectedCommand}}{{template "FormatUsage" .Context.SelectedCommand}}
|
|
||||||
{{else}}\
|
|
||||||
usage: {{.App.Name}}{{template "FormatUsage" .App}}
|
|
||||||
{{end}}\
|
|
||||||
{{if .Context.Flags}}\
|
|
||||||
Flags:
|
|
||||||
{{.Context.Flags|FlagsToTwoColumns|FormatTwoColumns}}
|
|
||||||
{{end}}\
|
|
||||||
{{if .Context.Args}}\
|
|
||||||
Args:
|
|
||||||
{{.Context.Args|ArgsToTwoColumns|FormatTwoColumns}}
|
|
||||||
{{end}}\
|
|
||||||
{{if .Context.SelectedCommand}}\
|
|
||||||
Subcommands:
|
|
||||||
{{if .Context.SelectedCommand.Commands}}\
|
|
||||||
{{template "FormatCommands" .Context.SelectedCommand}}
|
|
||||||
{{end}}\
|
|
||||||
{{else if .App.Commands}}\
|
|
||||||
Commands:
|
|
||||||
{{template "FormatCommands" .App}}
|
|
||||||
{{end}}\
|
|
||||||
`
|
|
||||||
|
|
||||||
// Usage template with compactly formatted commands.
|
|
||||||
var CompactUsageTemplate = `{{define "FormatCommand"}}\
|
|
||||||
{{if .FlagSummary}} {{.FlagSummary}}{{end}}\
|
|
||||||
{{range .Args}} {{if not .Required}}[{{end}}<{{.Name}}>{{if .Value|IsCumulative}}...{{end}}{{if not .Required}}]{{end}}{{end}}\
|
|
||||||
{{end}}\
|
|
||||||
|
|
||||||
{{define "FormatCommandList"}}\
|
|
||||||
{{range .}}\
|
|
||||||
{{.Depth|Indent}}{{.Name}}{{template "FormatCommand" .}}
|
|
||||||
{{template "FormatCommandList" .Commands}}\
|
|
||||||
{{end}}\
|
|
||||||
{{end}}\
|
|
||||||
|
|
||||||
{{define "FormatUsage"}}\
|
|
||||||
{{template "FormatCommand" .}}{{if .Commands}} <command> [<args> ...]{{end}}
|
|
||||||
{{if .Help}}
|
|
||||||
{{.Help|Wrap 0}}\
|
|
||||||
{{end}}\
|
|
||||||
|
|
||||||
{{end}}\
|
|
||||||
|
|
||||||
{{if .Context.SelectedCommand}}\
|
|
||||||
usage: {{.App.Name}} {{.Context.SelectedCommand}}{{template "FormatUsage" .Context.SelectedCommand}}
|
|
||||||
{{else}}\
|
|
||||||
usage: {{.App.Name}}{{template "FormatUsage" .App}}
|
|
||||||
{{end}}\
|
|
||||||
{{if .Context.Flags}}\
|
|
||||||
Flags:
|
|
||||||
{{.Context.Flags|FlagsToTwoColumns|FormatTwoColumns}}
|
|
||||||
{{end}}\
|
|
||||||
{{if .Context.Args}}\
|
|
||||||
Args:
|
|
||||||
{{.Context.Args|ArgsToTwoColumns|FormatTwoColumns}}
|
|
||||||
{{end}}\
|
|
||||||
{{if .Context.SelectedCommand}}\
|
|
||||||
{{if .Context.SelectedCommand.Commands}}\
|
|
||||||
Commands:
|
|
||||||
{{.Context.SelectedCommand}}
|
|
||||||
{{template "FormatCommandList" .Context.SelectedCommand.Commands}}
|
|
||||||
{{end}}\
|
|
||||||
{{else if .App.Commands}}\
|
|
||||||
Commands:
|
|
||||||
{{template "FormatCommandList" .App.Commands}}
|
|
||||||
{{end}}\
|
|
||||||
`
|
|
||||||
|
|
||||||
var ManPageTemplate = `{{define "FormatFlags"}}\
|
|
||||||
{{range .Flags}}\
|
|
||||||
{{if not .Hidden}}\
|
|
||||||
.TP
|
|
||||||
\fB{{if .Short}}-{{.Short|Char}}, {{end}}--{{.Name}}{{if not .IsBoolFlag}}={{.FormatPlaceHolder}}{{end}}\\fR
|
|
||||||
{{.Help}}
|
|
||||||
{{end}}\
|
|
||||||
{{end}}\
|
|
||||||
{{end}}\
|
|
||||||
|
|
||||||
{{define "FormatCommand"}}\
|
|
||||||
{{if .FlagSummary}} {{.FlagSummary}}{{end}}\
|
|
||||||
{{range .Args}} {{if not .Required}}[{{end}}<{{.Name}}>{{if .Value|IsCumulative}}...{{end}}{{if not .Required}}]{{end}}{{end}}\
|
|
||||||
{{end}}\
|
|
||||||
|
|
||||||
{{define "FormatCommands"}}\
|
|
||||||
{{range .FlattenedCommands}}\
|
|
||||||
.SS
|
|
||||||
\fB{{.FullCommand}}{{template "FormatCommand" .}}\\fR
|
|
||||||
.PP
|
|
||||||
{{.Help}}
|
|
||||||
{{template "FormatFlags" .}}\
|
|
||||||
{{end}}\
|
|
||||||
{{end}}\
|
|
||||||
|
|
||||||
{{define "FormatUsage"}}\
|
|
||||||
{{template "FormatCommand" .}}{{if .Commands}} <command> [<args> ...]{{end}}\\fR
|
|
||||||
{{end}}\
|
|
||||||
|
|
||||||
.TH {{.App.Name}} 1 {{.App.Version}} "{{.App.Author}}"
|
|
||||||
.SH "NAME"
|
|
||||||
{{.App.Name}}
|
|
||||||
.SH "SYNOPSIS"
|
|
||||||
.TP
|
|
||||||
\fB{{.App.Name}}{{template "FormatUsage" .App}}
|
|
||||||
.SH "DESCRIPTION"
|
|
||||||
{{.App.Help}}
|
|
||||||
.SH "OPTIONS"
|
|
||||||
{{template "FormatFlags" .App}}\
|
|
||||||
{{if .App.Commands}}\
|
|
||||||
.SH "COMMANDS"
|
|
||||||
{{template "FormatCommands" .App}}\
|
|
||||||
{{end}}\
|
|
||||||
`
|
|
||||||
|
|
||||||
// Default usage template.
|
|
||||||
var LongHelpTemplate = `{{define "FormatCommand"}}\
|
|
||||||
{{if .FlagSummary}} {{.FlagSummary}}{{end}}\
|
|
||||||
{{range .Args}} {{if not .Required}}[{{end}}<{{.Name}}>{{if .Value|IsCumulative}}...{{end}}{{if not .Required}}]{{end}}{{end}}\
|
|
||||||
{{end}}\
|
|
||||||
|
|
||||||
{{define "FormatCommands"}}\
|
|
||||||
{{range .FlattenedCommands}}\
|
|
||||||
{{.FullCommand}}{{template "FormatCommand" .}}
|
|
||||||
{{.Help|Wrap 4}}
|
|
||||||
{{with .Flags|FlagsToTwoColumns}}{{FormatTwoColumnsWithIndent . 4 2}}{{end}}
|
|
||||||
{{end}}\
|
|
||||||
{{end}}\
|
|
||||||
|
|
||||||
{{define "FormatUsage"}}\
|
|
||||||
{{template "FormatCommand" .}}{{if .Commands}} <command> [<args> ...]{{end}}
|
|
||||||
{{if .Help}}
|
|
||||||
{{.Help|Wrap 0}}\
|
|
||||||
{{end}}\
|
|
||||||
|
|
||||||
{{end}}\
|
|
||||||
|
|
||||||
usage: {{.App.Name}}{{template "FormatUsage" .App}}
|
|
||||||
{{if .Context.Flags}}\
|
|
||||||
Flags:
|
|
||||||
{{.Context.Flags|FlagsToTwoColumns|FormatTwoColumns}}
|
|
||||||
{{end}}\
|
|
||||||
{{if .Context.Args}}\
|
|
||||||
Args:
|
|
||||||
{{.Context.Args|ArgsToTwoColumns|FormatTwoColumns}}
|
|
||||||
{{end}}\
|
|
||||||
{{if .App.Commands}}\
|
|
||||||
Commands:
|
|
||||||
{{template "FormatCommands" .App}}
|
|
||||||
{{end}}\
|
|
||||||
`
|
|
178
vendor/gopkg.in/alecthomas/kingpin.v2/usage.go
generated
vendored
178
vendor/gopkg.in/alecthomas/kingpin.v2/usage.go
generated
vendored
@ -1,178 +0,0 @@
|
|||||||
package kingpin
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"go/doc"
|
|
||||||
"io"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/alecthomas/template"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
preIndent = " "
|
|
||||||
)
|
|
||||||
|
|
||||||
func formatTwoColumns(w io.Writer, indent, padding, width int, rows [][2]string) {
|
|
||||||
// Find size of first column.
|
|
||||||
s := 0
|
|
||||||
for _, row := range rows {
|
|
||||||
if c := len(row[0]); c > s && c < 20 {
|
|
||||||
s = c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
indentStr := strings.Repeat(" ", indent)
|
|
||||||
offsetStr := strings.Repeat(" ", s+padding)
|
|
||||||
|
|
||||||
for _, row := range rows {
|
|
||||||
buf := bytes.NewBuffer(nil)
|
|
||||||
doc.ToText(buf, row[1], "", preIndent, width-s-padding-indent)
|
|
||||||
lines := strings.Split(strings.TrimRight(buf.String(), "\n"), "\n")
|
|
||||||
fmt.Fprintf(w, "%s%-*s%*s", indentStr, s, row[0], padding, "")
|
|
||||||
if len(row[0]) >= 20 {
|
|
||||||
fmt.Fprintf(w, "\n%s%s", indentStr, offsetStr)
|
|
||||||
}
|
|
||||||
fmt.Fprintf(w, "%s\n", lines[0])
|
|
||||||
for _, line := range lines[1:] {
|
|
||||||
fmt.Fprintf(w, "%s%s%s\n", indentStr, offsetStr, line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Usage writes application usage to w. It parses args to determine
|
|
||||||
// appropriate help context, such as which command to show help for.
|
|
||||||
func (a *Application) Usage(args []string) {
|
|
||||||
context, err := a.ParseContext(args)
|
|
||||||
a.FatalIfError(err, "")
|
|
||||||
if err := a.UsageForContextWithTemplate(context, 2, a.usageTemplate); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatAppUsage(app *ApplicationModel) string {
|
|
||||||
s := []string{app.Name}
|
|
||||||
if len(app.Flags) > 0 {
|
|
||||||
s = append(s, app.FlagSummary())
|
|
||||||
}
|
|
||||||
if len(app.Args) > 0 {
|
|
||||||
s = append(s, app.ArgSummary())
|
|
||||||
}
|
|
||||||
return strings.Join(s, " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatCmdUsage(app *ApplicationModel, cmd *CmdModel) string {
|
|
||||||
s := []string{app.Name, cmd.String()}
|
|
||||||
if len(app.Flags) > 0 {
|
|
||||||
s = append(s, app.FlagSummary())
|
|
||||||
}
|
|
||||||
if len(app.Args) > 0 {
|
|
||||||
s = append(s, app.ArgSummary())
|
|
||||||
}
|
|
||||||
return strings.Join(s, " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatFlag(flag *FlagModel) string {
|
|
||||||
flagString := ""
|
|
||||||
if flag.Short != 0 {
|
|
||||||
flagString += fmt.Sprintf("-%c, ", flag.Short)
|
|
||||||
}
|
|
||||||
flagString += fmt.Sprintf("--%s", flag.Name)
|
|
||||||
if !flag.IsBoolFlag() {
|
|
||||||
flagString += fmt.Sprintf("=%s", flag.FormatPlaceHolder())
|
|
||||||
}
|
|
||||||
return flagString
|
|
||||||
}
|
|
||||||
|
|
||||||
type templateParseContext struct {
|
|
||||||
SelectedCommand *CmdModel
|
|
||||||
*FlagGroupModel
|
|
||||||
*ArgGroupModel
|
|
||||||
}
|
|
||||||
|
|
||||||
type templateContext struct {
|
|
||||||
App *ApplicationModel
|
|
||||||
Width int
|
|
||||||
Context *templateParseContext
|
|
||||||
}
|
|
||||||
|
|
||||||
// UsageForContext displays usage information from a ParseContext (obtained from
|
|
||||||
// Application.ParseContext() or Action(f) callbacks).
|
|
||||||
func (a *Application) UsageForContext(context *ParseContext) error {
|
|
||||||
return a.UsageForContextWithTemplate(context, 2, a.usageTemplate)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UsageForContextWithTemplate is the base usage function. You generally don't need to use this.
|
|
||||||
func (a *Application) UsageForContextWithTemplate(context *ParseContext, indent int, tmpl string) error {
|
|
||||||
width := guessWidth(a.writer)
|
|
||||||
funcs := template.FuncMap{
|
|
||||||
"Indent": func(level int) string {
|
|
||||||
return strings.Repeat(" ", level*indent)
|
|
||||||
},
|
|
||||||
"Wrap": func(indent int, s string) string {
|
|
||||||
buf := bytes.NewBuffer(nil)
|
|
||||||
indentText := strings.Repeat(" ", indent)
|
|
||||||
doc.ToText(buf, s, indentText, indentText, width)
|
|
||||||
return buf.String()
|
|
||||||
},
|
|
||||||
"FormatFlag": formatFlag,
|
|
||||||
"FlagsToTwoColumns": func(f []*FlagModel) [][2]string {
|
|
||||||
rows := [][2]string{}
|
|
||||||
for _, flag := range f {
|
|
||||||
if !flag.Hidden {
|
|
||||||
rows = append(rows, [2]string{formatFlag(flag), flag.Help})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rows
|
|
||||||
},
|
|
||||||
"ArgsToTwoColumns": func(a []*ArgModel) [][2]string {
|
|
||||||
rows := [][2]string{}
|
|
||||||
for _, arg := range a {
|
|
||||||
s := "<" + arg.Name + ">"
|
|
||||||
if !arg.Required {
|
|
||||||
s = "[" + s + "]"
|
|
||||||
}
|
|
||||||
rows = append(rows, [2]string{s, arg.Help})
|
|
||||||
}
|
|
||||||
return rows
|
|
||||||
},
|
|
||||||
"FormatTwoColumns": func(rows [][2]string) string {
|
|
||||||
buf := bytes.NewBuffer(nil)
|
|
||||||
formatTwoColumns(buf, indent, indent, width, rows)
|
|
||||||
return buf.String()
|
|
||||||
},
|
|
||||||
"FormatTwoColumnsWithIndent": func(rows [][2]string, indent, padding int) string {
|
|
||||||
buf := bytes.NewBuffer(nil)
|
|
||||||
formatTwoColumns(buf, indent, padding, width, rows)
|
|
||||||
return buf.String()
|
|
||||||
},
|
|
||||||
"FormatAppUsage": formatAppUsage,
|
|
||||||
"FormatCommandUsage": formatCmdUsage,
|
|
||||||
"IsCumulative": func(value Value) bool {
|
|
||||||
_, ok := value.(remainderArg)
|
|
||||||
return ok
|
|
||||||
},
|
|
||||||
"Char": func(c rune) string {
|
|
||||||
return string(c)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
t, err := template.New("usage").Funcs(funcs).Parse(tmpl)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var selectedCommand *CmdModel
|
|
||||||
if context.SelectedCommand != nil {
|
|
||||||
selectedCommand = context.SelectedCommand.Model()
|
|
||||||
}
|
|
||||||
ctx := templateContext{
|
|
||||||
App: a.Model(),
|
|
||||||
Width: width,
|
|
||||||
Context: &templateParseContext{
|
|
||||||
SelectedCommand: selectedCommand,
|
|
||||||
FlagGroupModel: context.flags.Model(),
|
|
||||||
ArgGroupModel: context.arguments.Model(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
return t.Execute(a.writer, ctx)
|
|
||||||
}
|
|
507
vendor/gopkg.in/alecthomas/kingpin.v2/values.go
generated
vendored
507
vendor/gopkg.in/alecthomas/kingpin.v2/values.go
generated
vendored
@ -1,507 +0,0 @@
|
|||||||
package kingpin
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"reflect"
|
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/alecthomas/units"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NOTE: Most of the base type values were lifted from:
|
|
||||||
// http://golang.org/src/pkg/flag/flag.go?s=20146:20222
|
|
||||||
|
|
||||||
// Value is the interface to the dynamic value stored in a flag.
|
|
||||||
// (The default value is represented as a string.)
|
|
||||||
//
|
|
||||||
// If a Value has an IsBoolFlag() bool method returning true, the command-line
|
|
||||||
// parser makes --name equivalent to -name=true rather than using the next
|
|
||||||
// command-line argument, and adds a --no-name counterpart for negating the
|
|
||||||
// flag.
|
|
||||||
type Value interface {
|
|
||||||
String() string
|
|
||||||
Set(string) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Getter is an interface that allows the contents of a Value to be retrieved.
|
|
||||||
// It wraps the Value interface, rather than being part of it, because it
|
|
||||||
// appeared after Go 1 and its compatibility rules. All Value types provided
|
|
||||||
// by this package satisfy the Getter interface.
|
|
||||||
type Getter interface {
|
|
||||||
Value
|
|
||||||
Get() interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optional interface to indicate boolean flags that don't accept a value, and
|
|
||||||
// implicitly have a --no-<x> negation counterpart.
|
|
||||||
type boolFlag interface {
|
|
||||||
Value
|
|
||||||
IsBoolFlag() bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optional interface for arguments that cumulatively consume all remaining
|
|
||||||
// input.
|
|
||||||
type remainderArg interface {
|
|
||||||
Value
|
|
||||||
IsCumulative() bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type accumulator struct {
|
|
||||||
element func(value interface{}) Value
|
|
||||||
typ reflect.Type
|
|
||||||
slice reflect.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use reflection to accumulate values into a slice.
|
|
||||||
//
|
|
||||||
// target := []string{}
|
|
||||||
// newAccumulator(&target, func (value interface{}) Value {
|
|
||||||
// return newStringValue(value.(*string))
|
|
||||||
// })
|
|
||||||
func newAccumulator(slice interface{}, element func(value interface{}) Value) *accumulator {
|
|
||||||
typ := reflect.TypeOf(slice)
|
|
||||||
if typ.Kind() != reflect.Ptr || typ.Elem().Kind() != reflect.Slice {
|
|
||||||
panic("expected a pointer to a slice")
|
|
||||||
}
|
|
||||||
return &accumulator{
|
|
||||||
element: element,
|
|
||||||
typ: typ.Elem().Elem(),
|
|
||||||
slice: reflect.ValueOf(slice),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *accumulator) String() string {
|
|
||||||
out := []string{}
|
|
||||||
s := a.slice.Elem()
|
|
||||||
for i := 0; i < s.Len(); i++ {
|
|
||||||
out = append(out, a.element(s.Index(i).Addr().Interface()).String())
|
|
||||||
}
|
|
||||||
return strings.Join(out, ",")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *accumulator) Set(value string) error {
|
|
||||||
e := reflect.New(a.typ)
|
|
||||||
if err := a.element(e.Interface()).Set(value); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
slice := reflect.Append(a.slice.Elem(), e.Elem())
|
|
||||||
a.slice.Elem().Set(slice)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *accumulator) IsCumulative() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- bool Value
|
|
||||||
type boolValue bool
|
|
||||||
|
|
||||||
func newBoolValue(p *bool) *boolValue {
|
|
||||||
return (*boolValue)(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *boolValue) Set(s string) error {
|
|
||||||
if s == "" {
|
|
||||||
s = "true"
|
|
||||||
}
|
|
||||||
v, err := strconv.ParseBool(s)
|
|
||||||
*b = boolValue(v)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *boolValue) Get() interface{} { return bool(*b) }
|
|
||||||
|
|
||||||
func (b *boolValue) String() string { return fmt.Sprintf("%v", *b) }
|
|
||||||
|
|
||||||
func (b *boolValue) IsBoolFlag() bool { return true }
|
|
||||||
|
|
||||||
// -- int Value
|
|
||||||
type intValue int
|
|
||||||
|
|
||||||
func newIntValue(p *int) *intValue {
|
|
||||||
return (*intValue)(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *intValue) Set(s string) error {
|
|
||||||
v, err := strconv.ParseInt(s, 0, 64)
|
|
||||||
*i = intValue(v)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *intValue) Get() interface{} { return int(*i) }
|
|
||||||
|
|
||||||
func (i *intValue) String() string { return fmt.Sprintf("%v", *i) }
|
|
||||||
|
|
||||||
// -- int64 Value
|
|
||||||
type int64Value int64
|
|
||||||
|
|
||||||
func newInt64Value(p *int64) *int64Value {
|
|
||||||
return (*int64Value)(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *int64Value) Set(s string) error {
|
|
||||||
v, err := strconv.ParseInt(s, 0, 64)
|
|
||||||
*i = int64Value(v)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *int64Value) Get() interface{} { return int64(*i) }
|
|
||||||
|
|
||||||
func (i *int64Value) String() string { return fmt.Sprintf("%v", *i) }
|
|
||||||
|
|
||||||
// -- uint Value
|
|
||||||
type uintValue uint
|
|
||||||
|
|
||||||
func (i *uintValue) Set(s string) error {
|
|
||||||
v, err := strconv.ParseUint(s, 0, 64)
|
|
||||||
*i = uintValue(v)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *uintValue) Get() interface{} { return uint(*i) }
|
|
||||||
|
|
||||||
func (i *uintValue) String() string { return fmt.Sprintf("%v", *i) }
|
|
||||||
|
|
||||||
// -- uint64 Value
|
|
||||||
type uint64Value uint64
|
|
||||||
|
|
||||||
func newUint64Value(p *uint64) *uint64Value {
|
|
||||||
return (*uint64Value)(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *uint64Value) Set(s string) error {
|
|
||||||
v, err := strconv.ParseUint(s, 0, 64)
|
|
||||||
*i = uint64Value(v)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *uint64Value) Get() interface{} { return uint64(*i) }
|
|
||||||
|
|
||||||
func (i *uint64Value) String() string { return fmt.Sprintf("%v", *i) }
|
|
||||||
|
|
||||||
// -- string Value
|
|
||||||
type stringValue string
|
|
||||||
|
|
||||||
func newStringValue(p *string) *stringValue {
|
|
||||||
return (*stringValue)(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stringValue) Set(val string) error {
|
|
||||||
*s = stringValue(val)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stringValue) Get() interface{} { return string(*s) }
|
|
||||||
|
|
||||||
func (s *stringValue) String() string { return fmt.Sprintf("%s", *s) }
|
|
||||||
|
|
||||||
// -- float64 Value
|
|
||||||
type float64Value float64
|
|
||||||
|
|
||||||
func newFloat64Value(p *float64) *float64Value {
|
|
||||||
return (*float64Value)(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *float64Value) Set(s string) error {
|
|
||||||
v, err := strconv.ParseFloat(s, 64)
|
|
||||||
*f = float64Value(v)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *float64Value) Get() interface{} { return float64(*f) }
|
|
||||||
|
|
||||||
func (f *float64Value) String() string { return fmt.Sprintf("%v", *f) }
|
|
||||||
|
|
||||||
// -- time.Duration Value
|
|
||||||
type durationValue time.Duration
|
|
||||||
|
|
||||||
func newDurationValue(p *time.Duration) *durationValue {
|
|
||||||
return (*durationValue)(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *durationValue) Set(s string) error {
|
|
||||||
v, err := time.ParseDuration(s)
|
|
||||||
*d = durationValue(v)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *durationValue) Get() interface{} { return time.Duration(*d) }
|
|
||||||
|
|
||||||
func (d *durationValue) String() string { return (*time.Duration)(d).String() }
|
|
||||||
|
|
||||||
// -- map[string]string Value
|
|
||||||
type stringMapValue map[string]string
|
|
||||||
|
|
||||||
func newStringMapValue(p *map[string]string) *stringMapValue {
|
|
||||||
return (*stringMapValue)(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
var stringMapRegex = regexp.MustCompile("[:=]")
|
|
||||||
|
|
||||||
func (s *stringMapValue) Set(value string) error {
|
|
||||||
parts := stringMapRegex.Split(value, 2)
|
|
||||||
if len(parts) != 2 {
|
|
||||||
return fmt.Errorf("expected KEY=VALUE got '%s'", value)
|
|
||||||
}
|
|
||||||
(*s)[parts[0]] = parts[1]
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func (s *stringMapValue) String() string {
|
|
||||||
return fmt.Sprintf("%s", map[string]string(*s))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stringMapValue) IsCumulative() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- net.IP Value
|
|
||||||
type ipValue net.IP
|
|
||||||
|
|
||||||
func newIPValue(p *net.IP) *ipValue {
|
|
||||||
return (*ipValue)(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *ipValue) Set(value string) error {
|
|
||||||
if ip := net.ParseIP(value); ip == nil {
|
|
||||||
return fmt.Errorf("'%s' is not an IP address", value)
|
|
||||||
} else {
|
|
||||||
*i = *(*ipValue)(&ip)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *ipValue) String() string {
|
|
||||||
return (*net.IP)(i).String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- *net.TCPAddr Value
|
|
||||||
type tcpAddrValue struct {
|
|
||||||
addr **net.TCPAddr
|
|
||||||
}
|
|
||||||
|
|
||||||
func newTCPAddrValue(p **net.TCPAddr) *tcpAddrValue {
|
|
||||||
return &tcpAddrValue{p}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *tcpAddrValue) Set(value string) error {
|
|
||||||
if addr, err := net.ResolveTCPAddr("tcp", value); err != nil {
|
|
||||||
return fmt.Errorf("'%s' is not a valid TCP address: %s", value, err)
|
|
||||||
} else {
|
|
||||||
*i.addr = addr
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *tcpAddrValue) String() string {
|
|
||||||
return (*i.addr).String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- existingFile Value
|
|
||||||
|
|
||||||
type fileStatValue struct {
|
|
||||||
path *string
|
|
||||||
predicate func(os.FileInfo) error
|
|
||||||
}
|
|
||||||
|
|
||||||
func newFileStatValue(p *string, predicate func(os.FileInfo) error) *fileStatValue {
|
|
||||||
return &fileStatValue{
|
|
||||||
path: p,
|
|
||||||
predicate: predicate,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *fileStatValue) Set(value string) error {
|
|
||||||
if s, err := os.Stat(value); os.IsNotExist(err) {
|
|
||||||
return fmt.Errorf("path '%s' does not exist", value)
|
|
||||||
} else if err != nil {
|
|
||||||
return err
|
|
||||||
} else if err := e.predicate(s); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*e.path = value
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *fileStatValue) String() string {
|
|
||||||
return *e.path
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- os.File value
|
|
||||||
|
|
||||||
type fileValue struct {
|
|
||||||
f **os.File
|
|
||||||
flag int
|
|
||||||
perm os.FileMode
|
|
||||||
}
|
|
||||||
|
|
||||||
func newFileValue(p **os.File, flag int, perm os.FileMode) *fileValue {
|
|
||||||
return &fileValue{p, flag, perm}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *fileValue) Set(value string) error {
|
|
||||||
if fd, err := os.OpenFile(value, f.flag, f.perm); err != nil {
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
*f.f = fd
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *fileValue) String() string {
|
|
||||||
if *f.f == nil {
|
|
||||||
return "<nil>"
|
|
||||||
}
|
|
||||||
return (*f.f).Name()
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- url.URL Value
|
|
||||||
type urlValue struct {
|
|
||||||
u **url.URL
|
|
||||||
}
|
|
||||||
|
|
||||||
func newURLValue(p **url.URL) *urlValue {
|
|
||||||
return &urlValue{p}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *urlValue) Set(value string) error {
|
|
||||||
if url, err := url.Parse(value); err != nil {
|
|
||||||
return fmt.Errorf("invalid URL: %s", err)
|
|
||||||
} else {
|
|
||||||
*u.u = url
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *urlValue) String() string {
|
|
||||||
if *u.u == nil {
|
|
||||||
return "<nil>"
|
|
||||||
}
|
|
||||||
return (*u.u).String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- []*url.URL Value
|
|
||||||
type urlListValue []*url.URL
|
|
||||||
|
|
||||||
func newURLListValue(p *[]*url.URL) *urlListValue {
|
|
||||||
return (*urlListValue)(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *urlListValue) Set(value string) error {
|
|
||||||
if url, err := url.Parse(value); err != nil {
|
|
||||||
return fmt.Errorf("invalid URL: %s", err)
|
|
||||||
} else {
|
|
||||||
*u = append(*u, url)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *urlListValue) String() string {
|
|
||||||
out := []string{}
|
|
||||||
for _, url := range *u {
|
|
||||||
out = append(out, url.String())
|
|
||||||
}
|
|
||||||
return strings.Join(out, ",")
|
|
||||||
}
|
|
||||||
|
|
||||||
// A flag whose value must be in a set of options.
|
|
||||||
type enumValue struct {
|
|
||||||
value *string
|
|
||||||
options []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func newEnumFlag(target **string, options ...string) *enumValue {
|
|
||||||
return &enumValue{
|
|
||||||
value: *target,
|
|
||||||
options: options,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *enumValue) String() string {
|
|
||||||
return *a.value
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *enumValue) Set(value string) error {
|
|
||||||
for _, v := range a.options {
|
|
||||||
if v == value {
|
|
||||||
*a.value = value
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fmt.Errorf("enum value must be one of %s, got '%s'", strings.Join(a.options, ","), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- []string Enum Value
|
|
||||||
type enumsValue struct {
|
|
||||||
value *[]string
|
|
||||||
options []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func newEnumsFlag(target *[]string, options ...string) *enumsValue {
|
|
||||||
return &enumsValue{
|
|
||||||
value: target,
|
|
||||||
options: options,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *enumsValue) Set(value string) error {
|
|
||||||
for _, v := range s.options {
|
|
||||||
if v == value {
|
|
||||||
*s.value = append(*s.value, value)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fmt.Errorf("enum value must be one of %s, got '%s'", strings.Join(s.options, ","), value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *enumsValue) String() string {
|
|
||||||
return strings.Join(*s.value, ",")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *enumsValue) IsCumulative() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- units.Base2Bytes Value
|
|
||||||
type bytesValue units.Base2Bytes
|
|
||||||
|
|
||||||
func newBytesValue(p *units.Base2Bytes) *bytesValue {
|
|
||||||
return (*bytesValue)(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *bytesValue) Set(s string) error {
|
|
||||||
v, err := units.ParseBase2Bytes(s)
|
|
||||||
*d = bytesValue(v)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *bytesValue) Get() interface{} { return units.Base2Bytes(*d) }
|
|
||||||
|
|
||||||
func (d *bytesValue) String() string { return (*units.Base2Bytes)(d).String() }
|
|
||||||
|
|
||||||
func newExistingFileValue(target *string) *fileStatValue {
|
|
||||||
return newFileStatValue(target, func(s os.FileInfo) error {
|
|
||||||
if s.IsDir() {
|
|
||||||
return fmt.Errorf("'%s' is a directory", s.Name())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func newExistingDirValue(target *string) *fileStatValue {
|
|
||||||
return newFileStatValue(target, func(s os.FileInfo) error {
|
|
||||||
if !s.IsDir() {
|
|
||||||
return fmt.Errorf("'%s' is a file", s.Name())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func newExistingFileOrDirValue(target *string) *fileStatValue {
|
|
||||||
return newFileStatValue(target, func(s os.FileInfo) error { return nil })
|
|
||||||
}
|
|
188
vendor/gopkg.in/yaml.v2/LICENSE
generated
vendored
Normal file
188
vendor/gopkg.in/yaml.v2/LICENSE
generated
vendored
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
|
||||||
|
Copyright (c) 2011-2014 - Canonical Inc.
|
||||||
|
|
||||||
|
This software is licensed under the LGPLv3, included below.
|
||||||
|
|
||||||
|
As a special exception to the GNU Lesser General Public License version 3
|
||||||
|
("LGPL3"), the copyright holders of this Library give you permission to
|
||||||
|
convey to a third party a Combined Work that links statically or dynamically
|
||||||
|
to this Library without providing any Minimal Corresponding Source or
|
||||||
|
Minimal Application Code as set out in 4d or providing the installation
|
||||||
|
information set out in section 4e, provided that you comply with the other
|
||||||
|
provisions of LGPL3 and provided that you meet, for the Application the
|
||||||
|
terms and conditions of the license(s) which apply to the Application.
|
||||||
|
|
||||||
|
Except as stated in this special exception, the provisions of LGPL3 will
|
||||||
|
continue to comply in full to this Library. If you modify this Library, you
|
||||||
|
may apply this exception to your version of this Library, but you are not
|
||||||
|
obliged to do so. If you do not wish to do so, delete this exception
|
||||||
|
statement from your version. This exception does not (and cannot) modify any
|
||||||
|
license terms which apply to the Application, with which you must still
|
||||||
|
comply.
|
||||||
|
|
||||||
|
|
||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
|
||||||
|
This version of the GNU Lesser General Public License incorporates
|
||||||
|
the terms and conditions of version 3 of the GNU General Public
|
||||||
|
License, supplemented by the additional permissions listed below.
|
||||||
|
|
||||||
|
0. Additional Definitions.
|
||||||
|
|
||||||
|
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||||
|
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||||
|
General Public License.
|
||||||
|
|
||||||
|
"The Library" refers to a covered work governed by this License,
|
||||||
|
other than an Application or a Combined Work as defined below.
|
||||||
|
|
||||||
|
An "Application" is any work that makes use of an interface provided
|
||||||
|
by the Library, but which is not otherwise based on the Library.
|
||||||
|
Defining a subclass of a class defined by the Library is deemed a mode
|
||||||
|
of using an interface provided by the Library.
|
||||||
|
|
||||||
|
A "Combined Work" is a work produced by combining or linking an
|
||||||
|
Application with the Library. The particular version of the Library
|
||||||
|
with which the Combined Work was made is also called the "Linked
|
||||||
|
Version".
|
||||||
|
|
||||||
|
The "Minimal Corresponding Source" for a Combined Work means the
|
||||||
|
Corresponding Source for the Combined Work, excluding any source code
|
||||||
|
for portions of the Combined Work that, considered in isolation, are
|
||||||
|
based on the Application, and not on the Linked Version.
|
||||||
|
|
||||||
|
The "Corresponding Application Code" for a Combined Work means the
|
||||||
|
object code and/or source code for the Application, including any data
|
||||||
|
and utility programs needed for reproducing the Combined Work from the
|
||||||
|
Application, but excluding the System Libraries of the Combined Work.
|
||||||
|
|
||||||
|
1. Exception to Section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
You may convey a covered work under sections 3 and 4 of this License
|
||||||
|
without being bound by section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
2. Conveying Modified Versions.
|
||||||
|
|
||||||
|
If you modify a copy of the Library, and, in your modifications, a
|
||||||
|
facility refers to a function or data to be supplied by an Application
|
||||||
|
that uses the facility (other than as an argument passed when the
|
||||||
|
facility is invoked), then you may convey a copy of the modified
|
||||||
|
version:
|
||||||
|
|
||||||
|
a) under this License, provided that you make a good faith effort to
|
||||||
|
ensure that, in the event an Application does not supply the
|
||||||
|
function or data, the facility still operates, and performs
|
||||||
|
whatever part of its purpose remains meaningful, or
|
||||||
|
|
||||||
|
b) under the GNU GPL, with none of the additional permissions of
|
||||||
|
this License applicable to that copy.
|
||||||
|
|
||||||
|
3. Object Code Incorporating Material from Library Header Files.
|
||||||
|
|
||||||
|
The object code form of an Application may incorporate material from
|
||||||
|
a header file that is part of the Library. You may convey such object
|
||||||
|
code under terms of your choice, provided that, if the incorporated
|
||||||
|
material is not limited to numerical parameters, data structure
|
||||||
|
layouts and accessors, or small macros, inline functions and templates
|
||||||
|
(ten or fewer lines in length), you do both of the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the object code that the
|
||||||
|
Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
4. Combined Works.
|
||||||
|
|
||||||
|
You may convey a Combined Work under terms of your choice that,
|
||||||
|
taken together, effectively do not restrict modification of the
|
||||||
|
portions of the Library contained in the Combined Work and reverse
|
||||||
|
engineering for debugging such modifications, if you also do each of
|
||||||
|
the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the Combined Work that
|
||||||
|
the Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
c) For a Combined Work that displays copyright notices during
|
||||||
|
execution, include the copyright notice for the Library among
|
||||||
|
these notices, as well as a reference directing the user to the
|
||||||
|
copies of the GNU GPL and this license document.
|
||||||
|
|
||||||
|
d) Do one of the following:
|
||||||
|
|
||||||
|
0) Convey the Minimal Corresponding Source under the terms of this
|
||||||
|
License, and the Corresponding Application Code in a form
|
||||||
|
suitable for, and under terms that permit, the user to
|
||||||
|
recombine or relink the Application with a modified version of
|
||||||
|
the Linked Version to produce a modified Combined Work, in the
|
||||||
|
manner specified by section 6 of the GNU GPL for conveying
|
||||||
|
Corresponding Source.
|
||||||
|
|
||||||
|
1) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (a) uses at run time
|
||||||
|
a copy of the Library already present on the user's computer
|
||||||
|
system, and (b) will operate properly with a modified version
|
||||||
|
of the Library that is interface-compatible with the Linked
|
||||||
|
Version.
|
||||||
|
|
||||||
|
e) Provide Installation Information, but only if you would otherwise
|
||||||
|
be required to provide such information under section 6 of the
|
||||||
|
GNU GPL, and only to the extent that such information is
|
||||||
|
necessary to install and execute a modified version of the
|
||||||
|
Combined Work produced by recombining or relinking the
|
||||||
|
Application with a modified version of the Linked Version. (If
|
||||||
|
you use option 4d0, the Installation Information must accompany
|
||||||
|
the Minimal Corresponding Source and Corresponding Application
|
||||||
|
Code. If you use option 4d1, you must provide the Installation
|
||||||
|
Information in the manner specified by section 6 of the GNU GPL
|
||||||
|
for conveying Corresponding Source.)
|
||||||
|
|
||||||
|
5. Combined Libraries.
|
||||||
|
|
||||||
|
You may place library facilities that are a work based on the
|
||||||
|
Library side by side in a single library together with other library
|
||||||
|
facilities that are not Applications and are not covered by this
|
||||||
|
License, and convey such a combined library under terms of your
|
||||||
|
choice, if you do both of the following:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work based
|
||||||
|
on the Library, uncombined with any other library facilities,
|
||||||
|
conveyed under the terms of this License.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library that part of it
|
||||||
|
is a work based on the Library, and explaining where to find the
|
||||||
|
accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
6. Revised Versions of the GNU Lesser General Public License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the GNU Lesser General Public License from time to time. Such new
|
||||||
|
versions will be similar in spirit to the present version, but may
|
||||||
|
differ in detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Library as you received it specifies that a certain numbered version
|
||||||
|
of the GNU Lesser General Public License "or any later version"
|
||||||
|
applies to it, you have the option of following the terms and
|
||||||
|
conditions either of that published version or of any later version
|
||||||
|
published by the Free Software Foundation. If the Library as you
|
||||||
|
received it does not specify a version number of the GNU Lesser
|
||||||
|
General Public License, you may choose any version of the GNU Lesser
|
||||||
|
General Public License ever published by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Library as you received it specifies that a proxy can decide
|
||||||
|
whether future versions of the GNU Lesser General Public License shall
|
||||||
|
apply, that proxy's public statement of acceptance of any version is
|
||||||
|
permanent authorization for you to choose that version for the
|
||||||
|
Library.
|
14
vendor/gopkg.in/alecthomas/kingpin.v2/COPYING → vendor/gopkg.in/yaml.v2/LICENSE.libyaml
generated
vendored
14
vendor/gopkg.in/alecthomas/kingpin.v2/COPYING → vendor/gopkg.in/yaml.v2/LICENSE.libyaml
generated
vendored
@ -1,4 +1,16 @@
|
|||||||
Copyright (C) 2014 Alec Thomas
|
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
|
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
|
this software and associated documentation files (the "Software"), to deal in
|
131
vendor/gopkg.in/yaml.v2/README.md
generated
vendored
Normal file
131
vendor/gopkg.in/yaml.v2/README.md
generated
vendored
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
# 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 LGPL with an exception that allows it to be linked statically. Please see the LICENSE file for details.
|
||||||
|
|
||||||
|
|
||||||
|
Example
|
||||||
|
-------
|
||||||
|
|
||||||
|
```Go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var data = `
|
||||||
|
a: Easy!
|
||||||
|
b:
|
||||||
|
c: 2
|
||||||
|
d: [3, 4]
|
||||||
|
`
|
||||||
|
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
742
vendor/gopkg.in/yaml.v2/apic.go
generated
vendored
Normal file
742
vendor/gopkg.in/yaml.v2/apic.go
generated
vendored
Normal file
@ -0,0 +1,742 @@
|
|||||||
|
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
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//
|
683
vendor/gopkg.in/yaml.v2/decode.go
generated
vendored
Normal file
683
vendor/gopkg.in/yaml.v2/decode.go
generated
vendored
Normal file
@ -0,0 +1,683 @@
|
|||||||
|
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)))
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
mapItemType = reflect.TypeOf(MapItem{})
|
||||||
|
durationType = reflect.TypeOf(time.Duration(0))
|
||||||
|
defaultMapType = reflect.TypeOf(map[interface{}]interface{}{})
|
||||||
|
ifaceType = defaultMapType.Elem()
|
||||||
|
)
|
||||||
|
|
||||||
|
func newDecoder() *decoder {
|
||||||
|
d := &decoder{mapType: defaultMapType}
|
||||||
|
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 == "") {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
988
vendor/gopkg.in/yaml.v2/decode_test.go
generated
vendored
Normal file
988
vendor/gopkg.in/yaml.v2/decode_test.go
generated
vendored
Normal file
@ -0,0 +1,988 @@
|
|||||||
|
package yaml_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
. "gopkg.in/check.v1"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
"math"
|
||||||
|
"net"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var unmarshalIntTest = 123
|
||||||
|
|
||||||
|
var unmarshalTests = []struct {
|
||||||
|
data string
|
||||||
|
value interface{}
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"",
|
||||||
|
&struct{}{},
|
||||||
|
}, {
|
||||||
|
"{}", &struct{}{},
|
||||||
|
}, {
|
||||||
|
"v: hi",
|
||||||
|
map[string]string{"v": "hi"},
|
||||||
|
}, {
|
||||||
|
"v: hi", map[string]interface{}{"v": "hi"},
|
||||||
|
}, {
|
||||||
|
"v: true",
|
||||||
|
map[string]string{"v": "true"},
|
||||||
|
}, {
|
||||||
|
"v: true",
|
||||||
|
map[string]interface{}{"v": true},
|
||||||
|
}, {
|
||||||
|
"v: 10",
|
||||||
|
map[string]interface{}{"v": 10},
|
||||||
|
}, {
|
||||||
|
"v: 0b10",
|
||||||
|
map[string]interface{}{"v": 2},
|
||||||
|
}, {
|
||||||
|
"v: 0xA",
|
||||||
|
map[string]interface{}{"v": 10},
|
||||||
|
}, {
|
||||||
|
"v: 4294967296",
|
||||||
|
map[string]int64{"v": 4294967296},
|
||||||
|
}, {
|
||||||
|
"v: 0.1",
|
||||||
|
map[string]interface{}{"v": 0.1},
|
||||||
|
}, {
|
||||||
|
"v: .1",
|
||||||
|
map[string]interface{}{"v": 0.1},
|
||||||
|
}, {
|
||||||
|
"v: .Inf",
|
||||||
|
map[string]interface{}{"v": math.Inf(+1)},
|
||||||
|
}, {
|
||||||
|
"v: -.Inf",
|
||||||
|
map[string]interface{}{"v": math.Inf(-1)},
|
||||||
|
}, {
|
||||||
|
"v: -10",
|
||||||
|
map[string]interface{}{"v": -10},
|
||||||
|
}, {
|
||||||
|
"v: -.1",
|
||||||
|
map[string]interface{}{"v": -0.1},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Simple values.
|
||||||
|
{
|
||||||
|
"123",
|
||||||
|
&unmarshalIntTest,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Floats from spec
|
||||||
|
{
|
||||||
|
"canonical: 6.8523e+5",
|
||||||
|
map[string]interface{}{"canonical": 6.8523e+5},
|
||||||
|
}, {
|
||||||
|
"expo: 685.230_15e+03",
|
||||||
|
map[string]interface{}{"expo": 685.23015e+03},
|
||||||
|
}, {
|
||||||
|
"fixed: 685_230.15",
|
||||||
|
map[string]interface{}{"fixed": 685230.15},
|
||||||
|
}, {
|
||||||
|
"neginf: -.inf",
|
||||||
|
map[string]interface{}{"neginf": math.Inf(-1)},
|
||||||
|
}, {
|
||||||
|
"fixed: 685_230.15",
|
||||||
|
map[string]float64{"fixed": 685230.15},
|
||||||
|
},
|
||||||
|
//{"sexa: 190:20:30.15", map[string]interface{}{"sexa": 0}}, // Unsupported
|
||||||
|
//{"notanum: .NaN", map[string]interface{}{"notanum": math.NaN()}}, // Equality of NaN fails.
|
||||||
|
|
||||||
|
// Bools from spec
|
||||||
|
{
|
||||||
|
"canonical: y",
|
||||||
|
map[string]interface{}{"canonical": true},
|
||||||
|
}, {
|
||||||
|
"answer: NO",
|
||||||
|
map[string]interface{}{"answer": false},
|
||||||
|
}, {
|
||||||
|
"logical: True",
|
||||||
|
map[string]interface{}{"logical": true},
|
||||||
|
}, {
|
||||||
|
"option: on",
|
||||||
|
map[string]interface{}{"option": true},
|
||||||
|
}, {
|
||||||
|
"option: on",
|
||||||
|
map[string]bool{"option": true},
|
||||||
|
},
|
||||||
|
// Ints from spec
|
||||||
|
{
|
||||||
|
"canonical: 685230",
|
||||||
|
map[string]interface{}{"canonical": 685230},
|
||||||
|
}, {
|
||||||
|
"decimal: +685_230",
|
||||||
|
map[string]interface{}{"decimal": 685230},
|
||||||
|
}, {
|
||||||
|
"octal: 02472256",
|
||||||
|
map[string]interface{}{"octal": 685230},
|
||||||
|
}, {
|
||||||
|
"hexa: 0x_0A_74_AE",
|
||||||
|
map[string]interface{}{"hexa": 685230},
|
||||||
|
}, {
|
||||||
|
"bin: 0b1010_0111_0100_1010_1110",
|
||||||
|
map[string]interface{}{"bin": 685230},
|
||||||
|
}, {
|
||||||
|
"bin: -0b101010",
|
||||||
|
map[string]interface{}{"bin": -42},
|
||||||
|
}, {
|
||||||
|
"decimal: +685_230",
|
||||||
|
map[string]int{"decimal": 685230},
|
||||||
|
},
|
||||||
|
|
||||||
|
//{"sexa: 190:20:30", map[string]interface{}{"sexa": 0}}, // Unsupported
|
||||||
|
|
||||||
|
// Nulls from spec
|
||||||
|
{
|
||||||
|
"empty:",
|
||||||
|
map[string]interface{}{"empty": nil},
|
||||||
|
}, {
|
||||||
|
"canonical: ~",
|
||||||
|
map[string]interface{}{"canonical": nil},
|
||||||
|
}, {
|
||||||
|
"english: null",
|
||||||
|
map[string]interface{}{"english": nil},
|
||||||
|
}, {
|
||||||
|
"~: null key",
|
||||||
|
map[interface{}]string{nil: "null key"},
|
||||||
|
}, {
|
||||||
|
"empty:",
|
||||||
|
map[string]*bool{"empty": nil},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Flow sequence
|
||||||
|
{
|
||||||
|
"seq: [A,B]",
|
||||||
|
map[string]interface{}{"seq": []interface{}{"A", "B"}},
|
||||||
|
}, {
|
||||||
|
"seq: [A,B,C,]",
|
||||||
|
map[string][]string{"seq": []string{"A", "B", "C"}},
|
||||||
|
}, {
|
||||||
|
"seq: [A,1,C]",
|
||||||
|
map[string][]string{"seq": []string{"A", "1", "C"}},
|
||||||
|
}, {
|
||||||
|
"seq: [A,1,C]",
|
||||||
|
map[string][]int{"seq": []int{1}},
|
||||||
|
}, {
|
||||||
|
"seq: [A,1,C]",
|
||||||
|
map[string]interface{}{"seq": []interface{}{"A", 1, "C"}},
|
||||||
|
},
|
||||||
|
// Block sequence
|
||||||
|
{
|
||||||
|
"seq:\n - A\n - B",
|
||||||
|
map[string]interface{}{"seq": []interface{}{"A", "B"}},
|
||||||
|
}, {
|
||||||
|
"seq:\n - A\n - B\n - C",
|
||||||
|
map[string][]string{"seq": []string{"A", "B", "C"}},
|
||||||
|
}, {
|
||||||
|
"seq:\n - A\n - 1\n - C",
|
||||||
|
map[string][]string{"seq": []string{"A", "1", "C"}},
|
||||||
|
}, {
|
||||||
|
"seq:\n - A\n - 1\n - C",
|
||||||
|
map[string][]int{"seq": []int{1}},
|
||||||
|
}, {
|
||||||
|
"seq:\n - A\n - 1\n - C",
|
||||||
|
map[string]interface{}{"seq": []interface{}{"A", 1, "C"}},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Literal block scalar
|
||||||
|
{
|
||||||
|
"scalar: | # Comment\n\n literal\n\n \ttext\n\n",
|
||||||
|
map[string]string{"scalar": "\nliteral\n\n\ttext\n"},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Folded block scalar
|
||||||
|
{
|
||||||
|
"scalar: > # Comment\n\n folded\n line\n \n next\n line\n * one\n * two\n\n last\n line\n\n",
|
||||||
|
map[string]string{"scalar": "\nfolded line\nnext line\n * one\n * two\n\nlast line\n"},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Map inside interface with no type hints.
|
||||||
|
{
|
||||||
|
"a: {b: c}",
|
||||||
|
map[interface{}]interface{}{"a": map[interface{}]interface{}{"b": "c"}},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Structs and type conversions.
|
||||||
|
{
|
||||||
|
"hello: world",
|
||||||
|
&struct{ Hello string }{"world"},
|
||||||
|
}, {
|
||||||
|
"a: {b: c}",
|
||||||
|
&struct{ A struct{ B string } }{struct{ B string }{"c"}},
|
||||||
|
}, {
|
||||||
|
"a: {b: c}",
|
||||||
|
&struct{ A *struct{ B string } }{&struct{ B string }{"c"}},
|
||||||
|
}, {
|
||||||
|
"a: {b: c}",
|
||||||
|
&struct{ A map[string]string }{map[string]string{"b": "c"}},
|
||||||
|
}, {
|
||||||
|
"a: {b: c}",
|
||||||
|
&struct{ A *map[string]string }{&map[string]string{"b": "c"}},
|
||||||
|
}, {
|
||||||
|
"a:",
|
||||||
|
&struct{ A map[string]string }{},
|
||||||
|
}, {
|
||||||
|
"a: 1",
|
||||||
|
&struct{ A int }{1},
|
||||||
|
}, {
|
||||||
|
"a: 1",
|
||||||
|
&struct{ A float64 }{1},
|
||||||
|
}, {
|
||||||
|
"a: 1.0",
|
||||||
|
&struct{ A int }{1},
|
||||||
|
}, {
|
||||||
|
"a: 1.0",
|
||||||
|
&struct{ A uint }{1},
|
||||||
|
}, {
|
||||||
|
"a: [1, 2]",
|
||||||
|
&struct{ A []int }{[]int{1, 2}},
|
||||||
|
}, {
|
||||||
|
"a: 1",
|
||||||
|
&struct{ B int }{0},
|
||||||
|
}, {
|
||||||
|
"a: 1",
|
||||||
|
&struct {
|
||||||
|
B int "a"
|
||||||
|
}{1},
|
||||||
|
}, {
|
||||||
|
"a: y",
|
||||||
|
&struct{ A bool }{true},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Some cross type conversions
|
||||||
|
{
|
||||||
|
"v: 42",
|
||||||
|
map[string]uint{"v": 42},
|
||||||
|
}, {
|
||||||
|
"v: -42",
|
||||||
|
map[string]uint{},
|
||||||
|
}, {
|
||||||
|
"v: 4294967296",
|
||||||
|
map[string]uint64{"v": 4294967296},
|
||||||
|
}, {
|
||||||
|
"v: -4294967296",
|
||||||
|
map[string]uint64{},
|
||||||
|
},
|
||||||
|
|
||||||
|
// int
|
||||||
|
{
|
||||||
|
"int_max: 2147483647",
|
||||||
|
map[string]int{"int_max": math.MaxInt32},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"int_min: -2147483648",
|
||||||
|
map[string]int{"int_min": math.MinInt32},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"int_overflow: 9223372036854775808", // math.MaxInt64 + 1
|
||||||
|
map[string]int{},
|
||||||
|
},
|
||||||
|
|
||||||
|
// int64
|
||||||
|
{
|
||||||
|
"int64_max: 9223372036854775807",
|
||||||
|
map[string]int64{"int64_max": math.MaxInt64},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"int64_max_base2: 0b111111111111111111111111111111111111111111111111111111111111111",
|
||||||
|
map[string]int64{"int64_max_base2": math.MaxInt64},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"int64_min: -9223372036854775808",
|
||||||
|
map[string]int64{"int64_min": math.MinInt64},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"int64_neg_base2: -0b111111111111111111111111111111111111111111111111111111111111111",
|
||||||
|
map[string]int64{"int64_neg_base2": -math.MaxInt64},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"int64_overflow: 9223372036854775808", // math.MaxInt64 + 1
|
||||||
|
map[string]int64{},
|
||||||
|
},
|
||||||
|
|
||||||
|
// uint
|
||||||
|
{
|
||||||
|
"uint_min: 0",
|
||||||
|
map[string]uint{"uint_min": 0},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uint_max: 4294967295",
|
||||||
|
map[string]uint{"uint_max": math.MaxUint32},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uint_underflow: -1",
|
||||||
|
map[string]uint{},
|
||||||
|
},
|
||||||
|
|
||||||
|
// uint64
|
||||||
|
{
|
||||||
|
"uint64_min: 0",
|
||||||
|
map[string]uint{"uint64_min": 0},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uint64_max: 18446744073709551615",
|
||||||
|
map[string]uint64{"uint64_max": math.MaxUint64},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uint64_max_base2: 0b1111111111111111111111111111111111111111111111111111111111111111",
|
||||||
|
map[string]uint64{"uint64_max_base2": math.MaxUint64},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uint64_maxint64: 9223372036854775807",
|
||||||
|
map[string]uint64{"uint64_maxint64": math.MaxInt64},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uint64_underflow: -1",
|
||||||
|
map[string]uint64{},
|
||||||
|
},
|
||||||
|
|
||||||
|
// float32
|
||||||
|
{
|
||||||
|
"float32_max: 3.40282346638528859811704183484516925440e+38",
|
||||||
|
map[string]float32{"float32_max": math.MaxFloat32},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"float32_nonzero: 1.401298464324817070923729583289916131280e-45",
|
||||||
|
map[string]float32{"float32_nonzero": math.SmallestNonzeroFloat32},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"float32_maxuint64: 18446744073709551615",
|
||||||
|
map[string]float32{"float32_maxuint64": float32(math.MaxUint64)},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"float32_maxuint64+1: 18446744073709551616",
|
||||||
|
map[string]float32{"float32_maxuint64+1": float32(math.MaxUint64 + 1)},
|
||||||
|
},
|
||||||
|
|
||||||
|
// float64
|
||||||
|
{
|
||||||
|
"float64_max: 1.797693134862315708145274237317043567981e+308",
|
||||||
|
map[string]float64{"float64_max": math.MaxFloat64},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"float64_nonzero: 4.940656458412465441765687928682213723651e-324",
|
||||||
|
map[string]float64{"float64_nonzero": math.SmallestNonzeroFloat64},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"float64_maxuint64: 18446744073709551615",
|
||||||
|
map[string]float64{"float64_maxuint64": float64(math.MaxUint64)},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"float64_maxuint64+1: 18446744073709551616",
|
||||||
|
map[string]float64{"float64_maxuint64+1": float64(math.MaxUint64 + 1)},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Overflow cases.
|
||||||
|
{
|
||||||
|
"v: 4294967297",
|
||||||
|
map[string]int32{},
|
||||||
|
}, {
|
||||||
|
"v: 128",
|
||||||
|
map[string]int8{},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Quoted values.
|
||||||
|
{
|
||||||
|
"'1': '\"2\"'",
|
||||||
|
map[interface{}]interface{}{"1": "\"2\""},
|
||||||
|
}, {
|
||||||
|
"v:\n- A\n- 'B\n\n C'\n",
|
||||||
|
map[string][]string{"v": []string{"A", "B\nC"}},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Explicit tags.
|
||||||
|
{
|
||||||
|
"v: !!float '1.1'",
|
||||||
|
map[string]interface{}{"v": 1.1},
|
||||||
|
}, {
|
||||||
|
"v: !!null ''",
|
||||||
|
map[string]interface{}{"v": nil},
|
||||||
|
}, {
|
||||||
|
"%TAG !y! tag:yaml.org,2002:\n---\nv: !y!int '1'",
|
||||||
|
map[string]interface{}{"v": 1},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Anchors and aliases.
|
||||||
|
{
|
||||||
|
"a: &x 1\nb: &y 2\nc: *x\nd: *y\n",
|
||||||
|
&struct{ A, B, C, D int }{1, 2, 1, 2},
|
||||||
|
}, {
|
||||||
|
"a: &a {c: 1}\nb: *a",
|
||||||
|
&struct {
|
||||||
|
A, B struct {
|
||||||
|
C int
|
||||||
|
}
|
||||||
|
}{struct{ C int }{1}, struct{ C int }{1}},
|
||||||
|
}, {
|
||||||
|
"a: &a [1, 2]\nb: *a",
|
||||||
|
&struct{ B []int }{[]int{1, 2}},
|
||||||
|
}, {
|
||||||
|
"b: *a\na: &a {c: 1}",
|
||||||
|
&struct {
|
||||||
|
A, B struct {
|
||||||
|
C int
|
||||||
|
}
|
||||||
|
}{struct{ C int }{1}, struct{ C int }{1}},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Bug #1133337
|
||||||
|
{
|
||||||
|
"foo: ''",
|
||||||
|
map[string]*string{"foo": new(string)},
|
||||||
|
}, {
|
||||||
|
"foo: null",
|
||||||
|
map[string]string{"foo": ""},
|
||||||
|
}, {
|
||||||
|
"foo: null",
|
||||||
|
map[string]interface{}{"foo": nil},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Ignored field
|
||||||
|
{
|
||||||
|
"a: 1\nb: 2\n",
|
||||||
|
&struct {
|
||||||
|
A int
|
||||||
|
B int "-"
|
||||||
|
}{1, 0},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Bug #1191981
|
||||||
|
{
|
||||||
|
"" +
|
||||||
|
"%YAML 1.1\n" +
|
||||||
|
"--- !!str\n" +
|
||||||
|
`"Generic line break (no glyph)\n\` + "\n" +
|
||||||
|
` Generic line break (glyphed)\n\` + "\n" +
|
||||||
|
` Line separator\u2028\` + "\n" +
|
||||||
|
` Paragraph separator\u2029"` + "\n",
|
||||||
|
"" +
|
||||||
|
"Generic line break (no glyph)\n" +
|
||||||
|
"Generic line break (glyphed)\n" +
|
||||||
|
"Line separator\u2028Paragraph separator\u2029",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Struct inlining
|
||||||
|
{
|
||||||
|
"a: 1\nb: 2\nc: 3\n",
|
||||||
|
&struct {
|
||||||
|
A int
|
||||||
|
C inlineB `yaml:",inline"`
|
||||||
|
}{1, inlineB{2, inlineC{3}}},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Map inlining
|
||||||
|
{
|
||||||
|
"a: 1\nb: 2\nc: 3\n",
|
||||||
|
&struct {
|
||||||
|
A int
|
||||||
|
C map[string]int `yaml:",inline"`
|
||||||
|
}{1, map[string]int{"b": 2, "c": 3}},
|
||||||
|
},
|
||||||
|
|
||||||
|
// bug 1243827
|
||||||
|
{
|
||||||
|
"a: -b_c",
|
||||||
|
map[string]interface{}{"a": "-b_c"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a: +b_c",
|
||||||
|
map[string]interface{}{"a": "+b_c"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a: 50cent_of_dollar",
|
||||||
|
map[string]interface{}{"a": "50cent_of_dollar"},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Duration
|
||||||
|
{
|
||||||
|
"a: 3s",
|
||||||
|
map[string]time.Duration{"a": 3 * time.Second},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Issue #24.
|
||||||
|
{
|
||||||
|
"a: <foo>",
|
||||||
|
map[string]string{"a": "<foo>"},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Base 60 floats are obsolete and unsupported.
|
||||||
|
{
|
||||||
|
"a: 1:1\n",
|
||||||
|
map[string]string{"a": "1:1"},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Binary data.
|
||||||
|
{
|
||||||
|
"a: !!binary gIGC\n",
|
||||||
|
map[string]string{"a": "\x80\x81\x82"},
|
||||||
|
}, {
|
||||||
|
"a: !!binary |\n " + strings.Repeat("kJCQ", 17) + "kJ\n CQ\n",
|
||||||
|
map[string]string{"a": strings.Repeat("\x90", 54)},
|
||||||
|
}, {
|
||||||
|
"a: !!binary |\n " + strings.Repeat("A", 70) + "\n ==\n",
|
||||||
|
map[string]string{"a": strings.Repeat("\x00", 52)},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Ordered maps.
|
||||||
|
{
|
||||||
|
"{b: 2, a: 1, d: 4, c: 3, sub: {e: 5}}",
|
||||||
|
&yaml.MapSlice{{"b", 2}, {"a", 1}, {"d", 4}, {"c", 3}, {"sub", yaml.MapSlice{{"e", 5}}}},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Issue #39.
|
||||||
|
{
|
||||||
|
"a:\n b:\n c: d\n",
|
||||||
|
map[string]struct{ B interface{} }{"a": {map[interface{}]interface{}{"c": "d"}}},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Custom map type.
|
||||||
|
{
|
||||||
|
"a: {b: c}",
|
||||||
|
M{"a": M{"b": "c"}},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Support encoding.TextUnmarshaler.
|
||||||
|
{
|
||||||
|
"a: 1.2.3.4\n",
|
||||||
|
map[string]net.IP{"a": net.IPv4(1, 2, 3, 4)},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a: 2015-02-24T18:19:39Z\n",
|
||||||
|
map[string]time.Time{"a": time.Unix(1424801979, 0)},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Encode empty lists as zero-length slices.
|
||||||
|
{
|
||||||
|
"a: []",
|
||||||
|
&struct{ A []int }{[]int{}},
|
||||||
|
},
|
||||||
|
|
||||||
|
// UTF-16-LE
|
||||||
|
{
|
||||||
|
"\xff\xfe\xf1\x00o\x00\xf1\x00o\x00:\x00 \x00v\x00e\x00r\x00y\x00 \x00y\x00e\x00s\x00\n\x00",
|
||||||
|
M{"ñoño": "very yes"},
|
||||||
|
},
|
||||||
|
// UTF-16-LE with surrogate.
|
||||||
|
{
|
||||||
|
"\xff\xfe\xf1\x00o\x00\xf1\x00o\x00:\x00 \x00v\x00e\x00r\x00y\x00 \x00y\x00e\x00s\x00 \x00=\xd8\xd4\xdf\n\x00",
|
||||||
|
M{"ñoño": "very yes 🟔"},
|
||||||
|
},
|
||||||
|
|
||||||
|
// UTF-16-BE
|
||||||
|
{
|
||||||
|
"\xfe\xff\x00\xf1\x00o\x00\xf1\x00o\x00:\x00 \x00v\x00e\x00r\x00y\x00 \x00y\x00e\x00s\x00\n",
|
||||||
|
M{"ñoño": "very yes"},
|
||||||
|
},
|
||||||
|
// UTF-16-BE with surrogate.
|
||||||
|
{
|
||||||
|
"\xfe\xff\x00\xf1\x00o\x00\xf1\x00o\x00:\x00 \x00v\x00e\x00r\x00y\x00 \x00y\x00e\x00s\x00 \xd8=\xdf\xd4\x00\n",
|
||||||
|
M{"ñoño": "very yes 🟔"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
type M map[interface{}]interface{}
|
||||||
|
|
||||||
|
type inlineB struct {
|
||||||
|
B int
|
||||||
|
inlineC `yaml:",inline"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type inlineC struct {
|
||||||
|
C int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestUnmarshal(c *C) {
|
||||||
|
for _, item := range unmarshalTests {
|
||||||
|
t := reflect.ValueOf(item.value).Type()
|
||||||
|
var value interface{}
|
||||||
|
switch t.Kind() {
|
||||||
|
case reflect.Map:
|
||||||
|
value = reflect.MakeMap(t).Interface()
|
||||||
|
case reflect.String:
|
||||||
|
value = reflect.New(t).Interface()
|
||||||
|
case reflect.Ptr:
|
||||||
|
value = reflect.New(t.Elem()).Interface()
|
||||||
|
default:
|
||||||
|
c.Fatalf("missing case for %s", t)
|
||||||
|
}
|
||||||
|
err := yaml.Unmarshal([]byte(item.data), value)
|
||||||
|
if _, ok := err.(*yaml.TypeError); !ok {
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
}
|
||||||
|
if t.Kind() == reflect.String {
|
||||||
|
c.Assert(*value.(*string), Equals, item.value)
|
||||||
|
} else {
|
||||||
|
c.Assert(value, DeepEquals, item.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestUnmarshalNaN(c *C) {
|
||||||
|
value := map[string]interface{}{}
|
||||||
|
err := yaml.Unmarshal([]byte("notanum: .NaN"), &value)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
c.Assert(math.IsNaN(value["notanum"].(float64)), Equals, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
var unmarshalErrorTests = []struct {
|
||||||
|
data, error string
|
||||||
|
}{
|
||||||
|
{"v: !!float 'error'", "yaml: cannot decode !!str `error` as a !!float"},
|
||||||
|
{"v: [A,", "yaml: line 1: did not find expected node content"},
|
||||||
|
{"v:\n- [A,", "yaml: line 2: did not find expected node content"},
|
||||||
|
{"a: *b\n", "yaml: unknown anchor 'b' referenced"},
|
||||||
|
{"a: &a\n b: *a\n", "yaml: anchor 'a' value contains itself"},
|
||||||
|
{"value: -", "yaml: block sequence entries are not allowed in this context"},
|
||||||
|
{"a: !!binary ==", "yaml: !!binary value contains invalid base64 data"},
|
||||||
|
{"{[.]}", `yaml: invalid map key: \[\]interface \{\}\{"\."\}`},
|
||||||
|
{"{{.}}", `yaml: invalid map key: map\[interface\ \{\}\]interface \{\}\{".":interface \{\}\(nil\)\}`},
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestUnmarshalErrors(c *C) {
|
||||||
|
for _, item := range unmarshalErrorTests {
|
||||||
|
var value interface{}
|
||||||
|
err := yaml.Unmarshal([]byte(item.data), &value)
|
||||||
|
c.Assert(err, ErrorMatches, item.error, Commentf("Partial unmarshal: %#v", value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var unmarshalerTests = []struct {
|
||||||
|
data, tag string
|
||||||
|
value interface{}
|
||||||
|
}{
|
||||||
|
{"_: {hi: there}", "!!map", map[interface{}]interface{}{"hi": "there"}},
|
||||||
|
{"_: [1,A]", "!!seq", []interface{}{1, "A"}},
|
||||||
|
{"_: 10", "!!int", 10},
|
||||||
|
{"_: null", "!!null", nil},
|
||||||
|
{`_: BAR!`, "!!str", "BAR!"},
|
||||||
|
{`_: "BAR!"`, "!!str", "BAR!"},
|
||||||
|
{"_: !!foo 'BAR!'", "!!foo", "BAR!"},
|
||||||
|
}
|
||||||
|
|
||||||
|
var unmarshalerResult = map[int]error{}
|
||||||
|
|
||||||
|
type unmarshalerType struct {
|
||||||
|
value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *unmarshalerType) UnmarshalYAML(unmarshal func(v interface{}) error) error {
|
||||||
|
if err := unmarshal(&o.value); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if i, ok := o.value.(int); ok {
|
||||||
|
if result, ok := unmarshalerResult[i]; ok {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type unmarshalerPointer struct {
|
||||||
|
Field *unmarshalerType "_"
|
||||||
|
}
|
||||||
|
|
||||||
|
type unmarshalerValue struct {
|
||||||
|
Field unmarshalerType "_"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestUnmarshalerPointerField(c *C) {
|
||||||
|
for _, item := range unmarshalerTests {
|
||||||
|
obj := &unmarshalerPointer{}
|
||||||
|
err := yaml.Unmarshal([]byte(item.data), obj)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
if item.value == nil {
|
||||||
|
c.Assert(obj.Field, IsNil)
|
||||||
|
} else {
|
||||||
|
c.Assert(obj.Field, NotNil, Commentf("Pointer not initialized (%#v)", item.value))
|
||||||
|
c.Assert(obj.Field.value, DeepEquals, item.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestUnmarshalerValueField(c *C) {
|
||||||
|
for _, item := range unmarshalerTests {
|
||||||
|
obj := &unmarshalerValue{}
|
||||||
|
err := yaml.Unmarshal([]byte(item.data), obj)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
c.Assert(obj.Field, NotNil, Commentf("Pointer not initialized (%#v)", item.value))
|
||||||
|
c.Assert(obj.Field.value, DeepEquals, item.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestUnmarshalerWholeDocument(c *C) {
|
||||||
|
obj := &unmarshalerType{}
|
||||||
|
err := yaml.Unmarshal([]byte(unmarshalerTests[0].data), obj)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
value, ok := obj.value.(map[interface{}]interface{})
|
||||||
|
c.Assert(ok, Equals, true, Commentf("value: %#v", obj.value))
|
||||||
|
c.Assert(value["_"], DeepEquals, unmarshalerTests[0].value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestUnmarshalerTypeError(c *C) {
|
||||||
|
unmarshalerResult[2] = &yaml.TypeError{[]string{"foo"}}
|
||||||
|
unmarshalerResult[4] = &yaml.TypeError{[]string{"bar"}}
|
||||||
|
defer func() {
|
||||||
|
delete(unmarshalerResult, 2)
|
||||||
|
delete(unmarshalerResult, 4)
|
||||||
|
}()
|
||||||
|
|
||||||
|
type T struct {
|
||||||
|
Before int
|
||||||
|
After int
|
||||||
|
M map[string]*unmarshalerType
|
||||||
|
}
|
||||||
|
var v T
|
||||||
|
data := `{before: A, m: {abc: 1, def: 2, ghi: 3, jkl: 4}, after: B}`
|
||||||
|
err := yaml.Unmarshal([]byte(data), &v)
|
||||||
|
c.Assert(err, ErrorMatches, ""+
|
||||||
|
"yaml: unmarshal errors:\n"+
|
||||||
|
" line 1: cannot unmarshal !!str `A` into int\n"+
|
||||||
|
" foo\n"+
|
||||||
|
" bar\n"+
|
||||||
|
" line 1: cannot unmarshal !!str `B` into int")
|
||||||
|
c.Assert(v.M["abc"], NotNil)
|
||||||
|
c.Assert(v.M["def"], IsNil)
|
||||||
|
c.Assert(v.M["ghi"], NotNil)
|
||||||
|
c.Assert(v.M["jkl"], IsNil)
|
||||||
|
|
||||||
|
c.Assert(v.M["abc"].value, Equals, 1)
|
||||||
|
c.Assert(v.M["ghi"].value, Equals, 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
type proxyTypeError struct{}
|
||||||
|
|
||||||
|
func (v *proxyTypeError) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
|
var s string
|
||||||
|
var a int32
|
||||||
|
var b int64
|
||||||
|
if err := unmarshal(&s); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if s == "a" {
|
||||||
|
if err := unmarshal(&b); err == nil {
|
||||||
|
panic("should have failed")
|
||||||
|
}
|
||||||
|
return unmarshal(&a)
|
||||||
|
}
|
||||||
|
if err := unmarshal(&a); err == nil {
|
||||||
|
panic("should have failed")
|
||||||
|
}
|
||||||
|
return unmarshal(&b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestUnmarshalerTypeErrorProxying(c *C) {
|
||||||
|
type T struct {
|
||||||
|
Before int
|
||||||
|
After int
|
||||||
|
M map[string]*proxyTypeError
|
||||||
|
}
|
||||||
|
var v T
|
||||||
|
data := `{before: A, m: {abc: a, def: b}, after: B}`
|
||||||
|
err := yaml.Unmarshal([]byte(data), &v)
|
||||||
|
c.Assert(err, ErrorMatches, ""+
|
||||||
|
"yaml: unmarshal errors:\n"+
|
||||||
|
" line 1: cannot unmarshal !!str `A` into int\n"+
|
||||||
|
" line 1: cannot unmarshal !!str `a` into int32\n"+
|
||||||
|
" line 1: cannot unmarshal !!str `b` into int64\n"+
|
||||||
|
" line 1: cannot unmarshal !!str `B` into int")
|
||||||
|
}
|
||||||
|
|
||||||
|
type failingUnmarshaler struct{}
|
||||||
|
|
||||||
|
var failingErr = errors.New("failingErr")
|
||||||
|
|
||||||
|
func (ft *failingUnmarshaler) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
|
return failingErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestUnmarshalerError(c *C) {
|
||||||
|
err := yaml.Unmarshal([]byte("a: b"), &failingUnmarshaler{})
|
||||||
|
c.Assert(err, Equals, failingErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
type sliceUnmarshaler []int
|
||||||
|
|
||||||
|
func (su *sliceUnmarshaler) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
|
var slice []int
|
||||||
|
err := unmarshal(&slice)
|
||||||
|
if err == nil {
|
||||||
|
*su = slice
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var intVal int
|
||||||
|
err = unmarshal(&intVal)
|
||||||
|
if err == nil {
|
||||||
|
*su = []int{intVal}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestUnmarshalerRetry(c *C) {
|
||||||
|
var su sliceUnmarshaler
|
||||||
|
err := yaml.Unmarshal([]byte("[1, 2, 3]"), &su)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
c.Assert(su, DeepEquals, sliceUnmarshaler([]int{1, 2, 3}))
|
||||||
|
|
||||||
|
err = yaml.Unmarshal([]byte("1"), &su)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
c.Assert(su, DeepEquals, sliceUnmarshaler([]int{1}))
|
||||||
|
}
|
||||||
|
|
||||||
|
// From http://yaml.org/type/merge.html
|
||||||
|
var mergeTests = `
|
||||||
|
anchors:
|
||||||
|
list:
|
||||||
|
- &CENTER { "x": 1, "y": 2 }
|
||||||
|
- &LEFT { "x": 0, "y": 2 }
|
||||||
|
- &BIG { "r": 10 }
|
||||||
|
- &SMALL { "r": 1 }
|
||||||
|
|
||||||
|
# All the following maps are equal:
|
||||||
|
|
||||||
|
plain:
|
||||||
|
# Explicit keys
|
||||||
|
"x": 1
|
||||||
|
"y": 2
|
||||||
|
"r": 10
|
||||||
|
label: center/big
|
||||||
|
|
||||||
|
mergeOne:
|
||||||
|
# Merge one map
|
||||||
|
<< : *CENTER
|
||||||
|
"r": 10
|
||||||
|
label: center/big
|
||||||
|
|
||||||
|
mergeMultiple:
|
||||||
|
# Merge multiple maps
|
||||||
|
<< : [ *CENTER, *BIG ]
|
||||||
|
label: center/big
|
||||||
|
|
||||||
|
override:
|
||||||
|
# Override
|
||||||
|
<< : [ *BIG, *LEFT, *SMALL ]
|
||||||
|
"x": 1
|
||||||
|
label: center/big
|
||||||
|
|
||||||
|
shortTag:
|
||||||
|
# Explicit short merge tag
|
||||||
|
!!merge "<<" : [ *CENTER, *BIG ]
|
||||||
|
label: center/big
|
||||||
|
|
||||||
|
longTag:
|
||||||
|
# Explicit merge long tag
|
||||||
|
!<tag:yaml.org,2002:merge> "<<" : [ *CENTER, *BIG ]
|
||||||
|
label: center/big
|
||||||
|
|
||||||
|
inlineMap:
|
||||||
|
# Inlined map
|
||||||
|
<< : {"x": 1, "y": 2, "r": 10}
|
||||||
|
label: center/big
|
||||||
|
|
||||||
|
inlineSequenceMap:
|
||||||
|
# Inlined map in sequence
|
||||||
|
<< : [ *CENTER, {"r": 10} ]
|
||||||
|
label: center/big
|
||||||
|
`
|
||||||
|
|
||||||
|
func (s *S) TestMerge(c *C) {
|
||||||
|
var want = map[interface{}]interface{}{
|
||||||
|
"x": 1,
|
||||||
|
"y": 2,
|
||||||
|
"r": 10,
|
||||||
|
"label": "center/big",
|
||||||
|
}
|
||||||
|
|
||||||
|
var m map[interface{}]interface{}
|
||||||
|
err := yaml.Unmarshal([]byte(mergeTests), &m)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
for name, test := range m {
|
||||||
|
if name == "anchors" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
c.Assert(test, DeepEquals, want, Commentf("test %q failed", name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestMergeStruct(c *C) {
|
||||||
|
type Data struct {
|
||||||
|
X, Y, R int
|
||||||
|
Label string
|
||||||
|
}
|
||||||
|
want := Data{1, 2, 10, "center/big"}
|
||||||
|
|
||||||
|
var m map[string]Data
|
||||||
|
err := yaml.Unmarshal([]byte(mergeTests), &m)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
for name, test := range m {
|
||||||
|
if name == "anchors" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
c.Assert(test, Equals, want, Commentf("test %q failed", name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var unmarshalNullTests = []func() interface{}{
|
||||||
|
func() interface{} { var v interface{}; v = "v"; return &v },
|
||||||
|
func() interface{} { var s = "s"; return &s },
|
||||||
|
func() interface{} { var s = "s"; sptr := &s; return &sptr },
|
||||||
|
func() interface{} { var i = 1; return &i },
|
||||||
|
func() interface{} { var i = 1; iptr := &i; return &iptr },
|
||||||
|
func() interface{} { m := map[string]int{"s": 1}; return &m },
|
||||||
|
func() interface{} { m := map[string]int{"s": 1}; return m },
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestUnmarshalNull(c *C) {
|
||||||
|
for _, test := range unmarshalNullTests {
|
||||||
|
item := test()
|
||||||
|
zero := reflect.Zero(reflect.TypeOf(item).Elem()).Interface()
|
||||||
|
err := yaml.Unmarshal([]byte("null"), item)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
if reflect.TypeOf(item).Kind() == reflect.Map {
|
||||||
|
c.Assert(reflect.ValueOf(item).Interface(), DeepEquals, reflect.MakeMap(reflect.TypeOf(item)).Interface())
|
||||||
|
} else {
|
||||||
|
c.Assert(reflect.ValueOf(item).Elem().Interface(), DeepEquals, zero)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestUnmarshalSliceOnPreset(c *C) {
|
||||||
|
// Issue #48.
|
||||||
|
v := struct{ A []int }{[]int{1}}
|
||||||
|
yaml.Unmarshal([]byte("a: [2]"), &v)
|
||||||
|
c.Assert(v.A, DeepEquals, []int{2})
|
||||||
|
}
|
||||||
|
|
||||||
|
//var data []byte
|
||||||
|
//func init() {
|
||||||
|
// var err error
|
||||||
|
// data, err = ioutil.ReadFile("/tmp/file.yaml")
|
||||||
|
// if err != nil {
|
||||||
|
// panic(err)
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func (s *S) BenchmarkUnmarshal(c *C) {
|
||||||
|
// var err error
|
||||||
|
// for i := 0; i < c.N; i++ {
|
||||||
|
// var v map[string]interface{}
|
||||||
|
// err = yaml.Unmarshal(data, &v)
|
||||||
|
// }
|
||||||
|
// if err != nil {
|
||||||
|
// panic(err)
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func (s *S) BenchmarkMarshal(c *C) {
|
||||||
|
// var v map[string]interface{}
|
||||||
|
// yaml.Unmarshal(data, &v)
|
||||||
|
// c.ResetTimer()
|
||||||
|
// for i := 0; i < c.N; i++ {
|
||||||
|
// yaml.Marshal(&v)
|
||||||
|
// }
|
||||||
|
//}
|
1685
vendor/gopkg.in/yaml.v2/emitterc.go
generated
vendored
Normal file
1685
vendor/gopkg.in/yaml.v2/emitterc.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
306
vendor/gopkg.in/yaml.v2/encode.go
generated
vendored
Normal file
306
vendor/gopkg.in/yaml.v2/encode.go
generated
vendored
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
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()
|
||||||
|
}
|
501
vendor/gopkg.in/yaml.v2/encode_test.go
generated
vendored
Normal file
501
vendor/gopkg.in/yaml.v2/encode_test.go
generated
vendored
Normal file
@ -0,0 +1,501 @@
|
|||||||
|
package yaml_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
. "gopkg.in/check.v1"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var marshalIntTest = 123
|
||||||
|
|
||||||
|
var marshalTests = []struct {
|
||||||
|
value interface{}
|
||||||
|
data string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
nil,
|
||||||
|
"null\n",
|
||||||
|
}, {
|
||||||
|
&struct{}{},
|
||||||
|
"{}\n",
|
||||||
|
}, {
|
||||||
|
map[string]string{"v": "hi"},
|
||||||
|
"v: hi\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": "hi"},
|
||||||
|
"v: hi\n",
|
||||||
|
}, {
|
||||||
|
map[string]string{"v": "true"},
|
||||||
|
"v: \"true\"\n",
|
||||||
|
}, {
|
||||||
|
map[string]string{"v": "false"},
|
||||||
|
"v: \"false\"\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": true},
|
||||||
|
"v: true\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": false},
|
||||||
|
"v: false\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": 10},
|
||||||
|
"v: 10\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": -10},
|
||||||
|
"v: -10\n",
|
||||||
|
}, {
|
||||||
|
map[string]uint{"v": 42},
|
||||||
|
"v: 42\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": int64(4294967296)},
|
||||||
|
"v: 4294967296\n",
|
||||||
|
}, {
|
||||||
|
map[string]int64{"v": int64(4294967296)},
|
||||||
|
"v: 4294967296\n",
|
||||||
|
}, {
|
||||||
|
map[string]uint64{"v": 4294967296},
|
||||||
|
"v: 4294967296\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": "10"},
|
||||||
|
"v: \"10\"\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": 0.1},
|
||||||
|
"v: 0.1\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": float64(0.1)},
|
||||||
|
"v: 0.1\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": -0.1},
|
||||||
|
"v: -0.1\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": math.Inf(+1)},
|
||||||
|
"v: .inf\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": math.Inf(-1)},
|
||||||
|
"v: -.inf\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": math.NaN()},
|
||||||
|
"v: .nan\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": nil},
|
||||||
|
"v: null\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": ""},
|
||||||
|
"v: \"\"\n",
|
||||||
|
}, {
|
||||||
|
map[string][]string{"v": []string{"A", "B"}},
|
||||||
|
"v:\n- A\n- B\n",
|
||||||
|
}, {
|
||||||
|
map[string][]string{"v": []string{"A", "B\nC"}},
|
||||||
|
"v:\n- A\n- |-\n B\n C\n",
|
||||||
|
}, {
|
||||||
|
map[string][]interface{}{"v": []interface{}{"A", 1, map[string][]int{"B": []int{2, 3}}}},
|
||||||
|
"v:\n- A\n- 1\n- B:\n - 2\n - 3\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"a": map[interface{}]interface{}{"b": "c"}},
|
||||||
|
"a:\n b: c\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"a": "-"},
|
||||||
|
"a: '-'\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Simple values.
|
||||||
|
{
|
||||||
|
&marshalIntTest,
|
||||||
|
"123\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Structures
|
||||||
|
{
|
||||||
|
&struct{ Hello string }{"world"},
|
||||||
|
"hello: world\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
A struct {
|
||||||
|
B string
|
||||||
|
}
|
||||||
|
}{struct{ B string }{"c"}},
|
||||||
|
"a:\n b: c\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
A *struct {
|
||||||
|
B string
|
||||||
|
}
|
||||||
|
}{&struct{ B string }{"c"}},
|
||||||
|
"a:\n b: c\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
A *struct {
|
||||||
|
B string
|
||||||
|
}
|
||||||
|
}{},
|
||||||
|
"a: null\n",
|
||||||
|
}, {
|
||||||
|
&struct{ A int }{1},
|
||||||
|
"a: 1\n",
|
||||||
|
}, {
|
||||||
|
&struct{ A []int }{[]int{1, 2}},
|
||||||
|
"a:\n- 1\n- 2\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
B int "a"
|
||||||
|
}{1},
|
||||||
|
"a: 1\n",
|
||||||
|
}, {
|
||||||
|
&struct{ A bool }{true},
|
||||||
|
"a: true\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Conditional flag
|
||||||
|
{
|
||||||
|
&struct {
|
||||||
|
A int "a,omitempty"
|
||||||
|
B int "b,omitempty"
|
||||||
|
}{1, 0},
|
||||||
|
"a: 1\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
A int "a,omitempty"
|
||||||
|
B int "b,omitempty"
|
||||||
|
}{0, 0},
|
||||||
|
"{}\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
A *struct{ X, y int } "a,omitempty,flow"
|
||||||
|
}{&struct{ X, y int }{1, 2}},
|
||||||
|
"a: {x: 1}\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
A *struct{ X, y int } "a,omitempty,flow"
|
||||||
|
}{nil},
|
||||||
|
"{}\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
A *struct{ X, y int } "a,omitempty,flow"
|
||||||
|
}{&struct{ X, y int }{}},
|
||||||
|
"a: {x: 0}\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
A struct{ X, y int } "a,omitempty,flow"
|
||||||
|
}{struct{ X, y int }{1, 2}},
|
||||||
|
"a: {x: 1}\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
A struct{ X, y int } "a,omitempty,flow"
|
||||||
|
}{struct{ X, y int }{0, 1}},
|
||||||
|
"{}\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
A float64 "a,omitempty"
|
||||||
|
B float64 "b,omitempty"
|
||||||
|
}{1, 0},
|
||||||
|
"a: 1\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Flow flag
|
||||||
|
{
|
||||||
|
&struct {
|
||||||
|
A []int "a,flow"
|
||||||
|
}{[]int{1, 2}},
|
||||||
|
"a: [1, 2]\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
A map[string]string "a,flow"
|
||||||
|
}{map[string]string{"b": "c", "d": "e"}},
|
||||||
|
"a: {b: c, d: e}\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
A struct {
|
||||||
|
B, D string
|
||||||
|
} "a,flow"
|
||||||
|
}{struct{ B, D string }{"c", "e"}},
|
||||||
|
"a: {b: c, d: e}\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Unexported field
|
||||||
|
{
|
||||||
|
&struct {
|
||||||
|
u int
|
||||||
|
A int
|
||||||
|
}{0, 1},
|
||||||
|
"a: 1\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Ignored field
|
||||||
|
{
|
||||||
|
&struct {
|
||||||
|
A int
|
||||||
|
B int "-"
|
||||||
|
}{1, 2},
|
||||||
|
"a: 1\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Struct inlining
|
||||||
|
{
|
||||||
|
&struct {
|
||||||
|
A int
|
||||||
|
C inlineB `yaml:",inline"`
|
||||||
|
}{1, inlineB{2, inlineC{3}}},
|
||||||
|
"a: 1\nb: 2\nc: 3\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Map inlining
|
||||||
|
{
|
||||||
|
&struct {
|
||||||
|
A int
|
||||||
|
C map[string]int `yaml:",inline"`
|
||||||
|
}{1, map[string]int{"b": 2, "c": 3}},
|
||||||
|
"a: 1\nb: 2\nc: 3\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Duration
|
||||||
|
{
|
||||||
|
map[string]time.Duration{"a": 3 * time.Second},
|
||||||
|
"a: 3s\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Issue #24: bug in map merging logic.
|
||||||
|
{
|
||||||
|
map[string]string{"a": "<foo>"},
|
||||||
|
"a: <foo>\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Issue #34: marshal unsupported base 60 floats quoted for compatibility
|
||||||
|
// with old YAML 1.1 parsers.
|
||||||
|
{
|
||||||
|
map[string]string{"a": "1:1"},
|
||||||
|
"a: \"1:1\"\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Binary data.
|
||||||
|
{
|
||||||
|
map[string]string{"a": "\x00"},
|
||||||
|
"a: \"\\0\"\n",
|
||||||
|
}, {
|
||||||
|
map[string]string{"a": "\x80\x81\x82"},
|
||||||
|
"a: !!binary gIGC\n",
|
||||||
|
}, {
|
||||||
|
map[string]string{"a": strings.Repeat("\x90", 54)},
|
||||||
|
"a: !!binary |\n " + strings.Repeat("kJCQ", 17) + "kJ\n CQ\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Ordered maps.
|
||||||
|
{
|
||||||
|
&yaml.MapSlice{{"b", 2}, {"a", 1}, {"d", 4}, {"c", 3}, {"sub", yaml.MapSlice{{"e", 5}}}},
|
||||||
|
"b: 2\na: 1\nd: 4\nc: 3\nsub:\n e: 5\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Encode unicode as utf-8 rather than in escaped form.
|
||||||
|
{
|
||||||
|
map[string]string{"a": "你好"},
|
||||||
|
"a: 你好\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Support encoding.TextMarshaler.
|
||||||
|
{
|
||||||
|
map[string]net.IP{"a": net.IPv4(1, 2, 3, 4)},
|
||||||
|
"a: 1.2.3.4\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
map[string]time.Time{"a": time.Unix(1424801979, 0)},
|
||||||
|
"a: 2015-02-24T18:19:39Z\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Ensure strings containing ": " are quoted (reported as PR #43, but not reproducible).
|
||||||
|
{
|
||||||
|
map[string]string{"a": "b: c"},
|
||||||
|
"a: 'b: c'\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Containing hash mark ('#') in string should be quoted
|
||||||
|
{
|
||||||
|
map[string]string{"a": "Hello #comment"},
|
||||||
|
"a: 'Hello #comment'\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
map[string]string{"a": "你好 #comment"},
|
||||||
|
"a: '你好 #comment'\n",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestMarshal(c *C) {
|
||||||
|
defer os.Setenv("TZ", os.Getenv("TZ"))
|
||||||
|
os.Setenv("TZ", "UTC")
|
||||||
|
for _, item := range marshalTests {
|
||||||
|
data, err := yaml.Marshal(item.value)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
c.Assert(string(data), Equals, item.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var marshalErrorTests = []struct {
|
||||||
|
value interface{}
|
||||||
|
error string
|
||||||
|
panic string
|
||||||
|
}{{
|
||||||
|
value: &struct {
|
||||||
|
B int
|
||||||
|
inlineB ",inline"
|
||||||
|
}{1, inlineB{2, inlineC{3}}},
|
||||||
|
panic: `Duplicated key 'b' in struct struct \{ B int; .*`,
|
||||||
|
}, {
|
||||||
|
value: &struct {
|
||||||
|
A int
|
||||||
|
B map[string]int ",inline"
|
||||||
|
}{1, map[string]int{"a": 2}},
|
||||||
|
panic: `Can't have key "a" in inlined map; conflicts with struct field`,
|
||||||
|
}}
|
||||||
|
|
||||||
|
func (s *S) TestMarshalErrors(c *C) {
|
||||||
|
for _, item := range marshalErrorTests {
|
||||||
|
if item.panic != "" {
|
||||||
|
c.Assert(func() { yaml.Marshal(item.value) }, PanicMatches, item.panic)
|
||||||
|
} else {
|
||||||
|
_, err := yaml.Marshal(item.value)
|
||||||
|
c.Assert(err, ErrorMatches, item.error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestMarshalTypeCache(c *C) {
|
||||||
|
var data []byte
|
||||||
|
var err error
|
||||||
|
func() {
|
||||||
|
type T struct{ A int }
|
||||||
|
data, err = yaml.Marshal(&T{})
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
}()
|
||||||
|
func() {
|
||||||
|
type T struct{ B int }
|
||||||
|
data, err = yaml.Marshal(&T{})
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
}()
|
||||||
|
c.Assert(string(data), Equals, "b: 0\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
var marshalerTests = []struct {
|
||||||
|
data string
|
||||||
|
value interface{}
|
||||||
|
}{
|
||||||
|
{"_:\n hi: there\n", map[interface{}]interface{}{"hi": "there"}},
|
||||||
|
{"_:\n- 1\n- A\n", []interface{}{1, "A"}},
|
||||||
|
{"_: 10\n", 10},
|
||||||
|
{"_: null\n", nil},
|
||||||
|
{"_: BAR!\n", "BAR!"},
|
||||||
|
}
|
||||||
|
|
||||||
|
type marshalerType struct {
|
||||||
|
value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o marshalerType) MarshalText() ([]byte, error) {
|
||||||
|
panic("MarshalText called on type with MarshalYAML")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o marshalerType) MarshalYAML() (interface{}, error) {
|
||||||
|
return o.value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type marshalerValue struct {
|
||||||
|
Field marshalerType "_"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestMarshaler(c *C) {
|
||||||
|
for _, item := range marshalerTests {
|
||||||
|
obj := &marshalerValue{}
|
||||||
|
obj.Field.value = item.value
|
||||||
|
data, err := yaml.Marshal(obj)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
c.Assert(string(data), Equals, string(item.data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestMarshalerWholeDocument(c *C) {
|
||||||
|
obj := &marshalerType{}
|
||||||
|
obj.value = map[string]string{"hello": "world!"}
|
||||||
|
data, err := yaml.Marshal(obj)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
c.Assert(string(data), Equals, "hello: world!\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
type failingMarshaler struct{}
|
||||||
|
|
||||||
|
func (ft *failingMarshaler) MarshalYAML() (interface{}, error) {
|
||||||
|
return nil, failingErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestMarshalerError(c *C) {
|
||||||
|
_, err := yaml.Marshal(&failingMarshaler{})
|
||||||
|
c.Assert(err, Equals, failingErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestSortedOutput(c *C) {
|
||||||
|
order := []interface{}{
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
1,
|
||||||
|
uint(1),
|
||||||
|
1.0,
|
||||||
|
1.1,
|
||||||
|
1.2,
|
||||||
|
2,
|
||||||
|
uint(2),
|
||||||
|
2.0,
|
||||||
|
2.1,
|
||||||
|
"",
|
||||||
|
".1",
|
||||||
|
".2",
|
||||||
|
".a",
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"a!10",
|
||||||
|
"a/2",
|
||||||
|
"a/10",
|
||||||
|
"a~10",
|
||||||
|
"ab/1",
|
||||||
|
"b/1",
|
||||||
|
"b/01",
|
||||||
|
"b/2",
|
||||||
|
"b/02",
|
||||||
|
"b/3",
|
||||||
|
"b/03",
|
||||||
|
"b1",
|
||||||
|
"b01",
|
||||||
|
"b3",
|
||||||
|
"c2.10",
|
||||||
|
"c10.2",
|
||||||
|
"d1",
|
||||||
|
"d12",
|
||||||
|
"d12a",
|
||||||
|
}
|
||||||
|
m := make(map[interface{}]int)
|
||||||
|
for _, k := range order {
|
||||||
|
m[k] = 1
|
||||||
|
}
|
||||||
|
data, err := yaml.Marshal(m)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
out := "\n" + string(data)
|
||||||
|
last := 0
|
||||||
|
for i, k := range order {
|
||||||
|
repr := fmt.Sprint(k)
|
||||||
|
if s, ok := k.(string); ok {
|
||||||
|
if _, err = strconv.ParseFloat(repr, 32); s == "" || err == nil {
|
||||||
|
repr = `"` + repr + `"`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index := strings.Index(out, "\n"+repr+":")
|
||||||
|
if index == -1 {
|
||||||
|
c.Fatalf("%#v is not in the output: %#v", k, out)
|
||||||
|
}
|
||||||
|
if index < last {
|
||||||
|
c.Fatalf("%#v was generated before %#v: %q", k, order[i-1], out)
|
||||||
|
}
|
||||||
|
last = index
|
||||||
|
}
|
||||||
|
}
|
1096
vendor/gopkg.in/yaml.v2/parserc.go
generated
vendored
Normal file
1096
vendor/gopkg.in/yaml.v2/parserc.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
394
vendor/gopkg.in/yaml.v2/readerc.go
generated
vendored
Normal file
394
vendor/gopkg.in/yaml.v2/readerc.go
generated
vendored
Normal file
@ -0,0 +1,394 @@
|
|||||||
|
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
|
||||||
|
}
|
203
vendor/gopkg.in/yaml.v2/resolve.go
generated
vendored
Normal file
203
vendor/gopkg.in/yaml.v2/resolve.go
generated
vendored
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"math"
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
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])
|
||||||
|
}
|
2710
vendor/gopkg.in/yaml.v2/scannerc.go
generated
vendored
Normal file
2710
vendor/gopkg.in/yaml.v2/scannerc.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
104
vendor/gopkg.in/yaml.v2/sorter.go
generated
vendored
Normal file
104
vendor/gopkg.in/yaml.v2/sorter.go
generated
vendored
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
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")
|
||||||
|
}
|
12
vendor/gopkg.in/yaml.v2/suite_test.go
generated
vendored
Normal file
12
vendor/gopkg.in/yaml.v2/suite_test.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package yaml_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "gopkg.in/check.v1"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test(t *testing.T) { TestingT(t) }
|
||||||
|
|
||||||
|
type S struct{}
|
||||||
|
|
||||||
|
var _ = Suite(&S{})
|
89
vendor/gopkg.in/yaml.v2/writerc.go
generated
vendored
Normal file
89
vendor/gopkg.in/yaml.v2/writerc.go
generated
vendored
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
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
|
||||||
|
}
|
346
vendor/gopkg.in/yaml.v2/yaml.go
generated
vendored
Normal file
346
vendor/gopkg.in/yaml.v2/yaml.go
generated
vendored
Normal file
@ -0,0 +1,346 @@
|
|||||||
|
// 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) {
|
||||||
|
defer handleErr(&err)
|
||||||
|
d := newDecoder()
|
||||||
|
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:"[<key>][,<flag1>[,<flag2>]]" (...)`
|
||||||
|
//
|
||||||
|
// 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 "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 != "" {
|
||||||
|
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
|
||||||
|
}
|
716
vendor/gopkg.in/yaml.v2/yamlh.go
generated
vendored
Normal file
716
vendor/gopkg.in/yaml.v2/yamlh.go
generated
vendored
Normal file
@ -0,0 +1,716 @@
|
|||||||
|
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 "<unknown token>"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 "<unknown parser state>"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 occured.
|
||||||
|
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.
|
||||||
|
}
|
173
vendor/gopkg.in/yaml.v2/yamlprivateh.go
generated
vendored
Normal file
173
vendor/gopkg.in/yaml.v2/yamlprivateh.go
generated
vendored
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
}
|
@ -5,6 +5,7 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/coreos/clair/config"
|
||||||
"github.com/coreos/clair/database"
|
"github.com/coreos/clair/database"
|
||||||
"github.com/coreos/clair/utils/types"
|
"github.com/coreos/clair/utils/types"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -15,7 +16,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestDistUpgrade(t *testing.T) {
|
func TestDistUpgrade(t *testing.T) {
|
||||||
database.Open("memstore", "")
|
database.Open(&config.DatabaseConfig{Type: "memstore"})
|
||||||
defer database.Close()
|
defer database.Close()
|
||||||
|
|
||||||
_, f, _, _ := runtime.Caller(0)
|
_, f, _, _ := runtime.Caller(0)
|
||||||
|
Loading…
Reference in New Issue
Block a user