├── .gitignore ├── vendor ├── github.com │ ├── caarlos0 │ │ └── env │ │ │ ├── .gitignore │ │ │ ├── .hound.yml │ │ │ ├── .travis.yml │ │ │ ├── LICENSE.md │ │ │ ├── README.md │ │ │ └── env.go │ └── ericaro │ │ └── frontmatter │ │ ├── .travis.yml │ │ ├── README.md │ │ ├── writestring.go │ │ └── frontmatter.go ├── gopkg.in │ └── yaml.v2 │ │ ├── go.mod │ │ ├── .travis.yml │ │ ├── NOTICE │ │ ├── writerc.go │ │ ├── LICENSE.libyaml │ │ ├── sorter.go │ │ ├── README.md │ │ ├── yamlprivateh.go │ │ ├── resolve.go │ │ ├── encode.go │ │ ├── LICENSE │ │ ├── readerc.go │ │ ├── yaml.go │ │ ├── decode.go │ │ ├── apic.go │ │ └── yamlh.go └── modules.txt ├── jrnl.gif ├── fixtures ├── test-pixel.png └── entries │ └── 2018-08-01.md ├── .github ├── dependabot.yml └── workflows │ └── test.yml ├── commands ├── config.go ├── list-tags.go ├── find_test.go ├── sync.go ├── sync_test.go ├── memorize.go ├── image_test.go ├── find.go ├── open_test.go ├── image.go ├── open.go ├── common.go ├── index.go └── tag.go ├── go.mod ├── .goreleaser.yml ├── go.sum ├── cmd └── jrnl │ ├── main_test.go │ └── main.go └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | /jrnl 3 | main -------------------------------------------------------------------------------- /vendor/github.com/caarlos0/env/.gitignore: -------------------------------------------------------------------------------- 1 | coverage.out 2 | -------------------------------------------------------------------------------- /jrnl.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cjsaylor/jrnl/HEAD/jrnl.gif -------------------------------------------------------------------------------- /vendor/github.com/caarlos0/env/.hound.yml: -------------------------------------------------------------------------------- 1 | go: 2 | enabled: true 3 | -------------------------------------------------------------------------------- /fixtures/test-pixel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cjsaylor/jrnl/HEAD/fixtures/test-pixel.png -------------------------------------------------------------------------------- /vendor/github.com/ericaro/frontmatter/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.2 4 | - 1.3 5 | - 1.4 6 | - tip 7 | 8 | -------------------------------------------------------------------------------- /fixtures/entries/2018-08-01.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: Wed Aug 1 2018 00:00:00 +0000 UTC 3 | tags: 4 | - foo 5 | - bar 6 | --- 7 | Some Content -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v2/go.mod: -------------------------------------------------------------------------------- 1 | module "gopkg.in/yaml.v2" 2 | 3 | require ( 4 | "gopkg.in/check.v1" v0.0.0-20161208181325-20d25e280405 5 | ) 6 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gomod 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "10:00" 8 | open-pull-requests-limit: 10 9 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v2/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.4 5 | - 1.5 6 | - 1.6 7 | - 1.7 8 | - 1.8 9 | - 1.9 10 | - tip 11 | 12 | go_import_path: gopkg.in/yaml.v2 13 | -------------------------------------------------------------------------------- /commands/config.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | type Configuration struct { 4 | JournalPath string `env:"JOURNAL_PATH"` 5 | JournalEditor string `env:"JRNL_EDITOR" envDefault:"vim"` 6 | JournalEditorOptions string `env:"JRNL_EDITOR_OPTIONS"` 7 | } 8 | -------------------------------------------------------------------------------- /vendor/modules.txt: -------------------------------------------------------------------------------- 1 | # github.com/caarlos0/env v0.0.0-20170430215205-7110c4e2f569 2 | github.com/caarlos0/env 3 | # github.com/ericaro/frontmatter v0.0.0-20141225210444-9fedef9406e4 4 | github.com/ericaro/frontmatter 5 | # gopkg.in/yaml.v2 v2.2.2 6 | gopkg.in/yaml.v2 7 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/cjsaylor/jrnl 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/caarlos0/env v0.0.0-20170430215205-7110c4e2f569 7 | github.com/ericaro/frontmatter v0.0.0-20141225210444-9fedef9406e4 8 | github.com/kr/pretty v0.1.0 // indirect 9 | github.com/stretchr/testify v1.4.0 // indirect 10 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /vendor/github.com/caarlos0/env/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.4 4 | - 1.5 5 | - 1.6 6 | - tip 7 | before_install: 8 | - go get github.com/axw/gocov/gocov 9 | - go get github.com/mattn/goveralls 10 | - go get golang.org/x/tools/cmd/cover 11 | script: 12 | - go test -v -cover -race -coverprofile=coverage.out 13 | after_script: 14 | - go get github.com/mattn/goveralls 15 | - goveralls -coverprofile=coverage.out -service=travis-ci -repotoken='eCcizKmTdSaJCz8Ih33WDppdqb9kioYwi' 16 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | builds: 2 | - main: ./cmd/jrnl/main.go 3 | binary: jrnl 4 | goos: 5 | - windows 6 | - darwin 7 | - linux 8 | goarch: 9 | - amd64 10 | 11 | brew: 12 | github: 13 | owner: cjsaylor 14 | name: homebrew-tap 15 | folder: Formula 16 | commit_author: 17 | name: cjsaylor 18 | email: cjsaylor@gmail.com 19 | description: "Quick and easy CLI journaling tool for Github wiki journals." 20 | dependencies: 21 | - git 22 | 23 | release: 24 | prerelease: true -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test Application 2 | on: [push] 3 | jobs: 4 | test: 5 | name: Test 6 | runs-on: ubuntu-latest 7 | steps: 8 | 9 | - name: Set up Go 1.12 10 | uses: actions/setup-go@v1 11 | with: 12 | go-version: 1.12 13 | id: go 14 | 15 | - name: Check out code into the Go module directory 16 | uses: actions/checkout@v1 17 | 18 | - name: Get dependencies 19 | run: | 20 | go get -u golang.org/x/tools/cmd/cover 21 | 22 | - name: Test 23 | run: | 24 | go test -cover $(go list ./... | grep -v /vendor/) 25 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v2/NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2011-2016 Canonical Ltd. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /commands/list-tags.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import "context" 4 | import "fmt" 5 | import "os" 6 | 7 | type ListTagsCommand struct { 8 | options Configuration 9 | } 10 | 11 | // NewListTagsCommand creates a new command runner for listing tags. 12 | func NewListTagsCommand(config Configuration) *ListTagsCommand { 13 | listTagsCommand := ListTagsCommand{ 14 | options: config, 15 | } 16 | return &listTagsCommand 17 | } 18 | 19 | // Run the list-tags command 20 | func (l *ListTagsCommand) Run(ctd context.Context, subcommandArgs []string) error { 21 | index, err := tagMap(l.options.JournalPath) 22 | if err != nil { 23 | return err 24 | } 25 | tags := sortedTagKeys(index) 26 | for _, tag := range tags { 27 | fmt.Fprintf(os.Stdout, "%s\n", tag) 28 | } 29 | return nil 30 | } 31 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v2/writerc.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | // Set the writer error and return false. 4 | func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool { 5 | emitter.error = yaml_WRITER_ERROR 6 | emitter.problem = problem 7 | return false 8 | } 9 | 10 | // Flush the output buffer. 11 | func yaml_emitter_flush(emitter *yaml_emitter_t) bool { 12 | if emitter.write_handler == nil { 13 | panic("write handler not set") 14 | } 15 | 16 | // Check if the buffer is empty. 17 | if emitter.buffer_pos == 0 { 18 | return true 19 | } 20 | 21 | if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil { 22 | return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error()) 23 | } 24 | emitter.buffer_pos = 0 25 | return true 26 | } 27 | -------------------------------------------------------------------------------- /commands/find_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "io/ioutil" 7 | "os" 8 | "path/filepath" 9 | "testing" 10 | "time" 11 | 12 | "github.com/cjsaylor/jrnl/commands" 13 | ) 14 | 15 | func TestFindTag(t *testing.T) { 16 | path, _ := filepath.Abs("../fixtures") 17 | config := commands.Configuration{ 18 | JournalPath: path, 19 | } 20 | r, w, _ := os.Pipe() 21 | cmd := commands.NewFindCommand(config, w) 22 | ctx := context.WithValue(context.Background(), commands.CommandContextKey("date"), time.Date(2018, time.August, 1, 0, 0, 0, 0, time.UTC)) 23 | cmd.Run(ctx, []string{"-tag", "foo"}) 24 | w.Close() 25 | output, _ := ioutil.ReadAll(r) 26 | expectedOutput := fmt.Sprintf("%v/entries/2018-08-01.md\n", path) 27 | if expectedOutput != string(output) { 28 | t.Errorf("Expected %v, got %v", expectedOutput, string(output)) 29 | } 30 | fmt.Println(string(output)) 31 | } 32 | -------------------------------------------------------------------------------- /commands/sync.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | ) 7 | 8 | type SyncCommand struct { 9 | options Configuration 10 | runner GitCommandRunner 11 | } 12 | 13 | type GitCommandRunner interface { 14 | Pull(path string) error 15 | } 16 | 17 | type GitCommandRunnerImpl struct{} 18 | 19 | func (g GitCommandRunnerImpl) Pull(path string) error { 20 | params := []string{ 21 | "-C", 22 | path, 23 | "pull", 24 | } 25 | if code := gitCommand(params...); code != 0 { 26 | return errors.New("failed to sync journal") 27 | } 28 | return nil 29 | } 30 | 31 | // NewSyncCommand creates a new command runner for sync command 32 | func NewSyncCommand(config Configuration, runner GitCommandRunner) *SyncCommand { 33 | syncCommand := SyncCommand{ 34 | options: config, 35 | runner: runner, 36 | } 37 | return &syncCommand 38 | } 39 | 40 | // Run the sync command 41 | func (s *SyncCommand) Run(ctx context.Context, subcommandArgs []string) error { 42 | return s.runner.Pull(s.options.JournalPath) 43 | } 44 | -------------------------------------------------------------------------------- /commands/sync_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | "time" 7 | 8 | "github.com/cjsaylor/jrnl/commands" 9 | ) 10 | 11 | type fakeGitCommand struct { 12 | called map[string][]string 13 | } 14 | 15 | func (f fakeGitCommand) Pull(path string) error { 16 | f.called["pull"] = []string{path} 17 | return nil 18 | } 19 | 20 | func TestSyncRun(t *testing.T) { 21 | runner := fakeGitCommand{ 22 | called: make(map[string][]string), 23 | } 24 | config := commands.Configuration{ 25 | JournalPath: "/some/path", 26 | } 27 | cmd := commands.NewSyncCommand(config, runner) 28 | ctx := context.WithValue(context.Background(), commands.CommandContextKey("date"), time.Date(2018, time.July, 28, 0, 0, 0, 0, time.UTC)) 29 | if err := cmd.Run(ctx, []string{}); err != nil { 30 | t.Error(err) 31 | } 32 | if len(runner.called["pull"]) == 0 { 33 | t.Error("Expected a git pull") 34 | return 35 | } 36 | expectedPullPath := config.JournalPath 37 | if runner.called["pull"][0] != expectedPullPath { 38 | t.Errorf("Expected %v, got %v.", expectedPullPath, runner.called["pull"][0]) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /vendor/github.com/caarlos0/env/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2016 Carlos Alexandro Becker 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v2/LICENSE.libyaml: -------------------------------------------------------------------------------- 1 | The following files were ported to Go from C files of libyaml, and thus 2 | are still covered by their original copyright and license: 3 | 4 | apic.go 5 | emitterc.go 6 | parserc.go 7 | readerc.go 8 | scannerc.go 9 | writerc.go 10 | yamlh.go 11 | yamlprivateh.go 12 | 13 | Copyright (c) 2006 Kirill Simonov 14 | 15 | Permission is hereby granted, free of charge, to any person obtaining a copy of 16 | this software and associated documentation files (the "Software"), to deal in 17 | the Software without restriction, including without limitation the rights to 18 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 19 | of the Software, and to permit persons to whom the Software is furnished to do 20 | so, subject to the following conditions: 21 | 22 | The above copyright notice and this permission notice shall be included in all 23 | copies or substantial portions of the Software. 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | SOFTWARE. 32 | -------------------------------------------------------------------------------- /commands/memorize.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | ) 7 | 8 | type MemorizeCommand struct { 9 | options Configuration 10 | } 11 | 12 | // NewMemorizeCommand creates a new command runner for memorize command 13 | func NewMemorizeCommand(config Configuration) *MemorizeCommand { 14 | memorizeCommand := MemorizeCommand{ 15 | options: config, 16 | } 17 | return &memorizeCommand 18 | } 19 | 20 | // Run the memorize command 21 | func (m *MemorizeCommand) Run(ctx context.Context, subcommandArgs []string) error { 22 | params := []string{ 23 | "-C", 24 | m.options.JournalPath, 25 | "add", 26 | ".", 27 | } 28 | 29 | if code := gitCommand(params...); code != 0 { 30 | switch code { 31 | case 128: 32 | break 33 | default: 34 | return errors.New("failed to stage journal entries") 35 | } 36 | } 37 | 38 | params = []string{ 39 | "-C", 40 | m.options.JournalPath, 41 | "commit", 42 | "-am", 43 | "Memorized journal", 44 | } 45 | 46 | if code := gitCommand(params...); code != 0 { 47 | switch code { 48 | case 128: 49 | break 50 | default: 51 | return errors.New("failed to commit journal") 52 | } 53 | } 54 | 55 | params = []string{ 56 | "-C", 57 | m.options.JournalPath, 58 | "push", 59 | "origin", 60 | "master", 61 | } 62 | 63 | if code := gitCommand(params...); code != 0 { 64 | switch code { 65 | case 128: 66 | break 67 | default: 68 | return errors.New("failed to sync journal") 69 | } 70 | } 71 | return nil 72 | } 73 | -------------------------------------------------------------------------------- /commands/image_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "io/ioutil" 7 | "os" 8 | "path/filepath" 9 | "testing" 10 | "time" 11 | 12 | "github.com/cjsaylor/jrnl/commands" 13 | ) 14 | 15 | func TestAppendImage(t *testing.T) { 16 | path, _ := filepath.Abs("../fixtures") 17 | expectedImagePath := fmt.Sprintf("%v/bin/test-pixel.png", path) 18 | expectedEntryPath := fmt.Sprintf("%v/entries/2018-07-01.md", path) 19 | t.Run("appendImage", func(t *testing.T) { 20 | config := commands.Configuration{ 21 | JournalPath: path, 22 | } 23 | cmd := commands.NewImageCommand(config) 24 | ctx := context.WithValue(context.Background(), commands.CommandContextKey("date"), time.Date(2018, time.July, 1, 0, 0, 0, 0, time.UTC)) 25 | if err := cmd.Run(ctx, []string{fmt.Sprintf("%v/%v", path, "test-pixel.png")}); err != nil { 26 | t.Fatal(err) 27 | } 28 | if _, err := os.Stat(expectedImagePath); os.IsNotExist(err) { 29 | t.Errorf("Expected image to be copied to %v", expectedImagePath) 30 | } 31 | if _, err := os.Stat(expectedEntryPath); os.IsNotExist(err) { 32 | t.Errorf("Expected entry to be created at %v", expectedImagePath) 33 | } 34 | entryContent, err := ioutil.ReadFile(expectedEntryPath) 35 | if err != nil { 36 | t.Fatal(err) 37 | } 38 | expectedContent := "\n\n---\n\n![](bin/test-pixel.png)\n" 39 | if string(entryContent) != expectedContent { 40 | t.Errorf("Expected %v, got %v", expectedContent, string(entryContent)) 41 | } 42 | }) 43 | os.RemoveAll(fmt.Sprintf("%v/bin/", path)) 44 | os.Remove(fmt.Sprintf("%v/entries/2018-07-01.md", path)) 45 | } 46 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/caarlos0/env v0.0.0-20170430215205-7110c4e2f569 h1:oy9Vz7le12lsFsBsxlkIwiziGxTZEQ/Fd6swnxXq+Mg= 2 | github.com/caarlos0/env v0.0.0-20170430215205-7110c4e2f569/go.mod h1:tdCsowwCzMLdkqRYDlHpZCp2UooDD3MspDBjZ2AD02Y= 3 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/ericaro/frontmatter v0.0.0-20141225210444-9fedef9406e4 h1:oiAMKnBLTEddU4iszyKbHft09X9tE49oO5SeJ+S3pvw= 5 | github.com/ericaro/frontmatter v0.0.0-20141225210444-9fedef9406e4/go.mod h1:Xy0DdToffIGb/ZMCwM5zFgIQOrVh0cKvNABpKRJYo1w= 6 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 7 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 8 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 9 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 10 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 11 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 12 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 13 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 14 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 15 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 16 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 17 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 18 | -------------------------------------------------------------------------------- /vendor/github.com/ericaro/frontmatter/README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/ericaro/frontmatter.png?branch=master)](https://travis-ci.org/ericaro/ringbuffer) [![GoDoc](https://godoc.org/github.com/ericaro/frontmatter?status.svg)](https://godoc.org/github.com/ericaro/frontmatter) 2 | 3 | # Frontmatter 4 | 5 | frontmatter is a golang package that provides a Marshaler/Unmarshaler for frontmatter files. 6 | 7 | A frontmatter file is a file with any textual content, and a yaml frontmatter block for metadata, 8 | as defined by [Jekyll](http://jekyllrb.com/docs/frontmatter/) 9 | 10 | The frontmatter File must have the following format: 11 | 12 | `---\n` 13 | 14 | `\n---\n` 15 | 16 | 17 | Where, the 'yaml content' is handled by http://gopkg.in/yaml.v2 18 | 19 | And where, the text content is 'content' field's value. 20 | 21 | The 'content' field must: 22 | 23 | exist 24 | tagged `fm:"content"` 25 | be exported 26 | be of the correct type. 27 | 28 | A correct type is: 29 | 30 | - string, *string 31 | - any convertible to the above two. 32 | 33 | see [go doc](https://godoc.org/github.com/ericaro/frontmatter) for details. 34 | 35 | # Installation 36 | 37 | first get [go](http://golang.org) 38 | then `go get github.com/ericaro/frontmatter` 39 | 40 | This package depends on http://gopkg.in/yaml.v2 41 | 42 | # License 43 | 44 | frontmatter is available under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html). 45 | 46 | 47 | # Branches 48 | 49 | 50 | master: [![Build Status](https://travis-ci.org/ericaro/frontmatter.png?branch=master)](https://travis-ci.org/ericaro/frontmatter) against go versions: 51 | 52 | - 1.2 53 | - 1.3 54 | - 1.4 55 | - tip 56 | -------------------------------------------------------------------------------- /commands/find.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "fmt" 7 | "os" 8 | "sort" 9 | "strings" 10 | ) 11 | 12 | type FindCommand struct { 13 | options Configuration 14 | flags *flag.FlagSet 15 | consoleWriter *os.File 16 | } 17 | 18 | type arrayFlags []string 19 | 20 | func (a *arrayFlags) String() string { 21 | return strings.Join(*a, ", ") 22 | } 23 | 24 | func (a *arrayFlags) Set(value string) error { 25 | *a = append(*a, value) 26 | return nil 27 | } 28 | 29 | // NewFindCommand creates a new command runner for finding entries 30 | func NewFindCommand(config Configuration, consoleWriter *os.File) *FindCommand { 31 | findCommand := FindCommand{ 32 | options: config, 33 | flags: flag.NewFlagSet("find", flag.ExitOnError), 34 | consoleWriter: consoleWriter, 35 | } 36 | return &findCommand 37 | } 38 | 39 | // Run the list-tags command 40 | func (f *FindCommand) Run(ctx context.Context, subcommandArgs []string) error { 41 | var tags arrayFlags 42 | f.flags.Var(&tags, "tag", "Find entries of a specific tag or tags.") 43 | if !f.flags.Parsed() { 44 | if err := f.flags.Parse(subcommandArgs); err != nil { 45 | return err 46 | } 47 | } 48 | index, err := tagMap(f.options.JournalPath) 49 | if err != nil { 50 | return err 51 | } 52 | seen := make(map[string]bool) 53 | for _, tag := range tags { 54 | if index[tag] != nil { 55 | for _, entry := range index[tag] { 56 | if !seen[entry] { 57 | seen[entry] = true 58 | } 59 | } 60 | } 61 | } 62 | output := make([]string, 0) 63 | for key := range seen { 64 | output = append(output, fmt.Sprintf("%s/entries/%s.md", f.options.JournalPath, key)) 65 | } 66 | sort.Strings(output) 67 | fmt.Fprintln(f.consoleWriter, strings.Join(output, "\n")) 68 | return nil 69 | } 70 | -------------------------------------------------------------------------------- /commands/open_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "context" 5 | "io/ioutil" 6 | "os" 7 | "path/filepath" 8 | "testing" 9 | "time" 10 | 11 | "github.com/cjsaylor/jrnl/commands" 12 | ) 13 | 14 | type fakeEditor struct { 15 | called map[string][]string 16 | } 17 | 18 | func (f *fakeEditor) OpenEditor(editor string, args ...string) error { 19 | f.called["open_editor"] = append([]string{editor}, args...) 20 | return nil 21 | } 22 | 23 | func TestFileCreatedOnStartup(t *testing.T) { 24 | path, _ := filepath.Abs("../fixtures") 25 | expectedFilePath := path + "/entries/2018-07-28.md" 26 | t.Run("FileCreatedOnStartup", func(t *testing.T) { 27 | config := commands.Configuration{ 28 | JournalPath: path, 29 | JournalEditor: "vim", 30 | } 31 | editor := fakeEditor{ 32 | called: make(map[string][]string), 33 | } 34 | cmd := commands.NewOpenCommand(config, &editor) 35 | ctx := context.WithValue(context.Background(), commands.CommandContextKey("date"), time.Date(2018, time.July, 28, 0, 0, 0, 0, time.UTC)) 36 | if err := cmd.Run(ctx, []string{}); err != nil { 37 | t.Fatal(err) 38 | } 39 | content, err := ioutil.ReadFile(expectedFilePath) 40 | if err != nil { 41 | t.Fatal(err) 42 | } 43 | expectedContent := "---\ndate: Sat Jul 28 2018 00:00:00 +0000 UTC\n---\n" 44 | if string(content) != expectedContent { 45 | t.Errorf("Expected %v, got %v", expectedContent, string(content)) 46 | } 47 | if len(editor.called["open_editor"]) != 2 { 48 | t.Error("Expected OpenEditor to be called properly.") 49 | } 50 | if editor.called["open_editor"][0] != "vim" || editor.called["open_editor"][1] != expectedFilePath { 51 | t.Errorf("Expected editor to be vim, got %v", editor.called["open_editor"][0]) 52 | t.Errorf("Expected file path to be %v, got %v", expectedFilePath, editor.called["open_editor"][1]) 53 | } 54 | }) 55 | os.Remove(expectedFilePath) 56 | } 57 | -------------------------------------------------------------------------------- /commands/image.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "flag" 7 | "fmt" 8 | "io/ioutil" 9 | "os" 10 | "path/filepath" 11 | "time" 12 | ) 13 | 14 | var appendTemplate = "\n\n---\n\n![](bin/%s)\n" 15 | 16 | type ImageCommand struct { 17 | options Configuration 18 | flags *flag.FlagSet 19 | } 20 | 21 | // NewImageCommand creates a new command runner for image command 22 | func NewImageCommand(config Configuration) *ImageCommand { 23 | imageCommand := ImageCommand{ 24 | options: config, 25 | flags: flag.NewFlagSet("image", flag.ExitOnError), 26 | } 27 | return &imageCommand 28 | } 29 | 30 | // Run the image command 31 | func (i *ImageCommand) Run(ctx context.Context, subcommandArgs []string) error { 32 | subjectFlag := i.flags.String("s", "", "Set the subject (this will not use a journal date.") 33 | if !i.flags.Parsed() { 34 | if err := i.flags.Parse(subcommandArgs); err != nil { 35 | return err 36 | } 37 | } 38 | var filebase string 39 | if *subjectFlag != "" { 40 | filebase = *subjectFlag 41 | } else { 42 | filebase = ctx.Value(CommandContextKey("date")).(time.Time).Format("2006-01-02") 43 | } 44 | commandArgs := i.flags.Args() 45 | if len(commandArgs) == 0 { 46 | return errors.New("must provide file path") 47 | } 48 | data, err := ioutil.ReadFile(commandArgs[0]) 49 | if err != nil { 50 | return err 51 | } 52 | os.MkdirAll(i.options.JournalPath+"/bin", os.ModePerm) 53 | err = ioutil.WriteFile(i.options.JournalPath+"/bin/"+filepath.Base(commandArgs[0]), data, 0644) 54 | if err != nil { 55 | return err 56 | } 57 | journalEntry := i.options.JournalPath + "/entries/" + filebase + ".md" 58 | f, err := os.OpenFile(journalEntry, os.O_APPEND|os.O_WRONLY, 0644) 59 | if err != nil { 60 | f, err = os.Create(journalEntry) 61 | } 62 | if err != nil { 63 | return err 64 | } 65 | _, err = f.WriteString(fmt.Sprintf(appendTemplate, filepath.Base(commandArgs[0]))) 66 | return err 67 | } 68 | -------------------------------------------------------------------------------- /vendor/github.com/ericaro/frontmatter/writestring.go: -------------------------------------------------------------------------------- 1 | package frontmatter 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | var ( 8 | stringType = reflect.ValueOf("txt").Type() 9 | ) 10 | 11 | //Read a String out of a field identified by tag/tagvalue pair 12 | func ReadString(v interface{}, tag, tagval string) (txt string, err error) { 13 | fv := findField(v, tag, tagval) //find the field 14 | if fv == nil { //there was no such field, report it as an error 15 | return "", ErrNoContentField 16 | } 17 | //convert to string type () 18 | if !fv.Type().ConvertibleTo(stringType) { 19 | return "", ErrWrongContentFieldType //has the wrong type 20 | } 21 | //conversion has been checked above 22 | txt = fv.Convert(stringType).Interface().(string) 23 | return 24 | 25 | } 26 | 27 | //WriteString set 'txt' on the field tagged with 'tag' 28 | func WriteString(v interface{}, tag, tagval, txt string) error { 29 | fv := findField(v, tag, tagval) 30 | if fv == nil { 31 | return ErrNoContentField 32 | } 33 | 34 | if !fv.CanSet() { 35 | return ErrUnexported 36 | } 37 | 38 | fvt := fv.Type() 39 | //attempt the only two cases: string convertible to field type 40 | // or *string is 41 | switch { 42 | 43 | case reflect.TypeOf(txt).ConvertibleTo(fvt): 44 | fv.Set(reflect.ValueOf(txt).Convert(fvt)) 45 | 46 | case reflect.TypeOf(&txt).ConvertibleTo(fvt): 47 | fv.Set(reflect.ValueOf(&txt).Convert(fvt)) 48 | 49 | default: 50 | return ErrWrongContentFieldType 51 | } 52 | return nil 53 | } 54 | 55 | //findField by tagkey tagvalue pair 56 | func findField(v interface{}, tag, tagval string) *reflect.Value { 57 | 58 | val := reflect.ValueOf(v) 59 | ty := val.Type() 60 | 61 | // if it was a pointer to a struct open the underlying type, instead 62 | if ty.Kind() == reflect.Ptr { 63 | ty = ty.Elem() // the actual underneath type 64 | val = val.Elem() 65 | } 66 | 67 | for i := 0; i < ty.NumField(); i++ { //for each field, (yeah, I know it's a bit gross) 68 | //get the field, and the fields tag 69 | if x := ty.Field(i).Tag.Get(tag); x == tagval { 70 | f := val.Field(i) // get the field value 71 | return &f //and return it 72 | } 73 | } 74 | return nil 75 | } 76 | -------------------------------------------------------------------------------- /commands/open.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "fmt" 7 | "io/ioutil" 8 | "os" 9 | "os/exec" 10 | "strings" 11 | "time" 12 | ) 13 | 14 | type OpenCommand struct { 15 | options Configuration 16 | flags *flag.FlagSet 17 | editorSpawner ExternalEditor 18 | } 19 | 20 | type ExternalEditor interface { 21 | OpenEditor(editor string, args ...string) error 22 | } 23 | 24 | type ExternalEditorImpl struct{} 25 | 26 | func (e *ExternalEditorImpl) OpenEditor(editor string, args ...string) error { 27 | cmd := exec.Command(editor, args...) 28 | cmd.Stdin = os.Stdin 29 | cmd.Stdout = os.Stdout 30 | return cmd.Run() 31 | } 32 | 33 | // NewOpenCommand creates a new command runner for open command 34 | func NewOpenCommand(config Configuration, editorSpawner ExternalEditor) *OpenCommand { 35 | openCommand := OpenCommand{ 36 | options: config, 37 | flags: flag.NewFlagSet("open", flag.ExitOnError), 38 | editorSpawner: editorSpawner, 39 | } 40 | return &openCommand 41 | } 42 | 43 | func generateFrontmatter(ctx context.Context) ([]byte, error) { 44 | entry := entryHeader{ 45 | Date: ctx.Value(CommandContextKey("date")).(time.Time), 46 | } 47 | return entry.MarshalFrontmatter() 48 | } 49 | 50 | // Run the open command 51 | func (o *OpenCommand) Run(ctx context.Context, subcommandArgs []string) error { 52 | subjectFlag := o.flags.String("s", "", "Set the subject (this will not use a journal date.") 53 | if !o.flags.Parsed() { 54 | if err := o.flags.Parse(subcommandArgs); err != nil { 55 | return err 56 | } 57 | } 58 | var filename string 59 | if *subjectFlag != "" { 60 | filename = *subjectFlag 61 | } else { 62 | filename = ctx.Value(CommandContextKey("date")).(time.Time).Format("2006-01-02") 63 | } 64 | var options []string 65 | if editorOptions := o.options.JournalEditorOptions; editorOptions != "" { 66 | options = strings.Split(editorOptions, " ") 67 | } 68 | filePath := fmt.Sprintf("%s/entries/%s.md", o.options.JournalPath, filename) 69 | options = append(options, filePath) 70 | os.MkdirAll(o.options.JournalPath+"/entries", os.ModePerm) 71 | if _, err := os.Stat(filePath); os.IsNotExist(err) { 72 | content, err := generateFrontmatter(ctx) 73 | if err != nil { 74 | return err 75 | } 76 | if err := ioutil.WriteFile(filePath, content, 0644); err != nil { 77 | return err 78 | } 79 | } 80 | 81 | return o.editorSpawner.OpenEditor(o.options.JournalEditor, options...) 82 | } 83 | -------------------------------------------------------------------------------- /commands/common.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "context" 5 | "io/ioutil" 6 | "os/exec" 7 | "path" 8 | "syscall" 9 | "time" 10 | 11 | "github.com/ericaro/frontmatter" 12 | ) 13 | 14 | // CommandRunner is an interface for runnable commands 15 | type CommandRunner interface { 16 | Run(context.Context, []string) error 17 | } 18 | 19 | // CommandContextKey is a context key specific to commands package 20 | type CommandContextKey string 21 | 22 | func gitCommand(params ...string) int { 23 | cmd := exec.Command("git", params...) 24 | if err := cmd.Run(); err != nil { 25 | if exiterr, ok := err.(*exec.ExitError); ok { 26 | if status, ok := exiterr.Sys().(syscall.WaitStatus); ok { 27 | return status.ExitStatus() 28 | } 29 | } 30 | } 31 | return 0 32 | } 33 | 34 | const JournalTimeformat = "Mon Jan 2 2006 15:04:05 -0700 MST" 35 | 36 | type entryHeader struct { 37 | Filepath string `yaml:"-"` 38 | Filename string `yaml:"-"` 39 | Tags []string `yaml:"tags,omitempty"` 40 | Date time.Time `yaml:"date,omitempty"` 41 | Content string `fm:"content" yaml:"-"` 42 | } 43 | 44 | func (e *entryHeader) MarshalFrontmatter() ([]byte, error) { 45 | return frontmatter.Marshal(&struct { 46 | Tags []string `yaml:"tags,omitempty"` 47 | Date string `yaml:"date"` 48 | Content string `fm:"content" yaml:"-"` 49 | }{ 50 | Tags: e.Tags, 51 | Date: e.Date.Format(JournalTimeformat), 52 | Content: e.Content, 53 | }) 54 | } 55 | 56 | func unmarshalFrontmatter(input []byte) (*entryHeader, error) { 57 | type rawHeader struct { 58 | Tags []string `yaml:"tags,omitempty"` 59 | Date string `yaml:"date,omitempty"` 60 | Content string `fm:"content" yaml:"-"` 61 | } 62 | raw := new(rawHeader) 63 | frontmatter.Unmarshal(input, raw) 64 | var date time.Time 65 | var err error 66 | if raw.Date != "" { 67 | date, err = time.Parse(JournalTimeformat, raw.Date) 68 | if err != nil { 69 | return nil, err 70 | } 71 | } 72 | return &entryHeader{ 73 | Tags: raw.Tags, 74 | Date: date, 75 | Content: raw.Content, 76 | }, nil 77 | } 78 | 79 | type frontmatterResult struct { 80 | header *entryHeader 81 | err error 82 | } 83 | 84 | func readFrontmatter(filePath string, results chan<- frontmatterResult) { 85 | content, err := ioutil.ReadFile(filePath) 86 | if err != nil { 87 | results <- frontmatterResult{ 88 | header: nil, 89 | err: err, 90 | } 91 | return 92 | } 93 | head, err := unmarshalFrontmatter(content) 94 | head.Filepath = filePath 95 | head.Filename = path.Base(filePath) 96 | results <- frontmatterResult{ 97 | header: head, 98 | err: err, 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /commands/index.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "fmt" 7 | "io/ioutil" 8 | "path" 9 | "sort" 10 | "strings" 11 | "sync" 12 | ) 13 | 14 | type IndexCommand struct { 15 | options Configuration 16 | flags *flag.FlagSet 17 | } 18 | 19 | func tagMap(journalPath string) (map[string][]string, error) { 20 | directory := journalPath + "/entries" 21 | files, err := ioutil.ReadDir(directory) 22 | if err != nil { 23 | return nil, err 24 | } 25 | index := make(map[string][]string) 26 | results := make(chan frontmatterResult, len(files)) 27 | var wg sync.WaitGroup 28 | for _, file := range files { 29 | wg.Add(1) 30 | go func(filePath string) { 31 | defer wg.Done() 32 | readFrontmatter(filePath, results) 33 | }(fmt.Sprintf("%s/%s", directory, file.Name())) 34 | } 35 | wg.Wait() 36 | close(results) 37 | for result := range results { 38 | if result.err != nil { 39 | return nil, result.err 40 | } 41 | for _, tag := range result.header.Tags { 42 | index[tag] = append(index[tag], strings.TrimSuffix(result.header.Filename, ".md")) 43 | } 44 | } 45 | for tag := range index { 46 | sort.Strings(index[tag]) 47 | } 48 | return index, nil 49 | } 50 | 51 | func sortedTagKeys(index map[string][]string) []string { 52 | keys := make([]string, 0, len(index)) 53 | for key := range index { 54 | keys = append(keys, key) 55 | } 56 | sort.Strings(keys) 57 | return keys 58 | } 59 | 60 | // NewIndexCommand creates a new command runner for index command 61 | func NewIndexCommand(config Configuration) *IndexCommand { 62 | indexCommand := IndexCommand{ 63 | options: config, 64 | flags: flag.NewFlagSet("index", flag.ExitOnError), 65 | } 66 | return &indexCommand 67 | } 68 | 69 | // Run the index command 70 | func (i *IndexCommand) Run(ctx context.Context, subcommandArgs []string) error { 71 | outputPath := i.flags.String("o", "Index.md", "Output path contained to the $JOURNAL_PATH.") 72 | if !i.flags.Parsed() { 73 | if err := i.flags.Parse(subcommandArgs); err != nil { 74 | return err 75 | } 76 | } 77 | if *outputPath == "." { 78 | *outputPath = "Index.md" 79 | } 80 | index, err := tagMap(i.options.JournalPath) 81 | if err != nil { 82 | return err 83 | } 84 | keys := sortedTagKeys(index) 85 | var newIndex string 86 | for _, tag := range keys { 87 | newIndex += fmt.Sprintf("\n* *%s* ", tag) 88 | mappedEntries := make([]string, len(index[tag])) 89 | mapper := func(entry string) string { 90 | return fmt.Sprintf("[%s](%s)", entry, entry) 91 | } 92 | for i, entry := range index[tag] { 93 | mappedEntries[i] = mapper(entry) 94 | } 95 | newIndex += strings.Join(mappedEntries, ", ") 96 | } 97 | indexPath := fmt.Sprintf("%s/%s", i.options.JournalPath, path.Base(*outputPath)) 98 | return ioutil.WriteFile(indexPath, []byte(newIndex), 0644) 99 | } 100 | -------------------------------------------------------------------------------- /commands/tag.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "fmt" 7 | "io/ioutil" 8 | "os" 9 | "sort" 10 | "sync" 11 | "time" 12 | ) 13 | 14 | type TagCommand struct { 15 | options Configuration 16 | flags *flag.FlagSet 17 | } 18 | 19 | // NewTagCommand creates a new command runner for tagging entries 20 | func NewTagCommand(config Configuration) *TagCommand { 21 | tagCommand := TagCommand{ 22 | options: config, 23 | flags: flag.NewFlagSet("tag", flag.ExitOnError), 24 | } 25 | return &tagCommand 26 | } 27 | 28 | // Run the tag command 29 | func (t *TagCommand) Run(ctx context.Context, subcommandArgs []string) error { 30 | var files arrayFlags 31 | var subjects arrayFlags 32 | var tags arrayFlags 33 | var dates arrayFlags 34 | t.flags.Var(&files, "f", "File path of document to tag") 35 | t.flags.Var(&subjects, "s", "Subject(s) entries to tag") 36 | t.flags.Var(&dates, "d", "Specify the date(s) of entry.") 37 | t.flags.Var(&tags, "t", "Tag or tags to append to specified files, subjects, or dates") 38 | if !t.flags.Parsed() { 39 | if err := t.flags.Parse(subcommandArgs); err != nil { 40 | return err 41 | } 42 | } 43 | var fileEntries []string 44 | for _, file := range files { 45 | fileEntries = append(fileEntries, file) 46 | } 47 | for _, subject := range subjects { 48 | fileEntries = append(fileEntries, fmt.Sprintf("%s/entries/%s.md", t.options.JournalPath, subject)) 49 | } 50 | for _, date := range dates { 51 | parsedDate, err := time.Parse("2006-01-02", date) 52 | if err != nil { 53 | return err 54 | } 55 | fileEntries = append(fileEntries, fmt.Sprintf("%s/entries/%s.md", t.options.JournalPath, parsedDate.String())) 56 | } 57 | if len(fileEntries) == 0 { 58 | toCreate := fmt.Sprintf("%s/entries/%s.md", t.options.JournalPath, ctx.Value(CommandContextKey("date")).(time.Time).Format("2006-01-02")) 59 | os.OpenFile(toCreate, os.O_RDONLY|os.O_CREATE, 0644) 60 | fileEntries = append(fileEntries, toCreate) 61 | } 62 | var wg sync.WaitGroup 63 | results := make(chan frontmatterResult, len(fileEntries)) 64 | for _, file := range fileEntries { 65 | wg.Add(1) 66 | go func(filePath string) { 67 | defer wg.Done() 68 | readFrontmatter(filePath, results) 69 | }(file) 70 | } 71 | wg.Wait() 72 | close(results) 73 | // @todo Make this async for performance after certain len() 74 | for result := range results { 75 | if result.err != nil { 76 | return result.err 77 | } 78 | result.header.Tags = dedupe(append(result.header.Tags, tags...)) 79 | sort.Strings(result.header.Tags) 80 | output, err := result.header.MarshalFrontmatter() 81 | if err != nil { 82 | return err 83 | } 84 | err = ioutil.WriteFile(result.header.Filepath, output, 0644) 85 | if err != nil { 86 | return err 87 | } 88 | } 89 | return nil 90 | } 91 | 92 | func dedupe(subject []string) []string { 93 | encountered := make(map[string]struct{}) 94 | results := []string{} 95 | for _, str := range subject { 96 | if _, ok := encountered[str]; !ok { 97 | results = append(results, str) 98 | encountered[str] = struct{}{} 99 | } 100 | } 101 | return results 102 | } 103 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v2/sorter.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | import ( 4 | "reflect" 5 | "unicode" 6 | ) 7 | 8 | type keyList []reflect.Value 9 | 10 | func (l keyList) Len() int { return len(l) } 11 | func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } 12 | func (l keyList) Less(i, j int) bool { 13 | a := l[i] 14 | b := l[j] 15 | ak := a.Kind() 16 | bk := b.Kind() 17 | for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() { 18 | a = a.Elem() 19 | ak = a.Kind() 20 | } 21 | for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() { 22 | b = b.Elem() 23 | bk = b.Kind() 24 | } 25 | af, aok := keyFloat(a) 26 | bf, bok := keyFloat(b) 27 | if aok && bok { 28 | if af != bf { 29 | return af < bf 30 | } 31 | if ak != bk { 32 | return ak < bk 33 | } 34 | return numLess(a, b) 35 | } 36 | if ak != reflect.String || bk != reflect.String { 37 | return ak < bk 38 | } 39 | ar, br := []rune(a.String()), []rune(b.String()) 40 | for i := 0; i < len(ar) && i < len(br); i++ { 41 | if ar[i] == br[i] { 42 | continue 43 | } 44 | al := unicode.IsLetter(ar[i]) 45 | bl := unicode.IsLetter(br[i]) 46 | if al && bl { 47 | return ar[i] < br[i] 48 | } 49 | if al || bl { 50 | return bl 51 | } 52 | var ai, bi int 53 | var an, bn int64 54 | if ar[i] == '0' || br[i] == '0' { 55 | for j := i-1; j >= 0 && unicode.IsDigit(ar[j]); j-- { 56 | if ar[j] != '0' { 57 | an = 1 58 | bn = 1 59 | break 60 | } 61 | } 62 | } 63 | for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ { 64 | an = an*10 + int64(ar[ai]-'0') 65 | } 66 | for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ { 67 | bn = bn*10 + int64(br[bi]-'0') 68 | } 69 | if an != bn { 70 | return an < bn 71 | } 72 | if ai != bi { 73 | return ai < bi 74 | } 75 | return ar[i] < br[i] 76 | } 77 | return len(ar) < len(br) 78 | } 79 | 80 | // keyFloat returns a float value for v if it is a number/bool 81 | // and whether it is a number/bool or not. 82 | func keyFloat(v reflect.Value) (f float64, ok bool) { 83 | switch v.Kind() { 84 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 85 | return float64(v.Int()), true 86 | case reflect.Float32, reflect.Float64: 87 | return v.Float(), true 88 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 89 | return float64(v.Uint()), true 90 | case reflect.Bool: 91 | if v.Bool() { 92 | return 1, true 93 | } 94 | return 0, true 95 | } 96 | return 0, false 97 | } 98 | 99 | // numLess returns whether a < b. 100 | // a and b must necessarily have the same kind. 101 | func numLess(a, b reflect.Value) bool { 102 | switch a.Kind() { 103 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 104 | return a.Int() < b.Int() 105 | case reflect.Float32, reflect.Float64: 106 | return a.Float() < b.Float() 107 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 108 | return a.Uint() < b.Uint() 109 | case reflect.Bool: 110 | return !a.Bool() && b.Bool() 111 | } 112 | panic("not a number") 113 | } 114 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v2/README.md: -------------------------------------------------------------------------------- 1 | # YAML support for the Go language 2 | 3 | Introduction 4 | ------------ 5 | 6 | The yaml package enables Go programs to comfortably encode and decode YAML 7 | values. It was developed within [Canonical](https://www.canonical.com) as 8 | part of the [juju](https://juju.ubuntu.com) project, and is based on a 9 | pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML) 10 | C library to parse and generate YAML data quickly and reliably. 11 | 12 | Compatibility 13 | ------------- 14 | 15 | The yaml package supports most of YAML 1.1 and 1.2, including support for 16 | anchors, tags, map merging, etc. Multi-document unmarshalling is not yet 17 | implemented, and base-60 floats from YAML 1.1 are purposefully not 18 | supported since they're a poor design and are gone in YAML 1.2. 19 | 20 | Installation and usage 21 | ---------------------- 22 | 23 | The import path for the package is *gopkg.in/yaml.v2*. 24 | 25 | To install it, run: 26 | 27 | go get gopkg.in/yaml.v2 28 | 29 | API documentation 30 | ----------------- 31 | 32 | If opened in a browser, the import path itself leads to the API documentation: 33 | 34 | * [https://gopkg.in/yaml.v2](https://gopkg.in/yaml.v2) 35 | 36 | API stability 37 | ------------- 38 | 39 | The package API for yaml v2 will remain stable as described in [gopkg.in](https://gopkg.in). 40 | 41 | 42 | License 43 | ------- 44 | 45 | The yaml package is licensed under the Apache License 2.0. Please see the LICENSE file for details. 46 | 47 | 48 | Example 49 | ------- 50 | 51 | ```Go 52 | package main 53 | 54 | import ( 55 | "fmt" 56 | "log" 57 | 58 | "gopkg.in/yaml.v2" 59 | ) 60 | 61 | var data = ` 62 | a: Easy! 63 | b: 64 | c: 2 65 | d: [3, 4] 66 | ` 67 | 68 | // Note: struct fields must be public in order for unmarshal to 69 | // correctly populate the data. 70 | type T struct { 71 | A string 72 | B struct { 73 | RenamedC int `yaml:"c"` 74 | D []int `yaml:",flow"` 75 | } 76 | } 77 | 78 | func main() { 79 | t := T{} 80 | 81 | err := yaml.Unmarshal([]byte(data), &t) 82 | if err != nil { 83 | log.Fatalf("error: %v", err) 84 | } 85 | fmt.Printf("--- t:\n%v\n\n", t) 86 | 87 | d, err := yaml.Marshal(&t) 88 | if err != nil { 89 | log.Fatalf("error: %v", err) 90 | } 91 | fmt.Printf("--- t dump:\n%s\n\n", string(d)) 92 | 93 | m := make(map[interface{}]interface{}) 94 | 95 | err = yaml.Unmarshal([]byte(data), &m) 96 | if err != nil { 97 | log.Fatalf("error: %v", err) 98 | } 99 | fmt.Printf("--- m:\n%v\n\n", m) 100 | 101 | d, err = yaml.Marshal(&m) 102 | if err != nil { 103 | log.Fatalf("error: %v", err) 104 | } 105 | fmt.Printf("--- m dump:\n%s\n\n", string(d)) 106 | } 107 | ``` 108 | 109 | This example will generate the following output: 110 | 111 | ``` 112 | --- t: 113 | {Easy! {2 [3 4]}} 114 | 115 | --- t dump: 116 | a: Easy! 117 | b: 118 | c: 2 119 | d: [3, 4] 120 | 121 | 122 | --- m: 123 | map[a:Easy! b:map[c:2 d:[3 4]]] 124 | 125 | --- m dump: 126 | a: Easy! 127 | b: 128 | c: 2 129 | d: 130 | - 3 131 | - 4 132 | ``` 133 | 134 | -------------------------------------------------------------------------------- /cmd/jrnl/main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "testing" 7 | "time" 8 | ) 9 | 10 | var location *time.Location 11 | 12 | func init() { 13 | location, _ = time.LoadLocation("UTC") 14 | now = time.Date(2018, time.August, 1, 13, 24, 15, 0, location) 15 | } 16 | 17 | func TestParseDate(t *testing.T) { 18 | dateTests := []struct { 19 | input string 20 | output time.Time 21 | expectsError bool 22 | }{ 23 | {"2018-02-28", time.Date(2018, time.February, 28, 13, 24, 15, 0, location), false}, 24 | {"2018-12-31", time.Date(2018, time.December, 31, 13, 24, 15, 0, location), false}, 25 | {"2018-02-31", now, true}, 26 | {"random text", now, true}, 27 | } 28 | for _, testInput := range dateTests { 29 | t.Run(testInput.input, func(t *testing.T) { 30 | output, err := ParseDate(testInput.input) 31 | if err != nil && !testInput.expectsError { 32 | t.Fatal(err) 33 | } else if err == nil && testInput.expectsError { 34 | t.Error("Expected input to produce an error") 35 | } else if err != nil && testInput.expectsError { 36 | return 37 | } 38 | if err != nil && !testInput.expectsError { 39 | t.Fatal(err) 40 | } 41 | if err == nil && testInput.expectsError { 42 | t.Error("Expected input to produce an error") 43 | } else if err != nil && testInput.expectsError { 44 | return 45 | } 46 | if output != testInput.output { 47 | t.Errorf("expected %v, got %v", testInput.output, output) 48 | } 49 | }) 50 | } 51 | } 52 | 53 | func TestLongestStringLength(t *testing.T) { 54 | inputs := []struct { 55 | input []string 56 | expected int 57 | }{ 58 | {[]string{"a", "aa", "abc", "bb"}, 3}, 59 | {[]string{"", ""}, 0}, 60 | {[]string{"12345678901234567890", "12345678901234567890"}, 20}, 61 | } 62 | for _, input := range inputs { 63 | t.Run(fmt.Sprint(input.input), func(t *testing.T) { 64 | output := LongestStringLength(input.input) 65 | if output != input.expected { 66 | t.Errorf("expected %v, got %v", input.expected, output) 67 | } 68 | }) 69 | } 70 | } 71 | 72 | func getType(input interface{}) string { 73 | if t := reflect.TypeOf(input); t.Kind() == reflect.Ptr { 74 | return "*" + t.Elem().Name() 75 | } else { 76 | return t.Name() 77 | } 78 | } 79 | 80 | func TestFromCommandName(t *testing.T) { 81 | inputs := []struct { 82 | input string 83 | expected string 84 | expectsError bool 85 | }{ 86 | {"open", "*OpenCommand", false}, 87 | {"memorize", "*MemorizeCommand", false}, 88 | {"sync", "*SyncCommand", false}, 89 | {"index", "*IndexCommand", false}, 90 | {"image", "*ImageCommand", false}, 91 | {"list-tags", "*ListTagsCommand", false}, 92 | {"find", "*FindCommand", false}, 93 | {"tag", "*TagCommand", false}, 94 | {"Unknown", "", true}, 95 | } 96 | 97 | for _, input := range inputs { 98 | t.Run(input.input, func(t *testing.T) { 99 | output, err := FromCommandName(input.input) 100 | if err != nil && !input.expectsError { 101 | t.Fatal(err) 102 | } else if err == nil && input.expectsError { 103 | t.Error("Expected input to produce an error") 104 | } else if err != nil && input.expectsError { 105 | return 106 | } 107 | outputName := getType(output) 108 | if outputName != input.expected { 109 | t.Errorf("expected %v, got %v", input.expected, outputName) 110 | } 111 | }) 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /vendor/github.com/caarlos0/env/README.md: -------------------------------------------------------------------------------- 1 | # env [![Build Status](https://travis-ci.org/caarlos0/env.svg?branch=master)](https://travis-ci.org/caarlos0/env) [![Coverage Status](https://coveralls.io/repos/caarlos0/env/badge.svg?branch=master&service=github)](https://coveralls.io/github/caarlos0/env?branch=master) [![](https://godoc.org/github.com/caarlos0/env?status.svg)](http://godoc.org/github.com/caarlos0/env) [![](http://goreportcard.com/badge/caarlos0/env)](http://goreportcard.com/report/caarlos0/env) [![SayThanks.io](https://img.shields.io/badge/SayThanks.io-%E2%98%BC-1EAEDB.svg?style=flat-square)](https://saythanks.io/to/caarlos0) 2 | 3 | A KISS way to deal with environment variables in Go. 4 | 5 | ## Why 6 | 7 | At first, it was boring for me to write down an entire function just to 8 | get some `var` from the environment and default to another in case it's missing. 9 | 10 | For that manner, I wrote a `GetOr` function in the 11 | [go-idioms](https://github.com/caarlos0/go-idioms) project. 12 | 13 | Then, I got pissed about writing `os.Getenv`, `os.Setenv`, `os.Unsetenv`... 14 | it kind of make more sense to me write it as `env.Get`, `env.Set`, `env.Unset`. 15 | So I did. 16 | 17 | Then I got a better idea: to use `struct` tags to do all that work for me. 18 | 19 | ## Example 20 | 21 | A very basic example (check the `examples` folder): 22 | 23 | ```go 24 | package main 25 | 26 | import ( 27 | "fmt" 28 | "time" 29 | 30 | "github.com/caarlos0/env" 31 | ) 32 | 33 | type config struct { 34 | Home string `env:"HOME"` 35 | Port int `env:"PORT" envDefault:"3000"` 36 | IsProduction bool `env:"PRODUCTION"` 37 | Hosts []string `env:"HOSTS" envSeparator:":"` 38 | Duration time.Duration `env:"DURATION"` 39 | } 40 | 41 | func main() { 42 | cfg := config{} 43 | err := env.Parse(&cfg) 44 | if err != nil { 45 | fmt.Printf("%+v\n", err) 46 | } 47 | fmt.Printf("%+v\n", cfg) 48 | } 49 | ``` 50 | 51 | You can run it like this: 52 | 53 | ```sh 54 | $ PRODUCTION=true HOSTS="host1:host2:host3" DURATION=1s go run examples/first.go 55 | {Home:/your/home Port:3000 IsProduction:true Hosts:[host1 host2 host3] Duration:1s} 56 | ``` 57 | 58 | ## Supported types and defaults 59 | 60 | The library has support for the following types: 61 | 62 | * `string` 63 | * `int` 64 | * `int64` 65 | * `bool` 66 | * `float32` 67 | * `float64` 68 | * `[]string` 69 | * `[]int` 70 | * `[]bool` 71 | * `[]float32` 72 | * `[]float64` 73 | 74 | If you set the `envDefault` tag for something, this value will be used in the 75 | case of absence of it in the environment. If you don't do that AND the 76 | environment variable is also not set, the zero-value 77 | of the type will be used: empty for `string`s, `false` for `bool`s 78 | and `0` for `int`s. 79 | 80 | By default, slice types will split the environment value on `,`; you can change this behavior by setting the `envSeparator` tag. 81 | 82 | ## Required fields 83 | 84 | The `env` tag option `required` (e.g., `env:"tagKey,required"`) can be added 85 | to ensure that some environment variable is set. In the example above, 86 | an error is returned if the `config` struct is changed to: 87 | 88 | 89 | ```go 90 | type config struct { 91 | Home string `env:"HOME"` 92 | Port int `env:"PORT" envDefault:"3000"` 93 | IsProduction bool `env:"PRODUCTION"` 94 | Hosts []string `env:"HOSTS" envSeparator:":"` 95 | SecretKey string `env:"SECRET_KEY,required"` 96 | } 97 | ``` 98 | -------------------------------------------------------------------------------- /vendor/github.com/ericaro/frontmatter/frontmatter.go: -------------------------------------------------------------------------------- 1 | //package frontmatter provide a Marshaler/Unmarshaler for frontmatter files. 2 | // 3 | // A frontmatter file is a file with any textual content, and a yaml frontmatter block for metadata, 4 | // as defined by Jekyll http://jekyllrb.com/docs/frontmatter/ 5 | // 6 | // The frontmatter File must have the following format: 7 | // 8 | // `---\n` 9 | // 10 | // `\n---\n` 11 | // 12 | // 13 | // Where, the 'yaml content' is handled by http://gopkg.in/yaml.v2 14 | // 15 | // And where, the text content is 'content' field's value. 16 | // 17 | // The 'content' field must: 18 | // 19 | // exist 20 | // tagged `fm:"content"` 21 | // be exported 22 | // be of the correct type. 23 | // 24 | // A correct type is: 25 | // 26 | // - string, *string 27 | // - any convertible to the above two. 28 | // 29 | // See example for details. 30 | // 31 | package frontmatter 32 | 33 | import ( 34 | "errors" 35 | yaml "gopkg.in/yaml.v2" 36 | "strings" 37 | ) 38 | 39 | const ( 40 | Tag = "fm" //Tag used to find the content field 41 | Content = "content" // value used to identify the content field 42 | Header = "---\n" // front matter file header 43 | Separator = "\n---\n" // front matter metadata/content separator 44 | ) 45 | 46 | var ( 47 | ErrMissingSeparator = errors.New("found a heading '---' without separator '---'") 48 | ErrUnexported = errors.New("cannot set an unexported content field") 49 | ErrNoContentField = errors.New("missing content field") 50 | ErrWrongContentFieldType = errors.New("No content field with the right type") 51 | ) 52 | 53 | //Marshal any object. 54 | func Marshal(v interface{}) ([]byte, error) { 55 | //first delegate the metadata marshalling, and errors are reported 56 | yamlBytes, yerr := yaml.Marshal(v) 57 | if yerr != nil { 58 | return nil, yerr 59 | } 60 | // the do the frontmatter reading 61 | content, cerr := ReadString(v, Tag, Content) 62 | if cerr != nil { 63 | return nil, cerr 64 | } 65 | // we trim space (useless in yaml) to have a more stable output format 66 | yamlContent := strings.TrimSpace(string(yamlBytes)) 67 | //the result is just a simple join 68 | result := strings.Join([]string{Header, yamlContent, Separator, content}, "") 69 | return ([]byte)(result), nil 70 | } 71 | 72 | //Unmarshal any object from 'data'. 73 | func Unmarshal(data []byte, v interface{}) (err error) { 74 | //always working as string 75 | txt := string(data) 76 | 77 | content := txt //by default 78 | 79 | if strings.HasPrefix(txt, Header) { // there is a header, therefore there MUST be a front matter 80 | 81 | //we remove the prefix 82 | txt = strings.TrimPrefix(txt, Header) 83 | // nice trick: we split using the separator 84 | // and we hope the get: metadata (valid yaml) and the content 85 | // all the rest is check 86 | splitted := strings.SplitN(txt, Separator, 2) 87 | 88 | if len(splitted) != 2 { 89 | return ErrMissingSeparator 90 | } 91 | 92 | metadata := splitted[0] 93 | // now this is supposed to be a valid yaml. 94 | yamlerr := yaml.Unmarshal(([]byte)(metadata), v) 95 | if yamlerr != nil { 96 | //there have been a yaml error, we report it, but we don't fail 97 | err = yamlerr 98 | } else { 99 | // on success we only keep the content 100 | // because the metadata content is assumed to have been read (and therefore not lost) 101 | // on error, the metadata content would be lost 102 | content = splitted[1] 103 | } 104 | } 105 | contenterr := WriteString(v, Tag, Content, content) 106 | if contenterr != nil { 107 | err = contenterr 108 | } 109 | return 110 | } 111 | -------------------------------------------------------------------------------- /cmd/jrnl/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "flag" 7 | "fmt" 8 | "os" 9 | "sort" 10 | "strings" 11 | "time" 12 | 13 | "github.com/caarlos0/env" 14 | "github.com/cjsaylor/jrnl/commands" 15 | ) 16 | 17 | var config commands.Configuration 18 | 19 | var availableCommands = map[string]string{ 20 | "open": "Open a journal entry in configured editor.", 21 | "memorize": "Commit all journal entries.", 22 | "sync": "Syncronize journal entries from source.", 23 | "index": "Write index file based on frontmatter tags.", 24 | "image": "Append an image to the current journal entry.", 25 | "list-tags": "List all tags used in journal entries.", 26 | "find": "Find journal entries.", 27 | "tag": "Append a tag or tags to journal entries.", 28 | } 29 | 30 | var version = "dev" 31 | var now time.Time 32 | 33 | func LongestStringLength(strings []string) int { 34 | length := 0 35 | for _, v := range strings { 36 | if len(v) > length { 37 | length = len(v) 38 | } 39 | } 40 | return length 41 | } 42 | 43 | func init() { 44 | config = commands.Configuration{} 45 | env.Parse(&config) 46 | if config.JournalPath == "" { 47 | config.JournalPath = os.Getenv("HOME") + "/journal.wiki" 48 | } 49 | flag.Usage = func() { 50 | fmt.Fprintf(os.Stderr, "Usage: jrnl [options...] [command]\n\n") 51 | fmt.Fprintf(os.Stderr, "Commands:\n\n") 52 | var keys []string 53 | for key := range availableCommands { 54 | keys = append(keys, key) 55 | } 56 | maxLength := LongestStringLength(keys) 57 | sort.Strings(keys) 58 | for _, command := range keys { 59 | keyPadding := strings.Repeat(" ", maxLength+1) 60 | fmt.Fprintf(os.Stderr, "%s %s\n", command+keyPadding[len(command):], availableCommands[command]) 61 | } 62 | fmt.Fprintf(os.Stderr, "\nOptions:\n") 63 | flag.PrintDefaults() 64 | } 65 | now = time.Now() 66 | } 67 | 68 | func FromCommandName(name string) (commands.CommandRunner, error) { 69 | switch name { 70 | case "open": 71 | return commands.NewOpenCommand( 72 | config, 73 | &commands.ExternalEditorImpl{}), nil 74 | case "memorize": 75 | return commands.NewMemorizeCommand(config), nil 76 | case "sync": 77 | return commands.NewSyncCommand( 78 | config, 79 | &commands.GitCommandRunnerImpl{}), nil 80 | case "index": 81 | return commands.NewIndexCommand(config), nil 82 | case "image": 83 | return commands.NewImageCommand(config), nil 84 | case "list-tags": 85 | return commands.NewListTagsCommand(config), nil 86 | case "find": 87 | return commands.NewFindCommand(config, os.Stdout), nil 88 | case "tag": 89 | return commands.NewTagCommand(config), nil 90 | default: 91 | return nil, errors.New("Command not found") 92 | } 93 | } 94 | 95 | func ParseDate(input string) (time.Time, error) { 96 | return time.ParseInLocation( 97 | "2006-01-02 15:04:05", 98 | fmt.Sprintf("%v %v", input, now.Format("15:04:05")), 99 | now.Location()) 100 | } 101 | 102 | func main() { 103 | dateInput := flag.String("date", now.Format("2006-01-02"), "Specify the date of entry.") 104 | versionRequested := flag.Bool("version", false, "Prints the current version.") 105 | flag.Parse() 106 | 107 | if *versionRequested { 108 | fmt.Println(version) 109 | os.Exit(0) 110 | } 111 | parsedDate, err := ParseDate(*dateInput) 112 | if err != nil { 113 | fmt.Fprintf(os.Stderr, "Unable to parse date: %v. Must be in form of YYYY-mm-dd", *dateInput) 114 | os.Exit(1) 115 | } 116 | 117 | ctx := context.WithValue(context.Background(), commands.CommandContextKey("date"), parsedDate) 118 | 119 | commandArgs := flag.Args() 120 | var command string 121 | if len(commandArgs) < 1 { 122 | command = "open" 123 | } else { 124 | command = commandArgs[0] 125 | commandArgs = commandArgs[1:] 126 | } 127 | cmd, err := FromCommandName(command) 128 | if err != nil { 129 | fmt.Fprintln(os.Stderr, err) 130 | os.Exit(1) 131 | } 132 | if err := cmd.Run(ctx, commandArgs); err != nil { 133 | fmt.Fprintf(os.Stderr, "%v error: %v.\n", command, err) 134 | os.Exit(2) 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jrnl [![Test Application Status](https://github.com/cjsaylor/jrnl/workflows/Test%20Application/badge.svg)](https://github.com/cjsaylor/jrnl/actions) 2 | 3 | A quick and easy CLI journaling tool that uses Github Wiki repos for organizing journal entries. 4 | 5 | ![](jrnl.gif) 6 | --- 7 | 8 | [View an example wiki journal](https://github.com/cjsaylor/jrnl/wiki) 9 | 10 | --- 11 | 12 | [![GoDoc](https://godoc.org/github.com/cjsaylor/jrnl?status.svg)](https://godoc.org/github.com/cjsaylor/jrnl) 13 | 14 | * [Requirements](#requirements) 15 | * [Installation](#installation) 16 | * [Quick Start](#quick-start) 17 | * [Options](#options) 18 | * [Commands](#commands) 19 | * [Tag Journal Entries](#tag) 20 | * [Generate Index](#index) 21 | * [Append Images](#append-an-image) 22 | * [Tips & Tricks](#tips--tricks) 23 | * [Use `find` command to create a book](#use-find-command-to-create-a-book) 24 | * [Use `find` and `tag` commands to add a common tag](#use-find-and-tag-commands-to-add-a-common-tag) 25 | * [Development](#development) 26 | 27 | ## Requirements 28 | 29 | * Git 30 | * Github account (and access to a repo for the wiki) 31 | 32 | ## Installation 33 | 34 | ### MacOS 35 | 36 | ```bash 37 | brew install cjsaylor/tap/jrnl 38 | ``` 39 | 40 | ### Windows & Linux 41 | 42 | Download the binary from the [latest release](https://github.com/cjsaylor/jrnl/releases/latest) 43 | 44 | ### Compiling from source 45 | 46 | ```bash 47 | go get -u github.com/cjsaylor/jrnl/cmd/jrnl 48 | ``` 49 | 50 | ## Quick start 51 | 52 | [Install `jrnl`](#installation) 53 | 54 | ```bash 55 | go get -u github.com/cjsaylor/jrnl/cmd/jrnl 56 | ``` 57 | 58 | Clone a github wiki you want to act as the store of your journal: 59 | 60 | ```bash 61 | git clone https://github.com//.wiki.git ~/journal.wiki 62 | ``` 63 | 64 | Quickly drop into the editor of your choice (default `vim` but configurable via `$JRNL_EDITOR`): 65 | 66 | ```bash 67 | jrnl 68 | ``` 69 | 70 | Write your entry and then "memorize": 71 | 72 | ```bash 73 | jrnl memorize 74 | ``` 75 | 76 | ## Options 77 | 78 | You can configure `jrnl` with the following environment variables: 79 | 80 | * `JRNL_EDITOR` (`vim`) - Editor to use 81 | * `JRNL_EDITOR_OPTIONS` (`""`) - Additional CLI flags for your editor. IE, for VS Code: `-n $HOME/journal.wiki/` 82 | * `JOURNAL_PATH` (`~/journal.wiki`) - Path to your cloned Github wiki repo. 83 | 84 | ## Commands 85 | 86 | ### Tag 87 | 88 | `jrnl` has the ability to tag a journal entry so that it can be easily referenced and found. 89 | 90 | ```bash 91 | jrnl tag -t sometag 92 | ``` 93 | 94 | This would append "sometag" to the journal entry in `frontmatter` format: 95 | 96 | ```yaml 97 | --- 98 | tags: 99 | - sometag 100 | --- 101 | ``` 102 | 103 | ### Index 104 | 105 | `jrnl` has the ability to generate an `Index.md` that allows you to easily reference any journal entry by a tag. 106 | 107 | You can use the `tag` command specified above to specify tags. 108 | 109 | ```bash 110 | jrnl tag -t cooltag -t another cool tag -d "2017-12-01" 111 | ``` 112 | 113 | Then run the index command: 114 | 115 | ```bash 116 | jrnl index 117 | ``` 118 | 119 | Which generates: 120 | 121 | > ~/journal.wiki/Index.md 122 | 123 | > * *cooltag* [2017-12-01]() 124 | > * *another cool tag* [2017-12-01]() 125 | 126 | If there is more than one journal entry that uses the same tag: 127 | 128 | ```bash 129 | jrnl tag -t cooltag -t -d "2017-12-04" 130 | ``` 131 | 132 | Then `jrnl index` would generate: 133 | 134 | > ~/journal.wiki/Index.md 135 | 136 | > * *cooltag* [2017-12-01](), [2017-12-04]() 137 | > * *another cool tag* [2017-12-01]() 138 | 139 | ### Append an image 140 | 141 | Many developers use hand-written notes (or a whiteboard) and want to store it in a common journal. 142 | 143 | You can use the `jrnl image /path/to/image` command to quickly add an image to the journal repo and append it to the current journal entry. 144 | 145 | ## Tips & Tricks 146 | 147 | ### Use Find Command to Create a Book 148 | 149 | You can use the `find` command (as of `v0.3.0`) to create a single document of all journal entries related to a tag (or tags): 150 | 151 | ```bash 152 | jrnl find --tag sometag --tag somerelatedtag | xargs cat > sometag.md 153 | ``` 154 | 155 | ### Use `find` command to add a common tag 156 | 157 | You can use the `find` (as of `v0.3.0`) command and the `tag` command (as of `v0.4.0`) to add a common tag or tags: 158 | 159 | ```bash 160 | jrnl tag -t newtag $(jrnl find -tag existingtag | xargs -I {} echo "-f {}") 161 | ``` 162 | 163 | ## Development 164 | 165 | To compile the CLI tool: 166 | 167 | ```bash 168 | go build -o jrnl cmd/jrnl/main.go 169 | ``` 170 | 171 | To run the unit tests: 172 | 173 | ```bash 174 | go test $(go list ./... | grep -v /vendor/) 175 | ``` 176 | 177 | To add a dependency use [`go modules`](https://blog.golang.org/using-go-modules) 178 | 179 | For distribution, the [`goreleaser` tool](https://goreleaser.com/) is used. Tag a new version and run `goreleaser --rm-dist` to tag and distribute. 180 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v2/yamlprivateh.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | const ( 4 | // The size of the input raw buffer. 5 | input_raw_buffer_size = 512 6 | 7 | // The size of the input buffer. 8 | // It should be possible to decode the whole raw buffer. 9 | input_buffer_size = input_raw_buffer_size * 3 10 | 11 | // The size of the output buffer. 12 | output_buffer_size = 128 13 | 14 | // The size of the output raw buffer. 15 | // It should be possible to encode the whole output buffer. 16 | output_raw_buffer_size = (output_buffer_size*2 + 2) 17 | 18 | // The size of other stacks and queues. 19 | initial_stack_size = 16 20 | initial_queue_size = 16 21 | initial_string_size = 16 22 | ) 23 | 24 | // Check if the character at the specified position is an alphabetical 25 | // character, a digit, '_', or '-'. 26 | func is_alpha(b []byte, i int) bool { 27 | return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'Z' || b[i] >= 'a' && b[i] <= 'z' || b[i] == '_' || b[i] == '-' 28 | } 29 | 30 | // Check if the character at the specified position is a digit. 31 | func is_digit(b []byte, i int) bool { 32 | return b[i] >= '0' && b[i] <= '9' 33 | } 34 | 35 | // Get the value of a digit. 36 | func as_digit(b []byte, i int) int { 37 | return int(b[i]) - '0' 38 | } 39 | 40 | // Check if the character at the specified position is a hex-digit. 41 | func is_hex(b []byte, i int) bool { 42 | return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'F' || b[i] >= 'a' && b[i] <= 'f' 43 | } 44 | 45 | // Get the value of a hex-digit. 46 | func as_hex(b []byte, i int) int { 47 | bi := b[i] 48 | if bi >= 'A' && bi <= 'F' { 49 | return int(bi) - 'A' + 10 50 | } 51 | if bi >= 'a' && bi <= 'f' { 52 | return int(bi) - 'a' + 10 53 | } 54 | return int(bi) - '0' 55 | } 56 | 57 | // Check if the character is ASCII. 58 | func is_ascii(b []byte, i int) bool { 59 | return b[i] <= 0x7F 60 | } 61 | 62 | // Check if the character at the start of the buffer can be printed unescaped. 63 | func is_printable(b []byte, i int) bool { 64 | return ((b[i] == 0x0A) || // . == #x0A 65 | (b[i] >= 0x20 && b[i] <= 0x7E) || // #x20 <= . <= #x7E 66 | (b[i] == 0xC2 && b[i+1] >= 0xA0) || // #0xA0 <= . <= #xD7FF 67 | (b[i] > 0xC2 && b[i] < 0xED) || 68 | (b[i] == 0xED && b[i+1] < 0xA0) || 69 | (b[i] == 0xEE) || 70 | (b[i] == 0xEF && // #xE000 <= . <= #xFFFD 71 | !(b[i+1] == 0xBB && b[i+2] == 0xBF) && // && . != #xFEFF 72 | !(b[i+1] == 0xBF && (b[i+2] == 0xBE || b[i+2] == 0xBF)))) 73 | } 74 | 75 | // Check if the character at the specified position is NUL. 76 | func is_z(b []byte, i int) bool { 77 | return b[i] == 0x00 78 | } 79 | 80 | // Check if the beginning of the buffer is a BOM. 81 | func is_bom(b []byte, i int) bool { 82 | return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF 83 | } 84 | 85 | // Check if the character at the specified position is space. 86 | func is_space(b []byte, i int) bool { 87 | return b[i] == ' ' 88 | } 89 | 90 | // Check if the character at the specified position is tab. 91 | func is_tab(b []byte, i int) bool { 92 | return b[i] == '\t' 93 | } 94 | 95 | // Check if the character at the specified position is blank (space or tab). 96 | func is_blank(b []byte, i int) bool { 97 | //return is_space(b, i) || is_tab(b, i) 98 | return b[i] == ' ' || b[i] == '\t' 99 | } 100 | 101 | // Check if the character at the specified position is a line break. 102 | func is_break(b []byte, i int) bool { 103 | return (b[i] == '\r' || // CR (#xD) 104 | b[i] == '\n' || // LF (#xA) 105 | b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) 106 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) 107 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9) // PS (#x2029) 108 | } 109 | 110 | func is_crlf(b []byte, i int) bool { 111 | return b[i] == '\r' && b[i+1] == '\n' 112 | } 113 | 114 | // Check if the character is a line break or NUL. 115 | func is_breakz(b []byte, i int) bool { 116 | //return is_break(b, i) || is_z(b, i) 117 | return ( // is_break: 118 | b[i] == '\r' || // CR (#xD) 119 | b[i] == '\n' || // LF (#xA) 120 | b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) 121 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) 122 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) 123 | // is_z: 124 | b[i] == 0) 125 | } 126 | 127 | // Check if the character is a line break, space, or NUL. 128 | func is_spacez(b []byte, i int) bool { 129 | //return is_space(b, i) || is_breakz(b, i) 130 | return ( // is_space: 131 | b[i] == ' ' || 132 | // is_breakz: 133 | b[i] == '\r' || // CR (#xD) 134 | b[i] == '\n' || // LF (#xA) 135 | b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) 136 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) 137 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) 138 | b[i] == 0) 139 | } 140 | 141 | // Check if the character is a line break, space, tab, or NUL. 142 | func is_blankz(b []byte, i int) bool { 143 | //return is_blank(b, i) || is_breakz(b, i) 144 | return ( // is_blank: 145 | b[i] == ' ' || b[i] == '\t' || 146 | // is_breakz: 147 | b[i] == '\r' || // CR (#xD) 148 | b[i] == '\n' || // LF (#xA) 149 | b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) 150 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) 151 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) 152 | b[i] == 0) 153 | } 154 | 155 | // Determine the width of the character. 156 | func width(b byte) int { 157 | // Don't replace these by a switch without first 158 | // confirming that it is being inlined. 159 | if b&0x80 == 0x00 { 160 | return 1 161 | } 162 | if b&0xE0 == 0xC0 { 163 | return 2 164 | } 165 | if b&0xF0 == 0xE0 { 166 | return 3 167 | } 168 | if b&0xF8 == 0xF0 { 169 | return 4 170 | } 171 | return 0 172 | 173 | } 174 | -------------------------------------------------------------------------------- /vendor/github.com/caarlos0/env/env.go: -------------------------------------------------------------------------------- 1 | package env 2 | 3 | import ( 4 | "errors" 5 | "os" 6 | "reflect" 7 | "strconv" 8 | "strings" 9 | "time" 10 | ) 11 | 12 | var ( 13 | // ErrNotAStructPtr is returned if you pass something that is not a pointer to a 14 | // Struct to Parse 15 | ErrNotAStructPtr = errors.New("Expected a pointer to a Struct") 16 | // ErrUnsupportedType if the struct field type is not supported by env 17 | ErrUnsupportedType = errors.New("Type is not supported") 18 | // ErrUnsupportedSliceType if the slice element type is not supported by env 19 | ErrUnsupportedSliceType = errors.New("Unsupported slice type") 20 | // Friendly names for reflect types 21 | sliceOfInts = reflect.TypeOf([]int(nil)) 22 | sliceOfInt64s = reflect.TypeOf([]int64(nil)) 23 | sliceOfStrings = reflect.TypeOf([]string(nil)) 24 | sliceOfBools = reflect.TypeOf([]bool(nil)) 25 | sliceOfFloat32s = reflect.TypeOf([]float32(nil)) 26 | sliceOfFloat64s = reflect.TypeOf([]float64(nil)) 27 | ) 28 | 29 | // Parse parses a struct containing `env` tags and loads its values from 30 | // environment variables. 31 | func Parse(v interface{}) error { 32 | ptrRef := reflect.ValueOf(v) 33 | if ptrRef.Kind() != reflect.Ptr { 34 | return ErrNotAStructPtr 35 | } 36 | ref := ptrRef.Elem() 37 | if ref.Kind() != reflect.Struct { 38 | return ErrNotAStructPtr 39 | } 40 | return doParse(ref) 41 | } 42 | 43 | func doParse(ref reflect.Value) error { 44 | refType := ref.Type() 45 | var errorList []string 46 | 47 | for i := 0; i < refType.NumField(); i++ { 48 | value, err := get(refType.Field(i)) 49 | if err != nil { 50 | errorList = append(errorList, err.Error()) 51 | continue 52 | } 53 | if value == "" { 54 | continue 55 | } 56 | if err := set(ref.Field(i), refType.Field(i), value); err != nil { 57 | errorList = append(errorList, err.Error()) 58 | continue 59 | } 60 | } 61 | if len(errorList) == 0 { 62 | return nil 63 | } 64 | return errors.New(strings.Join(errorList, ". ")) 65 | } 66 | 67 | func get(field reflect.StructField) (string, error) { 68 | var ( 69 | val string 70 | err error 71 | ) 72 | 73 | key, opts := parseKeyForOption(field.Tag.Get("env")) 74 | 75 | defaultValue := field.Tag.Get("envDefault") 76 | val = getOr(key, defaultValue) 77 | 78 | if len(opts) > 0 { 79 | for _, opt := range opts { 80 | // The only option supported is "required". 81 | switch opt { 82 | case "": 83 | break 84 | case "required": 85 | val, err = getRequired(key) 86 | default: 87 | err = errors.New("Env tag option " + opt + " not supported.") 88 | } 89 | } 90 | } 91 | 92 | return val, err 93 | } 94 | 95 | // split the env tag's key into the expected key and desired option, if any. 96 | func parseKeyForOption(key string) (string, []string) { 97 | opts := strings.Split(key, ",") 98 | return opts[0], opts[1:] 99 | } 100 | 101 | func getRequired(key string) (string, error) { 102 | if value := os.Getenv(key); value != "" { 103 | return value, nil 104 | } 105 | // We do not use fmt.Errorf to avoid another import. 106 | return "", errors.New("Required environment variable " + key + " is not set") 107 | } 108 | 109 | func getOr(key, defaultValue string) string { 110 | value := os.Getenv(key) 111 | if value != "" { 112 | return value 113 | } 114 | return defaultValue 115 | } 116 | 117 | func set(field reflect.Value, refType reflect.StructField, value string) error { 118 | switch field.Kind() { 119 | case reflect.Slice: 120 | separator := refType.Tag.Get("envSeparator") 121 | return handleSlice(field, value, separator) 122 | case reflect.String: 123 | field.SetString(value) 124 | case reflect.Bool: 125 | bvalue, err := strconv.ParseBool(value) 126 | if err != nil { 127 | return err 128 | } 129 | field.SetBool(bvalue) 130 | case reflect.Int: 131 | intValue, err := strconv.ParseInt(value, 10, 32) 132 | if err != nil { 133 | return err 134 | } 135 | field.SetInt(intValue) 136 | case reflect.Float32: 137 | v, err := strconv.ParseFloat(value, 32) 138 | if err != nil { 139 | return err 140 | } 141 | field.SetFloat(v) 142 | case reflect.Float64: 143 | v, err := strconv.ParseFloat(value, 64) 144 | if err != nil { 145 | return err 146 | } 147 | field.Set(reflect.ValueOf(v)) 148 | case reflect.Int64: 149 | if refType.Type.String() == "time.Duration" { 150 | dValue, err := time.ParseDuration(value) 151 | if err != nil { 152 | return err 153 | } 154 | field.Set(reflect.ValueOf(dValue)) 155 | } else { 156 | intValue, err := strconv.ParseInt(value, 10, 64) 157 | if err != nil { 158 | return err 159 | } 160 | field.SetInt(intValue) 161 | } 162 | default: 163 | return ErrUnsupportedType 164 | } 165 | return nil 166 | } 167 | 168 | func handleSlice(field reflect.Value, value, separator string) error { 169 | if separator == "" { 170 | separator = "," 171 | } 172 | 173 | splitData := strings.Split(value, separator) 174 | 175 | switch field.Type() { 176 | case sliceOfStrings: 177 | field.Set(reflect.ValueOf(splitData)) 178 | case sliceOfInts: 179 | intData, err := parseInts(splitData) 180 | if err != nil { 181 | return err 182 | } 183 | field.Set(reflect.ValueOf(intData)) 184 | case sliceOfInt64s: 185 | int64Data, err := parseInt64s(splitData) 186 | if err != nil { 187 | return err 188 | } 189 | field.Set(reflect.ValueOf(int64Data)) 190 | 191 | case sliceOfFloat32s: 192 | data, err := parseFloat32s(splitData) 193 | if err != nil { 194 | return err 195 | } 196 | field.Set(reflect.ValueOf(data)) 197 | case sliceOfFloat64s: 198 | data, err := parseFloat64s(splitData) 199 | if err != nil { 200 | return err 201 | } 202 | field.Set(reflect.ValueOf(data)) 203 | case sliceOfBools: 204 | boolData, err := parseBools(splitData) 205 | if err != nil { 206 | return err 207 | } 208 | field.Set(reflect.ValueOf(boolData)) 209 | default: 210 | return ErrUnsupportedSliceType 211 | } 212 | return nil 213 | } 214 | 215 | func parseInts(data []string) ([]int, error) { 216 | var intSlice []int 217 | 218 | for _, v := range data { 219 | intValue, err := strconv.ParseInt(v, 10, 32) 220 | if err != nil { 221 | return nil, err 222 | } 223 | intSlice = append(intSlice, int(intValue)) 224 | } 225 | return intSlice, nil 226 | } 227 | 228 | func parseInt64s(data []string) ([]int64, error) { 229 | var intSlice []int64 230 | 231 | for _, v := range data { 232 | intValue, err := strconv.ParseInt(v, 10, 64) 233 | if err != nil { 234 | return nil, err 235 | } 236 | intSlice = append(intSlice, int64(intValue)) 237 | } 238 | return intSlice, nil 239 | } 240 | 241 | func parseFloat32s(data []string) ([]float32, error) { 242 | var float32Slice []float32 243 | 244 | for _, v := range data { 245 | data, err := strconv.ParseFloat(v, 32) 246 | if err != nil { 247 | return nil, err 248 | } 249 | float32Slice = append(float32Slice, float32(data)) 250 | } 251 | return float32Slice, nil 252 | } 253 | 254 | func parseFloat64s(data []string) ([]float64, error) { 255 | var float64Slice []float64 256 | 257 | for _, v := range data { 258 | data, err := strconv.ParseFloat(v, 64) 259 | if err != nil { 260 | return nil, err 261 | } 262 | float64Slice = append(float64Slice, float64(data)) 263 | } 264 | return float64Slice, nil 265 | } 266 | 267 | func parseBools(data []string) ([]bool, error) { 268 | var boolSlice []bool 269 | 270 | for _, v := range data { 271 | bvalue, err := strconv.ParseBool(v) 272 | if err != nil { 273 | return nil, err 274 | } 275 | 276 | boolSlice = append(boolSlice, bvalue) 277 | } 278 | return boolSlice, nil 279 | } 280 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v2/resolve.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | import ( 4 | "encoding/base64" 5 | "math" 6 | "regexp" 7 | "strconv" 8 | "strings" 9 | "time" 10 | ) 11 | 12 | type resolveMapItem struct { 13 | value interface{} 14 | tag string 15 | } 16 | 17 | var resolveTable = make([]byte, 256) 18 | var resolveMap = make(map[string]resolveMapItem) 19 | 20 | func init() { 21 | t := resolveTable 22 | t[int('+')] = 'S' // Sign 23 | t[int('-')] = 'S' 24 | for _, c := range "0123456789" { 25 | t[int(c)] = 'D' // Digit 26 | } 27 | for _, c := range "yYnNtTfFoO~" { 28 | t[int(c)] = 'M' // In map 29 | } 30 | t[int('.')] = '.' // Float (potentially in map) 31 | 32 | var resolveMapList = []struct { 33 | v interface{} 34 | tag string 35 | l []string 36 | }{ 37 | {true, yaml_BOOL_TAG, []string{"y", "Y", "yes", "Yes", "YES"}}, 38 | {true, yaml_BOOL_TAG, []string{"true", "True", "TRUE"}}, 39 | {true, yaml_BOOL_TAG, []string{"on", "On", "ON"}}, 40 | {false, yaml_BOOL_TAG, []string{"n", "N", "no", "No", "NO"}}, 41 | {false, yaml_BOOL_TAG, []string{"false", "False", "FALSE"}}, 42 | {false, yaml_BOOL_TAG, []string{"off", "Off", "OFF"}}, 43 | {nil, yaml_NULL_TAG, []string{"", "~", "null", "Null", "NULL"}}, 44 | {math.NaN(), yaml_FLOAT_TAG, []string{".nan", ".NaN", ".NAN"}}, 45 | {math.Inf(+1), yaml_FLOAT_TAG, []string{".inf", ".Inf", ".INF"}}, 46 | {math.Inf(+1), yaml_FLOAT_TAG, []string{"+.inf", "+.Inf", "+.INF"}}, 47 | {math.Inf(-1), yaml_FLOAT_TAG, []string{"-.inf", "-.Inf", "-.INF"}}, 48 | {"<<", yaml_MERGE_TAG, []string{"<<"}}, 49 | } 50 | 51 | m := resolveMap 52 | for _, item := range resolveMapList { 53 | for _, s := range item.l { 54 | m[s] = resolveMapItem{item.v, item.tag} 55 | } 56 | } 57 | } 58 | 59 | const longTagPrefix = "tag:yaml.org,2002:" 60 | 61 | func shortTag(tag string) string { 62 | // TODO This can easily be made faster and produce less garbage. 63 | if strings.HasPrefix(tag, longTagPrefix) { 64 | return "!!" + tag[len(longTagPrefix):] 65 | } 66 | return tag 67 | } 68 | 69 | func longTag(tag string) string { 70 | if strings.HasPrefix(tag, "!!") { 71 | return longTagPrefix + tag[2:] 72 | } 73 | return tag 74 | } 75 | 76 | func resolvableTag(tag string) bool { 77 | switch tag { 78 | case "", yaml_STR_TAG, yaml_BOOL_TAG, yaml_INT_TAG, yaml_FLOAT_TAG, yaml_NULL_TAG, yaml_TIMESTAMP_TAG: 79 | return true 80 | } 81 | return false 82 | } 83 | 84 | var yamlStyleFloat = regexp.MustCompile(`^[-+]?[0-9]*\.?[0-9]+([eE][-+][0-9]+)?$`) 85 | 86 | func resolve(tag string, in string) (rtag string, out interface{}) { 87 | if !resolvableTag(tag) { 88 | return tag, in 89 | } 90 | 91 | defer func() { 92 | switch tag { 93 | case "", rtag, yaml_STR_TAG, yaml_BINARY_TAG: 94 | return 95 | case yaml_FLOAT_TAG: 96 | if rtag == yaml_INT_TAG { 97 | switch v := out.(type) { 98 | case int64: 99 | rtag = yaml_FLOAT_TAG 100 | out = float64(v) 101 | return 102 | case int: 103 | rtag = yaml_FLOAT_TAG 104 | out = float64(v) 105 | return 106 | } 107 | } 108 | } 109 | failf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(tag)) 110 | }() 111 | 112 | // Any data is accepted as a !!str or !!binary. 113 | // Otherwise, the prefix is enough of a hint about what it might be. 114 | hint := byte('N') 115 | if in != "" { 116 | hint = resolveTable[in[0]] 117 | } 118 | if hint != 0 && tag != yaml_STR_TAG && tag != yaml_BINARY_TAG { 119 | // Handle things we can lookup in a map. 120 | if item, ok := resolveMap[in]; ok { 121 | return item.tag, item.value 122 | } 123 | 124 | // Base 60 floats are a bad idea, were dropped in YAML 1.2, and 125 | // are purposefully unsupported here. They're still quoted on 126 | // the way out for compatibility with other parser, though. 127 | 128 | switch hint { 129 | case 'M': 130 | // We've already checked the map above. 131 | 132 | case '.': 133 | // Not in the map, so maybe a normal float. 134 | floatv, err := strconv.ParseFloat(in, 64) 135 | if err == nil { 136 | return yaml_FLOAT_TAG, floatv 137 | } 138 | 139 | case 'D', 'S': 140 | // Int, float, or timestamp. 141 | // Only try values as a timestamp if the value is unquoted or there's an explicit 142 | // !!timestamp tag. 143 | if tag == "" || tag == yaml_TIMESTAMP_TAG { 144 | t, ok := parseTimestamp(in) 145 | if ok { 146 | return yaml_TIMESTAMP_TAG, t 147 | } 148 | } 149 | 150 | plain := strings.Replace(in, "_", "", -1) 151 | intv, err := strconv.ParseInt(plain, 0, 64) 152 | if err == nil { 153 | if intv == int64(int(intv)) { 154 | return yaml_INT_TAG, int(intv) 155 | } else { 156 | return yaml_INT_TAG, intv 157 | } 158 | } 159 | uintv, err := strconv.ParseUint(plain, 0, 64) 160 | if err == nil { 161 | return yaml_INT_TAG, uintv 162 | } 163 | if yamlStyleFloat.MatchString(plain) { 164 | floatv, err := strconv.ParseFloat(plain, 64) 165 | if err == nil { 166 | return yaml_FLOAT_TAG, floatv 167 | } 168 | } 169 | if strings.HasPrefix(plain, "0b") { 170 | intv, err := strconv.ParseInt(plain[2:], 2, 64) 171 | if err == nil { 172 | if intv == int64(int(intv)) { 173 | return yaml_INT_TAG, int(intv) 174 | } else { 175 | return yaml_INT_TAG, intv 176 | } 177 | } 178 | uintv, err := strconv.ParseUint(plain[2:], 2, 64) 179 | if err == nil { 180 | return yaml_INT_TAG, uintv 181 | } 182 | } else if strings.HasPrefix(plain, "-0b") { 183 | intv, err := strconv.ParseInt("-" + plain[3:], 2, 64) 184 | if err == nil { 185 | if true || intv == int64(int(intv)) { 186 | return yaml_INT_TAG, int(intv) 187 | } else { 188 | return yaml_INT_TAG, intv 189 | } 190 | } 191 | } 192 | default: 193 | panic("resolveTable item not yet handled: " + string(rune(hint)) + " (with " + in + ")") 194 | } 195 | } 196 | return yaml_STR_TAG, in 197 | } 198 | 199 | // encodeBase64 encodes s as base64 that is broken up into multiple lines 200 | // as appropriate for the resulting length. 201 | func encodeBase64(s string) string { 202 | const lineLen = 70 203 | encLen := base64.StdEncoding.EncodedLen(len(s)) 204 | lines := encLen/lineLen + 1 205 | buf := make([]byte, encLen*2+lines) 206 | in := buf[0:encLen] 207 | out := buf[encLen:] 208 | base64.StdEncoding.Encode(in, []byte(s)) 209 | k := 0 210 | for i := 0; i < len(in); i += lineLen { 211 | j := i + lineLen 212 | if j > len(in) { 213 | j = len(in) 214 | } 215 | k += copy(out[k:], in[i:j]) 216 | if lines > 1 { 217 | out[k] = '\n' 218 | k++ 219 | } 220 | } 221 | return string(out[:k]) 222 | } 223 | 224 | // This is a subset of the formats allowed by the regular expression 225 | // defined at http://yaml.org/type/timestamp.html. 226 | var allowedTimestampFormats = []string{ 227 | "2006-1-2T15:4:5.999999999Z07:00", // RCF3339Nano with short date fields. 228 | "2006-1-2t15:4:5.999999999Z07:00", // RFC3339Nano with short date fields and lower-case "t". 229 | "2006-1-2 15:4:5.999999999", // space separated with no time zone 230 | "2006-1-2", // date only 231 | // Notable exception: time.Parse cannot handle: "2001-12-14 21:59:43.10 -5" 232 | // from the set of examples. 233 | } 234 | 235 | // parseTimestamp parses s as a timestamp string and 236 | // returns the timestamp and reports whether it succeeded. 237 | // Timestamp formats are defined at http://yaml.org/type/timestamp.html 238 | func parseTimestamp(s string) (time.Time, bool) { 239 | // TODO write code to check all the formats supported by 240 | // http://yaml.org/type/timestamp.html instead of using time.Parse. 241 | 242 | // Quick check: all date formats start with YYYY-. 243 | i := 0 244 | for ; i < len(s); i++ { 245 | if c := s[i]; c < '0' || c > '9' { 246 | break 247 | } 248 | } 249 | if i != 4 || i == len(s) || s[i] != '-' { 250 | return time.Time{}, false 251 | } 252 | for _, format := range allowedTimestampFormats { 253 | if t, err := time.Parse(format, s); err == nil { 254 | return t, true 255 | } 256 | } 257 | return time.Time{}, false 258 | } 259 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v2/encode.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | import ( 4 | "encoding" 5 | "fmt" 6 | "io" 7 | "reflect" 8 | "regexp" 9 | "sort" 10 | "strconv" 11 | "strings" 12 | "time" 13 | "unicode/utf8" 14 | ) 15 | 16 | // jsonNumber is the interface of the encoding/json.Number datatype. 17 | // Repeating the interface here avoids a dependency on encoding/json, and also 18 | // supports other libraries like jsoniter, which use a similar datatype with 19 | // the same interface. Detecting this interface is useful when dealing with 20 | // structures containing json.Number, which is a string under the hood. The 21 | // encoder should prefer the use of Int64(), Float64() and string(), in that 22 | // order, when encoding this type. 23 | type jsonNumber interface { 24 | Float64() (float64, error) 25 | Int64() (int64, error) 26 | String() string 27 | } 28 | 29 | type encoder struct { 30 | emitter yaml_emitter_t 31 | event yaml_event_t 32 | out []byte 33 | flow bool 34 | // doneInit holds whether the initial stream_start_event has been 35 | // emitted. 36 | doneInit bool 37 | } 38 | 39 | func newEncoder() *encoder { 40 | e := &encoder{} 41 | yaml_emitter_initialize(&e.emitter) 42 | yaml_emitter_set_output_string(&e.emitter, &e.out) 43 | yaml_emitter_set_unicode(&e.emitter, true) 44 | return e 45 | } 46 | 47 | func newEncoderWithWriter(w io.Writer) *encoder { 48 | e := &encoder{} 49 | yaml_emitter_initialize(&e.emitter) 50 | yaml_emitter_set_output_writer(&e.emitter, w) 51 | yaml_emitter_set_unicode(&e.emitter, true) 52 | return e 53 | } 54 | 55 | func (e *encoder) init() { 56 | if e.doneInit { 57 | return 58 | } 59 | yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING) 60 | e.emit() 61 | e.doneInit = true 62 | } 63 | 64 | func (e *encoder) finish() { 65 | e.emitter.open_ended = false 66 | yaml_stream_end_event_initialize(&e.event) 67 | e.emit() 68 | } 69 | 70 | func (e *encoder) destroy() { 71 | yaml_emitter_delete(&e.emitter) 72 | } 73 | 74 | func (e *encoder) emit() { 75 | // This will internally delete the e.event value. 76 | e.must(yaml_emitter_emit(&e.emitter, &e.event)) 77 | } 78 | 79 | func (e *encoder) must(ok bool) { 80 | if !ok { 81 | msg := e.emitter.problem 82 | if msg == "" { 83 | msg = "unknown problem generating YAML content" 84 | } 85 | failf("%s", msg) 86 | } 87 | } 88 | 89 | func (e *encoder) marshalDoc(tag string, in reflect.Value) { 90 | e.init() 91 | yaml_document_start_event_initialize(&e.event, nil, nil, true) 92 | e.emit() 93 | e.marshal(tag, in) 94 | yaml_document_end_event_initialize(&e.event, true) 95 | e.emit() 96 | } 97 | 98 | func (e *encoder) marshal(tag string, in reflect.Value) { 99 | if !in.IsValid() || in.Kind() == reflect.Ptr && in.IsNil() { 100 | e.nilv() 101 | return 102 | } 103 | iface := in.Interface() 104 | switch m := iface.(type) { 105 | case jsonNumber: 106 | integer, err := m.Int64() 107 | if err == nil { 108 | // In this case the json.Number is a valid int64 109 | in = reflect.ValueOf(integer) 110 | break 111 | } 112 | float, err := m.Float64() 113 | if err == nil { 114 | // In this case the json.Number is a valid float64 115 | in = reflect.ValueOf(float) 116 | break 117 | } 118 | // fallback case - no number could be obtained 119 | in = reflect.ValueOf(m.String()) 120 | case time.Time, *time.Time: 121 | // Although time.Time implements TextMarshaler, 122 | // we don't want to treat it as a string for YAML 123 | // purposes because YAML has special support for 124 | // timestamps. 125 | case Marshaler: 126 | v, err := m.MarshalYAML() 127 | if err != nil { 128 | fail(err) 129 | } 130 | if v == nil { 131 | e.nilv() 132 | return 133 | } 134 | in = reflect.ValueOf(v) 135 | case encoding.TextMarshaler: 136 | text, err := m.MarshalText() 137 | if err != nil { 138 | fail(err) 139 | } 140 | in = reflect.ValueOf(string(text)) 141 | case nil: 142 | e.nilv() 143 | return 144 | } 145 | switch in.Kind() { 146 | case reflect.Interface: 147 | e.marshal(tag, in.Elem()) 148 | case reflect.Map: 149 | e.mapv(tag, in) 150 | case reflect.Ptr: 151 | if in.Type() == ptrTimeType { 152 | e.timev(tag, in.Elem()) 153 | } else { 154 | e.marshal(tag, in.Elem()) 155 | } 156 | case reflect.Struct: 157 | if in.Type() == timeType { 158 | e.timev(tag, in) 159 | } else { 160 | e.structv(tag, in) 161 | } 162 | case reflect.Slice, reflect.Array: 163 | if in.Type().Elem() == mapItemType { 164 | e.itemsv(tag, in) 165 | } else { 166 | e.slicev(tag, in) 167 | } 168 | case reflect.String: 169 | e.stringv(tag, in) 170 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 171 | if in.Type() == durationType { 172 | e.stringv(tag, reflect.ValueOf(iface.(time.Duration).String())) 173 | } else { 174 | e.intv(tag, in) 175 | } 176 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 177 | e.uintv(tag, in) 178 | case reflect.Float32, reflect.Float64: 179 | e.floatv(tag, in) 180 | case reflect.Bool: 181 | e.boolv(tag, in) 182 | default: 183 | panic("cannot marshal type: " + in.Type().String()) 184 | } 185 | } 186 | 187 | func (e *encoder) mapv(tag string, in reflect.Value) { 188 | e.mappingv(tag, func() { 189 | keys := keyList(in.MapKeys()) 190 | sort.Sort(keys) 191 | for _, k := range keys { 192 | e.marshal("", k) 193 | e.marshal("", in.MapIndex(k)) 194 | } 195 | }) 196 | } 197 | 198 | func (e *encoder) itemsv(tag string, in reflect.Value) { 199 | e.mappingv(tag, func() { 200 | slice := in.Convert(reflect.TypeOf([]MapItem{})).Interface().([]MapItem) 201 | for _, item := range slice { 202 | e.marshal("", reflect.ValueOf(item.Key)) 203 | e.marshal("", reflect.ValueOf(item.Value)) 204 | } 205 | }) 206 | } 207 | 208 | func (e *encoder) structv(tag string, in reflect.Value) { 209 | sinfo, err := getStructInfo(in.Type()) 210 | if err != nil { 211 | panic(err) 212 | } 213 | e.mappingv(tag, func() { 214 | for _, info := range sinfo.FieldsList { 215 | var value reflect.Value 216 | if info.Inline == nil { 217 | value = in.Field(info.Num) 218 | } else { 219 | value = in.FieldByIndex(info.Inline) 220 | } 221 | if info.OmitEmpty && isZero(value) { 222 | continue 223 | } 224 | e.marshal("", reflect.ValueOf(info.Key)) 225 | e.flow = info.Flow 226 | e.marshal("", value) 227 | } 228 | if sinfo.InlineMap >= 0 { 229 | m := in.Field(sinfo.InlineMap) 230 | if m.Len() > 0 { 231 | e.flow = false 232 | keys := keyList(m.MapKeys()) 233 | sort.Sort(keys) 234 | for _, k := range keys { 235 | if _, found := sinfo.FieldsMap[k.String()]; found { 236 | panic(fmt.Sprintf("Can't have key %q in inlined map; conflicts with struct field", k.String())) 237 | } 238 | e.marshal("", k) 239 | e.flow = false 240 | e.marshal("", m.MapIndex(k)) 241 | } 242 | } 243 | } 244 | }) 245 | } 246 | 247 | func (e *encoder) mappingv(tag string, f func()) { 248 | implicit := tag == "" 249 | style := yaml_BLOCK_MAPPING_STYLE 250 | if e.flow { 251 | e.flow = false 252 | style = yaml_FLOW_MAPPING_STYLE 253 | } 254 | yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style) 255 | e.emit() 256 | f() 257 | yaml_mapping_end_event_initialize(&e.event) 258 | e.emit() 259 | } 260 | 261 | func (e *encoder) slicev(tag string, in reflect.Value) { 262 | implicit := tag == "" 263 | style := yaml_BLOCK_SEQUENCE_STYLE 264 | if e.flow { 265 | e.flow = false 266 | style = yaml_FLOW_SEQUENCE_STYLE 267 | } 268 | e.must(yaml_sequence_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)) 269 | e.emit() 270 | n := in.Len() 271 | for i := 0; i < n; i++ { 272 | e.marshal("", in.Index(i)) 273 | } 274 | e.must(yaml_sequence_end_event_initialize(&e.event)) 275 | e.emit() 276 | } 277 | 278 | // isBase60 returns whether s is in base 60 notation as defined in YAML 1.1. 279 | // 280 | // The base 60 float notation in YAML 1.1 is a terrible idea and is unsupported 281 | // in YAML 1.2 and by this package, but these should be marshalled quoted for 282 | // the time being for compatibility with other parsers. 283 | func isBase60Float(s string) (result bool) { 284 | // Fast path. 285 | if s == "" { 286 | return false 287 | } 288 | c := s[0] 289 | if !(c == '+' || c == '-' || c >= '0' && c <= '9') || strings.IndexByte(s, ':') < 0 { 290 | return false 291 | } 292 | // Do the full match. 293 | return base60float.MatchString(s) 294 | } 295 | 296 | // From http://yaml.org/type/float.html, except the regular expression there 297 | // is bogus. In practice parsers do not enforce the "\.[0-9_]*" suffix. 298 | var base60float = regexp.MustCompile(`^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+(?:\.[0-9_]*)?$`) 299 | 300 | func (e *encoder) stringv(tag string, in reflect.Value) { 301 | var style yaml_scalar_style_t 302 | s := in.String() 303 | canUsePlain := true 304 | switch { 305 | case !utf8.ValidString(s): 306 | if tag == yaml_BINARY_TAG { 307 | failf("explicitly tagged !!binary data must be base64-encoded") 308 | } 309 | if tag != "" { 310 | failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag)) 311 | } 312 | // It can't be encoded directly as YAML so use a binary tag 313 | // and encode it as base64. 314 | tag = yaml_BINARY_TAG 315 | s = encodeBase64(s) 316 | case tag == "": 317 | // Check to see if it would resolve to a specific 318 | // tag when encoded unquoted. If it doesn't, 319 | // there's no need to quote it. 320 | rtag, _ := resolve("", s) 321 | canUsePlain = rtag == yaml_STR_TAG && !isBase60Float(s) 322 | } 323 | // Note: it's possible for user code to emit invalid YAML 324 | // if they explicitly specify a tag and a string containing 325 | // text that's incompatible with that tag. 326 | switch { 327 | case strings.Contains(s, "\n"): 328 | style = yaml_LITERAL_SCALAR_STYLE 329 | case canUsePlain: 330 | style = yaml_PLAIN_SCALAR_STYLE 331 | default: 332 | style = yaml_DOUBLE_QUOTED_SCALAR_STYLE 333 | } 334 | e.emitScalar(s, "", tag, style) 335 | } 336 | 337 | func (e *encoder) boolv(tag string, in reflect.Value) { 338 | var s string 339 | if in.Bool() { 340 | s = "true" 341 | } else { 342 | s = "false" 343 | } 344 | e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) 345 | } 346 | 347 | func (e *encoder) intv(tag string, in reflect.Value) { 348 | s := strconv.FormatInt(in.Int(), 10) 349 | e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) 350 | } 351 | 352 | func (e *encoder) uintv(tag string, in reflect.Value) { 353 | s := strconv.FormatUint(in.Uint(), 10) 354 | e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) 355 | } 356 | 357 | func (e *encoder) timev(tag string, in reflect.Value) { 358 | t := in.Interface().(time.Time) 359 | s := t.Format(time.RFC3339Nano) 360 | e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) 361 | } 362 | 363 | func (e *encoder) floatv(tag string, in reflect.Value) { 364 | // Issue #352: When formatting, use the precision of the underlying value 365 | precision := 64 366 | if in.Kind() == reflect.Float32 { 367 | precision = 32 368 | } 369 | 370 | s := strconv.FormatFloat(in.Float(), 'g', -1, precision) 371 | switch s { 372 | case "+Inf": 373 | s = ".inf" 374 | case "-Inf": 375 | s = "-.inf" 376 | case "NaN": 377 | s = ".nan" 378 | } 379 | e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) 380 | } 381 | 382 | func (e *encoder) nilv() { 383 | e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE) 384 | } 385 | 386 | func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t) { 387 | implicit := tag == "" 388 | e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style)) 389 | e.emit() 390 | } 391 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v2/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v2/readerc.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | import ( 4 | "io" 5 | ) 6 | 7 | // Set the reader error and return 0. 8 | func yaml_parser_set_reader_error(parser *yaml_parser_t, problem string, offset int, value int) bool { 9 | parser.error = yaml_READER_ERROR 10 | parser.problem = problem 11 | parser.problem_offset = offset 12 | parser.problem_value = value 13 | return false 14 | } 15 | 16 | // Byte order marks. 17 | const ( 18 | bom_UTF8 = "\xef\xbb\xbf" 19 | bom_UTF16LE = "\xff\xfe" 20 | bom_UTF16BE = "\xfe\xff" 21 | ) 22 | 23 | // Determine the input stream encoding by checking the BOM symbol. If no BOM is 24 | // found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure. 25 | func yaml_parser_determine_encoding(parser *yaml_parser_t) bool { 26 | // Ensure that we had enough bytes in the raw buffer. 27 | for !parser.eof && len(parser.raw_buffer)-parser.raw_buffer_pos < 3 { 28 | if !yaml_parser_update_raw_buffer(parser) { 29 | return false 30 | } 31 | } 32 | 33 | // Determine the encoding. 34 | buf := parser.raw_buffer 35 | pos := parser.raw_buffer_pos 36 | avail := len(buf) - pos 37 | if avail >= 2 && buf[pos] == bom_UTF16LE[0] && buf[pos+1] == bom_UTF16LE[1] { 38 | parser.encoding = yaml_UTF16LE_ENCODING 39 | parser.raw_buffer_pos += 2 40 | parser.offset += 2 41 | } else if avail >= 2 && buf[pos] == bom_UTF16BE[0] && buf[pos+1] == bom_UTF16BE[1] { 42 | parser.encoding = yaml_UTF16BE_ENCODING 43 | parser.raw_buffer_pos += 2 44 | parser.offset += 2 45 | } else if avail >= 3 && buf[pos] == bom_UTF8[0] && buf[pos+1] == bom_UTF8[1] && buf[pos+2] == bom_UTF8[2] { 46 | parser.encoding = yaml_UTF8_ENCODING 47 | parser.raw_buffer_pos += 3 48 | parser.offset += 3 49 | } else { 50 | parser.encoding = yaml_UTF8_ENCODING 51 | } 52 | return true 53 | } 54 | 55 | // Update the raw buffer. 56 | func yaml_parser_update_raw_buffer(parser *yaml_parser_t) bool { 57 | size_read := 0 58 | 59 | // Return if the raw buffer is full. 60 | if parser.raw_buffer_pos == 0 && len(parser.raw_buffer) == cap(parser.raw_buffer) { 61 | return true 62 | } 63 | 64 | // Return on EOF. 65 | if parser.eof { 66 | return true 67 | } 68 | 69 | // Move the remaining bytes in the raw buffer to the beginning. 70 | if parser.raw_buffer_pos > 0 && parser.raw_buffer_pos < len(parser.raw_buffer) { 71 | copy(parser.raw_buffer, parser.raw_buffer[parser.raw_buffer_pos:]) 72 | } 73 | parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)-parser.raw_buffer_pos] 74 | parser.raw_buffer_pos = 0 75 | 76 | // Call the read handler to fill the buffer. 77 | size_read, err := parser.read_handler(parser, parser.raw_buffer[len(parser.raw_buffer):cap(parser.raw_buffer)]) 78 | parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)+size_read] 79 | if err == io.EOF { 80 | parser.eof = true 81 | } else if err != nil { 82 | return yaml_parser_set_reader_error(parser, "input error: "+err.Error(), parser.offset, -1) 83 | } 84 | return true 85 | } 86 | 87 | // Ensure that the buffer contains at least `length` characters. 88 | // Return true on success, false on failure. 89 | // 90 | // The length is supposed to be significantly less that the buffer size. 91 | func yaml_parser_update_buffer(parser *yaml_parser_t, length int) bool { 92 | if parser.read_handler == nil { 93 | panic("read handler must be set") 94 | } 95 | 96 | // [Go] This function was changed to guarantee the requested length size at EOF. 97 | // The fact we need to do this is pretty awful, but the description above implies 98 | // for that to be the case, and there are tests 99 | 100 | // If the EOF flag is set and the raw buffer is empty, do nothing. 101 | if parser.eof && parser.raw_buffer_pos == len(parser.raw_buffer) { 102 | // [Go] ACTUALLY! Read the documentation of this function above. 103 | // This is just broken. To return true, we need to have the 104 | // given length in the buffer. Not doing that means every single 105 | // check that calls this function to make sure the buffer has a 106 | // given length is Go) panicking; or C) accessing invalid memory. 107 | //return true 108 | } 109 | 110 | // Return if the buffer contains enough characters. 111 | if parser.unread >= length { 112 | return true 113 | } 114 | 115 | // Determine the input encoding if it is not known yet. 116 | if parser.encoding == yaml_ANY_ENCODING { 117 | if !yaml_parser_determine_encoding(parser) { 118 | return false 119 | } 120 | } 121 | 122 | // Move the unread characters to the beginning of the buffer. 123 | buffer_len := len(parser.buffer) 124 | if parser.buffer_pos > 0 && parser.buffer_pos < buffer_len { 125 | copy(parser.buffer, parser.buffer[parser.buffer_pos:]) 126 | buffer_len -= parser.buffer_pos 127 | parser.buffer_pos = 0 128 | } else if parser.buffer_pos == buffer_len { 129 | buffer_len = 0 130 | parser.buffer_pos = 0 131 | } 132 | 133 | // Open the whole buffer for writing, and cut it before returning. 134 | parser.buffer = parser.buffer[:cap(parser.buffer)] 135 | 136 | // Fill the buffer until it has enough characters. 137 | first := true 138 | for parser.unread < length { 139 | 140 | // Fill the raw buffer if necessary. 141 | if !first || parser.raw_buffer_pos == len(parser.raw_buffer) { 142 | if !yaml_parser_update_raw_buffer(parser) { 143 | parser.buffer = parser.buffer[:buffer_len] 144 | return false 145 | } 146 | } 147 | first = false 148 | 149 | // Decode the raw buffer. 150 | inner: 151 | for parser.raw_buffer_pos != len(parser.raw_buffer) { 152 | var value rune 153 | var width int 154 | 155 | raw_unread := len(parser.raw_buffer) - parser.raw_buffer_pos 156 | 157 | // Decode the next character. 158 | switch parser.encoding { 159 | case yaml_UTF8_ENCODING: 160 | // Decode a UTF-8 character. Check RFC 3629 161 | // (http://www.ietf.org/rfc/rfc3629.txt) for more details. 162 | // 163 | // The following table (taken from the RFC) is used for 164 | // decoding. 165 | // 166 | // Char. number range | UTF-8 octet sequence 167 | // (hexadecimal) | (binary) 168 | // --------------------+------------------------------------ 169 | // 0000 0000-0000 007F | 0xxxxxxx 170 | // 0000 0080-0000 07FF | 110xxxxx 10xxxxxx 171 | // 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx 172 | // 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 173 | // 174 | // Additionally, the characters in the range 0xD800-0xDFFF 175 | // are prohibited as they are reserved for use with UTF-16 176 | // surrogate pairs. 177 | 178 | // Determine the length of the UTF-8 sequence. 179 | octet := parser.raw_buffer[parser.raw_buffer_pos] 180 | switch { 181 | case octet&0x80 == 0x00: 182 | width = 1 183 | case octet&0xE0 == 0xC0: 184 | width = 2 185 | case octet&0xF0 == 0xE0: 186 | width = 3 187 | case octet&0xF8 == 0xF0: 188 | width = 4 189 | default: 190 | // The leading octet is invalid. 191 | return yaml_parser_set_reader_error(parser, 192 | "invalid leading UTF-8 octet", 193 | parser.offset, int(octet)) 194 | } 195 | 196 | // Check if the raw buffer contains an incomplete character. 197 | if width > raw_unread { 198 | if parser.eof { 199 | return yaml_parser_set_reader_error(parser, 200 | "incomplete UTF-8 octet sequence", 201 | parser.offset, -1) 202 | } 203 | break inner 204 | } 205 | 206 | // Decode the leading octet. 207 | switch { 208 | case octet&0x80 == 0x00: 209 | value = rune(octet & 0x7F) 210 | case octet&0xE0 == 0xC0: 211 | value = rune(octet & 0x1F) 212 | case octet&0xF0 == 0xE0: 213 | value = rune(octet & 0x0F) 214 | case octet&0xF8 == 0xF0: 215 | value = rune(octet & 0x07) 216 | default: 217 | value = 0 218 | } 219 | 220 | // Check and decode the trailing octets. 221 | for k := 1; k < width; k++ { 222 | octet = parser.raw_buffer[parser.raw_buffer_pos+k] 223 | 224 | // Check if the octet is valid. 225 | if (octet & 0xC0) != 0x80 { 226 | return yaml_parser_set_reader_error(parser, 227 | "invalid trailing UTF-8 octet", 228 | parser.offset+k, int(octet)) 229 | } 230 | 231 | // Decode the octet. 232 | value = (value << 6) + rune(octet&0x3F) 233 | } 234 | 235 | // Check the length of the sequence against the value. 236 | switch { 237 | case width == 1: 238 | case width == 2 && value >= 0x80: 239 | case width == 3 && value >= 0x800: 240 | case width == 4 && value >= 0x10000: 241 | default: 242 | return yaml_parser_set_reader_error(parser, 243 | "invalid length of a UTF-8 sequence", 244 | parser.offset, -1) 245 | } 246 | 247 | // Check the range of the value. 248 | if value >= 0xD800 && value <= 0xDFFF || value > 0x10FFFF { 249 | return yaml_parser_set_reader_error(parser, 250 | "invalid Unicode character", 251 | parser.offset, int(value)) 252 | } 253 | 254 | case yaml_UTF16LE_ENCODING, yaml_UTF16BE_ENCODING: 255 | var low, high int 256 | if parser.encoding == yaml_UTF16LE_ENCODING { 257 | low, high = 0, 1 258 | } else { 259 | low, high = 1, 0 260 | } 261 | 262 | // The UTF-16 encoding is not as simple as one might 263 | // naively think. Check RFC 2781 264 | // (http://www.ietf.org/rfc/rfc2781.txt). 265 | // 266 | // Normally, two subsequent bytes describe a Unicode 267 | // character. However a special technique (called a 268 | // surrogate pair) is used for specifying character 269 | // values larger than 0xFFFF. 270 | // 271 | // A surrogate pair consists of two pseudo-characters: 272 | // high surrogate area (0xD800-0xDBFF) 273 | // low surrogate area (0xDC00-0xDFFF) 274 | // 275 | // The following formulas are used for decoding 276 | // and encoding characters using surrogate pairs: 277 | // 278 | // U = U' + 0x10000 (0x01 00 00 <= U <= 0x10 FF FF) 279 | // U' = yyyyyyyyyyxxxxxxxxxx (0 <= U' <= 0x0F FF FF) 280 | // W1 = 110110yyyyyyyyyy 281 | // W2 = 110111xxxxxxxxxx 282 | // 283 | // where U is the character value, W1 is the high surrogate 284 | // area, W2 is the low surrogate area. 285 | 286 | // Check for incomplete UTF-16 character. 287 | if raw_unread < 2 { 288 | if parser.eof { 289 | return yaml_parser_set_reader_error(parser, 290 | "incomplete UTF-16 character", 291 | parser.offset, -1) 292 | } 293 | break inner 294 | } 295 | 296 | // Get the character. 297 | value = rune(parser.raw_buffer[parser.raw_buffer_pos+low]) + 298 | (rune(parser.raw_buffer[parser.raw_buffer_pos+high]) << 8) 299 | 300 | // Check for unexpected low surrogate area. 301 | if value&0xFC00 == 0xDC00 { 302 | return yaml_parser_set_reader_error(parser, 303 | "unexpected low surrogate area", 304 | parser.offset, int(value)) 305 | } 306 | 307 | // Check for a high surrogate area. 308 | if value&0xFC00 == 0xD800 { 309 | width = 4 310 | 311 | // Check for incomplete surrogate pair. 312 | if raw_unread < 4 { 313 | if parser.eof { 314 | return yaml_parser_set_reader_error(parser, 315 | "incomplete UTF-16 surrogate pair", 316 | parser.offset, -1) 317 | } 318 | break inner 319 | } 320 | 321 | // Get the next character. 322 | value2 := rune(parser.raw_buffer[parser.raw_buffer_pos+low+2]) + 323 | (rune(parser.raw_buffer[parser.raw_buffer_pos+high+2]) << 8) 324 | 325 | // Check for a low surrogate area. 326 | if value2&0xFC00 != 0xDC00 { 327 | return yaml_parser_set_reader_error(parser, 328 | "expected low surrogate area", 329 | parser.offset+2, int(value2)) 330 | } 331 | 332 | // Generate the value of the surrogate pair. 333 | value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF) 334 | } else { 335 | width = 2 336 | } 337 | 338 | default: 339 | panic("impossible") 340 | } 341 | 342 | // Check if the character is in the allowed range: 343 | // #x9 | #xA | #xD | [#x20-#x7E] (8 bit) 344 | // | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD] (16 bit) 345 | // | [#x10000-#x10FFFF] (32 bit) 346 | switch { 347 | case value == 0x09: 348 | case value == 0x0A: 349 | case value == 0x0D: 350 | case value >= 0x20 && value <= 0x7E: 351 | case value == 0x85: 352 | case value >= 0xA0 && value <= 0xD7FF: 353 | case value >= 0xE000 && value <= 0xFFFD: 354 | case value >= 0x10000 && value <= 0x10FFFF: 355 | default: 356 | return yaml_parser_set_reader_error(parser, 357 | "control characters are not allowed", 358 | parser.offset, int(value)) 359 | } 360 | 361 | // Move the raw pointers. 362 | parser.raw_buffer_pos += width 363 | parser.offset += width 364 | 365 | // Finally put the character into the buffer. 366 | if value <= 0x7F { 367 | // 0000 0000-0000 007F . 0xxxxxxx 368 | parser.buffer[buffer_len+0] = byte(value) 369 | buffer_len += 1 370 | } else if value <= 0x7FF { 371 | // 0000 0080-0000 07FF . 110xxxxx 10xxxxxx 372 | parser.buffer[buffer_len+0] = byte(0xC0 + (value >> 6)) 373 | parser.buffer[buffer_len+1] = byte(0x80 + (value & 0x3F)) 374 | buffer_len += 2 375 | } else if value <= 0xFFFF { 376 | // 0000 0800-0000 FFFF . 1110xxxx 10xxxxxx 10xxxxxx 377 | parser.buffer[buffer_len+0] = byte(0xE0 + (value >> 12)) 378 | parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 6) & 0x3F)) 379 | parser.buffer[buffer_len+2] = byte(0x80 + (value & 0x3F)) 380 | buffer_len += 3 381 | } else { 382 | // 0001 0000-0010 FFFF . 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 383 | parser.buffer[buffer_len+0] = byte(0xF0 + (value >> 18)) 384 | parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 12) & 0x3F)) 385 | parser.buffer[buffer_len+2] = byte(0x80 + ((value >> 6) & 0x3F)) 386 | parser.buffer[buffer_len+3] = byte(0x80 + (value & 0x3F)) 387 | buffer_len += 4 388 | } 389 | 390 | parser.unread++ 391 | } 392 | 393 | // On EOF, put NUL into the buffer and return. 394 | if parser.eof { 395 | parser.buffer[buffer_len] = 0 396 | buffer_len++ 397 | parser.unread++ 398 | break 399 | } 400 | } 401 | // [Go] Read the documentation of this function above. To return true, 402 | // we need to have the given length in the buffer. Not doing that means 403 | // every single check that calls this function to make sure the buffer 404 | // has a given length is Go) panicking; or C) accessing invalid memory. 405 | // This happens here due to the EOF above breaking early. 406 | for buffer_len < length { 407 | parser.buffer[buffer_len] = 0 408 | buffer_len++ 409 | } 410 | parser.buffer = parser.buffer[:buffer_len] 411 | return true 412 | } 413 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v2/yaml.go: -------------------------------------------------------------------------------- 1 | // Package yaml implements YAML support for the Go language. 2 | // 3 | // Source code and other details for the project are available at GitHub: 4 | // 5 | // https://github.com/go-yaml/yaml 6 | // 7 | package yaml 8 | 9 | import ( 10 | "errors" 11 | "fmt" 12 | "io" 13 | "reflect" 14 | "strings" 15 | "sync" 16 | ) 17 | 18 | // MapSlice encodes and decodes as a YAML map. 19 | // The order of keys is preserved when encoding and decoding. 20 | type MapSlice []MapItem 21 | 22 | // MapItem is an item in a MapSlice. 23 | type MapItem struct { 24 | Key, Value interface{} 25 | } 26 | 27 | // The Unmarshaler interface may be implemented by types to customize their 28 | // behavior when being unmarshaled from a YAML document. The UnmarshalYAML 29 | // method receives a function that may be called to unmarshal the original 30 | // YAML value into a field or variable. It is safe to call the unmarshal 31 | // function parameter more than once if necessary. 32 | type Unmarshaler interface { 33 | UnmarshalYAML(unmarshal func(interface{}) error) error 34 | } 35 | 36 | // The Marshaler interface may be implemented by types to customize their 37 | // behavior when being marshaled into a YAML document. The returned value 38 | // is marshaled in place of the original value implementing Marshaler. 39 | // 40 | // If an error is returned by MarshalYAML, the marshaling procedure stops 41 | // and returns with the provided error. 42 | type Marshaler interface { 43 | MarshalYAML() (interface{}, error) 44 | } 45 | 46 | // Unmarshal decodes the first document found within the in byte slice 47 | // and assigns decoded values into the out value. 48 | // 49 | // Maps and pointers (to a struct, string, int, etc) are accepted as out 50 | // values. If an internal pointer within a struct is not initialized, 51 | // the yaml package will initialize it if necessary for unmarshalling 52 | // the provided data. The out parameter must not be nil. 53 | // 54 | // The type of the decoded values should be compatible with the respective 55 | // values in out. If one or more values cannot be decoded due to a type 56 | // mismatches, decoding continues partially until the end of the YAML 57 | // content, and a *yaml.TypeError is returned with details for all 58 | // missed values. 59 | // 60 | // Struct fields are only unmarshalled if they are exported (have an 61 | // upper case first letter), and are unmarshalled using the field name 62 | // lowercased as the default key. Custom keys may be defined via the 63 | // "yaml" name in the field tag: the content preceding the first comma 64 | // is used as the key, and the following comma-separated options are 65 | // used to tweak the marshalling process (see Marshal). 66 | // Conflicting names result in a runtime error. 67 | // 68 | // For example: 69 | // 70 | // type T struct { 71 | // F int `yaml:"a,omitempty"` 72 | // B int 73 | // } 74 | // var t T 75 | // yaml.Unmarshal([]byte("a: 1\nb: 2"), &t) 76 | // 77 | // See the documentation of Marshal for the format of tags and a list of 78 | // supported tag options. 79 | // 80 | func Unmarshal(in []byte, out interface{}) (err error) { 81 | return unmarshal(in, out, false) 82 | } 83 | 84 | // UnmarshalStrict is like Unmarshal except that any fields that are found 85 | // in the data that do not have corresponding struct members, or mapping 86 | // keys that are duplicates, will result in 87 | // an error. 88 | func UnmarshalStrict(in []byte, out interface{}) (err error) { 89 | return unmarshal(in, out, true) 90 | } 91 | 92 | // A Decorder reads and decodes YAML values from an input stream. 93 | type Decoder struct { 94 | strict bool 95 | parser *parser 96 | } 97 | 98 | // NewDecoder returns a new decoder that reads from r. 99 | // 100 | // The decoder introduces its own buffering and may read 101 | // data from r beyond the YAML values requested. 102 | func NewDecoder(r io.Reader) *Decoder { 103 | return &Decoder{ 104 | parser: newParserFromReader(r), 105 | } 106 | } 107 | 108 | // SetStrict sets whether strict decoding behaviour is enabled when 109 | // decoding items in the data (see UnmarshalStrict). By default, decoding is not strict. 110 | func (dec *Decoder) SetStrict(strict bool) { 111 | dec.strict = strict 112 | } 113 | 114 | // Decode reads the next YAML-encoded value from its input 115 | // and stores it in the value pointed to by v. 116 | // 117 | // See the documentation for Unmarshal for details about the 118 | // conversion of YAML into a Go value. 119 | func (dec *Decoder) Decode(v interface{}) (err error) { 120 | d := newDecoder(dec.strict) 121 | defer handleErr(&err) 122 | node := dec.parser.parse() 123 | if node == nil { 124 | return io.EOF 125 | } 126 | out := reflect.ValueOf(v) 127 | if out.Kind() == reflect.Ptr && !out.IsNil() { 128 | out = out.Elem() 129 | } 130 | d.unmarshal(node, out) 131 | if len(d.terrors) > 0 { 132 | return &TypeError{d.terrors} 133 | } 134 | return nil 135 | } 136 | 137 | func unmarshal(in []byte, out interface{}, strict bool) (err error) { 138 | defer handleErr(&err) 139 | d := newDecoder(strict) 140 | p := newParser(in) 141 | defer p.destroy() 142 | node := p.parse() 143 | if node != nil { 144 | v := reflect.ValueOf(out) 145 | if v.Kind() == reflect.Ptr && !v.IsNil() { 146 | v = v.Elem() 147 | } 148 | d.unmarshal(node, v) 149 | } 150 | if len(d.terrors) > 0 { 151 | return &TypeError{d.terrors} 152 | } 153 | return nil 154 | } 155 | 156 | // Marshal serializes the value provided into a YAML document. The structure 157 | // of the generated document will reflect the structure of the value itself. 158 | // Maps and pointers (to struct, string, int, etc) are accepted as the in value. 159 | // 160 | // Struct fields are only marshalled if they are exported (have an upper case 161 | // first letter), and are marshalled using the field name lowercased as the 162 | // default key. Custom keys may be defined via the "yaml" name in the field 163 | // tag: the content preceding the first comma is used as the key, and the 164 | // following comma-separated options are used to tweak the marshalling process. 165 | // Conflicting names result in a runtime error. 166 | // 167 | // The field tag format accepted is: 168 | // 169 | // `(...) yaml:"[][,[,]]" (...)` 170 | // 171 | // The following flags are currently supported: 172 | // 173 | // omitempty Only include the field if it's not set to the zero 174 | // value for the type or to empty slices or maps. 175 | // Zero valued structs will be omitted if all their public 176 | // fields are zero, unless they implement an IsZero 177 | // method (see the IsZeroer interface type), in which 178 | // case the field will be included if that method returns true. 179 | // 180 | // flow Marshal using a flow style (useful for structs, 181 | // sequences and maps). 182 | // 183 | // inline Inline the field, which must be a struct or a map, 184 | // causing all of its fields or keys to be processed as if 185 | // they were part of the outer struct. For maps, keys must 186 | // not conflict with the yaml keys of other struct fields. 187 | // 188 | // In addition, if the key is "-", the field is ignored. 189 | // 190 | // For example: 191 | // 192 | // type T struct { 193 | // F int `yaml:"a,omitempty"` 194 | // B int 195 | // } 196 | // yaml.Marshal(&T{B: 2}) // Returns "b: 2\n" 197 | // yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n" 198 | // 199 | func Marshal(in interface{}) (out []byte, err error) { 200 | defer handleErr(&err) 201 | e := newEncoder() 202 | defer e.destroy() 203 | e.marshalDoc("", reflect.ValueOf(in)) 204 | e.finish() 205 | out = e.out 206 | return 207 | } 208 | 209 | // An Encoder writes YAML values to an output stream. 210 | type Encoder struct { 211 | encoder *encoder 212 | } 213 | 214 | // NewEncoder returns a new encoder that writes to w. 215 | // The Encoder should be closed after use to flush all data 216 | // to w. 217 | func NewEncoder(w io.Writer) *Encoder { 218 | return &Encoder{ 219 | encoder: newEncoderWithWriter(w), 220 | } 221 | } 222 | 223 | // Encode writes the YAML encoding of v to the stream. 224 | // If multiple items are encoded to the stream, the 225 | // second and subsequent document will be preceded 226 | // with a "---" document separator, but the first will not. 227 | // 228 | // See the documentation for Marshal for details about the conversion of Go 229 | // values to YAML. 230 | func (e *Encoder) Encode(v interface{}) (err error) { 231 | defer handleErr(&err) 232 | e.encoder.marshalDoc("", reflect.ValueOf(v)) 233 | return nil 234 | } 235 | 236 | // Close closes the encoder by writing any remaining data. 237 | // It does not write a stream terminating string "...". 238 | func (e *Encoder) Close() (err error) { 239 | defer handleErr(&err) 240 | e.encoder.finish() 241 | return nil 242 | } 243 | 244 | func handleErr(err *error) { 245 | if v := recover(); v != nil { 246 | if e, ok := v.(yamlError); ok { 247 | *err = e.err 248 | } else { 249 | panic(v) 250 | } 251 | } 252 | } 253 | 254 | type yamlError struct { 255 | err error 256 | } 257 | 258 | func fail(err error) { 259 | panic(yamlError{err}) 260 | } 261 | 262 | func failf(format string, args ...interface{}) { 263 | panic(yamlError{fmt.Errorf("yaml: "+format, args...)}) 264 | } 265 | 266 | // A TypeError is returned by Unmarshal when one or more fields in 267 | // the YAML document cannot be properly decoded into the requested 268 | // types. When this error is returned, the value is still 269 | // unmarshaled partially. 270 | type TypeError struct { 271 | Errors []string 272 | } 273 | 274 | func (e *TypeError) Error() string { 275 | return fmt.Sprintf("yaml: unmarshal errors:\n %s", strings.Join(e.Errors, "\n ")) 276 | } 277 | 278 | // -------------------------------------------------------------------------- 279 | // Maintain a mapping of keys to structure field indexes 280 | 281 | // The code in this section was copied from mgo/bson. 282 | 283 | // structInfo holds details for the serialization of fields of 284 | // a given struct. 285 | type structInfo struct { 286 | FieldsMap map[string]fieldInfo 287 | FieldsList []fieldInfo 288 | 289 | // InlineMap is the number of the field in the struct that 290 | // contains an ,inline map, or -1 if there's none. 291 | InlineMap int 292 | } 293 | 294 | type fieldInfo struct { 295 | Key string 296 | Num int 297 | OmitEmpty bool 298 | Flow bool 299 | // Id holds the unique field identifier, so we can cheaply 300 | // check for field duplicates without maintaining an extra map. 301 | Id int 302 | 303 | // Inline holds the field index if the field is part of an inlined struct. 304 | Inline []int 305 | } 306 | 307 | var structMap = make(map[reflect.Type]*structInfo) 308 | var fieldMapMutex sync.RWMutex 309 | 310 | func getStructInfo(st reflect.Type) (*structInfo, error) { 311 | fieldMapMutex.RLock() 312 | sinfo, found := structMap[st] 313 | fieldMapMutex.RUnlock() 314 | if found { 315 | return sinfo, nil 316 | } 317 | 318 | n := st.NumField() 319 | fieldsMap := make(map[string]fieldInfo) 320 | fieldsList := make([]fieldInfo, 0, n) 321 | inlineMap := -1 322 | for i := 0; i != n; i++ { 323 | field := st.Field(i) 324 | if field.PkgPath != "" && !field.Anonymous { 325 | continue // Private field 326 | } 327 | 328 | info := fieldInfo{Num: i} 329 | 330 | tag := field.Tag.Get("yaml") 331 | if tag == "" && strings.Index(string(field.Tag), ":") < 0 { 332 | tag = string(field.Tag) 333 | } 334 | if tag == "-" { 335 | continue 336 | } 337 | 338 | inline := false 339 | fields := strings.Split(tag, ",") 340 | if len(fields) > 1 { 341 | for _, flag := range fields[1:] { 342 | switch flag { 343 | case "omitempty": 344 | info.OmitEmpty = true 345 | case "flow": 346 | info.Flow = true 347 | case "inline": 348 | inline = true 349 | default: 350 | return nil, errors.New(fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st)) 351 | } 352 | } 353 | tag = fields[0] 354 | } 355 | 356 | if inline { 357 | switch field.Type.Kind() { 358 | case reflect.Map: 359 | if inlineMap >= 0 { 360 | return nil, errors.New("Multiple ,inline maps in struct " + st.String()) 361 | } 362 | if field.Type.Key() != reflect.TypeOf("") { 363 | return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String()) 364 | } 365 | inlineMap = info.Num 366 | case reflect.Struct: 367 | sinfo, err := getStructInfo(field.Type) 368 | if err != nil { 369 | return nil, err 370 | } 371 | for _, finfo := range sinfo.FieldsList { 372 | if _, found := fieldsMap[finfo.Key]; found { 373 | msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String() 374 | return nil, errors.New(msg) 375 | } 376 | if finfo.Inline == nil { 377 | finfo.Inline = []int{i, finfo.Num} 378 | } else { 379 | finfo.Inline = append([]int{i}, finfo.Inline...) 380 | } 381 | finfo.Id = len(fieldsList) 382 | fieldsMap[finfo.Key] = finfo 383 | fieldsList = append(fieldsList, finfo) 384 | } 385 | default: 386 | //return nil, errors.New("Option ,inline needs a struct value or map field") 387 | return nil, errors.New("Option ,inline needs a struct value field") 388 | } 389 | continue 390 | } 391 | 392 | if tag != "" { 393 | info.Key = tag 394 | } else { 395 | info.Key = strings.ToLower(field.Name) 396 | } 397 | 398 | if _, found = fieldsMap[info.Key]; found { 399 | msg := "Duplicated key '" + info.Key + "' in struct " + st.String() 400 | return nil, errors.New(msg) 401 | } 402 | 403 | info.Id = len(fieldsList) 404 | fieldsList = append(fieldsList, info) 405 | fieldsMap[info.Key] = info 406 | } 407 | 408 | sinfo = &structInfo{ 409 | FieldsMap: fieldsMap, 410 | FieldsList: fieldsList, 411 | InlineMap: inlineMap, 412 | } 413 | 414 | fieldMapMutex.Lock() 415 | structMap[st] = sinfo 416 | fieldMapMutex.Unlock() 417 | return sinfo, nil 418 | } 419 | 420 | // IsZeroer is used to check whether an object is zero to 421 | // determine whether it should be omitted when marshaling 422 | // with the omitempty flag. One notable implementation 423 | // is time.Time. 424 | type IsZeroer interface { 425 | IsZero() bool 426 | } 427 | 428 | func isZero(v reflect.Value) bool { 429 | kind := v.Kind() 430 | if z, ok := v.Interface().(IsZeroer); ok { 431 | if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() { 432 | return true 433 | } 434 | return z.IsZero() 435 | } 436 | switch kind { 437 | case reflect.String: 438 | return len(v.String()) == 0 439 | case reflect.Interface, reflect.Ptr: 440 | return v.IsNil() 441 | case reflect.Slice: 442 | return v.Len() == 0 443 | case reflect.Map: 444 | return v.Len() == 0 445 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 446 | return v.Int() == 0 447 | case reflect.Float32, reflect.Float64: 448 | return v.Float() == 0 449 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 450 | return v.Uint() == 0 451 | case reflect.Bool: 452 | return !v.Bool() 453 | case reflect.Struct: 454 | vt := v.Type() 455 | for i := v.NumField() - 1; i >= 0; i-- { 456 | if vt.Field(i).PkgPath != "" { 457 | continue // Private field 458 | } 459 | if !isZero(v.Field(i)) { 460 | return false 461 | } 462 | } 463 | return true 464 | } 465 | return false 466 | } 467 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v2/decode.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | import ( 4 | "encoding" 5 | "encoding/base64" 6 | "fmt" 7 | "io" 8 | "math" 9 | "reflect" 10 | "strconv" 11 | "time" 12 | ) 13 | 14 | const ( 15 | documentNode = 1 << iota 16 | mappingNode 17 | sequenceNode 18 | scalarNode 19 | aliasNode 20 | ) 21 | 22 | type node struct { 23 | kind int 24 | line, column int 25 | tag string 26 | // For an alias node, alias holds the resolved alias. 27 | alias *node 28 | value string 29 | implicit bool 30 | children []*node 31 | anchors map[string]*node 32 | } 33 | 34 | // ---------------------------------------------------------------------------- 35 | // Parser, produces a node tree out of a libyaml event stream. 36 | 37 | type parser struct { 38 | parser yaml_parser_t 39 | event yaml_event_t 40 | doc *node 41 | doneInit bool 42 | } 43 | 44 | func newParser(b []byte) *parser { 45 | p := parser{} 46 | if !yaml_parser_initialize(&p.parser) { 47 | panic("failed to initialize YAML emitter") 48 | } 49 | if len(b) == 0 { 50 | b = []byte{'\n'} 51 | } 52 | yaml_parser_set_input_string(&p.parser, b) 53 | return &p 54 | } 55 | 56 | func newParserFromReader(r io.Reader) *parser { 57 | p := parser{} 58 | if !yaml_parser_initialize(&p.parser) { 59 | panic("failed to initialize YAML emitter") 60 | } 61 | yaml_parser_set_input_reader(&p.parser, r) 62 | return &p 63 | } 64 | 65 | func (p *parser) init() { 66 | if p.doneInit { 67 | return 68 | } 69 | p.expect(yaml_STREAM_START_EVENT) 70 | p.doneInit = true 71 | } 72 | 73 | func (p *parser) destroy() { 74 | if p.event.typ != yaml_NO_EVENT { 75 | yaml_event_delete(&p.event) 76 | } 77 | yaml_parser_delete(&p.parser) 78 | } 79 | 80 | // expect consumes an event from the event stream and 81 | // checks that it's of the expected type. 82 | func (p *parser) expect(e yaml_event_type_t) { 83 | if p.event.typ == yaml_NO_EVENT { 84 | if !yaml_parser_parse(&p.parser, &p.event) { 85 | p.fail() 86 | } 87 | } 88 | if p.event.typ == yaml_STREAM_END_EVENT { 89 | failf("attempted to go past the end of stream; corrupted value?") 90 | } 91 | if p.event.typ != e { 92 | p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ) 93 | p.fail() 94 | } 95 | yaml_event_delete(&p.event) 96 | p.event.typ = yaml_NO_EVENT 97 | } 98 | 99 | // peek peeks at the next event in the event stream, 100 | // puts the results into p.event and returns the event type. 101 | func (p *parser) peek() yaml_event_type_t { 102 | if p.event.typ != yaml_NO_EVENT { 103 | return p.event.typ 104 | } 105 | if !yaml_parser_parse(&p.parser, &p.event) { 106 | p.fail() 107 | } 108 | return p.event.typ 109 | } 110 | 111 | func (p *parser) fail() { 112 | var where string 113 | var line int 114 | if p.parser.problem_mark.line != 0 { 115 | line = p.parser.problem_mark.line 116 | // Scanner errors don't iterate line before returning error 117 | if p.parser.error == yaml_SCANNER_ERROR { 118 | line++ 119 | } 120 | } else if p.parser.context_mark.line != 0 { 121 | line = p.parser.context_mark.line 122 | } 123 | if line != 0 { 124 | where = "line " + strconv.Itoa(line) + ": " 125 | } 126 | var msg string 127 | if len(p.parser.problem) > 0 { 128 | msg = p.parser.problem 129 | } else { 130 | msg = "unknown problem parsing YAML content" 131 | } 132 | failf("%s%s", where, msg) 133 | } 134 | 135 | func (p *parser) anchor(n *node, anchor []byte) { 136 | if anchor != nil { 137 | p.doc.anchors[string(anchor)] = n 138 | } 139 | } 140 | 141 | func (p *parser) parse() *node { 142 | p.init() 143 | switch p.peek() { 144 | case yaml_SCALAR_EVENT: 145 | return p.scalar() 146 | case yaml_ALIAS_EVENT: 147 | return p.alias() 148 | case yaml_MAPPING_START_EVENT: 149 | return p.mapping() 150 | case yaml_SEQUENCE_START_EVENT: 151 | return p.sequence() 152 | case yaml_DOCUMENT_START_EVENT: 153 | return p.document() 154 | case yaml_STREAM_END_EVENT: 155 | // Happens when attempting to decode an empty buffer. 156 | return nil 157 | default: 158 | panic("attempted to parse unknown event: " + p.event.typ.String()) 159 | } 160 | } 161 | 162 | func (p *parser) node(kind int) *node { 163 | return &node{ 164 | kind: kind, 165 | line: p.event.start_mark.line, 166 | column: p.event.start_mark.column, 167 | } 168 | } 169 | 170 | func (p *parser) document() *node { 171 | n := p.node(documentNode) 172 | n.anchors = make(map[string]*node) 173 | p.doc = n 174 | p.expect(yaml_DOCUMENT_START_EVENT) 175 | n.children = append(n.children, p.parse()) 176 | p.expect(yaml_DOCUMENT_END_EVENT) 177 | return n 178 | } 179 | 180 | func (p *parser) alias() *node { 181 | n := p.node(aliasNode) 182 | n.value = string(p.event.anchor) 183 | n.alias = p.doc.anchors[n.value] 184 | if n.alias == nil { 185 | failf("unknown anchor '%s' referenced", n.value) 186 | } 187 | p.expect(yaml_ALIAS_EVENT) 188 | return n 189 | } 190 | 191 | func (p *parser) scalar() *node { 192 | n := p.node(scalarNode) 193 | n.value = string(p.event.value) 194 | n.tag = string(p.event.tag) 195 | n.implicit = p.event.implicit 196 | p.anchor(n, p.event.anchor) 197 | p.expect(yaml_SCALAR_EVENT) 198 | return n 199 | } 200 | 201 | func (p *parser) sequence() *node { 202 | n := p.node(sequenceNode) 203 | p.anchor(n, p.event.anchor) 204 | p.expect(yaml_SEQUENCE_START_EVENT) 205 | for p.peek() != yaml_SEQUENCE_END_EVENT { 206 | n.children = append(n.children, p.parse()) 207 | } 208 | p.expect(yaml_SEQUENCE_END_EVENT) 209 | return n 210 | } 211 | 212 | func (p *parser) mapping() *node { 213 | n := p.node(mappingNode) 214 | p.anchor(n, p.event.anchor) 215 | p.expect(yaml_MAPPING_START_EVENT) 216 | for p.peek() != yaml_MAPPING_END_EVENT { 217 | n.children = append(n.children, p.parse(), p.parse()) 218 | } 219 | p.expect(yaml_MAPPING_END_EVENT) 220 | return n 221 | } 222 | 223 | // ---------------------------------------------------------------------------- 224 | // Decoder, unmarshals a node into a provided value. 225 | 226 | type decoder struct { 227 | doc *node 228 | aliases map[*node]bool 229 | mapType reflect.Type 230 | terrors []string 231 | strict bool 232 | } 233 | 234 | var ( 235 | mapItemType = reflect.TypeOf(MapItem{}) 236 | durationType = reflect.TypeOf(time.Duration(0)) 237 | defaultMapType = reflect.TypeOf(map[interface{}]interface{}{}) 238 | ifaceType = defaultMapType.Elem() 239 | timeType = reflect.TypeOf(time.Time{}) 240 | ptrTimeType = reflect.TypeOf(&time.Time{}) 241 | ) 242 | 243 | func newDecoder(strict bool) *decoder { 244 | d := &decoder{mapType: defaultMapType, strict: strict} 245 | d.aliases = make(map[*node]bool) 246 | return d 247 | } 248 | 249 | func (d *decoder) terror(n *node, tag string, out reflect.Value) { 250 | if n.tag != "" { 251 | tag = n.tag 252 | } 253 | value := n.value 254 | if tag != yaml_SEQ_TAG && tag != yaml_MAP_TAG { 255 | if len(value) > 10 { 256 | value = " `" + value[:7] + "...`" 257 | } else { 258 | value = " `" + value + "`" 259 | } 260 | } 261 | d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.line+1, shortTag(tag), value, out.Type())) 262 | } 263 | 264 | func (d *decoder) callUnmarshaler(n *node, u Unmarshaler) (good bool) { 265 | terrlen := len(d.terrors) 266 | err := u.UnmarshalYAML(func(v interface{}) (err error) { 267 | defer handleErr(&err) 268 | d.unmarshal(n, reflect.ValueOf(v)) 269 | if len(d.terrors) > terrlen { 270 | issues := d.terrors[terrlen:] 271 | d.terrors = d.terrors[:terrlen] 272 | return &TypeError{issues} 273 | } 274 | return nil 275 | }) 276 | if e, ok := err.(*TypeError); ok { 277 | d.terrors = append(d.terrors, e.Errors...) 278 | return false 279 | } 280 | if err != nil { 281 | fail(err) 282 | } 283 | return true 284 | } 285 | 286 | // d.prepare initializes and dereferences pointers and calls UnmarshalYAML 287 | // if a value is found to implement it. 288 | // It returns the initialized and dereferenced out value, whether 289 | // unmarshalling was already done by UnmarshalYAML, and if so whether 290 | // its types unmarshalled appropriately. 291 | // 292 | // If n holds a null value, prepare returns before doing anything. 293 | func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) { 294 | if n.tag == yaml_NULL_TAG || n.kind == scalarNode && n.tag == "" && (n.value == "null" || n.value == "~" || n.value == "" && n.implicit) { 295 | return out, false, false 296 | } 297 | again := true 298 | for again { 299 | again = false 300 | if out.Kind() == reflect.Ptr { 301 | if out.IsNil() { 302 | out.Set(reflect.New(out.Type().Elem())) 303 | } 304 | out = out.Elem() 305 | again = true 306 | } 307 | if out.CanAddr() { 308 | if u, ok := out.Addr().Interface().(Unmarshaler); ok { 309 | good = d.callUnmarshaler(n, u) 310 | return out, true, good 311 | } 312 | } 313 | } 314 | return out, false, false 315 | } 316 | 317 | func (d *decoder) unmarshal(n *node, out reflect.Value) (good bool) { 318 | switch n.kind { 319 | case documentNode: 320 | return d.document(n, out) 321 | case aliasNode: 322 | return d.alias(n, out) 323 | } 324 | out, unmarshaled, good := d.prepare(n, out) 325 | if unmarshaled { 326 | return good 327 | } 328 | switch n.kind { 329 | case scalarNode: 330 | good = d.scalar(n, out) 331 | case mappingNode: 332 | good = d.mapping(n, out) 333 | case sequenceNode: 334 | good = d.sequence(n, out) 335 | default: 336 | panic("internal error: unknown node kind: " + strconv.Itoa(n.kind)) 337 | } 338 | return good 339 | } 340 | 341 | func (d *decoder) document(n *node, out reflect.Value) (good bool) { 342 | if len(n.children) == 1 { 343 | d.doc = n 344 | d.unmarshal(n.children[0], out) 345 | return true 346 | } 347 | return false 348 | } 349 | 350 | func (d *decoder) alias(n *node, out reflect.Value) (good bool) { 351 | if d.aliases[n] { 352 | // TODO this could actually be allowed in some circumstances. 353 | failf("anchor '%s' value contains itself", n.value) 354 | } 355 | d.aliases[n] = true 356 | good = d.unmarshal(n.alias, out) 357 | delete(d.aliases, n) 358 | return good 359 | } 360 | 361 | var zeroValue reflect.Value 362 | 363 | func resetMap(out reflect.Value) { 364 | for _, k := range out.MapKeys() { 365 | out.SetMapIndex(k, zeroValue) 366 | } 367 | } 368 | 369 | func (d *decoder) scalar(n *node, out reflect.Value) bool { 370 | var tag string 371 | var resolved interface{} 372 | if n.tag == "" && !n.implicit { 373 | tag = yaml_STR_TAG 374 | resolved = n.value 375 | } else { 376 | tag, resolved = resolve(n.tag, n.value) 377 | if tag == yaml_BINARY_TAG { 378 | data, err := base64.StdEncoding.DecodeString(resolved.(string)) 379 | if err != nil { 380 | failf("!!binary value contains invalid base64 data") 381 | } 382 | resolved = string(data) 383 | } 384 | } 385 | if resolved == nil { 386 | if out.Kind() == reflect.Map && !out.CanAddr() { 387 | resetMap(out) 388 | } else { 389 | out.Set(reflect.Zero(out.Type())) 390 | } 391 | return true 392 | } 393 | if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() { 394 | // We've resolved to exactly the type we want, so use that. 395 | out.Set(resolvedv) 396 | return true 397 | } 398 | // Perhaps we can use the value as a TextUnmarshaler to 399 | // set its value. 400 | if out.CanAddr() { 401 | u, ok := out.Addr().Interface().(encoding.TextUnmarshaler) 402 | if ok { 403 | var text []byte 404 | if tag == yaml_BINARY_TAG { 405 | text = []byte(resolved.(string)) 406 | } else { 407 | // We let any value be unmarshaled into TextUnmarshaler. 408 | // That might be more lax than we'd like, but the 409 | // TextUnmarshaler itself should bowl out any dubious values. 410 | text = []byte(n.value) 411 | } 412 | err := u.UnmarshalText(text) 413 | if err != nil { 414 | fail(err) 415 | } 416 | return true 417 | } 418 | } 419 | switch out.Kind() { 420 | case reflect.String: 421 | if tag == yaml_BINARY_TAG { 422 | out.SetString(resolved.(string)) 423 | return true 424 | } 425 | if resolved != nil { 426 | out.SetString(n.value) 427 | return true 428 | } 429 | case reflect.Interface: 430 | if resolved == nil { 431 | out.Set(reflect.Zero(out.Type())) 432 | } else if tag == yaml_TIMESTAMP_TAG { 433 | // It looks like a timestamp but for backward compatibility 434 | // reasons we set it as a string, so that code that unmarshals 435 | // timestamp-like values into interface{} will continue to 436 | // see a string and not a time.Time. 437 | // TODO(v3) Drop this. 438 | out.Set(reflect.ValueOf(n.value)) 439 | } else { 440 | out.Set(reflect.ValueOf(resolved)) 441 | } 442 | return true 443 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 444 | switch resolved := resolved.(type) { 445 | case int: 446 | if !out.OverflowInt(int64(resolved)) { 447 | out.SetInt(int64(resolved)) 448 | return true 449 | } 450 | case int64: 451 | if !out.OverflowInt(resolved) { 452 | out.SetInt(resolved) 453 | return true 454 | } 455 | case uint64: 456 | if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) { 457 | out.SetInt(int64(resolved)) 458 | return true 459 | } 460 | case float64: 461 | if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) { 462 | out.SetInt(int64(resolved)) 463 | return true 464 | } 465 | case string: 466 | if out.Type() == durationType { 467 | d, err := time.ParseDuration(resolved) 468 | if err == nil { 469 | out.SetInt(int64(d)) 470 | return true 471 | } 472 | } 473 | } 474 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 475 | switch resolved := resolved.(type) { 476 | case int: 477 | if resolved >= 0 && !out.OverflowUint(uint64(resolved)) { 478 | out.SetUint(uint64(resolved)) 479 | return true 480 | } 481 | case int64: 482 | if resolved >= 0 && !out.OverflowUint(uint64(resolved)) { 483 | out.SetUint(uint64(resolved)) 484 | return true 485 | } 486 | case uint64: 487 | if !out.OverflowUint(uint64(resolved)) { 488 | out.SetUint(uint64(resolved)) 489 | return true 490 | } 491 | case float64: 492 | if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) { 493 | out.SetUint(uint64(resolved)) 494 | return true 495 | } 496 | } 497 | case reflect.Bool: 498 | switch resolved := resolved.(type) { 499 | case bool: 500 | out.SetBool(resolved) 501 | return true 502 | } 503 | case reflect.Float32, reflect.Float64: 504 | switch resolved := resolved.(type) { 505 | case int: 506 | out.SetFloat(float64(resolved)) 507 | return true 508 | case int64: 509 | out.SetFloat(float64(resolved)) 510 | return true 511 | case uint64: 512 | out.SetFloat(float64(resolved)) 513 | return true 514 | case float64: 515 | out.SetFloat(resolved) 516 | return true 517 | } 518 | case reflect.Struct: 519 | if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() { 520 | out.Set(resolvedv) 521 | return true 522 | } 523 | case reflect.Ptr: 524 | if out.Type().Elem() == reflect.TypeOf(resolved) { 525 | // TODO DOes this make sense? When is out a Ptr except when decoding a nil value? 526 | elem := reflect.New(out.Type().Elem()) 527 | elem.Elem().Set(reflect.ValueOf(resolved)) 528 | out.Set(elem) 529 | return true 530 | } 531 | } 532 | d.terror(n, tag, out) 533 | return false 534 | } 535 | 536 | func settableValueOf(i interface{}) reflect.Value { 537 | v := reflect.ValueOf(i) 538 | sv := reflect.New(v.Type()).Elem() 539 | sv.Set(v) 540 | return sv 541 | } 542 | 543 | func (d *decoder) sequence(n *node, out reflect.Value) (good bool) { 544 | l := len(n.children) 545 | 546 | var iface reflect.Value 547 | switch out.Kind() { 548 | case reflect.Slice: 549 | out.Set(reflect.MakeSlice(out.Type(), l, l)) 550 | case reflect.Array: 551 | if l != out.Len() { 552 | failf("invalid array: want %d elements but got %d", out.Len(), l) 553 | } 554 | case reflect.Interface: 555 | // No type hints. Will have to use a generic sequence. 556 | iface = out 557 | out = settableValueOf(make([]interface{}, l)) 558 | default: 559 | d.terror(n, yaml_SEQ_TAG, out) 560 | return false 561 | } 562 | et := out.Type().Elem() 563 | 564 | j := 0 565 | for i := 0; i < l; i++ { 566 | e := reflect.New(et).Elem() 567 | if ok := d.unmarshal(n.children[i], e); ok { 568 | out.Index(j).Set(e) 569 | j++ 570 | } 571 | } 572 | if out.Kind() != reflect.Array { 573 | out.Set(out.Slice(0, j)) 574 | } 575 | if iface.IsValid() { 576 | iface.Set(out) 577 | } 578 | return true 579 | } 580 | 581 | func (d *decoder) mapping(n *node, out reflect.Value) (good bool) { 582 | switch out.Kind() { 583 | case reflect.Struct: 584 | return d.mappingStruct(n, out) 585 | case reflect.Slice: 586 | return d.mappingSlice(n, out) 587 | case reflect.Map: 588 | // okay 589 | case reflect.Interface: 590 | if d.mapType.Kind() == reflect.Map { 591 | iface := out 592 | out = reflect.MakeMap(d.mapType) 593 | iface.Set(out) 594 | } else { 595 | slicev := reflect.New(d.mapType).Elem() 596 | if !d.mappingSlice(n, slicev) { 597 | return false 598 | } 599 | out.Set(slicev) 600 | return true 601 | } 602 | default: 603 | d.terror(n, yaml_MAP_TAG, out) 604 | return false 605 | } 606 | outt := out.Type() 607 | kt := outt.Key() 608 | et := outt.Elem() 609 | 610 | mapType := d.mapType 611 | if outt.Key() == ifaceType && outt.Elem() == ifaceType { 612 | d.mapType = outt 613 | } 614 | 615 | if out.IsNil() { 616 | out.Set(reflect.MakeMap(outt)) 617 | } 618 | l := len(n.children) 619 | for i := 0; i < l; i += 2 { 620 | if isMerge(n.children[i]) { 621 | d.merge(n.children[i+1], out) 622 | continue 623 | } 624 | k := reflect.New(kt).Elem() 625 | if d.unmarshal(n.children[i], k) { 626 | kkind := k.Kind() 627 | if kkind == reflect.Interface { 628 | kkind = k.Elem().Kind() 629 | } 630 | if kkind == reflect.Map || kkind == reflect.Slice { 631 | failf("invalid map key: %#v", k.Interface()) 632 | } 633 | e := reflect.New(et).Elem() 634 | if d.unmarshal(n.children[i+1], e) { 635 | d.setMapIndex(n.children[i+1], out, k, e) 636 | } 637 | } 638 | } 639 | d.mapType = mapType 640 | return true 641 | } 642 | 643 | func (d *decoder) setMapIndex(n *node, out, k, v reflect.Value) { 644 | if d.strict && out.MapIndex(k) != zeroValue { 645 | d.terrors = append(d.terrors, fmt.Sprintf("line %d: key %#v already set in map", n.line+1, k.Interface())) 646 | return 647 | } 648 | out.SetMapIndex(k, v) 649 | } 650 | 651 | func (d *decoder) mappingSlice(n *node, out reflect.Value) (good bool) { 652 | outt := out.Type() 653 | if outt.Elem() != mapItemType { 654 | d.terror(n, yaml_MAP_TAG, out) 655 | return false 656 | } 657 | 658 | mapType := d.mapType 659 | d.mapType = outt 660 | 661 | var slice []MapItem 662 | var l = len(n.children) 663 | for i := 0; i < l; i += 2 { 664 | if isMerge(n.children[i]) { 665 | d.merge(n.children[i+1], out) 666 | continue 667 | } 668 | item := MapItem{} 669 | k := reflect.ValueOf(&item.Key).Elem() 670 | if d.unmarshal(n.children[i], k) { 671 | v := reflect.ValueOf(&item.Value).Elem() 672 | if d.unmarshal(n.children[i+1], v) { 673 | slice = append(slice, item) 674 | } 675 | } 676 | } 677 | out.Set(reflect.ValueOf(slice)) 678 | d.mapType = mapType 679 | return true 680 | } 681 | 682 | func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) { 683 | sinfo, err := getStructInfo(out.Type()) 684 | if err != nil { 685 | panic(err) 686 | } 687 | name := settableValueOf("") 688 | l := len(n.children) 689 | 690 | var inlineMap reflect.Value 691 | var elemType reflect.Type 692 | if sinfo.InlineMap != -1 { 693 | inlineMap = out.Field(sinfo.InlineMap) 694 | inlineMap.Set(reflect.New(inlineMap.Type()).Elem()) 695 | elemType = inlineMap.Type().Elem() 696 | } 697 | 698 | var doneFields []bool 699 | if d.strict { 700 | doneFields = make([]bool, len(sinfo.FieldsList)) 701 | } 702 | for i := 0; i < l; i += 2 { 703 | ni := n.children[i] 704 | if isMerge(ni) { 705 | d.merge(n.children[i+1], out) 706 | continue 707 | } 708 | if !d.unmarshal(ni, name) { 709 | continue 710 | } 711 | if info, ok := sinfo.FieldsMap[name.String()]; ok { 712 | if d.strict { 713 | if doneFields[info.Id] { 714 | d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.line+1, name.String(), out.Type())) 715 | continue 716 | } 717 | doneFields[info.Id] = true 718 | } 719 | var field reflect.Value 720 | if info.Inline == nil { 721 | field = out.Field(info.Num) 722 | } else { 723 | field = out.FieldByIndex(info.Inline) 724 | } 725 | d.unmarshal(n.children[i+1], field) 726 | } else if sinfo.InlineMap != -1 { 727 | if inlineMap.IsNil() { 728 | inlineMap.Set(reflect.MakeMap(inlineMap.Type())) 729 | } 730 | value := reflect.New(elemType).Elem() 731 | d.unmarshal(n.children[i+1], value) 732 | d.setMapIndex(n.children[i+1], inlineMap, name, value) 733 | } else if d.strict { 734 | d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.line+1, name.String(), out.Type())) 735 | } 736 | } 737 | return true 738 | } 739 | 740 | func failWantMap() { 741 | failf("map merge requires map or sequence of maps as the value") 742 | } 743 | 744 | func (d *decoder) merge(n *node, out reflect.Value) { 745 | switch n.kind { 746 | case mappingNode: 747 | d.unmarshal(n, out) 748 | case aliasNode: 749 | an, ok := d.doc.anchors[n.value] 750 | if ok && an.kind != mappingNode { 751 | failWantMap() 752 | } 753 | d.unmarshal(n, out) 754 | case sequenceNode: 755 | // Step backwards as earlier nodes take precedence. 756 | for i := len(n.children) - 1; i >= 0; i-- { 757 | ni := n.children[i] 758 | if ni.kind == aliasNode { 759 | an, ok := d.doc.anchors[ni.value] 760 | if ok && an.kind != mappingNode { 761 | failWantMap() 762 | } 763 | } else if ni.kind != mappingNode { 764 | failWantMap() 765 | } 766 | d.unmarshal(ni, out) 767 | } 768 | default: 769 | failWantMap() 770 | } 771 | } 772 | 773 | func isMerge(n *node) bool { 774 | return n.kind == scalarNode && n.value == "<<" && (n.implicit == true || n.tag == yaml_MERGE_TAG) 775 | } 776 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v2/apic.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | import ( 4 | "io" 5 | ) 6 | 7 | func yaml_insert_token(parser *yaml_parser_t, pos int, token *yaml_token_t) { 8 | //fmt.Println("yaml_insert_token", "pos:", pos, "typ:", token.typ, "head:", parser.tokens_head, "len:", len(parser.tokens)) 9 | 10 | // Check if we can move the queue at the beginning of the buffer. 11 | if parser.tokens_head > 0 && len(parser.tokens) == cap(parser.tokens) { 12 | if parser.tokens_head != len(parser.tokens) { 13 | copy(parser.tokens, parser.tokens[parser.tokens_head:]) 14 | } 15 | parser.tokens = parser.tokens[:len(parser.tokens)-parser.tokens_head] 16 | parser.tokens_head = 0 17 | } 18 | parser.tokens = append(parser.tokens, *token) 19 | if pos < 0 { 20 | return 21 | } 22 | copy(parser.tokens[parser.tokens_head+pos+1:], parser.tokens[parser.tokens_head+pos:]) 23 | parser.tokens[parser.tokens_head+pos] = *token 24 | } 25 | 26 | // Create a new parser object. 27 | func yaml_parser_initialize(parser *yaml_parser_t) bool { 28 | *parser = yaml_parser_t{ 29 | raw_buffer: make([]byte, 0, input_raw_buffer_size), 30 | buffer: make([]byte, 0, input_buffer_size), 31 | } 32 | return true 33 | } 34 | 35 | // Destroy a parser object. 36 | func yaml_parser_delete(parser *yaml_parser_t) { 37 | *parser = yaml_parser_t{} 38 | } 39 | 40 | // String read handler. 41 | func yaml_string_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) { 42 | if parser.input_pos == len(parser.input) { 43 | return 0, io.EOF 44 | } 45 | n = copy(buffer, parser.input[parser.input_pos:]) 46 | parser.input_pos += n 47 | return n, nil 48 | } 49 | 50 | // Reader read handler. 51 | func yaml_reader_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) { 52 | return parser.input_reader.Read(buffer) 53 | } 54 | 55 | // Set a string input. 56 | func yaml_parser_set_input_string(parser *yaml_parser_t, input []byte) { 57 | if parser.read_handler != nil { 58 | panic("must set the input source only once") 59 | } 60 | parser.read_handler = yaml_string_read_handler 61 | parser.input = input 62 | parser.input_pos = 0 63 | } 64 | 65 | // Set a file input. 66 | func yaml_parser_set_input_reader(parser *yaml_parser_t, r io.Reader) { 67 | if parser.read_handler != nil { 68 | panic("must set the input source only once") 69 | } 70 | parser.read_handler = yaml_reader_read_handler 71 | parser.input_reader = r 72 | } 73 | 74 | // Set the source encoding. 75 | func yaml_parser_set_encoding(parser *yaml_parser_t, encoding yaml_encoding_t) { 76 | if parser.encoding != yaml_ANY_ENCODING { 77 | panic("must set the encoding only once") 78 | } 79 | parser.encoding = encoding 80 | } 81 | 82 | // Create a new emitter object. 83 | func yaml_emitter_initialize(emitter *yaml_emitter_t) { 84 | *emitter = yaml_emitter_t{ 85 | buffer: make([]byte, output_buffer_size), 86 | raw_buffer: make([]byte, 0, output_raw_buffer_size), 87 | states: make([]yaml_emitter_state_t, 0, initial_stack_size), 88 | events: make([]yaml_event_t, 0, initial_queue_size), 89 | } 90 | } 91 | 92 | // Destroy an emitter object. 93 | func yaml_emitter_delete(emitter *yaml_emitter_t) { 94 | *emitter = yaml_emitter_t{} 95 | } 96 | 97 | // String write handler. 98 | func yaml_string_write_handler(emitter *yaml_emitter_t, buffer []byte) error { 99 | *emitter.output_buffer = append(*emitter.output_buffer, buffer...) 100 | return nil 101 | } 102 | 103 | // yaml_writer_write_handler uses emitter.output_writer to write the 104 | // emitted text. 105 | func yaml_writer_write_handler(emitter *yaml_emitter_t, buffer []byte) error { 106 | _, err := emitter.output_writer.Write(buffer) 107 | return err 108 | } 109 | 110 | // Set a string output. 111 | func yaml_emitter_set_output_string(emitter *yaml_emitter_t, output_buffer *[]byte) { 112 | if emitter.write_handler != nil { 113 | panic("must set the output target only once") 114 | } 115 | emitter.write_handler = yaml_string_write_handler 116 | emitter.output_buffer = output_buffer 117 | } 118 | 119 | // Set a file output. 120 | func yaml_emitter_set_output_writer(emitter *yaml_emitter_t, w io.Writer) { 121 | if emitter.write_handler != nil { 122 | panic("must set the output target only once") 123 | } 124 | emitter.write_handler = yaml_writer_write_handler 125 | emitter.output_writer = w 126 | } 127 | 128 | // Set the output encoding. 129 | func yaml_emitter_set_encoding(emitter *yaml_emitter_t, encoding yaml_encoding_t) { 130 | if emitter.encoding != yaml_ANY_ENCODING { 131 | panic("must set the output encoding only once") 132 | } 133 | emitter.encoding = encoding 134 | } 135 | 136 | // Set the canonical output style. 137 | func yaml_emitter_set_canonical(emitter *yaml_emitter_t, canonical bool) { 138 | emitter.canonical = canonical 139 | } 140 | 141 | //// Set the indentation increment. 142 | func yaml_emitter_set_indent(emitter *yaml_emitter_t, indent int) { 143 | if indent < 2 || indent > 9 { 144 | indent = 2 145 | } 146 | emitter.best_indent = indent 147 | } 148 | 149 | // Set the preferred line width. 150 | func yaml_emitter_set_width(emitter *yaml_emitter_t, width int) { 151 | if width < 0 { 152 | width = -1 153 | } 154 | emitter.best_width = width 155 | } 156 | 157 | // Set if unescaped non-ASCII characters are allowed. 158 | func yaml_emitter_set_unicode(emitter *yaml_emitter_t, unicode bool) { 159 | emitter.unicode = unicode 160 | } 161 | 162 | // Set the preferred line break character. 163 | func yaml_emitter_set_break(emitter *yaml_emitter_t, line_break yaml_break_t) { 164 | emitter.line_break = line_break 165 | } 166 | 167 | ///* 168 | // * Destroy a token object. 169 | // */ 170 | // 171 | //YAML_DECLARE(void) 172 | //yaml_token_delete(yaml_token_t *token) 173 | //{ 174 | // assert(token); // Non-NULL token object expected. 175 | // 176 | // switch (token.type) 177 | // { 178 | // case YAML_TAG_DIRECTIVE_TOKEN: 179 | // yaml_free(token.data.tag_directive.handle); 180 | // yaml_free(token.data.tag_directive.prefix); 181 | // break; 182 | // 183 | // case YAML_ALIAS_TOKEN: 184 | // yaml_free(token.data.alias.value); 185 | // break; 186 | // 187 | // case YAML_ANCHOR_TOKEN: 188 | // yaml_free(token.data.anchor.value); 189 | // break; 190 | // 191 | // case YAML_TAG_TOKEN: 192 | // yaml_free(token.data.tag.handle); 193 | // yaml_free(token.data.tag.suffix); 194 | // break; 195 | // 196 | // case YAML_SCALAR_TOKEN: 197 | // yaml_free(token.data.scalar.value); 198 | // break; 199 | // 200 | // default: 201 | // break; 202 | // } 203 | // 204 | // memset(token, 0, sizeof(yaml_token_t)); 205 | //} 206 | // 207 | ///* 208 | // * Check if a string is a valid UTF-8 sequence. 209 | // * 210 | // * Check 'reader.c' for more details on UTF-8 encoding. 211 | // */ 212 | // 213 | //static int 214 | //yaml_check_utf8(yaml_char_t *start, size_t length) 215 | //{ 216 | // yaml_char_t *end = start+length; 217 | // yaml_char_t *pointer = start; 218 | // 219 | // while (pointer < end) { 220 | // unsigned char octet; 221 | // unsigned int width; 222 | // unsigned int value; 223 | // size_t k; 224 | // 225 | // octet = pointer[0]; 226 | // width = (octet & 0x80) == 0x00 ? 1 : 227 | // (octet & 0xE0) == 0xC0 ? 2 : 228 | // (octet & 0xF0) == 0xE0 ? 3 : 229 | // (octet & 0xF8) == 0xF0 ? 4 : 0; 230 | // value = (octet & 0x80) == 0x00 ? octet & 0x7F : 231 | // (octet & 0xE0) == 0xC0 ? octet & 0x1F : 232 | // (octet & 0xF0) == 0xE0 ? octet & 0x0F : 233 | // (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; 234 | // if (!width) return 0; 235 | // if (pointer+width > end) return 0; 236 | // for (k = 1; k < width; k ++) { 237 | // octet = pointer[k]; 238 | // if ((octet & 0xC0) != 0x80) return 0; 239 | // value = (value << 6) + (octet & 0x3F); 240 | // } 241 | // if (!((width == 1) || 242 | // (width == 2 && value >= 0x80) || 243 | // (width == 3 && value >= 0x800) || 244 | // (width == 4 && value >= 0x10000))) return 0; 245 | // 246 | // pointer += width; 247 | // } 248 | // 249 | // return 1; 250 | //} 251 | // 252 | 253 | // Create STREAM-START. 254 | func yaml_stream_start_event_initialize(event *yaml_event_t, encoding yaml_encoding_t) { 255 | *event = yaml_event_t{ 256 | typ: yaml_STREAM_START_EVENT, 257 | encoding: encoding, 258 | } 259 | } 260 | 261 | // Create STREAM-END. 262 | func yaml_stream_end_event_initialize(event *yaml_event_t) { 263 | *event = yaml_event_t{ 264 | typ: yaml_STREAM_END_EVENT, 265 | } 266 | } 267 | 268 | // Create DOCUMENT-START. 269 | func yaml_document_start_event_initialize( 270 | event *yaml_event_t, 271 | version_directive *yaml_version_directive_t, 272 | tag_directives []yaml_tag_directive_t, 273 | implicit bool, 274 | ) { 275 | *event = yaml_event_t{ 276 | typ: yaml_DOCUMENT_START_EVENT, 277 | version_directive: version_directive, 278 | tag_directives: tag_directives, 279 | implicit: implicit, 280 | } 281 | } 282 | 283 | // Create DOCUMENT-END. 284 | func yaml_document_end_event_initialize(event *yaml_event_t, implicit bool) { 285 | *event = yaml_event_t{ 286 | typ: yaml_DOCUMENT_END_EVENT, 287 | implicit: implicit, 288 | } 289 | } 290 | 291 | ///* 292 | // * Create ALIAS. 293 | // */ 294 | // 295 | //YAML_DECLARE(int) 296 | //yaml_alias_event_initialize(event *yaml_event_t, anchor *yaml_char_t) 297 | //{ 298 | // mark yaml_mark_t = { 0, 0, 0 } 299 | // anchor_copy *yaml_char_t = NULL 300 | // 301 | // assert(event) // Non-NULL event object is expected. 302 | // assert(anchor) // Non-NULL anchor is expected. 303 | // 304 | // if (!yaml_check_utf8(anchor, strlen((char *)anchor))) return 0 305 | // 306 | // anchor_copy = yaml_strdup(anchor) 307 | // if (!anchor_copy) 308 | // return 0 309 | // 310 | // ALIAS_EVENT_INIT(*event, anchor_copy, mark, mark) 311 | // 312 | // return 1 313 | //} 314 | 315 | // Create SCALAR. 316 | func yaml_scalar_event_initialize(event *yaml_event_t, anchor, tag, value []byte, plain_implicit, quoted_implicit bool, style yaml_scalar_style_t) bool { 317 | *event = yaml_event_t{ 318 | typ: yaml_SCALAR_EVENT, 319 | anchor: anchor, 320 | tag: tag, 321 | value: value, 322 | implicit: plain_implicit, 323 | quoted_implicit: quoted_implicit, 324 | style: yaml_style_t(style), 325 | } 326 | return true 327 | } 328 | 329 | // Create SEQUENCE-START. 330 | func yaml_sequence_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_sequence_style_t) bool { 331 | *event = yaml_event_t{ 332 | typ: yaml_SEQUENCE_START_EVENT, 333 | anchor: anchor, 334 | tag: tag, 335 | implicit: implicit, 336 | style: yaml_style_t(style), 337 | } 338 | return true 339 | } 340 | 341 | // Create SEQUENCE-END. 342 | func yaml_sequence_end_event_initialize(event *yaml_event_t) bool { 343 | *event = yaml_event_t{ 344 | typ: yaml_SEQUENCE_END_EVENT, 345 | } 346 | return true 347 | } 348 | 349 | // Create MAPPING-START. 350 | func yaml_mapping_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_mapping_style_t) { 351 | *event = yaml_event_t{ 352 | typ: yaml_MAPPING_START_EVENT, 353 | anchor: anchor, 354 | tag: tag, 355 | implicit: implicit, 356 | style: yaml_style_t(style), 357 | } 358 | } 359 | 360 | // Create MAPPING-END. 361 | func yaml_mapping_end_event_initialize(event *yaml_event_t) { 362 | *event = yaml_event_t{ 363 | typ: yaml_MAPPING_END_EVENT, 364 | } 365 | } 366 | 367 | // Destroy an event object. 368 | func yaml_event_delete(event *yaml_event_t) { 369 | *event = yaml_event_t{} 370 | } 371 | 372 | ///* 373 | // * Create a document object. 374 | // */ 375 | // 376 | //YAML_DECLARE(int) 377 | //yaml_document_initialize(document *yaml_document_t, 378 | // version_directive *yaml_version_directive_t, 379 | // tag_directives_start *yaml_tag_directive_t, 380 | // tag_directives_end *yaml_tag_directive_t, 381 | // start_implicit int, end_implicit int) 382 | //{ 383 | // struct { 384 | // error yaml_error_type_t 385 | // } context 386 | // struct { 387 | // start *yaml_node_t 388 | // end *yaml_node_t 389 | // top *yaml_node_t 390 | // } nodes = { NULL, NULL, NULL } 391 | // version_directive_copy *yaml_version_directive_t = NULL 392 | // struct { 393 | // start *yaml_tag_directive_t 394 | // end *yaml_tag_directive_t 395 | // top *yaml_tag_directive_t 396 | // } tag_directives_copy = { NULL, NULL, NULL } 397 | // value yaml_tag_directive_t = { NULL, NULL } 398 | // mark yaml_mark_t = { 0, 0, 0 } 399 | // 400 | // assert(document) // Non-NULL document object is expected. 401 | // assert((tag_directives_start && tag_directives_end) || 402 | // (tag_directives_start == tag_directives_end)) 403 | // // Valid tag directives are expected. 404 | // 405 | // if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error 406 | // 407 | // if (version_directive) { 408 | // version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t)) 409 | // if (!version_directive_copy) goto error 410 | // version_directive_copy.major = version_directive.major 411 | // version_directive_copy.minor = version_directive.minor 412 | // } 413 | // 414 | // if (tag_directives_start != tag_directives_end) { 415 | // tag_directive *yaml_tag_directive_t 416 | // if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE)) 417 | // goto error 418 | // for (tag_directive = tag_directives_start 419 | // tag_directive != tag_directives_end; tag_directive ++) { 420 | // assert(tag_directive.handle) 421 | // assert(tag_directive.prefix) 422 | // if (!yaml_check_utf8(tag_directive.handle, 423 | // strlen((char *)tag_directive.handle))) 424 | // goto error 425 | // if (!yaml_check_utf8(tag_directive.prefix, 426 | // strlen((char *)tag_directive.prefix))) 427 | // goto error 428 | // value.handle = yaml_strdup(tag_directive.handle) 429 | // value.prefix = yaml_strdup(tag_directive.prefix) 430 | // if (!value.handle || !value.prefix) goto error 431 | // if (!PUSH(&context, tag_directives_copy, value)) 432 | // goto error 433 | // value.handle = NULL 434 | // value.prefix = NULL 435 | // } 436 | // } 437 | // 438 | // DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy, 439 | // tag_directives_copy.start, tag_directives_copy.top, 440 | // start_implicit, end_implicit, mark, mark) 441 | // 442 | // return 1 443 | // 444 | //error: 445 | // STACK_DEL(&context, nodes) 446 | // yaml_free(version_directive_copy) 447 | // while (!STACK_EMPTY(&context, tag_directives_copy)) { 448 | // value yaml_tag_directive_t = POP(&context, tag_directives_copy) 449 | // yaml_free(value.handle) 450 | // yaml_free(value.prefix) 451 | // } 452 | // STACK_DEL(&context, tag_directives_copy) 453 | // yaml_free(value.handle) 454 | // yaml_free(value.prefix) 455 | // 456 | // return 0 457 | //} 458 | // 459 | ///* 460 | // * Destroy a document object. 461 | // */ 462 | // 463 | //YAML_DECLARE(void) 464 | //yaml_document_delete(document *yaml_document_t) 465 | //{ 466 | // struct { 467 | // error yaml_error_type_t 468 | // } context 469 | // tag_directive *yaml_tag_directive_t 470 | // 471 | // context.error = YAML_NO_ERROR // Eliminate a compiler warning. 472 | // 473 | // assert(document) // Non-NULL document object is expected. 474 | // 475 | // while (!STACK_EMPTY(&context, document.nodes)) { 476 | // node yaml_node_t = POP(&context, document.nodes) 477 | // yaml_free(node.tag) 478 | // switch (node.type) { 479 | // case YAML_SCALAR_NODE: 480 | // yaml_free(node.data.scalar.value) 481 | // break 482 | // case YAML_SEQUENCE_NODE: 483 | // STACK_DEL(&context, node.data.sequence.items) 484 | // break 485 | // case YAML_MAPPING_NODE: 486 | // STACK_DEL(&context, node.data.mapping.pairs) 487 | // break 488 | // default: 489 | // assert(0) // Should not happen. 490 | // } 491 | // } 492 | // STACK_DEL(&context, document.nodes) 493 | // 494 | // yaml_free(document.version_directive) 495 | // for (tag_directive = document.tag_directives.start 496 | // tag_directive != document.tag_directives.end 497 | // tag_directive++) { 498 | // yaml_free(tag_directive.handle) 499 | // yaml_free(tag_directive.prefix) 500 | // } 501 | // yaml_free(document.tag_directives.start) 502 | // 503 | // memset(document, 0, sizeof(yaml_document_t)) 504 | //} 505 | // 506 | ///** 507 | // * Get a document node. 508 | // */ 509 | // 510 | //YAML_DECLARE(yaml_node_t *) 511 | //yaml_document_get_node(document *yaml_document_t, index int) 512 | //{ 513 | // assert(document) // Non-NULL document object is expected. 514 | // 515 | // if (index > 0 && document.nodes.start + index <= document.nodes.top) { 516 | // return document.nodes.start + index - 1 517 | // } 518 | // return NULL 519 | //} 520 | // 521 | ///** 522 | // * Get the root object. 523 | // */ 524 | // 525 | //YAML_DECLARE(yaml_node_t *) 526 | //yaml_document_get_root_node(document *yaml_document_t) 527 | //{ 528 | // assert(document) // Non-NULL document object is expected. 529 | // 530 | // if (document.nodes.top != document.nodes.start) { 531 | // return document.nodes.start 532 | // } 533 | // return NULL 534 | //} 535 | // 536 | ///* 537 | // * Add a scalar node to a document. 538 | // */ 539 | // 540 | //YAML_DECLARE(int) 541 | //yaml_document_add_scalar(document *yaml_document_t, 542 | // tag *yaml_char_t, value *yaml_char_t, length int, 543 | // style yaml_scalar_style_t) 544 | //{ 545 | // struct { 546 | // error yaml_error_type_t 547 | // } context 548 | // mark yaml_mark_t = { 0, 0, 0 } 549 | // tag_copy *yaml_char_t = NULL 550 | // value_copy *yaml_char_t = NULL 551 | // node yaml_node_t 552 | // 553 | // assert(document) // Non-NULL document object is expected. 554 | // assert(value) // Non-NULL value is expected. 555 | // 556 | // if (!tag) { 557 | // tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG 558 | // } 559 | // 560 | // if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error 561 | // tag_copy = yaml_strdup(tag) 562 | // if (!tag_copy) goto error 563 | // 564 | // if (length < 0) { 565 | // length = strlen((char *)value) 566 | // } 567 | // 568 | // if (!yaml_check_utf8(value, length)) goto error 569 | // value_copy = yaml_malloc(length+1) 570 | // if (!value_copy) goto error 571 | // memcpy(value_copy, value, length) 572 | // value_copy[length] = '\0' 573 | // 574 | // SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark) 575 | // if (!PUSH(&context, document.nodes, node)) goto error 576 | // 577 | // return document.nodes.top - document.nodes.start 578 | // 579 | //error: 580 | // yaml_free(tag_copy) 581 | // yaml_free(value_copy) 582 | // 583 | // return 0 584 | //} 585 | // 586 | ///* 587 | // * Add a sequence node to a document. 588 | // */ 589 | // 590 | //YAML_DECLARE(int) 591 | //yaml_document_add_sequence(document *yaml_document_t, 592 | // tag *yaml_char_t, style yaml_sequence_style_t) 593 | //{ 594 | // struct { 595 | // error yaml_error_type_t 596 | // } context 597 | // mark yaml_mark_t = { 0, 0, 0 } 598 | // tag_copy *yaml_char_t = NULL 599 | // struct { 600 | // start *yaml_node_item_t 601 | // end *yaml_node_item_t 602 | // top *yaml_node_item_t 603 | // } items = { NULL, NULL, NULL } 604 | // node yaml_node_t 605 | // 606 | // assert(document) // Non-NULL document object is expected. 607 | // 608 | // if (!tag) { 609 | // tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG 610 | // } 611 | // 612 | // if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error 613 | // tag_copy = yaml_strdup(tag) 614 | // if (!tag_copy) goto error 615 | // 616 | // if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error 617 | // 618 | // SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end, 619 | // style, mark, mark) 620 | // if (!PUSH(&context, document.nodes, node)) goto error 621 | // 622 | // return document.nodes.top - document.nodes.start 623 | // 624 | //error: 625 | // STACK_DEL(&context, items) 626 | // yaml_free(tag_copy) 627 | // 628 | // return 0 629 | //} 630 | // 631 | ///* 632 | // * Add a mapping node to a document. 633 | // */ 634 | // 635 | //YAML_DECLARE(int) 636 | //yaml_document_add_mapping(document *yaml_document_t, 637 | // tag *yaml_char_t, style yaml_mapping_style_t) 638 | //{ 639 | // struct { 640 | // error yaml_error_type_t 641 | // } context 642 | // mark yaml_mark_t = { 0, 0, 0 } 643 | // tag_copy *yaml_char_t = NULL 644 | // struct { 645 | // start *yaml_node_pair_t 646 | // end *yaml_node_pair_t 647 | // top *yaml_node_pair_t 648 | // } pairs = { NULL, NULL, NULL } 649 | // node yaml_node_t 650 | // 651 | // assert(document) // Non-NULL document object is expected. 652 | // 653 | // if (!tag) { 654 | // tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG 655 | // } 656 | // 657 | // if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error 658 | // tag_copy = yaml_strdup(tag) 659 | // if (!tag_copy) goto error 660 | // 661 | // if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error 662 | // 663 | // MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end, 664 | // style, mark, mark) 665 | // if (!PUSH(&context, document.nodes, node)) goto error 666 | // 667 | // return document.nodes.top - document.nodes.start 668 | // 669 | //error: 670 | // STACK_DEL(&context, pairs) 671 | // yaml_free(tag_copy) 672 | // 673 | // return 0 674 | //} 675 | // 676 | ///* 677 | // * Append an item to a sequence node. 678 | // */ 679 | // 680 | //YAML_DECLARE(int) 681 | //yaml_document_append_sequence_item(document *yaml_document_t, 682 | // sequence int, item int) 683 | //{ 684 | // struct { 685 | // error yaml_error_type_t 686 | // } context 687 | // 688 | // assert(document) // Non-NULL document is required. 689 | // assert(sequence > 0 690 | // && document.nodes.start + sequence <= document.nodes.top) 691 | // // Valid sequence id is required. 692 | // assert(document.nodes.start[sequence-1].type == YAML_SEQUENCE_NODE) 693 | // // A sequence node is required. 694 | // assert(item > 0 && document.nodes.start + item <= document.nodes.top) 695 | // // Valid item id is required. 696 | // 697 | // if (!PUSH(&context, 698 | // document.nodes.start[sequence-1].data.sequence.items, item)) 699 | // return 0 700 | // 701 | // return 1 702 | //} 703 | // 704 | ///* 705 | // * Append a pair of a key and a value to a mapping node. 706 | // */ 707 | // 708 | //YAML_DECLARE(int) 709 | //yaml_document_append_mapping_pair(document *yaml_document_t, 710 | // mapping int, key int, value int) 711 | //{ 712 | // struct { 713 | // error yaml_error_type_t 714 | // } context 715 | // 716 | // pair yaml_node_pair_t 717 | // 718 | // assert(document) // Non-NULL document is required. 719 | // assert(mapping > 0 720 | // && document.nodes.start + mapping <= document.nodes.top) 721 | // // Valid mapping id is required. 722 | // assert(document.nodes.start[mapping-1].type == YAML_MAPPING_NODE) 723 | // // A mapping node is required. 724 | // assert(key > 0 && document.nodes.start + key <= document.nodes.top) 725 | // // Valid key id is required. 726 | // assert(value > 0 && document.nodes.start + value <= document.nodes.top) 727 | // // Valid value id is required. 728 | // 729 | // pair.key = key 730 | // pair.value = value 731 | // 732 | // if (!PUSH(&context, 733 | // document.nodes.start[mapping-1].data.mapping.pairs, pair)) 734 | // return 0 735 | // 736 | // return 1 737 | //} 738 | // 739 | // 740 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v2/yamlh.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | ) 7 | 8 | // The version directive data. 9 | type yaml_version_directive_t struct { 10 | major int8 // The major version number. 11 | minor int8 // The minor version number. 12 | } 13 | 14 | // The tag directive data. 15 | type yaml_tag_directive_t struct { 16 | handle []byte // The tag handle. 17 | prefix []byte // The tag prefix. 18 | } 19 | 20 | type yaml_encoding_t int 21 | 22 | // The stream encoding. 23 | const ( 24 | // Let the parser choose the encoding. 25 | yaml_ANY_ENCODING yaml_encoding_t = iota 26 | 27 | yaml_UTF8_ENCODING // The default UTF-8 encoding. 28 | yaml_UTF16LE_ENCODING // The UTF-16-LE encoding with BOM. 29 | yaml_UTF16BE_ENCODING // The UTF-16-BE encoding with BOM. 30 | ) 31 | 32 | type yaml_break_t int 33 | 34 | // Line break types. 35 | const ( 36 | // Let the parser choose the break type. 37 | yaml_ANY_BREAK yaml_break_t = iota 38 | 39 | yaml_CR_BREAK // Use CR for line breaks (Mac style). 40 | yaml_LN_BREAK // Use LN for line breaks (Unix style). 41 | yaml_CRLN_BREAK // Use CR LN for line breaks (DOS style). 42 | ) 43 | 44 | type yaml_error_type_t int 45 | 46 | // Many bad things could happen with the parser and emitter. 47 | const ( 48 | // No error is produced. 49 | yaml_NO_ERROR yaml_error_type_t = iota 50 | 51 | yaml_MEMORY_ERROR // Cannot allocate or reallocate a block of memory. 52 | yaml_READER_ERROR // Cannot read or decode the input stream. 53 | yaml_SCANNER_ERROR // Cannot scan the input stream. 54 | yaml_PARSER_ERROR // Cannot parse the input stream. 55 | yaml_COMPOSER_ERROR // Cannot compose a YAML document. 56 | yaml_WRITER_ERROR // Cannot write to the output stream. 57 | yaml_EMITTER_ERROR // Cannot emit a YAML stream. 58 | ) 59 | 60 | // The pointer position. 61 | type yaml_mark_t struct { 62 | index int // The position index. 63 | line int // The position line. 64 | column int // The position column. 65 | } 66 | 67 | // Node Styles 68 | 69 | type yaml_style_t int8 70 | 71 | type yaml_scalar_style_t yaml_style_t 72 | 73 | // Scalar styles. 74 | const ( 75 | // Let the emitter choose the style. 76 | yaml_ANY_SCALAR_STYLE yaml_scalar_style_t = iota 77 | 78 | yaml_PLAIN_SCALAR_STYLE // The plain scalar style. 79 | yaml_SINGLE_QUOTED_SCALAR_STYLE // The single-quoted scalar style. 80 | yaml_DOUBLE_QUOTED_SCALAR_STYLE // The double-quoted scalar style. 81 | yaml_LITERAL_SCALAR_STYLE // The literal scalar style. 82 | yaml_FOLDED_SCALAR_STYLE // The folded scalar style. 83 | ) 84 | 85 | type yaml_sequence_style_t yaml_style_t 86 | 87 | // Sequence styles. 88 | const ( 89 | // Let the emitter choose the style. 90 | yaml_ANY_SEQUENCE_STYLE yaml_sequence_style_t = iota 91 | 92 | yaml_BLOCK_SEQUENCE_STYLE // The block sequence style. 93 | yaml_FLOW_SEQUENCE_STYLE // The flow sequence style. 94 | ) 95 | 96 | type yaml_mapping_style_t yaml_style_t 97 | 98 | // Mapping styles. 99 | const ( 100 | // Let the emitter choose the style. 101 | yaml_ANY_MAPPING_STYLE yaml_mapping_style_t = iota 102 | 103 | yaml_BLOCK_MAPPING_STYLE // The block mapping style. 104 | yaml_FLOW_MAPPING_STYLE // The flow mapping style. 105 | ) 106 | 107 | // Tokens 108 | 109 | type yaml_token_type_t int 110 | 111 | // Token types. 112 | const ( 113 | // An empty token. 114 | yaml_NO_TOKEN yaml_token_type_t = iota 115 | 116 | yaml_STREAM_START_TOKEN // A STREAM-START token. 117 | yaml_STREAM_END_TOKEN // A STREAM-END token. 118 | 119 | yaml_VERSION_DIRECTIVE_TOKEN // A VERSION-DIRECTIVE token. 120 | yaml_TAG_DIRECTIVE_TOKEN // A TAG-DIRECTIVE token. 121 | yaml_DOCUMENT_START_TOKEN // A DOCUMENT-START token. 122 | yaml_DOCUMENT_END_TOKEN // A DOCUMENT-END token. 123 | 124 | yaml_BLOCK_SEQUENCE_START_TOKEN // A BLOCK-SEQUENCE-START token. 125 | yaml_BLOCK_MAPPING_START_TOKEN // A BLOCK-SEQUENCE-END token. 126 | yaml_BLOCK_END_TOKEN // A BLOCK-END token. 127 | 128 | yaml_FLOW_SEQUENCE_START_TOKEN // A FLOW-SEQUENCE-START token. 129 | yaml_FLOW_SEQUENCE_END_TOKEN // A FLOW-SEQUENCE-END token. 130 | yaml_FLOW_MAPPING_START_TOKEN // A FLOW-MAPPING-START token. 131 | yaml_FLOW_MAPPING_END_TOKEN // A FLOW-MAPPING-END token. 132 | 133 | yaml_BLOCK_ENTRY_TOKEN // A BLOCK-ENTRY token. 134 | yaml_FLOW_ENTRY_TOKEN // A FLOW-ENTRY token. 135 | yaml_KEY_TOKEN // A KEY token. 136 | yaml_VALUE_TOKEN // A VALUE token. 137 | 138 | yaml_ALIAS_TOKEN // An ALIAS token. 139 | yaml_ANCHOR_TOKEN // An ANCHOR token. 140 | yaml_TAG_TOKEN // A TAG token. 141 | yaml_SCALAR_TOKEN // A SCALAR token. 142 | ) 143 | 144 | func (tt yaml_token_type_t) String() string { 145 | switch tt { 146 | case yaml_NO_TOKEN: 147 | return "yaml_NO_TOKEN" 148 | case yaml_STREAM_START_TOKEN: 149 | return "yaml_STREAM_START_TOKEN" 150 | case yaml_STREAM_END_TOKEN: 151 | return "yaml_STREAM_END_TOKEN" 152 | case yaml_VERSION_DIRECTIVE_TOKEN: 153 | return "yaml_VERSION_DIRECTIVE_TOKEN" 154 | case yaml_TAG_DIRECTIVE_TOKEN: 155 | return "yaml_TAG_DIRECTIVE_TOKEN" 156 | case yaml_DOCUMENT_START_TOKEN: 157 | return "yaml_DOCUMENT_START_TOKEN" 158 | case yaml_DOCUMENT_END_TOKEN: 159 | return "yaml_DOCUMENT_END_TOKEN" 160 | case yaml_BLOCK_SEQUENCE_START_TOKEN: 161 | return "yaml_BLOCK_SEQUENCE_START_TOKEN" 162 | case yaml_BLOCK_MAPPING_START_TOKEN: 163 | return "yaml_BLOCK_MAPPING_START_TOKEN" 164 | case yaml_BLOCK_END_TOKEN: 165 | return "yaml_BLOCK_END_TOKEN" 166 | case yaml_FLOW_SEQUENCE_START_TOKEN: 167 | return "yaml_FLOW_SEQUENCE_START_TOKEN" 168 | case yaml_FLOW_SEQUENCE_END_TOKEN: 169 | return "yaml_FLOW_SEQUENCE_END_TOKEN" 170 | case yaml_FLOW_MAPPING_START_TOKEN: 171 | return "yaml_FLOW_MAPPING_START_TOKEN" 172 | case yaml_FLOW_MAPPING_END_TOKEN: 173 | return "yaml_FLOW_MAPPING_END_TOKEN" 174 | case yaml_BLOCK_ENTRY_TOKEN: 175 | return "yaml_BLOCK_ENTRY_TOKEN" 176 | case yaml_FLOW_ENTRY_TOKEN: 177 | return "yaml_FLOW_ENTRY_TOKEN" 178 | case yaml_KEY_TOKEN: 179 | return "yaml_KEY_TOKEN" 180 | case yaml_VALUE_TOKEN: 181 | return "yaml_VALUE_TOKEN" 182 | case yaml_ALIAS_TOKEN: 183 | return "yaml_ALIAS_TOKEN" 184 | case yaml_ANCHOR_TOKEN: 185 | return "yaml_ANCHOR_TOKEN" 186 | case yaml_TAG_TOKEN: 187 | return "yaml_TAG_TOKEN" 188 | case yaml_SCALAR_TOKEN: 189 | return "yaml_SCALAR_TOKEN" 190 | } 191 | return "" 192 | } 193 | 194 | // The token structure. 195 | type yaml_token_t struct { 196 | // The token type. 197 | typ yaml_token_type_t 198 | 199 | // The start/end of the token. 200 | start_mark, end_mark yaml_mark_t 201 | 202 | // The stream encoding (for yaml_STREAM_START_TOKEN). 203 | encoding yaml_encoding_t 204 | 205 | // The alias/anchor/scalar value or tag/tag directive handle 206 | // (for yaml_ALIAS_TOKEN, yaml_ANCHOR_TOKEN, yaml_SCALAR_TOKEN, yaml_TAG_TOKEN, yaml_TAG_DIRECTIVE_TOKEN). 207 | value []byte 208 | 209 | // The tag suffix (for yaml_TAG_TOKEN). 210 | suffix []byte 211 | 212 | // The tag directive prefix (for yaml_TAG_DIRECTIVE_TOKEN). 213 | prefix []byte 214 | 215 | // The scalar style (for yaml_SCALAR_TOKEN). 216 | style yaml_scalar_style_t 217 | 218 | // The version directive major/minor (for yaml_VERSION_DIRECTIVE_TOKEN). 219 | major, minor int8 220 | } 221 | 222 | // Events 223 | 224 | type yaml_event_type_t int8 225 | 226 | // Event types. 227 | const ( 228 | // An empty event. 229 | yaml_NO_EVENT yaml_event_type_t = iota 230 | 231 | yaml_STREAM_START_EVENT // A STREAM-START event. 232 | yaml_STREAM_END_EVENT // A STREAM-END event. 233 | yaml_DOCUMENT_START_EVENT // A DOCUMENT-START event. 234 | yaml_DOCUMENT_END_EVENT // A DOCUMENT-END event. 235 | yaml_ALIAS_EVENT // An ALIAS event. 236 | yaml_SCALAR_EVENT // A SCALAR event. 237 | yaml_SEQUENCE_START_EVENT // A SEQUENCE-START event. 238 | yaml_SEQUENCE_END_EVENT // A SEQUENCE-END event. 239 | yaml_MAPPING_START_EVENT // A MAPPING-START event. 240 | yaml_MAPPING_END_EVENT // A MAPPING-END event. 241 | ) 242 | 243 | var eventStrings = []string{ 244 | yaml_NO_EVENT: "none", 245 | yaml_STREAM_START_EVENT: "stream start", 246 | yaml_STREAM_END_EVENT: "stream end", 247 | yaml_DOCUMENT_START_EVENT: "document start", 248 | yaml_DOCUMENT_END_EVENT: "document end", 249 | yaml_ALIAS_EVENT: "alias", 250 | yaml_SCALAR_EVENT: "scalar", 251 | yaml_SEQUENCE_START_EVENT: "sequence start", 252 | yaml_SEQUENCE_END_EVENT: "sequence end", 253 | yaml_MAPPING_START_EVENT: "mapping start", 254 | yaml_MAPPING_END_EVENT: "mapping end", 255 | } 256 | 257 | func (e yaml_event_type_t) String() string { 258 | if e < 0 || int(e) >= len(eventStrings) { 259 | return fmt.Sprintf("unknown event %d", e) 260 | } 261 | return eventStrings[e] 262 | } 263 | 264 | // The event structure. 265 | type yaml_event_t struct { 266 | 267 | // The event type. 268 | typ yaml_event_type_t 269 | 270 | // The start and end of the event. 271 | start_mark, end_mark yaml_mark_t 272 | 273 | // The document encoding (for yaml_STREAM_START_EVENT). 274 | encoding yaml_encoding_t 275 | 276 | // The version directive (for yaml_DOCUMENT_START_EVENT). 277 | version_directive *yaml_version_directive_t 278 | 279 | // The list of tag directives (for yaml_DOCUMENT_START_EVENT). 280 | tag_directives []yaml_tag_directive_t 281 | 282 | // The anchor (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_ALIAS_EVENT). 283 | anchor []byte 284 | 285 | // The tag (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT). 286 | tag []byte 287 | 288 | // The scalar value (for yaml_SCALAR_EVENT). 289 | value []byte 290 | 291 | // Is the document start/end indicator implicit, or the tag optional? 292 | // (for yaml_DOCUMENT_START_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_SCALAR_EVENT). 293 | implicit bool 294 | 295 | // Is the tag optional for any non-plain style? (for yaml_SCALAR_EVENT). 296 | quoted_implicit bool 297 | 298 | // The style (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT). 299 | style yaml_style_t 300 | } 301 | 302 | func (e *yaml_event_t) scalar_style() yaml_scalar_style_t { return yaml_scalar_style_t(e.style) } 303 | func (e *yaml_event_t) sequence_style() yaml_sequence_style_t { return yaml_sequence_style_t(e.style) } 304 | func (e *yaml_event_t) mapping_style() yaml_mapping_style_t { return yaml_mapping_style_t(e.style) } 305 | 306 | // Nodes 307 | 308 | const ( 309 | yaml_NULL_TAG = "tag:yaml.org,2002:null" // The tag !!null with the only possible value: null. 310 | yaml_BOOL_TAG = "tag:yaml.org,2002:bool" // The tag !!bool with the values: true and false. 311 | yaml_STR_TAG = "tag:yaml.org,2002:str" // The tag !!str for string values. 312 | yaml_INT_TAG = "tag:yaml.org,2002:int" // The tag !!int for integer values. 313 | yaml_FLOAT_TAG = "tag:yaml.org,2002:float" // The tag !!float for float values. 314 | yaml_TIMESTAMP_TAG = "tag:yaml.org,2002:timestamp" // The tag !!timestamp for date and time values. 315 | 316 | yaml_SEQ_TAG = "tag:yaml.org,2002:seq" // The tag !!seq is used to denote sequences. 317 | yaml_MAP_TAG = "tag:yaml.org,2002:map" // The tag !!map is used to denote mapping. 318 | 319 | // Not in original libyaml. 320 | yaml_BINARY_TAG = "tag:yaml.org,2002:binary" 321 | yaml_MERGE_TAG = "tag:yaml.org,2002:merge" 322 | 323 | yaml_DEFAULT_SCALAR_TAG = yaml_STR_TAG // The default scalar tag is !!str. 324 | yaml_DEFAULT_SEQUENCE_TAG = yaml_SEQ_TAG // The default sequence tag is !!seq. 325 | yaml_DEFAULT_MAPPING_TAG = yaml_MAP_TAG // The default mapping tag is !!map. 326 | ) 327 | 328 | type yaml_node_type_t int 329 | 330 | // Node types. 331 | const ( 332 | // An empty node. 333 | yaml_NO_NODE yaml_node_type_t = iota 334 | 335 | yaml_SCALAR_NODE // A scalar node. 336 | yaml_SEQUENCE_NODE // A sequence node. 337 | yaml_MAPPING_NODE // A mapping node. 338 | ) 339 | 340 | // An element of a sequence node. 341 | type yaml_node_item_t int 342 | 343 | // An element of a mapping node. 344 | type yaml_node_pair_t struct { 345 | key int // The key of the element. 346 | value int // The value of the element. 347 | } 348 | 349 | // The node structure. 350 | type yaml_node_t struct { 351 | typ yaml_node_type_t // The node type. 352 | tag []byte // The node tag. 353 | 354 | // The node data. 355 | 356 | // The scalar parameters (for yaml_SCALAR_NODE). 357 | scalar struct { 358 | value []byte // The scalar value. 359 | length int // The length of the scalar value. 360 | style yaml_scalar_style_t // The scalar style. 361 | } 362 | 363 | // The sequence parameters (for YAML_SEQUENCE_NODE). 364 | sequence struct { 365 | items_data []yaml_node_item_t // The stack of sequence items. 366 | style yaml_sequence_style_t // The sequence style. 367 | } 368 | 369 | // The mapping parameters (for yaml_MAPPING_NODE). 370 | mapping struct { 371 | pairs_data []yaml_node_pair_t // The stack of mapping pairs (key, value). 372 | pairs_start *yaml_node_pair_t // The beginning of the stack. 373 | pairs_end *yaml_node_pair_t // The end of the stack. 374 | pairs_top *yaml_node_pair_t // The top of the stack. 375 | style yaml_mapping_style_t // The mapping style. 376 | } 377 | 378 | start_mark yaml_mark_t // The beginning of the node. 379 | end_mark yaml_mark_t // The end of the node. 380 | 381 | } 382 | 383 | // The document structure. 384 | type yaml_document_t struct { 385 | 386 | // The document nodes. 387 | nodes []yaml_node_t 388 | 389 | // The version directive. 390 | version_directive *yaml_version_directive_t 391 | 392 | // The list of tag directives. 393 | tag_directives_data []yaml_tag_directive_t 394 | tag_directives_start int // The beginning of the tag directives list. 395 | tag_directives_end int // The end of the tag directives list. 396 | 397 | start_implicit int // Is the document start indicator implicit? 398 | end_implicit int // Is the document end indicator implicit? 399 | 400 | // The start/end of the document. 401 | start_mark, end_mark yaml_mark_t 402 | } 403 | 404 | // The prototype of a read handler. 405 | // 406 | // The read handler is called when the parser needs to read more bytes from the 407 | // source. The handler should write not more than size bytes to the buffer. 408 | // The number of written bytes should be set to the size_read variable. 409 | // 410 | // [in,out] data A pointer to an application data specified by 411 | // yaml_parser_set_input(). 412 | // [out] buffer The buffer to write the data from the source. 413 | // [in] size The size of the buffer. 414 | // [out] size_read The actual number of bytes read from the source. 415 | // 416 | // On success, the handler should return 1. If the handler failed, 417 | // the returned value should be 0. On EOF, the handler should set the 418 | // size_read to 0 and return 1. 419 | type yaml_read_handler_t func(parser *yaml_parser_t, buffer []byte) (n int, err error) 420 | 421 | // This structure holds information about a potential simple key. 422 | type yaml_simple_key_t struct { 423 | possible bool // Is a simple key possible? 424 | required bool // Is a simple key required? 425 | token_number int // The number of the token. 426 | mark yaml_mark_t // The position mark. 427 | } 428 | 429 | // The states of the parser. 430 | type yaml_parser_state_t int 431 | 432 | const ( 433 | yaml_PARSE_STREAM_START_STATE yaml_parser_state_t = iota 434 | 435 | yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE // Expect the beginning of an implicit document. 436 | yaml_PARSE_DOCUMENT_START_STATE // Expect DOCUMENT-START. 437 | yaml_PARSE_DOCUMENT_CONTENT_STATE // Expect the content of a document. 438 | yaml_PARSE_DOCUMENT_END_STATE // Expect DOCUMENT-END. 439 | yaml_PARSE_BLOCK_NODE_STATE // Expect a block node. 440 | yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE // Expect a block node or indentless sequence. 441 | yaml_PARSE_FLOW_NODE_STATE // Expect a flow node. 442 | yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a block sequence. 443 | yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE // Expect an entry of a block sequence. 444 | yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE // Expect an entry of an indentless sequence. 445 | yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping. 446 | yaml_PARSE_BLOCK_MAPPING_KEY_STATE // Expect a block mapping key. 447 | yaml_PARSE_BLOCK_MAPPING_VALUE_STATE // Expect a block mapping value. 448 | yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a flow sequence. 449 | yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE // Expect an entry of a flow sequence. 450 | yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE // Expect a key of an ordered mapping. 451 | yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE // Expect a value of an ordered mapping. 452 | yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE // Expect the and of an ordered mapping entry. 453 | yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping. 454 | yaml_PARSE_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping. 455 | yaml_PARSE_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping. 456 | yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE // Expect an empty value of a flow mapping. 457 | yaml_PARSE_END_STATE // Expect nothing. 458 | ) 459 | 460 | func (ps yaml_parser_state_t) String() string { 461 | switch ps { 462 | case yaml_PARSE_STREAM_START_STATE: 463 | return "yaml_PARSE_STREAM_START_STATE" 464 | case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE: 465 | return "yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE" 466 | case yaml_PARSE_DOCUMENT_START_STATE: 467 | return "yaml_PARSE_DOCUMENT_START_STATE" 468 | case yaml_PARSE_DOCUMENT_CONTENT_STATE: 469 | return "yaml_PARSE_DOCUMENT_CONTENT_STATE" 470 | case yaml_PARSE_DOCUMENT_END_STATE: 471 | return "yaml_PARSE_DOCUMENT_END_STATE" 472 | case yaml_PARSE_BLOCK_NODE_STATE: 473 | return "yaml_PARSE_BLOCK_NODE_STATE" 474 | case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE: 475 | return "yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE" 476 | case yaml_PARSE_FLOW_NODE_STATE: 477 | return "yaml_PARSE_FLOW_NODE_STATE" 478 | case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE: 479 | return "yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE" 480 | case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE: 481 | return "yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE" 482 | case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE: 483 | return "yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE" 484 | case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE: 485 | return "yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE" 486 | case yaml_PARSE_BLOCK_MAPPING_KEY_STATE: 487 | return "yaml_PARSE_BLOCK_MAPPING_KEY_STATE" 488 | case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE: 489 | return "yaml_PARSE_BLOCK_MAPPING_VALUE_STATE" 490 | case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE: 491 | return "yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE" 492 | case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE: 493 | return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE" 494 | case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE: 495 | return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE" 496 | case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE: 497 | return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE" 498 | case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE: 499 | return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE" 500 | case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE: 501 | return "yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE" 502 | case yaml_PARSE_FLOW_MAPPING_KEY_STATE: 503 | return "yaml_PARSE_FLOW_MAPPING_KEY_STATE" 504 | case yaml_PARSE_FLOW_MAPPING_VALUE_STATE: 505 | return "yaml_PARSE_FLOW_MAPPING_VALUE_STATE" 506 | case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE: 507 | return "yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE" 508 | case yaml_PARSE_END_STATE: 509 | return "yaml_PARSE_END_STATE" 510 | } 511 | return "" 512 | } 513 | 514 | // This structure holds aliases data. 515 | type yaml_alias_data_t struct { 516 | anchor []byte // The anchor. 517 | index int // The node id. 518 | mark yaml_mark_t // The anchor mark. 519 | } 520 | 521 | // The parser structure. 522 | // 523 | // All members are internal. Manage the structure using the 524 | // yaml_parser_ family of functions. 525 | type yaml_parser_t struct { 526 | 527 | // Error handling 528 | 529 | error yaml_error_type_t // Error type. 530 | 531 | problem string // Error description. 532 | 533 | // The byte about which the problem occurred. 534 | problem_offset int 535 | problem_value int 536 | problem_mark yaml_mark_t 537 | 538 | // The error context. 539 | context string 540 | context_mark yaml_mark_t 541 | 542 | // Reader stuff 543 | 544 | read_handler yaml_read_handler_t // Read handler. 545 | 546 | input_reader io.Reader // File input data. 547 | input []byte // String input data. 548 | input_pos int 549 | 550 | eof bool // EOF flag 551 | 552 | buffer []byte // The working buffer. 553 | buffer_pos int // The current position of the buffer. 554 | 555 | unread int // The number of unread characters in the buffer. 556 | 557 | raw_buffer []byte // The raw buffer. 558 | raw_buffer_pos int // The current position of the buffer. 559 | 560 | encoding yaml_encoding_t // The input encoding. 561 | 562 | offset int // The offset of the current position (in bytes). 563 | mark yaml_mark_t // The mark of the current position. 564 | 565 | // Scanner stuff 566 | 567 | stream_start_produced bool // Have we started to scan the input stream? 568 | stream_end_produced bool // Have we reached the end of the input stream? 569 | 570 | flow_level int // The number of unclosed '[' and '{' indicators. 571 | 572 | tokens []yaml_token_t // The tokens queue. 573 | tokens_head int // The head of the tokens queue. 574 | tokens_parsed int // The number of tokens fetched from the queue. 575 | token_available bool // Does the tokens queue contain a token ready for dequeueing. 576 | 577 | indent int // The current indentation level. 578 | indents []int // The indentation levels stack. 579 | 580 | simple_key_allowed bool // May a simple key occur at the current position? 581 | simple_keys []yaml_simple_key_t // The stack of simple keys. 582 | 583 | // Parser stuff 584 | 585 | state yaml_parser_state_t // The current parser state. 586 | states []yaml_parser_state_t // The parser states stack. 587 | marks []yaml_mark_t // The stack of marks. 588 | tag_directives []yaml_tag_directive_t // The list of TAG directives. 589 | 590 | // Dumper stuff 591 | 592 | aliases []yaml_alias_data_t // The alias data. 593 | 594 | document *yaml_document_t // The currently parsed document. 595 | } 596 | 597 | // Emitter Definitions 598 | 599 | // The prototype of a write handler. 600 | // 601 | // The write handler is called when the emitter needs to flush the accumulated 602 | // characters to the output. The handler should write @a size bytes of the 603 | // @a buffer to the output. 604 | // 605 | // @param[in,out] data A pointer to an application data specified by 606 | // yaml_emitter_set_output(). 607 | // @param[in] buffer The buffer with bytes to be written. 608 | // @param[in] size The size of the buffer. 609 | // 610 | // @returns On success, the handler should return @c 1. If the handler failed, 611 | // the returned value should be @c 0. 612 | // 613 | type yaml_write_handler_t func(emitter *yaml_emitter_t, buffer []byte) error 614 | 615 | type yaml_emitter_state_t int 616 | 617 | // The emitter states. 618 | const ( 619 | // Expect STREAM-START. 620 | yaml_EMIT_STREAM_START_STATE yaml_emitter_state_t = iota 621 | 622 | yaml_EMIT_FIRST_DOCUMENT_START_STATE // Expect the first DOCUMENT-START or STREAM-END. 623 | yaml_EMIT_DOCUMENT_START_STATE // Expect DOCUMENT-START or STREAM-END. 624 | yaml_EMIT_DOCUMENT_CONTENT_STATE // Expect the content of a document. 625 | yaml_EMIT_DOCUMENT_END_STATE // Expect DOCUMENT-END. 626 | yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a flow sequence. 627 | yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE // Expect an item of a flow sequence. 628 | yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping. 629 | yaml_EMIT_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping. 630 | yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a flow mapping. 631 | yaml_EMIT_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping. 632 | yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a block sequence. 633 | yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE // Expect an item of a block sequence. 634 | yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping. 635 | yaml_EMIT_BLOCK_MAPPING_KEY_STATE // Expect the key of a block mapping. 636 | yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a block mapping. 637 | yaml_EMIT_BLOCK_MAPPING_VALUE_STATE // Expect a value of a block mapping. 638 | yaml_EMIT_END_STATE // Expect nothing. 639 | ) 640 | 641 | // The emitter structure. 642 | // 643 | // All members are internal. Manage the structure using the @c yaml_emitter_ 644 | // family of functions. 645 | type yaml_emitter_t struct { 646 | 647 | // Error handling 648 | 649 | error yaml_error_type_t // Error type. 650 | problem string // Error description. 651 | 652 | // Writer stuff 653 | 654 | write_handler yaml_write_handler_t // Write handler. 655 | 656 | output_buffer *[]byte // String output data. 657 | output_writer io.Writer // File output data. 658 | 659 | buffer []byte // The working buffer. 660 | buffer_pos int // The current position of the buffer. 661 | 662 | raw_buffer []byte // The raw buffer. 663 | raw_buffer_pos int // The current position of the buffer. 664 | 665 | encoding yaml_encoding_t // The stream encoding. 666 | 667 | // Emitter stuff 668 | 669 | canonical bool // If the output is in the canonical style? 670 | best_indent int // The number of indentation spaces. 671 | best_width int // The preferred width of the output lines. 672 | unicode bool // Allow unescaped non-ASCII characters? 673 | line_break yaml_break_t // The preferred line break. 674 | 675 | state yaml_emitter_state_t // The current emitter state. 676 | states []yaml_emitter_state_t // The stack of states. 677 | 678 | events []yaml_event_t // The event queue. 679 | events_head int // The head of the event queue. 680 | 681 | indents []int // The stack of indentation levels. 682 | 683 | tag_directives []yaml_tag_directive_t // The list of tag directives. 684 | 685 | indent int // The current indentation level. 686 | 687 | flow_level int // The current flow level. 688 | 689 | root_context bool // Is it the document root context? 690 | sequence_context bool // Is it a sequence context? 691 | mapping_context bool // Is it a mapping context? 692 | simple_key_context bool // Is it a simple mapping key context? 693 | 694 | line int // The current line. 695 | column int // The current column. 696 | whitespace bool // If the last character was a whitespace? 697 | indention bool // If the last character was an indentation character (' ', '-', '?', ':')? 698 | open_ended bool // If an explicit document end is required? 699 | 700 | // Anchor analysis. 701 | anchor_data struct { 702 | anchor []byte // The anchor value. 703 | alias bool // Is it an alias? 704 | } 705 | 706 | // Tag analysis. 707 | tag_data struct { 708 | handle []byte // The tag handle. 709 | suffix []byte // The tag suffix. 710 | } 711 | 712 | // Scalar analysis. 713 | scalar_data struct { 714 | value []byte // The scalar value. 715 | multiline bool // Does the scalar contain line breaks? 716 | flow_plain_allowed bool // Can the scalar be expessed in the flow plain style? 717 | block_plain_allowed bool // Can the scalar be expressed in the block plain style? 718 | single_quoted_allowed bool // Can the scalar be expressed in the single quoted style? 719 | block_allowed bool // Can the scalar be expressed in the literal or folded styles? 720 | style yaml_scalar_style_t // The output style. 721 | } 722 | 723 | // Dumper stuff 724 | 725 | opened bool // If the stream was already opened? 726 | closed bool // If the stream was already closed? 727 | 728 | // The information associated with the document nodes. 729 | anchors *struct { 730 | references int // The number of references. 731 | anchor int // The anchor id. 732 | serialized bool // If the node has been emitted? 733 | } 734 | 735 | last_anchor_id int // The last assigned anchor id. 736 | 737 | document *yaml_document_t // The currently emitted document. 738 | } 739 | --------------------------------------------------------------------------------