mirror of
https://github.com/git-chglog/git-chglog.git
synced 2026-01-23 02:15:12 +00:00
feat: Add cli client
This commit is contained in:
parent
22cfb51124
commit
066fa21430
75 changed files with 15744 additions and 1 deletions
30
Gopkg.lock
generated
30
Gopkg.lock
generated
|
|
@ -31,6 +31,12 @@
|
|||
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/mgutz/ansi"
|
||||
packages = ["."]
|
||||
revision = "9520e82c474b0a04dd04f8a40959027271bab992"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/pmezard/go-difflib"
|
||||
packages = ["difflib"]
|
||||
|
|
@ -61,9 +67,31 @@
|
|||
packages = ["unix"]
|
||||
revision = "37707fdb30a5b38865cfb95e5aab41707daec7fd"
|
||||
|
||||
[[projects]]
|
||||
name = "gopkg.in/AlecAivazis/survey.v1"
|
||||
packages = [
|
||||
".",
|
||||
"core",
|
||||
"terminal"
|
||||
]
|
||||
revision = "0aa8b6a162b391fe2d95648b7677d1d6ac2090a6"
|
||||
version = "v1.4.1"
|
||||
|
||||
[[projects]]
|
||||
name = "gopkg.in/kyokomi/emoji.v1"
|
||||
packages = ["."]
|
||||
revision = "7e06b236c489543f53868841f188a294e3383eab"
|
||||
version = "v1.5"
|
||||
|
||||
[[projects]]
|
||||
branch = "v2"
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
revision = "d670f9405373e636a5a2765eea47fac0c9bc91a4"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "a5e632da6da114d491d308913d8a2efb69ffc559833fb44c98dd45ddaf62befa"
|
||||
inputs-digest = "0be1d1c2f1a9b1c1f1d63ad065141425b62687efb378f6657b088ddf993c3882"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
|
|
|||
12
Gopkg.toml
12
Gopkg.toml
|
|
@ -22,3 +22,15 @@
|
|||
[[constraint]]
|
||||
name = "github.com/imdario/mergo"
|
||||
version = "0.3.2"
|
||||
|
||||
[[constraint]]
|
||||
branch = "v2"
|
||||
name = "gopkg.in/yaml.v2"
|
||||
|
||||
[[constraint]]
|
||||
name = "gopkg.in/AlecAivazis/survey.v1"
|
||||
version = "1.4.1"
|
||||
|
||||
[[constraint]]
|
||||
name = "gopkg.in/kyokomi/emoji.v1"
|
||||
version = "1.5.0"
|
||||
|
|
|
|||
133
cmd/git-chglog/cli.go
Normal file
133
cmd/git-chglog/cli.go
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
chglog "github.com/git-chglog/git-chglog"
|
||||
)
|
||||
|
||||
// CLI ...
|
||||
type CLI struct {
|
||||
ctx *Context
|
||||
fs FileSystem
|
||||
logger *Logger
|
||||
configLoader ConfigLoader
|
||||
generator Generator
|
||||
processorFactory *ProcessorFactory
|
||||
}
|
||||
|
||||
// NewCLI ...
|
||||
func NewCLI(
|
||||
ctx *Context,
|
||||
fs FileSystem,
|
||||
configLoader ConfigLoader,
|
||||
generator Generator,
|
||||
) *CLI {
|
||||
silent := false
|
||||
if ctx.Silent || ctx.OutputPath == "" {
|
||||
silent = true
|
||||
}
|
||||
|
||||
return &CLI{
|
||||
ctx: ctx,
|
||||
fs: fs,
|
||||
logger: NewLogger(ctx.Stdout, ctx.Stderr, silent, ctx.NoEmoji),
|
||||
configLoader: configLoader,
|
||||
generator: generator,
|
||||
processorFactory: NewProcessorFactory(),
|
||||
}
|
||||
}
|
||||
|
||||
// Run ...
|
||||
func (c *CLI) Run() int {
|
||||
start := time.Now()
|
||||
|
||||
if c.ctx.NoColor {
|
||||
color.NoColor = true
|
||||
}
|
||||
|
||||
c.logger.Log(":watch: Generating changelog ...")
|
||||
|
||||
config, err := c.prepareConfig()
|
||||
if err != nil {
|
||||
c.logger.Error(err.Error())
|
||||
return ExitCodeError
|
||||
}
|
||||
|
||||
changelogConfig, err := c.createChangelogConfig(config)
|
||||
if err != nil {
|
||||
c.logger.Error(err.Error())
|
||||
return ExitCodeError
|
||||
}
|
||||
|
||||
w, err := c.createOutputWriter()
|
||||
if err != nil {
|
||||
c.logger.Error(err.Error())
|
||||
return ExitCodeError
|
||||
}
|
||||
|
||||
err = c.generator.Generate(w, c.ctx.Query, changelogConfig)
|
||||
if err != nil {
|
||||
c.logger.Error(err.Error())
|
||||
return ExitCodeError
|
||||
}
|
||||
|
||||
c.logger.Log(fmt.Sprintf(":sparkles:Generate of %s is completed! (%s)",
|
||||
color.GreenString("\""+c.ctx.OutputPath+"\""),
|
||||
color.New(color.Bold).SprintFunc()(time.Since(start).String()),
|
||||
))
|
||||
|
||||
return ExitCodeOK
|
||||
}
|
||||
|
||||
func (c *CLI) prepareConfig() (*Config, error) {
|
||||
config, err := c.configLoader.Load(c.ctx.ConfigPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = config.Normalize(c.ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config.Convert(c.ctx)
|
||||
|
||||
return config, err
|
||||
}
|
||||
|
||||
func (c *CLI) createChangelogConfig(config *Config) (*chglog.Config, error) {
|
||||
processor, err := c.processorFactory.Create(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
changelogConfig := config.Convert(c.ctx)
|
||||
changelogConfig.Options.Processor = processor
|
||||
|
||||
return changelogConfig, nil
|
||||
}
|
||||
|
||||
func (c *CLI) createOutputWriter() (io.Writer, error) {
|
||||
if c.ctx.OutputPath == "" {
|
||||
return c.ctx.Stdout, nil
|
||||
}
|
||||
|
||||
out := c.ctx.OutputPath
|
||||
dir := filepath.Dir(out)
|
||||
err := c.fs.MkdirP(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
file, err := c.fs.Create(out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return file, nil
|
||||
}
|
||||
126
cmd/git-chglog/cli_test.go
Normal file
126
cmd/git-chglog/cli_test.go
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
chglog "github.com/git-chglog/git-chglog"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCLIForStdout(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
assert.True(true)
|
||||
|
||||
stdout := &bytes.Buffer{}
|
||||
stderr := &bytes.Buffer{}
|
||||
mockFS := &mockFileSystem{}
|
||||
|
||||
configLoader := &mockConfigLoaderImpl{
|
||||
ReturnLoad: func(path string) (*Config, error) {
|
||||
if path != "/.chglog/config.yml" {
|
||||
return nil, errors.New("")
|
||||
}
|
||||
return &Config{
|
||||
Bin: "/custom/bin/git",
|
||||
}, nil
|
||||
},
|
||||
}
|
||||
|
||||
generator := &mockGeneratorImpl{
|
||||
ReturnGenerate: func(w io.Writer, query string, config *chglog.Config) error {
|
||||
if config.Bin != "/custom/bin/git" {
|
||||
return errors.New("")
|
||||
}
|
||||
w.Write([]byte("success!!"))
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
c := NewCLI(
|
||||
&Context{
|
||||
WorkingDir: "/",
|
||||
ConfigPath: "/.chglog/config.yml",
|
||||
OutputPath: "",
|
||||
Stdout: stdout,
|
||||
Stderr: stderr,
|
||||
},
|
||||
mockFS,
|
||||
configLoader,
|
||||
generator,
|
||||
)
|
||||
|
||||
assert.Equal(ExitCodeOK, c.Run())
|
||||
assert.Equal("", stderr.String())
|
||||
assert.Equal("success!!", stdout.String())
|
||||
}
|
||||
|
||||
func TestCLIForFile(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
assert.True(true)
|
||||
|
||||
stdout := &bytes.Buffer{}
|
||||
stderr := &bytes.Buffer{}
|
||||
|
||||
mockFS := &mockFileSystem{
|
||||
ReturnMkdirP: func(path string) error {
|
||||
if path != "/dir/to" {
|
||||
return errors.New("")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
ReturnCreate: func(name string) (File, error) {
|
||||
if name != "/dir/to/CHANGELOG.tpl" {
|
||||
return nil, errors.New("")
|
||||
}
|
||||
return &mockFile{
|
||||
ReturnWrite: func(b []byte) (int, error) {
|
||||
if string(b) != "success!!" {
|
||||
return 0, errors.New("")
|
||||
}
|
||||
return 0, nil
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
}
|
||||
|
||||
configLoader := &mockConfigLoaderImpl{
|
||||
ReturnLoad: func(path string) (*Config, error) {
|
||||
if path != "/.chglog/config.yml" {
|
||||
return nil, errors.New("")
|
||||
}
|
||||
return &Config{
|
||||
Bin: "/custom/bin/git",
|
||||
}, nil
|
||||
},
|
||||
}
|
||||
|
||||
generator := &mockGeneratorImpl{
|
||||
ReturnGenerate: func(w io.Writer, query string, config *chglog.Config) error {
|
||||
if config.Bin != "/custom/bin/git" {
|
||||
return errors.New("")
|
||||
}
|
||||
w.Write([]byte("success!!"))
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
c := NewCLI(
|
||||
&Context{
|
||||
WorkingDir: "/",
|
||||
ConfigPath: "/.chglog/config.yml",
|
||||
OutputPath: "/dir/to/CHANGELOG.tpl",
|
||||
Stdout: stdout,
|
||||
Stderr: stderr,
|
||||
},
|
||||
mockFS,
|
||||
configLoader,
|
||||
generator,
|
||||
)
|
||||
|
||||
assert.Equal(ExitCodeOK, c.Run())
|
||||
assert.Equal("", stderr.String())
|
||||
assert.Contains(stdout.String(), "Generate of \"/dir/to/CHANGELOG.tpl\"")
|
||||
}
|
||||
180
cmd/git-chglog/config.go
Normal file
180
cmd/git-chglog/config.go
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
chglog "github.com/git-chglog/git-chglog"
|
||||
"github.com/imdario/mergo"
|
||||
)
|
||||
|
||||
// Info ...
|
||||
type Info struct {
|
||||
Title string `yaml:"title"`
|
||||
RepositoryURL string `yaml:"repository_url"`
|
||||
}
|
||||
|
||||
// CommitOptions ...
|
||||
type CommitOptions struct {
|
||||
Filters map[string][]string `yaml:"filters"`
|
||||
SortBy string `yaml:"sort_by"`
|
||||
}
|
||||
|
||||
// CommitGroupOptions ...
|
||||
type CommitGroupOptions struct {
|
||||
GroupBy string `yaml:"group_by"`
|
||||
SortBy string `yaml:"sort_by"`
|
||||
TitleMaps map[string]string `yaml:"title_maps"`
|
||||
}
|
||||
|
||||
// PatternOptions ...
|
||||
type PatternOptions struct {
|
||||
Pattern string `yaml:"pattern"`
|
||||
PatternMaps []string `yaml:"pattern_maps"`
|
||||
}
|
||||
|
||||
// IssueOptions ...
|
||||
type IssueOptions struct {
|
||||
Prefix []string `yaml:"prefix"`
|
||||
}
|
||||
|
||||
// RefOptions ...
|
||||
type RefOptions struct {
|
||||
Actions []string `yaml:"actions"`
|
||||
}
|
||||
|
||||
// NoteOptions ...
|
||||
type NoteOptions struct {
|
||||
Keywords []string `yaml:"keywords"`
|
||||
}
|
||||
|
||||
// Options ...
|
||||
type Options struct {
|
||||
Commits CommitOptions `yaml:"commits"`
|
||||
CommitGroups CommitGroupOptions `yaml:"commit_groups"`
|
||||
Header PatternOptions `yaml:"header"`
|
||||
Issues IssueOptions `yaml:"issues"`
|
||||
Refs RefOptions `yaml:"refs"`
|
||||
Merges PatternOptions `yaml:"merges"`
|
||||
Reverts PatternOptions `yaml:"reverts"`
|
||||
Notes NoteOptions `yaml:"notes"`
|
||||
}
|
||||
|
||||
// Config ...
|
||||
type Config struct {
|
||||
Bin string `yaml:"bin"`
|
||||
Template string `yaml:"template"`
|
||||
Style string `yaml:"style"`
|
||||
Info Info `yaml:"info"`
|
||||
Options Options `yaml:"options"`
|
||||
}
|
||||
|
||||
// Normalize ...
|
||||
func (config *Config) Normalize(ctx *Context) error {
|
||||
err := mergo.Merge(config, &Config{
|
||||
Bin: "git",
|
||||
Template: "CHANGELOG.tpl.md",
|
||||
Info: Info{
|
||||
Title: "CHANGELOG",
|
||||
},
|
||||
Options: Options{
|
||||
Commits: CommitOptions{
|
||||
SortBy: "Scope",
|
||||
},
|
||||
CommitGroups: CommitGroupOptions{
|
||||
GroupBy: "Type",
|
||||
SortBy: "Title",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config.Info.RepositoryURL = strings.TrimRight(config.Info.RepositoryURL, "/")
|
||||
|
||||
if !filepath.IsAbs(config.Template) {
|
||||
config.Template = filepath.Join(filepath.Dir(ctx.ConfigPath), config.Template)
|
||||
}
|
||||
|
||||
config.normalizeStyle()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Normalize style
|
||||
func (config *Config) normalizeStyle() {
|
||||
switch config.Style {
|
||||
case "github":
|
||||
config.normalizeStyleOfGitHub()
|
||||
}
|
||||
}
|
||||
|
||||
// For GitHub
|
||||
func (config *Config) normalizeStyleOfGitHub() {
|
||||
opts := config.Options
|
||||
|
||||
if len(opts.Issues.Prefix) == 0 {
|
||||
opts.Issues.Prefix = []string{
|
||||
"#",
|
||||
"gh-",
|
||||
}
|
||||
}
|
||||
|
||||
if len(opts.Refs.Actions) == 0 {
|
||||
opts.Refs.Actions = []string{
|
||||
"close",
|
||||
"closes",
|
||||
"closed",
|
||||
"fix",
|
||||
"fixes",
|
||||
"fixed",
|
||||
"resolve",
|
||||
"resolves",
|
||||
"resolved",
|
||||
}
|
||||
}
|
||||
|
||||
if opts.Merges.Pattern == "" && len(opts.Merges.PatternMaps) == 0 {
|
||||
opts.Merges.Pattern = "^Merge pull request #(\\d+) from (.*)$"
|
||||
opts.Merges.PatternMaps = []string{
|
||||
"Ref",
|
||||
"Source",
|
||||
}
|
||||
}
|
||||
|
||||
config.Options = opts
|
||||
}
|
||||
|
||||
// Convert ...
|
||||
func (config *Config) Convert(ctx *Context) *chglog.Config {
|
||||
info := config.Info
|
||||
opts := config.Options
|
||||
|
||||
return &chglog.Config{
|
||||
Bin: config.Bin,
|
||||
WorkingDir: ctx.WorkingDir,
|
||||
Template: config.Template,
|
||||
Info: &chglog.Info{
|
||||
Title: info.Title,
|
||||
RepositoryURL: info.RepositoryURL,
|
||||
},
|
||||
Options: &chglog.Options{
|
||||
CommitFilters: opts.Commits.Filters,
|
||||
CommitSortBy: opts.Commits.SortBy,
|
||||
CommitGroupBy: opts.CommitGroups.GroupBy,
|
||||
CommitGroupSortBy: opts.CommitGroups.SortBy,
|
||||
CommitGroupTitleMaps: opts.CommitGroups.TitleMaps,
|
||||
HeaderPattern: opts.Header.Pattern,
|
||||
HeaderPatternMaps: opts.Header.PatternMaps,
|
||||
IssuePrefix: opts.Issues.Prefix,
|
||||
RefActions: opts.Refs.Actions,
|
||||
MergePattern: opts.Merges.Pattern,
|
||||
MergePatternMaps: opts.Merges.PatternMaps,
|
||||
RevertPattern: opts.Reverts.Pattern,
|
||||
RevertPatternMaps: opts.Reverts.PatternMaps,
|
||||
NoteKeywords: opts.Notes.Keywords,
|
||||
},
|
||||
}
|
||||
}
|
||||
35
cmd/git-chglog/config_loader.go
Normal file
35
cmd/git-chglog/config_loader.go
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// ConfigLoader ...
|
||||
type ConfigLoader interface {
|
||||
Load(string) (*Config, error)
|
||||
}
|
||||
|
||||
type configLoaderImpl struct {
|
||||
}
|
||||
|
||||
// NewConfigLoader ...
|
||||
func NewConfigLoader() ConfigLoader {
|
||||
return &configLoaderImpl{}
|
||||
}
|
||||
|
||||
func (loader *configLoaderImpl) Load(path string) (*Config, error) {
|
||||
bytes, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config := &Config{}
|
||||
err = yaml.Unmarshal(bytes, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
9
cmd/git-chglog/config_loader_mock.go
Normal file
9
cmd/git-chglog/config_loader_mock.go
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
package main
|
||||
|
||||
type mockConfigLoaderImpl struct {
|
||||
ReturnLoad func(string) (*Config, error)
|
||||
}
|
||||
|
||||
func (m *mockConfigLoaderImpl) Load(path string) (*Config, error) {
|
||||
return m.ReturnLoad(path)
|
||||
}
|
||||
39
cmd/git-chglog/config_test.go
Normal file
39
cmd/git-chglog/config_test.go
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestConfigNormalize(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
// basic
|
||||
config := &Config{
|
||||
Info: Info{
|
||||
RepositoryURL: "https://example.com/foo/bar/",
|
||||
},
|
||||
}
|
||||
|
||||
err := config.Normalize(&Context{
|
||||
ConfigPath: "/test/config.yml",
|
||||
})
|
||||
|
||||
assert.Nil(err)
|
||||
assert.Equal("git", config.Bin)
|
||||
assert.Equal("https://example.com/foo/bar", config.Info.RepositoryURL)
|
||||
assert.Equal("/test/CHANGELOG.tpl.md", config.Template)
|
||||
|
||||
// abs template
|
||||
config = &Config{
|
||||
Template: "/CHANGELOG.tpl.md",
|
||||
}
|
||||
|
||||
err = config.Normalize(&Context{
|
||||
ConfigPath: "/test/config.yml",
|
||||
})
|
||||
|
||||
assert.Nil(err)
|
||||
assert.Equal("/CHANGELOG.tpl.md", config.Template)
|
||||
}
|
||||
18
cmd/git-chglog/context.go
Normal file
18
cmd/git-chglog/context.go
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// Context ...
|
||||
type Context struct {
|
||||
WorkingDir string
|
||||
Stdout io.Writer
|
||||
Stderr io.Writer
|
||||
ConfigPath string
|
||||
OutputPath string
|
||||
Silent bool
|
||||
NoColor bool
|
||||
NoEmoji bool
|
||||
Query string
|
||||
}
|
||||
37
cmd/git-chglog/fs.go
Normal file
37
cmd/git-chglog/fs.go
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// FileSystem ...
|
||||
type FileSystem interface {
|
||||
MkdirP(path string) error
|
||||
Create(name string) (File, error)
|
||||
}
|
||||
|
||||
// File ...
|
||||
type File interface {
|
||||
io.Closer
|
||||
io.Reader
|
||||
io.ReaderAt
|
||||
io.Seeker
|
||||
io.Writer
|
||||
Stat() (os.FileInfo, error)
|
||||
}
|
||||
|
||||
var fs = &osFileSystem{}
|
||||
|
||||
type osFileSystem struct{}
|
||||
|
||||
func (*osFileSystem) MkdirP(path string) error {
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
return os.MkdirAll(path, os.ModePerm)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*osFileSystem) Create(name string) (File, error) {
|
||||
return os.Create(name)
|
||||
}
|
||||
23
cmd/git-chglog/fs_mock.go
Normal file
23
cmd/git-chglog/fs_mock.go
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
package main
|
||||
|
||||
type mockFileSystem struct {
|
||||
ReturnMkdirP func(string) error
|
||||
ReturnCreate func(string) (File, error)
|
||||
}
|
||||
|
||||
func (m *mockFileSystem) MkdirP(path string) error {
|
||||
return m.ReturnMkdirP(path)
|
||||
}
|
||||
|
||||
func (m *mockFileSystem) Create(name string) (File, error) {
|
||||
return m.ReturnCreate(name)
|
||||
}
|
||||
|
||||
type mockFile struct {
|
||||
File
|
||||
ReturnWrite func([]byte) (int, error)
|
||||
}
|
||||
|
||||
func (m *mockFile) Write(b []byte) (int, error) {
|
||||
return m.ReturnWrite(b)
|
||||
}
|
||||
24
cmd/git-chglog/generator.go
Normal file
24
cmd/git-chglog/generator.go
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
chglog "github.com/git-chglog/git-chglog"
|
||||
)
|
||||
|
||||
// Generator ...
|
||||
type Generator interface {
|
||||
Generate(io.Writer, string, *chglog.Config) error
|
||||
}
|
||||
|
||||
type generatorImpl struct{}
|
||||
|
||||
// NewGenerator ...
|
||||
func NewGenerator() Generator {
|
||||
return &generatorImpl{}
|
||||
}
|
||||
|
||||
// Generate ...
|
||||
func (*generatorImpl) Generate(w io.Writer, query string, config *chglog.Config) error {
|
||||
return chglog.NewGenerator(config).Generate(w, query)
|
||||
}
|
||||
15
cmd/git-chglog/generator_mock.go
Normal file
15
cmd/git-chglog/generator_mock.go
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
chglog "github.com/git-chglog/git-chglog"
|
||||
)
|
||||
|
||||
type mockGeneratorImpl struct {
|
||||
ReturnGenerate func(io.Writer, string, *chglog.Config) error
|
||||
}
|
||||
|
||||
func (m *mockGeneratorImpl) Generate(w io.Writer, query string, config *chglog.Config) error {
|
||||
return m.ReturnGenerate(w, query, config)
|
||||
}
|
||||
412
cmd/git-chglog/initializer.go
Normal file
412
cmd/git-chglog/initializer.go
Normal file
|
|
@ -0,0 +1,412 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/fatih/color"
|
||||
gitcmd "github.com/tsuyoshiwada/go-gitcmd"
|
||||
survey "gopkg.in/AlecAivazis/survey.v1"
|
||||
emoji "gopkg.in/kyokomi/emoji.v1"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultConfigFilename = "config.yml"
|
||||
defaultTemplateFilename = "CHANGELOG.tpl.md"
|
||||
|
||||
styleGitHub = "github"
|
||||
styleNone = "none"
|
||||
changelogStyles = []string{
|
||||
styleGitHub,
|
||||
styleNone,
|
||||
}
|
||||
|
||||
fmtTypeScopeSubject = "<type>(<scope>): <subject>"
|
||||
fmtTypeSubject = "<type>: <subject>"
|
||||
fmtSubject = "<subject>"
|
||||
commitMessageFormats = []string{
|
||||
fmtTypeScopeSubject,
|
||||
fmtTypeSubject,
|
||||
fmtSubject,
|
||||
}
|
||||
|
||||
tplStandard = "standard"
|
||||
tplCool = "rich"
|
||||
templateStyles = []string{
|
||||
tplStandard,
|
||||
tplCool,
|
||||
}
|
||||
)
|
||||
|
||||
// Answer ...
|
||||
type Answer struct {
|
||||
RepositoryURL string `survey:"repository_url"`
|
||||
Style string `survey:"style"`
|
||||
CommitMessageFormat string `survey:"commit_message_format"`
|
||||
Template string `survey:"template"`
|
||||
IncludeMerges bool `survey:"include_merges"`
|
||||
IncludeReverts bool `survey:"include_reverts"`
|
||||
ConfigDir string `survey:"config_dir"`
|
||||
}
|
||||
|
||||
// Initializer ...
|
||||
type Initializer struct {
|
||||
client gitcmd.Client
|
||||
}
|
||||
|
||||
// NewInitializer ...
|
||||
func NewInitializer() *Initializer {
|
||||
return &Initializer{
|
||||
client: gitcmd.New(&gitcmd.Config{
|
||||
Bin: "git",
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
// Run ...
|
||||
func (init *Initializer) Run() int {
|
||||
answer, err := init.ask()
|
||||
if err != nil {
|
||||
return ExitCodeError
|
||||
}
|
||||
|
||||
err = init.generateConfigure(answer)
|
||||
if err != nil {
|
||||
return ExitCodeError
|
||||
}
|
||||
|
||||
success := color.CyanString("✔")
|
||||
emoji.Fprintf(os.Stdout, `
|
||||
:sparkles:%s
|
||||
%s %s
|
||||
%s %s
|
||||
|
||||
`,
|
||||
color.GreenString("Configuration file and template generation completed!"),
|
||||
success,
|
||||
filepath.Join(answer.ConfigDir, defaultConfigFilename),
|
||||
success,
|
||||
filepath.Join(answer.ConfigDir, defaultTemplateFilename),
|
||||
)
|
||||
|
||||
return ExitCodeOK
|
||||
}
|
||||
|
||||
func (init *Initializer) ask() (*Answer, error) {
|
||||
answer := &Answer{}
|
||||
qs := init.createQuestions()
|
||||
err := survey.Ask(qs, answer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return answer, nil
|
||||
}
|
||||
|
||||
func (init *Initializer) createQuestions() []*survey.Question {
|
||||
originURL := init.getRepositoryURL()
|
||||
|
||||
return []*survey.Question{
|
||||
{
|
||||
Name: "repository_url",
|
||||
Prompt: &survey.Input{
|
||||
Message: "What is the URL of your repository?",
|
||||
Default: originURL,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "style",
|
||||
Prompt: &survey.Select{
|
||||
Message: "What is your favorite style?",
|
||||
Options: changelogStyles,
|
||||
Default: changelogStyles[0],
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "commit_message_format",
|
||||
Prompt: &survey.Select{
|
||||
Message: "Choose the format of your favorite commit message",
|
||||
Options: commitMessageFormats,
|
||||
Default: commitMessageFormats[0],
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "template",
|
||||
Prompt: &survey.Select{
|
||||
Message: "What is your favorite template style?",
|
||||
Options: templateStyles,
|
||||
Default: templateStyles[0],
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "include_merges",
|
||||
Prompt: &survey.Confirm{
|
||||
Message: "Do you include Merge Commit in CHANGELOG?",
|
||||
Default: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "include_reverts",
|
||||
Prompt: &survey.Confirm{
|
||||
Message: "Do you include Revert Commit in CHANGELOG?",
|
||||
Default: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "config_dir",
|
||||
Prompt: &survey.Input{
|
||||
Message: "In which directory do you output configuration files and templates?",
|
||||
Default: ".chglog",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (init *Initializer) getRepositoryURL() string {
|
||||
if init.client.CanExec() != nil || init.client.InsideWorkTree() != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
rawurl, err := init.client.Exec("config", "--get", "remote.origin.url")
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return remoteOriginURLToHTTP(rawurl)
|
||||
}
|
||||
|
||||
func (init *Initializer) generateConfigure(answer *Answer) error {
|
||||
var err error
|
||||
|
||||
err = fs.MkdirP(answer.ConfigDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config := init.createConfigYamlContent(answer)
|
||||
tpl := init.createTemplate(answer)
|
||||
|
||||
configPath := filepath.Join(answer.ConfigDir, defaultConfigFilename)
|
||||
templatePath := filepath.Join(answer.ConfigDir, defaultTemplateFilename)
|
||||
|
||||
err = init.createFileWithConfirm(configPath, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = init.createFileWithConfirm(templatePath, tpl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*Initializer) createFileWithConfirm(path, content string) error {
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
answer := struct {
|
||||
OK bool
|
||||
}{}
|
||||
|
||||
err := survey.Ask([]*survey.Question{
|
||||
{
|
||||
Name: "ok",
|
||||
Prompt: &survey.Confirm{
|
||||
Message: fmt.Sprintf("\"%s\" already exists. Do you want to overwrite?", path),
|
||||
Default: true,
|
||||
},
|
||||
},
|
||||
}, &answer)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !answer.OK {
|
||||
return errors.New("creation of the file was interrupted")
|
||||
}
|
||||
}
|
||||
|
||||
err := ioutil.WriteFile(path, []byte(content), os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (init *Initializer) createConfigYamlContent(answer *Answer) string {
|
||||
var (
|
||||
style = answer.Style
|
||||
template = defaultTemplateFilename
|
||||
repositoryURL = answer.RepositoryURL
|
||||
headerPattern string
|
||||
headerPatternMaps string
|
||||
)
|
||||
|
||||
switch answer.CommitMessageFormat {
|
||||
case fmtTypeScopeSubject:
|
||||
headerPattern = `^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$`
|
||||
headerPatternMaps = `
|
||||
- Type
|
||||
- Scope
|
||||
- Subject`
|
||||
case fmtTypeSubject:
|
||||
headerPattern = `^(\\w*)\\:\\s(.*)$`
|
||||
headerPatternMaps = `
|
||||
- Type
|
||||
- Subject`
|
||||
case fmtSubject:
|
||||
headerPattern = `^(.*)$`
|
||||
headerPatternMaps = `
|
||||
- Subject`
|
||||
}
|
||||
|
||||
config := fmt.Sprintf(`style: %s
|
||||
template: %s
|
||||
info:
|
||||
title: CHANGELOG
|
||||
repository_url: %s
|
||||
options:
|
||||
commits:
|
||||
# filters:
|
||||
# Type:
|
||||
# - feat
|
||||
# - fix
|
||||
# - perf
|
||||
# - refactor
|
||||
commit_groups:
|
||||
# title_maps:
|
||||
# feat: Features
|
||||
# fix: Bug Fixes
|
||||
# perf: Performance Improvements
|
||||
# refactor: Code Refactoring
|
||||
header:
|
||||
pattern: "%s"
|
||||
pattern_maps:%s
|
||||
notes:
|
||||
keywords:
|
||||
- BREAKING CHANGE`,
|
||||
style,
|
||||
template,
|
||||
repositoryURL,
|
||||
headerPattern,
|
||||
headerPatternMaps,
|
||||
)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
func (init *Initializer) createTemplate(answer *Answer) string {
|
||||
tpl := "{{range .Versions}}\n"
|
||||
|
||||
// versions
|
||||
tpl += init.versionHeader(answer.Style, answer.Template)
|
||||
|
||||
// commits
|
||||
tpl += init.commits(answer.Style, answer.Template, answer.CommitMessageFormat)
|
||||
|
||||
// merges
|
||||
if answer.IncludeReverts {
|
||||
tpl += `{{if .RevertCommits}}
|
||||
### Reverts
|
||||
{{range .RevertCommits}}
|
||||
* {{.Header}}{{end}}
|
||||
{{end}}`
|
||||
}
|
||||
|
||||
// reverts
|
||||
if answer.IncludeReverts {
|
||||
tpl += fmt.Sprintf(`{{if .MergeCommits}}
|
||||
### %s
|
||||
{{range .MergeCommits}}
|
||||
* {{.Header}}{{end}}
|
||||
{{end}}`, init.mergeTitle(answer.Style))
|
||||
}
|
||||
|
||||
tpl += `{{range .NoteGroups}}
|
||||
### {{.Title}}
|
||||
{{range .Notes}}
|
||||
{{.Body}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}`
|
||||
|
||||
return tpl
|
||||
}
|
||||
|
||||
func (*Initializer) versionHeader(style, template string) string {
|
||||
var (
|
||||
tpl string
|
||||
tagName string
|
||||
date = "{{datetime \"2006-01-02\" .Tag.Date}}"
|
||||
)
|
||||
|
||||
// parts
|
||||
switch style {
|
||||
case styleGitHub:
|
||||
tpl = "<a name=\"{{.Tag.Name}}\"></a>\n"
|
||||
tagName = "{{if .Tag.Previous}}[{{.Tag.Name}}]({{$.Info.RepositoryURL}}/compare/{{.Tag.Previous.Name}}...{{.Tag.Name}}){{else}}{{.Tag.Name}}{{end}}"
|
||||
default:
|
||||
tagName = "{{.Tag.Name}}"
|
||||
}
|
||||
|
||||
// format
|
||||
switch template {
|
||||
case tplStandard:
|
||||
tpl = fmt.Sprintf("%s## %s (%s)\n",
|
||||
tpl,
|
||||
tagName,
|
||||
date,
|
||||
)
|
||||
case tplCool:
|
||||
tpl = fmt.Sprintf("%s## %s\n\n> %s\n",
|
||||
tpl,
|
||||
tagName,
|
||||
date,
|
||||
)
|
||||
}
|
||||
|
||||
return tpl
|
||||
}
|
||||
|
||||
func (*Initializer) commits(style, template, format string) string {
|
||||
var (
|
||||
header string
|
||||
body string
|
||||
)
|
||||
|
||||
switch format {
|
||||
case fmtTypeScopeSubject, fmtTypeSubject:
|
||||
if format == fmtTypeScopeSubject {
|
||||
header = "{{if ne .Scope \"\"}}**{{.Scope}}:** {{end}}{{.Subject}}"
|
||||
} else {
|
||||
header = "{{.Subject}}"
|
||||
}
|
||||
|
||||
body = fmt.Sprintf(`### {{.Title}}
|
||||
{{range .Commits}}
|
||||
* %s{{end}}
|
||||
`, header)
|
||||
|
||||
case fmtSubject:
|
||||
body = `{{range .Commits}}
|
||||
* {{.Header}}{{end}}
|
||||
`
|
||||
}
|
||||
|
||||
return fmt.Sprintf(`{{range .CommitGroups}}
|
||||
%s{{end}}`, body)
|
||||
}
|
||||
|
||||
func (*Initializer) mergeTitle(style string) string {
|
||||
switch style {
|
||||
case styleGitHub:
|
||||
return "Pull Requests"
|
||||
default:
|
||||
return "Merges"
|
||||
}
|
||||
}
|
||||
59
cmd/git-chglog/logger.go
Normal file
59
cmd/git-chglog/logger.go
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"regexp"
|
||||
|
||||
"github.com/fatih/color"
|
||||
emoji "gopkg.in/kyokomi/emoji.v1"
|
||||
)
|
||||
|
||||
// Logger ...
|
||||
type Logger struct {
|
||||
stdout io.Writer
|
||||
stderr io.Writer
|
||||
silent bool
|
||||
noEmoji bool
|
||||
reEmoji *regexp.Regexp
|
||||
}
|
||||
|
||||
// NewLogger ...
|
||||
func NewLogger(stdout, stderr io.Writer, silent, noEmoji bool) *Logger {
|
||||
return &Logger{
|
||||
stdout: stdout,
|
||||
stderr: stderr,
|
||||
silent: silent,
|
||||
noEmoji: noEmoji,
|
||||
reEmoji: regexp.MustCompile(":[\\w\\+_\\-]+:\\s?"),
|
||||
}
|
||||
}
|
||||
|
||||
// Log ...
|
||||
func (l *Logger) Log(msg string) {
|
||||
if !l.silent {
|
||||
l.log(l.stdout, msg+"\n")
|
||||
}
|
||||
}
|
||||
|
||||
// Error ...
|
||||
func (l *Logger) Error(msg string) {
|
||||
prefix := color.New(color.FgWhite, color.BgRed, color.Bold).SprintFunc()
|
||||
l.log(l.stderr, fmt.Sprintf("%s %s\n", prefix(" ERROR "), color.RedString(msg)))
|
||||
}
|
||||
|
||||
func (l *Logger) log(w io.Writer, msg string) {
|
||||
var printer func(io.Writer, ...interface{}) (int, error)
|
||||
|
||||
if l.noEmoji {
|
||||
msg = l.reEmoji.ReplaceAllString(msg, "")
|
||||
printer = fmt.Fprint
|
||||
} else {
|
||||
printer = emoji.Fprint
|
||||
}
|
||||
|
||||
if _, err := printer(w, msg); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
75
cmd/git-chglog/logger_test.go
Normal file
75
cmd/git-chglog/logger_test.go
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/stretchr/testify/assert"
|
||||
emoji "gopkg.in/kyokomi/emoji.v1"
|
||||
)
|
||||
|
||||
func TestLoggerLogSilent(t *testing.T) {
|
||||
color.NoColor = false
|
||||
assert := assert.New(t)
|
||||
|
||||
stdout := &bytes.Buffer{}
|
||||
stderr := &bytes.Buffer{}
|
||||
logger := NewLogger(stdout, stderr, true, false)
|
||||
logger.Log(":+1:Hello, World! :)")
|
||||
assert.Equal("", stdout.String())
|
||||
}
|
||||
|
||||
func TestLoggerLog(t *testing.T) {
|
||||
color.NoColor = false
|
||||
assert := assert.New(t)
|
||||
|
||||
stdout := &bytes.Buffer{}
|
||||
stderr := &bytes.Buffer{}
|
||||
logger := NewLogger(stdout, stderr, false, false)
|
||||
logger.Log(":+1:Hello, World! :)")
|
||||
assert.Equal(emoji.Sprint(":+1:Hello, World! :)\n"), stdout.String())
|
||||
}
|
||||
|
||||
func TestLoggerLogNoEmoji(t *testing.T) {
|
||||
color.NoColor = false
|
||||
assert := assert.New(t)
|
||||
|
||||
stdout := &bytes.Buffer{}
|
||||
stderr := &bytes.Buffer{}
|
||||
logger := NewLogger(stdout, stderr, false, true)
|
||||
logger.Log(":+1:Hello, World! :)")
|
||||
assert.Equal(fmt.Sprint("Hello, World! :)\n"), stdout.String())
|
||||
}
|
||||
|
||||
func TestLoggerError(t *testing.T) {
|
||||
color.NoColor = false
|
||||
assert := assert.New(t)
|
||||
|
||||
prefix := color.New(color.FgWhite, color.BgRed, color.Bold).SprintFunc()
|
||||
|
||||
// Basic
|
||||
stdout := &bytes.Buffer{}
|
||||
stderr := &bytes.Buffer{}
|
||||
logger := NewLogger(stdout, stderr, false, false)
|
||||
logger.Error("This is error message!! :dog:")
|
||||
assert.Equal("", stdout.String())
|
||||
assert.Equal(emoji.Sprint(fmt.Sprintf("%s %s\n", prefix(" ERROR "), color.RedString("This is error message!! :dog:"))), stderr.String())
|
||||
|
||||
// Silent
|
||||
stdout = &bytes.Buffer{}
|
||||
stderr = &bytes.Buffer{}
|
||||
logger = NewLogger(stdout, stderr, true, false)
|
||||
logger.Error("Foo")
|
||||
assert.Equal("", stdout.String())
|
||||
assert.NotEqual("", stderr.String())
|
||||
|
||||
// NoEmoji
|
||||
stdout = &bytes.Buffer{}
|
||||
stderr = &bytes.Buffer{}
|
||||
logger = NewLogger(stdout, stderr, true, true)
|
||||
logger.Error("HOGE :hand:")
|
||||
assert.Equal("", stdout.String())
|
||||
assert.NotContains(stderr.String(), emoji.Sprint(":hand:"))
|
||||
}
|
||||
128
cmd/git-chglog/main.go
Normal file
128
cmd/git-chglog/main.go
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ttl := color.New(color.FgYellow).SprintFunc()
|
||||
|
||||
cli.AppHelpTemplate = fmt.Sprintf(`
|
||||
%s
|
||||
{{.Name}} [options] [tag revision]
|
||||
|
||||
%s
|
||||
{{.Version}}{{if .Author}}
|
||||
|
||||
%s
|
||||
{{.Author}}{{end}}
|
||||
|
||||
%s
|
||||
{{range .Flags}}{{.}}
|
||||
{{end}}
|
||||
%s
|
||||
{{.Name}} todo1
|
||||
{{.Name}} todo2
|
||||
{{.Name}} todo3
|
||||
{{.Name}} todo4
|
||||
`,
|
||||
ttl("USAGE:"),
|
||||
ttl("VERSION:"),
|
||||
ttl("AUTHOR:"),
|
||||
ttl("OPTIONS:"),
|
||||
ttl("EXAMPLE:"),
|
||||
)
|
||||
|
||||
app := cli.NewApp()
|
||||
app.Name = "git-chglog"
|
||||
app.Usage = "todo usage for git-chglog"
|
||||
app.Version = Version
|
||||
|
||||
app.Flags = []cli.Flag{
|
||||
// init
|
||||
cli.BoolFlag{
|
||||
Name: "init",
|
||||
Usage: "generate the git-chglog configuration file in interactive",
|
||||
},
|
||||
|
||||
// config
|
||||
cli.StringFlag{
|
||||
Name: "config, c",
|
||||
Usage: "specifies a different configuration file to pick up",
|
||||
Value: ".chglog/config.yml",
|
||||
},
|
||||
|
||||
// output
|
||||
cli.StringFlag{
|
||||
Name: "output, o",
|
||||
Usage: "output path and filename for the changelogs (default: output to stdout)",
|
||||
},
|
||||
|
||||
// silent
|
||||
cli.BoolFlag{
|
||||
Name: "silent",
|
||||
Usage: "disable stdout output",
|
||||
},
|
||||
|
||||
// no-color
|
||||
cli.BoolFlag{
|
||||
Name: "no-color",
|
||||
Usage: "disable color output",
|
||||
EnvVar: "NO_COLOR",
|
||||
},
|
||||
|
||||
// no-emoji
|
||||
cli.BoolFlag{
|
||||
Name: "no-emoji",
|
||||
Usage: "disable emoji output",
|
||||
EnvVar: "NO_EMOJI",
|
||||
},
|
||||
|
||||
// help & version
|
||||
cli.HelpFlag,
|
||||
cli.VersionFlag,
|
||||
}
|
||||
|
||||
app.Action = func(c *cli.Context) error {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "failed to get working directory", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// initializer
|
||||
if c.Bool("init") {
|
||||
os.Exit(NewInitializer().Run())
|
||||
}
|
||||
|
||||
// chglog
|
||||
ctx := &Context{
|
||||
WorkingDir: wd,
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stderr,
|
||||
ConfigPath: c.String("config"),
|
||||
OutputPath: c.String("output"),
|
||||
Silent: c.Bool("silent"),
|
||||
NoColor: c.Bool("no-color"),
|
||||
NoEmoji: c.Bool("no-emoji"),
|
||||
Query: c.Args().First(),
|
||||
}
|
||||
|
||||
chglogCLI := NewCLI(
|
||||
ctx,
|
||||
fs,
|
||||
NewConfigLoader(),
|
||||
NewGenerator(),
|
||||
)
|
||||
|
||||
os.Exit(chglogCLI.Run())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
app.Run(os.Args)
|
||||
}
|
||||
47
cmd/git-chglog/processor_factory.go
Normal file
47
cmd/git-chglog/processor_factory.go
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
chglog "github.com/git-chglog/git-chglog"
|
||||
)
|
||||
|
||||
// ProcessorFactory ...
|
||||
type ProcessorFactory struct {
|
||||
hostRegistry map[string]string
|
||||
}
|
||||
|
||||
// NewProcessorFactory ...
|
||||
func NewProcessorFactory() *ProcessorFactory {
|
||||
return &ProcessorFactory{
|
||||
hostRegistry: map[string]string{
|
||||
"github": "github.com",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Create ...
|
||||
func (factory *ProcessorFactory) Create(config *Config) (chglog.Processor, error) {
|
||||
obj, err := url.Parse(config.Info.RepositoryURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
host := obj.Host
|
||||
|
||||
if config.Style != "" {
|
||||
if styleHost, ok := factory.hostRegistry[config.Style]; ok {
|
||||
host = styleHost
|
||||
}
|
||||
}
|
||||
|
||||
switch host {
|
||||
case "github.com":
|
||||
return &chglog.GitHubProcessor{
|
||||
Host: fmt.Sprintf("%s://%s", obj.Scheme, obj.Host),
|
||||
}, nil
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
58
cmd/git-chglog/processor_factory_test.go
Normal file
58
cmd/git-chglog/processor_factory_test.go
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
chglog "github.com/git-chglog/git-chglog"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestProcessorFactory(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
factory := NewProcessorFactory()
|
||||
|
||||
processor, err := factory.Create(&Config{
|
||||
Info: Info{
|
||||
RepositoryURL: "https://example.com/owner/repo",
|
||||
},
|
||||
})
|
||||
|
||||
assert.Nil(err)
|
||||
assert.Nil(processor)
|
||||
}
|
||||
|
||||
func TestProcessorFactoryForGitHub(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
factory := NewProcessorFactory()
|
||||
|
||||
// github.com
|
||||
processor, err := factory.Create(&Config{
|
||||
Info: Info{
|
||||
RepositoryURL: "https://github.com/owner/repo",
|
||||
},
|
||||
})
|
||||
|
||||
assert.Nil(err)
|
||||
assert.Equal(
|
||||
&chglog.GitHubProcessor{
|
||||
Host: "https://github.com",
|
||||
},
|
||||
processor,
|
||||
)
|
||||
|
||||
// ghe
|
||||
processor, err = factory.Create(&Config{
|
||||
Style: "github",
|
||||
Info: Info{
|
||||
RepositoryURL: "https://ghe-example.com/owner/repo",
|
||||
},
|
||||
})
|
||||
|
||||
assert.Nil(err)
|
||||
assert.Equal(
|
||||
&chglog.GitHubProcessor{
|
||||
Host: "https://ghe-example.com",
|
||||
},
|
||||
processor,
|
||||
)
|
||||
}
|
||||
7
cmd/git-chglog/status_code.go
Normal file
7
cmd/git-chglog/status_code.go
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
package main
|
||||
|
||||
// Status code
|
||||
const (
|
||||
ExitCodeOK = iota
|
||||
ExitCodeError
|
||||
)
|
||||
47
cmd/git-chglog/utils.go
Normal file
47
cmd/git-chglog/utils.go
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var reSSH = regexp.MustCompile("^\\w+@([\\w\\.\\-]+):([\\w\\.\\-]+)\\/([\\w\\.\\-]+)$")
|
||||
|
||||
func remoteOriginURLToHTTP(rawurl string) string {
|
||||
if rawurl == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
rawurl = strings.TrimSuffix(rawurl, ".git")
|
||||
|
||||
// for normal url format
|
||||
originURL, err := url.Parse(rawurl)
|
||||
|
||||
if err == nil {
|
||||
scheme := originURL.Scheme
|
||||
if scheme != "http" {
|
||||
scheme = "https"
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
"%s://%s%s",
|
||||
scheme,
|
||||
originURL.Host,
|
||||
originURL.Path,
|
||||
)
|
||||
}
|
||||
|
||||
// for `user@server:repo.git`
|
||||
res := reSSH.FindAllStringSubmatch(rawurl, -1)
|
||||
if len(res) > 0 {
|
||||
return fmt.Sprintf(
|
||||
"https://%s/%s/%s",
|
||||
res[0][1],
|
||||
res[0][2],
|
||||
res[0][3],
|
||||
)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
23
cmd/git-chglog/utils_test.go
Normal file
23
cmd/git-chglog/utils_test.go
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRemoteOriginURLToHTTP(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
table := [][]string{
|
||||
{"git://github.com/owner0/repo0.git", "https://github.com/owner0/repo0"},
|
||||
{"git@github.com:owner1/repo1.git", "https://github.com/owner1/repo1"},
|
||||
{"git+ssh://git@github.com/owner2/repo2.git", "https://github.com/owner2/repo2"},
|
||||
{"https://github.com/owner3/repo3.git", "https://github.com/owner3/repo3"},
|
||||
{"", ""},
|
||||
}
|
||||
|
||||
for _, v := range table {
|
||||
assert.Equal(v[1], remoteOriginURLToHTTP(v[0]))
|
||||
}
|
||||
}
|
||||
4
cmd/git-chglog/version.go
Normal file
4
cmd/git-chglog/version.go
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
package main
|
||||
|
||||
// Version of git-chglog cli client
|
||||
const Version = "0.0.1"
|
||||
9
vendor/github.com/mgutz/ansi/LICENSE
generated
vendored
Normal file
9
vendor/github.com/mgutz/ansi/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
The MIT License (MIT)
|
||||
Copyright (c) 2013 Mario L. Gutierrez
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
285
vendor/github.com/mgutz/ansi/ansi.go
generated
vendored
Normal file
285
vendor/github.com/mgutz/ansi/ansi.go
generated
vendored
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
package ansi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
black = iota
|
||||
red
|
||||
green
|
||||
yellow
|
||||
blue
|
||||
magenta
|
||||
cyan
|
||||
white
|
||||
defaultt = 9
|
||||
|
||||
normalIntensityFG = 30
|
||||
highIntensityFG = 90
|
||||
normalIntensityBG = 40
|
||||
highIntensityBG = 100
|
||||
|
||||
start = "\033["
|
||||
bold = "1;"
|
||||
blink = "5;"
|
||||
underline = "4;"
|
||||
inverse = "7;"
|
||||
strikethrough = "9;"
|
||||
|
||||
// Reset is the ANSI reset escape sequence
|
||||
Reset = "\033[0m"
|
||||
// DefaultBG is the default background
|
||||
DefaultBG = "\033[49m"
|
||||
// DefaultFG is the default foreground
|
||||
DefaultFG = "\033[39m"
|
||||
)
|
||||
|
||||
// Black FG
|
||||
var Black string
|
||||
|
||||
// Red FG
|
||||
var Red string
|
||||
|
||||
// Green FG
|
||||
var Green string
|
||||
|
||||
// Yellow FG
|
||||
var Yellow string
|
||||
|
||||
// Blue FG
|
||||
var Blue string
|
||||
|
||||
// Magenta FG
|
||||
var Magenta string
|
||||
|
||||
// Cyan FG
|
||||
var Cyan string
|
||||
|
||||
// White FG
|
||||
var White string
|
||||
|
||||
// LightBlack FG
|
||||
var LightBlack string
|
||||
|
||||
// LightRed FG
|
||||
var LightRed string
|
||||
|
||||
// LightGreen FG
|
||||
var LightGreen string
|
||||
|
||||
// LightYellow FG
|
||||
var LightYellow string
|
||||
|
||||
// LightBlue FG
|
||||
var LightBlue string
|
||||
|
||||
// LightMagenta FG
|
||||
var LightMagenta string
|
||||
|
||||
// LightCyan FG
|
||||
var LightCyan string
|
||||
|
||||
// LightWhite FG
|
||||
var LightWhite string
|
||||
|
||||
var (
|
||||
plain = false
|
||||
// Colors maps common color names to their ANSI color code.
|
||||
Colors = map[string]int{
|
||||
"black": black,
|
||||
"red": red,
|
||||
"green": green,
|
||||
"yellow": yellow,
|
||||
"blue": blue,
|
||||
"magenta": magenta,
|
||||
"cyan": cyan,
|
||||
"white": white,
|
||||
"default": defaultt,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
for i := 0; i < 256; i++ {
|
||||
Colors[strconv.Itoa(i)] = i
|
||||
}
|
||||
|
||||
Black = ColorCode("black")
|
||||
Red = ColorCode("red")
|
||||
Green = ColorCode("green")
|
||||
Yellow = ColorCode("yellow")
|
||||
Blue = ColorCode("blue")
|
||||
Magenta = ColorCode("magenta")
|
||||
Cyan = ColorCode("cyan")
|
||||
White = ColorCode("white")
|
||||
LightBlack = ColorCode("black+h")
|
||||
LightRed = ColorCode("red+h")
|
||||
LightGreen = ColorCode("green+h")
|
||||
LightYellow = ColorCode("yellow+h")
|
||||
LightBlue = ColorCode("blue+h")
|
||||
LightMagenta = ColorCode("magenta+h")
|
||||
LightCyan = ColorCode("cyan+h")
|
||||
LightWhite = ColorCode("white+h")
|
||||
}
|
||||
|
||||
// ColorCode returns the ANSI color color code for style.
|
||||
func ColorCode(style string) string {
|
||||
return colorCode(style).String()
|
||||
}
|
||||
|
||||
// Gets the ANSI color code for a style.
|
||||
func colorCode(style string) *bytes.Buffer {
|
||||
buf := bytes.NewBufferString("")
|
||||
if plain || style == "" {
|
||||
return buf
|
||||
}
|
||||
if style == "reset" {
|
||||
buf.WriteString(Reset)
|
||||
return buf
|
||||
} else if style == "off" {
|
||||
return buf
|
||||
}
|
||||
|
||||
foregroundBackground := strings.Split(style, ":")
|
||||
foreground := strings.Split(foregroundBackground[0], "+")
|
||||
fgKey := foreground[0]
|
||||
fg := Colors[fgKey]
|
||||
fgStyle := ""
|
||||
if len(foreground) > 1 {
|
||||
fgStyle = foreground[1]
|
||||
}
|
||||
|
||||
bg, bgStyle := "", ""
|
||||
|
||||
if len(foregroundBackground) > 1 {
|
||||
background := strings.Split(foregroundBackground[1], "+")
|
||||
bg = background[0]
|
||||
if len(background) > 1 {
|
||||
bgStyle = background[1]
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteString(start)
|
||||
base := normalIntensityFG
|
||||
if len(fgStyle) > 0 {
|
||||
if strings.Contains(fgStyle, "b") {
|
||||
buf.WriteString(bold)
|
||||
}
|
||||
if strings.Contains(fgStyle, "B") {
|
||||
buf.WriteString(blink)
|
||||
}
|
||||
if strings.Contains(fgStyle, "u") {
|
||||
buf.WriteString(underline)
|
||||
}
|
||||
if strings.Contains(fgStyle, "i") {
|
||||
buf.WriteString(inverse)
|
||||
}
|
||||
if strings.Contains(fgStyle, "s") {
|
||||
buf.WriteString(strikethrough)
|
||||
}
|
||||
if strings.Contains(fgStyle, "h") {
|
||||
base = highIntensityFG
|
||||
}
|
||||
}
|
||||
|
||||
// if 256-color
|
||||
n, err := strconv.Atoi(fgKey)
|
||||
if err == nil {
|
||||
fmt.Fprintf(buf, "38;5;%d;", n)
|
||||
} else {
|
||||
fmt.Fprintf(buf, "%d;", base+fg)
|
||||
}
|
||||
|
||||
base = normalIntensityBG
|
||||
if len(bg) > 0 {
|
||||
if strings.Contains(bgStyle, "h") {
|
||||
base = highIntensityBG
|
||||
}
|
||||
// if 256-color
|
||||
n, err := strconv.Atoi(bg)
|
||||
if err == nil {
|
||||
fmt.Fprintf(buf, "48;5;%d;", n)
|
||||
} else {
|
||||
fmt.Fprintf(buf, "%d;", base+Colors[bg])
|
||||
}
|
||||
}
|
||||
|
||||
// remove last ";"
|
||||
buf.Truncate(buf.Len() - 1)
|
||||
buf.WriteRune('m')
|
||||
return buf
|
||||
}
|
||||
|
||||
// Color colors a string based on the ANSI color code for style.
|
||||
func Color(s, style string) string {
|
||||
if plain || len(style) < 1 {
|
||||
return s
|
||||
}
|
||||
buf := colorCode(style)
|
||||
buf.WriteString(s)
|
||||
buf.WriteString(Reset)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// ColorFunc creates a closure to avoid computation ANSI color code.
|
||||
func ColorFunc(style string) func(string) string {
|
||||
if style == "" {
|
||||
return func(s string) string {
|
||||
return s
|
||||
}
|
||||
}
|
||||
color := ColorCode(style)
|
||||
return func(s string) string {
|
||||
if plain || s == "" {
|
||||
return s
|
||||
}
|
||||
buf := bytes.NewBufferString(color)
|
||||
buf.WriteString(s)
|
||||
buf.WriteString(Reset)
|
||||
result := buf.String()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
// DisableColors disables ANSI color codes. The default is false (colors are on).
|
||||
func DisableColors(disable bool) {
|
||||
plain = disable
|
||||
if plain {
|
||||
Black = ""
|
||||
Red = ""
|
||||
Green = ""
|
||||
Yellow = ""
|
||||
Blue = ""
|
||||
Magenta = ""
|
||||
Cyan = ""
|
||||
White = ""
|
||||
LightBlack = ""
|
||||
LightRed = ""
|
||||
LightGreen = ""
|
||||
LightYellow = ""
|
||||
LightBlue = ""
|
||||
LightMagenta = ""
|
||||
LightCyan = ""
|
||||
LightWhite = ""
|
||||
} else {
|
||||
Black = ColorCode("black")
|
||||
Red = ColorCode("red")
|
||||
Green = ColorCode("green")
|
||||
Yellow = ColorCode("yellow")
|
||||
Blue = ColorCode("blue")
|
||||
Magenta = ColorCode("magenta")
|
||||
Cyan = ColorCode("cyan")
|
||||
White = ColorCode("white")
|
||||
LightBlack = ColorCode("black+h")
|
||||
LightRed = ColorCode("red+h")
|
||||
LightGreen = ColorCode("green+h")
|
||||
LightYellow = ColorCode("yellow+h")
|
||||
LightBlue = ColorCode("blue+h")
|
||||
LightMagenta = ColorCode("magenta+h")
|
||||
LightCyan = ColorCode("cyan+h")
|
||||
LightWhite = ColorCode("white+h")
|
||||
}
|
||||
}
|
||||
65
vendor/github.com/mgutz/ansi/doc.go
generated
vendored
Normal file
65
vendor/github.com/mgutz/ansi/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
Package ansi is a small, fast library to create ANSI colored strings and codes.
|
||||
|
||||
Installation
|
||||
|
||||
# this installs the color viewer and the package
|
||||
go get -u github.com/mgutz/ansi/cmd/ansi-mgutz
|
||||
|
||||
Example
|
||||
|
||||
// colorize a string, SLOW
|
||||
msg := ansi.Color("foo", "red+b:white")
|
||||
|
||||
// create a closure to avoid recalculating ANSI code compilation
|
||||
phosphorize := ansi.ColorFunc("green+h:black")
|
||||
msg = phosphorize("Bring back the 80s!")
|
||||
msg2 := phospohorize("Look, I'm a CRT!")
|
||||
|
||||
// cache escape codes and build strings manually
|
||||
lime := ansi.ColorCode("green+h:black")
|
||||
reset := ansi.ColorCode("reset")
|
||||
|
||||
fmt.Println(lime, "Bring back the 80s!", reset)
|
||||
|
||||
Other examples
|
||||
|
||||
Color(s, "red") // red
|
||||
Color(s, "red+b") // red bold
|
||||
Color(s, "red+B") // red blinking
|
||||
Color(s, "red+u") // red underline
|
||||
Color(s, "red+bh") // red bold bright
|
||||
Color(s, "red:white") // red on white
|
||||
Color(s, "red+b:white+h") // red bold on white bright
|
||||
Color(s, "red+B:white+h") // red blink on white bright
|
||||
|
||||
To view color combinations, from terminal
|
||||
|
||||
ansi-mgutz
|
||||
|
||||
Style format
|
||||
|
||||
"foregroundColor+attributes:backgroundColor+attributes"
|
||||
|
||||
Colors
|
||||
|
||||
black
|
||||
red
|
||||
green
|
||||
yellow
|
||||
blue
|
||||
magenta
|
||||
cyan
|
||||
white
|
||||
|
||||
Attributes
|
||||
|
||||
b = bold foreground
|
||||
B = Blink foreground
|
||||
u = underline foreground
|
||||
h = high intensity (bright) foreground, background
|
||||
i = inverse
|
||||
|
||||
Wikipedia ANSI escape codes [Colors](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors)
|
||||
*/
|
||||
package ansi
|
||||
57
vendor/github.com/mgutz/ansi/print.go
generated
vendored
Normal file
57
vendor/github.com/mgutz/ansi/print.go
generated
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package ansi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
colorable "github.com/mattn/go-colorable"
|
||||
)
|
||||
|
||||
// PrintStyles prints all style combinations to the terminal.
|
||||
func PrintStyles() {
|
||||
// for compatibility with Windows, not needed for *nix
|
||||
stdout := colorable.NewColorableStdout()
|
||||
|
||||
bgColors := []string{
|
||||
"",
|
||||
":black",
|
||||
":red",
|
||||
":green",
|
||||
":yellow",
|
||||
":blue",
|
||||
":magenta",
|
||||
":cyan",
|
||||
":white",
|
||||
}
|
||||
|
||||
keys := make([]string, 0, len(Colors))
|
||||
for k := range Colors {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
sort.Sort(sort.StringSlice(keys))
|
||||
|
||||
for _, fg := range keys {
|
||||
for _, bg := range bgColors {
|
||||
fmt.Fprintln(stdout, padColor(fg, []string{"" + bg, "+b" + bg, "+bh" + bg, "+u" + bg}))
|
||||
fmt.Fprintln(stdout, padColor(fg, []string{"+s" + bg, "+i" + bg}))
|
||||
fmt.Fprintln(stdout, padColor(fg, []string{"+uh" + bg, "+B" + bg, "+Bb" + bg /* backgrounds */, "" + bg + "+h"}))
|
||||
fmt.Fprintln(stdout, padColor(fg, []string{"+b" + bg + "+h", "+bh" + bg + "+h", "+u" + bg + "+h", "+uh" + bg + "+h"}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func pad(s string, length int) string {
|
||||
for len(s) < length {
|
||||
s += " "
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func padColor(color string, styles []string) string {
|
||||
buffer := ""
|
||||
for _, style := range styles {
|
||||
buffer += Color(pad(color+style, 20), color+style)
|
||||
}
|
||||
return buffer
|
||||
}
|
||||
21
vendor/gopkg.in/AlecAivazis/survey.v1/LICENSE
generated
vendored
Normal file
21
vendor/gopkg.in/AlecAivazis/survey.v1/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2016 Alec Aivazis
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
138
vendor/gopkg.in/AlecAivazis/survey.v1/confirm.go
generated
vendored
Normal file
138
vendor/gopkg.in/AlecAivazis/survey.v1/confirm.go
generated
vendored
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
package survey
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
|
||||
"gopkg.in/AlecAivazis/survey.v1/core"
|
||||
"gopkg.in/AlecAivazis/survey.v1/terminal"
|
||||
)
|
||||
|
||||
// Confirm is a regular text input that accept yes/no answers. Response type is a bool.
|
||||
type Confirm struct {
|
||||
core.Renderer
|
||||
Message string
|
||||
Default bool
|
||||
Help string
|
||||
}
|
||||
|
||||
// data available to the templates when processing
|
||||
type ConfirmTemplateData struct {
|
||||
Confirm
|
||||
Answer string
|
||||
ShowHelp bool
|
||||
}
|
||||
|
||||
// Templates with Color formatting. See Documentation: https://github.com/mgutz/ansi#style-format
|
||||
var ConfirmQuestionTemplate = `
|
||||
{{- if .ShowHelp }}{{- color "cyan"}}{{ HelpIcon }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}}
|
||||
{{- color "green+hb"}}{{ QuestionIcon }} {{color "reset"}}
|
||||
{{- color "default+hb"}}{{ .Message }} {{color "reset"}}
|
||||
{{- if .Answer}}
|
||||
{{- color "cyan"}}{{.Answer}}{{color "reset"}}{{"\n"}}
|
||||
{{- else }}
|
||||
{{- if and .Help (not .ShowHelp)}}{{color "cyan"}}[{{ HelpInputRune }} for help]{{color "reset"}} {{end}}
|
||||
{{- color "white"}}{{if .Default}}(Y/n) {{else}}(y/N) {{end}}{{color "reset"}}
|
||||
{{- end}}`
|
||||
|
||||
// the regex for answers
|
||||
var (
|
||||
yesRx = regexp.MustCompile("^(?i:y(?:es)?)$")
|
||||
noRx = regexp.MustCompile("^(?i:n(?:o)?)$")
|
||||
)
|
||||
|
||||
func yesNo(t bool) string {
|
||||
if t {
|
||||
return "Yes"
|
||||
}
|
||||
return "No"
|
||||
}
|
||||
|
||||
func (c *Confirm) getBool(showHelp bool) (bool, error) {
|
||||
rr := terminal.NewRuneReader(os.Stdin)
|
||||
rr.SetTermMode()
|
||||
defer rr.RestoreTermMode()
|
||||
// start waiting for input
|
||||
for {
|
||||
line, err := rr.ReadLine(0)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// move back up a line to compensate for the \n echoed from terminal
|
||||
terminal.CursorPreviousLine(1)
|
||||
val := string(line)
|
||||
|
||||
// get the answer that matches the
|
||||
var answer bool
|
||||
switch {
|
||||
case yesRx.Match([]byte(val)):
|
||||
answer = true
|
||||
case noRx.Match([]byte(val)):
|
||||
answer = false
|
||||
case val == "":
|
||||
answer = c.Default
|
||||
case val == string(core.HelpInputRune) && c.Help != "":
|
||||
err := c.Render(
|
||||
ConfirmQuestionTemplate,
|
||||
ConfirmTemplateData{Confirm: *c, ShowHelp: true},
|
||||
)
|
||||
if err != nil {
|
||||
// use the default value and bubble up
|
||||
return c.Default, err
|
||||
}
|
||||
showHelp = true
|
||||
continue
|
||||
default:
|
||||
// we didnt get a valid answer, so print error and prompt again
|
||||
if err := c.Error(fmt.Errorf("%q is not a valid answer, please try again.", val)); err != nil {
|
||||
return c.Default, err
|
||||
}
|
||||
err := c.Render(
|
||||
ConfirmQuestionTemplate,
|
||||
ConfirmTemplateData{Confirm: *c, ShowHelp: showHelp},
|
||||
)
|
||||
if err != nil {
|
||||
// use the default value and bubble up
|
||||
return c.Default, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
return answer, nil
|
||||
}
|
||||
// should not get here
|
||||
return c.Default, nil
|
||||
}
|
||||
|
||||
/*
|
||||
Prompt prompts the user with a simple text field and expects a reply followed
|
||||
by a carriage return.
|
||||
|
||||
likesPie := false
|
||||
prompt := &survey.Confirm{ Message: "What is your name?" }
|
||||
survey.AskOne(prompt, &likesPie, nil)
|
||||
*/
|
||||
func (c *Confirm) Prompt() (interface{}, error) {
|
||||
// render the question template
|
||||
err := c.Render(
|
||||
ConfirmQuestionTemplate,
|
||||
ConfirmTemplateData{Confirm: *c},
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// get input and return
|
||||
return c.getBool(false)
|
||||
}
|
||||
|
||||
// Cleanup overwrite the line with the finalized formatted version
|
||||
func (c *Confirm) Cleanup(val interface{}) error {
|
||||
// if the value was previously true
|
||||
ans := yesNo(val.(bool))
|
||||
// render the template
|
||||
return c.Render(
|
||||
ConfirmQuestionTemplate,
|
||||
ConfirmTemplateData{Confirm: *c, Answer: ans},
|
||||
)
|
||||
}
|
||||
62
vendor/gopkg.in/AlecAivazis/survey.v1/core/renderer.go
generated
vendored
Normal file
62
vendor/gopkg.in/AlecAivazis/survey.v1/core/renderer.go
generated
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"gopkg.in/AlecAivazis/survey.v1/terminal"
|
||||
)
|
||||
|
||||
type Renderer struct {
|
||||
lineCount int
|
||||
errorLineCount int
|
||||
}
|
||||
|
||||
var ErrorTemplate = `{{color "red"}}{{ ErrorIcon }} Sorry, your reply was invalid: {{.Error}}{{color "reset"}}
|
||||
`
|
||||
|
||||
func (r *Renderer) Error(invalid error) error {
|
||||
// since errors are printed on top we need to reset the prompt
|
||||
// as well as any previous error print
|
||||
r.resetPrompt(r.lineCount + r.errorLineCount)
|
||||
// we just cleared the prompt lines
|
||||
r.lineCount = 0
|
||||
out, err := RunTemplate(ErrorTemplate, invalid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// keep track of how many lines are printed so we can clean up later
|
||||
r.errorLineCount = strings.Count(out, "\n")
|
||||
|
||||
// send the message to the user
|
||||
terminal.Print(out)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Renderer) resetPrompt(lines int) {
|
||||
// clean out current line in case tmpl didnt end in newline
|
||||
terminal.CursorHorizontalAbsolute(0)
|
||||
terminal.EraseLine(terminal.ERASE_LINE_ALL)
|
||||
// clean up what we left behind last time
|
||||
for i := 0; i < lines; i++ {
|
||||
terminal.CursorPreviousLine(1)
|
||||
terminal.EraseLine(terminal.ERASE_LINE_ALL)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Renderer) Render(tmpl string, data interface{}) error {
|
||||
r.resetPrompt(r.lineCount)
|
||||
// render the template summarizing the current state
|
||||
out, err := RunTemplate(tmpl, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// keep track of how many lines are printed so we can clean up later
|
||||
r.lineCount = strings.Count(out, "\n")
|
||||
|
||||
// print the summary
|
||||
terminal.Print(out)
|
||||
|
||||
// nothing went wrong
|
||||
return nil
|
||||
}
|
||||
83
vendor/gopkg.in/AlecAivazis/survey.v1/core/template.go
generated
vendored
Normal file
83
vendor/gopkg.in/AlecAivazis/survey.v1/core/template.go
generated
vendored
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"text/template"
|
||||
|
||||
"github.com/mgutz/ansi"
|
||||
)
|
||||
|
||||
var DisableColor = false
|
||||
|
||||
var (
|
||||
HelpInputRune = '?'
|
||||
|
||||
ErrorIcon = "✘"
|
||||
HelpIcon = "ⓘ"
|
||||
QuestionIcon = "?"
|
||||
|
||||
MarkedOptionIcon = "◉"
|
||||
UnmarkedOptionIcon = "◯"
|
||||
|
||||
SelectFocusIcon = "❯"
|
||||
)
|
||||
|
||||
var TemplateFuncs = map[string]interface{}{
|
||||
// Templates with Color formatting. See Documentation: https://github.com/mgutz/ansi#style-format
|
||||
"color": func(color string) string {
|
||||
if DisableColor {
|
||||
return ""
|
||||
}
|
||||
return ansi.ColorCode(color)
|
||||
},
|
||||
"HelpInputRune": func() string {
|
||||
return string(HelpInputRune)
|
||||
},
|
||||
"ErrorIcon": func() string {
|
||||
return ErrorIcon
|
||||
},
|
||||
"HelpIcon": func() string {
|
||||
return HelpIcon
|
||||
},
|
||||
"QuestionIcon": func() string {
|
||||
return QuestionIcon
|
||||
},
|
||||
"MarkedOptionIcon": func() string {
|
||||
return MarkedOptionIcon
|
||||
},
|
||||
"UnmarkedOptionIcon": func() string {
|
||||
return UnmarkedOptionIcon
|
||||
},
|
||||
"SelectFocusIcon": func() string {
|
||||
return SelectFocusIcon
|
||||
},
|
||||
}
|
||||
|
||||
var memoizedGetTemplate = map[string]*template.Template{}
|
||||
|
||||
func getTemplate(tmpl string) (*template.Template, error) {
|
||||
if t, ok := memoizedGetTemplate[tmpl]; ok {
|
||||
return t, nil
|
||||
}
|
||||
|
||||
t, err := template.New("prompt").Funcs(TemplateFuncs).Parse(tmpl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
memoizedGetTemplate[tmpl] = t
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func RunTemplate(tmpl string, data interface{}) (string, error) {
|
||||
t, err := getTemplate(tmpl)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
buf := bytes.NewBufferString("")
|
||||
err = t.Execute(buf, data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return buf.String(), err
|
||||
}
|
||||
246
vendor/gopkg.in/AlecAivazis/survey.v1/core/write.go
generated
vendored
Normal file
246
vendor/gopkg.in/AlecAivazis/survey.v1/core/write.go
generated
vendored
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// the tag used to denote the name of the question
|
||||
const tagName = "survey"
|
||||
|
||||
// add a few interfaces so users can configure how the prompt values are set
|
||||
type settable interface {
|
||||
WriteAnswer(field string, value interface{}) error
|
||||
}
|
||||
|
||||
func WriteAnswer(t interface{}, name string, v interface{}) (err error) {
|
||||
// if the field is a custom type
|
||||
if s, ok := t.(settable); ok {
|
||||
// use the interface method
|
||||
return s.WriteAnswer(name, v)
|
||||
}
|
||||
|
||||
// the target to write to
|
||||
target := reflect.ValueOf(t)
|
||||
// the value to write from
|
||||
value := reflect.ValueOf(v)
|
||||
|
||||
// make sure we are writing to a pointer
|
||||
if target.Kind() != reflect.Ptr {
|
||||
return errors.New("you must pass a pointer as the target of a Write operation")
|
||||
}
|
||||
// the object "inside" of the target pointer
|
||||
elem := target.Elem()
|
||||
|
||||
// handle the special types
|
||||
switch elem.Kind() {
|
||||
// if we are writing to a struct
|
||||
case reflect.Struct:
|
||||
// get the name of the field that matches the string we were given
|
||||
fieldIndex, err := findFieldIndex(elem, name)
|
||||
// if something went wrong
|
||||
if err != nil {
|
||||
// bubble up
|
||||
return err
|
||||
}
|
||||
field := elem.Field(fieldIndex)
|
||||
// handle references to the settable interface aswell
|
||||
if s, ok := field.Interface().(settable); ok {
|
||||
// use the interface method
|
||||
return s.WriteAnswer(name, v)
|
||||
}
|
||||
if field.CanAddr() {
|
||||
if s, ok := field.Addr().Interface().(settable); ok {
|
||||
// use the interface method
|
||||
return s.WriteAnswer(name, v)
|
||||
}
|
||||
}
|
||||
|
||||
// copy the value over to the normal struct
|
||||
return copy(field, value)
|
||||
case reflect.Map:
|
||||
mapType := reflect.TypeOf(t).Elem()
|
||||
if mapType.Key().Kind() != reflect.String || mapType.Elem().Kind() != reflect.Interface {
|
||||
return errors.New("answer maps must be of type map[string]interface")
|
||||
}
|
||||
mt := *t.(*map[string]interface{})
|
||||
mt[name] = value.Interface()
|
||||
return nil
|
||||
}
|
||||
// otherwise just copy the value to the target
|
||||
return copy(elem, value)
|
||||
}
|
||||
|
||||
// BUG(AlecAivazis): the current implementation might cause weird conflicts if there are
|
||||
// two fields with same name that only differ by casing.
|
||||
func findFieldIndex(s reflect.Value, name string) (int, error) {
|
||||
// the type of the value
|
||||
sType := s.Type()
|
||||
|
||||
// first look for matching tags so we can overwrite matching field names
|
||||
for i := 0; i < sType.NumField(); i++ {
|
||||
// the field we are current scanning
|
||||
field := sType.Field(i)
|
||||
|
||||
// the value of the survey tag
|
||||
tag := field.Tag.Get(tagName)
|
||||
// if the tag matches the name we are looking for
|
||||
if tag != "" && tag == name {
|
||||
// then we found our index
|
||||
return i, nil
|
||||
}
|
||||
}
|
||||
|
||||
// then look for matching names
|
||||
for i := 0; i < sType.NumField(); i++ {
|
||||
// the field we are current scanning
|
||||
field := sType.Field(i)
|
||||
|
||||
// if the name of the field matches what we're looking for
|
||||
if strings.ToLower(field.Name) == strings.ToLower(name) {
|
||||
return i, nil
|
||||
}
|
||||
}
|
||||
|
||||
// we didn't find the field
|
||||
return -1, fmt.Errorf("could not find field matching %v", name)
|
||||
}
|
||||
|
||||
// isList returns true if the element is something we can Len()
|
||||
func isList(v reflect.Value) bool {
|
||||
switch v.Type().Kind() {
|
||||
case reflect.Array, reflect.Slice:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Write takes a value and copies it to the target
|
||||
func copy(t reflect.Value, v reflect.Value) (err error) {
|
||||
// if something ends up panicing we need to catch it in a deferred func
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
// if we paniced with an error
|
||||
if _, ok := r.(error); ok {
|
||||
// cast the result to an error object
|
||||
err = r.(error)
|
||||
} else if _, ok := r.(string); ok {
|
||||
// otherwise we could have paniced with a string so wrap it in an error
|
||||
err = errors.New(r.(string))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// if we are copying from a string result to something else
|
||||
if v.Kind() == reflect.String && v.Type() != t.Type() {
|
||||
var castVal interface{}
|
||||
var casterr error
|
||||
vString := v.Interface().(string)
|
||||
|
||||
switch t.Kind() {
|
||||
case reflect.Bool:
|
||||
castVal, casterr = strconv.ParseBool(vString)
|
||||
case reflect.Int:
|
||||
castVal, casterr = strconv.Atoi(vString)
|
||||
case reflect.Int8:
|
||||
var val64 int64
|
||||
val64, casterr = strconv.ParseInt(vString, 10, 8)
|
||||
if casterr == nil {
|
||||
castVal = int8(val64)
|
||||
}
|
||||
case reflect.Int16:
|
||||
var val64 int64
|
||||
val64, casterr = strconv.ParseInt(vString, 10, 16)
|
||||
if casterr == nil {
|
||||
castVal = int16(val64)
|
||||
}
|
||||
case reflect.Int32:
|
||||
var val64 int64
|
||||
val64, casterr = strconv.ParseInt(vString, 10, 32)
|
||||
if casterr == nil {
|
||||
castVal = int32(val64)
|
||||
}
|
||||
case reflect.Int64:
|
||||
castVal, casterr = strconv.ParseInt(vString, 10, 64)
|
||||
case reflect.Uint:
|
||||
var val64 uint64
|
||||
val64, casterr = strconv.ParseUint(vString, 10, 8)
|
||||
if casterr == nil {
|
||||
castVal = uint(val64)
|
||||
}
|
||||
case reflect.Uint8:
|
||||
var val64 uint64
|
||||
val64, casterr = strconv.ParseUint(vString, 10, 8)
|
||||
if casterr == nil {
|
||||
castVal = uint8(val64)
|
||||
}
|
||||
case reflect.Uint16:
|
||||
var val64 uint64
|
||||
val64, casterr = strconv.ParseUint(vString, 10, 16)
|
||||
if casterr == nil {
|
||||
castVal = uint16(val64)
|
||||
}
|
||||
case reflect.Uint32:
|
||||
var val64 uint64
|
||||
val64, casterr = strconv.ParseUint(vString, 10, 32)
|
||||
if casterr == nil {
|
||||
castVal = uint32(val64)
|
||||
}
|
||||
case reflect.Uint64:
|
||||
castVal, casterr = strconv.ParseUint(vString, 10, 64)
|
||||
case reflect.Float32:
|
||||
var val64 float64
|
||||
val64, casterr = strconv.ParseFloat(vString, 32)
|
||||
if casterr == nil {
|
||||
castVal = float32(val64)
|
||||
}
|
||||
case reflect.Float64:
|
||||
castVal, casterr = strconv.ParseFloat(vString, 64)
|
||||
default:
|
||||
return fmt.Errorf("Unable to convert from string to type %s", t.Kind())
|
||||
}
|
||||
|
||||
if casterr != nil {
|
||||
return casterr
|
||||
}
|
||||
|
||||
t.Set(reflect.ValueOf(castVal))
|
||||
return
|
||||
}
|
||||
|
||||
// if we are copying from one slice or array to another
|
||||
if isList(v) && isList(t) {
|
||||
// loop over every item in the desired value
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
// write to the target given its kind
|
||||
switch t.Kind() {
|
||||
// if its a slice
|
||||
case reflect.Slice:
|
||||
// an object of the correct type
|
||||
obj := reflect.Indirect(reflect.New(t.Type().Elem()))
|
||||
|
||||
// write the appropriate value to the obj and catch any errors
|
||||
if err := copy(obj, v.Index(i)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// just append the value to the end
|
||||
t.Set(reflect.Append(t, obj))
|
||||
// otherwise it could be an array
|
||||
case reflect.Array:
|
||||
// set the index to the appropriate value
|
||||
copy(t.Slice(i, i+1).Index(0), v.Index(i))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// set the value to the target
|
||||
t.Set(v)
|
||||
}
|
||||
|
||||
// we're done
|
||||
return
|
||||
}
|
||||
178
vendor/gopkg.in/AlecAivazis/survey.v1/editor.go
generated
vendored
Normal file
178
vendor/gopkg.in/AlecAivazis/survey.v1/editor.go
generated
vendored
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
package survey
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
|
||||
"gopkg.in/AlecAivazis/survey.v1/core"
|
||||
"gopkg.in/AlecAivazis/survey.v1/terminal"
|
||||
)
|
||||
|
||||
/*
|
||||
Editor launches an instance of the users preferred editor on a temporary file.
|
||||
The editor to use is determined by reading the $VISUAL or $EDITOR environment
|
||||
variables. If neither of those are present, notepad (on Windows) or vim
|
||||
(others) is used.
|
||||
The launch of the editor is triggered by the enter key. Since the response may
|
||||
be long, it will not be echoed as Input does, instead, it print <Received>.
|
||||
Response type is a string.
|
||||
|
||||
message := ""
|
||||
prompt := &survey.Editor{ Message: "What is your commit message?" }
|
||||
survey.AskOne(prompt, &message, nil)
|
||||
*/
|
||||
type Editor struct {
|
||||
core.Renderer
|
||||
Message string
|
||||
Default string
|
||||
Help string
|
||||
HideDefault bool
|
||||
AppendDefault bool
|
||||
}
|
||||
|
||||
// data available to the templates when processing
|
||||
type EditorTemplateData struct {
|
||||
Editor
|
||||
Answer string
|
||||
ShowAnswer bool
|
||||
ShowHelp bool
|
||||
}
|
||||
|
||||
// Templates with Color formatting. See Documentation: https://github.com/mgutz/ansi#style-format
|
||||
var EditorQuestionTemplate = `
|
||||
{{- if .ShowHelp }}{{- color "cyan"}}{{ HelpIcon }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}}
|
||||
{{- color "green+hb"}}{{ QuestionIcon }} {{color "reset"}}
|
||||
{{- color "default+hb"}}{{ .Message }} {{color "reset"}}
|
||||
{{- if .ShowAnswer}}
|
||||
{{- color "cyan"}}{{.Answer}}{{color "reset"}}{{"\n"}}
|
||||
{{- else }}
|
||||
{{- if and .Help (not .ShowHelp)}}{{color "cyan"}}[{{ HelpInputRune }} for help]{{color "reset"}} {{end}}
|
||||
{{- if and .Default (not .HideDefault)}}{{color "white"}}({{.Default}}) {{color "reset"}}{{end}}
|
||||
{{- color "cyan"}}[Enter to launch editor] {{color "reset"}}
|
||||
{{- end}}`
|
||||
|
||||
var (
|
||||
bom = []byte{0xef, 0xbb, 0xbf}
|
||||
editor = "vim"
|
||||
)
|
||||
|
||||
func init() {
|
||||
if runtime.GOOS == "windows" {
|
||||
editor = "notepad"
|
||||
}
|
||||
if v := os.Getenv("VISUAL"); v != "" {
|
||||
editor = v
|
||||
} else if e := os.Getenv("EDITOR"); e != "" {
|
||||
editor = e
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Editor) Prompt() (interface{}, error) {
|
||||
// render the template
|
||||
err := e.Render(
|
||||
EditorQuestionTemplate,
|
||||
EditorTemplateData{Editor: *e},
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// start reading runes from the standard in
|
||||
rr := terminal.NewRuneReader(os.Stdin)
|
||||
rr.SetTermMode()
|
||||
defer rr.RestoreTermMode()
|
||||
|
||||
terminal.CursorHide()
|
||||
defer terminal.CursorShow()
|
||||
|
||||
for {
|
||||
r, _, err := rr.ReadRune()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if r == '\r' || r == '\n' {
|
||||
break
|
||||
}
|
||||
if r == terminal.KeyInterrupt {
|
||||
return "", terminal.InterruptErr
|
||||
}
|
||||
if r == terminal.KeyEndTransmission {
|
||||
break
|
||||
}
|
||||
if r == core.HelpInputRune && e.Help != "" {
|
||||
err = e.Render(
|
||||
EditorQuestionTemplate,
|
||||
EditorTemplateData{Editor: *e, ShowHelp: true},
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// prepare the temp file
|
||||
f, err := ioutil.TempFile("", "survey")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer os.Remove(f.Name())
|
||||
|
||||
// write utf8 BOM header
|
||||
// The reason why we do this is because notepad.exe on Windows determines the
|
||||
// encoding of an "empty" text file by the locale, for example, GBK in China,
|
||||
// while golang string only handles utf8 well. However, a text file with utf8
|
||||
// BOM header is not considered "empty" on Windows, and the encoding will then
|
||||
// be determined utf8 by notepad.exe, instead of GBK or other encodings.
|
||||
if _, err := f.Write(bom); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// write default value
|
||||
if e.Default != "" && e.AppendDefault {
|
||||
if _, err := f.WriteString(e.Default); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
// close the fd to prevent the editor unable to save file
|
||||
if err := f.Close(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// open the editor
|
||||
cmd := exec.Command(editor, f.Name())
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
terminal.CursorShow()
|
||||
if err := cmd.Run(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// raw is a BOM-unstripped UTF8 byte slice
|
||||
raw, err := ioutil.ReadFile(f.Name())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// strip BOM header
|
||||
text := string(bytes.TrimPrefix(raw, bom))
|
||||
|
||||
// check length, return default value on empty
|
||||
if len(text) == 0 && !e.AppendDefault {
|
||||
return e.Default, nil
|
||||
}
|
||||
|
||||
return text, nil
|
||||
}
|
||||
|
||||
func (e *Editor) Cleanup(val interface{}) error {
|
||||
return e.Render(
|
||||
EditorQuestionTemplate,
|
||||
EditorTemplateData{Editor: *e, Answer: "<Received>", ShowAnswer: true},
|
||||
)
|
||||
}
|
||||
98
vendor/gopkg.in/AlecAivazis/survey.v1/input.go
generated
vendored
Normal file
98
vendor/gopkg.in/AlecAivazis/survey.v1/input.go
generated
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
package survey
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"gopkg.in/AlecAivazis/survey.v1/core"
|
||||
"gopkg.in/AlecAivazis/survey.v1/terminal"
|
||||
)
|
||||
|
||||
/*
|
||||
Input is a regular text input that prints each character the user types on the screen
|
||||
and accepts the input with the enter key. Response type is a string.
|
||||
|
||||
name := ""
|
||||
prompt := &survey.Input{ Message: "What is your name?" }
|
||||
survey.AskOne(prompt, &name, nil)
|
||||
*/
|
||||
type Input struct {
|
||||
core.Renderer
|
||||
Message string
|
||||
Default string
|
||||
Help string
|
||||
}
|
||||
|
||||
// data available to the templates when processing
|
||||
type InputTemplateData struct {
|
||||
Input
|
||||
Answer string
|
||||
ShowAnswer bool
|
||||
ShowHelp bool
|
||||
}
|
||||
|
||||
// Templates with Color formatting. See Documentation: https://github.com/mgutz/ansi#style-format
|
||||
var InputQuestionTemplate = `
|
||||
{{- if .ShowHelp }}{{- color "cyan"}}{{ HelpIcon }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}}
|
||||
{{- color "green+hb"}}{{ QuestionIcon }} {{color "reset"}}
|
||||
{{- color "default+hb"}}{{ .Message }} {{color "reset"}}
|
||||
{{- if .ShowAnswer}}
|
||||
{{- color "cyan"}}{{.Answer}}{{color "reset"}}{{"\n"}}
|
||||
{{- else }}
|
||||
{{- if and .Help (not .ShowHelp)}}{{color "cyan"}}[{{ HelpInputRune }} for help]{{color "reset"}} {{end}}
|
||||
{{- if .Default}}{{color "white"}}({{.Default}}) {{color "reset"}}{{end}}
|
||||
{{- end}}`
|
||||
|
||||
func (i *Input) Prompt() (interface{}, error) {
|
||||
// render the template
|
||||
err := i.Render(
|
||||
InputQuestionTemplate,
|
||||
InputTemplateData{Input: *i},
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// start reading runes from the standard in
|
||||
rr := terminal.NewRuneReader(os.Stdin)
|
||||
rr.SetTermMode()
|
||||
defer rr.RestoreTermMode()
|
||||
|
||||
line := []rune{}
|
||||
// get the next line
|
||||
for {
|
||||
line, err = rr.ReadLine(0)
|
||||
if err != nil {
|
||||
return string(line), err
|
||||
}
|
||||
// terminal will echo the \n so we need to jump back up one row
|
||||
terminal.CursorPreviousLine(1)
|
||||
|
||||
if string(line) == string(core.HelpInputRune) && i.Help != "" {
|
||||
err = i.Render(
|
||||
InputQuestionTemplate,
|
||||
InputTemplateData{Input: *i, ShowHelp: true},
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// if the line is empty
|
||||
if line == nil || len(line) == 0 {
|
||||
// use the default value
|
||||
return i.Default, err
|
||||
}
|
||||
|
||||
// we're done
|
||||
return string(line), err
|
||||
}
|
||||
|
||||
func (i *Input) Cleanup(val interface{}) error {
|
||||
return i.Render(
|
||||
InputQuestionTemplate,
|
||||
InputTemplateData{Input: *i, Answer: val.(string), ShowAnswer: true},
|
||||
)
|
||||
}
|
||||
203
vendor/gopkg.in/AlecAivazis/survey.v1/multiselect.go
generated
vendored
Normal file
203
vendor/gopkg.in/AlecAivazis/survey.v1/multiselect.go
generated
vendored
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
package survey
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/AlecAivazis/survey.v1/core"
|
||||
"gopkg.in/AlecAivazis/survey.v1/terminal"
|
||||
)
|
||||
|
||||
/*
|
||||
MultiSelect is a prompt that presents a list of various options to the user
|
||||
for them to select using the arrow keys and enter. Response type is a slice of strings.
|
||||
|
||||
days := []string{}
|
||||
prompt := &survey.MultiSelect{
|
||||
Message: "What days do you prefer:",
|
||||
Options: []string{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"},
|
||||
}
|
||||
survey.AskOne(prompt, &days, nil)
|
||||
*/
|
||||
type MultiSelect struct {
|
||||
core.Renderer
|
||||
Message string
|
||||
Options []string
|
||||
Default []string
|
||||
Help string
|
||||
PageSize int
|
||||
selectedIndex int
|
||||
checked map[string]bool
|
||||
showingHelp bool
|
||||
}
|
||||
|
||||
// data available to the templates when processing
|
||||
type MultiSelectTemplateData struct {
|
||||
MultiSelect
|
||||
Answer string
|
||||
ShowAnswer bool
|
||||
Checked map[string]bool
|
||||
SelectedIndex int
|
||||
ShowHelp bool
|
||||
PageEntries []string
|
||||
}
|
||||
|
||||
var MultiSelectQuestionTemplate = `
|
||||
{{- if .ShowHelp }}{{- color "cyan"}}{{ HelpIcon }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}}
|
||||
{{- color "green+hb"}}{{ QuestionIcon }} {{color "reset"}}
|
||||
{{- color "default+hb"}}{{ .Message }}{{color "reset"}}
|
||||
{{- if .ShowAnswer}}{{color "cyan"}} {{.Answer}}{{color "reset"}}{{"\n"}}
|
||||
{{- else }}
|
||||
{{- if and .Help (not .ShowHelp)}} {{color "cyan"}}[{{ HelpInputRune }} for help]{{color "reset"}}{{end}}
|
||||
{{- "\n"}}
|
||||
{{- range $ix, $option := .PageEntries}}
|
||||
{{- if eq $ix $.SelectedIndex}}{{color "cyan"}}{{ SelectFocusIcon }}{{color "reset"}}{{else}} {{end}}
|
||||
{{- if index $.Checked $option}}{{color "green"}} {{ MarkedOptionIcon }} {{else}}{{color "default+hb"}} {{ UnmarkedOptionIcon }} {{end}}
|
||||
{{- color "reset"}}
|
||||
{{- " "}}{{$option}}{{"\n"}}
|
||||
{{- end}}
|
||||
{{- end}}`
|
||||
|
||||
// OnChange is called on every keypress.
|
||||
func (m *MultiSelect) OnChange(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool) {
|
||||
if key == terminal.KeyArrowUp {
|
||||
// if we are at the top of the list
|
||||
if m.selectedIndex == 0 {
|
||||
// go to the bottom
|
||||
m.selectedIndex = len(m.Options) - 1
|
||||
} else {
|
||||
// decrement the selected index
|
||||
m.selectedIndex--
|
||||
}
|
||||
} else if key == terminal.KeyArrowDown {
|
||||
// if we are at the bottom of the list
|
||||
if m.selectedIndex == len(m.Options)-1 {
|
||||
// start at the top
|
||||
m.selectedIndex = 0
|
||||
} else {
|
||||
// increment the selected index
|
||||
m.selectedIndex++
|
||||
}
|
||||
// if the user pressed down and there is room to move
|
||||
} else if key == terminal.KeySpace {
|
||||
if old, ok := m.checked[m.Options[m.selectedIndex]]; !ok {
|
||||
// otherwise just invert the current value
|
||||
m.checked[m.Options[m.selectedIndex]] = true
|
||||
} else {
|
||||
// otherwise just invert the current value
|
||||
m.checked[m.Options[m.selectedIndex]] = !old
|
||||
}
|
||||
// only show the help message if we have one to show
|
||||
} else if key == core.HelpInputRune && m.Help != "" {
|
||||
m.showingHelp = true
|
||||
}
|
||||
|
||||
// paginate the options
|
||||
opts, idx := paginate(m.PageSize, m.Options, m.selectedIndex)
|
||||
|
||||
// render the options
|
||||
m.Render(
|
||||
MultiSelectQuestionTemplate,
|
||||
MultiSelectTemplateData{
|
||||
MultiSelect: *m,
|
||||
SelectedIndex: idx,
|
||||
Checked: m.checked,
|
||||
ShowHelp: m.showingHelp,
|
||||
PageEntries: opts,
|
||||
},
|
||||
)
|
||||
|
||||
// if we are not pressing ent
|
||||
return line, 0, true
|
||||
}
|
||||
|
||||
func (m *MultiSelect) Prompt() (interface{}, error) {
|
||||
// compute the default state
|
||||
m.checked = make(map[string]bool)
|
||||
// if there is a default
|
||||
if len(m.Default) > 0 {
|
||||
for _, dflt := range m.Default {
|
||||
for _, opt := range m.Options {
|
||||
// if the option correponds to the default
|
||||
if opt == dflt {
|
||||
// we found our initial value
|
||||
m.checked[opt] = true
|
||||
// stop looking
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if there are no options to render
|
||||
if len(m.Options) == 0 {
|
||||
// we failed
|
||||
return "", errors.New("please provide options to select from")
|
||||
}
|
||||
|
||||
// hide the cursor
|
||||
terminal.CursorHide()
|
||||
// show the cursor when we're done
|
||||
defer terminal.CursorShow()
|
||||
|
||||
// paginate the options
|
||||
opts, idx := paginate(m.PageSize, m.Options, m.selectedIndex)
|
||||
|
||||
// ask the question
|
||||
err := m.Render(
|
||||
MultiSelectQuestionTemplate,
|
||||
MultiSelectTemplateData{
|
||||
MultiSelect: *m,
|
||||
SelectedIndex: idx,
|
||||
Checked: m.checked,
|
||||
PageEntries: opts,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
rr := terminal.NewRuneReader(os.Stdin)
|
||||
rr.SetTermMode()
|
||||
defer rr.RestoreTermMode()
|
||||
|
||||
// start waiting for input
|
||||
for {
|
||||
r, _, _ := rr.ReadRune()
|
||||
if r == '\r' || r == '\n' {
|
||||
break
|
||||
}
|
||||
if r == terminal.KeyInterrupt {
|
||||
return "", terminal.InterruptErr
|
||||
}
|
||||
if r == terminal.KeyEndTransmission {
|
||||
break
|
||||
}
|
||||
m.OnChange(nil, 0, r)
|
||||
}
|
||||
|
||||
answers := []string{}
|
||||
for _, option := range m.Options {
|
||||
if val, ok := m.checked[option]; ok && val {
|
||||
answers = append(answers, option)
|
||||
}
|
||||
}
|
||||
|
||||
return answers, nil
|
||||
}
|
||||
|
||||
// Cleanup removes the options section, and renders the ask like a normal question.
|
||||
func (m *MultiSelect) Cleanup(val interface{}) error {
|
||||
// execute the output summary template with the answer
|
||||
return m.Render(
|
||||
MultiSelectQuestionTemplate,
|
||||
MultiSelectTemplateData{
|
||||
MultiSelect: *m,
|
||||
SelectedIndex: m.selectedIndex,
|
||||
Checked: m.checked,
|
||||
Answer: strings.Join(val.([]string), ", "),
|
||||
ShowAnswer: true,
|
||||
},
|
||||
)
|
||||
}
|
||||
84
vendor/gopkg.in/AlecAivazis/survey.v1/password.go
generated
vendored
Normal file
84
vendor/gopkg.in/AlecAivazis/survey.v1/password.go
generated
vendored
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
package survey
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"gopkg.in/AlecAivazis/survey.v1/core"
|
||||
"gopkg.in/AlecAivazis/survey.v1/terminal"
|
||||
)
|
||||
|
||||
/*
|
||||
Password is like a normal Input but the text shows up as *'s and there is no default. Response
|
||||
type is a string.
|
||||
|
||||
password := ""
|
||||
prompt := &survey.Password{ Message: "Please type your password" }
|
||||
survey.AskOne(prompt, &password, nil)
|
||||
*/
|
||||
type Password struct {
|
||||
core.Renderer
|
||||
Message string
|
||||
Help string
|
||||
}
|
||||
|
||||
type PasswordTemplateData struct {
|
||||
Password
|
||||
ShowHelp bool
|
||||
}
|
||||
|
||||
// Templates with Color formatting. See Documentation: https://github.com/mgutz/ansi#style-format
|
||||
var PasswordQuestionTemplate = `
|
||||
{{- if .ShowHelp }}{{- color "cyan"}}{{ HelpIcon }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}}
|
||||
{{- color "green+hb"}}{{ QuestionIcon }} {{color "reset"}}
|
||||
{{- color "default+hb"}}{{ .Message }} {{color "reset"}}
|
||||
{{- if and .Help (not .ShowHelp)}}{{color "cyan"}}[{{ HelpInputRune }} for help]{{color "reset"}} {{end}}`
|
||||
|
||||
func (p *Password) Prompt() (line interface{}, err error) {
|
||||
// render the question template
|
||||
out, err := core.RunTemplate(
|
||||
PasswordQuestionTemplate,
|
||||
PasswordTemplateData{Password: *p},
|
||||
)
|
||||
terminal.Print(out)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
rr := terminal.NewRuneReader(os.Stdin)
|
||||
rr.SetTermMode()
|
||||
defer rr.RestoreTermMode()
|
||||
|
||||
// no help msg? Just return any response
|
||||
if p.Help == "" {
|
||||
line, err := rr.ReadLine('*')
|
||||
return string(line), err
|
||||
}
|
||||
|
||||
// process answers looking for help prompt answer
|
||||
for {
|
||||
line, err := rr.ReadLine('*')
|
||||
if err != nil {
|
||||
return string(line), err
|
||||
}
|
||||
|
||||
if string(line) == string(core.HelpInputRune) {
|
||||
// terminal will echo the \n so we need to jump back up one row
|
||||
terminal.CursorPreviousLine(1)
|
||||
|
||||
err = p.Render(
|
||||
PasswordQuestionTemplate,
|
||||
PasswordTemplateData{Password: *p, ShowHelp: true},
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
continue
|
||||
}
|
||||
return string(line), err
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup hides the string with a fixed number of characters.
|
||||
func (prompt *Password) Cleanup(val interface{}) error {
|
||||
return nil
|
||||
}
|
||||
209
vendor/gopkg.in/AlecAivazis/survey.v1/select.go
generated
vendored
Normal file
209
vendor/gopkg.in/AlecAivazis/survey.v1/select.go
generated
vendored
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
package survey
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
"gopkg.in/AlecAivazis/survey.v1/core"
|
||||
"gopkg.in/AlecAivazis/survey.v1/terminal"
|
||||
)
|
||||
|
||||
/*
|
||||
Select is a prompt that presents a list of various options to the user
|
||||
for them to select using the arrow keys and enter. Response type is a string.
|
||||
|
||||
color := ""
|
||||
prompt := &survey.Select{
|
||||
Message: "Choose a color:",
|
||||
Options: []string{"red", "blue", "green"},
|
||||
}
|
||||
survey.AskOne(prompt, &color, nil)
|
||||
*/
|
||||
type Select struct {
|
||||
core.Renderer
|
||||
Message string
|
||||
Options []string
|
||||
Default string
|
||||
Help string
|
||||
PageSize int
|
||||
selectedIndex int
|
||||
useDefault bool
|
||||
showingHelp bool
|
||||
}
|
||||
|
||||
// the data available to the templates when processing
|
||||
type SelectTemplateData struct {
|
||||
Select
|
||||
PageEntries []string
|
||||
SelectedIndex int
|
||||
Answer string
|
||||
ShowAnswer bool
|
||||
ShowHelp bool
|
||||
}
|
||||
|
||||
var SelectQuestionTemplate = `
|
||||
{{- if .ShowHelp }}{{- color "cyan"}}{{ HelpIcon }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}}
|
||||
{{- color "green+hb"}}{{ QuestionIcon }} {{color "reset"}}
|
||||
{{- color "default+hb"}}{{ .Message }}{{color "reset"}}
|
||||
{{- if .ShowAnswer}}{{color "cyan"}} {{.Answer}}{{color "reset"}}{{"\n"}}
|
||||
{{- else}}
|
||||
{{- if and .Help (not .ShowHelp)}} {{color "cyan"}}[{{ HelpInputRune }} for help]{{color "reset"}}{{end}}
|
||||
{{- "\n"}}
|
||||
{{- range $ix, $choice := .PageEntries}}
|
||||
{{- if eq $ix $.SelectedIndex}}{{color "cyan+b"}}{{ SelectFocusIcon }} {{else}}{{color "default+hb"}} {{end}}
|
||||
{{- $choice}}
|
||||
{{- color "reset"}}{{"\n"}}
|
||||
{{- end}}
|
||||
{{- end}}`
|
||||
|
||||
// OnChange is called on every keypress.
|
||||
func (s *Select) OnChange(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool) {
|
||||
// if the user pressed the enter key
|
||||
if key == terminal.KeyEnter {
|
||||
return []rune(s.Options[s.selectedIndex]), 0, true
|
||||
// if the user pressed the up arrow
|
||||
} else if key == terminal.KeyArrowUp {
|
||||
s.useDefault = false
|
||||
|
||||
// if we are at the top of the list
|
||||
if s.selectedIndex == 0 {
|
||||
// start from the button
|
||||
s.selectedIndex = len(s.Options) - 1
|
||||
} else {
|
||||
// otherwise we are not at the top of the list so decrement the selected index
|
||||
s.selectedIndex--
|
||||
}
|
||||
// if the user pressed down and there is room to move
|
||||
} else if key == terminal.KeyArrowDown {
|
||||
s.useDefault = false
|
||||
// if we are at the bottom of the list
|
||||
if s.selectedIndex == len(s.Options)-1 {
|
||||
// start from the top
|
||||
s.selectedIndex = 0
|
||||
} else {
|
||||
// increment the selected index
|
||||
s.selectedIndex++
|
||||
}
|
||||
// only show the help message if we have one
|
||||
} else if key == core.HelpInputRune && s.Help != "" {
|
||||
s.showingHelp = true
|
||||
}
|
||||
|
||||
// figure out the options and index to render
|
||||
opts, idx := paginate(s.PageSize, s.Options, s.selectedIndex)
|
||||
|
||||
// render the options
|
||||
s.Render(
|
||||
SelectQuestionTemplate,
|
||||
SelectTemplateData{
|
||||
Select: *s,
|
||||
SelectedIndex: idx,
|
||||
ShowHelp: s.showingHelp,
|
||||
PageEntries: opts,
|
||||
},
|
||||
)
|
||||
|
||||
// if we are not pressing ent
|
||||
return []rune(s.Options[s.selectedIndex]), 0, true
|
||||
}
|
||||
|
||||
func (s *Select) Prompt() (interface{}, error) {
|
||||
// if there are no options to render
|
||||
if len(s.Options) == 0 {
|
||||
// we failed
|
||||
return "", errors.New("please provide options to select from")
|
||||
}
|
||||
|
||||
// start off with the first option selected
|
||||
sel := 0
|
||||
// if there is a default
|
||||
if s.Default != "" {
|
||||
// find the choice
|
||||
for i, opt := range s.Options {
|
||||
// if the option correponds to the default
|
||||
if opt == s.Default {
|
||||
// we found our initial value
|
||||
sel = i
|
||||
// stop looking
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// save the selected index
|
||||
s.selectedIndex = sel
|
||||
|
||||
// figure out the options and index to render
|
||||
opts, idx := paginate(s.PageSize, s.Options, sel)
|
||||
|
||||
// ask the question
|
||||
err := s.Render(
|
||||
SelectQuestionTemplate,
|
||||
SelectTemplateData{
|
||||
Select: *s,
|
||||
PageEntries: opts,
|
||||
SelectedIndex: idx,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// hide the cursor
|
||||
terminal.CursorHide()
|
||||
// show the cursor when we're done
|
||||
defer terminal.CursorShow()
|
||||
|
||||
// by default, use the default value
|
||||
s.useDefault = true
|
||||
|
||||
rr := terminal.NewRuneReader(os.Stdin)
|
||||
rr.SetTermMode()
|
||||
defer rr.RestoreTermMode()
|
||||
// start waiting for input
|
||||
for {
|
||||
r, _, err := rr.ReadRune()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if r == '\r' || r == '\n' {
|
||||
break
|
||||
}
|
||||
if r == terminal.KeyInterrupt {
|
||||
return "", terminal.InterruptErr
|
||||
}
|
||||
if r == terminal.KeyEndTransmission {
|
||||
break
|
||||
}
|
||||
s.OnChange(nil, 0, r)
|
||||
}
|
||||
|
||||
var val string
|
||||
// if we are supposed to use the default value
|
||||
if s.useDefault {
|
||||
// if there is a default value
|
||||
if s.Default != "" {
|
||||
// use the default value
|
||||
val = s.Default
|
||||
} else {
|
||||
// there is no default value so use the first
|
||||
val = s.Options[0]
|
||||
}
|
||||
// otherwise the selected index points to the value
|
||||
} else {
|
||||
// the
|
||||
val = s.Options[s.selectedIndex]
|
||||
}
|
||||
|
||||
return val, err
|
||||
}
|
||||
|
||||
func (s *Select) Cleanup(val interface{}) error {
|
||||
return s.Render(
|
||||
SelectQuestionTemplate,
|
||||
SelectTemplateData{
|
||||
Select: *s,
|
||||
Answer: val.(string),
|
||||
ShowAnswer: true,
|
||||
},
|
||||
)
|
||||
}
|
||||
198
vendor/gopkg.in/AlecAivazis/survey.v1/survey.go
generated
vendored
Normal file
198
vendor/gopkg.in/AlecAivazis/survey.v1/survey.go
generated
vendored
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
package survey
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"gopkg.in/AlecAivazis/survey.v1/core"
|
||||
)
|
||||
|
||||
// PageSize is the default maximum number of items to show in select/multiselect prompts
|
||||
var PageSize = 7
|
||||
|
||||
// Validator is a function passed to a Question after a user has provided a response.
|
||||
// If the function returns an error, then the user will be prompted again for another
|
||||
// response.
|
||||
type Validator func(ans interface{}) error
|
||||
|
||||
// Transformer is a function passed to a Question after a user has provided a response.
|
||||
// The function can be used to implement a custom logic that will result to return
|
||||
// a different representation of the given answer.
|
||||
//
|
||||
// Look `TransformString`, `ToLower` `Title` and `ComposeTransformers` for more.
|
||||
type Transformer func(ans interface{}) (newAns interface{})
|
||||
|
||||
// Question is the core data structure for a survey questionnaire.
|
||||
type Question struct {
|
||||
Name string
|
||||
Prompt Prompt
|
||||
Validate Validator
|
||||
Transform Transformer
|
||||
}
|
||||
|
||||
// Prompt is the primary interface for the objects that can take user input
|
||||
// and return a response.
|
||||
type Prompt interface {
|
||||
Prompt() (interface{}, error)
|
||||
Cleanup(interface{}) error
|
||||
Error(error) error
|
||||
}
|
||||
|
||||
/*
|
||||
AskOne performs the prompt for a single prompt and asks for validation if required.
|
||||
Response types should be something that can be casted from the response type designated
|
||||
in the documentation. For example:
|
||||
|
||||
name := ""
|
||||
prompt := &survey.Input{
|
||||
Message: "name",
|
||||
}
|
||||
|
||||
survey.AskOne(prompt, &name, nil)
|
||||
|
||||
*/
|
||||
func AskOne(p Prompt, response interface{}, v Validator) error {
|
||||
err := Ask([]*Question{{Prompt: p, Validate: v}}, response)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
Ask performs the prompt loop, asking for validation when appropriate. The response
|
||||
type can be one of two options. If a struct is passed, the answer will be written to
|
||||
the field whose name matches the Name field on the corresponding question. Field types
|
||||
should be something that can be casted from the response type designated in the
|
||||
documentation. Note, a survey tag can also be used to identify a Otherwise, a
|
||||
map[string]interface{} can be passed, responses will be written to the key with the
|
||||
matching name. For example:
|
||||
|
||||
qs := []*survey.Question{
|
||||
{
|
||||
Name: "name",
|
||||
Prompt: &survey.Input{Message: "What is your name?"},
|
||||
Validate: survey.Required,
|
||||
Transform: survey.Title,
|
||||
},
|
||||
}
|
||||
|
||||
answers := struct{ Name string }{}
|
||||
|
||||
|
||||
err := survey.Ask(qs, &answers)
|
||||
*/
|
||||
func Ask(qs []*Question, response interface{}) error {
|
||||
|
||||
// if we weren't passed a place to record the answers
|
||||
if response == nil {
|
||||
// we can't go any further
|
||||
return errors.New("cannot call Ask() with a nil reference to record the answers")
|
||||
}
|
||||
|
||||
// go over every question
|
||||
for _, q := range qs {
|
||||
// grab the user input and save it
|
||||
ans, err := q.Prompt.Prompt()
|
||||
// if there was a problem
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if there is a validate handler for this question
|
||||
if q.Validate != nil {
|
||||
// wait for a valid response
|
||||
for invalid := q.Validate(ans); invalid != nil; invalid = q.Validate(ans) {
|
||||
err := q.Prompt.Error(invalid)
|
||||
// if there was a problem
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// ask for more input
|
||||
ans, err = q.Prompt.Prompt()
|
||||
// if there was a problem
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if q.Transform != nil {
|
||||
// check if we have a transformer available, if so
|
||||
// then try to acquire the new representation of the
|
||||
// answer, if the resulting answer is not nil.
|
||||
if newAns := q.Transform(ans); newAns != nil {
|
||||
ans = newAns
|
||||
}
|
||||
}
|
||||
|
||||
// tell the prompt to cleanup with the validated value
|
||||
q.Prompt.Cleanup(ans)
|
||||
|
||||
// if something went wrong
|
||||
if err != nil {
|
||||
// stop listening
|
||||
return err
|
||||
}
|
||||
|
||||
// add it to the map
|
||||
err = core.WriteAnswer(response, q.Name, ans)
|
||||
// if something went wrong
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
// return the response
|
||||
return nil
|
||||
}
|
||||
|
||||
// paginate returns a single page of choices given the page size, the total list of
|
||||
// possible choices, and the current selected index in the total list.
|
||||
func paginate(page int, choices []string, sel int) ([]string, int) {
|
||||
// the number of elements to show in a single page
|
||||
var pageSize int
|
||||
// if the select has a specific page size
|
||||
if page != 0 {
|
||||
// use the specified one
|
||||
pageSize = page
|
||||
// otherwise the select does not have a page size
|
||||
} else {
|
||||
// use the package default
|
||||
pageSize = PageSize
|
||||
}
|
||||
|
||||
var start, end, cursor int
|
||||
|
||||
if len(choices) < pageSize {
|
||||
// if we dont have enough options to fill a page
|
||||
start = 0
|
||||
end = len(choices)
|
||||
cursor = sel
|
||||
|
||||
} else if sel < pageSize/2 {
|
||||
// if we are in the first half page
|
||||
start = 0
|
||||
end = pageSize
|
||||
cursor = sel
|
||||
|
||||
} else if len(choices)-sel-1 < pageSize/2 {
|
||||
// if we are in the last half page
|
||||
start = len(choices) - pageSize
|
||||
end = len(choices)
|
||||
cursor = sel - start
|
||||
|
||||
} else {
|
||||
// somewhere in the middle
|
||||
above := pageSize / 2
|
||||
below := pageSize - above
|
||||
|
||||
cursor = pageSize / 2
|
||||
start = sel - above
|
||||
end = sel + below
|
||||
}
|
||||
|
||||
// return the subset we care about and the index
|
||||
return choices[start:end], cursor
|
||||
}
|
||||
134
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/cursor.go
generated
vendored
Normal file
134
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/cursor.go
generated
vendored
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
// +build !windows
|
||||
|
||||
package terminal
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CursorUp moves the cursor n cells to up.
|
||||
func CursorUp(n int) {
|
||||
fmt.Printf("\x1b[%dA", n)
|
||||
}
|
||||
|
||||
// CursorDown moves the cursor n cells to down.
|
||||
func CursorDown(n int) {
|
||||
fmt.Printf("\x1b[%dB", n)
|
||||
}
|
||||
|
||||
// CursorForward moves the cursor n cells to right.
|
||||
func CursorForward(n int) {
|
||||
fmt.Printf("\x1b[%dC", n)
|
||||
}
|
||||
|
||||
// CursorBack moves the cursor n cells to left.
|
||||
func CursorBack(n int) {
|
||||
fmt.Printf("\x1b[%dD", n)
|
||||
}
|
||||
|
||||
// CursorNextLine moves cursor to beginning of the line n lines down.
|
||||
func CursorNextLine(n int) {
|
||||
fmt.Printf("\x1b[%dE", n)
|
||||
}
|
||||
|
||||
// CursorPreviousLine moves cursor to beginning of the line n lines up.
|
||||
func CursorPreviousLine(n int) {
|
||||
fmt.Printf("\x1b[%dF", n)
|
||||
}
|
||||
|
||||
// CursorHorizontalAbsolute moves cursor horizontally to x.
|
||||
func CursorHorizontalAbsolute(x int) {
|
||||
fmt.Printf("\x1b[%dG", x)
|
||||
}
|
||||
|
||||
// CursorShow shows the cursor.
|
||||
func CursorShow() {
|
||||
fmt.Print("\x1b[?25h")
|
||||
}
|
||||
|
||||
// CursorHide hide the cursor.
|
||||
func CursorHide() {
|
||||
fmt.Print("\x1b[?25l")
|
||||
}
|
||||
|
||||
// CursorMove moves the cursor to a specific x,y location.
|
||||
func CursorMove(x int, y int) {
|
||||
fmt.Printf("\x1b[%d;%df", x, y)
|
||||
}
|
||||
|
||||
// CursorLocation returns the current location of the cursor in the terminal
|
||||
func CursorLocation() (*Coord, error) {
|
||||
// print the escape sequence to receive the position in our stdin
|
||||
fmt.Print("\x1b[6n")
|
||||
|
||||
// read from stdin to get the response
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
// spec says we read 'til R, so do that
|
||||
text, err := reader.ReadSlice('R')
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// spec also says they're split by ;, so do that too
|
||||
if strings.Contains(string(text), ";") {
|
||||
// a regex to parse the output of the ansi code
|
||||
re := regexp.MustCompile(`\d+;\d+`)
|
||||
line := re.FindString(string(text))
|
||||
|
||||
// find the column and rows embedded in the string
|
||||
coords := strings.Split(line, ";")
|
||||
|
||||
// try to cast the col number to an int
|
||||
col, err := strconv.Atoi(coords[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// try to cast the row number to an int
|
||||
row, err := strconv.Atoi(coords[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// return the coordinate object with the col and row we calculated
|
||||
return &Coord{Short(col), Short(row)}, nil
|
||||
}
|
||||
|
||||
// it didn't work so return an error
|
||||
return nil, fmt.Errorf("could not compute the cursor position using ascii escape sequences")
|
||||
}
|
||||
|
||||
// Size returns the height and width of the terminal.
|
||||
func Size() (*Coord, error) {
|
||||
// the general approach here is to move the cursor to the very bottom
|
||||
// of the terminal, ask for the current location and then move the
|
||||
// cursor back where we started
|
||||
|
||||
// save the current location of the cursor
|
||||
origin, err := CursorLocation()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// move the cursor to the very bottom of the terminal
|
||||
CursorMove(999, 999)
|
||||
|
||||
// ask for the current location
|
||||
bottom, err := CursorLocation()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// move back where we began
|
||||
CursorUp(int(bottom.Y - origin.Y))
|
||||
CursorHorizontalAbsolute(int(origin.X))
|
||||
|
||||
// sice the bottom was calcuated in the lower right corner, it
|
||||
// is the dimensions we are looking for
|
||||
return bottom, nil
|
||||
}
|
||||
101
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/cursor_windows.go
generated
vendored
Normal file
101
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/cursor_windows.go
generated
vendored
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
package terminal
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func CursorUp(n int) {
|
||||
cursorMove(0, n)
|
||||
}
|
||||
|
||||
func CursorDown(n int) {
|
||||
cursorMove(0, -1*n)
|
||||
}
|
||||
|
||||
func CursorForward(n int) {
|
||||
cursorMove(n, 0)
|
||||
}
|
||||
|
||||
func CursorBack(n int) {
|
||||
cursorMove(-1*n, 0)
|
||||
}
|
||||
|
||||
func cursorMove(x int, y int) {
|
||||
handle := syscall.Handle(os.Stdout.Fd())
|
||||
|
||||
var csbi consoleScreenBufferInfo
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
|
||||
var cursor Coord
|
||||
cursor.X = csbi.cursorPosition.X + Short(x)
|
||||
cursor.Y = csbi.cursorPosition.Y + Short(y)
|
||||
|
||||
procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursor))))
|
||||
}
|
||||
|
||||
func CursorNextLine(n int) {
|
||||
CursorUp(n)
|
||||
CursorHorizontalAbsolute(0)
|
||||
}
|
||||
|
||||
func CursorPreviousLine(n int) {
|
||||
CursorDown(n)
|
||||
CursorHorizontalAbsolute(0)
|
||||
}
|
||||
|
||||
func CursorHorizontalAbsolute(x int) {
|
||||
handle := syscall.Handle(os.Stdout.Fd())
|
||||
|
||||
var csbi consoleScreenBufferInfo
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
|
||||
var cursor Coord
|
||||
cursor.X = Short(x)
|
||||
cursor.Y = csbi.cursorPosition.Y
|
||||
|
||||
if csbi.size.X < cursor.X {
|
||||
cursor.X = csbi.size.X
|
||||
}
|
||||
|
||||
procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursor))))
|
||||
}
|
||||
|
||||
func CursorShow() {
|
||||
handle := syscall.Handle(os.Stdout.Fd())
|
||||
|
||||
var cci consoleCursorInfo
|
||||
procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci)))
|
||||
cci.visible = 1
|
||||
|
||||
procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci)))
|
||||
}
|
||||
|
||||
func CursorHide() {
|
||||
handle := syscall.Handle(os.Stdout.Fd())
|
||||
|
||||
var cci consoleCursorInfo
|
||||
procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci)))
|
||||
cci.visible = 0
|
||||
|
||||
procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci)))
|
||||
}
|
||||
|
||||
func CursorLocation() (Coord, error) {
|
||||
handle := syscall.Handle(os.Stdout.Fd())
|
||||
|
||||
var csbi consoleScreenBufferInfo
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
|
||||
return csbi.cursorPosition, nil
|
||||
}
|
||||
|
||||
func Size() (Coord, error) {
|
||||
handle := syscall.Handle(os.Stdout.Fd())
|
||||
|
||||
var csbi consoleScreenBufferInfo
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
|
||||
return csbi.size, nil
|
||||
}
|
||||
9
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/display.go
generated
vendored
Normal file
9
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/display.go
generated
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
package terminal
|
||||
|
||||
type EraseLineMode int
|
||||
|
||||
const (
|
||||
ERASE_LINE_END EraseLineMode = iota
|
||||
ERASE_LINE_START
|
||||
ERASE_LINE_ALL
|
||||
)
|
||||
11
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/display_posix.go
generated
vendored
Normal file
11
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/display_posix.go
generated
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// +build !windows
|
||||
|
||||
package terminal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func EraseLine(mode EraseLineMode) {
|
||||
fmt.Printf("\x1b[%dK", mode)
|
||||
}
|
||||
28
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/display_windows.go
generated
vendored
Normal file
28
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/display_windows.go
generated
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
package terminal
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func EraseLine(mode EraseLineMode) {
|
||||
handle := syscall.Handle(os.Stdout.Fd())
|
||||
|
||||
var csbi consoleScreenBufferInfo
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
|
||||
var w uint32
|
||||
var x Short
|
||||
cursor := csbi.cursorPosition
|
||||
switch mode {
|
||||
case ERASE_LINE_END:
|
||||
x = csbi.size.X
|
||||
case ERASE_LINE_START:
|
||||
x = 0
|
||||
case ERASE_LINE_ALL:
|
||||
cursor.X = 0
|
||||
x = csbi.size.X
|
||||
}
|
||||
procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(x), uintptr(*(*int32)(unsafe.Pointer(&cursor))), uintptr(unsafe.Pointer(&w)))
|
||||
}
|
||||
9
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/error.go
generated
vendored
Normal file
9
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/error.go
generated
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
package terminal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
InterruptErr = errors.New("interrupt")
|
||||
)
|
||||
20
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/output.go
generated
vendored
Normal file
20
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/output.go
generated
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
// +build !windows
|
||||
|
||||
package terminal
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Returns special stdout, which converts escape sequences to Windows API calls
|
||||
// on Windows environment.
|
||||
func NewAnsiStdout() io.Writer {
|
||||
return os.Stdout
|
||||
}
|
||||
|
||||
// Returns special stderr, which converts escape sequences to Windows API calls
|
||||
// on Windows environment.
|
||||
func NewAnsiStderr() io.Writer {
|
||||
return os.Stderr
|
||||
}
|
||||
228
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/output_windows.go
generated
vendored
Normal file
228
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/output_windows.go
generated
vendored
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
package terminal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/mattn/go-isatty"
|
||||
)
|
||||
|
||||
var (
|
||||
singleArgFunctions = map[rune]func(int){
|
||||
'A': CursorUp,
|
||||
'B': CursorDown,
|
||||
'C': CursorForward,
|
||||
'D': CursorBack,
|
||||
'E': CursorNextLine,
|
||||
'F': CursorPreviousLine,
|
||||
'G': CursorHorizontalAbsolute,
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
foregroundBlue = 0x1
|
||||
foregroundGreen = 0x2
|
||||
foregroundRed = 0x4
|
||||
foregroundIntensity = 0x8
|
||||
foregroundMask = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity)
|
||||
backgroundBlue = 0x10
|
||||
backgroundGreen = 0x20
|
||||
backgroundRed = 0x40
|
||||
backgroundIntensity = 0x80
|
||||
backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity)
|
||||
)
|
||||
|
||||
type Writer struct {
|
||||
out io.Writer
|
||||
handle syscall.Handle
|
||||
orgAttr word
|
||||
}
|
||||
|
||||
func NewAnsiStdout() io.Writer {
|
||||
var csbi consoleScreenBufferInfo
|
||||
out := os.Stdout
|
||||
if !isatty.IsTerminal(out.Fd()) {
|
||||
return out
|
||||
}
|
||||
handle := syscall.Handle(out.Fd())
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
return &Writer{out: out, handle: handle, orgAttr: csbi.attributes}
|
||||
}
|
||||
|
||||
func NewAnsiStderr() io.Writer {
|
||||
var csbi consoleScreenBufferInfo
|
||||
out := os.Stderr
|
||||
if !isatty.IsTerminal(out.Fd()) {
|
||||
return out
|
||||
}
|
||||
handle := syscall.Handle(out.Fd())
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
return &Writer{out: out, handle: handle, orgAttr: csbi.attributes}
|
||||
}
|
||||
|
||||
func (w *Writer) Write(data []byte) (n int, err error) {
|
||||
r := bytes.NewReader(data)
|
||||
|
||||
for {
|
||||
ch, size, err := r.ReadRune()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
n += size
|
||||
|
||||
switch ch {
|
||||
case '\x1b':
|
||||
size, err = w.handleEscape(r)
|
||||
n += size
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
default:
|
||||
fmt.Fprint(w.out, string(ch))
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (w *Writer) handleEscape(r *bytes.Reader) (n int, err error) {
|
||||
buf := make([]byte, 0, 10)
|
||||
buf = append(buf, "\x1b"...)
|
||||
|
||||
// Check '[' continues after \x1b
|
||||
ch, size, err := r.ReadRune()
|
||||
if err != nil {
|
||||
fmt.Fprint(w.out, string(buf))
|
||||
return
|
||||
}
|
||||
n += size
|
||||
if ch != '[' {
|
||||
fmt.Fprint(w.out, string(buf))
|
||||
return
|
||||
}
|
||||
|
||||
// Parse escape code
|
||||
var code rune
|
||||
argBuf := make([]byte, 0, 10)
|
||||
for {
|
||||
ch, size, err = r.ReadRune()
|
||||
if err != nil {
|
||||
fmt.Fprint(w.out, string(buf))
|
||||
return
|
||||
}
|
||||
n += size
|
||||
if ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') {
|
||||
code = ch
|
||||
break
|
||||
}
|
||||
argBuf = append(argBuf, string(ch)...)
|
||||
}
|
||||
|
||||
w.applyEscapeCode(buf, string(argBuf), code)
|
||||
return
|
||||
}
|
||||
|
||||
func (w *Writer) applyEscapeCode(buf []byte, arg string, code rune) {
|
||||
switch arg + string(code) {
|
||||
case "?25h":
|
||||
CursorShow()
|
||||
return
|
||||
case "?25l":
|
||||
CursorHide()
|
||||
return
|
||||
}
|
||||
|
||||
if f, ok := singleArgFunctions[code]; ok {
|
||||
if n, err := strconv.Atoi(arg); err == nil {
|
||||
f(n)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
switch code {
|
||||
case 'm':
|
||||
w.applySelectGraphicRendition(arg)
|
||||
default:
|
||||
buf = append(buf, string(code)...)
|
||||
fmt.Fprint(w.out, string(buf))
|
||||
}
|
||||
}
|
||||
|
||||
// Original implementation: https://github.com/mattn/go-colorable
|
||||
func (w *Writer) applySelectGraphicRendition(arg string) {
|
||||
if arg == "" {
|
||||
procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.orgAttr))
|
||||
return
|
||||
}
|
||||
|
||||
var csbi consoleScreenBufferInfo
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
|
||||
attr := csbi.attributes
|
||||
|
||||
for _, param := range strings.Split(arg, ";") {
|
||||
n, err := strconv.Atoi(param)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
switch {
|
||||
case n == 0 || n == 100:
|
||||
attr = w.orgAttr
|
||||
case 1 <= n && n <= 5:
|
||||
attr |= foregroundIntensity
|
||||
case 30 <= n && n <= 37:
|
||||
attr = (attr & backgroundMask)
|
||||
if (n-30)&1 != 0 {
|
||||
attr |= foregroundRed
|
||||
}
|
||||
if (n-30)&2 != 0 {
|
||||
attr |= foregroundGreen
|
||||
}
|
||||
if (n-30)&4 != 0 {
|
||||
attr |= foregroundBlue
|
||||
}
|
||||
case 40 <= n && n <= 47:
|
||||
attr = (attr & foregroundMask)
|
||||
if (n-40)&1 != 0 {
|
||||
attr |= backgroundRed
|
||||
}
|
||||
if (n-40)&2 != 0 {
|
||||
attr |= backgroundGreen
|
||||
}
|
||||
if (n-40)&4 != 0 {
|
||||
attr |= backgroundBlue
|
||||
}
|
||||
case 90 <= n && n <= 97:
|
||||
attr = (attr & backgroundMask)
|
||||
attr |= foregroundIntensity
|
||||
if (n-90)&1 != 0 {
|
||||
attr |= foregroundRed
|
||||
}
|
||||
if (n-90)&2 != 0 {
|
||||
attr |= foregroundGreen
|
||||
}
|
||||
if (n-90)&4 != 0 {
|
||||
attr |= foregroundBlue
|
||||
}
|
||||
case 100 <= n && n <= 107:
|
||||
attr = (attr & foregroundMask)
|
||||
attr |= backgroundIntensity
|
||||
if (n-100)&1 != 0 {
|
||||
attr |= backgroundRed
|
||||
}
|
||||
if (n-100)&2 != 0 {
|
||||
attr |= backgroundGreen
|
||||
}
|
||||
if (n-100)&4 != 0 {
|
||||
attr |= backgroundBlue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr))
|
||||
}
|
||||
25
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/print.go
generated
vendored
Normal file
25
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/print.go
generated
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
package terminal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
Stdout = NewAnsiStdout()
|
||||
)
|
||||
|
||||
// Print prints given arguments with escape sequence conversion for windows.
|
||||
func Print(a ...interface{}) (n int, err error) {
|
||||
return fmt.Fprint(Stdout, a...)
|
||||
}
|
||||
|
||||
// Printf prints a given format with escape sequence conversion for windows.
|
||||
func Printf(format string, a ...interface{}) (n int, err error) {
|
||||
return fmt.Fprintf(Stdout, format, a...)
|
||||
}
|
||||
|
||||
// Println prints given arguments with newline and escape sequence conversion
|
||||
// for windows.
|
||||
func Println(a ...interface{}) (n int, err error) {
|
||||
return fmt.Fprintln(Stdout, a...)
|
||||
}
|
||||
183
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/runereader.go
generated
vendored
Normal file
183
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/runereader.go
generated
vendored
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
package terminal
|
||||
|
||||
import (
|
||||
"os"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
type RuneReader struct {
|
||||
Input *os.File
|
||||
|
||||
state runeReaderState
|
||||
}
|
||||
|
||||
func NewRuneReader(input *os.File) *RuneReader {
|
||||
return &RuneReader{
|
||||
Input: input,
|
||||
state: newRuneReaderState(input),
|
||||
}
|
||||
}
|
||||
|
||||
func (rr *RuneReader) ReadLine(mask rune) ([]rune, error) {
|
||||
line := []rune{}
|
||||
|
||||
// we only care about horizontal displacements from the origin so start counting at 0
|
||||
index := 0
|
||||
|
||||
for {
|
||||
// wait for some input
|
||||
r, _, err := rr.ReadRune()
|
||||
if err != nil {
|
||||
return line, err
|
||||
}
|
||||
|
||||
// if the user pressed enter or some other newline/termination like ctrl+d
|
||||
if r == '\r' || r == '\n' || r == KeyEndTransmission {
|
||||
// go to the beginning of the next line
|
||||
Print("\r\n")
|
||||
|
||||
// we're done processing the input
|
||||
return line, nil
|
||||
}
|
||||
|
||||
// if the user interrupts (ie with ctrl+c)
|
||||
if r == KeyInterrupt {
|
||||
// go to the beginning of the next line
|
||||
Print("\r\n")
|
||||
|
||||
// we're done processing the input, and treat interrupt like an error
|
||||
return line, InterruptErr
|
||||
}
|
||||
|
||||
// allow for backspace/delete editing of inputs
|
||||
if r == KeyBackspace || r == KeyDelete {
|
||||
// and we're not at the beginning of the line
|
||||
if index > 0 && len(line) > 0 {
|
||||
// if we are at the end of the word
|
||||
if index == len(line) {
|
||||
// just remove the last letter from the internal representation
|
||||
line = line[:len(line)-1]
|
||||
|
||||
// go back one
|
||||
CursorBack(1)
|
||||
|
||||
// clear the rest of the line
|
||||
EraseLine(ERASE_LINE_END)
|
||||
} else {
|
||||
// we need to remove a character from the middle of the word
|
||||
|
||||
// remove the current index from the list
|
||||
line = append(line[:index-1], line[index:]...)
|
||||
|
||||
// go back one space so we can clear the rest
|
||||
CursorBack(1)
|
||||
|
||||
// clear the rest of the line
|
||||
EraseLine(ERASE_LINE_END)
|
||||
|
||||
// print what comes after
|
||||
Print(string(line[index-1:]))
|
||||
|
||||
// leave the cursor where the user left it
|
||||
CursorBack(len(line) - index + 1)
|
||||
}
|
||||
|
||||
// decrement the index
|
||||
index--
|
||||
} else {
|
||||
// otherwise the user pressed backspace while at the beginning of the line
|
||||
soundBell()
|
||||
}
|
||||
|
||||
// we're done processing this key
|
||||
continue
|
||||
}
|
||||
|
||||
// if the left arrow is pressed
|
||||
if r == KeyArrowLeft {
|
||||
// and we have space to the left
|
||||
if index > 0 {
|
||||
// move the cursor to the left
|
||||
CursorBack(1)
|
||||
// decrement the index
|
||||
index--
|
||||
|
||||
} else {
|
||||
// otherwise we are at the beginning of where we started reading lines
|
||||
// sound the bell
|
||||
soundBell()
|
||||
}
|
||||
|
||||
// we're done processing this key press
|
||||
continue
|
||||
}
|
||||
|
||||
// if the right arrow is pressed
|
||||
if r == KeyArrowRight {
|
||||
// and we have space to the right of the word
|
||||
if index < len(line) {
|
||||
// move the cursor to the right
|
||||
CursorForward(1)
|
||||
// increment the index
|
||||
index++
|
||||
|
||||
} else {
|
||||
// otherwise we are at the end of the word and can't go past
|
||||
// sound the bell
|
||||
soundBell()
|
||||
}
|
||||
|
||||
// we're done processing this key press
|
||||
continue
|
||||
}
|
||||
|
||||
// if the letter is another escape sequence
|
||||
if unicode.IsControl(r) {
|
||||
// ignore it
|
||||
continue
|
||||
}
|
||||
|
||||
// the user pressed a regular key
|
||||
|
||||
// if we are at the end of the line
|
||||
if index == len(line) {
|
||||
// just append the character at the end of the line
|
||||
line = append(line, r)
|
||||
// increment the location counter
|
||||
index++
|
||||
|
||||
// if we don't need to mask the input
|
||||
if mask == 0 {
|
||||
// just print the character the user pressed
|
||||
Printf("%c", r)
|
||||
} else {
|
||||
// otherwise print the mask we were given
|
||||
Printf("%c", mask)
|
||||
}
|
||||
} else {
|
||||
// we are in the middle of the word so we need to insert the character the user pressed
|
||||
line = append(line[:index], append([]rune{r}, line[index:]...)...)
|
||||
|
||||
// visually insert the character by deleting the rest of the line
|
||||
EraseLine(ERASE_LINE_END)
|
||||
|
||||
// print the rest of the word after
|
||||
for _, char := range line[index:] {
|
||||
// if we don't need to mask the input
|
||||
if mask == 0 {
|
||||
// just print the character the user pressed
|
||||
Printf("%c", char)
|
||||
} else {
|
||||
// otherwise print the mask we were given
|
||||
Printf("%c", mask)
|
||||
}
|
||||
}
|
||||
|
||||
// leave the cursor where the user left it
|
||||
CursorBack(len(line) - index - 1)
|
||||
|
||||
// accommodate the new letter in our counter
|
||||
index++
|
||||
}
|
||||
}
|
||||
}
|
||||
13
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/runereader_bsd.go
generated
vendored
Normal file
13
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/runereader_bsd.go
generated
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// copied from: https://github.com/golang/crypto/blob/master/ssh/terminal/util_bsd.go
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build darwin dragonfly freebsd netbsd openbsd
|
||||
|
||||
package terminal
|
||||
|
||||
import "syscall"
|
||||
|
||||
const ioctlReadTermios = syscall.TIOCGETA
|
||||
const ioctlWriteTermios = syscall.TIOCSETA
|
||||
12
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/runereader_linux.go
generated
vendored
Normal file
12
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/runereader_linux.go
generated
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// copied from https://github.com/golang/crypto/blob/master/ssh/terminal/util_linux.go
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package terminal
|
||||
|
||||
// These constants are declared here, rather than importing
|
||||
// them from the syscall package as some syscall packages, even
|
||||
// on linux, for example gccgo, do not declare them.
|
||||
const ioctlReadTermios = 0x5401 // syscall.TCGETS
|
||||
const ioctlWriteTermios = 0x5402 // syscall.TCSETS
|
||||
84
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/runereader_posix.go
generated
vendored
Normal file
84
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/runereader_posix.go
generated
vendored
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
// +build !windows
|
||||
|
||||
// The terminal mode manipulation code is derived heavily from:
|
||||
// https://github.com/golang/crypto/blob/master/ssh/terminal/util.go:
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package terminal
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type runeReaderState struct {
|
||||
term syscall.Termios
|
||||
buf *bufio.Reader
|
||||
}
|
||||
|
||||
func newRuneReaderState(input *os.File) runeReaderState {
|
||||
return runeReaderState{
|
||||
buf: bufio.NewReader(input),
|
||||
}
|
||||
}
|
||||
|
||||
// For reading runes we just want to disable echo.
|
||||
func (rr *RuneReader) SetTermMode() error {
|
||||
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(rr.Input.Fd()), ioctlReadTermios, uintptr(unsafe.Pointer(&rr.state.term)), 0, 0, 0); err != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
newState := rr.state.term
|
||||
newState.Lflag &^= syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG
|
||||
|
||||
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(rr.Input.Fd()), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rr *RuneReader) RestoreTermMode() error {
|
||||
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(rr.Input.Fd()), ioctlWriteTermios, uintptr(unsafe.Pointer(&rr.state.term)), 0, 0, 0); err != 0 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rr *RuneReader) ReadRune() (rune, int, error) {
|
||||
r, size, err := rr.state.buf.ReadRune()
|
||||
if err != nil {
|
||||
return r, size, err
|
||||
}
|
||||
// parse ^[ sequences to look for arrow keys
|
||||
if r == '\033' {
|
||||
r, size, err = rr.state.buf.ReadRune()
|
||||
if err != nil {
|
||||
return r, size, err
|
||||
}
|
||||
if r != '[' {
|
||||
return r, size, fmt.Errorf("Unexpected Escape Sequence: %q", []rune{'\033', r})
|
||||
}
|
||||
r, size, err = rr.state.buf.ReadRune()
|
||||
if err != nil {
|
||||
return r, size, err
|
||||
}
|
||||
switch r {
|
||||
case 'D':
|
||||
return KeyArrowLeft, 1, nil
|
||||
case 'C':
|
||||
return KeyArrowRight, 1, nil
|
||||
case 'A':
|
||||
return KeyArrowUp, 1, nil
|
||||
case 'B':
|
||||
return KeyArrowDown, 1, nil
|
||||
}
|
||||
return r, size, fmt.Errorf("Unknown Escape Sequence: %q", []rune{'\033', '[', r})
|
||||
}
|
||||
return r, size, err
|
||||
}
|
||||
130
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/runereader_windows.go
generated
vendored
Normal file
130
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/runereader_windows.go
generated
vendored
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
package terminal
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
dll = syscall.NewLazyDLL("kernel32.dll")
|
||||
setConsoleMode = dll.NewProc("SetConsoleMode")
|
||||
getConsoleMode = dll.NewProc("GetConsoleMode")
|
||||
readConsoleInput = dll.NewProc("ReadConsoleInputW")
|
||||
)
|
||||
|
||||
const (
|
||||
EVENT_KEY = 0x0001
|
||||
|
||||
// key codes for arrow keys
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
|
||||
VK_LEFT = 0x25
|
||||
VK_UP = 0x26
|
||||
VK_RIGHT = 0x27
|
||||
VK_DOWN = 0x28
|
||||
|
||||
RIGHT_CTRL_PRESSED = 0x0004
|
||||
LEFT_CTRL_PRESSED = 0x0008
|
||||
|
||||
ENABLE_ECHO_INPUT uint32 = 0x0004
|
||||
ENABLE_LINE_INPUT uint32 = 0x0002
|
||||
ENABLE_PROCESSED_INPUT uint32 = 0x0001
|
||||
)
|
||||
|
||||
type inputRecord struct {
|
||||
eventType uint16
|
||||
padding uint16
|
||||
event [16]byte
|
||||
}
|
||||
|
||||
type keyEventRecord struct {
|
||||
bKeyDown int32
|
||||
wRepeatCount uint16
|
||||
wVirtualKeyCode uint16
|
||||
wVirtualScanCode uint16
|
||||
unicodeChar uint16
|
||||
wdControlKeyState uint32
|
||||
}
|
||||
|
||||
type runeReaderState struct {
|
||||
term uint32
|
||||
}
|
||||
|
||||
func newRuneReaderState(input *os.File) runeReaderState {
|
||||
return runeReaderState{}
|
||||
}
|
||||
|
||||
func (rr *RuneReader) SetTermMode() error {
|
||||
r, _, err := getConsoleMode.Call(uintptr(rr.Input.Fd()), uintptr(unsafe.Pointer(&rr.state.term)))
|
||||
// windows return 0 on error
|
||||
if r == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
newState := rr.state.term
|
||||
newState &^= ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT
|
||||
r, _, err = setConsoleMode.Call(uintptr(rr.Input.Fd()), uintptr(newState))
|
||||
// windows return 0 on error
|
||||
if r == 0 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rr *RuneReader) RestoreTermMode() error {
|
||||
r, _, err := setConsoleMode.Call(uintptr(rr.Input.Fd()), uintptr(rr.state.term))
|
||||
// windows return 0 on error
|
||||
if r == 0 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rr *RuneReader) ReadRune() (rune, int, error) {
|
||||
ir := &inputRecord{}
|
||||
bytesRead := 0
|
||||
for {
|
||||
rv, _, e := readConsoleInput.Call(rr.Input.Fd(), uintptr(unsafe.Pointer(ir)), 1, uintptr(unsafe.Pointer(&bytesRead)))
|
||||
// windows returns non-zero to indicate success
|
||||
if rv == 0 && e != nil {
|
||||
return 0, 0, e
|
||||
}
|
||||
|
||||
if ir.eventType != EVENT_KEY {
|
||||
continue
|
||||
}
|
||||
|
||||
// the event data is really a c struct union, so here we have to do an usafe
|
||||
// cast to put the data into the keyEventRecord (since we have already verified
|
||||
// above that this event does correspond to a key event
|
||||
key := (*keyEventRecord)(unsafe.Pointer(&ir.event[0]))
|
||||
// we only care about key down events
|
||||
if key.bKeyDown == 0 {
|
||||
continue
|
||||
}
|
||||
if key.wdControlKeyState&(LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED) != 0 && key.unicodeChar == 'C' {
|
||||
return KeyInterrupt, bytesRead, nil
|
||||
}
|
||||
|
||||
// not a normal character so look up the input sequence from the
|
||||
// virtual key code mappings (VK_*)
|
||||
if key.unicodeChar == 0 {
|
||||
switch key.wVirtualKeyCode {
|
||||
case VK_DOWN:
|
||||
return KeyArrowDown, bytesRead, nil
|
||||
case VK_LEFT:
|
||||
return KeyArrowLeft, bytesRead, nil
|
||||
case VK_RIGHT:
|
||||
return KeyArrowRight, bytesRead, nil
|
||||
case VK_UP:
|
||||
return KeyArrowUp, bytesRead, nil
|
||||
default:
|
||||
// not a virtual key that we care about so just continue on to
|
||||
// the next input key
|
||||
continue
|
||||
}
|
||||
}
|
||||
r := rune(key.unicodeChar)
|
||||
return r, bytesRead, nil
|
||||
}
|
||||
}
|
||||
18
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/sequences.go
generated
vendored
Normal file
18
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/sequences.go
generated
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
package terminal
|
||||
|
||||
const (
|
||||
KeyArrowLeft = '\x02'
|
||||
KeyArrowRight = '\x06'
|
||||
KeyArrowUp = '\x10'
|
||||
KeyArrowDown = '\x0e'
|
||||
KeySpace = ' '
|
||||
KeyEnter = '\r'
|
||||
KeyBackspace = '\b'
|
||||
KeyDelete = '\x7f'
|
||||
KeyInterrupt = '\x03'
|
||||
KeyEndTransmission = '\x04'
|
||||
)
|
||||
|
||||
func soundBell() {
|
||||
Print("\a")
|
||||
}
|
||||
39
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/syscall_windows.go
generated
vendored
Normal file
39
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/syscall_windows.go
generated
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
package terminal
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var (
|
||||
kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
|
||||
procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute")
|
||||
procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition")
|
||||
procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
|
||||
procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo")
|
||||
procSetConsoleCursorInfo = kernel32.NewProc("SetConsoleCursorInfo")
|
||||
)
|
||||
|
||||
type wchar uint16
|
||||
type dword uint32
|
||||
type word uint16
|
||||
|
||||
type smallRect struct {
|
||||
left Short
|
||||
top Short
|
||||
right Short
|
||||
bottom Short
|
||||
}
|
||||
|
||||
type consoleScreenBufferInfo struct {
|
||||
size Coord
|
||||
cursorPosition Coord
|
||||
attributes word
|
||||
window smallRect
|
||||
maximumWindowSize Coord
|
||||
}
|
||||
|
||||
type consoleCursorInfo struct {
|
||||
size dword
|
||||
visible int32
|
||||
}
|
||||
8
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/terminal.go
generated
vendored
Normal file
8
vendor/gopkg.in/AlecAivazis/survey.v1/terminal/terminal.go
generated
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
package terminal
|
||||
|
||||
type Short int16
|
||||
|
||||
type Coord struct {
|
||||
X Short
|
||||
Y Short
|
||||
}
|
||||
76
vendor/gopkg.in/AlecAivazis/survey.v1/transform.go
generated
vendored
Normal file
76
vendor/gopkg.in/AlecAivazis/survey.v1/transform.go
generated
vendored
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
package survey
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// TransformString returns a `Transformer` based on the "f"
|
||||
// function which accepts a string representation of the answer
|
||||
// and returns a new one, transformed, answer.
|
||||
// Take for example the functions inside the std `strings` package,
|
||||
// they can be converted to a compatible `Transformer` by using this function,
|
||||
// i.e: `TransformString(strings.Title)`, `TransformString(strings.ToUpper)`.
|
||||
//
|
||||
// Note that `TransformString` is just a helper, `Transformer` can be used
|
||||
// to transform any type of answer.
|
||||
func TransformString(f func(s string) string) Transformer {
|
||||
return func(ans interface{}) interface{} {
|
||||
// if the answer value passed in is the zero value of the appropriate type
|
||||
if isZero(reflect.ValueOf(ans)) {
|
||||
// skip this `Transformer` by returning a nil value.
|
||||
// The original answer will be not affected,
|
||||
// see survey.go#L125.
|
||||
return nil
|
||||
}
|
||||
|
||||
// "ans" is never nil here, so we don't have to check that
|
||||
// see survey.go#L97 for more.
|
||||
// Make sure that the the answer's value was a typeof string.
|
||||
s, ok := ans.(string)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return f(s)
|
||||
}
|
||||
}
|
||||
|
||||
// ToLower is a `Transformer`.
|
||||
// It receives an answer value
|
||||
// and returns a copy of the "ans"
|
||||
// with all Unicode letters mapped to their lower case.
|
||||
//
|
||||
// Note that if "ans" is not a string then it will
|
||||
// return a nil value, meaning that the above answer
|
||||
// will not be affected by this call at all.
|
||||
func ToLower(ans interface{}) interface{} {
|
||||
transformer := TransformString(strings.ToLower)
|
||||
return transformer(ans)
|
||||
}
|
||||
|
||||
// Title is a `Transformer`.
|
||||
// It receives an answer value
|
||||
// and returns a copy of the "ans"
|
||||
// with all Unicode letters that begin words
|
||||
// mapped to their title case.
|
||||
//
|
||||
// Note that if "ans" is not a string then it will
|
||||
// return a nil value, meaning that the above answer
|
||||
// will not be affected by this call at all.
|
||||
func Title(ans interface{}) interface{} {
|
||||
transformer := TransformString(strings.Title)
|
||||
return transformer(ans)
|
||||
}
|
||||
|
||||
// ComposeTransformers is a variadic function used to create one transformer from many.
|
||||
func ComposeTransformers(transformers ...Transformer) Transformer {
|
||||
// return a transformer that calls each one sequentially
|
||||
return func(ans interface{}) interface{} {
|
||||
// execute each transformer
|
||||
for _, t := range transformers {
|
||||
ans = t(ans)
|
||||
}
|
||||
return ans
|
||||
}
|
||||
}
|
||||
84
vendor/gopkg.in/AlecAivazis/survey.v1/validate.go
generated
vendored
Normal file
84
vendor/gopkg.in/AlecAivazis/survey.v1/validate.go
generated
vendored
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
package survey
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Required does not allow an empty value
|
||||
func Required(val interface{}) error {
|
||||
// if the value passed in is the zero value of the appropriate type
|
||||
if isZero(reflect.ValueOf(val)) {
|
||||
return errors.New("Value is required")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MaxLength requires that the string is no longer than the specified value
|
||||
func MaxLength(length int) Validator {
|
||||
// return a validator that checks the length of the string
|
||||
return func(val interface{}) error {
|
||||
if str, ok := val.(string); ok {
|
||||
// if the string is longer than the given value
|
||||
if len(str) > length {
|
||||
// yell loudly
|
||||
return fmt.Errorf("value is too long. Max length is %v", length)
|
||||
}
|
||||
} else {
|
||||
// otherwise we cannot convert the value into a string and cannot enforce length
|
||||
return fmt.Errorf("cannot enforce length on response of type %v", reflect.TypeOf(val).Name())
|
||||
}
|
||||
|
||||
// the input is fine
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// MinLength requires that the string is longer or equal in length to the specified value
|
||||
func MinLength(length int) Validator {
|
||||
// return a validator that checks the length of the string
|
||||
return func(val interface{}) error {
|
||||
if str, ok := val.(string); ok {
|
||||
// if the string is shorter than the given value
|
||||
if len(str) < length {
|
||||
// yell loudly
|
||||
return fmt.Errorf("value is too short. Min length is %v", length)
|
||||
}
|
||||
} else {
|
||||
// otherwise we cannot convert the value into a string and cannot enforce length
|
||||
return fmt.Errorf("cannot enforce length on response of type %v", reflect.TypeOf(val).Name())
|
||||
}
|
||||
|
||||
// the input is fine
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ComposeValidators is a variadic function used to create one validator from many.
|
||||
func ComposeValidators(validators ...Validator) Validator {
|
||||
// return a validator that calls each one sequentially
|
||||
return func(val interface{}) error {
|
||||
// execute each validator
|
||||
for _, validator := range validators {
|
||||
// if the answer's value is not valid
|
||||
if err := validator(val); err != nil {
|
||||
// return the error
|
||||
return err
|
||||
}
|
||||
}
|
||||
// we passed all validators, the answer is valid
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// isZero returns true if the passed value is the zero object
|
||||
func isZero(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Slice, reflect.Map:
|
||||
return v.Len() == 0
|
||||
}
|
||||
|
||||
// compare the types directly with more general coverage
|
||||
return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())
|
||||
}
|
||||
21
vendor/gopkg.in/kyokomi/emoji.v1/LICENSE
generated
vendored
Normal file
21
vendor/gopkg.in/kyokomi/emoji.v1/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 kyokomi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
137
vendor/gopkg.in/kyokomi/emoji.v1/emoji.go
generated
vendored
Normal file
137
vendor/gopkg.in/kyokomi/emoji.v1/emoji.go
generated
vendored
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
// Package emoji terminal output.
|
||||
package emoji
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
//go:generate generateEmojiCodeMap -pkg emoji
|
||||
|
||||
// Replace Padding character for emoji.
|
||||
const (
|
||||
ReplacePadding = " "
|
||||
)
|
||||
|
||||
// CodeMap gets the underlying map of emoji.
|
||||
func CodeMap() map[string]string {
|
||||
return emojiCodeMap
|
||||
}
|
||||
|
||||
func emojize(x string) string {
|
||||
str, ok := emojiCodeMap[x]
|
||||
if ok {
|
||||
return str + ReplacePadding
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func replaseEmoji(input *bytes.Buffer) string {
|
||||
emoji := bytes.NewBufferString(":")
|
||||
for {
|
||||
i, _, err := input.ReadRune()
|
||||
if err != nil {
|
||||
// not replase
|
||||
return emoji.String()
|
||||
}
|
||||
|
||||
if i == ':' && emoji.Len() == 1 {
|
||||
return emoji.String() + replaseEmoji(input)
|
||||
}
|
||||
|
||||
emoji.WriteRune(i)
|
||||
switch {
|
||||
case unicode.IsSpace(i):
|
||||
return emoji.String()
|
||||
case i == ':':
|
||||
return emojize(emoji.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func compile(x string) string {
|
||||
if x == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
input := bytes.NewBufferString(x)
|
||||
output := bytes.NewBufferString("")
|
||||
|
||||
for {
|
||||
i, _, err := input.ReadRune()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
switch i {
|
||||
default:
|
||||
output.WriteRune(i)
|
||||
case ':':
|
||||
output.WriteString(replaseEmoji(input))
|
||||
}
|
||||
}
|
||||
return output.String()
|
||||
}
|
||||
|
||||
func compileValues(a *[]interface{}) {
|
||||
for i, x := range *a {
|
||||
if str, ok := x.(string); ok {
|
||||
(*a)[i] = compile(str)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Print is fmt.Print which supports emoji
|
||||
func Print(a ...interface{}) (int, error) {
|
||||
compileValues(&a)
|
||||
return fmt.Print(a...)
|
||||
}
|
||||
|
||||
// Println is fmt.Println which supports emoji
|
||||
func Println(a ...interface{}) (int, error) {
|
||||
compileValues(&a)
|
||||
return fmt.Println(a...)
|
||||
}
|
||||
|
||||
// Printf is fmt.Printf which supports emoji
|
||||
func Printf(format string, a ...interface{}) (int, error) {
|
||||
format = compile(format)
|
||||
return fmt.Printf(format, a...)
|
||||
}
|
||||
|
||||
// Fprint is fmt.Fprint which supports emoji
|
||||
func Fprint(w io.Writer, a ...interface{}) (int, error) {
|
||||
compileValues(&a)
|
||||
return fmt.Fprint(w, a...)
|
||||
}
|
||||
|
||||
// Fprintln is fmt.Fprintln which supports emoji
|
||||
func Fprintln(w io.Writer, a ...interface{}) (int, error) {
|
||||
compileValues(&a)
|
||||
return fmt.Fprintln(w, a...)
|
||||
}
|
||||
|
||||
// Fprintf is fmt.Fprintf which supports emoji
|
||||
func Fprintf(w io.Writer, format string, a ...interface{}) (int, error) {
|
||||
format = compile(format)
|
||||
return fmt.Fprintf(w, format, a...)
|
||||
}
|
||||
|
||||
// Sprint is fmt.Sprint which supports emoji
|
||||
func Sprint(a ...interface{}) string {
|
||||
compileValues(&a)
|
||||
return fmt.Sprint(a...)
|
||||
}
|
||||
|
||||
// Sprintf is fmt.Sprintf which supports emoji
|
||||
func Sprintf(format string, a ...interface{}) string {
|
||||
format = compile(format)
|
||||
return fmt.Sprintf(format, a...)
|
||||
}
|
||||
|
||||
// Errorf is fmt.Errorf which supports emoji
|
||||
func Errorf(format string, a ...interface{}) error {
|
||||
return errors.New(Sprintf(format, a...))
|
||||
}
|
||||
1402
vendor/gopkg.in/kyokomi/emoji.v1/emoji_codemap.go
generated
vendored
Normal file
1402
vendor/gopkg.in/kyokomi/emoji.v1/emoji_codemap.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
201
vendor/gopkg.in/yaml.v2/LICENSE
generated
vendored
Normal file
201
vendor/gopkg.in/yaml.v2/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
31
vendor/gopkg.in/yaml.v2/LICENSE.libyaml
generated
vendored
Normal file
31
vendor/gopkg.in/yaml.v2/LICENSE.libyaml
generated
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
The following files were ported to Go from C files of libyaml, and thus
|
||||
are still covered by their original copyright and license:
|
||||
|
||||
apic.go
|
||||
emitterc.go
|
||||
parserc.go
|
||||
readerc.go
|
||||
scannerc.go
|
||||
writerc.go
|
||||
yamlh.go
|
||||
yamlprivateh.go
|
||||
|
||||
Copyright (c) 2006 Kirill Simonov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
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
|
||||
//}
|
||||
//
|
||||
//
|
||||
685
vendor/gopkg.in/yaml.v2/decode.go
generated
vendored
Normal file
685
vendor/gopkg.in/yaml.v2/decode.go
generated
vendored
Normal file
|
|
@ -0,0 +1,685 @@
|
|||
package yaml
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
documentNode = 1 << iota
|
||||
mappingNode
|
||||
sequenceNode
|
||||
scalarNode
|
||||
aliasNode
|
||||
)
|
||||
|
||||
type node struct {
|
||||
kind int
|
||||
line, column int
|
||||
tag string
|
||||
value string
|
||||
implicit bool
|
||||
children []*node
|
||||
anchors map[string]*node
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Parser, produces a node tree out of a libyaml event stream.
|
||||
|
||||
type parser struct {
|
||||
parser yaml_parser_t
|
||||
event yaml_event_t
|
||||
doc *node
|
||||
}
|
||||
|
||||
func newParser(b []byte) *parser {
|
||||
p := parser{}
|
||||
if !yaml_parser_initialize(&p.parser) {
|
||||
panic("failed to initialize YAML emitter")
|
||||
}
|
||||
|
||||
if len(b) == 0 {
|
||||
b = []byte{'\n'}
|
||||
}
|
||||
|
||||
yaml_parser_set_input_string(&p.parser, b)
|
||||
|
||||
p.skip()
|
||||
if p.event.typ != yaml_STREAM_START_EVENT {
|
||||
panic("expected stream start event, got " + strconv.Itoa(int(p.event.typ)))
|
||||
}
|
||||
p.skip()
|
||||
return &p
|
||||
}
|
||||
|
||||
func (p *parser) destroy() {
|
||||
if p.event.typ != yaml_NO_EVENT {
|
||||
yaml_event_delete(&p.event)
|
||||
}
|
||||
yaml_parser_delete(&p.parser)
|
||||
}
|
||||
|
||||
func (p *parser) skip() {
|
||||
if p.event.typ != yaml_NO_EVENT {
|
||||
if p.event.typ == yaml_STREAM_END_EVENT {
|
||||
failf("attempted to go past the end of stream; corrupted value?")
|
||||
}
|
||||
yaml_event_delete(&p.event)
|
||||
}
|
||||
if !yaml_parser_parse(&p.parser, &p.event) {
|
||||
p.fail()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *parser) fail() {
|
||||
var where string
|
||||
var line int
|
||||
if p.parser.problem_mark.line != 0 {
|
||||
line = p.parser.problem_mark.line
|
||||
} else if p.parser.context_mark.line != 0 {
|
||||
line = p.parser.context_mark.line
|
||||
}
|
||||
if line != 0 {
|
||||
where = "line " + strconv.Itoa(line) + ": "
|
||||
}
|
||||
var msg string
|
||||
if len(p.parser.problem) > 0 {
|
||||
msg = p.parser.problem
|
||||
} else {
|
||||
msg = "unknown problem parsing YAML content"
|
||||
}
|
||||
failf("%s%s", where, msg)
|
||||
}
|
||||
|
||||
func (p *parser) anchor(n *node, anchor []byte) {
|
||||
if anchor != nil {
|
||||
p.doc.anchors[string(anchor)] = n
|
||||
}
|
||||
}
|
||||
|
||||
func (p *parser) parse() *node {
|
||||
switch p.event.typ {
|
||||
case yaml_SCALAR_EVENT:
|
||||
return p.scalar()
|
||||
case yaml_ALIAS_EVENT:
|
||||
return p.alias()
|
||||
case yaml_MAPPING_START_EVENT:
|
||||
return p.mapping()
|
||||
case yaml_SEQUENCE_START_EVENT:
|
||||
return p.sequence()
|
||||
case yaml_DOCUMENT_START_EVENT:
|
||||
return p.document()
|
||||
case yaml_STREAM_END_EVENT:
|
||||
// Happens when attempting to decode an empty buffer.
|
||||
return nil
|
||||
default:
|
||||
panic("attempted to parse unknown event: " + strconv.Itoa(int(p.event.typ)))
|
||||
}
|
||||
}
|
||||
|
||||
func (p *parser) node(kind int) *node {
|
||||
return &node{
|
||||
kind: kind,
|
||||
line: p.event.start_mark.line,
|
||||
column: p.event.start_mark.column,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *parser) document() *node {
|
||||
n := p.node(documentNode)
|
||||
n.anchors = make(map[string]*node)
|
||||
p.doc = n
|
||||
p.skip()
|
||||
n.children = append(n.children, p.parse())
|
||||
if p.event.typ != yaml_DOCUMENT_END_EVENT {
|
||||
panic("expected end of document event but got " + strconv.Itoa(int(p.event.typ)))
|
||||
}
|
||||
p.skip()
|
||||
return n
|
||||
}
|
||||
|
||||
func (p *parser) alias() *node {
|
||||
n := p.node(aliasNode)
|
||||
n.value = string(p.event.anchor)
|
||||
p.skip()
|
||||
return n
|
||||
}
|
||||
|
||||
func (p *parser) scalar() *node {
|
||||
n := p.node(scalarNode)
|
||||
n.value = string(p.event.value)
|
||||
n.tag = string(p.event.tag)
|
||||
n.implicit = p.event.implicit
|
||||
p.anchor(n, p.event.anchor)
|
||||
p.skip()
|
||||
return n
|
||||
}
|
||||
|
||||
func (p *parser) sequence() *node {
|
||||
n := p.node(sequenceNode)
|
||||
p.anchor(n, p.event.anchor)
|
||||
p.skip()
|
||||
for p.event.typ != yaml_SEQUENCE_END_EVENT {
|
||||
n.children = append(n.children, p.parse())
|
||||
}
|
||||
p.skip()
|
||||
return n
|
||||
}
|
||||
|
||||
func (p *parser) mapping() *node {
|
||||
n := p.node(mappingNode)
|
||||
p.anchor(n, p.event.anchor)
|
||||
p.skip()
|
||||
for p.event.typ != yaml_MAPPING_END_EVENT {
|
||||
n.children = append(n.children, p.parse(), p.parse())
|
||||
}
|
||||
p.skip()
|
||||
return n
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Decoder, unmarshals a node into a provided value.
|
||||
|
||||
type decoder struct {
|
||||
doc *node
|
||||
aliases map[string]bool
|
||||
mapType reflect.Type
|
||||
terrors []string
|
||||
strict bool
|
||||
}
|
||||
|
||||
var (
|
||||
mapItemType = reflect.TypeOf(MapItem{})
|
||||
durationType = reflect.TypeOf(time.Duration(0))
|
||||
defaultMapType = reflect.TypeOf(map[interface{}]interface{}{})
|
||||
ifaceType = defaultMapType.Elem()
|
||||
)
|
||||
|
||||
func newDecoder(strict bool) *decoder {
|
||||
d := &decoder{mapType: defaultMapType, strict: strict}
|
||||
d.aliases = make(map[string]bool)
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *decoder) terror(n *node, tag string, out reflect.Value) {
|
||||
if n.tag != "" {
|
||||
tag = n.tag
|
||||
}
|
||||
value := n.value
|
||||
if tag != yaml_SEQ_TAG && tag != yaml_MAP_TAG {
|
||||
if len(value) > 10 {
|
||||
value = " `" + value[:7] + "...`"
|
||||
} else {
|
||||
value = " `" + value + "`"
|
||||
}
|
||||
}
|
||||
d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.line+1, shortTag(tag), value, out.Type()))
|
||||
}
|
||||
|
||||
func (d *decoder) callUnmarshaler(n *node, u Unmarshaler) (good bool) {
|
||||
terrlen := len(d.terrors)
|
||||
err := u.UnmarshalYAML(func(v interface{}) (err error) {
|
||||
defer handleErr(&err)
|
||||
d.unmarshal(n, reflect.ValueOf(v))
|
||||
if len(d.terrors) > terrlen {
|
||||
issues := d.terrors[terrlen:]
|
||||
d.terrors = d.terrors[:terrlen]
|
||||
return &TypeError{issues}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if e, ok := err.(*TypeError); ok {
|
||||
d.terrors = append(d.terrors, e.Errors...)
|
||||
return false
|
||||
}
|
||||
if err != nil {
|
||||
fail(err)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// d.prepare initializes and dereferences pointers and calls UnmarshalYAML
|
||||
// if a value is found to implement it.
|
||||
// It returns the initialized and dereferenced out value, whether
|
||||
// unmarshalling was already done by UnmarshalYAML, and if so whether
|
||||
// its types unmarshalled appropriately.
|
||||
//
|
||||
// If n holds a null value, prepare returns before doing anything.
|
||||
func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) {
|
||||
if n.tag == yaml_NULL_TAG || n.kind == scalarNode && n.tag == "" && (n.value == "null" || n.value == "~" || n.value == "" && n.implicit) {
|
||||
return out, false, false
|
||||
}
|
||||
again := true
|
||||
for again {
|
||||
again = false
|
||||
if out.Kind() == reflect.Ptr {
|
||||
if out.IsNil() {
|
||||
out.Set(reflect.New(out.Type().Elem()))
|
||||
}
|
||||
out = out.Elem()
|
||||
again = true
|
||||
}
|
||||
if out.CanAddr() {
|
||||
if u, ok := out.Addr().Interface().(Unmarshaler); ok {
|
||||
good = d.callUnmarshaler(n, u)
|
||||
return out, true, good
|
||||
}
|
||||
}
|
||||
}
|
||||
return out, false, false
|
||||
}
|
||||
|
||||
func (d *decoder) unmarshal(n *node, out reflect.Value) (good bool) {
|
||||
switch n.kind {
|
||||
case documentNode:
|
||||
return d.document(n, out)
|
||||
case aliasNode:
|
||||
return d.alias(n, out)
|
||||
}
|
||||
out, unmarshaled, good := d.prepare(n, out)
|
||||
if unmarshaled {
|
||||
return good
|
||||
}
|
||||
switch n.kind {
|
||||
case scalarNode:
|
||||
good = d.scalar(n, out)
|
||||
case mappingNode:
|
||||
good = d.mapping(n, out)
|
||||
case sequenceNode:
|
||||
good = d.sequence(n, out)
|
||||
default:
|
||||
panic("internal error: unknown node kind: " + strconv.Itoa(n.kind))
|
||||
}
|
||||
return good
|
||||
}
|
||||
|
||||
func (d *decoder) document(n *node, out reflect.Value) (good bool) {
|
||||
if len(n.children) == 1 {
|
||||
d.doc = n
|
||||
d.unmarshal(n.children[0], out)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (d *decoder) alias(n *node, out reflect.Value) (good bool) {
|
||||
an, ok := d.doc.anchors[n.value]
|
||||
if !ok {
|
||||
failf("unknown anchor '%s' referenced", n.value)
|
||||
}
|
||||
if d.aliases[n.value] {
|
||||
failf("anchor '%s' value contains itself", n.value)
|
||||
}
|
||||
d.aliases[n.value] = true
|
||||
good = d.unmarshal(an, out)
|
||||
delete(d.aliases, n.value)
|
||||
return good
|
||||
}
|
||||
|
||||
var zeroValue reflect.Value
|
||||
|
||||
func resetMap(out reflect.Value) {
|
||||
for _, k := range out.MapKeys() {
|
||||
out.SetMapIndex(k, zeroValue)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *decoder) scalar(n *node, out reflect.Value) (good bool) {
|
||||
var tag string
|
||||
var resolved interface{}
|
||||
if n.tag == "" && !n.implicit {
|
||||
tag = yaml_STR_TAG
|
||||
resolved = n.value
|
||||
} else {
|
||||
tag, resolved = resolve(n.tag, n.value)
|
||||
if tag == yaml_BINARY_TAG {
|
||||
data, err := base64.StdEncoding.DecodeString(resolved.(string))
|
||||
if err != nil {
|
||||
failf("!!binary value contains invalid base64 data")
|
||||
}
|
||||
resolved = string(data)
|
||||
}
|
||||
}
|
||||
if resolved == nil {
|
||||
if out.Kind() == reflect.Map && !out.CanAddr() {
|
||||
resetMap(out)
|
||||
} else {
|
||||
out.Set(reflect.Zero(out.Type()))
|
||||
}
|
||||
return true
|
||||
}
|
||||
if s, ok := resolved.(string); ok && out.CanAddr() {
|
||||
if u, ok := out.Addr().Interface().(encoding.TextUnmarshaler); ok {
|
||||
err := u.UnmarshalText([]byte(s))
|
||||
if err != nil {
|
||||
fail(err)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
switch out.Kind() {
|
||||
case reflect.String:
|
||||
if tag == yaml_BINARY_TAG {
|
||||
out.SetString(resolved.(string))
|
||||
good = true
|
||||
} else if resolved != nil {
|
||||
out.SetString(n.value)
|
||||
good = true
|
||||
}
|
||||
case reflect.Interface:
|
||||
if resolved == nil {
|
||||
out.Set(reflect.Zero(out.Type()))
|
||||
} else {
|
||||
out.Set(reflect.ValueOf(resolved))
|
||||
}
|
||||
good = true
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
switch resolved := resolved.(type) {
|
||||
case int:
|
||||
if !out.OverflowInt(int64(resolved)) {
|
||||
out.SetInt(int64(resolved))
|
||||
good = true
|
||||
}
|
||||
case int64:
|
||||
if !out.OverflowInt(resolved) {
|
||||
out.SetInt(resolved)
|
||||
good = true
|
||||
}
|
||||
case uint64:
|
||||
if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
|
||||
out.SetInt(int64(resolved))
|
||||
good = true
|
||||
}
|
||||
case float64:
|
||||
if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
|
||||
out.SetInt(int64(resolved))
|
||||
good = true
|
||||
}
|
||||
case string:
|
||||
if out.Type() == durationType {
|
||||
d, err := time.ParseDuration(resolved)
|
||||
if err == nil {
|
||||
out.SetInt(int64(d))
|
||||
good = true
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
switch resolved := resolved.(type) {
|
||||
case int:
|
||||
if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
|
||||
out.SetUint(uint64(resolved))
|
||||
good = true
|
||||
}
|
||||
case int64:
|
||||
if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
|
||||
out.SetUint(uint64(resolved))
|
||||
good = true
|
||||
}
|
||||
case uint64:
|
||||
if !out.OverflowUint(uint64(resolved)) {
|
||||
out.SetUint(uint64(resolved))
|
||||
good = true
|
||||
}
|
||||
case float64:
|
||||
if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) {
|
||||
out.SetUint(uint64(resolved))
|
||||
good = true
|
||||
}
|
||||
}
|
||||
case reflect.Bool:
|
||||
switch resolved := resolved.(type) {
|
||||
case bool:
|
||||
out.SetBool(resolved)
|
||||
good = true
|
||||
}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
switch resolved := resolved.(type) {
|
||||
case int:
|
||||
out.SetFloat(float64(resolved))
|
||||
good = true
|
||||
case int64:
|
||||
out.SetFloat(float64(resolved))
|
||||
good = true
|
||||
case uint64:
|
||||
out.SetFloat(float64(resolved))
|
||||
good = true
|
||||
case float64:
|
||||
out.SetFloat(resolved)
|
||||
good = true
|
||||
}
|
||||
case reflect.Ptr:
|
||||
if out.Type().Elem() == reflect.TypeOf(resolved) {
|
||||
// TODO DOes this make sense? When is out a Ptr except when decoding a nil value?
|
||||
elem := reflect.New(out.Type().Elem())
|
||||
elem.Elem().Set(reflect.ValueOf(resolved))
|
||||
out.Set(elem)
|
||||
good = true
|
||||
}
|
||||
}
|
||||
if !good {
|
||||
d.terror(n, tag, out)
|
||||
}
|
||||
return good
|
||||
}
|
||||
|
||||
func settableValueOf(i interface{}) reflect.Value {
|
||||
v := reflect.ValueOf(i)
|
||||
sv := reflect.New(v.Type()).Elem()
|
||||
sv.Set(v)
|
||||
return sv
|
||||
}
|
||||
|
||||
func (d *decoder) sequence(n *node, out reflect.Value) (good bool) {
|
||||
l := len(n.children)
|
||||
|
||||
var iface reflect.Value
|
||||
switch out.Kind() {
|
||||
case reflect.Slice:
|
||||
out.Set(reflect.MakeSlice(out.Type(), l, l))
|
||||
case reflect.Interface:
|
||||
// No type hints. Will have to use a generic sequence.
|
||||
iface = out
|
||||
out = settableValueOf(make([]interface{}, l))
|
||||
default:
|
||||
d.terror(n, yaml_SEQ_TAG, out)
|
||||
return false
|
||||
}
|
||||
et := out.Type().Elem()
|
||||
|
||||
j := 0
|
||||
for i := 0; i < l; i++ {
|
||||
e := reflect.New(et).Elem()
|
||||
if ok := d.unmarshal(n.children[i], e); ok {
|
||||
out.Index(j).Set(e)
|
||||
j++
|
||||
}
|
||||
}
|
||||
out.Set(out.Slice(0, j))
|
||||
if iface.IsValid() {
|
||||
iface.Set(out)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (d *decoder) mapping(n *node, out reflect.Value) (good bool) {
|
||||
switch out.Kind() {
|
||||
case reflect.Struct:
|
||||
return d.mappingStruct(n, out)
|
||||
case reflect.Slice:
|
||||
return d.mappingSlice(n, out)
|
||||
case reflect.Map:
|
||||
// okay
|
||||
case reflect.Interface:
|
||||
if d.mapType.Kind() == reflect.Map {
|
||||
iface := out
|
||||
out = reflect.MakeMap(d.mapType)
|
||||
iface.Set(out)
|
||||
} else {
|
||||
slicev := reflect.New(d.mapType).Elem()
|
||||
if !d.mappingSlice(n, slicev) {
|
||||
return false
|
||||
}
|
||||
out.Set(slicev)
|
||||
return true
|
||||
}
|
||||
default:
|
||||
d.terror(n, yaml_MAP_TAG, out)
|
||||
return false
|
||||
}
|
||||
outt := out.Type()
|
||||
kt := outt.Key()
|
||||
et := outt.Elem()
|
||||
|
||||
mapType := d.mapType
|
||||
if outt.Key() == ifaceType && outt.Elem() == ifaceType {
|
||||
d.mapType = outt
|
||||
}
|
||||
|
||||
if out.IsNil() {
|
||||
out.Set(reflect.MakeMap(outt))
|
||||
}
|
||||
l := len(n.children)
|
||||
for i := 0; i < l; i += 2 {
|
||||
if isMerge(n.children[i]) {
|
||||
d.merge(n.children[i+1], out)
|
||||
continue
|
||||
}
|
||||
k := reflect.New(kt).Elem()
|
||||
if d.unmarshal(n.children[i], k) {
|
||||
kkind := k.Kind()
|
||||
if kkind == reflect.Interface {
|
||||
kkind = k.Elem().Kind()
|
||||
}
|
||||
if kkind == reflect.Map || kkind == reflect.Slice {
|
||||
failf("invalid map key: %#v", k.Interface())
|
||||
}
|
||||
e := reflect.New(et).Elem()
|
||||
if d.unmarshal(n.children[i+1], e) {
|
||||
out.SetMapIndex(k, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
d.mapType = mapType
|
||||
return true
|
||||
}
|
||||
|
||||
func (d *decoder) mappingSlice(n *node, out reflect.Value) (good bool) {
|
||||
outt := out.Type()
|
||||
if outt.Elem() != mapItemType {
|
||||
d.terror(n, yaml_MAP_TAG, out)
|
||||
return false
|
||||
}
|
||||
|
||||
mapType := d.mapType
|
||||
d.mapType = outt
|
||||
|
||||
var slice []MapItem
|
||||
var l = len(n.children)
|
||||
for i := 0; i < l; i += 2 {
|
||||
if isMerge(n.children[i]) {
|
||||
d.merge(n.children[i+1], out)
|
||||
continue
|
||||
}
|
||||
item := MapItem{}
|
||||
k := reflect.ValueOf(&item.Key).Elem()
|
||||
if d.unmarshal(n.children[i], k) {
|
||||
v := reflect.ValueOf(&item.Value).Elem()
|
||||
if d.unmarshal(n.children[i+1], v) {
|
||||
slice = append(slice, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
out.Set(reflect.ValueOf(slice))
|
||||
d.mapType = mapType
|
||||
return true
|
||||
}
|
||||
|
||||
func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) {
|
||||
sinfo, err := getStructInfo(out.Type())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
name := settableValueOf("")
|
||||
l := len(n.children)
|
||||
|
||||
var inlineMap reflect.Value
|
||||
var elemType reflect.Type
|
||||
if sinfo.InlineMap != -1 {
|
||||
inlineMap = out.Field(sinfo.InlineMap)
|
||||
inlineMap.Set(reflect.New(inlineMap.Type()).Elem())
|
||||
elemType = inlineMap.Type().Elem()
|
||||
}
|
||||
|
||||
for i := 0; i < l; i += 2 {
|
||||
ni := n.children[i]
|
||||
if isMerge(ni) {
|
||||
d.merge(n.children[i+1], out)
|
||||
continue
|
||||
}
|
||||
if !d.unmarshal(ni, name) {
|
||||
continue
|
||||
}
|
||||
if info, ok := sinfo.FieldsMap[name.String()]; ok {
|
||||
var field reflect.Value
|
||||
if info.Inline == nil {
|
||||
field = out.Field(info.Num)
|
||||
} else {
|
||||
field = out.FieldByIndex(info.Inline)
|
||||
}
|
||||
d.unmarshal(n.children[i+1], field)
|
||||
} else if sinfo.InlineMap != -1 {
|
||||
if inlineMap.IsNil() {
|
||||
inlineMap.Set(reflect.MakeMap(inlineMap.Type()))
|
||||
}
|
||||
value := reflect.New(elemType).Elem()
|
||||
d.unmarshal(n.children[i+1], value)
|
||||
inlineMap.SetMapIndex(name, value)
|
||||
} else if d.strict {
|
||||
d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in struct %s", ni.line+1, name.String(), out.Type()))
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func failWantMap() {
|
||||
failf("map merge requires map or sequence of maps as the value")
|
||||
}
|
||||
|
||||
func (d *decoder) merge(n *node, out reflect.Value) {
|
||||
switch n.kind {
|
||||
case mappingNode:
|
||||
d.unmarshal(n, out)
|
||||
case aliasNode:
|
||||
an, ok := d.doc.anchors[n.value]
|
||||
if ok && an.kind != mappingNode {
|
||||
failWantMap()
|
||||
}
|
||||
d.unmarshal(n, out)
|
||||
case sequenceNode:
|
||||
// Step backwards as earlier nodes take precedence.
|
||||
for i := len(n.children) - 1; i >= 0; i-- {
|
||||
ni := n.children[i]
|
||||
if ni.kind == aliasNode {
|
||||
an, ok := d.doc.anchors[ni.value]
|
||||
if ok && an.kind != mappingNode {
|
||||
failWantMap()
|
||||
}
|
||||
} else if ni.kind != mappingNode {
|
||||
failWantMap()
|
||||
}
|
||||
d.unmarshal(ni, out)
|
||||
}
|
||||
default:
|
||||
failWantMap()
|
||||
}
|
||||
}
|
||||
|
||||
func isMerge(n *node) bool {
|
||||
return n.kind == scalarNode && n.value == "<<" && (n.implicit == true || n.tag == yaml_MERGE_TAG)
|
||||
}
|
||||
1684
vendor/gopkg.in/yaml.v2/emitterc.go
generated
vendored
Normal file
1684
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()
|
||||
}
|
||||
1095
vendor/gopkg.in/yaml.v2/parserc.go
generated
vendored
Normal file
1095
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
|
||||
}
|
||||
208
vendor/gopkg.in/yaml.v2/resolve.go
generated
vendored
Normal file
208
vendor/gopkg.in/yaml.v2/resolve.go
generated
vendored
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
package yaml
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"math"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type resolveMapItem struct {
|
||||
value interface{}
|
||||
tag string
|
||||
}
|
||||
|
||||
var resolveTable = make([]byte, 256)
|
||||
var resolveMap = make(map[string]resolveMapItem)
|
||||
|
||||
func init() {
|
||||
t := resolveTable
|
||||
t[int('+')] = 'S' // Sign
|
||||
t[int('-')] = 'S'
|
||||
for _, c := range "0123456789" {
|
||||
t[int(c)] = 'D' // Digit
|
||||
}
|
||||
for _, c := range "yYnNtTfFoO~" {
|
||||
t[int(c)] = 'M' // In map
|
||||
}
|
||||
t[int('.')] = '.' // Float (potentially in map)
|
||||
|
||||
var resolveMapList = []struct {
|
||||
v interface{}
|
||||
tag string
|
||||
l []string
|
||||
}{
|
||||
{true, yaml_BOOL_TAG, []string{"y", "Y", "yes", "Yes", "YES"}},
|
||||
{true, yaml_BOOL_TAG, []string{"true", "True", "TRUE"}},
|
||||
{true, yaml_BOOL_TAG, []string{"on", "On", "ON"}},
|
||||
{false, yaml_BOOL_TAG, []string{"n", "N", "no", "No", "NO"}},
|
||||
{false, yaml_BOOL_TAG, []string{"false", "False", "FALSE"}},
|
||||
{false, yaml_BOOL_TAG, []string{"off", "Off", "OFF"}},
|
||||
{nil, yaml_NULL_TAG, []string{"", "~", "null", "Null", "NULL"}},
|
||||
{math.NaN(), yaml_FLOAT_TAG, []string{".nan", ".NaN", ".NAN"}},
|
||||
{math.Inf(+1), yaml_FLOAT_TAG, []string{".inf", ".Inf", ".INF"}},
|
||||
{math.Inf(+1), yaml_FLOAT_TAG, []string{"+.inf", "+.Inf", "+.INF"}},
|
||||
{math.Inf(-1), yaml_FLOAT_TAG, []string{"-.inf", "-.Inf", "-.INF"}},
|
||||
{"<<", yaml_MERGE_TAG, []string{"<<"}},
|
||||
}
|
||||
|
||||
m := resolveMap
|
||||
for _, item := range resolveMapList {
|
||||
for _, s := range item.l {
|
||||
m[s] = resolveMapItem{item.v, item.tag}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const longTagPrefix = "tag:yaml.org,2002:"
|
||||
|
||||
func shortTag(tag string) string {
|
||||
// TODO This can easily be made faster and produce less garbage.
|
||||
if strings.HasPrefix(tag, longTagPrefix) {
|
||||
return "!!" + tag[len(longTagPrefix):]
|
||||
}
|
||||
return tag
|
||||
}
|
||||
|
||||
func longTag(tag string) string {
|
||||
if strings.HasPrefix(tag, "!!") {
|
||||
return longTagPrefix + tag[2:]
|
||||
}
|
||||
return tag
|
||||
}
|
||||
|
||||
func resolvableTag(tag string) bool {
|
||||
switch tag {
|
||||
case "", yaml_STR_TAG, yaml_BOOL_TAG, yaml_INT_TAG, yaml_FLOAT_TAG, yaml_NULL_TAG:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var yamlStyleFloat = regexp.MustCompile(`^[-+]?[0-9]*\.?[0-9]+([eE][-+][0-9]+)?$`)
|
||||
|
||||
func resolve(tag string, in string) (rtag string, out interface{}) {
|
||||
if !resolvableTag(tag) {
|
||||
return tag, in
|
||||
}
|
||||
|
||||
defer func() {
|
||||
switch tag {
|
||||
case "", rtag, yaml_STR_TAG, yaml_BINARY_TAG:
|
||||
return
|
||||
}
|
||||
failf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(tag))
|
||||
}()
|
||||
|
||||
// Any data is accepted as a !!str or !!binary.
|
||||
// Otherwise, the prefix is enough of a hint about what it might be.
|
||||
hint := byte('N')
|
||||
if in != "" {
|
||||
hint = resolveTable[in[0]]
|
||||
}
|
||||
if hint != 0 && tag != yaml_STR_TAG && tag != yaml_BINARY_TAG {
|
||||
// Handle things we can lookup in a map.
|
||||
if item, ok := resolveMap[in]; ok {
|
||||
return item.tag, item.value
|
||||
}
|
||||
|
||||
// Base 60 floats are a bad idea, were dropped in YAML 1.2, and
|
||||
// are purposefully unsupported here. They're still quoted on
|
||||
// the way out for compatibility with other parser, though.
|
||||
|
||||
switch hint {
|
||||
case 'M':
|
||||
// We've already checked the map above.
|
||||
|
||||
case '.':
|
||||
// Not in the map, so maybe a normal float.
|
||||
floatv, err := strconv.ParseFloat(in, 64)
|
||||
if err == nil {
|
||||
return yaml_FLOAT_TAG, floatv
|
||||
}
|
||||
|
||||
case 'D', 'S':
|
||||
// Int, float, or timestamp.
|
||||
plain := strings.Replace(in, "_", "", -1)
|
||||
intv, err := strconv.ParseInt(plain, 0, 64)
|
||||
if err == nil {
|
||||
if intv == int64(int(intv)) {
|
||||
return yaml_INT_TAG, int(intv)
|
||||
} else {
|
||||
return yaml_INT_TAG, intv
|
||||
}
|
||||
}
|
||||
uintv, err := strconv.ParseUint(plain, 0, 64)
|
||||
if err == nil {
|
||||
return yaml_INT_TAG, uintv
|
||||
}
|
||||
if yamlStyleFloat.MatchString(plain) {
|
||||
floatv, err := strconv.ParseFloat(plain, 64)
|
||||
if err == nil {
|
||||
return yaml_FLOAT_TAG, floatv
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(plain, "0b") {
|
||||
intv, err := strconv.ParseInt(plain[2:], 2, 64)
|
||||
if err == nil {
|
||||
if intv == int64(int(intv)) {
|
||||
return yaml_INT_TAG, int(intv)
|
||||
} else {
|
||||
return yaml_INT_TAG, intv
|
||||
}
|
||||
}
|
||||
uintv, err := strconv.ParseUint(plain[2:], 2, 64)
|
||||
if err == nil {
|
||||
return yaml_INT_TAG, uintv
|
||||
}
|
||||
} else if strings.HasPrefix(plain, "-0b") {
|
||||
intv, err := strconv.ParseInt(plain[3:], 2, 64)
|
||||
if err == nil {
|
||||
if intv == int64(int(intv)) {
|
||||
return yaml_INT_TAG, -int(intv)
|
||||
} else {
|
||||
return yaml_INT_TAG, -intv
|
||||
}
|
||||
}
|
||||
}
|
||||
// XXX Handle timestamps here.
|
||||
|
||||
default:
|
||||
panic("resolveTable item not yet handled: " + string(rune(hint)) + " (with " + in + ")")
|
||||
}
|
||||
}
|
||||
if tag == yaml_BINARY_TAG {
|
||||
return yaml_BINARY_TAG, in
|
||||
}
|
||||
if utf8.ValidString(in) {
|
||||
return yaml_STR_TAG, in
|
||||
}
|
||||
return yaml_BINARY_TAG, encodeBase64(in)
|
||||
}
|
||||
|
||||
// encodeBase64 encodes s as base64 that is broken up into multiple lines
|
||||
// as appropriate for the resulting length.
|
||||
func encodeBase64(s string) string {
|
||||
const lineLen = 70
|
||||
encLen := base64.StdEncoding.EncodedLen(len(s))
|
||||
lines := encLen/lineLen + 1
|
||||
buf := make([]byte, encLen*2+lines)
|
||||
in := buf[0:encLen]
|
||||
out := buf[encLen:]
|
||||
base64.StdEncoding.Encode(in, []byte(s))
|
||||
k := 0
|
||||
for i := 0; i < len(in); i += lineLen {
|
||||
j := i + lineLen
|
||||
if j > len(in) {
|
||||
j = len(in)
|
||||
}
|
||||
k += copy(out[k:], in[i:j])
|
||||
if lines > 1 {
|
||||
out[k] = '\n'
|
||||
k++
|
||||
}
|
||||
}
|
||||
return string(out[:k])
|
||||
}
|
||||
2711
vendor/gopkg.in/yaml.v2/scannerc.go
generated
vendored
Normal file
2711
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")
|
||||
}
|
||||
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
|
||||
}
|
||||
357
vendor/gopkg.in/yaml.v2/yaml.go
generated
vendored
Normal file
357
vendor/gopkg.in/yaml.v2/yaml.go
generated
vendored
Normal file
|
|
@ -0,0 +1,357 @@
|
|||
// Package yaml implements YAML support for the Go language.
|
||||
//
|
||||
// Source code and other details for the project are available at GitHub:
|
||||
//
|
||||
// https://github.com/go-yaml/yaml
|
||||
//
|
||||
package yaml
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// MapSlice encodes and decodes as a YAML map.
|
||||
// The order of keys is preserved when encoding and decoding.
|
||||
type MapSlice []MapItem
|
||||
|
||||
// MapItem is an item in a MapSlice.
|
||||
type MapItem struct {
|
||||
Key, Value interface{}
|
||||
}
|
||||
|
||||
// The Unmarshaler interface may be implemented by types to customize their
|
||||
// behavior when being unmarshaled from a YAML document. The UnmarshalYAML
|
||||
// method receives a function that may be called to unmarshal the original
|
||||
// YAML value into a field or variable. It is safe to call the unmarshal
|
||||
// function parameter more than once if necessary.
|
||||
type Unmarshaler interface {
|
||||
UnmarshalYAML(unmarshal func(interface{}) error) error
|
||||
}
|
||||
|
||||
// The Marshaler interface may be implemented by types to customize their
|
||||
// behavior when being marshaled into a YAML document. The returned value
|
||||
// is marshaled in place of the original value implementing Marshaler.
|
||||
//
|
||||
// If an error is returned by MarshalYAML, the marshaling procedure stops
|
||||
// and returns with the provided error.
|
||||
type Marshaler interface {
|
||||
MarshalYAML() (interface{}, error)
|
||||
}
|
||||
|
||||
// Unmarshal decodes the first document found within the in byte slice
|
||||
// and assigns decoded values into the out value.
|
||||
//
|
||||
// Maps and pointers (to a struct, string, int, etc) are accepted as out
|
||||
// values. If an internal pointer within a struct is not initialized,
|
||||
// the yaml package will initialize it if necessary for unmarshalling
|
||||
// the provided data. The out parameter must not be nil.
|
||||
//
|
||||
// The type of the decoded values should be compatible with the respective
|
||||
// values in out. If one or more values cannot be decoded due to a type
|
||||
// mismatches, decoding continues partially until the end of the YAML
|
||||
// content, and a *yaml.TypeError is returned with details for all
|
||||
// missed values.
|
||||
//
|
||||
// Struct fields are only unmarshalled if they are exported (have an
|
||||
// upper case first letter), and are unmarshalled using the field name
|
||||
// lowercased as the default key. Custom keys may be defined via the
|
||||
// "yaml" name in the field tag: the content preceding the first comma
|
||||
// is used as the key, and the following comma-separated options are
|
||||
// used to tweak the marshalling process (see Marshal).
|
||||
// Conflicting names result in a runtime error.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// type T struct {
|
||||
// F int `yaml:"a,omitempty"`
|
||||
// B int
|
||||
// }
|
||||
// var t T
|
||||
// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
|
||||
//
|
||||
// See the documentation of Marshal for the format of tags and a list of
|
||||
// supported tag options.
|
||||
//
|
||||
func Unmarshal(in []byte, out interface{}) (err error) {
|
||||
return unmarshal(in, out, false)
|
||||
}
|
||||
|
||||
// UnmarshalStrict is like Unmarshal except that any fields that are found
|
||||
// in the data that do not have corresponding struct members will result in
|
||||
// an error.
|
||||
func UnmarshalStrict(in []byte, out interface{}) (err error) {
|
||||
return unmarshal(in, out, true)
|
||||
}
|
||||
|
||||
func unmarshal(in []byte, out interface{}, strict bool) (err error) {
|
||||
defer handleErr(&err)
|
||||
d := newDecoder(strict)
|
||||
p := newParser(in)
|
||||
defer p.destroy()
|
||||
node := p.parse()
|
||||
if node != nil {
|
||||
v := reflect.ValueOf(out)
|
||||
if v.Kind() == reflect.Ptr && !v.IsNil() {
|
||||
v = v.Elem()
|
||||
}
|
||||
d.unmarshal(node, v)
|
||||
}
|
||||
if len(d.terrors) > 0 {
|
||||
return &TypeError{d.terrors}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Marshal serializes the value provided into a YAML document. The structure
|
||||
// of the generated document will reflect the structure of the value itself.
|
||||
// Maps and pointers (to struct, string, int, etc) are accepted as the in value.
|
||||
//
|
||||
// Struct fields are only unmarshalled if they are exported (have an upper case
|
||||
// first letter), and are unmarshalled using the field name lowercased as the
|
||||
// default key. Custom keys may be defined via the "yaml" name in the field
|
||||
// tag: the content preceding the first comma is used as the key, and the
|
||||
// following comma-separated options are used to tweak the marshalling process.
|
||||
// Conflicting names result in a runtime error.
|
||||
//
|
||||
// The field tag format accepted is:
|
||||
//
|
||||
// `(...) yaml:"[<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 `yaml:"a,omitempty"`
|
||||
// B int
|
||||
// }
|
||||
// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
|
||||
// yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n"
|
||||
//
|
||||
func Marshal(in interface{}) (out []byte, err error) {
|
||||
defer handleErr(&err)
|
||||
e := newEncoder()
|
||||
defer e.destroy()
|
||||
e.marshal("", reflect.ValueOf(in))
|
||||
e.finish()
|
||||
out = e.out
|
||||
return
|
||||
}
|
||||
|
||||
func handleErr(err *error) {
|
||||
if v := recover(); v != nil {
|
||||
if e, ok := v.(yamlError); ok {
|
||||
*err = e.err
|
||||
} else {
|
||||
panic(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type yamlError struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func fail(err error) {
|
||||
panic(yamlError{err})
|
||||
}
|
||||
|
||||
func failf(format string, args ...interface{}) {
|
||||
panic(yamlError{fmt.Errorf("yaml: "+format, args...)})
|
||||
}
|
||||
|
||||
// A TypeError is returned by Unmarshal when one or more fields in
|
||||
// the YAML document cannot be properly decoded into the requested
|
||||
// types. When this error is returned, the value is still
|
||||
// unmarshaled partially.
|
||||
type TypeError struct {
|
||||
Errors []string
|
||||
}
|
||||
|
||||
func (e *TypeError) Error() string {
|
||||
return fmt.Sprintf("yaml: unmarshal errors:\n %s", strings.Join(e.Errors, "\n "))
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Maintain a mapping of keys to structure field indexes
|
||||
|
||||
// The code in this section was copied from mgo/bson.
|
||||
|
||||
// structInfo holds details for the serialization of fields of
|
||||
// a given struct.
|
||||
type structInfo struct {
|
||||
FieldsMap map[string]fieldInfo
|
||||
FieldsList []fieldInfo
|
||||
|
||||
// InlineMap is the number of the field in the struct that
|
||||
// contains an ,inline map, or -1 if there's none.
|
||||
InlineMap int
|
||||
}
|
||||
|
||||
type fieldInfo struct {
|
||||
Key string
|
||||
Num int
|
||||
OmitEmpty bool
|
||||
Flow bool
|
||||
|
||||
// Inline holds the field index if the field is part of an inlined struct.
|
||||
Inline []int
|
||||
}
|
||||
|
||||
var structMap = make(map[reflect.Type]*structInfo)
|
||||
var fieldMapMutex sync.RWMutex
|
||||
|
||||
func getStructInfo(st reflect.Type) (*structInfo, error) {
|
||||
fieldMapMutex.RLock()
|
||||
sinfo, found := structMap[st]
|
||||
fieldMapMutex.RUnlock()
|
||||
if found {
|
||||
return sinfo, nil
|
||||
}
|
||||
|
||||
n := st.NumField()
|
||||
fieldsMap := make(map[string]fieldInfo)
|
||||
fieldsList := make([]fieldInfo, 0, n)
|
||||
inlineMap := -1
|
||||
for i := 0; i != n; i++ {
|
||||
field := st.Field(i)
|
||||
if field.PkgPath != "" && !field.Anonymous {
|
||||
continue // Private field
|
||||
}
|
||||
|
||||
info := fieldInfo{Num: i}
|
||||
|
||||
tag := field.Tag.Get("yaml")
|
||||
if tag == "" && strings.Index(string(field.Tag), ":") < 0 {
|
||||
tag = string(field.Tag)
|
||||
}
|
||||
if tag == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
inline := false
|
||||
fields := strings.Split(tag, ",")
|
||||
if len(fields) > 1 {
|
||||
for _, flag := range fields[1:] {
|
||||
switch flag {
|
||||
case "omitempty":
|
||||
info.OmitEmpty = true
|
||||
case "flow":
|
||||
info.Flow = true
|
||||
case "inline":
|
||||
inline = true
|
||||
default:
|
||||
return nil, errors.New(fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st))
|
||||
}
|
||||
}
|
||||
tag = fields[0]
|
||||
}
|
||||
|
||||
if inline {
|
||||
switch field.Type.Kind() {
|
||||
case reflect.Map:
|
||||
if inlineMap >= 0 {
|
||||
return nil, errors.New("Multiple ,inline maps in struct " + st.String())
|
||||
}
|
||||
if field.Type.Key() != reflect.TypeOf("") {
|
||||
return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String())
|
||||
}
|
||||
inlineMap = info.Num
|
||||
case reflect.Struct:
|
||||
sinfo, err := getStructInfo(field.Type)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, finfo := range sinfo.FieldsList {
|
||||
if _, found := fieldsMap[finfo.Key]; found {
|
||||
msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String()
|
||||
return nil, errors.New(msg)
|
||||
}
|
||||
if finfo.Inline == nil {
|
||||
finfo.Inline = []int{i, finfo.Num}
|
||||
} else {
|
||||
finfo.Inline = append([]int{i}, finfo.Inline...)
|
||||
}
|
||||
fieldsMap[finfo.Key] = finfo
|
||||
fieldsList = append(fieldsList, finfo)
|
||||
}
|
||||
default:
|
||||
//return nil, errors.New("Option ,inline needs a struct value or map field")
|
||||
return nil, errors.New("Option ,inline needs a struct value field")
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if tag != "" {
|
||||
info.Key = tag
|
||||
} else {
|
||||
info.Key = strings.ToLower(field.Name)
|
||||
}
|
||||
|
||||
if _, found = fieldsMap[info.Key]; found {
|
||||
msg := "Duplicated key '" + info.Key + "' in struct " + st.String()
|
||||
return nil, errors.New(msg)
|
||||
}
|
||||
|
||||
fieldsList = append(fieldsList, info)
|
||||
fieldsMap[info.Key] = info
|
||||
}
|
||||
|
||||
sinfo = &structInfo{fieldsMap, fieldsList, inlineMap}
|
||||
|
||||
fieldMapMutex.Lock()
|
||||
structMap[st] = sinfo
|
||||
fieldMapMutex.Unlock()
|
||||
return sinfo, nil
|
||||
}
|
||||
|
||||
func isZero(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.String:
|
||||
return len(v.String()) == 0
|
||||
case reflect.Interface, reflect.Ptr:
|
||||
return v.IsNil()
|
||||
case reflect.Slice:
|
||||
return v.Len() == 0
|
||||
case reflect.Map:
|
||||
return v.Len() == 0
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return v.Int() == 0
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return v.Float() == 0
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return v.Uint() == 0
|
||||
case reflect.Bool:
|
||||
return !v.Bool()
|
||||
case reflect.Struct:
|
||||
vt := v.Type()
|
||||
for i := v.NumField() - 1; i >= 0; i-- {
|
||||
if vt.Field(i).PkgPath != "" {
|
||||
continue // Private field
|
||||
}
|
||||
if !isZero(v.Field(i)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
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 occurred.
|
||||
problem_offset int
|
||||
problem_value int
|
||||
problem_mark yaml_mark_t
|
||||
|
||||
// The error context.
|
||||
context string
|
||||
context_mark yaml_mark_t
|
||||
|
||||
// Reader stuff
|
||||
|
||||
read_handler yaml_read_handler_t // Read handler.
|
||||
|
||||
input_file io.Reader // File input data.
|
||||
input []byte // String input data.
|
||||
input_pos int
|
||||
|
||||
eof bool // EOF flag
|
||||
|
||||
buffer []byte // The working buffer.
|
||||
buffer_pos int // The current position of the buffer.
|
||||
|
||||
unread int // The number of unread characters in the buffer.
|
||||
|
||||
raw_buffer []byte // The raw buffer.
|
||||
raw_buffer_pos int // The current position of the buffer.
|
||||
|
||||
encoding yaml_encoding_t // The input encoding.
|
||||
|
||||
offset int // The offset of the current position (in bytes).
|
||||
mark yaml_mark_t // The mark of the current position.
|
||||
|
||||
// Scanner stuff
|
||||
|
||||
stream_start_produced bool // Have we started to scan the input stream?
|
||||
stream_end_produced bool // Have we reached the end of the input stream?
|
||||
|
||||
flow_level int // The number of unclosed '[' and '{' indicators.
|
||||
|
||||
tokens []yaml_token_t // The tokens queue.
|
||||
tokens_head int // The head of the tokens queue.
|
||||
tokens_parsed int // The number of tokens fetched from the queue.
|
||||
token_available bool // Does the tokens queue contain a token ready for dequeueing.
|
||||
|
||||
indent int // The current indentation level.
|
||||
indents []int // The indentation levels stack.
|
||||
|
||||
simple_key_allowed bool // May a simple key occur at the current position?
|
||||
simple_keys []yaml_simple_key_t // The stack of simple keys.
|
||||
|
||||
// Parser stuff
|
||||
|
||||
state yaml_parser_state_t // The current parser state.
|
||||
states []yaml_parser_state_t // The parser states stack.
|
||||
marks []yaml_mark_t // The stack of marks.
|
||||
tag_directives []yaml_tag_directive_t // The list of TAG directives.
|
||||
|
||||
// Dumper stuff
|
||||
|
||||
aliases []yaml_alias_data_t // The alias data.
|
||||
|
||||
document *yaml_document_t // The currently parsed document.
|
||||
}
|
||||
|
||||
// Emitter Definitions
|
||||
|
||||
// The prototype of a write handler.
|
||||
//
|
||||
// The write handler is called when the emitter needs to flush the accumulated
|
||||
// characters to the output. The handler should write @a size bytes of the
|
||||
// @a buffer to the output.
|
||||
//
|
||||
// @param[in,out] data A pointer to an application data specified by
|
||||
// yaml_emitter_set_output().
|
||||
// @param[in] buffer The buffer with bytes to be written.
|
||||
// @param[in] size The size of the buffer.
|
||||
//
|
||||
// @returns On success, the handler should return @c 1. If the handler failed,
|
||||
// the returned value should be @c 0.
|
||||
//
|
||||
type yaml_write_handler_t func(emitter *yaml_emitter_t, buffer []byte) error
|
||||
|
||||
type yaml_emitter_state_t int
|
||||
|
||||
// The emitter states.
|
||||
const (
|
||||
// Expect STREAM-START.
|
||||
yaml_EMIT_STREAM_START_STATE yaml_emitter_state_t = iota
|
||||
|
||||
yaml_EMIT_FIRST_DOCUMENT_START_STATE // Expect the first DOCUMENT-START or STREAM-END.
|
||||
yaml_EMIT_DOCUMENT_START_STATE // Expect DOCUMENT-START or STREAM-END.
|
||||
yaml_EMIT_DOCUMENT_CONTENT_STATE // Expect the content of a document.
|
||||
yaml_EMIT_DOCUMENT_END_STATE // Expect DOCUMENT-END.
|
||||
yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a flow sequence.
|
||||
yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE // Expect an item of a flow sequence.
|
||||
yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping.
|
||||
yaml_EMIT_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping.
|
||||
yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a flow mapping.
|
||||
yaml_EMIT_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping.
|
||||
yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a block sequence.
|
||||
yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE // Expect an item of a block sequence.
|
||||
yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping.
|
||||
yaml_EMIT_BLOCK_MAPPING_KEY_STATE // Expect the key of a block mapping.
|
||||
yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a block mapping.
|
||||
yaml_EMIT_BLOCK_MAPPING_VALUE_STATE // Expect a value of a block mapping.
|
||||
yaml_EMIT_END_STATE // Expect nothing.
|
||||
)
|
||||
|
||||
// The emitter structure.
|
||||
//
|
||||
// All members are internal. Manage the structure using the @c yaml_emitter_
|
||||
// family of functions.
|
||||
type yaml_emitter_t struct {
|
||||
|
||||
// Error handling
|
||||
|
||||
error yaml_error_type_t // Error type.
|
||||
problem string // Error description.
|
||||
|
||||
// Writer stuff
|
||||
|
||||
write_handler yaml_write_handler_t // Write handler.
|
||||
|
||||
output_buffer *[]byte // String output data.
|
||||
output_file io.Writer // File output data.
|
||||
|
||||
buffer []byte // The working buffer.
|
||||
buffer_pos int // The current position of the buffer.
|
||||
|
||||
raw_buffer []byte // The raw buffer.
|
||||
raw_buffer_pos int // The current position of the buffer.
|
||||
|
||||
encoding yaml_encoding_t // The stream encoding.
|
||||
|
||||
// Emitter stuff
|
||||
|
||||
canonical bool // If the output is in the canonical style?
|
||||
best_indent int // The number of indentation spaces.
|
||||
best_width int // The preferred width of the output lines.
|
||||
unicode bool // Allow unescaped non-ASCII characters?
|
||||
line_break yaml_break_t // The preferred line break.
|
||||
|
||||
state yaml_emitter_state_t // The current emitter state.
|
||||
states []yaml_emitter_state_t // The stack of states.
|
||||
|
||||
events []yaml_event_t // The event queue.
|
||||
events_head int // The head of the event queue.
|
||||
|
||||
indents []int // The stack of indentation levels.
|
||||
|
||||
tag_directives []yaml_tag_directive_t // The list of tag directives.
|
||||
|
||||
indent int // The current indentation level.
|
||||
|
||||
flow_level int // The current flow level.
|
||||
|
||||
root_context bool // Is it the document root context?
|
||||
sequence_context bool // Is it a sequence context?
|
||||
mapping_context bool // Is it a mapping context?
|
||||
simple_key_context bool // Is it a simple mapping key context?
|
||||
|
||||
line int // The current line.
|
||||
column int // The current column.
|
||||
whitespace bool // If the last character was a whitespace?
|
||||
indention bool // If the last character was an indentation character (' ', '-', '?', ':')?
|
||||
open_ended bool // If an explicit document end is required?
|
||||
|
||||
// Anchor analysis.
|
||||
anchor_data struct {
|
||||
anchor []byte // The anchor value.
|
||||
alias bool // Is it an alias?
|
||||
}
|
||||
|
||||
// Tag analysis.
|
||||
tag_data struct {
|
||||
handle []byte // The tag handle.
|
||||
suffix []byte // The tag suffix.
|
||||
}
|
||||
|
||||
// Scalar analysis.
|
||||
scalar_data struct {
|
||||
value []byte // The scalar value.
|
||||
multiline bool // Does the scalar contain line breaks?
|
||||
flow_plain_allowed bool // Can the scalar be expessed in the flow plain style?
|
||||
block_plain_allowed bool // Can the scalar be expressed in the block plain style?
|
||||
single_quoted_allowed bool // Can the scalar be expressed in the single quoted style?
|
||||
block_allowed bool // Can the scalar be expressed in the literal or folded styles?
|
||||
style yaml_scalar_style_t // The output style.
|
||||
}
|
||||
|
||||
// Dumper stuff
|
||||
|
||||
opened bool // If the stream was already opened?
|
||||
closed bool // If the stream was already closed?
|
||||
|
||||
// The information associated with the document nodes.
|
||||
anchors *struct {
|
||||
references int // The number of references.
|
||||
anchor int // The anchor id.
|
||||
serialized bool // If the node has been emitted?
|
||||
}
|
||||
|
||||
last_anchor_id int // The last assigned anchor id.
|
||||
|
||||
document *yaml_document_t // The currently emitted document.
|
||||
}
|
||||
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
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue