From 49136f2ce41993a889cb8673edc372e894e4818e Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Mon, 20 Mar 2017 10:24:40 -0500 Subject: [PATCH 01/20] Vendor pelletier/go-toml TOM library and deps github.com/pelletier/go-toml@fee7787d3f811af92276f5ff10107092e95b7a1d - Can't use latest release, it has a show-stopping bug in ToTomlString github.com/pelletier/go-buffruneio@v0.2.0 --- .../pelletier/go-buffruneio/.gitignore | 1 + .../pelletier/go-buffruneio/.travis.yml | 7 + .../pelletier/go-buffruneio/README.md | 62 ++ .../pelletier/go-buffruneio/buffruneio.go | 117 +++ .../go-buffruneio/buffruneio_test.go | 145 ++++ .../github.com/pelletier/go-toml/.gitignore | 1 + .../github.com/pelletier/go-toml/.travis.yml | 21 + vendor/github.com/pelletier/go-toml/LICENSE | 21 + vendor/github.com/pelletier/go-toml/README.md | 120 +++ vendor/github.com/pelletier/go-toml/clean.sh | 6 + .../pelletier/go-toml/cmd/test_program.go | 91 ++ .../pelletier/go-toml/cmd/tomljson/main.go | 67 ++ .../go-toml/cmd/tomljson/main_test.go | 82 ++ .../pelletier/go-toml/cmd/tomll/main.go | 61 ++ vendor/github.com/pelletier/go-toml/doc.go | 250 ++++++ .../github.com/pelletier/go-toml/doc_test.go | 81 ++ .../pelletier/go-toml/example-crlf.toml | 29 + .../github.com/pelletier/go-toml/example.toml | 29 + .../pelletier/go-toml/keysparsing.go | 94 +++ .../pelletier/go-toml/keysparsing_test.go | 56 ++ vendor/github.com/pelletier/go-toml/lexer.go | 657 +++++++++++++++ .../pelletier/go-toml/lexer_test.go | 750 +++++++++++++++++ vendor/github.com/pelletier/go-toml/match.go | 234 ++++++ .../pelletier/go-toml/match_test.go | 201 +++++ vendor/github.com/pelletier/go-toml/parser.go | 393 +++++++++ .../pelletier/go-toml/parser_test.go | 784 ++++++++++++++++++ .../github.com/pelletier/go-toml/position.go | 29 + .../pelletier/go-toml/position_test.go | 29 + vendor/github.com/pelletier/go-toml/query.go | 153 ++++ .../pelletier/go-toml/query_test.go | 70 ++ .../pelletier/go-toml/querylexer.go | 356 ++++++++ .../pelletier/go-toml/querylexer_test.go | 178 ++++ .../pelletier/go-toml/queryparser.go | 275 ++++++ .../pelletier/go-toml/queryparser_test.go | 483 +++++++++++ vendor/github.com/pelletier/go-toml/test.sh | 82 ++ vendor/github.com/pelletier/go-toml/token.go | 140 ++++ .../pelletier/go-toml/token_test.go | 67 ++ vendor/github.com/pelletier/go-toml/toml.go | 284 +++++++ .../github.com/pelletier/go-toml/toml_test.go | 131 +++ .../pelletier/go-toml/tomltree_create.go | 129 +++ .../pelletier/go-toml/tomltree_create_test.go | 95 +++ .../pelletier/go-toml/tomltree_write.go | 209 +++++ .../pelletier/go-toml/tomltree_write_test.go | 284 +++++++ 43 files changed, 7354 insertions(+) create mode 100644 vendor/github.com/pelletier/go-buffruneio/.gitignore create mode 100644 vendor/github.com/pelletier/go-buffruneio/.travis.yml create mode 100644 vendor/github.com/pelletier/go-buffruneio/README.md create mode 100644 vendor/github.com/pelletier/go-buffruneio/buffruneio.go create mode 100644 vendor/github.com/pelletier/go-buffruneio/buffruneio_test.go create mode 100644 vendor/github.com/pelletier/go-toml/.gitignore create mode 100644 vendor/github.com/pelletier/go-toml/.travis.yml create mode 100644 vendor/github.com/pelletier/go-toml/LICENSE create mode 100644 vendor/github.com/pelletier/go-toml/README.md create mode 100755 vendor/github.com/pelletier/go-toml/clean.sh create mode 100644 vendor/github.com/pelletier/go-toml/cmd/test_program.go create mode 100644 vendor/github.com/pelletier/go-toml/cmd/tomljson/main.go create mode 100644 vendor/github.com/pelletier/go-toml/cmd/tomljson/main_test.go create mode 100644 vendor/github.com/pelletier/go-toml/cmd/tomll/main.go create mode 100644 vendor/github.com/pelletier/go-toml/doc.go create mode 100644 vendor/github.com/pelletier/go-toml/doc_test.go create mode 100644 vendor/github.com/pelletier/go-toml/example-crlf.toml create mode 100644 vendor/github.com/pelletier/go-toml/example.toml create mode 100644 vendor/github.com/pelletier/go-toml/keysparsing.go create mode 100644 vendor/github.com/pelletier/go-toml/keysparsing_test.go create mode 100644 vendor/github.com/pelletier/go-toml/lexer.go create mode 100644 vendor/github.com/pelletier/go-toml/lexer_test.go create mode 100644 vendor/github.com/pelletier/go-toml/match.go create mode 100644 vendor/github.com/pelletier/go-toml/match_test.go create mode 100644 vendor/github.com/pelletier/go-toml/parser.go create mode 100644 vendor/github.com/pelletier/go-toml/parser_test.go create mode 100644 vendor/github.com/pelletier/go-toml/position.go create mode 100644 vendor/github.com/pelletier/go-toml/position_test.go create mode 100644 vendor/github.com/pelletier/go-toml/query.go create mode 100644 vendor/github.com/pelletier/go-toml/query_test.go create mode 100644 vendor/github.com/pelletier/go-toml/querylexer.go create mode 100644 vendor/github.com/pelletier/go-toml/querylexer_test.go create mode 100644 vendor/github.com/pelletier/go-toml/queryparser.go create mode 100644 vendor/github.com/pelletier/go-toml/queryparser_test.go create mode 100755 vendor/github.com/pelletier/go-toml/test.sh create mode 100644 vendor/github.com/pelletier/go-toml/token.go create mode 100644 vendor/github.com/pelletier/go-toml/token_test.go create mode 100644 vendor/github.com/pelletier/go-toml/toml.go create mode 100644 vendor/github.com/pelletier/go-toml/toml_test.go create mode 100644 vendor/github.com/pelletier/go-toml/tomltree_create.go create mode 100644 vendor/github.com/pelletier/go-toml/tomltree_create_test.go create mode 100644 vendor/github.com/pelletier/go-toml/tomltree_write.go create mode 100644 vendor/github.com/pelletier/go-toml/tomltree_write_test.go diff --git a/vendor/github.com/pelletier/go-buffruneio/.gitignore b/vendor/github.com/pelletier/go-buffruneio/.gitignore new file mode 100644 index 0000000000..c56069fe26 --- /dev/null +++ b/vendor/github.com/pelletier/go-buffruneio/.gitignore @@ -0,0 +1 @@ +*.test \ No newline at end of file diff --git a/vendor/github.com/pelletier/go-buffruneio/.travis.yml b/vendor/github.com/pelletier/go-buffruneio/.travis.yml new file mode 100644 index 0000000000..9720442cd8 --- /dev/null +++ b/vendor/github.com/pelletier/go-buffruneio/.travis.yml @@ -0,0 +1,7 @@ +language: go +sudo: false +go: + - 1.3.3 + - 1.4.3 + - 1.5.3 + - tip diff --git a/vendor/github.com/pelletier/go-buffruneio/README.md b/vendor/github.com/pelletier/go-buffruneio/README.md new file mode 100644 index 0000000000..ff608b3ab8 --- /dev/null +++ b/vendor/github.com/pelletier/go-buffruneio/README.md @@ -0,0 +1,62 @@ +# buffruneio + +[![Tests Status](https://travis-ci.org/pelletier/go-buffruneio.svg?branch=master)](https://travis-ci.org/pelletier/go-buffruneio) +[![GoDoc](https://godoc.org/github.com/pelletier/go-buffruneio?status.svg)](https://godoc.org/github.com/pelletier/go-buffruneio) + +Buffruneio is a wrapper around bufio to provide buffered runes access with +unlimited unreads. + +```go +import "github.com/pelletier/go-buffruneio" +``` + +## Examples + +```go +import ( + "fmt" + "github.com/pelletier/go-buffruneio" + "strings" +) + +reader := buffruneio.NewReader(strings.NewReader("abcd")) +fmt.Println(reader.ReadRune()) // 'a' +fmt.Println(reader.ReadRune()) // 'b' +fmt.Println(reader.ReadRune()) // 'c' +reader.UnreadRune() +reader.UnreadRune() +fmt.Println(reader.ReadRune()) // 'b' +fmt.Println(reader.ReadRune()) // 'c' +``` + +## Documentation + +The documentation and additional examples are available at +[godoc.org](http://godoc.org/github.com/pelletier/go-buffruneio). + +## Contribute + +Feel free to report bugs and patches using GitHub's pull requests system on +[pelletier/go-toml](https://github.com/pelletier/go-buffruneio). Any feedback is +much appreciated! + +## LICENSE + +Copyright (c) 2016 Thomas Pelletier + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/pelletier/go-buffruneio/buffruneio.go b/vendor/github.com/pelletier/go-buffruneio/buffruneio.go new file mode 100644 index 0000000000..4e6d6ea610 --- /dev/null +++ b/vendor/github.com/pelletier/go-buffruneio/buffruneio.go @@ -0,0 +1,117 @@ +// Package buffruneio is a wrapper around bufio to provide buffered runes access with unlimited unreads. +package buffruneio + +import ( + "bufio" + "container/list" + "errors" + "io" +) + +// Rune to indicate end of file. +const ( + EOF = -(iota + 1) +) + +// ErrNoRuneToUnread is returned by UnreadRune() when the read index is already at the beginning of the buffer. +var ErrNoRuneToUnread = errors.New("no rune to unwind") + +// Reader implements runes buffering for an io.Reader object. +type Reader struct { + buffer *list.List + current *list.Element + input *bufio.Reader +} + +// NewReader returns a new Reader. +func NewReader(rd io.Reader) *Reader { + return &Reader{ + buffer: list.New(), + input: bufio.NewReader(rd), + } +} + +type runeWithSize struct { + r rune + size int +} + +func (rd *Reader) feedBuffer() error { + r, size, err := rd.input.ReadRune() + + if err != nil { + if err != io.EOF { + return err + } + r = EOF + } + + newRuneWithSize := runeWithSize{r, size} + + rd.buffer.PushBack(newRuneWithSize) + if rd.current == nil { + rd.current = rd.buffer.Back() + } + return nil +} + +// ReadRune reads the next rune from buffer, or from the underlying reader if needed. +func (rd *Reader) ReadRune() (rune, int, error) { + if rd.current == rd.buffer.Back() || rd.current == nil { + err := rd.feedBuffer() + if err != nil { + return EOF, 0, err + } + } + + runeWithSize := rd.current.Value.(runeWithSize) + rd.current = rd.current.Next() + return runeWithSize.r, runeWithSize.size, nil +} + +// UnreadRune pushes back the previously read rune in the buffer, extending it if needed. +func (rd *Reader) UnreadRune() error { + if rd.current == rd.buffer.Front() { + return ErrNoRuneToUnread + } + if rd.current == nil { + rd.current = rd.buffer.Back() + } else { + rd.current = rd.current.Prev() + } + return nil +} + +// Forget removes runes stored before the current stream position index. +func (rd *Reader) Forget() { + if rd.current == nil { + rd.current = rd.buffer.Back() + } + for ; rd.current != rd.buffer.Front(); rd.buffer.Remove(rd.current.Prev()) { + } +} + +// PeekRune returns at most the next n runes, reading from the uderlying source if +// needed. Does not move the current index. It includes EOF if reached. +func (rd *Reader) PeekRunes(n int) []rune { + res := make([]rune, 0, n) + cursor := rd.current + for i := 0; i < n; i++ { + if cursor == nil { + err := rd.feedBuffer() + if err != nil { + return res + } + cursor = rd.buffer.Back() + } + if cursor != nil { + r := cursor.Value.(runeWithSize).r + res = append(res, r) + if r == EOF { + return res + } + cursor = cursor.Next() + } + } + return res +} diff --git a/vendor/github.com/pelletier/go-buffruneio/buffruneio_test.go b/vendor/github.com/pelletier/go-buffruneio/buffruneio_test.go new file mode 100644 index 0000000000..67b0cba9b3 --- /dev/null +++ b/vendor/github.com/pelletier/go-buffruneio/buffruneio_test.go @@ -0,0 +1,145 @@ +package buffruneio + +import ( + "runtime/debug" + "strings" + "testing" +) + +func assertNoError(t *testing.T, err error) { + if err != nil { + t.Log("unexpected error", err) + debug.PrintStack() + t.FailNow() + } +} + +func assumeRunesArray(t *testing.T, expected []rune, got []rune) { + if len(expected) != len(got) { + t.Fatal("expected", len(expected), "runes, but got", len(got)) + } + for i := 0; i < len(got); i++ { + if expected[i] != got[i] { + t.Fatal("expected rune", expected[i], "at index", i, "but got", got[i]) + } + } +} + +func assumeRune(t *testing.T, rd *Reader, r rune) { + gotRune, size, err := rd.ReadRune() + assertNoError(t, err) + if gotRune != r { + t.Fatal("got", string(gotRune), + "(", []byte(string(gotRune)), ")", + "expected", string(r), + "(", []byte(string(r)), ")") + t.Fatal("got size", size, + "expected", len([]byte(string(r)))) + } +} + +func TestReadString(t *testing.T) { + s := "hello" + rd := NewReader(strings.NewReader(s)) + + assumeRune(t, rd, 'h') + assumeRune(t, rd, 'e') + assumeRune(t, rd, 'l') + assumeRune(t, rd, 'l') + assumeRune(t, rd, 'o') + assumeRune(t, rd, EOF) +} + +func TestMultipleEOF(t *testing.T) { + s := "" + rd := NewReader(strings.NewReader(s)) + + assumeRune(t, rd, EOF) + assumeRune(t, rd, EOF) +} + +func TestUnread(t *testing.T) { + s := "ab" + rd := NewReader(strings.NewReader(s)) + + assumeRune(t, rd, 'a') + assumeRune(t, rd, 'b') + assertNoError(t, rd.UnreadRune()) + assumeRune(t, rd, 'b') + assumeRune(t, rd, EOF) +} + +func TestUnreadEOF(t *testing.T) { + s := "" + rd := NewReader(strings.NewReader(s)) + + _ = rd.UnreadRune() + assumeRune(t, rd, EOF) + assumeRune(t, rd, EOF) + assertNoError(t, rd.UnreadRune()) + assumeRune(t, rd, EOF) +} + +func TestForget(t *testing.T) { + s := "hello" + rd := NewReader(strings.NewReader(s)) + + assumeRune(t, rd, 'h') + assumeRune(t, rd, 'e') + assumeRune(t, rd, 'l') + assumeRune(t, rd, 'l') + rd.Forget() + if rd.UnreadRune() != ErrNoRuneToUnread { + t.Fatal("no rune should be available") + } +} + +func TestForgetEmpty(t *testing.T) { + s := "" + rd := NewReader(strings.NewReader(s)) + + rd.Forget() + assumeRune(t, rd, EOF) + rd.Forget() +} + +func TestPeekEmpty(t *testing.T) { + s := "" + rd := NewReader(strings.NewReader(s)) + + runes := rd.PeekRunes(1) + if len(runes) != 1 { + t.Fatal("incorrect number of runes", len(runes)) + } + if runes[0] != EOF { + t.Fatal("incorrect rune", runes[0]) + } +} + +func TestPeek(t *testing.T) { + s := "a" + rd := NewReader(strings.NewReader(s)) + + runes := rd.PeekRunes(1) + assumeRunesArray(t, []rune{'a'}, runes) + + runes = rd.PeekRunes(1) + assumeRunesArray(t, []rune{'a'}, runes) + + assumeRune(t, rd, 'a') + runes = rd.PeekRunes(1) + assumeRunesArray(t, []rune{EOF}, runes) + + assumeRune(t, rd, EOF) +} + +func TestPeekLarge(t *testing.T) { + s := "abcdefg" + rd := NewReader(strings.NewReader(s)) + + runes := rd.PeekRunes(100) + if len(runes) != len(s)+1 { + t.Fatal("incorrect number of runes", len(runes)) + } + assumeRunesArray(t, []rune{'a', 'b', 'c', 'd', 'e', 'f', 'g', EOF}, runes) +} diff --git a/vendor/github.com/pelletier/go-toml/.gitignore b/vendor/github.com/pelletier/go-toml/.gitignore new file mode 100644 index 0000000000..f1b619018e --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/.gitignore @@ -0,0 +1 @@ +test_program/test_program_bin diff --git a/vendor/github.com/pelletier/go-toml/.travis.yml b/vendor/github.com/pelletier/go-toml/.travis.yml new file mode 100644 index 0000000000..64f03809a1 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/.travis.yml @@ -0,0 +1,21 @@ +sudo: false +language: go +go: + - 1.6.4 + - 1.7.5 + - 1.8 + - tip +matrix: + allow_failures: + - go: tip + fast_finish: true +script: + - ./test.sh +before_install: + - go get github.com/axw/gocov/gocov + - go get github.com/mattn/goveralls + - if ! go get code.google.com/p/go.tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi +branches: + only: [master] +after_success: + - $HOME/gopath/bin/goveralls -service=travis-ci -coverprofile=coverage.out -repotoken $COVERALLS_TOKEN diff --git a/vendor/github.com/pelletier/go-toml/LICENSE b/vendor/github.com/pelletier/go-toml/LICENSE new file mode 100644 index 0000000000..583bdae628 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013 - 2017 Thomas Pelletier, Eric Anderton + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/pelletier/go-toml/README.md b/vendor/github.com/pelletier/go-toml/README.md new file mode 100644 index 0000000000..b8137e022d --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/README.md @@ -0,0 +1,120 @@ +# go-toml + +Go library for the [TOML](https://github.com/mojombo/toml) format. + +This library supports TOML version +[v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md) + +[![GoDoc](https://godoc.org/github.com/pelletier/go-toml?status.svg)](http://godoc.org/github.com/pelletier/go-toml) +[![license](https://img.shields.io/github/license/pelletier/go-toml.svg)](https://github.com/pelletier/go-toml/blob/master/LICENSE) +[![Build Status](https://travis-ci.org/pelletier/go-toml.svg?branch=master)](https://travis-ci.org/pelletier/go-toml) +[![Coverage Status](https://coveralls.io/repos/github/pelletier/go-toml/badge.svg?branch=master)](https://coveralls.io/github/pelletier/go-toml?branch=master) +[![Go Report Card](https://goreportcard.com/badge/github.com/pelletier/go-toml)](https://goreportcard.com/report/github.com/pelletier/go-toml) + +## Features + +Go-toml provides the following features for using data parsed from TOML documents: + +* Load TOML documents from files and string data +* Easily navigate TOML structure using TomlTree +* Line & column position data for all parsed elements +* Query support similar to JSON-Path +* Syntax errors contain line and column numbers + +Go-toml is designed to help cover use-cases not covered by reflection-based TOML parsing: + +* Semantic evaluation of parsed TOML +* Informing a user of mistakes in the source document, after it has been parsed +* Programatic handling of default values on a case-by-case basis +* Using a TOML document as a flexible data-store + +## Import + + import "github.com/pelletier/go-toml" + +## Usage + +### Example + +Say you have a TOML file that looks like this: + +```toml +[postgres] +user = "pelletier" +password = "mypassword" +``` + +Read the username and password like this: + +```go +import ( + "fmt" + "github.com/pelletier/go-toml" +) + +config, err := toml.LoadFile("config.toml") +if err != nil { + fmt.Println("Error ", err.Error()) +} else { + // retrieve data directly + user := config.Get("postgres.user").(string) + password := config.Get("postgres.password").(string) + + // or using an intermediate object + configTree := config.Get("postgres").(*toml.TomlTree) + user = configTree.Get("user").(string) + password = configTree.Get("password").(string) + fmt.Println("User is ", user, ". Password is ", password) + + // show where elements are in the file + fmt.Println("User position: %v", configTree.GetPosition("user")) + fmt.Println("Password position: %v", configTree.GetPosition("password")) + + // use a query to gather elements without walking the tree + results, _ := config.Query("$..[user,password]") + for ii, item := range results.Values() { + fmt.Println("Query result %d: %v", ii, item) + } +} +``` + +## Documentation + +The documentation and additional examples are available at +[godoc.org](http://godoc.org/github.com/pelletier/go-toml). + +## Tools + +Go-toml provides two handy command line tools: + +* `tomll`: Reads TOML files and lint them. + + ``` + go install github.com/pelletier/go-toml/cmd/tomll + tomll --help + ``` +* `tomljson`: Reads a TOML file and outputs its JSON representation. + + ``` + go install github.com/pelletier/go-toml/cmd/tomljson + tomljson --help + ``` + +## Contribute + +Feel free to report bugs and patches using GitHub's pull requests system on +[pelletier/go-toml](https://github.com/pelletier/go-toml). Any feedback would be +much appreciated! + +### Run tests + +You have to make sure two kind of tests run: + +1. The Go unit tests +2. The TOML examples base + +You can run both of them using `./test.sh`. + +## License + +The MIT License (MIT). Read [LICENSE](LICENSE). diff --git a/vendor/github.com/pelletier/go-toml/clean.sh b/vendor/github.com/pelletier/go-toml/clean.sh new file mode 100755 index 0000000000..44d49d936d --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/clean.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# fail out of the script if anything here fails +set -e + +# clear out stuff generated by test.sh +rm -rf src test_program_bin toml-test diff --git a/vendor/github.com/pelletier/go-toml/cmd/test_program.go b/vendor/github.com/pelletier/go-toml/cmd/test_program.go new file mode 100644 index 0000000000..58293446bd --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/cmd/test_program.go @@ -0,0 +1,91 @@ +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + "os" + "time" + + "github.com/pelletier/go-toml" +) + +func main() { + bytes, err := ioutil.ReadAll(os.Stdin) + if err != nil { + log.Fatalf("Error during TOML read: %s", err) + os.Exit(2) + } + tree, err := toml.Load(string(bytes)) + if err != nil { + log.Fatalf("Error during TOML load: %s", err) + os.Exit(1) + } + + typedTree := translate(*tree) + + if err := json.NewEncoder(os.Stdout).Encode(typedTree); err != nil { + log.Fatalf("Error encoding JSON: %s", err) + os.Exit(3) + } + + os.Exit(0) +} + +func translate(tomlData interface{}) interface{} { + switch orig := tomlData.(type) { + case map[string]interface{}: + typed := make(map[string]interface{}, len(orig)) + for k, v := range orig { + typed[k] = translate(v) + } + return typed + case *toml.TomlTree: + return translate(*orig) + case toml.TomlTree: + keys := orig.Keys() + typed := make(map[string]interface{}, len(keys)) + for _, k := range keys { + typed[k] = translate(orig.GetPath([]string{k})) + } + return typed + case []*toml.TomlTree: + typed := make([]map[string]interface{}, len(orig)) + for i, v := range orig { + typed[i] = translate(v).(map[string]interface{}) + } + return typed + case []map[string]interface{}: + typed := make([]map[string]interface{}, len(orig)) + for i, v := range orig { + typed[i] = translate(v).(map[string]interface{}) + } + return typed + case []interface{}: + typed := make([]interface{}, len(orig)) + for i, v := range orig { + typed[i] = translate(v) + } + return tag("array", typed) + case time.Time: + return tag("datetime", orig.Format("2006-01-02T15:04:05Z")) + case bool: + return tag("bool", fmt.Sprintf("%v", orig)) + case int64: + return tag("integer", fmt.Sprintf("%d", orig)) + case float64: + return tag("float", fmt.Sprintf("%v", orig)) + case string: + return tag("string", orig) + } + + panic(fmt.Sprintf("Unknown type: %T", tomlData)) +} + +func tag(typeName string, data interface{}) map[string]interface{} { + return map[string]interface{}{ + "type": typeName, + "value": data, + } +} diff --git a/vendor/github.com/pelletier/go-toml/cmd/tomljson/main.go b/vendor/github.com/pelletier/go-toml/cmd/tomljson/main.go new file mode 100644 index 0000000000..7e9dc467ea --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/cmd/tomljson/main.go @@ -0,0 +1,67 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "io" + "os" + + "github.com/pelletier/go-toml" +) + +func main() { + flag.Usage = func() { + fmt.Fprintln(os.Stderr, `tomljson can be used in two ways: +Writing to STDIN and reading from STDOUT: + cat file.toml | tomljson > file.json + +Reading from a file name: + tomljson file.toml +`) + } + flag.Parse() + os.Exit(processMain(flag.Args(), os.Stdin, os.Stdout, os.Stderr)) +} + +func processMain(files []string, defaultInput io.Reader, output io.Writer, errorOutput io.Writer) int { + // read from stdin and print to stdout + inputReader := defaultInput + + if len(files) > 0 { + var err error + inputReader, err = os.Open(files[0]) + if err != nil { + printError(err, errorOutput) + return -1 + } + } + s, err := reader(inputReader) + if err != nil { + printError(err, errorOutput) + return -1 + } + io.WriteString(output, s+"\n") + return 0 +} + +func printError(err error, output io.Writer) { + io.WriteString(output, err.Error()+"\n") +} + +func reader(r io.Reader) (string, error) { + tree, err := toml.LoadReader(r) + if err != nil { + return "", err + } + return mapToJSON(tree) +} + +func mapToJSON(tree *toml.TomlTree) (string, error) { + treeMap := tree.ToMap() + bytes, err := json.MarshalIndent(treeMap, "", " ") + if err != nil { + return "", err + } + return string(bytes[:]), nil +} diff --git a/vendor/github.com/pelletier/go-toml/cmd/tomljson/main_test.go b/vendor/github.com/pelletier/go-toml/cmd/tomljson/main_test.go new file mode 100644 index 0000000000..0b4bdbb11b --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/cmd/tomljson/main_test.go @@ -0,0 +1,82 @@ +package main + +import ( + "bytes" + "io/ioutil" + "os" + "strings" + "testing" +) + +func expectBufferEquality(t *testing.T, name string, buffer *bytes.Buffer, expected string) { + output := buffer.String() + if output != expected { + t.Errorf("incorrect %s:\n%s\n\nexpected %s:\n%s", name, output, name, expected) + t.Log([]rune(output)) + t.Log([]rune(expected)) + } +} + +func expectProcessMainResults(t *testing.T, input string, args []string, exitCode int, expectedOutput string, expectedError string) { + inputReader := strings.NewReader(input) + outputBuffer := new(bytes.Buffer) + errorBuffer := new(bytes.Buffer) + + returnCode := processMain(args, inputReader, outputBuffer, errorBuffer) + + expectBufferEquality(t, "output", outputBuffer, expectedOutput) + expectBufferEquality(t, "error", errorBuffer, expectedError) + + if returnCode != exitCode { + t.Error("incorrect return code:", returnCode, "expected", exitCode) + } +} + +func TestProcessMainReadFromStdin(t *testing.T) { + input := ` + [mytoml] + a = 42` + expectedOutput := `{ + "mytoml": { + "a": 42 + } +} +` + expectedError := `` + expectedExitCode := 0 + + expectProcessMainResults(t, input, []string{}, expectedExitCode, expectedOutput, expectedError) +} + +func TestProcessMainReadFromFile(t *testing.T) { + input := ` + [mytoml] + a = 42` + + tmpfile, err := ioutil.TempFile("", "example.toml") + if err != nil { + t.Fatal(err) + } + if _, err := tmpfile.Write([]byte(input)); err != nil { + t.Fatal(err) + } + + defer os.Remove(tmpfile.Name()) + + expectedOutput := `{ + "mytoml": { + "a": 42 + } +} +` + expectedError := `` + expectedExitCode := 0 + + expectProcessMainResults(t, ``, []string{tmpfile.Name()}, expectedExitCode, expectedOutput, expectedError) +} + +func TestProcessMainReadFromMissingFile(t *testing.T) { + expectedError := `open /this/file/does/not/exist: no such file or directory +` + expectProcessMainResults(t, ``, []string{"/this/file/does/not/exist"}, -1, ``, expectedError) +} diff --git a/vendor/github.com/pelletier/go-toml/cmd/tomll/main.go b/vendor/github.com/pelletier/go-toml/cmd/tomll/main.go new file mode 100644 index 0000000000..f185c56b98 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/cmd/tomll/main.go @@ -0,0 +1,61 @@ +package main + +import ( + "flag" + "fmt" + "io" + "io/ioutil" + "os" + + "github.com/pelletier/go-toml" +) + +func main() { + flag.Usage = func() { + fmt.Fprintln(os.Stderr, `tomll can be used in two ways: +Writing to STDIN and reading from STDOUT: + cat file.toml | tomll > file.toml + +Reading and updating a list of files: + tomll a.toml b.toml c.toml + +When given a list of files, tomll will modify all files in place without asking. +`) + } + flag.Parse() + // read from stdin and print to stdout + if flag.NArg() == 0 { + s, err := lintReader(os.Stdin) + if err != nil { + io.WriteString(os.Stderr, err.Error()) + os.Exit(-1) + } + io.WriteString(os.Stdout, s) + } else { + // otherwise modify a list of files + for _, filename := range flag.Args() { + s, err := lintFile(filename) + if err != nil { + io.WriteString(os.Stderr, err.Error()) + os.Exit(-1) + } + ioutil.WriteFile(filename, []byte(s), 0644) + } + } +} + +func lintFile(filename string) (string, error) { + tree, err := toml.LoadFile(filename) + if err != nil { + return "", err + } + return tree.String(), nil +} + +func lintReader(r io.Reader) (string, error) { + tree, err := toml.LoadReader(r) + if err != nil { + return "", err + } + return tree.String(), nil +} diff --git a/vendor/github.com/pelletier/go-toml/doc.go b/vendor/github.com/pelletier/go-toml/doc.go new file mode 100644 index 0000000000..9156b736fc --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/doc.go @@ -0,0 +1,250 @@ +// Package toml is a TOML markup language parser. +// +// This version supports the specification as described in +// https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md +// +// TOML Parsing +// +// TOML data may be parsed in two ways: by file, or by string. +// +// // load TOML data by filename +// tree, err := toml.LoadFile("filename.toml") +// +// // load TOML data stored in a string +// tree, err := toml.Load(stringContainingTomlData) +// +// Either way, the result is a TomlTree object that can be used to navigate the +// structure and data within the original document. +// +// +// Getting data from the TomlTree +// +// After parsing TOML data with Load() or LoadFile(), use the Has() and Get() +// methods on the returned TomlTree, to find your way through the document data. +// +// if tree.Has("foo") { +// fmt.Println("foo is:", tree.Get("foo")) +// } +// +// Working with Paths +// +// Go-toml has support for basic dot-separated key paths on the Has(), Get(), Set() +// and GetDefault() methods. These are the same kind of key paths used within the +// TOML specification for struct tames. +// +// // looks for a key named 'baz', within struct 'bar', within struct 'foo' +// tree.Has("foo.bar.baz") +// +// // returns the key at this path, if it is there +// tree.Get("foo.bar.baz") +// +// TOML allows keys to contain '.', which can cause this syntax to be problematic +// for some documents. In such cases, use the GetPath(), HasPath(), and SetPath(), +// methods to explicitly define the path. This form is also faster, since +// it avoids having to parse the passed key for '.' delimiters. +// +// // looks for a key named 'baz', within struct 'bar', within struct 'foo' +// tree.HasPath([]string{"foo","bar","baz"}) +// +// // returns the key at this path, if it is there +// tree.GetPath([]string{"foo","bar","baz"}) +// +// Note that this is distinct from the heavyweight query syntax supported by +// TomlTree.Query() and the Query() struct (see below). +// +// Position Support +// +// Each element within the TomlTree is stored with position metadata, which is +// invaluable for providing semantic feedback to a user. This helps in +// situations where the TOML file parses correctly, but contains data that is +// not correct for the application. In such cases, an error message can be +// generated that indicates the problem line and column number in the source +// TOML document. +// +// // load TOML data +// tree, _ := toml.Load("filename.toml") +// +// // get an entry and report an error if it's the wrong type +// element := tree.Get("foo") +// if value, ok := element.(int64); !ok { +// return fmt.Errorf("%v: Element 'foo' must be an integer", tree.GetPosition("foo")) +// } +// +// // report an error if an expected element is missing +// if !tree.Has("bar") { +// return fmt.Errorf("%v: Expected 'bar' element", tree.GetPosition("")) +// } +// +// Query Support +// +// The TOML query path implementation is based loosely on the JSONPath specification: +// http://goessner.net/articles/JsonPath/ +// +// The idea behind a query path is to allow quick access to any element, or set +// of elements within TOML document, with a single expression. +// +// result, err := tree.Query("$.foo.bar.baz") +// +// This is roughly equivalent to: +// +// next := tree.Get("foo") +// if next != nil { +// next = next.Get("bar") +// if next != nil { +// next = next.Get("baz") +// } +// } +// result := next +// +// err is nil if any parsing exception occurs. +// +// If no node in the tree matches the query, result will simply contain an empty list of +// items. +// +// As illustrated above, the query path is much more efficient, especially since +// the structure of the TOML file can vary. Rather than making assumptions about +// a document's structure, a query allows the programmer to make structured +// requests into the document, and get zero or more values as a result. +// +// The syntax of a query begins with a root token, followed by any number +// sub-expressions: +// +// $ +// Root of the TOML tree. This must always come first. +// .name +// Selects child of this node, where 'name' is a TOML key +// name. +// ['name'] +// Selects child of this node, where 'name' is a string +// containing a TOML key name. +// [index] +// Selcts child array element at 'index'. +// ..expr +// Recursively selects all children, filtered by an a union, +// index, or slice expression. +// ..* +// Recursive selection of all nodes at this point in the +// tree. +// .* +// Selects all children of the current node. +// [expr,expr] +// Union operator - a logical 'or' grouping of two or more +// sub-expressions: index, key name, or filter. +// [start:end:step] +// Slice operator - selects array elements from start to +// end-1, at the given step. All three arguments are +// optional. +// [?(filter)] +// Named filter expression - the function 'filter' is +// used to filter children at this node. +// +// Query Indexes And Slices +// +// Index expressions perform no bounds checking, and will contribute no +// values to the result set if the provided index or index range is invalid. +// Negative indexes represent values from the end of the array, counting backwards. +// +// // select the last index of the array named 'foo' +// tree.Query("$.foo[-1]") +// +// Slice expressions are supported, by using ':' to separate a start/end index pair. +// +// // select up to the first five elements in the array +// tree.Query("$.foo[0:5]") +// +// Slice expressions also allow negative indexes for the start and stop +// arguments. +// +// // select all array elements. +// tree.Query("$.foo[0:-1]") +// +// Slice expressions may have an optional stride/step parameter: +// +// // select every other element +// tree.Query("$.foo[0:-1:2]") +// +// Slice start and end parameters are also optional: +// +// // these are all equivalent and select all the values in the array +// tree.Query("$.foo[:]") +// tree.Query("$.foo[0:]") +// tree.Query("$.foo[:-1]") +// tree.Query("$.foo[0:-1:]") +// tree.Query("$.foo[::1]") +// tree.Query("$.foo[0::1]") +// tree.Query("$.foo[:-1:1]") +// tree.Query("$.foo[0:-1:1]") +// +// Query Filters +// +// Query filters are used within a Union [,] or single Filter [] expression. +// A filter only allows nodes that qualify through to the next expression, +// and/or into the result set. +// +// // returns children of foo that are permitted by the 'bar' filter. +// tree.Query("$.foo[?(bar)]") +// +// There are several filters provided with the library: +// +// tree +// Allows nodes of type TomlTree. +// int +// Allows nodes of type int64. +// float +// Allows nodes of type float64. +// string +// Allows nodes of type string. +// time +// Allows nodes of type time.Time. +// bool +// Allows nodes of type bool. +// +// Query Results +// +// An executed query returns a QueryResult object. This contains the nodes +// in the TOML tree that qualify the query expression. Position information +// is also available for each value in the set. +// +// // display the results of a query +// results := tree.Query("$.foo.bar.baz") +// for idx, value := results.Values() { +// fmt.Println("%v: %v", results.Positions()[idx], value) +// } +// +// Compiled Queries +// +// Queries may be executed directly on a TomlTree object, or compiled ahead +// of time and executed discretely. The former is more convienent, but has the +// penalty of having to recompile the query expression each time. +// +// // basic query +// results := tree.Query("$.foo.bar.baz") +// +// // compiled query +// query := toml.CompileQuery("$.foo.bar.baz") +// results := query.Execute(tree) +// +// // run the compiled query again on a different tree +// moreResults := query.Execute(anotherTree) +// +// User Defined Query Filters +// +// Filter expressions may also be user defined by using the SetFilter() +// function on the Query object. The function must return true/false, which +// signifies if the passed node is kept or discarded, respectively. +// +// // create a query that references a user-defined filter +// query, _ := CompileQuery("$[?(bazOnly)]") +// +// // define the filter, and assign it to the query +// query.SetFilter("bazOnly", func(node interface{}) bool{ +// if tree, ok := node.(*TomlTree); ok { +// return tree.Has("baz") +// } +// return false // reject all other node types +// }) +// +// // run the query +// query.Execute(tree) +// +package toml diff --git a/vendor/github.com/pelletier/go-toml/doc_test.go b/vendor/github.com/pelletier/go-toml/doc_test.go new file mode 100644 index 0000000000..69452415a2 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/doc_test.go @@ -0,0 +1,81 @@ +// code examples for godoc + +package toml + +import ( + "fmt" +) + +func ExampleNodeFilterFn_filterExample() { + tree, _ := Load(` + [struct_one] + foo = "foo" + bar = "bar" + + [struct_two] + baz = "baz" + gorf = "gorf" + `) + + // create a query that references a user-defined-filter + query, _ := CompileQuery("$[?(bazOnly)]") + + // define the filter, and assign it to the query + query.SetFilter("bazOnly", func(node interface{}) bool { + if tree, ok := node.(*TomlTree); ok { + return tree.Has("baz") + } + return false // reject all other node types + }) + + // results contain only the 'struct_two' TomlTree + query.Execute(tree) +} + +func ExampleQuery_queryExample() { + config, _ := Load(` + [[book]] + title = "The Stand" + author = "Stephen King" + [[book]] + title = "For Whom the Bell Tolls" + author = "Ernest Hemmingway" + [[book]] + title = "Neuromancer" + author = "William Gibson" + `) + + // find and print all the authors in the document + authors, _ := config.Query("$.book.author") + for _, name := range authors.Values() { + fmt.Println(name) + } +} + +func Example_comprehensiveExample() { + config, err := LoadFile("config.toml") + + if err != nil { + fmt.Println("Error ", err.Error()) + } else { + // retrieve data directly + user := config.Get("postgres.user").(string) + password := config.Get("postgres.password").(string) + + // or using an intermediate object + configTree := config.Get("postgres").(*TomlTree) + user = configTree.Get("user").(string) + password = configTree.Get("password").(string) + fmt.Println("User is ", user, ". Password is ", password) + + // show where elements are in the file + fmt.Printf("User position: %v\n", configTree.GetPosition("user")) + fmt.Printf("Password position: %v\n", configTree.GetPosition("password")) + + // use a query to gather elements without walking the tree + results, _ := config.Query("$..[user,password]") + for ii, item := range results.Values() { + fmt.Printf("Query result %d: %v\n", ii, item) + } + } +} diff --git a/vendor/github.com/pelletier/go-toml/example-crlf.toml b/vendor/github.com/pelletier/go-toml/example-crlf.toml new file mode 100644 index 0000000000..12950a163d --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/example-crlf.toml @@ -0,0 +1,29 @@ +# This is a TOML document. Boom. + +title = "TOML Example" + +[owner] +name = "Tom Preston-Werner" +organization = "GitHub" +bio = "GitHub Cofounder & CEO\nLikes tater tots and beer." +dob = 1979-05-27T07:32:00Z # First class dates? Why not? + +[database] +server = "192.168.1.1" +ports = [ 8001, 8001, 8002 ] +connection_max = 5000 +enabled = true + +[servers] + + # You can indent as you please. Tabs or spaces. TOML don't care. + [servers.alpha] + ip = "10.0.0.1" + dc = "eqdc10" + + [servers.beta] + ip = "10.0.0.2" + dc = "eqdc10" + +[clients] +data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it diff --git a/vendor/github.com/pelletier/go-toml/example.toml b/vendor/github.com/pelletier/go-toml/example.toml new file mode 100644 index 0000000000..3d902f2820 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/example.toml @@ -0,0 +1,29 @@ +# This is a TOML document. Boom. + +title = "TOML Example" + +[owner] +name = "Tom Preston-Werner" +organization = "GitHub" +bio = "GitHub Cofounder & CEO\nLikes tater tots and beer." +dob = 1979-05-27T07:32:00Z # First class dates? Why not? + +[database] +server = "192.168.1.1" +ports = [ 8001, 8001, 8002 ] +connection_max = 5000 +enabled = true + +[servers] + + # You can indent as you please. Tabs or spaces. TOML don't care. + [servers.alpha] + ip = "10.0.0.1" + dc = "eqdc10" + + [servers.beta] + ip = "10.0.0.2" + dc = "eqdc10" + +[clients] +data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it diff --git a/vendor/github.com/pelletier/go-toml/keysparsing.go b/vendor/github.com/pelletier/go-toml/keysparsing.go new file mode 100644 index 0000000000..d62ca5fd1d --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/keysparsing.go @@ -0,0 +1,94 @@ +// Parsing keys handling both bare and quoted keys. + +package toml + +import ( + "bytes" + "errors" + "fmt" + "unicode" +) + +func parseKey(key string) ([]string, error) { + groups := []string{} + var buffer bytes.Buffer + inQuotes := false + wasInQuotes := false + escapeNext := false + ignoreSpace := true + expectDot := false + + for _, char := range key { + if ignoreSpace { + if char == ' ' { + continue + } + ignoreSpace = false + } + if escapeNext { + buffer.WriteRune(char) + escapeNext = false + continue + } + switch char { + case '\\': + escapeNext = true + continue + case '"': + if inQuotes { + groups = append(groups, buffer.String()) + buffer.Reset() + wasInQuotes = true + } + inQuotes = !inQuotes + expectDot = false + case '.': + if inQuotes { + buffer.WriteRune(char) + } else { + if !wasInQuotes { + if buffer.Len() == 0 { + return nil, errors.New("empty table key") + } + groups = append(groups, buffer.String()) + buffer.Reset() + } + ignoreSpace = true + expectDot = false + wasInQuotes = false + } + case ' ': + if inQuotes { + buffer.WriteRune(char) + } else { + expectDot = true + } + default: + if !inQuotes && !isValidBareChar(char) { + return nil, fmt.Errorf("invalid bare character: %c", char) + } + if !inQuotes && expectDot { + return nil, errors.New("what?") + } + buffer.WriteRune(char) + expectDot = false + } + } + if inQuotes { + return nil, errors.New("mismatched quotes") + } + if escapeNext { + return nil, errors.New("unfinished escape sequence") + } + if buffer.Len() > 0 { + groups = append(groups, buffer.String()) + } + if len(groups) == 0 { + return nil, errors.New("empty key") + } + return groups, nil +} + +func isValidBareChar(r rune) bool { + return isAlphanumeric(r) || r == '-' || unicode.IsNumber(r) +} diff --git a/vendor/github.com/pelletier/go-toml/keysparsing_test.go b/vendor/github.com/pelletier/go-toml/keysparsing_test.go new file mode 100644 index 0000000000..1a9ecccaa9 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/keysparsing_test.go @@ -0,0 +1,56 @@ +package toml + +import ( + "fmt" + "testing" +) + +func testResult(t *testing.T, key string, expected []string) { + parsed, err := parseKey(key) + t.Logf("key=%s expected=%s parsed=%s", key, expected, parsed) + if err != nil { + t.Fatal("Unexpected error:", err) + } + if len(expected) != len(parsed) { + t.Fatal("Expected length", len(expected), "but", len(parsed), "parsed") + } + for index, expectedKey := range expected { + if expectedKey != parsed[index] { + t.Fatal("Expected", expectedKey, "at index", index, "but found", parsed[index]) + } + } +} + +func testError(t *testing.T, key string, expectedError string) { + _, err := parseKey(key) + if fmt.Sprintf("%s", err) != expectedError { + t.Fatalf("Expected error \"%s\", but got \"%s\".", expectedError, err) + } +} + +func TestBareKeyBasic(t *testing.T) { + testResult(t, "test", []string{"test"}) +} + +func TestBareKeyDotted(t *testing.T) { + testResult(t, "this.is.a.key", []string{"this", "is", "a", "key"}) +} + +func TestDottedKeyBasic(t *testing.T) { + testResult(t, "\"a.dotted.key\"", []string{"a.dotted.key"}) +} + +func TestBaseKeyPound(t *testing.T) { + testError(t, "hello#world", "invalid bare character: #") +} + +func TestQuotedKeys(t *testing.T) { + testResult(t, `hello."foo".bar`, []string{"hello", "foo", "bar"}) + testResult(t, `"hello!"`, []string{"hello!"}) +} + +func TestEmptyKey(t *testing.T) { + testError(t, "", "empty key") + testError(t, " ", "empty key") + testResult(t, `""`, []string{""}) +} diff --git a/vendor/github.com/pelletier/go-toml/lexer.go b/vendor/github.com/pelletier/go-toml/lexer.go new file mode 100644 index 0000000000..104f3b1f46 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/lexer.go @@ -0,0 +1,657 @@ +// TOML lexer. +// +// Written using the principles developed by Rob Pike in +// http://www.youtube.com/watch?v=HxaD_trXwRE + +package toml + +import ( + "errors" + "fmt" + "io" + "regexp" + "strconv" + "strings" + + "github.com/pelletier/go-buffruneio" +) + +var dateRegexp *regexp.Regexp + +// Define state functions +type tomlLexStateFn func() tomlLexStateFn + +// Define lexer +type tomlLexer struct { + input *buffruneio.Reader // Textual source + buffer []rune // Runes composing the current token + tokens chan token + depth int + line int + col int + endbufferLine int + endbufferCol int +} + +// Basic read operations on input + +func (l *tomlLexer) read() rune { + r, _, err := l.input.ReadRune() + if err != nil { + panic(err) + } + if r == '\n' { + l.endbufferLine++ + l.endbufferCol = 1 + } else { + l.endbufferCol++ + } + return r +} + +func (l *tomlLexer) next() rune { + r := l.read() + + if r != eof { + l.buffer = append(l.buffer, r) + } + return r +} + +func (l *tomlLexer) ignore() { + l.buffer = make([]rune, 0) + l.line = l.endbufferLine + l.col = l.endbufferCol +} + +func (l *tomlLexer) skip() { + l.next() + l.ignore() +} + +func (l *tomlLexer) fastForward(n int) { + for i := 0; i < n; i++ { + l.next() + } +} + +func (l *tomlLexer) emitWithValue(t tokenType, value string) { + l.tokens <- token{ + Position: Position{l.line, l.col}, + typ: t, + val: value, + } + l.ignore() +} + +func (l *tomlLexer) emit(t tokenType) { + l.emitWithValue(t, string(l.buffer)) +} + +func (l *tomlLexer) peek() rune { + r, _, err := l.input.ReadRune() + if err != nil { + panic(err) + } + l.input.UnreadRune() + return r +} + +func (l *tomlLexer) follow(next string) bool { + for _, expectedRune := range next { + r, _, err := l.input.ReadRune() + defer l.input.UnreadRune() + if err != nil { + panic(err) + } + if expectedRune != r { + return false + } + } + return true +} + +// Error management + +func (l *tomlLexer) errorf(format string, args ...interface{}) tomlLexStateFn { + l.tokens <- token{ + Position: Position{l.line, l.col}, + typ: tokenError, + val: fmt.Sprintf(format, args...), + } + return nil +} + +// State functions + +func (l *tomlLexer) lexVoid() tomlLexStateFn { + for { + next := l.peek() + switch next { + case '[': + return l.lexTableKey + case '#': + return l.lexComment(l.lexVoid) + case '=': + return l.lexEqual + case '\r': + fallthrough + case '\n': + l.skip() + continue + } + + if isSpace(next) { + l.skip() + } + + if l.depth > 0 { + return l.lexRvalue + } + + if isKeyStartChar(next) { + return l.lexKey + } + + if next == eof { + l.next() + break + } + } + + l.emit(tokenEOF) + return nil +} + +func (l *tomlLexer) lexRvalue() tomlLexStateFn { + for { + next := l.peek() + switch next { + case '.': + return l.errorf("cannot start float with a dot") + case '=': + return l.lexEqual + case '[': + l.depth++ + return l.lexLeftBracket + case ']': + l.depth-- + return l.lexRightBracket + case '{': + return l.lexLeftCurlyBrace + case '}': + return l.lexRightCurlyBrace + case '#': + return l.lexComment(l.lexRvalue) + case '"': + return l.lexString + case '\'': + return l.lexLiteralString + case ',': + return l.lexComma + case '\r': + fallthrough + case '\n': + l.skip() + if l.depth == 0 { + return l.lexVoid + } + return l.lexRvalue + case '_': + return l.errorf("cannot start number with underscore") + } + + if l.follow("true") { + return l.lexTrue + } + + if l.follow("false") { + return l.lexFalse + } + + if isSpace(next) { + l.skip() + continue + } + + if next == eof { + l.next() + break + } + + possibleDate := string(l.input.PeekRunes(35)) + dateMatch := dateRegexp.FindString(possibleDate) + if dateMatch != "" { + l.fastForward(len(dateMatch)) + return l.lexDate + } + + if next == '+' || next == '-' || isDigit(next) { + return l.lexNumber + } + + if isAlphanumeric(next) { + return l.lexKey + } + + return l.errorf("no value can start with %c", next) + } + + l.emit(tokenEOF) + return nil +} + +func (l *tomlLexer) lexLeftCurlyBrace() tomlLexStateFn { + l.next() + l.emit(tokenLeftCurlyBrace) + return l.lexRvalue +} + +func (l *tomlLexer) lexRightCurlyBrace() tomlLexStateFn { + l.next() + l.emit(tokenRightCurlyBrace) + return l.lexRvalue +} + +func (l *tomlLexer) lexDate() tomlLexStateFn { + l.emit(tokenDate) + return l.lexRvalue +} + +func (l *tomlLexer) lexTrue() tomlLexStateFn { + l.fastForward(4) + l.emit(tokenTrue) + return l.lexRvalue +} + +func (l *tomlLexer) lexFalse() tomlLexStateFn { + l.fastForward(5) + l.emit(tokenFalse) + return l.lexRvalue +} + +func (l *tomlLexer) lexEqual() tomlLexStateFn { + l.next() + l.emit(tokenEqual) + return l.lexRvalue +} + +func (l *tomlLexer) lexComma() tomlLexStateFn { + l.next() + l.emit(tokenComma) + return l.lexRvalue +} + +func (l *tomlLexer) lexKey() tomlLexStateFn { + growingString := "" + + for r := l.peek(); isKeyChar(r) || r == '\n' || r == '\r'; r = l.peek() { + if r == '"' { + l.next() + str, err := l.lexStringAsString(`"`, false, true) + if err != nil { + return l.errorf(err.Error()) + } + growingString += `"` + str + `"` + l.next() + continue + } else if r == '\n' { + return l.errorf("keys cannot contain new lines") + } else if isSpace(r) { + break + } else if !isValidBareChar(r) { + return l.errorf("keys cannot contain %c character", r) + } + growingString += string(r) + l.next() + } + l.emitWithValue(tokenKey, growingString) + return l.lexVoid +} + +func (l *tomlLexer) lexComment(previousState tomlLexStateFn) tomlLexStateFn { + return func() tomlLexStateFn { + for next := l.peek(); next != '\n' && next != eof; next = l.peek() { + if next == '\r' && l.follow("\r\n") { + break + } + l.next() + } + l.ignore() + return previousState + } +} + +func (l *tomlLexer) lexLeftBracket() tomlLexStateFn { + l.next() + l.emit(tokenLeftBracket) + return l.lexRvalue +} + +func (l *tomlLexer) lexLiteralStringAsString(terminator string, discardLeadingNewLine bool) (string, error) { + growingString := "" + + if discardLeadingNewLine { + if l.follow("\r\n") { + l.skip() + l.skip() + } else if l.peek() == '\n' { + l.skip() + } + } + + // find end of string + for { + if l.follow(terminator) { + return growingString, nil + } + + next := l.peek() + if next == eof { + break + } + growingString += string(l.next()) + } + + return "", errors.New("unclosed string") +} + +func (l *tomlLexer) lexLiteralString() tomlLexStateFn { + l.skip() + + // handle special case for triple-quote + terminator := "'" + discardLeadingNewLine := false + if l.follow("''") { + l.skip() + l.skip() + terminator = "'''" + discardLeadingNewLine = true + } + + str, err := l.lexLiteralStringAsString(terminator, discardLeadingNewLine) + if err != nil { + return l.errorf(err.Error()) + } + + l.emitWithValue(tokenString, str) + l.fastForward(len(terminator)) + l.ignore() + return l.lexRvalue +} + +// Lex a string and return the results as a string. +// Terminator is the substring indicating the end of the token. +// The resulting string does not include the terminator. +func (l *tomlLexer) lexStringAsString(terminator string, discardLeadingNewLine, acceptNewLines bool) (string, error) { + growingString := "" + + if discardLeadingNewLine { + if l.follow("\r\n") { + l.skip() + l.skip() + } else if l.peek() == '\n' { + l.skip() + } + } + + for { + if l.follow(terminator) { + return growingString, nil + } + + if l.follow("\\") { + l.next() + switch l.peek() { + case '\r': + fallthrough + case '\n': + fallthrough + case '\t': + fallthrough + case ' ': + // skip all whitespace chars following backslash + for strings.ContainsRune("\r\n\t ", l.peek()) { + l.next() + } + case '"': + growingString += "\"" + l.next() + case 'n': + growingString += "\n" + l.next() + case 'b': + growingString += "\b" + l.next() + case 'f': + growingString += "\f" + l.next() + case '/': + growingString += "/" + l.next() + case 't': + growingString += "\t" + l.next() + case 'r': + growingString += "\r" + l.next() + case '\\': + growingString += "\\" + l.next() + case 'u': + l.next() + code := "" + for i := 0; i < 4; i++ { + c := l.peek() + if !isHexDigit(c) { + return "", errors.New("unfinished unicode escape") + } + l.next() + code = code + string(c) + } + intcode, err := strconv.ParseInt(code, 16, 32) + if err != nil { + return "", errors.New("invalid unicode escape: \\u" + code) + } + growingString += string(rune(intcode)) + case 'U': + l.next() + code := "" + for i := 0; i < 8; i++ { + c := l.peek() + if !isHexDigit(c) { + return "", errors.New("unfinished unicode escape") + } + l.next() + code = code + string(c) + } + intcode, err := strconv.ParseInt(code, 16, 64) + if err != nil { + return "", errors.New("invalid unicode escape: \\U" + code) + } + growingString += string(rune(intcode)) + default: + return "", errors.New("invalid escape sequence: \\" + string(l.peek())) + } + } else { + r := l.peek() + + if 0x00 <= r && r <= 0x1F && !(acceptNewLines && (r == '\n' || r == '\r')) { + return "", fmt.Errorf("unescaped control character %U", r) + } + l.next() + growingString += string(r) + } + + if l.peek() == eof { + break + } + } + + return "", errors.New("unclosed string") +} + +func (l *tomlLexer) lexString() tomlLexStateFn { + l.skip() + + // handle special case for triple-quote + terminator := `"` + discardLeadingNewLine := false + acceptNewLines := false + if l.follow(`""`) { + l.skip() + l.skip() + terminator = `"""` + discardLeadingNewLine = true + acceptNewLines = true + } + + str, err := l.lexStringAsString(terminator, discardLeadingNewLine, acceptNewLines) + + if err != nil { + return l.errorf(err.Error()) + } + + l.emitWithValue(tokenString, str) + l.fastForward(len(terminator)) + l.ignore() + return l.lexRvalue +} + +func (l *tomlLexer) lexTableKey() tomlLexStateFn { + l.next() + + if l.peek() == '[' { + // token '[[' signifies an array of tables + l.next() + l.emit(tokenDoubleLeftBracket) + return l.lexInsideTableArrayKey + } + // vanilla table key + l.emit(tokenLeftBracket) + return l.lexInsideTableKey +} + +func (l *tomlLexer) lexInsideTableArrayKey() tomlLexStateFn { + for r := l.peek(); r != eof; r = l.peek() { + switch r { + case ']': + if len(l.buffer) > 0 { + l.emit(tokenKeyGroupArray) + } + l.next() + if l.peek() != ']' { + break + } + l.next() + l.emit(tokenDoubleRightBracket) + return l.lexVoid + case '[': + return l.errorf("table array key cannot contain ']'") + default: + l.next() + } + } + return l.errorf("unclosed table array key") +} + +func (l *tomlLexer) lexInsideTableKey() tomlLexStateFn { + for r := l.peek(); r != eof; r = l.peek() { + switch r { + case ']': + if len(l.buffer) > 0 { + l.emit(tokenKeyGroup) + } + l.next() + l.emit(tokenRightBracket) + return l.lexVoid + case '[': + return l.errorf("table key cannot contain ']'") + default: + l.next() + } + } + return l.errorf("unclosed table key") +} + +func (l *tomlLexer) lexRightBracket() tomlLexStateFn { + l.next() + l.emit(tokenRightBracket) + return l.lexRvalue +} + +func (l *tomlLexer) lexNumber() tomlLexStateFn { + r := l.peek() + if r == '+' || r == '-' { + l.next() + } + pointSeen := false + expSeen := false + digitSeen := false + for { + next := l.peek() + if next == '.' { + if pointSeen { + return l.errorf("cannot have two dots in one float") + } + l.next() + if !isDigit(l.peek()) { + return l.errorf("float cannot end with a dot") + } + pointSeen = true + } else if next == 'e' || next == 'E' { + expSeen = true + l.next() + r := l.peek() + if r == '+' || r == '-' { + l.next() + } + } else if isDigit(next) { + digitSeen = true + l.next() + } else if next == '_' { + l.next() + } else { + break + } + if pointSeen && !digitSeen { + return l.errorf("cannot start float with a dot") + } + } + + if !digitSeen { + return l.errorf("no digit in that number") + } + if pointSeen || expSeen { + l.emit(tokenFloat) + } else { + l.emit(tokenInteger) + } + return l.lexRvalue +} + +func (l *tomlLexer) run() { + for state := l.lexVoid; state != nil; { + state = state() + } + close(l.tokens) +} + +func init() { + dateRegexp = regexp.MustCompile(`^\d{1,4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,9})?(Z|[+-]\d{2}:\d{2})`) +} + +// Entry point +func lexToml(input io.Reader) chan token { + bufferedInput := buffruneio.NewReader(input) + l := &tomlLexer{ + input: bufferedInput, + tokens: make(chan token), + line: 1, + col: 1, + endbufferLine: 1, + endbufferCol: 1, + } + go l.run() + return l.tokens +} diff --git a/vendor/github.com/pelletier/go-toml/lexer_test.go b/vendor/github.com/pelletier/go-toml/lexer_test.go new file mode 100644 index 0000000000..6b324ea0e0 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/lexer_test.go @@ -0,0 +1,750 @@ +package toml + +import ( + "strings" + "testing" +) + +func testFlow(t *testing.T, input string, expectedFlow []token) { + ch := lexToml(strings.NewReader(input)) + for _, expected := range expectedFlow { + token := <-ch + if token != expected { + t.Log("While testing: ", input) + t.Log("compared (got)", token, "to (expected)", expected) + t.Log("\tvalue:", token.val, "<->", expected.val) + t.Log("\tvalue as bytes:", []byte(token.val), "<->", []byte(expected.val)) + t.Log("\ttype:", token.typ.String(), "<->", expected.typ.String()) + t.Log("\tline:", token.Line, "<->", expected.Line) + t.Log("\tcolumn:", token.Col, "<->", expected.Col) + t.Log("compared", token, "to", expected) + t.FailNow() + } + } + + tok, ok := <-ch + if ok { + t.Log("channel is not closed!") + t.Log(len(ch)+1, "tokens remaining:") + + t.Log("token ->", tok) + for token := range ch { + t.Log("token ->", token) + } + t.FailNow() + } +} + +func TestValidKeyGroup(t *testing.T) { + testFlow(t, "[hello world]", []token{ + {Position{1, 1}, tokenLeftBracket, "["}, + {Position{1, 2}, tokenKeyGroup, "hello world"}, + {Position{1, 13}, tokenRightBracket, "]"}, + {Position{1, 14}, tokenEOF, ""}, + }) +} + +func TestNestedQuotedUnicodeKeyGroup(t *testing.T) { + testFlow(t, `[ j . "ʞ" . l ]`, []token{ + {Position{1, 1}, tokenLeftBracket, "["}, + {Position{1, 2}, tokenKeyGroup, ` j . "ʞ" . l `}, + {Position{1, 15}, tokenRightBracket, "]"}, + {Position{1, 16}, tokenEOF, ""}, + }) +} + +func TestUnclosedKeyGroup(t *testing.T) { + testFlow(t, "[hello world", []token{ + {Position{1, 1}, tokenLeftBracket, "["}, + {Position{1, 2}, tokenError, "unclosed table key"}, + }) +} + +func TestComment(t *testing.T) { + testFlow(t, "# blahblah", []token{ + {Position{1, 11}, tokenEOF, ""}, + }) +} + +func TestKeyGroupComment(t *testing.T) { + testFlow(t, "[hello world] # blahblah", []token{ + {Position{1, 1}, tokenLeftBracket, "["}, + {Position{1, 2}, tokenKeyGroup, "hello world"}, + {Position{1, 13}, tokenRightBracket, "]"}, + {Position{1, 25}, tokenEOF, ""}, + }) +} + +func TestMultipleKeyGroupsComment(t *testing.T) { + testFlow(t, "[hello world] # blahblah\n[test]", []token{ + {Position{1, 1}, tokenLeftBracket, "["}, + {Position{1, 2}, tokenKeyGroup, "hello world"}, + {Position{1, 13}, tokenRightBracket, "]"}, + {Position{2, 1}, tokenLeftBracket, "["}, + {Position{2, 2}, tokenKeyGroup, "test"}, + {Position{2, 6}, tokenRightBracket, "]"}, + {Position{2, 7}, tokenEOF, ""}, + }) +} + +func TestSimpleWindowsCRLF(t *testing.T) { + testFlow(t, "a=4\r\nb=2", []token{ + {Position{1, 1}, tokenKey, "a"}, + {Position{1, 2}, tokenEqual, "="}, + {Position{1, 3}, tokenInteger, "4"}, + {Position{2, 1}, tokenKey, "b"}, + {Position{2, 2}, tokenEqual, "="}, + {Position{2, 3}, tokenInteger, "2"}, + {Position{2, 4}, tokenEOF, ""}, + }) +} + +func TestBasicKey(t *testing.T) { + testFlow(t, "hello", []token{ + {Position{1, 1}, tokenKey, "hello"}, + {Position{1, 6}, tokenEOF, ""}, + }) +} + +func TestBasicKeyWithUnderscore(t *testing.T) { + testFlow(t, "hello_hello", []token{ + {Position{1, 1}, tokenKey, "hello_hello"}, + {Position{1, 12}, tokenEOF, ""}, + }) +} + +func TestBasicKeyWithDash(t *testing.T) { + testFlow(t, "hello-world", []token{ + {Position{1, 1}, tokenKey, "hello-world"}, + {Position{1, 12}, tokenEOF, ""}, + }) +} + +func TestBasicKeyWithUppercaseMix(t *testing.T) { + testFlow(t, "helloHELLOHello", []token{ + {Position{1, 1}, tokenKey, "helloHELLOHello"}, + {Position{1, 16}, tokenEOF, ""}, + }) +} + +func TestBasicKeyWithInternationalCharacters(t *testing.T) { + testFlow(t, "héllÖ", []token{ + {Position{1, 1}, tokenKey, "héllÖ"}, + {Position{1, 6}, tokenEOF, ""}, + }) +} + +func TestBasicKeyAndEqual(t *testing.T) { + testFlow(t, "hello =", []token{ + {Position{1, 1}, tokenKey, "hello"}, + {Position{1, 7}, tokenEqual, "="}, + {Position{1, 8}, tokenEOF, ""}, + }) +} + +func TestKeyWithSharpAndEqual(t *testing.T) { + testFlow(t, "key#name = 5", []token{ + {Position{1, 1}, tokenError, "keys cannot contain # character"}, + }) +} + +func TestKeyWithSymbolsAndEqual(t *testing.T) { + testFlow(t, "~!@$^&*()_+-`1234567890[]\\|/?><.,;:' = 5", []token{ + {Position{1, 1}, tokenError, "keys cannot contain ~ character"}, + }) +} + +func TestKeyEqualStringEscape(t *testing.T) { + testFlow(t, `foo = "hello\""`, []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 8}, tokenString, "hello\""}, + {Position{1, 16}, tokenEOF, ""}, + }) +} + +func TestKeyEqualStringUnfinished(t *testing.T) { + testFlow(t, `foo = "bar`, []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 8}, tokenError, "unclosed string"}, + }) +} + +func TestKeyEqualString(t *testing.T) { + testFlow(t, `foo = "bar"`, []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 8}, tokenString, "bar"}, + {Position{1, 12}, tokenEOF, ""}, + }) +} + +func TestKeyEqualTrue(t *testing.T) { + testFlow(t, "foo = true", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 7}, tokenTrue, "true"}, + {Position{1, 11}, tokenEOF, ""}, + }) +} + +func TestKeyEqualFalse(t *testing.T) { + testFlow(t, "foo = false", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 7}, tokenFalse, "false"}, + {Position{1, 12}, tokenEOF, ""}, + }) +} + +func TestArrayNestedString(t *testing.T) { + testFlow(t, `a = [ ["hello", "world"] ]`, []token{ + {Position{1, 1}, tokenKey, "a"}, + {Position{1, 3}, tokenEqual, "="}, + {Position{1, 5}, tokenLeftBracket, "["}, + {Position{1, 7}, tokenLeftBracket, "["}, + {Position{1, 9}, tokenString, "hello"}, + {Position{1, 15}, tokenComma, ","}, + {Position{1, 18}, tokenString, "world"}, + {Position{1, 24}, tokenRightBracket, "]"}, + {Position{1, 26}, tokenRightBracket, "]"}, + {Position{1, 27}, tokenEOF, ""}, + }) +} + +func TestArrayNestedInts(t *testing.T) { + testFlow(t, "a = [ [42, 21], [10] ]", []token{ + {Position{1, 1}, tokenKey, "a"}, + {Position{1, 3}, tokenEqual, "="}, + {Position{1, 5}, tokenLeftBracket, "["}, + {Position{1, 7}, tokenLeftBracket, "["}, + {Position{1, 8}, tokenInteger, "42"}, + {Position{1, 10}, tokenComma, ","}, + {Position{1, 12}, tokenInteger, "21"}, + {Position{1, 14}, tokenRightBracket, "]"}, + {Position{1, 15}, tokenComma, ","}, + {Position{1, 17}, tokenLeftBracket, "["}, + {Position{1, 18}, tokenInteger, "10"}, + {Position{1, 20}, tokenRightBracket, "]"}, + {Position{1, 22}, tokenRightBracket, "]"}, + {Position{1, 23}, tokenEOF, ""}, + }) +} + +func TestArrayInts(t *testing.T) { + testFlow(t, "a = [ 42, 21, 10, ]", []token{ + {Position{1, 1}, tokenKey, "a"}, + {Position{1, 3}, tokenEqual, "="}, + {Position{1, 5}, tokenLeftBracket, "["}, + {Position{1, 7}, tokenInteger, "42"}, + {Position{1, 9}, tokenComma, ","}, + {Position{1, 11}, tokenInteger, "21"}, + {Position{1, 13}, tokenComma, ","}, + {Position{1, 15}, tokenInteger, "10"}, + {Position{1, 17}, tokenComma, ","}, + {Position{1, 19}, tokenRightBracket, "]"}, + {Position{1, 20}, tokenEOF, ""}, + }) +} + +func TestMultilineArrayComments(t *testing.T) { + testFlow(t, "a = [1, # wow\n2, # such items\n3, # so array\n]", []token{ + {Position{1, 1}, tokenKey, "a"}, + {Position{1, 3}, tokenEqual, "="}, + {Position{1, 5}, tokenLeftBracket, "["}, + {Position{1, 6}, tokenInteger, "1"}, + {Position{1, 7}, tokenComma, ","}, + {Position{2, 1}, tokenInteger, "2"}, + {Position{2, 2}, tokenComma, ","}, + {Position{3, 1}, tokenInteger, "3"}, + {Position{3, 2}, tokenComma, ","}, + {Position{4, 1}, tokenRightBracket, "]"}, + {Position{4, 2}, tokenEOF, ""}, + }) +} + +func TestNestedArraysComment(t *testing.T) { + toml := ` +someArray = [ +# does not work +["entry1"] +]` + testFlow(t, toml, []token{ + {Position{2, 1}, tokenKey, "someArray"}, + {Position{2, 11}, tokenEqual, "="}, + {Position{2, 13}, tokenLeftBracket, "["}, + {Position{4, 1}, tokenLeftBracket, "["}, + {Position{4, 3}, tokenString, "entry1"}, + {Position{4, 10}, tokenRightBracket, "]"}, + {Position{5, 1}, tokenRightBracket, "]"}, + {Position{5, 2}, tokenEOF, ""}, + }) +} + +func TestKeyEqualArrayBools(t *testing.T) { + testFlow(t, "foo = [true, false, true]", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 7}, tokenLeftBracket, "["}, + {Position{1, 8}, tokenTrue, "true"}, + {Position{1, 12}, tokenComma, ","}, + {Position{1, 14}, tokenFalse, "false"}, + {Position{1, 19}, tokenComma, ","}, + {Position{1, 21}, tokenTrue, "true"}, + {Position{1, 25}, tokenRightBracket, "]"}, + {Position{1, 26}, tokenEOF, ""}, + }) +} + +func TestKeyEqualArrayBoolsWithComments(t *testing.T) { + testFlow(t, "foo = [true, false, true] # YEAH", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 7}, tokenLeftBracket, "["}, + {Position{1, 8}, tokenTrue, "true"}, + {Position{1, 12}, tokenComma, ","}, + {Position{1, 14}, tokenFalse, "false"}, + {Position{1, 19}, tokenComma, ","}, + {Position{1, 21}, tokenTrue, "true"}, + {Position{1, 25}, tokenRightBracket, "]"}, + {Position{1, 33}, tokenEOF, ""}, + }) +} + +func TestDateRegexp(t *testing.T) { + if dateRegexp.FindString("1979-05-27T07:32:00Z") == "" { + t.Error("basic lexing") + } + if dateRegexp.FindString("1979-05-27T00:32:00-07:00") == "" { + t.Error("offset lexing") + } + if dateRegexp.FindString("1979-05-27T00:32:00.999999-07:00") == "" { + t.Error("nano precision lexing") + } +} + +func TestKeyEqualDate(t *testing.T) { + testFlow(t, "foo = 1979-05-27T07:32:00Z", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 7}, tokenDate, "1979-05-27T07:32:00Z"}, + {Position{1, 27}, tokenEOF, ""}, + }) + testFlow(t, "foo = 1979-05-27T00:32:00-07:00", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 7}, tokenDate, "1979-05-27T00:32:00-07:00"}, + {Position{1, 32}, tokenEOF, ""}, + }) + testFlow(t, "foo = 1979-05-27T00:32:00.999999-07:00", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 7}, tokenDate, "1979-05-27T00:32:00.999999-07:00"}, + {Position{1, 39}, tokenEOF, ""}, + }) +} + +func TestFloatEndingWithDot(t *testing.T) { + testFlow(t, "foo = 42.", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 7}, tokenError, "float cannot end with a dot"}, + }) +} + +func TestFloatWithTwoDots(t *testing.T) { + testFlow(t, "foo = 4.2.", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 7}, tokenError, "cannot have two dots in one float"}, + }) +} + +func TestFloatWithExponent1(t *testing.T) { + testFlow(t, "a = 5e+22", []token{ + {Position{1, 1}, tokenKey, "a"}, + {Position{1, 3}, tokenEqual, "="}, + {Position{1, 5}, tokenFloat, "5e+22"}, + {Position{1, 10}, tokenEOF, ""}, + }) +} + +func TestFloatWithExponent2(t *testing.T) { + testFlow(t, "a = 5E+22", []token{ + {Position{1, 1}, tokenKey, "a"}, + {Position{1, 3}, tokenEqual, "="}, + {Position{1, 5}, tokenFloat, "5E+22"}, + {Position{1, 10}, tokenEOF, ""}, + }) +} + +func TestFloatWithExponent3(t *testing.T) { + testFlow(t, "a = -5e+22", []token{ + {Position{1, 1}, tokenKey, "a"}, + {Position{1, 3}, tokenEqual, "="}, + {Position{1, 5}, tokenFloat, "-5e+22"}, + {Position{1, 11}, tokenEOF, ""}, + }) +} + +func TestFloatWithExponent4(t *testing.T) { + testFlow(t, "a = -5e-22", []token{ + {Position{1, 1}, tokenKey, "a"}, + {Position{1, 3}, tokenEqual, "="}, + {Position{1, 5}, tokenFloat, "-5e-22"}, + {Position{1, 11}, tokenEOF, ""}, + }) +} + +func TestFloatWithExponent5(t *testing.T) { + testFlow(t, "a = 6.626e-34", []token{ + {Position{1, 1}, tokenKey, "a"}, + {Position{1, 3}, tokenEqual, "="}, + {Position{1, 5}, tokenFloat, "6.626e-34"}, + {Position{1, 14}, tokenEOF, ""}, + }) +} + +func TestInvalidEsquapeSequence(t *testing.T) { + testFlow(t, `foo = "\x"`, []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 8}, tokenError, "invalid escape sequence: \\x"}, + }) +} + +func TestNestedArrays(t *testing.T) { + testFlow(t, "foo = [[[]]]", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 7}, tokenLeftBracket, "["}, + {Position{1, 8}, tokenLeftBracket, "["}, + {Position{1, 9}, tokenLeftBracket, "["}, + {Position{1, 10}, tokenRightBracket, "]"}, + {Position{1, 11}, tokenRightBracket, "]"}, + {Position{1, 12}, tokenRightBracket, "]"}, + {Position{1, 13}, tokenEOF, ""}, + }) +} + +func TestKeyEqualNumber(t *testing.T) { + testFlow(t, "foo = 42", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 7}, tokenInteger, "42"}, + {Position{1, 9}, tokenEOF, ""}, + }) + + testFlow(t, "foo = +42", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 7}, tokenInteger, "+42"}, + {Position{1, 10}, tokenEOF, ""}, + }) + + testFlow(t, "foo = -42", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 7}, tokenInteger, "-42"}, + {Position{1, 10}, tokenEOF, ""}, + }) + + testFlow(t, "foo = 4.2", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 7}, tokenFloat, "4.2"}, + {Position{1, 10}, tokenEOF, ""}, + }) + + testFlow(t, "foo = +4.2", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 7}, tokenFloat, "+4.2"}, + {Position{1, 11}, tokenEOF, ""}, + }) + + testFlow(t, "foo = -4.2", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 7}, tokenFloat, "-4.2"}, + {Position{1, 11}, tokenEOF, ""}, + }) + + testFlow(t, "foo = 1_000", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 7}, tokenInteger, "1_000"}, + {Position{1, 12}, tokenEOF, ""}, + }) + + testFlow(t, "foo = 5_349_221", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 7}, tokenInteger, "5_349_221"}, + {Position{1, 16}, tokenEOF, ""}, + }) + + testFlow(t, "foo = 1_2_3_4_5", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 7}, tokenInteger, "1_2_3_4_5"}, + {Position{1, 16}, tokenEOF, ""}, + }) + + testFlow(t, "flt8 = 9_224_617.445_991_228_313", []token{ + {Position{1, 1}, tokenKey, "flt8"}, + {Position{1, 6}, tokenEqual, "="}, + {Position{1, 8}, tokenFloat, "9_224_617.445_991_228_313"}, + {Position{1, 33}, tokenEOF, ""}, + }) + + testFlow(t, "foo = +", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 7}, tokenError, "no digit in that number"}, + }) +} + +func TestMultiline(t *testing.T) { + testFlow(t, "foo = 42\nbar=21", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 7}, tokenInteger, "42"}, + {Position{2, 1}, tokenKey, "bar"}, + {Position{2, 4}, tokenEqual, "="}, + {Position{2, 5}, tokenInteger, "21"}, + {Position{2, 7}, tokenEOF, ""}, + }) +} + +func TestKeyEqualStringUnicodeEscape(t *testing.T) { + testFlow(t, `foo = "hello \u2665"`, []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 8}, tokenString, "hello ♥"}, + {Position{1, 21}, tokenEOF, ""}, + }) + testFlow(t, `foo = "hello \U000003B4"`, []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 8}, tokenString, "hello δ"}, + {Position{1, 25}, tokenEOF, ""}, + }) + testFlow(t, `foo = "\uabcd"`, []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 8}, tokenString, "\uabcd"}, + {Position{1, 15}, tokenEOF, ""}, + }) + testFlow(t, `foo = "\uABCD"`, []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 8}, tokenString, "\uABCD"}, + {Position{1, 15}, tokenEOF, ""}, + }) + testFlow(t, `foo = "\U000bcdef"`, []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 8}, tokenString, "\U000bcdef"}, + {Position{1, 19}, tokenEOF, ""}, + }) + testFlow(t, `foo = "\U000BCDEF"`, []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 8}, tokenString, "\U000BCDEF"}, + {Position{1, 19}, tokenEOF, ""}, + }) + testFlow(t, `foo = "\u2"`, []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 8}, tokenError, "unfinished unicode escape"}, + }) + testFlow(t, `foo = "\U2"`, []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 8}, tokenError, "unfinished unicode escape"}, + }) +} + +func TestKeyEqualStringNoEscape(t *testing.T) { + testFlow(t, "foo = \"hello \u0002\"", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 8}, tokenError, "unescaped control character U+0002"}, + }) + testFlow(t, "foo = \"hello \u001F\"", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 8}, tokenError, "unescaped control character U+001F"}, + }) +} + +func TestLiteralString(t *testing.T) { + testFlow(t, `foo = 'C:\Users\nodejs\templates'`, []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 8}, tokenString, `C:\Users\nodejs\templates`}, + {Position{1, 34}, tokenEOF, ""}, + }) + testFlow(t, `foo = '\\ServerX\admin$\system32\'`, []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 8}, tokenString, `\\ServerX\admin$\system32\`}, + {Position{1, 35}, tokenEOF, ""}, + }) + testFlow(t, `foo = 'Tom "Dubs" Preston-Werner'`, []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 8}, tokenString, `Tom "Dubs" Preston-Werner`}, + {Position{1, 34}, tokenEOF, ""}, + }) + testFlow(t, `foo = '<\i\c*\s*>'`, []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 8}, tokenString, `<\i\c*\s*>`}, + {Position{1, 19}, tokenEOF, ""}, + }) + testFlow(t, `foo = 'C:\Users\nodejs\unfinis`, []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 8}, tokenError, "unclosed string"}, + }) +} + +func TestMultilineLiteralString(t *testing.T) { + testFlow(t, `foo = '''hello 'literal' world'''`, []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 10}, tokenString, `hello 'literal' world`}, + {Position{1, 34}, tokenEOF, ""}, + }) + + testFlow(t, "foo = '''\nhello\n'literal'\nworld'''", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{2, 1}, tokenString, "hello\n'literal'\nworld"}, + {Position{4, 9}, tokenEOF, ""}, + }) + testFlow(t, "foo = '''\r\nhello\r\n'literal'\r\nworld'''", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{2, 1}, tokenString, "hello\r\n'literal'\r\nworld"}, + {Position{4, 9}, tokenEOF, ""}, + }) +} + +func TestMultilineString(t *testing.T) { + testFlow(t, `foo = """hello "literal" world"""`, []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 10}, tokenString, `hello "literal" world`}, + {Position{1, 34}, tokenEOF, ""}, + }) + + testFlow(t, "foo = \"\"\"\r\nhello\\\r\n\"literal\"\\\nworld\"\"\"", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{2, 1}, tokenString, "hello\"literal\"world"}, + {Position{4, 9}, tokenEOF, ""}, + }) + + testFlow(t, "foo = \"\"\"\\\n \\\n \\\n hello\\\nmultiline\\\nworld\"\"\"", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 10}, tokenString, "hellomultilineworld"}, + {Position{6, 9}, tokenEOF, ""}, + }) + + testFlow(t, "key2 = \"\"\"\nThe quick brown \\\n\n\n fox jumps over \\\n the lazy dog.\"\"\"", []token{ + {Position{1, 1}, tokenKey, "key2"}, + {Position{1, 6}, tokenEqual, "="}, + {Position{2, 1}, tokenString, "The quick brown fox jumps over the lazy dog."}, + {Position{6, 21}, tokenEOF, ""}, + }) + + testFlow(t, "key2 = \"\"\"\\\n The quick brown \\\n fox jumps over \\\n the lazy dog.\\\n \"\"\"", []token{ + {Position{1, 1}, tokenKey, "key2"}, + {Position{1, 6}, tokenEqual, "="}, + {Position{1, 11}, tokenString, "The quick brown fox jumps over the lazy dog."}, + {Position{5, 11}, tokenEOF, ""}, + }) + + testFlow(t, `key2 = "Roses are red\nViolets are blue"`, []token{ + {Position{1, 1}, tokenKey, "key2"}, + {Position{1, 6}, tokenEqual, "="}, + {Position{1, 9}, tokenString, "Roses are red\nViolets are blue"}, + {Position{1, 41}, tokenEOF, ""}, + }) + + testFlow(t, "key2 = \"\"\"\nRoses are red\nViolets are blue\"\"\"", []token{ + {Position{1, 1}, tokenKey, "key2"}, + {Position{1, 6}, tokenEqual, "="}, + {Position{2, 1}, tokenString, "Roses are red\nViolets are blue"}, + {Position{3, 20}, tokenEOF, ""}, + }) +} + +func TestUnicodeString(t *testing.T) { + testFlow(t, `foo = "hello ♥ world"`, []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 8}, tokenString, "hello ♥ world"}, + {Position{1, 22}, tokenEOF, ""}, + }) +} +func TestEscapeInString(t *testing.T) { + testFlow(t, `foo = "\b\f\/"`, []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenEqual, "="}, + {Position{1, 8}, tokenString, "\b\f/"}, + {Position{1, 15}, tokenEOF, ""}, + }) +} + +func TestKeyGroupArray(t *testing.T) { + testFlow(t, "[[foo]]", []token{ + {Position{1, 1}, tokenDoubleLeftBracket, "[["}, + {Position{1, 3}, tokenKeyGroupArray, "foo"}, + {Position{1, 6}, tokenDoubleRightBracket, "]]"}, + {Position{1, 8}, tokenEOF, ""}, + }) +} + +func TestQuotedKey(t *testing.T) { + testFlow(t, "\"a b\" = 42", []token{ + {Position{1, 1}, tokenKey, "\"a b\""}, + {Position{1, 7}, tokenEqual, "="}, + {Position{1, 9}, tokenInteger, "42"}, + {Position{1, 11}, tokenEOF, ""}, + }) +} + +func TestKeyNewline(t *testing.T) { + testFlow(t, "a\n= 4", []token{ + {Position{1, 1}, tokenError, "keys cannot contain new lines"}, + }) +} + +func TestInvalidFloat(t *testing.T) { + testFlow(t, "a=7e1_", []token{ + {Position{1, 1}, tokenKey, "a"}, + {Position{1, 2}, tokenEqual, "="}, + {Position{1, 3}, tokenFloat, "7e1_"}, + {Position{1, 7}, tokenEOF, ""}, + }) +} + +func TestLexUnknownRvalue(t *testing.T) { + testFlow(t, `a = !b`, []token{ + {Position{1, 1}, tokenKey, "a"}, + {Position{1, 3}, tokenEqual, "="}, + {Position{1, 5}, tokenError, "no value can start with !"}, + }) + + testFlow(t, `a = \b`, []token{ + {Position{1, 1}, tokenKey, "a"}, + {Position{1, 3}, tokenEqual, "="}, + {Position{1, 5}, tokenError, `no value can start with \`}, + }) +} diff --git a/vendor/github.com/pelletier/go-toml/match.go b/vendor/github.com/pelletier/go-toml/match.go new file mode 100644 index 0000000000..48b0f2a153 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/match.go @@ -0,0 +1,234 @@ +package toml + +import ( + "fmt" +) + +// support function to set positions for tomlValues +// NOTE: this is done to allow ctx.lastPosition to indicate the start of any +// values returned by the query engines +func tomlValueCheck(node interface{}, ctx *queryContext) interface{} { + switch castNode := node.(type) { + case *tomlValue: + ctx.lastPosition = castNode.position + return castNode.value + case []*TomlTree: + if len(castNode) > 0 { + ctx.lastPosition = castNode[0].position + } + return node + default: + return node + } +} + +// base match +type matchBase struct { + next pathFn +} + +func (f *matchBase) setNext(next pathFn) { + f.next = next +} + +// terminating functor - gathers results +type terminatingFn struct { + // empty +} + +func newTerminatingFn() *terminatingFn { + return &terminatingFn{} +} + +func (f *terminatingFn) setNext(next pathFn) { + // do nothing +} + +func (f *terminatingFn) call(node interface{}, ctx *queryContext) { + switch castNode := node.(type) { + case *TomlTree: + ctx.result.appendResult(node, castNode.position) + case *tomlValue: + ctx.result.appendResult(node, castNode.position) + default: + // use last position for scalars + ctx.result.appendResult(node, ctx.lastPosition) + } +} + +// match single key +type matchKeyFn struct { + matchBase + Name string +} + +func newMatchKeyFn(name string) *matchKeyFn { + return &matchKeyFn{Name: name} +} + +func (f *matchKeyFn) call(node interface{}, ctx *queryContext) { + if array, ok := node.([]*TomlTree); ok { + for _, tree := range array { + item := tree.values[f.Name] + if item != nil { + f.next.call(item, ctx) + } + } + } else if tree, ok := node.(*TomlTree); ok { + item := tree.values[f.Name] + if item != nil { + f.next.call(item, ctx) + } + } +} + +// match single index +type matchIndexFn struct { + matchBase + Idx int +} + +func newMatchIndexFn(idx int) *matchIndexFn { + return &matchIndexFn{Idx: idx} +} + +func (f *matchIndexFn) call(node interface{}, ctx *queryContext) { + if arr, ok := tomlValueCheck(node, ctx).([]interface{}); ok { + if f.Idx < len(arr) && f.Idx >= 0 { + f.next.call(arr[f.Idx], ctx) + } + } +} + +// filter by slicing +type matchSliceFn struct { + matchBase + Start, End, Step int +} + +func newMatchSliceFn(start, end, step int) *matchSliceFn { + return &matchSliceFn{Start: start, End: end, Step: step} +} + +func (f *matchSliceFn) call(node interface{}, ctx *queryContext) { + if arr, ok := tomlValueCheck(node, ctx).([]interface{}); ok { + // adjust indexes for negative values, reverse ordering + realStart, realEnd := f.Start, f.End + if realStart < 0 { + realStart = len(arr) + realStart + } + if realEnd < 0 { + realEnd = len(arr) + realEnd + } + if realEnd < realStart { + realEnd, realStart = realStart, realEnd // swap + } + // loop and gather + for idx := realStart; idx < realEnd; idx += f.Step { + f.next.call(arr[idx], ctx) + } + } +} + +// match anything +type matchAnyFn struct { + matchBase +} + +func newMatchAnyFn() *matchAnyFn { + return &matchAnyFn{} +} + +func (f *matchAnyFn) call(node interface{}, ctx *queryContext) { + if tree, ok := node.(*TomlTree); ok { + for _, v := range tree.values { + f.next.call(v, ctx) + } + } +} + +// filter through union +type matchUnionFn struct { + Union []pathFn +} + +func (f *matchUnionFn) setNext(next pathFn) { + for _, fn := range f.Union { + fn.setNext(next) + } +} + +func (f *matchUnionFn) call(node interface{}, ctx *queryContext) { + for _, fn := range f.Union { + fn.call(node, ctx) + } +} + +// match every single last node in the tree +type matchRecursiveFn struct { + matchBase +} + +func newMatchRecursiveFn() *matchRecursiveFn { + return &matchRecursiveFn{} +} + +func (f *matchRecursiveFn) call(node interface{}, ctx *queryContext) { + if tree, ok := node.(*TomlTree); ok { + var visit func(tree *TomlTree) + visit = func(tree *TomlTree) { + for _, v := range tree.values { + f.next.call(v, ctx) + switch node := v.(type) { + case *TomlTree: + visit(node) + case []*TomlTree: + for _, subtree := range node { + visit(subtree) + } + } + } + } + f.next.call(tree, ctx) + visit(tree) + } +} + +// match based on an externally provided functional filter +type matchFilterFn struct { + matchBase + Pos Position + Name string +} + +func newMatchFilterFn(name string, pos Position) *matchFilterFn { + return &matchFilterFn{Name: name, Pos: pos} +} + +func (f *matchFilterFn) call(node interface{}, ctx *queryContext) { + fn, ok := (*ctx.filters)[f.Name] + if !ok { + panic(fmt.Sprintf("%s: query context does not have filter '%s'", + f.Pos.String(), f.Name)) + } + switch castNode := tomlValueCheck(node, ctx).(type) { + case *TomlTree: + for _, v := range castNode.values { + if tv, ok := v.(*tomlValue); ok { + if fn(tv.value) { + f.next.call(v, ctx) + } + } else { + if fn(v) { + f.next.call(v, ctx) + } + } + } + case []interface{}: + for _, v := range castNode { + if fn(v) { + f.next.call(v, ctx) + } + } + } +} diff --git a/vendor/github.com/pelletier/go-toml/match_test.go b/vendor/github.com/pelletier/go-toml/match_test.go new file mode 100644 index 0000000000..b63654ad2f --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/match_test.go @@ -0,0 +1,201 @@ +package toml + +import ( + "fmt" + "testing" +) + +// dump path tree to a string +func pathString(root pathFn) string { + result := fmt.Sprintf("%T:", root) + switch fn := root.(type) { + case *terminatingFn: + result += "{}" + case *matchKeyFn: + result += fmt.Sprintf("{%s}", fn.Name) + result += pathString(fn.next) + case *matchIndexFn: + result += fmt.Sprintf("{%d}", fn.Idx) + result += pathString(fn.next) + case *matchSliceFn: + result += fmt.Sprintf("{%d:%d:%d}", + fn.Start, fn.End, fn.Step) + result += pathString(fn.next) + case *matchAnyFn: + result += "{}" + result += pathString(fn.next) + case *matchUnionFn: + result += "{[" + for _, v := range fn.Union { + result += pathString(v) + ", " + } + result += "]}" + case *matchRecursiveFn: + result += "{}" + result += pathString(fn.next) + case *matchFilterFn: + result += fmt.Sprintf("{%s}", fn.Name) + result += pathString(fn.next) + } + return result +} + +func assertPathMatch(t *testing.T, path, ref *Query) bool { + pathStr := pathString(path.root) + refStr := pathString(ref.root) + if pathStr != refStr { + t.Errorf("paths do not match") + t.Log("test:", pathStr) + t.Log("ref: ", refStr) + return false + } + return true +} + +func assertPath(t *testing.T, query string, ref *Query) { + path, _ := parseQuery(lexQuery(query)) + assertPathMatch(t, path, ref) +} + +func buildPath(parts ...pathFn) *Query { + query := newQuery() + for _, v := range parts { + query.appendPath(v) + } + return query +} + +func TestPathRoot(t *testing.T) { + assertPath(t, + "$", + buildPath( + // empty + )) +} + +func TestPathKey(t *testing.T) { + assertPath(t, + "$.foo", + buildPath( + newMatchKeyFn("foo"), + )) +} + +func TestPathBracketKey(t *testing.T) { + assertPath(t, + "$[foo]", + buildPath( + newMatchKeyFn("foo"), + )) +} + +func TestPathBracketStringKey(t *testing.T) { + assertPath(t, + "$['foo']", + buildPath( + newMatchKeyFn("foo"), + )) +} + +func TestPathIndex(t *testing.T) { + assertPath(t, + "$[123]", + buildPath( + newMatchIndexFn(123), + )) +} + +func TestPathSliceStart(t *testing.T) { + assertPath(t, + "$[123:]", + buildPath( + newMatchSliceFn(123, maxInt, 1), + )) +} + +func TestPathSliceStartEnd(t *testing.T) { + assertPath(t, + "$[123:456]", + buildPath( + newMatchSliceFn(123, 456, 1), + )) +} + +func TestPathSliceStartEndColon(t *testing.T) { + assertPath(t, + "$[123:456:]", + buildPath( + newMatchSliceFn(123, 456, 1), + )) +} + +func TestPathSliceStartStep(t *testing.T) { + assertPath(t, + "$[123::7]", + buildPath( + newMatchSliceFn(123, maxInt, 7), + )) +} + +func TestPathSliceEndStep(t *testing.T) { + assertPath(t, + "$[:456:7]", + buildPath( + newMatchSliceFn(0, 456, 7), + )) +} + +func TestPathSliceStep(t *testing.T) { + assertPath(t, + "$[::7]", + buildPath( + newMatchSliceFn(0, maxInt, 7), + )) +} + +func TestPathSliceAll(t *testing.T) { + assertPath(t, + "$[123:456:7]", + buildPath( + newMatchSliceFn(123, 456, 7), + )) +} + +func TestPathAny(t *testing.T) { + assertPath(t, + "$.*", + buildPath( + newMatchAnyFn(), + )) +} + +func TestPathUnion(t *testing.T) { + assertPath(t, + "$[foo, bar, baz]", + buildPath( + &matchUnionFn{[]pathFn{ + newMatchKeyFn("foo"), + newMatchKeyFn("bar"), + newMatchKeyFn("baz"), + }}, + )) +} + +func TestPathRecurse(t *testing.T) { + assertPath(t, + "$..*", + buildPath( + newMatchRecursiveFn(), + )) +} + +func TestPathFilterExpr(t *testing.T) { + assertPath(t, + "$[?('foo'),?(bar)]", + buildPath( + &matchUnionFn{[]pathFn{ + newMatchFilterFn("foo", Position{}), + newMatchFilterFn("bar", Position{}), + }}, + )) +} diff --git a/vendor/github.com/pelletier/go-toml/parser.go b/vendor/github.com/pelletier/go-toml/parser.go new file mode 100644 index 0000000000..20e90a3ed7 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/parser.go @@ -0,0 +1,393 @@ +// TOML Parser. + +package toml + +import ( + "errors" + "fmt" + "reflect" + "regexp" + "strconv" + "strings" + "time" +) + +type tomlParser struct { + flow chan token + tree *TomlTree + tokensBuffer []token + currentTable []string + seenTableKeys []string +} + +type tomlParserStateFn func() tomlParserStateFn + +// Formats and panics an error message based on a token +func (p *tomlParser) raiseError(tok *token, msg string, args ...interface{}) { + panic(tok.Position.String() + ": " + fmt.Sprintf(msg, args...)) +} + +func (p *tomlParser) run() { + for state := p.parseStart; state != nil; { + state = state() + } +} + +func (p *tomlParser) peek() *token { + if len(p.tokensBuffer) != 0 { + return &(p.tokensBuffer[0]) + } + + tok, ok := <-p.flow + if !ok { + return nil + } + p.tokensBuffer = append(p.tokensBuffer, tok) + return &tok +} + +func (p *tomlParser) assume(typ tokenType) { + tok := p.getToken() + if tok == nil { + p.raiseError(tok, "was expecting token %s, but token stream is empty", tok) + } + if tok.typ != typ { + p.raiseError(tok, "was expecting token %s, but got %s instead", typ, tok) + } +} + +func (p *tomlParser) getToken() *token { + if len(p.tokensBuffer) != 0 { + tok := p.tokensBuffer[0] + p.tokensBuffer = p.tokensBuffer[1:] + return &tok + } + tok, ok := <-p.flow + if !ok { + return nil + } + return &tok +} + +func (p *tomlParser) parseStart() tomlParserStateFn { + tok := p.peek() + + // end of stream, parsing is finished + if tok == nil { + return nil + } + + switch tok.typ { + case tokenDoubleLeftBracket: + return p.parseGroupArray + case tokenLeftBracket: + return p.parseGroup + case tokenKey: + return p.parseAssign + case tokenEOF: + return nil + default: + p.raiseError(tok, "unexpected token") + } + return nil +} + +func (p *tomlParser) parseGroupArray() tomlParserStateFn { + startToken := p.getToken() // discard the [[ + key := p.getToken() + if key.typ != tokenKeyGroupArray { + p.raiseError(key, "unexpected token %s, was expecting a table array key", key) + } + + // get or create table array element at the indicated part in the path + keys, err := parseKey(key.val) + if err != nil { + p.raiseError(key, "invalid table array key: %s", err) + } + p.tree.createSubTree(keys[:len(keys)-1], startToken.Position) // create parent entries + destTree := p.tree.GetPath(keys) + var array []*TomlTree + if destTree == nil { + array = make([]*TomlTree, 0) + } else if target, ok := destTree.([]*TomlTree); ok && target != nil { + array = destTree.([]*TomlTree) + } else { + p.raiseError(key, "key %s is already assigned and not of type table array", key) + } + p.currentTable = keys + + // add a new tree to the end of the table array + newTree := newTomlTree() + newTree.position = startToken.Position + array = append(array, newTree) + p.tree.SetPath(p.currentTable, array) + + // remove all keys that were children of this table array + prefix := key.val + "." + found := false + for ii := 0; ii < len(p.seenTableKeys); { + tableKey := p.seenTableKeys[ii] + if strings.HasPrefix(tableKey, prefix) { + p.seenTableKeys = append(p.seenTableKeys[:ii], p.seenTableKeys[ii+1:]...) + } else { + found = (tableKey == key.val) + ii++ + } + } + + // keep this key name from use by other kinds of assignments + if !found { + p.seenTableKeys = append(p.seenTableKeys, key.val) + } + + // move to next parser state + p.assume(tokenDoubleRightBracket) + return p.parseStart +} + +func (p *tomlParser) parseGroup() tomlParserStateFn { + startToken := p.getToken() // discard the [ + key := p.getToken() + if key.typ != tokenKeyGroup { + p.raiseError(key, "unexpected token %s, was expecting a table key", key) + } + for _, item := range p.seenTableKeys { + if item == key.val { + p.raiseError(key, "duplicated tables") + } + } + + p.seenTableKeys = append(p.seenTableKeys, key.val) + keys, err := parseKey(key.val) + if err != nil { + p.raiseError(key, "invalid table array key: %s", err) + } + if err := p.tree.createSubTree(keys, startToken.Position); err != nil { + p.raiseError(key, "%s", err) + } + p.assume(tokenRightBracket) + p.currentTable = keys + return p.parseStart +} + +func (p *tomlParser) parseAssign() tomlParserStateFn { + key := p.getToken() + p.assume(tokenEqual) + + value := p.parseRvalue() + var tableKey []string + if len(p.currentTable) > 0 { + tableKey = p.currentTable + } else { + tableKey = []string{} + } + + // find the table to assign, looking out for arrays of tables + var targetNode *TomlTree + switch node := p.tree.GetPath(tableKey).(type) { + case []*TomlTree: + targetNode = node[len(node)-1] + case *TomlTree: + targetNode = node + default: + p.raiseError(key, "Unknown table type for path: %s", + strings.Join(tableKey, ".")) + } + + // assign value to the found table + keyVals, err := parseKey(key.val) + if err != nil { + p.raiseError(key, "%s", err) + } + if len(keyVals) != 1 { + p.raiseError(key, "Invalid key") + } + keyVal := keyVals[0] + localKey := []string{keyVal} + finalKey := append(tableKey, keyVal) + if targetNode.GetPath(localKey) != nil { + p.raiseError(key, "The following key was defined twice: %s", + strings.Join(finalKey, ".")) + } + var toInsert interface{} + + switch value.(type) { + case *TomlTree, []*TomlTree: + toInsert = value + default: + toInsert = &tomlValue{value, key.Position} + } + targetNode.values[keyVal] = toInsert + return p.parseStart +} + +var numberUnderscoreInvalidRegexp *regexp.Regexp + +func cleanupNumberToken(value string) (string, error) { + if numberUnderscoreInvalidRegexp.MatchString(value) { + return "", errors.New("invalid use of _ in number") + } + cleanedVal := strings.Replace(value, "_", "", -1) + return cleanedVal, nil +} + +func (p *tomlParser) parseRvalue() interface{} { + tok := p.getToken() + if tok == nil || tok.typ == tokenEOF { + p.raiseError(tok, "expecting a value") + } + + switch tok.typ { + case tokenString: + return tok.val + case tokenTrue: + return true + case tokenFalse: + return false + case tokenInteger: + cleanedVal, err := cleanupNumberToken(tok.val) + if err != nil { + p.raiseError(tok, "%s", err) + } + val, err := strconv.ParseInt(cleanedVal, 10, 64) + if err != nil { + p.raiseError(tok, "%s", err) + } + return val + case tokenFloat: + cleanedVal, err := cleanupNumberToken(tok.val) + if err != nil { + p.raiseError(tok, "%s", err) + } + val, err := strconv.ParseFloat(cleanedVal, 64) + if err != nil { + p.raiseError(tok, "%s", err) + } + return val + case tokenDate: + val, err := time.ParseInLocation(time.RFC3339Nano, tok.val, time.UTC) + if err != nil { + p.raiseError(tok, "%s", err) + } + return val + case tokenLeftBracket: + return p.parseArray() + case tokenLeftCurlyBrace: + return p.parseInlineTable() + case tokenEqual: + p.raiseError(tok, "cannot have multiple equals for the same key") + case tokenError: + p.raiseError(tok, "%s", tok) + } + + p.raiseError(tok, "never reached") + + return nil +} + +func tokenIsComma(t *token) bool { + return t != nil && t.typ == tokenComma +} + +func (p *tomlParser) parseInlineTable() *TomlTree { + tree := newTomlTree() + var previous *token +Loop: + for { + follow := p.peek() + if follow == nil || follow.typ == tokenEOF { + p.raiseError(follow, "unterminated inline table") + } + switch follow.typ { + case tokenRightCurlyBrace: + p.getToken() + break Loop + case tokenKey: + if !tokenIsComma(previous) && previous != nil { + p.raiseError(follow, "comma expected between fields in inline table") + } + key := p.getToken() + p.assume(tokenEqual) + value := p.parseRvalue() + tree.Set(key.val, value) + case tokenComma: + if previous == nil { + p.raiseError(follow, "inline table cannot start with a comma") + } + if tokenIsComma(previous) { + p.raiseError(follow, "need field between two commas in inline table") + } + p.getToken() + default: + p.raiseError(follow, "unexpected token type in inline table: %s", follow.typ.String()) + } + previous = follow + } + if tokenIsComma(previous) { + p.raiseError(previous, "trailing comma at the end of inline table") + } + return tree +} + +func (p *tomlParser) parseArray() interface{} { + var array []interface{} + arrayType := reflect.TypeOf(nil) + for { + follow := p.peek() + if follow == nil || follow.typ == tokenEOF { + p.raiseError(follow, "unterminated array") + } + if follow.typ == tokenRightBracket { + p.getToken() + break + } + val := p.parseRvalue() + if arrayType == nil { + arrayType = reflect.TypeOf(val) + } + if reflect.TypeOf(val) != arrayType { + p.raiseError(follow, "mixed types in array") + } + array = append(array, val) + follow = p.peek() + if follow == nil || follow.typ == tokenEOF { + p.raiseError(follow, "unterminated array") + } + if follow.typ != tokenRightBracket && follow.typ != tokenComma { + p.raiseError(follow, "missing comma") + } + if follow.typ == tokenComma { + p.getToken() + } + } + // An array of TomlTrees is actually an array of inline + // tables, which is a shorthand for a table array. If the + // array was not converted from []interface{} to []*TomlTree, + // the two notations would not be equivalent. + if arrayType == reflect.TypeOf(newTomlTree()) { + tomlArray := make([]*TomlTree, len(array)) + for i, v := range array { + tomlArray[i] = v.(*TomlTree) + } + return tomlArray + } + return array +} + +func parseToml(flow chan token) *TomlTree { + result := newTomlTree() + result.position = Position{1, 1} + parser := &tomlParser{ + flow: flow, + tree: result, + tokensBuffer: make([]token, 0), + currentTable: make([]string, 0), + seenTableKeys: make([]string, 0), + } + parser.run() + return result +} + +func init() { + numberUnderscoreInvalidRegexp = regexp.MustCompile(`([^\d]_|_[^\d]|_$|^_)`) +} diff --git a/vendor/github.com/pelletier/go-toml/parser_test.go b/vendor/github.com/pelletier/go-toml/parser_test.go new file mode 100644 index 0000000000..61a3a7cc13 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/parser_test.go @@ -0,0 +1,784 @@ +package toml + +import ( + "fmt" + "reflect" + "testing" + "time" + + "github.com/davecgh/go-spew/spew" +) + +func assertSubTree(t *testing.T, path []string, tree *TomlTree, err error, ref map[string]interface{}) { + if err != nil { + t.Error("Non-nil error:", err.Error()) + return + } + for k, v := range ref { + nextPath := append(path, k) + t.Log("asserting path", nextPath) + // NOTE: directly access key instead of resolve by path + // NOTE: see TestSpecialKV + switch node := tree.GetPath([]string{k}).(type) { + case []*TomlTree: + t.Log("\tcomparing key", nextPath, "by array iteration") + for idx, item := range node { + assertSubTree(t, nextPath, item, err, v.([]map[string]interface{})[idx]) + } + case *TomlTree: + t.Log("\tcomparing key", nextPath, "by subtree assestion") + assertSubTree(t, nextPath, node, err, v.(map[string]interface{})) + default: + t.Log("\tcomparing key", nextPath, "by string representation because it's of type", reflect.TypeOf(node)) + if fmt.Sprintf("%v", node) != fmt.Sprintf("%v", v) { + t.Errorf("was expecting %v at %v but got %v", v, k, node) + } + } + } +} + +func assertTree(t *testing.T, tree *TomlTree, err error, ref map[string]interface{}) { + t.Log("Asserting tree:\n", spew.Sdump(tree)) + assertSubTree(t, []string{}, tree, err, ref) + t.Log("Finished tree assertion.") +} + +func TestCreateSubTree(t *testing.T) { + tree := newTomlTree() + tree.createSubTree([]string{"a", "b", "c"}, Position{}) + tree.Set("a.b.c", 42) + if tree.Get("a.b.c") != 42 { + t.Fail() + } +} + +func TestSimpleKV(t *testing.T) { + tree, err := Load("a = 42") + assertTree(t, tree, err, map[string]interface{}{ + "a": int64(42), + }) + + tree, _ = Load("a = 42\nb = 21") + assertTree(t, tree, err, map[string]interface{}{ + "a": int64(42), + "b": int64(21), + }) +} + +func TestNumberInKey(t *testing.T) { + tree, err := Load("hello2 = 42") + assertTree(t, tree, err, map[string]interface{}{ + "hello2": int64(42), + }) +} + +func TestSimpleNumbers(t *testing.T) { + tree, err := Load("a = +42\nb = -21\nc = +4.2\nd = -2.1") + assertTree(t, tree, err, map[string]interface{}{ + "a": int64(42), + "b": int64(-21), + "c": float64(4.2), + "d": float64(-2.1), + }) +} + +func TestNumbersWithUnderscores(t *testing.T) { + tree, err := Load("a = 1_000") + assertTree(t, tree, err, map[string]interface{}{ + "a": int64(1000), + }) + + tree, err = Load("a = 5_349_221") + assertTree(t, tree, err, map[string]interface{}{ + "a": int64(5349221), + }) + + tree, err = Load("a = 1_2_3_4_5") + assertTree(t, tree, err, map[string]interface{}{ + "a": int64(12345), + }) + + tree, err = Load("flt8 = 9_224_617.445_991_228_313") + assertTree(t, tree, err, map[string]interface{}{ + "flt8": float64(9224617.445991228313), + }) + + tree, err = Load("flt9 = 1e1_00") + assertTree(t, tree, err, map[string]interface{}{ + "flt9": float64(1e100), + }) +} + +func TestFloatsWithExponents(t *testing.T) { + tree, err := Load("a = 5e+22\nb = 5E+22\nc = -5e+22\nd = -5e-22\ne = 6.626e-34") + assertTree(t, tree, err, map[string]interface{}{ + "a": float64(5e+22), + "b": float64(5E+22), + "c": float64(-5e+22), + "d": float64(-5e-22), + "e": float64(6.626e-34), + }) +} + +func TestSimpleDate(t *testing.T) { + tree, err := Load("a = 1979-05-27T07:32:00Z") + assertTree(t, tree, err, map[string]interface{}{ + "a": time.Date(1979, time.May, 27, 7, 32, 0, 0, time.UTC), + }) +} + +func TestDateOffset(t *testing.T) { + tree, err := Load("a = 1979-05-27T00:32:00-07:00") + assertTree(t, tree, err, map[string]interface{}{ + "a": time.Date(1979, time.May, 27, 0, 32, 0, 0, time.FixedZone("", -7*60*60)), + }) +} + +func TestDateNano(t *testing.T) { + tree, err := Load("a = 1979-05-27T00:32:00.999999999-07:00") + assertTree(t, tree, err, map[string]interface{}{ + "a": time.Date(1979, time.May, 27, 0, 32, 0, 999999999, time.FixedZone("", -7*60*60)), + }) +} + +func TestSimpleString(t *testing.T) { + tree, err := Load("a = \"hello world\"") + assertTree(t, tree, err, map[string]interface{}{ + "a": "hello world", + }) +} + +func TestSpaceKey(t *testing.T) { + tree, err := Load("\"a b\" = \"hello world\"") + assertTree(t, tree, err, map[string]interface{}{ + "a b": "hello world", + }) +} + +func TestStringEscapables(t *testing.T) { + tree, err := Load("a = \"a \\n b\"") + assertTree(t, tree, err, map[string]interface{}{ + "a": "a \n b", + }) + + tree, err = Load("a = \"a \\t b\"") + assertTree(t, tree, err, map[string]interface{}{ + "a": "a \t b", + }) + + tree, err = Load("a = \"a \\r b\"") + assertTree(t, tree, err, map[string]interface{}{ + "a": "a \r b", + }) + + tree, err = Load("a = \"a \\\\ b\"") + assertTree(t, tree, err, map[string]interface{}{ + "a": "a \\ b", + }) +} + +func TestEmptyQuotedString(t *testing.T) { + tree, err := Load(`[""] +"" = 1`) + assertTree(t, tree, err, map[string]interface{}{ + "": map[string]interface{}{ + "": int64(1), + }, + }) +} + +func TestBools(t *testing.T) { + tree, err := Load("a = true\nb = false") + assertTree(t, tree, err, map[string]interface{}{ + "a": true, + "b": false, + }) +} + +func TestNestedKeys(t *testing.T) { + tree, err := Load("[a.b.c]\nd = 42") + assertTree(t, tree, err, map[string]interface{}{ + "a": map[string]interface{}{ + "b": map[string]interface{}{ + "c": map[string]interface{}{ + "d": int64(42), + }, + }, + }, + }) +} + +func TestNestedQuotedUnicodeKeys(t *testing.T) { + tree, err := Load("[ j . \"ʞ\" . l ]\nd = 42") + assertTree(t, tree, err, map[string]interface{}{ + "j": map[string]interface{}{ + "ʞ": map[string]interface{}{ + "l": map[string]interface{}{ + "d": int64(42), + }, + }, + }, + }) + + tree, err = Load("[ g . h . i ]\nd = 42") + assertTree(t, tree, err, map[string]interface{}{ + "g": map[string]interface{}{ + "h": map[string]interface{}{ + "i": map[string]interface{}{ + "d": int64(42), + }, + }, + }, + }) + + tree, err = Load("[ d.e.f ]\nk = 42") + assertTree(t, tree, err, map[string]interface{}{ + "d": map[string]interface{}{ + "e": map[string]interface{}{ + "f": map[string]interface{}{ + "k": int64(42), + }, + }, + }, + }) +} + +func TestArrayOne(t *testing.T) { + tree, err := Load("a = [1]") + assertTree(t, tree, err, map[string]interface{}{ + "a": []int64{int64(1)}, + }) +} + +func TestArrayZero(t *testing.T) { + tree, err := Load("a = []") + assertTree(t, tree, err, map[string]interface{}{ + "a": []interface{}{}, + }) +} + +func TestArraySimple(t *testing.T) { + tree, err := Load("a = [42, 21, 10]") + assertTree(t, tree, err, map[string]interface{}{ + "a": []int64{int64(42), int64(21), int64(10)}, + }) + + tree, _ = Load("a = [42, 21, 10,]") + assertTree(t, tree, err, map[string]interface{}{ + "a": []int64{int64(42), int64(21), int64(10)}, + }) +} + +func TestArrayMultiline(t *testing.T) { + tree, err := Load("a = [42,\n21, 10,]") + assertTree(t, tree, err, map[string]interface{}{ + "a": []int64{int64(42), int64(21), int64(10)}, + }) +} + +func TestArrayNested(t *testing.T) { + tree, err := Load("a = [[42, 21], [10]]") + assertTree(t, tree, err, map[string]interface{}{ + "a": [][]int64{{int64(42), int64(21)}, {int64(10)}}, + }) +} + +func TestNestedArrayComment(t *testing.T) { + tree, err := Load(` +someArray = [ +# does not work +["entry1"] +]`) + assertTree(t, tree, err, map[string]interface{}{ + "someArray": [][]string{{"entry1"}}, + }) +} + +func TestNestedEmptyArrays(t *testing.T) { + tree, err := Load("a = [[[]]]") + assertTree(t, tree, err, map[string]interface{}{ + "a": [][][]interface{}{{{}}}, + }) +} + +func TestArrayMixedTypes(t *testing.T) { + _, err := Load("a = [42, 16.0]") + if err.Error() != "(1, 10): mixed types in array" { + t.Error("Bad error message:", err.Error()) + } + + _, err = Load("a = [42, \"hello\"]") + if err.Error() != "(1, 11): mixed types in array" { + t.Error("Bad error message:", err.Error()) + } +} + +func TestArrayNestedStrings(t *testing.T) { + tree, err := Load("data = [ [\"gamma\", \"delta\"], [\"Foo\"] ]") + assertTree(t, tree, err, map[string]interface{}{ + "data": [][]string{{"gamma", "delta"}, {"Foo"}}, + }) +} + +func TestParseUnknownRvalue(t *testing.T) { + _, err := Load("a = !bssss") + if err == nil { + t.Error("Expecting a parse error") + } + + _, err = Load("a = /b") + if err == nil { + t.Error("Expecting a parse error") + } +} + +func TestMissingValue(t *testing.T) { + _, err := Load("a = ") + if err.Error() != "(1, 5): expecting a value" { + t.Error("Bad error message:", err.Error()) + } +} + +func TestUnterminatedArray(t *testing.T) { + _, err := Load("a = [1,") + if err.Error() != "(1, 8): unterminated array" { + t.Error("Bad error message:", err.Error()) + } + + _, err = Load("a = [1") + if err.Error() != "(1, 7): unterminated array" { + t.Error("Bad error message:", err.Error()) + } + + _, err = Load("a = [1 2") + if err.Error() != "(1, 8): missing comma" { + t.Error("Bad error message:", err.Error()) + } +} + +func TestNewlinesInArrays(t *testing.T) { + tree, err := Load("a = [1,\n2,\n3]") + assertTree(t, tree, err, map[string]interface{}{ + "a": []int64{int64(1), int64(2), int64(3)}, + }) +} + +func TestArrayWithExtraComma(t *testing.T) { + tree, err := Load("a = [1,\n2,\n3,\n]") + assertTree(t, tree, err, map[string]interface{}{ + "a": []int64{int64(1), int64(2), int64(3)}, + }) +} + +func TestArrayWithExtraCommaComment(t *testing.T) { + tree, err := Load("a = [1, # wow\n2, # such items\n3, # so array\n]") + assertTree(t, tree, err, map[string]interface{}{ + "a": []int64{int64(1), int64(2), int64(3)}, + }) +} + +func TestSimpleInlineGroup(t *testing.T) { + tree, err := Load("key = {a = 42}") + assertTree(t, tree, err, map[string]interface{}{ + "key": map[string]interface{}{ + "a": int64(42), + }, + }) +} + +func TestDoubleInlineGroup(t *testing.T) { + tree, err := Load("key = {a = 42, b = \"foo\"}") + assertTree(t, tree, err, map[string]interface{}{ + "key": map[string]interface{}{ + "a": int64(42), + "b": "foo", + }, + }) +} + +func TestExampleInlineGroup(t *testing.T) { + tree, err := Load(`name = { first = "Tom", last = "Preston-Werner" } +point = { x = 1, y = 2 }`) + assertTree(t, tree, err, map[string]interface{}{ + "name": map[string]interface{}{ + "first": "Tom", + "last": "Preston-Werner", + }, + "point": map[string]interface{}{ + "x": int64(1), + "y": int64(2), + }, + }) +} + +func TestExampleInlineGroupInArray(t *testing.T) { + tree, err := Load(`points = [{ x = 1, y = 2 }]`) + assertTree(t, tree, err, map[string]interface{}{ + "points": []map[string]interface{}{ + { + "x": int64(1), + "y": int64(2), + }, + }, + }) +} + +func TestInlineTableUnterminated(t *testing.T) { + _, err := Load("foo = {") + if err.Error() != "(1, 8): unterminated inline table" { + t.Error("Bad error message:", err.Error()) + } +} + +func TestInlineTableCommaExpected(t *testing.T) { + _, err := Load("foo = {hello = 53 test = foo}") + if err.Error() != "(1, 19): comma expected between fields in inline table" { + t.Error("Bad error message:", err.Error()) + } +} + +func TestInlineTableCommaStart(t *testing.T) { + _, err := Load("foo = {, hello = 53}") + if err.Error() != "(1, 8): inline table cannot start with a comma" { + t.Error("Bad error message:", err.Error()) + } +} + +func TestInlineTableDoubleComma(t *testing.T) { + _, err := Load("foo = {hello = 53,, foo = 17}") + if err.Error() != "(1, 19): need field between two commas in inline table" { + t.Error("Bad error message:", err.Error()) + } +} + +func TestDuplicateGroups(t *testing.T) { + _, err := Load("[foo]\na=2\n[foo]b=3") + if err.Error() != "(3, 2): duplicated tables" { + t.Error("Bad error message:", err.Error()) + } +} + +func TestDuplicateKeys(t *testing.T) { + _, err := Load("foo = 2\nfoo = 3") + if err.Error() != "(2, 1): The following key was defined twice: foo" { + t.Error("Bad error message:", err.Error()) + } +} + +func TestEmptyIntermediateTable(t *testing.T) { + _, err := Load("[foo..bar]") + if err.Error() != "(1, 2): invalid table array key: empty table key" { + t.Error("Bad error message:", err.Error()) + } +} + +func TestImplicitDeclarationBefore(t *testing.T) { + tree, err := Load("[a.b.c]\nanswer = 42\n[a]\nbetter = 43") + assertTree(t, tree, err, map[string]interface{}{ + "a": map[string]interface{}{ + "b": map[string]interface{}{ + "c": map[string]interface{}{ + "answer": int64(42), + }, + }, + "better": int64(43), + }, + }) +} + +func TestFloatsWithoutLeadingZeros(t *testing.T) { + _, err := Load("a = .42") + if err.Error() != "(1, 5): cannot start float with a dot" { + t.Error("Bad error message:", err.Error()) + } + + _, err = Load("a = -.42") + if err.Error() != "(1, 5): cannot start float with a dot" { + t.Error("Bad error message:", err.Error()) + } +} + +func TestMissingFile(t *testing.T) { + _, err := LoadFile("foo.toml") + if err.Error() != "open foo.toml: no such file or directory" { + t.Error("Bad error message:", err.Error()) + } +} + +func TestParseFile(t *testing.T) { + tree, err := LoadFile("example.toml") + + assertTree(t, tree, err, map[string]interface{}{ + "title": "TOML Example", + "owner": map[string]interface{}{ + "name": "Tom Preston-Werner", + "organization": "GitHub", + "bio": "GitHub Cofounder & CEO\nLikes tater tots and beer.", + "dob": time.Date(1979, time.May, 27, 7, 32, 0, 0, time.UTC), + }, + "database": map[string]interface{}{ + "server": "192.168.1.1", + "ports": []int64{8001, 8001, 8002}, + "connection_max": 5000, + "enabled": true, + }, + "servers": map[string]interface{}{ + "alpha": map[string]interface{}{ + "ip": "10.0.0.1", + "dc": "eqdc10", + }, + "beta": map[string]interface{}{ + "ip": "10.0.0.2", + "dc": "eqdc10", + }, + }, + "clients": map[string]interface{}{ + "data": []interface{}{ + []string{"gamma", "delta"}, + []int64{1, 2}, + }, + }, + }) +} + +func TestParseFileCRLF(t *testing.T) { + tree, err := LoadFile("example-crlf.toml") + + assertTree(t, tree, err, map[string]interface{}{ + "title": "TOML Example", + "owner": map[string]interface{}{ + "name": "Tom Preston-Werner", + "organization": "GitHub", + "bio": "GitHub Cofounder & CEO\nLikes tater tots and beer.", + "dob": time.Date(1979, time.May, 27, 7, 32, 0, 0, time.UTC), + }, + "database": map[string]interface{}{ + "server": "192.168.1.1", + "ports": []int64{8001, 8001, 8002}, + "connection_max": 5000, + "enabled": true, + }, + "servers": map[string]interface{}{ + "alpha": map[string]interface{}{ + "ip": "10.0.0.1", + "dc": "eqdc10", + }, + "beta": map[string]interface{}{ + "ip": "10.0.0.2", + "dc": "eqdc10", + }, + }, + "clients": map[string]interface{}{ + "data": []interface{}{ + []string{"gamma", "delta"}, + []int64{1, 2}, + }, + }, + }) +} + +func TestParseKeyGroupArray(t *testing.T) { + tree, err := Load("[[foo.bar]] a = 42\n[[foo.bar]] a = 69") + assertTree(t, tree, err, map[string]interface{}{ + "foo": map[string]interface{}{ + "bar": []map[string]interface{}{ + {"a": int64(42)}, + {"a": int64(69)}, + }, + }, + }) +} + +func TestParseKeyGroupArrayUnfinished(t *testing.T) { + _, err := Load("[[foo.bar]\na = 42") + if err.Error() != "(1, 10): was expecting token [[, but got unclosed table array key instead" { + t.Error("Bad error message:", err.Error()) + } + + _, err = Load("[[foo.[bar]\na = 42") + if err.Error() != "(1, 3): unexpected token table array key cannot contain ']', was expecting a table array key" { + t.Error("Bad error message:", err.Error()) + } +} + +func TestParseKeyGroupArrayQueryExample(t *testing.T) { + tree, err := Load(` + [[book]] + title = "The Stand" + author = "Stephen King" + [[book]] + title = "For Whom the Bell Tolls" + author = "Ernest Hemmingway" + [[book]] + title = "Neuromancer" + author = "William Gibson" + `) + + assertTree(t, tree, err, map[string]interface{}{ + "book": []map[string]interface{}{ + {"title": "The Stand", "author": "Stephen King"}, + {"title": "For Whom the Bell Tolls", "author": "Ernest Hemmingway"}, + {"title": "Neuromancer", "author": "William Gibson"}, + }, + }) +} + +func TestParseKeyGroupArraySpec(t *testing.T) { + tree, err := Load("[[fruit]]\n name=\"apple\"\n [fruit.physical]\n color=\"red\"\n shape=\"round\"\n [[fruit]]\n name=\"banana\"") + assertTree(t, tree, err, map[string]interface{}{ + "fruit": []map[string]interface{}{ + {"name": "apple", "physical": map[string]interface{}{"color": "red", "shape": "round"}}, + {"name": "banana"}, + }, + }) +} + +func TestTomlValueStringRepresentation(t *testing.T) { + for idx, item := range []struct { + Value interface{} + Expect string + }{ + {int64(12345), "12345"}, + {uint64(50), "50"}, + {float64(123.45), "123.45"}, + {bool(true), "true"}, + {"hello world", "\"hello world\""}, + {"\b\t\n\f\r\"\\", "\"\\b\\t\\n\\f\\r\\\"\\\\\""}, + {"\x05", "\"\\u0005\""}, + {time.Date(1979, time.May, 27, 7, 32, 0, 0, time.UTC), + "1979-05-27T07:32:00Z"}, + {[]interface{}{"gamma", "delta"}, + "[\"gamma\",\"delta\"]"}, + {nil, ""}, + } { + result, err := tomlValueStringRepresentation(item.Value) + if err != nil { + t.Errorf("Test %d - unexpected error: %s", idx, err) + } + if result != item.Expect { + t.Errorf("Test %d - got '%s', expected '%s'", idx, result, item.Expect) + } + } +} + +func TestToStringMapStringString(t *testing.T) { + tree, err := TreeFromMap(map[string]interface{}{"m": map[string]interface{}{"v": "abc"}}) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + want := "\n[m]\n v = \"abc\"\n" + got := tree.String() + + if got != want { + t.Errorf("want:\n%q\ngot:\n%q", want, got) + } +} + +func assertPosition(t *testing.T, text string, ref map[string]Position) { + tree, err := Load(text) + if err != nil { + t.Errorf("Error loading document text: `%v`", text) + t.Errorf("Error: %v", err) + } + for path, pos := range ref { + testPos := tree.GetPosition(path) + if testPos.Invalid() { + t.Errorf("Failed to query tree path or path has invalid position: %s", path) + } else if pos != testPos { + t.Errorf("Expected position %v, got %v instead", pos, testPos) + } + } +} + +func TestDocumentPositions(t *testing.T) { + assertPosition(t, + "[foo]\nbar=42\nbaz=69", + map[string]Position{ + "": {1, 1}, + "foo": {1, 1}, + "foo.bar": {2, 1}, + "foo.baz": {3, 1}, + }) +} + +func TestDocumentPositionsWithSpaces(t *testing.T) { + assertPosition(t, + " [foo]\n bar=42\n baz=69", + map[string]Position{ + "": {1, 1}, + "foo": {1, 3}, + "foo.bar": {2, 3}, + "foo.baz": {3, 3}, + }) +} + +func TestDocumentPositionsWithGroupArray(t *testing.T) { + assertPosition(t, + "[[foo]]\nbar=42\nbaz=69", + map[string]Position{ + "": {1, 1}, + "foo": {1, 1}, + "foo.bar": {2, 1}, + "foo.baz": {3, 1}, + }) +} + +func TestNestedTreePosition(t *testing.T) { + assertPosition(t, + "[foo.bar]\na=42\nb=69", + map[string]Position{ + "": {1, 1}, + "foo": {1, 1}, + "foo.bar": {1, 1}, + "foo.bar.a": {2, 1}, + "foo.bar.b": {3, 1}, + }) +} + +func TestInvalidGroupArray(t *testing.T) { + _, err := Load("[table#key]\nanswer = 42") + if err == nil { + t.Error("Should error") + } + + _, err = Load("[foo.[bar]\na = 42") + if err.Error() != "(1, 2): unexpected token table key cannot contain ']', was expecting a table key" { + t.Error("Bad error message:", err.Error()) + } +} + +func TestDoubleEqual(t *testing.T) { + _, err := Load("foo= = 2") + if err.Error() != "(1, 6): cannot have multiple equals for the same key" { + t.Error("Bad error message:", err.Error()) + } +} + +func TestGroupArrayReassign(t *testing.T) { + _, err := Load("[hello]\n[[hello]]") + if err.Error() != "(2, 3): key \"hello\" is already assigned and not of type table array" { + t.Error("Bad error message:", err.Error()) + } +} + +func TestInvalidFloatParsing(t *testing.T) { + _, err := Load("a=1e_2") + if err.Error() != "(1, 3): invalid use of _ in number" { + t.Error("Bad error message:", err.Error()) + } + + _, err = Load("a=1e2_") + if err.Error() != "(1, 3): invalid use of _ in number" { + t.Error("Bad error message:", err.Error()) + } + + _, err = Load("a=1__2") + if err.Error() != "(1, 3): invalid use of _ in number" { + t.Error("Bad error message:", err.Error()) + } + + _, err = Load("a=_1_2") + if err.Error() != "(1, 3): cannot start number with underscore" { + t.Error("Bad error message:", err.Error()) + } +} diff --git a/vendor/github.com/pelletier/go-toml/position.go b/vendor/github.com/pelletier/go-toml/position.go new file mode 100644 index 0000000000..c17bff87ba --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/position.go @@ -0,0 +1,29 @@ +// Position support for go-toml + +package toml + +import ( + "fmt" +) + +// Position of a document element within a TOML document. +// +// Line and Col are both 1-indexed positions for the element's line number and +// column number, respectively. Values of zero or less will cause Invalid(), +// to return true. +type Position struct { + Line int // line within the document + Col int // column within the line +} + +// String representation of the position. +// Displays 1-indexed line and column numbers. +func (p Position) String() string { + return fmt.Sprintf("(%d, %d)", p.Line, p.Col) +} + +// Invalid returns whether or not the position is valid (i.e. with negative or +// null values) +func (p Position) Invalid() bool { + return p.Line <= 0 || p.Col <= 0 +} diff --git a/vendor/github.com/pelletier/go-toml/position_test.go b/vendor/github.com/pelletier/go-toml/position_test.go new file mode 100644 index 0000000000..63ad1afc86 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/position_test.go @@ -0,0 +1,29 @@ +// Testing support for go-toml + +package toml + +import ( + "testing" +) + +func TestPositionString(t *testing.T) { + p := Position{123, 456} + expected := "(123, 456)" + value := p.String() + + if value != expected { + t.Errorf("Expected %v, got %v instead", expected, value) + } +} + +func TestInvalid(t *testing.T) { + for i, v := range []Position{ + {0, 1234}, + {1234, 0}, + {0, 0}, + } { + if !v.Invalid() { + t.Errorf("Position at %v is valid: %v", i, v) + } + } +} diff --git a/vendor/github.com/pelletier/go-toml/query.go b/vendor/github.com/pelletier/go-toml/query.go new file mode 100644 index 0000000000..307a1ecabc --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/query.go @@ -0,0 +1,153 @@ +package toml + +import ( + "time" +) + +// NodeFilterFn represents a user-defined filter function, for use with +// Query.SetFilter(). +// +// The return value of the function must indicate if 'node' is to be included +// at this stage of the TOML path. Returning true will include the node, and +// returning false will exclude it. +// +// NOTE: Care should be taken to write script callbacks such that they are safe +// to use from multiple goroutines. +type NodeFilterFn func(node interface{}) bool + +// QueryResult is the result of Executing a Query. +type QueryResult struct { + items []interface{} + positions []Position +} + +// appends a value/position pair to the result set. +func (r *QueryResult) appendResult(node interface{}, pos Position) { + r.items = append(r.items, node) + r.positions = append(r.positions, pos) +} + +// Values is a set of values within a QueryResult. The order of values is not +// guaranteed to be in document order, and may be different each time a query is +// executed. +func (r QueryResult) Values() []interface{} { + values := make([]interface{}, len(r.items)) + for i, v := range r.items { + o, ok := v.(*tomlValue) + if ok { + values[i] = o.value + } else { + values[i] = v + } + } + return values +} + +// Positions is a set of positions for values within a QueryResult. Each index +// in Positions() corresponds to the entry in Value() of the same index. +func (r QueryResult) Positions() []Position { + return r.positions +} + +// runtime context for executing query paths +type queryContext struct { + result *QueryResult + filters *map[string]NodeFilterFn + lastPosition Position +} + +// generic path functor interface +type pathFn interface { + setNext(next pathFn) + call(node interface{}, ctx *queryContext) +} + +// A Query is the representation of a compiled TOML path. A Query is safe +// for concurrent use by multiple goroutines. +type Query struct { + root pathFn + tail pathFn + filters *map[string]NodeFilterFn +} + +func newQuery() *Query { + return &Query{ + root: nil, + tail: nil, + filters: &defaultFilterFunctions, + } +} + +func (q *Query) appendPath(next pathFn) { + if q.root == nil { + q.root = next + } else { + q.tail.setNext(next) + } + q.tail = next + next.setNext(newTerminatingFn()) // init the next functor +} + +// CompileQuery compiles a TOML path expression. The returned Query can be used +// to match elements within a TomlTree and its descendants. +func CompileQuery(path string) (*Query, error) { + return parseQuery(lexQuery(path)) +} + +// Execute executes a query against a TomlTree, and returns the result of the query. +func (q *Query) Execute(tree *TomlTree) *QueryResult { + result := &QueryResult{ + items: []interface{}{}, + positions: []Position{}, + } + if q.root == nil { + result.appendResult(tree, tree.GetPosition("")) + } else { + ctx := &queryContext{ + result: result, + filters: q.filters, + } + q.root.call(tree, ctx) + } + return result +} + +// SetFilter sets a user-defined filter function. These may be used inside +// "?(..)" query expressions to filter TOML document elements within a query. +func (q *Query) SetFilter(name string, fn NodeFilterFn) { + if q.filters == &defaultFilterFunctions { + // clone the static table + q.filters = &map[string]NodeFilterFn{} + for k, v := range defaultFilterFunctions { + (*q.filters)[k] = v + } + } + (*q.filters)[name] = fn +} + +var defaultFilterFunctions = map[string]NodeFilterFn{ + "tree": func(node interface{}) bool { + _, ok := node.(*TomlTree) + return ok + }, + "int": func(node interface{}) bool { + _, ok := node.(int64) + return ok + }, + "float": func(node interface{}) bool { + _, ok := node.(float64) + return ok + }, + "string": func(node interface{}) bool { + _, ok := node.(string) + return ok + }, + "time": func(node interface{}) bool { + _, ok := node.(time.Time) + return ok + }, + "bool": func(node interface{}) bool { + _, ok := node.(bool) + return ok + }, +} diff --git a/vendor/github.com/pelletier/go-toml/query_test.go b/vendor/github.com/pelletier/go-toml/query_test.go new file mode 100644 index 0000000000..0d9f3832b9 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/query_test.go @@ -0,0 +1,70 @@ +package toml + +import ( + "testing" +) + +func assertArrayContainsInAnyOrder(t *testing.T, array []interface{}, objects ...interface{}) { + if len(array) != len(objects) { + t.Fatalf("array contains %d objects but %d are expected", len(array), len(objects)) + } + + for _, o := range objects { + found := false + for _, a := range array { + if a == o { + found = true + break + } + } + if !found { + t.Fatal(o, "not found in array", array) + } + } +} + +func TestQueryExample(t *testing.T) { + config, _ := Load(` + [[book]] + title = "The Stand" + author = "Stephen King" + [[book]] + title = "For Whom the Bell Tolls" + author = "Ernest Hemmingway" + [[book]] + title = "Neuromancer" + author = "William Gibson" + `) + + authors, _ := config.Query("$.book.author") + names := authors.Values() + if len(names) != 3 { + t.Fatalf("query should return 3 names but returned %d", len(names)) + } + assertArrayContainsInAnyOrder(t, names, "Stephen King", "Ernest Hemmingway", "William Gibson") +} + +func TestQueryReadmeExample(t *testing.T) { + config, _ := Load(` +[postgres] +user = "pelletier" +password = "mypassword" +`) + results, _ := config.Query("$..[user,password]") + values := results.Values() + if len(values) != 2 { + t.Fatalf("query should return 2 values but returned %d", len(values)) + } + assertArrayContainsInAnyOrder(t, values, "pelletier", "mypassword") +} + +func TestQueryPathNotPresent(t *testing.T) { + config, _ := Load(`a = "hello"`) + results, err := config.Query("$.foo.bar") + if err != nil { + t.Fatalf("err should be nil. got %s instead", err) + } + if len(results.items) != 0 { + t.Fatalf("no items should be matched. %d matched instead", len(results.items)) + } +} diff --git a/vendor/github.com/pelletier/go-toml/querylexer.go b/vendor/github.com/pelletier/go-toml/querylexer.go new file mode 100644 index 0000000000..960681d0ff --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/querylexer.go @@ -0,0 +1,356 @@ +// TOML JSONPath lexer. +// +// Written using the principles developed by Rob Pike in +// http://www.youtube.com/watch?v=HxaD_trXwRE + +package toml + +import ( + "fmt" + "strconv" + "strings" + "unicode/utf8" +) + +// Lexer state function +type queryLexStateFn func() queryLexStateFn + +// Lexer definition +type queryLexer struct { + input string + start int + pos int + width int + tokens chan token + depth int + line int + col int + stringTerm string +} + +func (l *queryLexer) run() { + for state := l.lexVoid; state != nil; { + state = state() + } + close(l.tokens) +} + +func (l *queryLexer) nextStart() { + // iterate by runes (utf8 characters) + // search for newlines and advance line/col counts + for i := l.start; i < l.pos; { + r, width := utf8.DecodeRuneInString(l.input[i:]) + if r == '\n' { + l.line++ + l.col = 1 + } else { + l.col++ + } + i += width + } + // advance start position to next token + l.start = l.pos +} + +func (l *queryLexer) emit(t tokenType) { + l.tokens <- token{ + Position: Position{l.line, l.col}, + typ: t, + val: l.input[l.start:l.pos], + } + l.nextStart() +} + +func (l *queryLexer) emitWithValue(t tokenType, value string) { + l.tokens <- token{ + Position: Position{l.line, l.col}, + typ: t, + val: value, + } + l.nextStart() +} + +func (l *queryLexer) next() rune { + if l.pos >= len(l.input) { + l.width = 0 + return eof + } + var r rune + r, l.width = utf8.DecodeRuneInString(l.input[l.pos:]) + l.pos += l.width + return r +} + +func (l *queryLexer) ignore() { + l.nextStart() +} + +func (l *queryLexer) backup() { + l.pos -= l.width +} + +func (l *queryLexer) errorf(format string, args ...interface{}) queryLexStateFn { + l.tokens <- token{ + Position: Position{l.line, l.col}, + typ: tokenError, + val: fmt.Sprintf(format, args...), + } + return nil +} + +func (l *queryLexer) peek() rune { + r := l.next() + l.backup() + return r +} + +func (l *queryLexer) accept(valid string) bool { + if strings.ContainsRune(valid, l.next()) { + return true + } + l.backup() + return false +} + +func (l *queryLexer) follow(next string) bool { + return strings.HasPrefix(l.input[l.pos:], next) +} + +func (l *queryLexer) lexVoid() queryLexStateFn { + for { + next := l.peek() + switch next { + case '$': + l.pos++ + l.emit(tokenDollar) + continue + case '.': + if l.follow("..") { + l.pos += 2 + l.emit(tokenDotDot) + } else { + l.pos++ + l.emit(tokenDot) + } + continue + case '[': + l.pos++ + l.emit(tokenLeftBracket) + continue + case ']': + l.pos++ + l.emit(tokenRightBracket) + continue + case ',': + l.pos++ + l.emit(tokenComma) + continue + case '*': + l.pos++ + l.emit(tokenStar) + continue + case '(': + l.pos++ + l.emit(tokenLeftParen) + continue + case ')': + l.pos++ + l.emit(tokenRightParen) + continue + case '?': + l.pos++ + l.emit(tokenQuestion) + continue + case ':': + l.pos++ + l.emit(tokenColon) + continue + case '\'': + l.ignore() + l.stringTerm = string(next) + return l.lexString + case '"': + l.ignore() + l.stringTerm = string(next) + return l.lexString + } + + if isSpace(next) { + l.next() + l.ignore() + continue + } + + if isAlphanumeric(next) { + return l.lexKey + } + + if next == '+' || next == '-' || isDigit(next) { + return l.lexNumber + } + + if l.next() == eof { + break + } + + return l.errorf("unexpected char: '%v'", next) + } + l.emit(tokenEOF) + return nil +} + +func (l *queryLexer) lexKey() queryLexStateFn { + for { + next := l.peek() + if !isAlphanumeric(next) { + l.emit(tokenKey) + return l.lexVoid + } + + if l.next() == eof { + break + } + } + l.emit(tokenEOF) + return nil +} + +func (l *queryLexer) lexString() queryLexStateFn { + l.pos++ + l.ignore() + growingString := "" + + for { + if l.follow(l.stringTerm) { + l.emitWithValue(tokenString, growingString) + l.pos++ + l.ignore() + return l.lexVoid + } + + if l.follow("\\\"") { + l.pos++ + growingString += "\"" + } else if l.follow("\\'") { + l.pos++ + growingString += "'" + } else if l.follow("\\n") { + l.pos++ + growingString += "\n" + } else if l.follow("\\b") { + l.pos++ + growingString += "\b" + } else if l.follow("\\f") { + l.pos++ + growingString += "\f" + } else if l.follow("\\/") { + l.pos++ + growingString += "/" + } else if l.follow("\\t") { + l.pos++ + growingString += "\t" + } else if l.follow("\\r") { + l.pos++ + growingString += "\r" + } else if l.follow("\\\\") { + l.pos++ + growingString += "\\" + } else if l.follow("\\u") { + l.pos += 2 + code := "" + for i := 0; i < 4; i++ { + c := l.peek() + l.pos++ + if !isHexDigit(c) { + return l.errorf("unfinished unicode escape") + } + code = code + string(c) + } + l.pos-- + intcode, err := strconv.ParseInt(code, 16, 32) + if err != nil { + return l.errorf("invalid unicode escape: \\u" + code) + } + growingString += string(rune(intcode)) + } else if l.follow("\\U") { + l.pos += 2 + code := "" + for i := 0; i < 8; i++ { + c := l.peek() + l.pos++ + if !isHexDigit(c) { + return l.errorf("unfinished unicode escape") + } + code = code + string(c) + } + l.pos-- + intcode, err := strconv.ParseInt(code, 16, 32) + if err != nil { + return l.errorf("invalid unicode escape: \\u" + code) + } + growingString += string(rune(intcode)) + } else if l.follow("\\") { + l.pos++ + return l.errorf("invalid escape sequence: \\" + string(l.peek())) + } else { + growingString += string(l.peek()) + } + + if l.next() == eof { + break + } + } + + return l.errorf("unclosed string") +} + +func (l *queryLexer) lexNumber() queryLexStateFn { + l.ignore() + if !l.accept("+") { + l.accept("-") + } + pointSeen := false + digitSeen := false + for { + next := l.next() + if next == '.' { + if pointSeen { + return l.errorf("cannot have two dots in one float") + } + if !isDigit(l.peek()) { + return l.errorf("float cannot end with a dot") + } + pointSeen = true + } else if isDigit(next) { + digitSeen = true + } else { + l.backup() + break + } + if pointSeen && !digitSeen { + return l.errorf("cannot start float with a dot") + } + } + + if !digitSeen { + return l.errorf("no digit in that number") + } + if pointSeen { + l.emit(tokenFloat) + } else { + l.emit(tokenInteger) + } + return l.lexVoid +} + +// Entry point +func lexQuery(input string) chan token { + l := &queryLexer{ + input: input, + tokens: make(chan token), + line: 1, + col: 1, + } + go l.run() + return l.tokens +} diff --git a/vendor/github.com/pelletier/go-toml/querylexer_test.go b/vendor/github.com/pelletier/go-toml/querylexer_test.go new file mode 100644 index 0000000000..2d0803ff70 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/querylexer_test.go @@ -0,0 +1,178 @@ +package toml + +import ( + "testing" +) + +func testQLFlow(t *testing.T, input string, expectedFlow []token) { + ch := lexQuery(input) + for idx, expected := range expectedFlow { + token := <-ch + if token != expected { + t.Log("While testing #", idx, ":", input) + t.Log("compared (got)", token, "to (expected)", expected) + t.Log("\tvalue:", token.val, "<->", expected.val) + t.Log("\tvalue as bytes:", []byte(token.val), "<->", []byte(expected.val)) + t.Log("\ttype:", token.typ.String(), "<->", expected.typ.String()) + t.Log("\tline:", token.Line, "<->", expected.Line) + t.Log("\tcolumn:", token.Col, "<->", expected.Col) + t.Log("compared", token, "to", expected) + t.FailNow() + } + } + + tok, ok := <-ch + if ok { + t.Log("channel is not closed!") + t.Log(len(ch)+1, "tokens remaining:") + + t.Log("token ->", tok) + for token := range ch { + t.Log("token ->", token) + } + t.FailNow() + } +} + +func TestLexSpecialChars(t *testing.T) { + testQLFlow(t, " .$[]..()?*", []token{ + {Position{1, 2}, tokenDot, "."}, + {Position{1, 3}, tokenDollar, "$"}, + {Position{1, 4}, tokenLeftBracket, "["}, + {Position{1, 5}, tokenRightBracket, "]"}, + {Position{1, 6}, tokenDotDot, ".."}, + {Position{1, 8}, tokenLeftParen, "("}, + {Position{1, 9}, tokenRightParen, ")"}, + {Position{1, 10}, tokenQuestion, "?"}, + {Position{1, 11}, tokenStar, "*"}, + {Position{1, 12}, tokenEOF, ""}, + }) +} + +func TestLexString(t *testing.T) { + testQLFlow(t, "'foo\n'", []token{ + {Position{1, 2}, tokenString, "foo\n"}, + {Position{2, 2}, tokenEOF, ""}, + }) +} + +func TestLexDoubleString(t *testing.T) { + testQLFlow(t, `"bar"`, []token{ + {Position{1, 2}, tokenString, "bar"}, + {Position{1, 6}, tokenEOF, ""}, + }) +} + +func TestLexStringEscapes(t *testing.T) { + testQLFlow(t, `"foo \" \' \b \f \/ \t \r \\ \u03A9 \U00012345 \n bar"`, []token{ + {Position{1, 2}, tokenString, "foo \" ' \b \f / \t \r \\ \u03A9 \U00012345 \n bar"}, + {Position{1, 55}, tokenEOF, ""}, + }) +} + +func TestLexStringUnfinishedUnicode4(t *testing.T) { + testQLFlow(t, `"\u000"`, []token{ + {Position{1, 2}, tokenError, "unfinished unicode escape"}, + }) +} + +func TestLexStringUnfinishedUnicode8(t *testing.T) { + testQLFlow(t, `"\U0000"`, []token{ + {Position{1, 2}, tokenError, "unfinished unicode escape"}, + }) +} + +func TestLexStringInvalidEscape(t *testing.T) { + testQLFlow(t, `"\x"`, []token{ + {Position{1, 2}, tokenError, "invalid escape sequence: \\x"}, + }) +} + +func TestLexStringUnfinished(t *testing.T) { + testQLFlow(t, `"bar`, []token{ + {Position{1, 2}, tokenError, "unclosed string"}, + }) +} + +func TestLexKey(t *testing.T) { + testQLFlow(t, "foo", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 4}, tokenEOF, ""}, + }) +} + +func TestLexRecurse(t *testing.T) { + testQLFlow(t, "$..*", []token{ + {Position{1, 1}, tokenDollar, "$"}, + {Position{1, 2}, tokenDotDot, ".."}, + {Position{1, 4}, tokenStar, "*"}, + {Position{1, 5}, tokenEOF, ""}, + }) +} + +func TestLexBracketKey(t *testing.T) { + testQLFlow(t, "$[foo]", []token{ + {Position{1, 1}, tokenDollar, "$"}, + {Position{1, 2}, tokenLeftBracket, "["}, + {Position{1, 3}, tokenKey, "foo"}, + {Position{1, 6}, tokenRightBracket, "]"}, + {Position{1, 7}, tokenEOF, ""}, + }) +} + +func TestLexSpace(t *testing.T) { + testQLFlow(t, "foo bar baz", []token{ + {Position{1, 1}, tokenKey, "foo"}, + {Position{1, 5}, tokenKey, "bar"}, + {Position{1, 9}, tokenKey, "baz"}, + {Position{1, 12}, tokenEOF, ""}, + }) +} + +func TestLexInteger(t *testing.T) { + testQLFlow(t, "100 +200 -300", []token{ + {Position{1, 1}, tokenInteger, "100"}, + {Position{1, 5}, tokenInteger, "+200"}, + {Position{1, 10}, tokenInteger, "-300"}, + {Position{1, 14}, tokenEOF, ""}, + }) +} + +func TestLexFloat(t *testing.T) { + testQLFlow(t, "100.0 +200.0 -300.0", []token{ + {Position{1, 1}, tokenFloat, "100.0"}, + {Position{1, 7}, tokenFloat, "+200.0"}, + {Position{1, 14}, tokenFloat, "-300.0"}, + {Position{1, 20}, tokenEOF, ""}, + }) +} + +func TestLexFloatWithMultipleDots(t *testing.T) { + testQLFlow(t, "4.2.", []token{ + {Position{1, 1}, tokenError, "cannot have two dots in one float"}, + }) +} + +func TestLexFloatLeadingDot(t *testing.T) { + testQLFlow(t, "+.1", []token{ + {Position{1, 1}, tokenError, "cannot start float with a dot"}, + }) +} + +func TestLexFloatWithTrailingDot(t *testing.T) { + testQLFlow(t, "42.", []token{ + {Position{1, 1}, tokenError, "float cannot end with a dot"}, + }) +} + +func TestLexNumberWithoutDigit(t *testing.T) { + testQLFlow(t, "+", []token{ + {Position{1, 1}, tokenError, "no digit in that number"}, + }) +} + +func TestLexUnknown(t *testing.T) { + testQLFlow(t, "^", []token{ + {Position{1, 1}, tokenError, "unexpected char: '94'"}, + }) +} diff --git a/vendor/github.com/pelletier/go-toml/queryparser.go b/vendor/github.com/pelletier/go-toml/queryparser.go new file mode 100644 index 0000000000..1cbfc83b26 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/queryparser.go @@ -0,0 +1,275 @@ +/* + Based on the "jsonpath" spec/concept. + + http://goessner.net/articles/JsonPath/ + https://code.google.com/p/json-path/ +*/ + +package toml + +import ( + "fmt" +) + +const maxInt = int(^uint(0) >> 1) + +type queryParser struct { + flow chan token + tokensBuffer []token + query *Query + union []pathFn + err error +} + +type queryParserStateFn func() queryParserStateFn + +// Formats and panics an error message based on a token +func (p *queryParser) parseError(tok *token, msg string, args ...interface{}) queryParserStateFn { + p.err = fmt.Errorf(tok.Position.String()+": "+msg, args...) + return nil // trigger parse to end +} + +func (p *queryParser) run() { + for state := p.parseStart; state != nil; { + state = state() + } +} + +func (p *queryParser) backup(tok *token) { + p.tokensBuffer = append(p.tokensBuffer, *tok) +} + +func (p *queryParser) peek() *token { + if len(p.tokensBuffer) != 0 { + return &(p.tokensBuffer[0]) + } + + tok, ok := <-p.flow + if !ok { + return nil + } + p.backup(&tok) + return &tok +} + +func (p *queryParser) lookahead(types ...tokenType) bool { + result := true + buffer := []token{} + + for _, typ := range types { + tok := p.getToken() + if tok == nil { + result = false + break + } + buffer = append(buffer, *tok) + if tok.typ != typ { + result = false + break + } + } + // add the tokens back to the buffer, and return + p.tokensBuffer = append(p.tokensBuffer, buffer...) + return result +} + +func (p *queryParser) getToken() *token { + if len(p.tokensBuffer) != 0 { + tok := p.tokensBuffer[0] + p.tokensBuffer = p.tokensBuffer[1:] + return &tok + } + tok, ok := <-p.flow + if !ok { + return nil + } + return &tok +} + +func (p *queryParser) parseStart() queryParserStateFn { + tok := p.getToken() + + if tok == nil || tok.typ == tokenEOF { + return nil + } + + if tok.typ != tokenDollar { + return p.parseError(tok, "Expected '$' at start of expression") + } + + return p.parseMatchExpr +} + +// handle '.' prefix, '[]', and '..' +func (p *queryParser) parseMatchExpr() queryParserStateFn { + tok := p.getToken() + switch tok.typ { + case tokenDotDot: + p.query.appendPath(&matchRecursiveFn{}) + // nested parse for '..' + tok := p.getToken() + switch tok.typ { + case tokenKey: + p.query.appendPath(newMatchKeyFn(tok.val)) + return p.parseMatchExpr + case tokenLeftBracket: + return p.parseBracketExpr + case tokenStar: + // do nothing - the recursive predicate is enough + return p.parseMatchExpr + } + + case tokenDot: + // nested parse for '.' + tok := p.getToken() + switch tok.typ { + case tokenKey: + p.query.appendPath(newMatchKeyFn(tok.val)) + return p.parseMatchExpr + case tokenStar: + p.query.appendPath(&matchAnyFn{}) + return p.parseMatchExpr + } + + case tokenLeftBracket: + return p.parseBracketExpr + + case tokenEOF: + return nil // allow EOF at this stage + } + return p.parseError(tok, "expected match expression") +} + +func (p *queryParser) parseBracketExpr() queryParserStateFn { + if p.lookahead(tokenInteger, tokenColon) { + return p.parseSliceExpr + } + if p.peek().typ == tokenColon { + return p.parseSliceExpr + } + return p.parseUnionExpr +} + +func (p *queryParser) parseUnionExpr() queryParserStateFn { + var tok *token + + // this state can be traversed after some sub-expressions + // so be careful when setting up state in the parser + if p.union == nil { + p.union = []pathFn{} + } + +loop: // labeled loop for easy breaking + for { + if len(p.union) > 0 { + // parse delimiter or terminator + tok = p.getToken() + switch tok.typ { + case tokenComma: + // do nothing + case tokenRightBracket: + break loop + default: + return p.parseError(tok, "expected ',' or ']', not '%s'", tok.val) + } + } + + // parse sub expression + tok = p.getToken() + switch tok.typ { + case tokenInteger: + p.union = append(p.union, newMatchIndexFn(tok.Int())) + case tokenKey: + p.union = append(p.union, newMatchKeyFn(tok.val)) + case tokenString: + p.union = append(p.union, newMatchKeyFn(tok.val)) + case tokenQuestion: + return p.parseFilterExpr + default: + return p.parseError(tok, "expected union sub expression, not '%s', %d", tok.val, len(p.union)) + } + } + + // if there is only one sub-expression, use that instead + if len(p.union) == 1 { + p.query.appendPath(p.union[0]) + } else { + p.query.appendPath(&matchUnionFn{p.union}) + } + + p.union = nil // clear out state + return p.parseMatchExpr +} + +func (p *queryParser) parseSliceExpr() queryParserStateFn { + // init slice to grab all elements + start, end, step := 0, maxInt, 1 + + // parse optional start + tok := p.getToken() + if tok.typ == tokenInteger { + start = tok.Int() + tok = p.getToken() + } + if tok.typ != tokenColon { + return p.parseError(tok, "expected ':'") + } + + // parse optional end + tok = p.getToken() + if tok.typ == tokenInteger { + end = tok.Int() + tok = p.getToken() + } + if tok.typ == tokenRightBracket { + p.query.appendPath(newMatchSliceFn(start, end, step)) + return p.parseMatchExpr + } + if tok.typ != tokenColon { + return p.parseError(tok, "expected ']' or ':'") + } + + // parse optional step + tok = p.getToken() + if tok.typ == tokenInteger { + step = tok.Int() + if step < 0 { + return p.parseError(tok, "step must be a positive value") + } + tok = p.getToken() + } + if tok.typ != tokenRightBracket { + return p.parseError(tok, "expected ']'") + } + + p.query.appendPath(newMatchSliceFn(start, end, step)) + return p.parseMatchExpr +} + +func (p *queryParser) parseFilterExpr() queryParserStateFn { + tok := p.getToken() + if tok.typ != tokenLeftParen { + return p.parseError(tok, "expected left-parenthesis for filter expression") + } + tok = p.getToken() + if tok.typ != tokenKey && tok.typ != tokenString { + return p.parseError(tok, "expected key or string for filter funciton name") + } + name := tok.val + tok = p.getToken() + if tok.typ != tokenRightParen { + return p.parseError(tok, "expected right-parenthesis for filter expression") + } + p.union = append(p.union, newMatchFilterFn(name, tok.Position)) + return p.parseUnionExpr +} + +func parseQuery(flow chan token) (*Query, error) { + parser := &queryParser{ + flow: flow, + tokensBuffer: []token{}, + query: newQuery(), + } + parser.run() + return parser.query, parser.err +} diff --git a/vendor/github.com/pelletier/go-toml/queryparser_test.go b/vendor/github.com/pelletier/go-toml/queryparser_test.go new file mode 100644 index 0000000000..b2b85cefdc --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/queryparser_test.go @@ -0,0 +1,483 @@ +package toml + +import ( + "fmt" + "io/ioutil" + "sort" + "strings" + "testing" + "time" +) + +type queryTestNode struct { + value interface{} + position Position +} + +func valueString(root interface{}) string { + result := "" //fmt.Sprintf("%T:", root) + switch node := root.(type) { + case *tomlValue: + return valueString(node.value) + case *QueryResult: + items := []string{} + for i, v := range node.Values() { + items = append(items, fmt.Sprintf("%s:%s", + node.Positions()[i].String(), valueString(v))) + } + sort.Strings(items) + result = "[" + strings.Join(items, ", ") + "]" + case queryTestNode: + result = fmt.Sprintf("%s:%s", + node.position.String(), valueString(node.value)) + case []interface{}: + items := []string{} + for _, v := range node { + items = append(items, valueString(v)) + } + sort.Strings(items) + result = "[" + strings.Join(items, ", ") + "]" + case *TomlTree: + // workaround for unreliable map key ordering + items := []string{} + for _, k := range node.Keys() { + v := node.GetPath([]string{k}) + items = append(items, k+":"+valueString(v)) + } + sort.Strings(items) + result = "{" + strings.Join(items, ", ") + "}" + case map[string]interface{}: + // workaround for unreliable map key ordering + items := []string{} + for k, v := range node { + items = append(items, k+":"+valueString(v)) + } + sort.Strings(items) + result = "{" + strings.Join(items, ", ") + "}" + case int64: + result += fmt.Sprintf("%d", node) + case string: + result += "'" + node + "'" + case float64: + result += fmt.Sprintf("%f", node) + case bool: + result += fmt.Sprintf("%t", node) + case time.Time: + result += fmt.Sprintf("'%v'", node) + } + return result +} + +func assertValue(t *testing.T, result, ref interface{}) { + pathStr := valueString(result) + refStr := valueString(ref) + if pathStr != refStr { + t.Errorf("values do not match") + t.Log("test:", pathStr) + t.Log("ref: ", refStr) + } +} + +func assertQueryPositions(t *testing.T, toml, query string, ref []interface{}) { + tree, err := Load(toml) + if err != nil { + t.Errorf("Non-nil toml parse error: %v", err) + return + } + q, err := CompileQuery(query) + if err != nil { + t.Error(err) + return + } + results := q.Execute(tree) + assertValue(t, results, ref) +} + +func TestQueryRoot(t *testing.T) { + assertQueryPositions(t, + "a = 42", + "$", + []interface{}{ + queryTestNode{ + map[string]interface{}{ + "a": int64(42), + }, Position{1, 1}, + }, + }) +} + +func TestQueryKey(t *testing.T) { + assertQueryPositions(t, + "[foo]\na = 42", + "$.foo.a", + []interface{}{ + queryTestNode{ + int64(42), Position{2, 1}, + }, + }) +} + +func TestQueryKeyString(t *testing.T) { + assertQueryPositions(t, + "[foo]\na = 42", + "$.foo['a']", + []interface{}{ + queryTestNode{ + int64(42), Position{2, 1}, + }, + }) +} + +func TestQueryIndex(t *testing.T) { + assertQueryPositions(t, + "[foo]\na = [1,2,3,4,5,6,7,8,9,0]", + "$.foo.a[5]", + []interface{}{ + queryTestNode{ + int64(6), Position{2, 1}, + }, + }) +} + +func TestQuerySliceRange(t *testing.T) { + assertQueryPositions(t, + "[foo]\na = [1,2,3,4,5,6,7,8,9,0]", + "$.foo.a[0:5]", + []interface{}{ + queryTestNode{ + int64(1), Position{2, 1}, + }, + queryTestNode{ + int64(2), Position{2, 1}, + }, + queryTestNode{ + int64(3), Position{2, 1}, + }, + queryTestNode{ + int64(4), Position{2, 1}, + }, + queryTestNode{ + int64(5), Position{2, 1}, + }, + }) +} + +func TestQuerySliceStep(t *testing.T) { + assertQueryPositions(t, + "[foo]\na = [1,2,3,4,5,6,7,8,9,0]", + "$.foo.a[0:5:2]", + []interface{}{ + queryTestNode{ + int64(1), Position{2, 1}, + }, + queryTestNode{ + int64(3), Position{2, 1}, + }, + queryTestNode{ + int64(5), Position{2, 1}, + }, + }) +} + +func TestQueryAny(t *testing.T) { + assertQueryPositions(t, + "[foo.bar]\na=1\nb=2\n[foo.baz]\na=3\nb=4", + "$.foo.*", + []interface{}{ + queryTestNode{ + map[string]interface{}{ + "a": int64(1), + "b": int64(2), + }, Position{1, 1}, + }, + queryTestNode{ + map[string]interface{}{ + "a": int64(3), + "b": int64(4), + }, Position{4, 1}, + }, + }) +} +func TestQueryUnionSimple(t *testing.T) { + assertQueryPositions(t, + "[foo.bar]\na=1\nb=2\n[baz.foo]\na=3\nb=4\n[gorf.foo]\na=5\nb=6", + "$.*[bar,foo]", + []interface{}{ + queryTestNode{ + map[string]interface{}{ + "a": int64(1), + "b": int64(2), + }, Position{1, 1}, + }, + queryTestNode{ + map[string]interface{}{ + "a": int64(3), + "b": int64(4), + }, Position{4, 1}, + }, + queryTestNode{ + map[string]interface{}{ + "a": int64(5), + "b": int64(6), + }, Position{7, 1}, + }, + }) +} + +func TestQueryRecursionAll(t *testing.T) { + assertQueryPositions(t, + "[foo.bar]\na=1\nb=2\n[baz.foo]\na=3\nb=4\n[gorf.foo]\na=5\nb=6", + "$..*", + []interface{}{ + queryTestNode{ + map[string]interface{}{ + "foo": map[string]interface{}{ + "bar": map[string]interface{}{ + "a": int64(1), + "b": int64(2), + }, + }, + "baz": map[string]interface{}{ + "foo": map[string]interface{}{ + "a": int64(3), + "b": int64(4), + }, + }, + "gorf": map[string]interface{}{ + "foo": map[string]interface{}{ + "a": int64(5), + "b": int64(6), + }, + }, + }, Position{1, 1}, + }, + queryTestNode{ + map[string]interface{}{ + "bar": map[string]interface{}{ + "a": int64(1), + "b": int64(2), + }, + }, Position{1, 1}, + }, + queryTestNode{ + map[string]interface{}{ + "a": int64(1), + "b": int64(2), + }, Position{1, 1}, + }, + queryTestNode{ + int64(1), Position{2, 1}, + }, + queryTestNode{ + int64(2), Position{3, 1}, + }, + queryTestNode{ + map[string]interface{}{ + "foo": map[string]interface{}{ + "a": int64(3), + "b": int64(4), + }, + }, Position{4, 1}, + }, + queryTestNode{ + map[string]interface{}{ + "a": int64(3), + "b": int64(4), + }, Position{4, 1}, + }, + queryTestNode{ + int64(3), Position{5, 1}, + }, + queryTestNode{ + int64(4), Position{6, 1}, + }, + queryTestNode{ + map[string]interface{}{ + "foo": map[string]interface{}{ + "a": int64(5), + "b": int64(6), + }, + }, Position{7, 1}, + }, + queryTestNode{ + map[string]interface{}{ + "a": int64(5), + "b": int64(6), + }, Position{7, 1}, + }, + queryTestNode{ + int64(5), Position{8, 1}, + }, + queryTestNode{ + int64(6), Position{9, 1}, + }, + }) +} + +func TestQueryRecursionUnionSimple(t *testing.T) { + assertQueryPositions(t, + "[foo.bar]\na=1\nb=2\n[baz.foo]\na=3\nb=4\n[gorf.foo]\na=5\nb=6", + "$..['foo','bar']", + []interface{}{ + queryTestNode{ + map[string]interface{}{ + "bar": map[string]interface{}{ + "a": int64(1), + "b": int64(2), + }, + }, Position{1, 1}, + }, + queryTestNode{ + map[string]interface{}{ + "a": int64(3), + "b": int64(4), + }, Position{4, 1}, + }, + queryTestNode{ + map[string]interface{}{ + "a": int64(1), + "b": int64(2), + }, Position{1, 1}, + }, + queryTestNode{ + map[string]interface{}{ + "a": int64(5), + "b": int64(6), + }, Position{7, 1}, + }, + }) +} + +func TestQueryFilterFn(t *testing.T) { + buff, err := ioutil.ReadFile("example.toml") + if err != nil { + t.Error(err) + return + } + + assertQueryPositions(t, string(buff), + "$..[?(int)]", + []interface{}{ + queryTestNode{ + int64(8001), Position{13, 1}, + }, + queryTestNode{ + int64(8001), Position{13, 1}, + }, + queryTestNode{ + int64(8002), Position{13, 1}, + }, + queryTestNode{ + int64(5000), Position{14, 1}, + }, + }) + + assertQueryPositions(t, string(buff), + "$..[?(string)]", + []interface{}{ + queryTestNode{ + "TOML Example", Position{3, 1}, + }, + queryTestNode{ + "Tom Preston-Werner", Position{6, 1}, + }, + queryTestNode{ + "GitHub", Position{7, 1}, + }, + queryTestNode{ + "GitHub Cofounder & CEO\nLikes tater tots and beer.", + Position{8, 1}, + }, + queryTestNode{ + "192.168.1.1", Position{12, 1}, + }, + queryTestNode{ + "10.0.0.1", Position{21, 3}, + }, + queryTestNode{ + "eqdc10", Position{22, 3}, + }, + queryTestNode{ + "10.0.0.2", Position{25, 3}, + }, + queryTestNode{ + "eqdc10", Position{26, 3}, + }, + }) + + assertQueryPositions(t, string(buff), + "$..[?(float)]", + []interface{}{ + // no float values in document + }) + + tv, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z") + assertQueryPositions(t, string(buff), + "$..[?(tree)]", + []interface{}{ + queryTestNode{ + map[string]interface{}{ + "name": "Tom Preston-Werner", + "organization": "GitHub", + "bio": "GitHub Cofounder & CEO\nLikes tater tots and beer.", + "dob": tv, + }, Position{5, 1}, + }, + queryTestNode{ + map[string]interface{}{ + "server": "192.168.1.1", + "ports": []interface{}{int64(8001), int64(8001), int64(8002)}, + "connection_max": int64(5000), + "enabled": true, + }, Position{11, 1}, + }, + queryTestNode{ + map[string]interface{}{ + "alpha": map[string]interface{}{ + "ip": "10.0.0.1", + "dc": "eqdc10", + }, + "beta": map[string]interface{}{ + "ip": "10.0.0.2", + "dc": "eqdc10", + }, + }, Position{17, 1}, + }, + queryTestNode{ + map[string]interface{}{ + "ip": "10.0.0.1", + "dc": "eqdc10", + }, Position{20, 3}, + }, + queryTestNode{ + map[string]interface{}{ + "ip": "10.0.0.2", + "dc": "eqdc10", + }, Position{24, 3}, + }, + queryTestNode{ + map[string]interface{}{ + "data": []interface{}{ + []interface{}{"gamma", "delta"}, + []interface{}{int64(1), int64(2)}, + }, + }, Position{28, 1}, + }, + }) + + assertQueryPositions(t, string(buff), + "$..[?(time)]", + []interface{}{ + queryTestNode{ + tv, Position{9, 1}, + }, + }) + + assertQueryPositions(t, string(buff), + "$..[?(bool)]", + []interface{}{ + queryTestNode{ + true, Position{15, 1}, + }, + }) +} diff --git a/vendor/github.com/pelletier/go-toml/test.sh b/vendor/github.com/pelletier/go-toml/test.sh new file mode 100755 index 0000000000..436d2fb6ca --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/test.sh @@ -0,0 +1,82 @@ +#!/bin/bash +# fail out of the script if anything here fails +set -e + +# set the path to the present working directory +export GOPATH=`pwd` + +function git_clone() { + path=$1 + branch=$2 + version=$3 + if [ ! -d "src/$path" ]; then + mkdir -p src/$path + git clone https://$path.git src/$path + fi + pushd src/$path + git checkout "$branch" + git reset --hard "$version" + popd +} + +# Run go vet +go vet ./... + +go get github.com/pelletier/go-buffruneio +go get github.com/davecgh/go-spew/spew + +# get code for BurntSushi TOML validation +# pinning all to 'HEAD' for version 0.3.x work (TODO: pin to commit hash when tests stabilize) +git_clone github.com/BurntSushi/toml master HEAD +git_clone github.com/BurntSushi/toml-test master HEAD #was: 0.2.0 HEAD + +# build the BurntSushi test application +go build -o toml-test github.com/BurntSushi/toml-test + +# vendorize the current lib for testing +# NOTE: this basically mocks an install without having to go back out to github for code +mkdir -p src/github.com/pelletier/go-toml/cmd +cp *.go *.toml src/github.com/pelletier/go-toml +cp -R cmd/* src/github.com/pelletier/go-toml/cmd +go build -o test_program_bin src/github.com/pelletier/go-toml/cmd/test_program.go + +# Run basic unit tests +go test github.com/pelletier/go-toml -v -covermode=count -coverprofile=coverage.out +go test github.com/pelletier/go-toml/cmd/tomljson + +# run the entire BurntSushi test suite +if [[ $# -eq 0 ]] ; then + echo "Running all BurntSushi tests" + ./toml-test ./test_program_bin | tee test_out +else + # run a specific test + test=$1 + test_path='src/github.com/BurntSushi/toml-test/tests' + valid_test="$test_path/valid/$test" + invalid_test="$test_path/invalid/$test" + + if [ -e "$valid_test.toml" ]; then + echo "Valid Test TOML for $test:" + echo "====" + cat "$valid_test.toml" + + echo "Valid Test JSON for $test:" + echo "====" + cat "$valid_test.json" + + echo "Go-TOML Output for $test:" + echo "====" + cat "$valid_test.toml" | ./test_program_bin + fi + + if [ -e "$invalid_test.toml" ]; then + echo "Invalid Test TOML for $test:" + echo "====" + cat "$invalid_test.toml" + + echo "Go-TOML Output for $test:" + echo "====" + echo "go-toml Output:" + cat "$invalid_test.toml" | ./test_program_bin + fi +fi diff --git a/vendor/github.com/pelletier/go-toml/token.go b/vendor/github.com/pelletier/go-toml/token.go new file mode 100644 index 0000000000..5581fe0bcc --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/token.go @@ -0,0 +1,140 @@ +package toml + +import ( + "fmt" + "strconv" + "unicode" +) + +// Define tokens +type tokenType int + +const ( + eof = -(iota + 1) +) + +const ( + tokenError tokenType = iota + tokenEOF + tokenComment + tokenKey + tokenString + tokenInteger + tokenTrue + tokenFalse + tokenFloat + tokenEqual + tokenLeftBracket + tokenRightBracket + tokenLeftCurlyBrace + tokenRightCurlyBrace + tokenLeftParen + tokenRightParen + tokenDoubleLeftBracket + tokenDoubleRightBracket + tokenDate + tokenKeyGroup + tokenKeyGroupArray + tokenComma + tokenColon + tokenDollar + tokenStar + tokenQuestion + tokenDot + tokenDotDot + tokenEOL +) + +var tokenTypeNames = []string{ + "Error", + "EOF", + "Comment", + "Key", + "String", + "Integer", + "True", + "False", + "Float", + "=", + "[", + "]", + "{", + "}", + "(", + ")", + "]]", + "[[", + "Date", + "KeyGroup", + "KeyGroupArray", + ",", + ":", + "$", + "*", + "?", + ".", + "..", + "EOL", +} + +type token struct { + Position + typ tokenType + val string +} + +func (tt tokenType) String() string { + idx := int(tt) + if idx < len(tokenTypeNames) { + return tokenTypeNames[idx] + } + return "Unknown" +} + +func (t token) Int() int { + if result, err := strconv.Atoi(t.val); err != nil { + panic(err) + } else { + return result + } +} + +func (t token) String() string { + switch t.typ { + case tokenEOF: + return "EOF" + case tokenError: + return t.val + } + + return fmt.Sprintf("%q", t.val) +} + +func isSpace(r rune) bool { + return r == ' ' || r == '\t' +} + +func isAlphanumeric(r rune) bool { + return unicode.IsLetter(r) || r == '_' +} + +func isKeyChar(r rune) bool { + // Keys start with the first character that isn't whitespace or [ and end + // with the last non-whitespace character before the equals sign. Keys + // cannot contain a # character." + return !(r == '\r' || r == '\n' || r == eof || r == '=') +} + +func isKeyStartChar(r rune) bool { + return !(isSpace(r) || r == '\r' || r == '\n' || r == eof || r == '[') +} + +func isDigit(r rune) bool { + return unicode.IsNumber(r) +} + +func isHexDigit(r rune) bool { + return isDigit(r) || + (r >= 'a' && r <= 'f') || + (r >= 'A' && r <= 'F') +} diff --git a/vendor/github.com/pelletier/go-toml/token_test.go b/vendor/github.com/pelletier/go-toml/token_test.go new file mode 100644 index 0000000000..20b560d510 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/token_test.go @@ -0,0 +1,67 @@ +package toml + +import "testing" + +func TestTokenStringer(t *testing.T) { + var tests = []struct { + tt tokenType + expect string + }{ + {tokenError, "Error"}, + {tokenEOF, "EOF"}, + {tokenComment, "Comment"}, + {tokenKey, "Key"}, + {tokenString, "String"}, + {tokenInteger, "Integer"}, + {tokenTrue, "True"}, + {tokenFalse, "False"}, + {tokenFloat, "Float"}, + {tokenEqual, "="}, + {tokenLeftBracket, "["}, + {tokenRightBracket, "]"}, + {tokenLeftCurlyBrace, "{"}, + {tokenRightCurlyBrace, "}"}, + {tokenLeftParen, "("}, + {tokenRightParen, ")"}, + {tokenDoubleLeftBracket, "]]"}, + {tokenDoubleRightBracket, "[["}, + {tokenDate, "Date"}, + {tokenKeyGroup, "KeyGroup"}, + {tokenKeyGroupArray, "KeyGroupArray"}, + {tokenComma, ","}, + {tokenColon, ":"}, + {tokenDollar, "$"}, + {tokenStar, "*"}, + {tokenQuestion, "?"}, + {tokenDot, "."}, + {tokenDotDot, ".."}, + {tokenEOL, "EOL"}, + {tokenEOL + 1, "Unknown"}, + } + + for i, test := range tests { + got := test.tt.String() + if got != test.expect { + t.Errorf("[%d] invalid string of token type; got %q, expected %q", i, got, test.expect) + } + } +} + +func TestTokenString(t *testing.T) { + var tests = []struct { + tok token + expect string + }{ + {token{Position{1, 1}, tokenEOF, ""}, "EOF"}, + {token{Position{1, 1}, tokenError, "Δt"}, "Δt"}, + {token{Position{1, 1}, tokenString, "bar"}, `"bar"`}, + {token{Position{1, 1}, tokenString, "123456789012345"}, `"123456789012345"`}, + } + + for i, test := range tests { + got := test.tok.String() + if got != test.expect { + t.Errorf("[%d] invalid of string token; got %q, expected %q", i, got, test.expect) + } + } +} diff --git a/vendor/github.com/pelletier/go-toml/toml.go b/vendor/github.com/pelletier/go-toml/toml.go new file mode 100644 index 0000000000..1ba56a1c14 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/toml.go @@ -0,0 +1,284 @@ +package toml + +import ( + "errors" + "fmt" + "io" + "os" + "runtime" + "strings" +) + +type tomlValue struct { + value interface{} // string, int64, uint64, float64, bool, time.Time, [] of any of this list + position Position +} + +// TomlTree is the result of the parsing of a TOML file. +type TomlTree struct { + values map[string]interface{} // string -> *tomlValue, *TomlTree, []*TomlTree + position Position +} + +func newTomlTree() *TomlTree { + return &TomlTree{ + values: make(map[string]interface{}), + position: Position{}, + } +} + +// TreeFromMap initializes a new TomlTree object using the given map. +func TreeFromMap(m map[string]interface{}) (*TomlTree, error) { + result, err := toTree(m) + if err != nil { + return nil, err + } + return result.(*TomlTree), nil +} + +// Has returns a boolean indicating if the given key exists. +func (t *TomlTree) Has(key string) bool { + if key == "" { + return false + } + return t.HasPath(strings.Split(key, ".")) +} + +// HasPath returns true if the given path of keys exists, false otherwise. +func (t *TomlTree) HasPath(keys []string) bool { + return t.GetPath(keys) != nil +} + +// Keys returns the keys of the toplevel tree. +// Warning: this is a costly operation. +func (t *TomlTree) Keys() []string { + var keys []string + for k := range t.values { + keys = append(keys, k) + } + return keys +} + +// Get the value at key in the TomlTree. +// Key is a dot-separated path (e.g. a.b.c). +// Returns nil if the path does not exist in the tree. +// If keys is of length zero, the current tree is returned. +func (t *TomlTree) Get(key string) interface{} { + if key == "" { + return t + } + comps, err := parseKey(key) + if err != nil { + return nil + } + return t.GetPath(comps) +} + +// GetPath returns the element in the tree indicated by 'keys'. +// If keys is of length zero, the current tree is returned. +func (t *TomlTree) GetPath(keys []string) interface{} { + if len(keys) == 0 { + return t + } + subtree := t + for _, intermediateKey := range keys[:len(keys)-1] { + value, exists := subtree.values[intermediateKey] + if !exists { + return nil + } + switch node := value.(type) { + case *TomlTree: + subtree = node + case []*TomlTree: + // go to most recent element + if len(node) == 0 { + return nil + } + subtree = node[len(node)-1] + default: + return nil // cannot navigate through other node types + } + } + // branch based on final node type + switch node := subtree.values[keys[len(keys)-1]].(type) { + case *tomlValue: + return node.value + default: + return node + } +} + +// GetPosition returns the position of the given key. +func (t *TomlTree) GetPosition(key string) Position { + if key == "" { + return t.position + } + return t.GetPositionPath(strings.Split(key, ".")) +} + +// GetPositionPath returns the element in the tree indicated by 'keys'. +// If keys is of length zero, the current tree is returned. +func (t *TomlTree) GetPositionPath(keys []string) Position { + if len(keys) == 0 { + return t.position + } + subtree := t + for _, intermediateKey := range keys[:len(keys)-1] { + value, exists := subtree.values[intermediateKey] + if !exists { + return Position{0, 0} + } + switch node := value.(type) { + case *TomlTree: + subtree = node + case []*TomlTree: + // go to most recent element + if len(node) == 0 { + return Position{0, 0} + } + subtree = node[len(node)-1] + default: + return Position{0, 0} + } + } + // branch based on final node type + switch node := subtree.values[keys[len(keys)-1]].(type) { + case *tomlValue: + return node.position + case *TomlTree: + return node.position + case []*TomlTree: + // go to most recent element + if len(node) == 0 { + return Position{0, 0} + } + return node[len(node)-1].position + default: + return Position{0, 0} + } +} + +// GetDefault works like Get but with a default value +func (t *TomlTree) GetDefault(key string, def interface{}) interface{} { + val := t.Get(key) + if val == nil { + return def + } + return val +} + +// Set an element in the tree. +// Key is a dot-separated path (e.g. a.b.c). +// Creates all necessary intermediates trees, if needed. +func (t *TomlTree) Set(key string, value interface{}) { + t.SetPath(strings.Split(key, "."), value) +} + +// SetPath sets an element in the tree. +// Keys is an array of path elements (e.g. {"a","b","c"}). +// Creates all necessary intermediates trees, if needed. +func (t *TomlTree) SetPath(keys []string, value interface{}) { + subtree := t + for _, intermediateKey := range keys[:len(keys)-1] { + nextTree, exists := subtree.values[intermediateKey] + if !exists { + nextTree = newTomlTree() + subtree.values[intermediateKey] = nextTree // add new element here + } + switch node := nextTree.(type) { + case *TomlTree: + subtree = node + case []*TomlTree: + // go to most recent element + if len(node) == 0 { + // create element if it does not exist + subtree.values[intermediateKey] = append(node, newTomlTree()) + } + subtree = node[len(node)-1] + } + } + + var toInsert interface{} + + switch value.(type) { + case *TomlTree: + toInsert = value + case []*TomlTree: + toInsert = value + case *tomlValue: + toInsert = value + default: + toInsert = &tomlValue{value: value} + } + + subtree.values[keys[len(keys)-1]] = toInsert +} + +// createSubTree takes a tree and a key and create the necessary intermediate +// subtrees to create a subtree at that point. In-place. +// +// e.g. passing a.b.c will create (assuming tree is empty) tree[a], tree[a][b] +// and tree[a][b][c] +// +// Returns nil on success, error object on failure +func (t *TomlTree) createSubTree(keys []string, pos Position) error { + subtree := t + for _, intermediateKey := range keys { + nextTree, exists := subtree.values[intermediateKey] + if !exists { + tree := newTomlTree() + tree.position = pos + subtree.values[intermediateKey] = tree + nextTree = tree + } + + switch node := nextTree.(type) { + case []*TomlTree: + subtree = node[len(node)-1] + case *TomlTree: + subtree = node + default: + return fmt.Errorf("unknown type for path %s (%s): %T (%#v)", + strings.Join(keys, "."), intermediateKey, nextTree, nextTree) + } + } + return nil +} + +// Query compiles and executes a query on a tree and returns the query result. +func (t *TomlTree) Query(query string) (*QueryResult, error) { + q, err := CompileQuery(query) + if err != nil { + return nil, err + } + return q.Execute(t), nil +} + +// LoadReader creates a TomlTree from any io.Reader. +func LoadReader(reader io.Reader) (tree *TomlTree, err error) { + defer func() { + if r := recover(); r != nil { + if _, ok := r.(runtime.Error); ok { + panic(r) + } + err = errors.New(r.(string)) + } + }() + tree = parseToml(lexToml(reader)) + return +} + +// Load creates a TomlTree from a string. +func Load(content string) (tree *TomlTree, err error) { + return LoadReader(strings.NewReader(content)) +} + +// LoadFile creates a TomlTree from a file. +func LoadFile(path string) (tree *TomlTree, err error) { + file, err := os.Open(path) + if err != nil { + return nil, err + } + defer file.Close() + return LoadReader(file) +} diff --git a/vendor/github.com/pelletier/go-toml/toml_test.go b/vendor/github.com/pelletier/go-toml/toml_test.go new file mode 100644 index 0000000000..7c7f9eff95 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/toml_test.go @@ -0,0 +1,131 @@ +// Testing support for go-toml + +package toml + +import ( + "testing" +) + +func TestTomlHas(t *testing.T) { + tree, _ := Load(` + [test] + key = "value" + `) + + if !tree.Has("test.key") { + t.Errorf("Has - expected test.key to exists") + } + + if tree.Has("") { + t.Errorf("Should return false if the key is not provided") + } +} + +func TestTomlGet(t *testing.T) { + tree, _ := Load(` + [test] + key = "value" + `) + + if tree.Get("") != tree { + t.Errorf("Get should return the tree itself when given an empty path") + } + + if tree.Get("test.key") != "value" { + t.Errorf("Get should return the value") + } + if tree.Get(`\`) != nil { + t.Errorf("should return nil when the key is malformed") + } +} + +func TestTomlGetDefault(t *testing.T) { + tree, _ := Load(` + [test] + key = "value" + `) + + if tree.GetDefault("", "hello") != tree { + t.Error("GetDefault should return the tree itself when given an empty path") + } + + if tree.GetDefault("test.key", "hello") != "value" { + t.Error("Get should return the value") + } + + if tree.GetDefault("whatever", "hello") != "hello" { + t.Error("GetDefault should return the default value if the key does not exist") + } +} + +func TestTomlHasPath(t *testing.T) { + tree, _ := Load(` + [test] + key = "value" + `) + + if !tree.HasPath([]string{"test", "key"}) { + t.Errorf("HasPath - expected test.key to exists") + } +} + +func TestTomlGetPath(t *testing.T) { + node := newTomlTree() + //TODO: set other node data + + for idx, item := range []struct { + Path []string + Expected *TomlTree + }{ + { // empty path test + []string{}, + node, + }, + } { + result := node.GetPath(item.Path) + if result != item.Expected { + t.Errorf("GetPath[%d] %v - expected %v, got %v instead.", idx, item.Path, item.Expected, result) + } + } + + tree, _ := Load("[foo.bar]\na=1\nb=2\n[baz.foo]\na=3\nb=4\n[gorf.foo]\na=5\nb=6") + if tree.GetPath([]string{"whatever"}) != nil { + t.Error("GetPath should return nil when the key does not exist") + } +} + +func TestTomlQuery(t *testing.T) { + tree, err := Load("[foo.bar]\na=1\nb=2\n[baz.foo]\na=3\nb=4\n[gorf.foo]\na=5\nb=6") + if err != nil { + t.Error(err) + return + } + result, err := tree.Query("$.foo.bar") + if err != nil { + t.Error(err) + return + } + values := result.Values() + if len(values) != 1 { + t.Errorf("Expected resultset of 1, got %d instead: %v", len(values), values) + } + + if tt, ok := values[0].(*TomlTree); !ok { + t.Errorf("Expected type of TomlTree: %T", values[0]) + } else if tt.Get("a") != int64(1) { + t.Errorf("Expected 'a' with a value 1: %v", tt.Get("a")) + } else if tt.Get("b") != int64(2) { + t.Errorf("Expected 'b' with a value 2: %v", tt.Get("b")) + } +} + +func TestTomlFromMap(t *testing.T) { + simpleMap := map[string]interface{}{"hello": 42} + tree, err := TreeFromMap(simpleMap) + if err != nil { + t.Fatal("unexpected error:", err) + } + if tree.Get("hello") != int64(42) { + t.Fatal("hello should be 42, not", tree.Get("hello")) + } +} diff --git a/vendor/github.com/pelletier/go-toml/tomltree_create.go b/vendor/github.com/pelletier/go-toml/tomltree_create.go new file mode 100644 index 0000000000..d447755a62 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/tomltree_create.go @@ -0,0 +1,129 @@ +package toml + +import ( + "fmt" + "reflect" + "time" +) + +// supported values: +// string, bool, int64, uint64, float64, time.Time, int, int8, int16, int32, uint, uint8, uint16, uint32, float32 + +var kindToTypeMapping = map[reflect.Kind]reflect.Type{ + reflect.Bool: reflect.TypeOf(true), + reflect.String: reflect.TypeOf(""), + reflect.Float32: reflect.TypeOf(float64(1)), + reflect.Float64: reflect.TypeOf(float64(1)), + reflect.Int: reflect.TypeOf(int64(1)), + reflect.Int8: reflect.TypeOf(int64(1)), + reflect.Int16: reflect.TypeOf(int64(1)), + reflect.Int32: reflect.TypeOf(int64(1)), + reflect.Int64: reflect.TypeOf(int64(1)), + reflect.Uint: reflect.TypeOf(uint64(1)), + reflect.Uint8: reflect.TypeOf(uint64(1)), + reflect.Uint16: reflect.TypeOf(uint64(1)), + reflect.Uint32: reflect.TypeOf(uint64(1)), + reflect.Uint64: reflect.TypeOf(uint64(1)), +} + +func simpleValueCoercion(object interface{}) (interface{}, error) { + switch original := object.(type) { + case string, bool, int64, uint64, float64, time.Time: + return original, nil + case int: + return int64(original), nil + case int8: + return int64(original), nil + case int16: + return int64(original), nil + case int32: + return int64(original), nil + case uint: + return uint64(original), nil + case uint8: + return uint64(original), nil + case uint16: + return uint64(original), nil + case uint32: + return uint64(original), nil + case float32: + return float64(original), nil + default: + return nil, fmt.Errorf("cannot convert type %T to TomlTree", object) + } +} + +func sliceToTree(object interface{}) (interface{}, error) { + // arrays are a bit tricky, since they can represent either a + // collection of simple values, which is represented by one + // *tomlValue, or an array of tables, which is represented by an + // array of *TomlTree. + + // holding the assumption that this function is called from toTree only when value.Kind() is Array or Slice + value := reflect.ValueOf(object) + insideType := value.Type().Elem() + length := value.Len() + if insideType.Kind() == reflect.Map { + // this is considered as an array of tables + tablesArray := make([]*TomlTree, 0, length) + for i := 0; i < length; i++ { + table := value.Index(i) + tree, err := toTree(table.Interface()) + if err != nil { + return nil, err + } + tablesArray = append(tablesArray, tree.(*TomlTree)) + } + return tablesArray, nil + } + + sliceType := kindToTypeMapping[insideType.Kind()] + if sliceType == nil { + sliceType = insideType + } + + arrayValue := reflect.MakeSlice(reflect.SliceOf(sliceType), 0, length) + + for i := 0; i < length; i++ { + val := value.Index(i).Interface() + simpleValue, err := simpleValueCoercion(val) + if err != nil { + return nil, err + } + arrayValue = reflect.Append(arrayValue, reflect.ValueOf(simpleValue)) + } + return &tomlValue{arrayValue.Interface(), Position{}}, nil +} + +func toTree(object interface{}) (interface{}, error) { + value := reflect.ValueOf(object) + + if value.Kind() == reflect.Map { + values := map[string]interface{}{} + keys := value.MapKeys() + for _, key := range keys { + k, ok := key.Interface().(string) + if !ok { + return nil, fmt.Errorf("map key needs to be a string, not %T", key.Interface()) + } + + v := value.MapIndex(key) + newValue, err := toTree(v.Interface()) + if err != nil { + return nil, err + } + values[k] = newValue + } + return &TomlTree{values, Position{}}, nil + } + + if value.Kind() == reflect.Array || value.Kind() == reflect.Slice { + return sliceToTree(object) + } + + simpleValue, err := simpleValueCoercion(object) + if err != nil { + return nil, err + } + return &tomlValue{simpleValue, Position{}}, nil +} diff --git a/vendor/github.com/pelletier/go-toml/tomltree_create_test.go b/vendor/github.com/pelletier/go-toml/tomltree_create_test.go new file mode 100644 index 0000000000..8523f9ee5c --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/tomltree_create_test.go @@ -0,0 +1,95 @@ +package toml + +import ( + "testing" + "time" +) + +func validate(t *testing.T, path string, object interface{}) { + switch o := object.(type) { + case *TomlTree: + for key, tree := range o.values { + validate(t, path+"."+key, tree) + } + case []*TomlTree: + for index, tree := range o { + validate(t, path+"."+string(index), tree) + } + case *tomlValue: + switch o.value.(type) { + case int64, uint64, bool, string, float64, time.Time, + []int64, []uint64, []bool, []string, []float64, []time.Time: + return // ok + default: + t.Fatalf("tomlValue at key %s containing incorrect type %T", path, o.value) + } + default: + t.Fatalf("value at key %s is of incorrect type %T", path, object) + } + t.Log("validation ok", path) +} + +func validateTree(t *testing.T, tree *TomlTree) { + validate(t, "", tree) +} + +func TestTomlTreeCreateToTree(t *testing.T) { + data := map[string]interface{}{ + "a_string": "bar", + "an_int": 42, + "time": time.Now(), + "int8": int8(2), + "int16": int16(2), + "int32": int32(2), + "uint8": uint8(2), + "uint16": uint16(2), + "uint32": uint32(2), + "float32": float32(2), + "a_bool": false, + "nested": map[string]interface{}{ + "foo": "bar", + }, + "array": []string{"a", "b", "c"}, + "array_uint": []uint{uint(1), uint(2)}, + "array_table": []map[string]interface{}{map[string]interface{}{"sub_map": 52}}, + "array_times": []time.Time{time.Now(), time.Now()}, + "map_times": map[string]time.Time{"now": time.Now()}, + } + tree, err := TreeFromMap(data) + if err != nil { + t.Fatal("unexpected error:", err) + } + validateTree(t, tree) +} + +func TestTomlTreeCreateToTreeInvalidLeafType(t *testing.T) { + _, err := TreeFromMap(map[string]interface{}{"foo": t}) + expected := "cannot convert type *testing.T to TomlTree" + if err.Error() != expected { + t.Fatalf("expected error %s, got %s", expected, err.Error()) + } +} + +func TestTomlTreeCreateToTreeInvalidMapKeyType(t *testing.T) { + _, err := TreeFromMap(map[string]interface{}{"foo": map[int]interface{}{2: 1}}) + expected := "map key needs to be a string, not int" + if err.Error() != expected { + t.Fatalf("expected error %s, got %s", expected, err.Error()) + } +} + +func TestTomlTreeCreateToTreeInvalidArrayMemberType(t *testing.T) { + _, err := TreeFromMap(map[string]interface{}{"foo": []*testing.T{t}}) + expected := "cannot convert type *testing.T to TomlTree" + if err.Error() != expected { + t.Fatalf("expected error %s, got %s", expected, err.Error()) + } +} + +func TestTomlTreeCreateToTreeInvalidTableGroupType(t *testing.T) { + _, err := TreeFromMap(map[string]interface{}{"foo": []map[string]interface{}{map[string]interface{}{"hello": t}}}) + expected := "cannot convert type *testing.T to TomlTree" + if err.Error() != expected { + t.Fatalf("expected error %s, got %s", expected, err.Error()) + } +} diff --git a/vendor/github.com/pelletier/go-toml/tomltree_write.go b/vendor/github.com/pelletier/go-toml/tomltree_write.go new file mode 100644 index 0000000000..b50b549720 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/tomltree_write.go @@ -0,0 +1,209 @@ +package toml + +import ( + "bytes" + "fmt" + "io" + "sort" + "strconv" + "strings" + "time" +) + +// encodes a string to a TOML-compliant string value +func encodeTomlString(value string) string { + result := "" + for _, rr := range value { + switch rr { + case '\b': + result += "\\b" + case '\t': + result += "\\t" + case '\n': + result += "\\n" + case '\f': + result += "\\f" + case '\r': + result += "\\r" + case '"': + result += "\\\"" + case '\\': + result += "\\\\" + default: + intRr := uint16(rr) + if intRr < 0x001F { + result += fmt.Sprintf("\\u%0.4X", intRr) + } else { + result += string(rr) + } + } + } + return result +} + +func tomlValueStringRepresentation(v interface{}) (string, error) { + switch value := v.(type) { + case uint64: + return strconv.FormatUint(value, 10), nil + case int64: + return strconv.FormatInt(value, 10), nil + case float64: + return strconv.FormatFloat(value, 'f', -1, 32), nil + case string: + return "\"" + encodeTomlString(value) + "\"", nil + case bool: + if value { + return "true", nil + } + return "false", nil + case time.Time: + return value.Format(time.RFC3339), nil + case nil: + return "", nil + case []interface{}: + values := []string{} + for _, item := range value { + itemRepr, err := tomlValueStringRepresentation(item) + if err != nil { + return "", err + } + values = append(values, itemRepr) + } + return "[" + strings.Join(values, ",") + "]", nil + default: + return "", fmt.Errorf("unsupported value type %T: %v", value, value) + } +} + +func (t *TomlTree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (int64, error) { + simpleValuesKeys := make([]string, 0) + complexValuesKeys := make([]string, 0) + + for k := range t.values { + v := t.values[k] + switch v.(type) { + case *TomlTree, []*TomlTree: + complexValuesKeys = append(complexValuesKeys, k) + default: + simpleValuesKeys = append(simpleValuesKeys, k) + } + } + + sort.Strings(simpleValuesKeys) + sort.Strings(complexValuesKeys) + + for _, k := range simpleValuesKeys { + v, ok := t.values[k].(*tomlValue) + if !ok { + return bytesCount, fmt.Errorf("invalid value type at %s: %T", k, t.values[k]) + } + + repr, err := tomlValueStringRepresentation(v.value) + if err != nil { + return bytesCount, err + } + + kvRepr := fmt.Sprintf("%s%s = %s\n", indent, k, repr) + writtenBytesCount, err := w.Write([]byte(kvRepr)) + bytesCount += int64(writtenBytesCount) + if err != nil { + return bytesCount, err + } + } + + for _, k := range complexValuesKeys { + v := t.values[k] + + combinedKey := k + if keyspace != "" { + combinedKey = keyspace + "." + combinedKey + } + + switch node := v.(type) { + // node has to be of those two types given how keys are sorted above + case *TomlTree: + tableName := fmt.Sprintf("\n%s[%s]\n", indent, combinedKey) + writtenBytesCount, err := w.Write([]byte(tableName)) + bytesCount += int64(writtenBytesCount) + if err != nil { + return bytesCount, err + } + bytesCount, err = node.writeTo(w, indent+" ", combinedKey, bytesCount) + if err != nil { + return bytesCount, err + } + case []*TomlTree: + for _, subTree := range node { + if len(subTree.values) > 0 { + tableArrayName := fmt.Sprintf("\n%s[[%s]]\n", indent, combinedKey) + writtenBytesCount, err := w.Write([]byte(tableArrayName)) + bytesCount += int64(writtenBytesCount) + if err != nil { + return bytesCount, err + } + + bytesCount, err = subTree.writeTo(w, indent+" ", combinedKey, bytesCount) + if err != nil { + return bytesCount, err + } + } + } + } + } + + return bytesCount, nil +} + +// WriteTo encode the TomlTree as Toml and writes it to the writer w. +// Returns the number of bytes written in case of success, or an error if anything happened. +func (t *TomlTree) WriteTo(w io.Writer) (int64, error) { + return t.writeTo(w, "", "", 0) +} + +// ToTomlString generates a human-readable representation of the current tree. +// Output spans multiple lines, and is suitable for ingest by a TOML parser. +// If the conversion cannot be performed, ToString returns a non-nil error. +func (t *TomlTree) ToTomlString() (string, error) { + var buf bytes.Buffer + _, err := t.WriteTo(&buf) + if err != nil { + return "", err + } + return buf.String(), nil +} + +// String generates a human-readable representation of the current tree. +// Alias of ToString. Present to implement the fmt.Stringer interface. +func (t *TomlTree) String() string { + result, _ := t.ToTomlString() + return result +} + +// ToMap recursively generates a representation of the tree using Go built-in structures. +// The following types are used: +// * uint64 +// * int64 +// * bool +// * string +// * time.Time +// * map[string]interface{} (where interface{} is any of this list) +// * []interface{} (where interface{} is any of this list) +func (t *TomlTree) ToMap() map[string]interface{} { + result := map[string]interface{}{} + + for k, v := range t.values { + switch node := v.(type) { + case []*TomlTree: + var array []interface{} + for _, item := range node { + array = append(array, item.ToMap()) + } + result[k] = array + case *TomlTree: + result[k] = node.ToMap() + case *tomlValue: + result[k] = node.value + } + } + return result +} diff --git a/vendor/github.com/pelletier/go-toml/tomltree_write_test.go b/vendor/github.com/pelletier/go-toml/tomltree_write_test.go new file mode 100644 index 0000000000..6344b1c014 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/tomltree_write_test.go @@ -0,0 +1,284 @@ +package toml + +import ( + "bytes" + "errors" + "fmt" + "reflect" + "strings" + "testing" + "time" +) + +type failingWriter struct { + failAt int + written int + buffer bytes.Buffer +} + +func (f failingWriter) Write(p []byte) (n int, err error) { + count := len(p) + toWrite := f.failAt - count + f.written + if toWrite < 0 { + toWrite = 0 + } + if toWrite > count { + f.written += count + f.buffer.WriteString(string(p)) + return count, nil + } + + f.buffer.WriteString(string(p[:toWrite])) + f.written = f.failAt + return f.written, fmt.Errorf("failingWriter failed after writting %d bytes", f.written) +} + +func assertErrorString(t *testing.T, expected string, err error) { + expectedErr := errors.New(expected) + if err.Error() != expectedErr.Error() { + t.Errorf("expecting error %s, but got %s instead", expected, err) + } +} + +func TestTomlTreeWriteToTomlString(t *testing.T) { + toml, err := Load(`name = { first = "Tom", last = "Preston-Werner" } +points = { x = 1, y = 2 }`) + + if err != nil { + t.Fatal("Unexpected error:", err) + } + + tomlString, _ := toml.ToTomlString() + reparsedTree, err := Load(tomlString) + + assertTree(t, reparsedTree, err, map[string]interface{}{ + "name": map[string]interface{}{ + "first": "Tom", + "last": "Preston-Werner", + }, + "points": map[string]interface{}{ + "x": int64(1), + "y": int64(2), + }, + }) +} + +func TestTomlTreeWriteToTomlStringSimple(t *testing.T) { + tree, err := Load("[foo]\n\n[[foo.bar]]\na = 42\n\n[[foo.bar]]\na = 69\n") + if err != nil { + t.Errorf("Test failed to parse: %v", err) + return + } + result, err := tree.ToTomlString() + if err != nil { + t.Errorf("Unexpected error: %s", err) + } + expected := "\n[foo]\n\n [[foo.bar]]\n a = 42\n\n [[foo.bar]]\n a = 69\n" + if result != expected { + t.Errorf("Expected got '%s', expected '%s'", result, expected) + } +} + +func TestTomlTreeWriteToTomlStringKeysOrders(t *testing.T) { + for i := 0; i < 100; i++ { + tree, _ := Load(` + foobar = true + bar = "baz" + foo = 1 + [qux] + foo = 1 + bar = "baz2"`) + + stringRepr, _ := tree.ToTomlString() + + t.Log("Intermediate string representation:") + t.Log(stringRepr) + + r := strings.NewReader(stringRepr) + toml, err := LoadReader(r) + + if err != nil { + t.Fatal("Unexpected error:", err) + } + + assertTree(t, toml, err, map[string]interface{}{ + "foobar": true, + "bar": "baz", + "foo": 1, + "qux": map[string]interface{}{ + "foo": 1, + "bar": "baz2", + }, + }) + } +} + +func testMaps(t *testing.T, actual, expected map[string]interface{}) { + if !reflect.DeepEqual(actual, expected) { + t.Fatal("trees aren't equal.\n", "Expected:\n", expected, "\nActual:\n", actual) + } +} + +func TestToTomlStringTypeConversionError(t *testing.T) { + tree := TomlTree{ + values: map[string]interface{}{ + "thing": &tomlValue{[]string{"unsupported"}, Position{}}, + }, + } + _, err := tree.ToTomlString() + expected := errors.New("unsupported value type []string: [unsupported]") + if err.Error() != expected.Error() { + t.Errorf("expecting error %s, but got %s instead", expected, err) + } +} + +func TestTomlTreeWriteToMapSimple(t *testing.T) { + tree, _ := Load("a = 42\nb = 17") + + expected := map[string]interface{}{ + "a": int64(42), + "b": int64(17), + } + + testMaps(t, tree.ToMap(), expected) +} + +func TestTomlTreeWriteToInvalidTreeSimpleValue(t *testing.T) { + tree := TomlTree{values: map[string]interface{}{"foo": int8(1)}} + _, err := tree.ToTomlString() + assertErrorString(t, "invalid value type at foo: int8", err) +} + +func TestTomlTreeWriteToInvalidTreeTomlValue(t *testing.T) { + tree := TomlTree{values: map[string]interface{}{"foo": &tomlValue{int8(1), Position{}}}} + _, err := tree.ToTomlString() + assertErrorString(t, "unsupported value type int8: 1", err) +} + +func TestTomlTreeWriteToInvalidTreeTomlValueArray(t *testing.T) { + tree := TomlTree{values: map[string]interface{}{"foo": &tomlValue{[]interface{}{int8(1)}, Position{}}}} + _, err := tree.ToTomlString() + assertErrorString(t, "unsupported value type int8: 1", err) +} + +func TestTomlTreeWriteToFailingWriterInSimpleValue(t *testing.T) { + toml, _ := Load(`a = 2`) + writer := failingWriter{failAt: 0, written: 0} + _, err := toml.WriteTo(writer) + assertErrorString(t, "failingWriter failed after writting 0 bytes", err) +} + +func TestTomlTreeWriteToFailingWriterInTable(t *testing.T) { + toml, _ := Load(` +[b] +a = 2`) + writer := failingWriter{failAt: 2, written: 0} + _, err := toml.WriteTo(writer) + assertErrorString(t, "failingWriter failed after writting 2 bytes", err) + + writer = failingWriter{failAt: 13, written: 0} + _, err = toml.WriteTo(writer) + assertErrorString(t, "failingWriter failed after writting 13 bytes", err) +} + +func TestTomlTreeWriteToFailingWriterInArray(t *testing.T) { + toml, _ := Load(` +[[b]] +a = 2`) + writer := failingWriter{failAt: 2, written: 0} + _, err := toml.WriteTo(writer) + assertErrorString(t, "failingWriter failed after writting 2 bytes", err) + + writer = failingWriter{failAt: 15, written: 0} + _, err = toml.WriteTo(writer) + assertErrorString(t, "failingWriter failed after writting 15 bytes", err) +} + +func TestTomlTreeWriteToMapExampleFile(t *testing.T) { + tree, _ := LoadFile("example.toml") + expected := map[string]interface{}{ + "title": "TOML Example", + "owner": map[string]interface{}{ + "name": "Tom Preston-Werner", + "organization": "GitHub", + "bio": "GitHub Cofounder & CEO\nLikes tater tots and beer.", + "dob": time.Date(1979, time.May, 27, 7, 32, 0, 0, time.UTC), + }, + "database": map[string]interface{}{ + "server": "192.168.1.1", + "ports": []interface{}{int64(8001), int64(8001), int64(8002)}, + "connection_max": int64(5000), + "enabled": true, + }, + "servers": map[string]interface{}{ + "alpha": map[string]interface{}{ + "ip": "10.0.0.1", + "dc": "eqdc10", + }, + "beta": map[string]interface{}{ + "ip": "10.0.0.2", + "dc": "eqdc10", + }, + }, + "clients": map[string]interface{}{ + "data": []interface{}{ + []interface{}{"gamma", "delta"}, + []interface{}{int64(1), int64(2)}, + }, + }, + } + testMaps(t, tree.ToMap(), expected) +} + +func TestTomlTreeWriteToMapWithTablesInMultipleChunks(t *testing.T) { + tree, _ := Load(` + [[menu.main]] + a = "menu 1" + b = "menu 2" + [[menu.main]] + c = "menu 3" + d = "menu 4"`) + expected := map[string]interface{}{ + "menu": map[string]interface{}{ + "main": []interface{}{ + map[string]interface{}{"a": "menu 1", "b": "menu 2"}, + map[string]interface{}{"c": "menu 3", "d": "menu 4"}, + }, + }, + } + treeMap := tree.ToMap() + + testMaps(t, treeMap, expected) +} + +func TestTomlTreeWriteToMapWithArrayOfInlineTables(t *testing.T) { + tree, _ := Load(` + [params] + language_tabs = [ + { key = "shell", name = "Shell" }, + { key = "ruby", name = "Ruby" }, + { key = "python", name = "Python" } + ]`) + + expected := map[string]interface{}{ + "params": map[string]interface{}{ + "language_tabs": []interface{}{ + map[string]interface{}{ + "key": "shell", + "name": "Shell", + }, + map[string]interface{}{ + "key": "ruby", + "name": "Ruby", + }, + map[string]interface{}{ + "key": "python", + "name": "Python", + }, + }, + }, + } + + treeMap := tree.ToMap() + testMaps(t, treeMap, expected) +} From d3135b8a1effa7ba2ffe6805d43b58e317079aea Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Mon, 20 Mar 2017 13:13:48 -0500 Subject: [PATCH 02/20] Add MarshalTOML to manifest and lock --- lock.go | 51 +++++++++++++++++++++++++- lock_test.go | 16 ++++----- manifest.go | 67 +++++++++++++++++++++++++++++++++-- manifest_test.go | 6 ++-- testdata/lock/golden0.toml | 7 ++++ testdata/lock/golden1.toml | 7 ++++ testdata/manifest/golden.toml | 15 ++++++++ 7 files changed, 154 insertions(+), 15 deletions(-) create mode 100644 testdata/lock/golden0.toml create mode 100644 testdata/lock/golden1.toml create mode 100644 testdata/manifest/golden.toml diff --git a/lock.go b/lock.go index bbced3410f..4cac2519ca 100644 --- a/lock.go +++ b/lock.go @@ -11,6 +11,7 @@ import ( "io" "sort" + "github.com/pelletier/go-toml" "github.com/pkg/errors" "github.com/sdboyer/gps" ) @@ -85,7 +86,8 @@ func (l *Lock) Projects() []gps.LockedProject { return l.P } -func (l *Lock) MarshalJSON() ([]byte, error) { +// toRaw converts the manifest into a representation suitable to write to the lock file +func (l *Lock) toRaw() rawLock { raw := rawLock{ Memo: hex.EncodeToString(l.Memo), P: make([]lockedDep, len(l.P)), @@ -109,6 +111,12 @@ func (l *Lock) MarshalJSON() ([]byte, error) { // TODO sort output - #15 + return raw +} + +func (l *Lock) MarshalJSON() ([]byte, error) { + raw := l.toRaw() + var buf bytes.Buffer enc := json.NewEncoder(&buf) enc.SetIndent("", " ") @@ -118,6 +126,47 @@ func (l *Lock) MarshalJSON() ([]byte, error) { return buf.Bytes(), err } +func (l *Lock) MarshalTOML() (string, error) { + raw := l.toRaw() + + // TODO(carolynvs) Consider adding reflection-based marshal functionality to go-toml + m := make(map[string]interface{}) + m["memo"] = raw.Memo + p := make([]map[string]interface{}, len(raw.P)) + for i := 0; i < len(p); i++ { + prj := make(map[string]interface{}) + prj["name"] = raw.P[i].Name + prj["revision"] = raw.P[i].Revision + + if raw.P[i].Source != "" { + prj["source"] = raw.P[i].Source + } + if raw.P[i].Branch != "" { + prj["branch"] = raw.P[i].Branch + } + if raw.P[i].Version != "" { + prj["version"] = raw.P[i].Version + } + + pkgs := make([]interface{}, len(raw.P[i].Packages)) + for j := range raw.P[i].Packages { + pkgs[j] = raw.P[i].Packages[j] + } + prj["packages"] = pkgs + + p[i] = prj + } + m["projects"] = p + + t, err := toml.TreeFromMap(m) + if err != nil { + return "", errors.Wrap(err, "Unable to marshal lock to TOML tree") + } + + result, err := t.ToTomlString() + return result, errors.Wrap(err, "Unable to marshal lock to TOML string") +} + // TODO(carolynvs) this should be moved to gps func getVersionInfo(v gps.Version) (revision string, branch string, version string) { // Figure out how to get the underlying revision diff --git a/lock_test.go b/lock_test.go index be6cc24288..613e2290f5 100644 --- a/lock_test.go +++ b/lock_test.go @@ -71,7 +71,7 @@ func TestWriteLock(t *testing.T) { h := test.NewHelper(t) defer h.Cleanup() - golden := "lock/golden0.json" + golden := "lock/golden0.toml" want := h.GetTestFileString(golden) memo, _ := hex.DecodeString("2252a285ab27944a4d7adcba8dbd03980f59ba652f12db39fa93b927c345593e") l := &Lock{ @@ -85,9 +85,9 @@ func TestWriteLock(t *testing.T) { }, } - got, err := l.MarshalJSON() + got, err := l.MarshalTOML() if err != nil { - t.Fatalf("Error while marshaling valid lock to JSON: %q", err) + t.Fatalf("Error while marshaling valid lock to TOML: %q", err) } if string(got) != want { @@ -96,11 +96,11 @@ func TestWriteLock(t *testing.T) { t.Fatal(err) } } else { - t.Errorf("Valid lock did not marshal to JSON as expected:\n\t(GOT): %s\n\t(WNT): %s", string(got), want) + t.Errorf("Valid lock did not marshal to TOML as expected:\n\t(GOT): %s\n\t(WNT): %s", string(got), want) } } - golden = "lock/golden1.json" + golden = "lock/golden1.toml" want = h.GetTestFileString(golden) memo, _ = hex.DecodeString("2252a285ab27944a4d7adcba8dbd03980f59ba652f12db39fa93b927c345593e") l = &Lock{ @@ -114,9 +114,9 @@ func TestWriteLock(t *testing.T) { }, } - got, err = l.MarshalJSON() + got, err = l.MarshalTOML() if err != nil { - t.Fatalf("Error while marshaling valid lock to JSON: %q", err) + t.Fatalf("Error while marshaling valid lock to TOML: %q", err) } if string(got) != want { @@ -125,7 +125,7 @@ func TestWriteLock(t *testing.T) { t.Fatal(err) } } else { - t.Errorf("Valid lock did not marshal to JSON as expected:\n\t(GOT): %s\n\t(WNT): %s", string(got), want) + t.Errorf("Valid lock did not marshal to TOML as expected:\n\t(GOT): %s\n\t(WNT): %s", string(got), want) } } } diff --git a/manifest.go b/manifest.go index 2f017ecdfc..ff9b254605 100644 --- a/manifest.go +++ b/manifest.go @@ -9,6 +9,7 @@ import ( "encoding/json" "io" + "github.com/pelletier/go-toml" "github.com/pkg/errors" "github.com/sdboyer/gps" ) @@ -108,21 +109,25 @@ func toProps(n string, p possibleProps) (pp gps.ProjectProperties, err error) { return pp, nil } -func (m *Manifest) MarshalJSON() ([]byte, error) { +// toRaw converts the manifest into a representation suitable to write to the manifest file +func (m *Manifest) toRaw() rawManifest { raw := rawManifest{ Dependencies: make(map[string]possibleProps, len(m.Dependencies)), Overrides: make(map[string]possibleProps, len(m.Ovr)), Ignores: m.Ignores, Required: m.Required, } - for n, pp := range m.Dependencies { raw.Dependencies[string(n)] = toPossible(pp) } - for n, pp := range m.Ovr { raw.Overrides[string(n)] = toPossible(pp) } + return raw +} + +func (m *Manifest) MarshalJSON() ([]byte, error) { + raw := m.toRaw() var buf bytes.Buffer enc := json.NewEncoder(&buf) @@ -133,6 +138,62 @@ func (m *Manifest) MarshalJSON() ([]byte, error) { return buf.Bytes(), err } +func (m *Manifest) MarshalTOML() (string, error) { + raw := m.toRaw() + + // TODO(carolynvs) Consider adding reflection-based marshal functionality to go-toml + copyProject := func(src map[string]possibleProps) map[string]interface{} { + dest := make(map[string]interface{}, len(src)) + for k, v := range src { + prj := make(map[string]interface{}) + if v.Source != "" { + prj["source"] = v.Source + } + if v.Branch != "" { + prj["branch"] = v.Branch + } + if v.Version != "" { + prj["version"] = v.Version + } + if v.Revision != "" { + prj["revision"] = v.Revision + } + dest[k] = prj + + } + return dest + } + + copyProjectRef := func(src []string) []interface{} { + dest := make([]interface{}, len(src)) + for i := range src { + dest[i] = src[i] + } + return dest + } + + data := make(map[string]interface{}) + if len(raw.Dependencies) > 0 { + data["dependencies"] = copyProject(raw.Dependencies) + } + if len(raw.Overrides) > 0 { + data["overrides"] = copyProject(raw.Overrides) + } + if len(raw.Ignores) > 0 { + data["ignores"] = copyProjectRef(raw.Ignores) + } + if len(raw.Required) > 0 { + data["required"] = copyProjectRef(raw.Required) + } + + tree, err := toml.TreeFromMap(data) + if err != nil { + return "", errors.Wrap(err, "Unable to marshal the lock to a TOML tree") + } + result, err := tree.ToTomlString() + return result, errors.Wrap(err, "Unable to marshal the lock to a TOML string") +} + func toPossible(pp gps.ProjectProperties) possibleProps { p := possibleProps{ Source: pp.Source, diff --git a/manifest_test.go b/manifest_test.go index 38b40d82ed..5c7b1eecd7 100644 --- a/manifest_test.go +++ b/manifest_test.go @@ -58,7 +58,7 @@ func TestWriteManifest(t *testing.T) { h := test.NewHelper(t) defer h.Cleanup() - golden := "manifest/golden.json" + golden := "manifest/golden.toml" want := h.GetTestFileString(golden) c, _ := gps.NewSemverConstraint("^v0.12.0") m := &Manifest{ @@ -81,7 +81,7 @@ func TestWriteManifest(t *testing.T) { got, err := m.MarshalJSON() if err != nil { - t.Fatalf("Error while marshaling valid manifest to JSON: %q", err) + t.Fatalf("Error while marshaling valid manifest to TOML: %q", err) } if string(got) != want { @@ -90,7 +90,7 @@ func TestWriteManifest(t *testing.T) { t.Fatal(err) } } else { - t.Errorf("Valid manifest did not marshal to JSON as expected:\n\t(GOT): %s\n\t(WNT): %s", string(got), want) + t.Errorf("Valid manifest did not marshal to TOML as expected:\n\t(GOT): %s\n\t(WNT): %s", string(got), want) } } } diff --git a/testdata/lock/golden0.toml b/testdata/lock/golden0.toml new file mode 100644 index 0000000000..6e0cc983a3 --- /dev/null +++ b/testdata/lock/golden0.toml @@ -0,0 +1,7 @@ +memo = "2252a285ab27944a4d7adcba8dbd03980f59ba652f12db39fa93b927c345593e" + +[[projects]] + branch = "master" + name = "github.com/sdboyer/gps" + packages = ["."] + revision = "d05d5aca9f895d19e9265839bffeadd74a2d2ecb" diff --git a/testdata/lock/golden1.toml b/testdata/lock/golden1.toml new file mode 100644 index 0000000000..120ba3800a --- /dev/null +++ b/testdata/lock/golden1.toml @@ -0,0 +1,7 @@ +memo = "2252a285ab27944a4d7adcba8dbd03980f59ba652f12db39fa93b927c345593e" + +[[projects]] + name = "github.com/sdboyer/gps" + packages = ["."] + revision = "d05d5aca9f895d19e9265839bffeadd74a2d2ecb" + version = "0.12.2" diff --git a/testdata/manifest/golden.toml b/testdata/manifest/golden.toml new file mode 100644 index 0000000000..1c29f5b71f --- /dev/null +++ b/testdata/manifest/golden.toml @@ -0,0 +1,15 @@ +ignores = ["github.com/foo/bar"] + +[dependencies] + + [dependencies.github.com/babble/brook] + revision = "d05d5aca9f895d19e9265839bffeadd74a2d2ecb" + + [dependencies.github.com/sdboyer/gps] + version = ">=0.12.0, <1.0.0" + +[overrides] + + [overrides.github.com/sdboyer/gps] + branch = "master" + source = "https://github.com/sdboyer/gps" From 6366f9ed6813d399501331987906ac1d445cc8a1 Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Mon, 20 Mar 2017 13:14:02 -0500 Subject: [PATCH 03/20] Write manifest and lock in TOML --- analyzer_test.go | 2 +- fs.go | 14 ++++++++++---- manifest_test.go | 2 +- testdata/txn_writer/expected_lock.toml | 7 +++++++ txn_writer.go | 4 ++-- txn_writer_test.go | 2 +- 6 files changed, 22 insertions(+), 9 deletions(-) create mode 100644 testdata/txn_writer/expected_lock.toml diff --git a/analyzer_test.go b/analyzer_test.go index 611889b76f..ac8fe39882 100644 --- a/analyzer_test.go +++ b/analyzer_test.go @@ -29,7 +29,7 @@ func TestDeriveManifestAndLock(t *testing.T) { t.Fatal(err) } - got, err := m.(*Manifest).MarshalJSON() + got, err := m.(*Manifest).MarshalTOML() if err != nil { t.Fatal(err) } diff --git a/fs.go b/fs.go index 9dab36037c..83d568981a 100644 --- a/fs.go +++ b/fs.go @@ -5,7 +5,6 @@ package dep import ( - "encoding/json" "io" "io/ioutil" "os" @@ -16,6 +15,13 @@ import ( "github.com/pkg/errors" ) +// Marshaler is the interface implemented by types that +// can marshal themselves into valid TOML. +// TODO(carolynvs) Consider adding this to go-toml? +type Marshaler interface { + MarshalTOML() (string, error) +} + func IsRegular(name string) (bool, error) { // TODO: lstat? fi, err := os.Stat(name) @@ -59,19 +65,19 @@ func IsNonEmptyDir(name string) (bool, error) { return len(files) != 0, nil } -func writeFile(path string, in json.Marshaler) error { +func writeFile(path string, in Marshaler) error { f, err := os.Create(path) if err != nil { return err } defer f.Close() - b, err := in.MarshalJSON() + s, err := in.MarshalTOML() if err != nil { return err } - _, err = f.Write(b) + _, err = f.WriteString(s) return err } diff --git a/manifest_test.go b/manifest_test.go index 5c7b1eecd7..8bbfce9907 100644 --- a/manifest_test.go +++ b/manifest_test.go @@ -79,7 +79,7 @@ func TestWriteManifest(t *testing.T) { Ignores: []string{"github.com/foo/bar"}, } - got, err := m.MarshalJSON() + got, err := m.MarshalTOML() if err != nil { t.Fatalf("Error while marshaling valid manifest to TOML: %q", err) } diff --git a/testdata/txn_writer/expected_lock.toml b/testdata/txn_writer/expected_lock.toml new file mode 100644 index 0000000000..bda7ec14cb --- /dev/null +++ b/testdata/txn_writer/expected_lock.toml @@ -0,0 +1,7 @@ +memo = "595716d270828e763c811ef79c9c41f85b1d1bfbdfe85280036405c03772206c" + +[[projects]] + name = "github.com/sdboyer/dep-test" + packages = ["."] + revision = "2a3a211e171803acb82d1d5d42ceb53228f51751" + version = "1.0.0" diff --git a/txn_writer.go b/txn_writer.go index f159887406..cc97a6c2a5 100644 --- a/txn_writer.go +++ b/txn_writer.go @@ -365,7 +365,7 @@ fail: func (sw *SafeWriter) PrintPreparedActions() error { if sw.Payload.HasManifest() { fmt.Println("Would have written the following manifest.json:") - m, err := sw.Payload.Manifest.MarshalJSON() + m, err := sw.Payload.Manifest.MarshalTOML() if err != nil { return errors.Wrap(err, "ensure DryRun cannot serialize manifest") } @@ -375,7 +375,7 @@ func (sw *SafeWriter) PrintPreparedActions() error { if sw.Payload.HasLock() { if sw.Payload.LockDiff == nil { fmt.Println("Would have written the following lock.json:") - l, err := sw.Payload.Lock.MarshalJSON() + l, err := sw.Payload.Lock.MarshalTOML() if err != nil { return errors.Wrap(err, "ensure DryRun cannot serialize lock") } diff --git a/txn_writer_test.go b/txn_writer_test.go index c188d7ef6a..07aad9cb36 100644 --- a/txn_writer_test.go +++ b/txn_writer_test.go @@ -15,7 +15,7 @@ import ( const safeWriterProject = "safewritertest" const safeWriterGoldenManifest = "txn_writer/expected_manifest.json" -const safeWriterGoldenLock = "txn_writer/expected_lock.json" +const safeWriterGoldenLock = "txn_writer/expected_lock.toml" func TestSafeWriter_BadInput_MissingRoot(t *testing.T) { h := test.NewHelper(t) From 7b22cd825d41bb54c0f8b7d2cf02af7552b472b9 Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Tue, 21 Mar 2017 09:36:26 -0500 Subject: [PATCH 04/20] Represent manifest dependencies as an array of tables, not a map Using the project root as a key in TOML makes our life harder. This siplifies the manifest format and parsing. --- lock.go | 23 ++++++++++++----------- manifest.go | 35 ++++++++++++++++++----------------- testdata/manifest/golden.toml | 25 ++++++++++++------------- 3 files changed, 42 insertions(+), 41 deletions(-) diff --git a/lock.go b/lock.go index 4cac2519ca..771e592d18 100644 --- a/lock.go +++ b/lock.go @@ -134,23 +134,24 @@ func (l *Lock) MarshalTOML() (string, error) { m["memo"] = raw.Memo p := make([]map[string]interface{}, len(raw.P)) for i := 0; i < len(p); i++ { + srcPrj := raw.P[i] prj := make(map[string]interface{}) - prj["name"] = raw.P[i].Name - prj["revision"] = raw.P[i].Revision + prj["name"] = srcPrj.Name + prj["revision"] = srcPrj.Revision - if raw.P[i].Source != "" { - prj["source"] = raw.P[i].Source + if srcPrj.Source != "" { + prj["source"] = srcPrj.Source } - if raw.P[i].Branch != "" { - prj["branch"] = raw.P[i].Branch + if srcPrj.Branch != "" { + prj["branch"] = srcPrj.Branch } - if raw.P[i].Version != "" { - prj["version"] = raw.P[i].Version + if srcPrj.Version != "" { + prj["version"] = srcPrj.Version } - pkgs := make([]interface{}, len(raw.P[i].Packages)) - for j := range raw.P[i].Packages { - pkgs[j] = raw.P[i].Packages[j] + pkgs := make([]interface{}, len(srcPrj.Packages)) + for j := range srcPrj.Packages { + pkgs[j] = srcPrj.Packages[j] } prj["packages"] = pkgs diff --git a/manifest.go b/manifest.go index ff9b254605..3da2171e3a 100644 --- a/manifest.go +++ b/manifest.go @@ -142,29 +142,30 @@ func (m *Manifest) MarshalTOML() (string, error) { raw := m.toRaw() // TODO(carolynvs) Consider adding reflection-based marshal functionality to go-toml - copyProject := func(src map[string]possibleProps) map[string]interface{} { - dest := make(map[string]interface{}, len(src)) - for k, v := range src { + copyProjects := func(src map[string]possibleProps) []map[string]interface{} { + dest := make([]map[string]interface{}, 0, len(src)) + for prjName, srcPrj := range src { prj := make(map[string]interface{}) - if v.Source != "" { - prj["source"] = v.Source + prj["name"] = prjName + if srcPrj.Source != "" { + prj["source"] = srcPrj.Source } - if v.Branch != "" { - prj["branch"] = v.Branch + if srcPrj.Branch != "" { + prj["branch"] = srcPrj.Branch } - if v.Version != "" { - prj["version"] = v.Version + if srcPrj.Version != "" { + prj["version"] = srcPrj.Version } - if v.Revision != "" { - prj["revision"] = v.Revision + if srcPrj.Revision != "" { + prj["revision"] = srcPrj.Revision } - dest[k] = prj + dest = append(dest, prj) } return dest } - copyProjectRef := func(src []string) []interface{} { + copyProjectRefs := func(src []string) []interface{} { dest := make([]interface{}, len(src)) for i := range src { dest[i] = src[i] @@ -174,16 +175,16 @@ func (m *Manifest) MarshalTOML() (string, error) { data := make(map[string]interface{}) if len(raw.Dependencies) > 0 { - data["dependencies"] = copyProject(raw.Dependencies) + data["dependencies"] = copyProjects(raw.Dependencies) } if len(raw.Overrides) > 0 { - data["overrides"] = copyProject(raw.Overrides) + data["overrides"] = copyProjects(raw.Overrides) } if len(raw.Ignores) > 0 { - data["ignores"] = copyProjectRef(raw.Ignores) + data["ignores"] = copyProjectRefs(raw.Ignores) } if len(raw.Required) > 0 { - data["required"] = copyProjectRef(raw.Required) + data["required"] = copyProjectRefs(raw.Required) } tree, err := toml.TreeFromMap(data) diff --git a/testdata/manifest/golden.toml b/testdata/manifest/golden.toml index 1c29f5b71f..f3c4759d04 100644 --- a/testdata/manifest/golden.toml +++ b/testdata/manifest/golden.toml @@ -1,15 +1,14 @@ ignores = ["github.com/foo/bar"] -[dependencies] - - [dependencies.github.com/babble/brook] - revision = "d05d5aca9f895d19e9265839bffeadd74a2d2ecb" - - [dependencies.github.com/sdboyer/gps] - version = ">=0.12.0, <1.0.0" - -[overrides] - - [overrides.github.com/sdboyer/gps] - branch = "master" - source = "https://github.com/sdboyer/gps" +[[dependencies]] + name = "github.com/sdboyer/gps" + version = ">=0.12.0, <1.0.0" + +[[dependencies]] + name = "github.com/babble/brook" + revision = "d05d5aca9f895d19e9265839bffeadd74a2d2ecb" + +[[overrides]] + branch = "master" + name = "github.com/sdboyer/gps" + source = "https://github.com/sdboyer/gps" From d2a557e00930d033c94a8133056e904fae7f5401 Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Tue, 21 Mar 2017 09:31:39 -0500 Subject: [PATCH 05/20] Change manifest and lock file names to manifest.toml and lock.toml --- cmd/dep/integration_test.go | 5 +++-- cmd/dep/testdata/harness_tests/README.md | 6 +++--- context.go | 2 +- hack/validate-vendor.bash | 4 ++-- lock.go | 2 +- manifest.go | 2 +- test/test.go | 4 ++-- test_project_context_test.go | 2 +- txn_writer.go | 6 +++--- 9 files changed, 17 insertions(+), 16 deletions(-) diff --git a/cmd/dep/integration_test.go b/cmd/dep/integration_test.go index 63937fdb1f..07e0e00406 100644 --- a/cmd/dep/integration_test.go +++ b/cmd/dep/integration_test.go @@ -11,6 +11,7 @@ import ( "strings" "testing" + "github.com/golang/dep" "github.com/golang/dep/test" ) @@ -56,8 +57,8 @@ func TestIntegration(t *testing.T) { } // Check final manifest and lock - testCase.CompareFile("manifest.json", testProj.ProjPath("manifest.json")) - testCase.CompareFile("lock.json", testProj.ProjPath("lock.json")) + testCase.CompareFile(dep.ManifestName, testProj.ProjPath(dep.ManifestName)) + testCase.CompareFile(dep.LockName, testProj.ProjPath(dep.LockName)) // Check vendor paths testProj.CompareImportPaths() diff --git a/cmd/dep/testdata/harness_tests/README.md b/cmd/dep/testdata/harness_tests/README.md index 526b483705..9cd5cf3c2a 100644 --- a/cmd/dep/testdata/harness_tests/README.md +++ b/cmd/dep/testdata/harness_tests/README.md @@ -14,11 +14,11 @@ The directory structure is as follows: testcase.json initial/ file1.go - manifest.json + manifest.toml ... final/ - manifest.json - lock.json + manifest.toml + lock.toml case2/ ... diff --git a/context.go b/context.go index 6ce18d0689..54e60811e9 100644 --- a/context.go +++ b/context.go @@ -48,7 +48,7 @@ func (c *Ctx) SourceManager() (*gps.SourceMgr, error) { // a project root. If an absolute path is given, the search begins in that // directory. If a relative or empty path is given, the search start is computed // from the current working directory. The search stops when a file with the -// name ManifestName (manifest.json, by default) is located. +// name ManifestName (manifest.toml, by default) is located. // // The Project contains the parsed manifest as well as a parsed lock file, if // present. The import path is calculated as the remaining path segment diff --git a/hack/validate-vendor.bash b/hack/validate-vendor.bash index 08b62d2975..6f4d2c458e 100755 --- a/hack/validate-vendor.bash +++ b/hack/validate-vendor.bash @@ -21,7 +21,7 @@ fi VALIDATE_HEAD="$(git rev-parse --verify HEAD)" IFS=$'\n' -files=( $(git diff "$TRAVIS_BRANCH...$VALIDATE_HEAD" --diff-filter=ACMR --name-only -- 'manifest.json' 'lock.json' 'vendor/' || true) ) +files=( $(git diff "$TRAVIS_BRANCH...$VALIDATE_HEAD" --diff-filter=ACMR --name-only -- 'manifest.toml' 'lock.toml' 'vendor/' || true) ) unset IFS if [ ${#files[@]} -gt 0 ]; then @@ -29,7 +29,7 @@ if [ ${#files[@]} -gt 0 ]; then go build ./dep ensure # Let see if the working directory is clean - diffs="$(git status --porcelain -- vendor manifest.json lock.json 2>/dev/null)" + diffs="$(git status --porcelain -- vendor manifest.toml lock.toml 2>/dev/null)" if [ "$diffs" ]; then { echo 'The result of ensure differs' diff --git a/lock.go b/lock.go index 771e592d18..72c5b0d588 100644 --- a/lock.go +++ b/lock.go @@ -16,7 +16,7 @@ import ( "github.com/sdboyer/gps" ) -const LockName = "lock.json" +const LockName = "lock.toml" type Lock struct { Memo []byte diff --git a/manifest.go b/manifest.go index 3da2171e3a..e890a15370 100644 --- a/manifest.go +++ b/manifest.go @@ -14,7 +14,7 @@ import ( "github.com/sdboyer/gps" ) -const ManifestName = "manifest.json" +const ManifestName = "manifest.toml" type Manifest struct { Dependencies gps.ProjectConstraints diff --git a/test/test.go b/test/test.go index 459caa8f2c..3ea6668196 100644 --- a/test/test.go +++ b/test/test.go @@ -584,7 +584,7 @@ func (h *Helper) Cleanup() { // ReadManifest returns the manifest in the current directory. func (h *Helper) ReadManifest() string { - m := filepath.Join(h.pwd(), "manifest.json") + m := filepath.Join(h.pwd(), "manifest.toml") h.MustExist(m) f, err := ioutil.ReadFile(m) @@ -594,7 +594,7 @@ func (h *Helper) ReadManifest() string { // ReadLock returns the lock in the current directory. func (h *Helper) ReadLock() string { - l := filepath.Join(h.pwd(), "lock.json") + l := filepath.Join(h.pwd(), "lock.toml") h.MustExist(l) f, err := ioutil.ReadFile(l) diff --git a/test_project_context_test.go b/test_project_context_test.go index 9451016c42..d1cda66e67 100644 --- a/test_project_context_test.go +++ b/test_project_context_test.go @@ -54,7 +54,7 @@ func (pc *TestProjectContext) CopyFile(projectPath string, testdataPath string) } func (pc *TestProjectContext) Load() { - // TODO(carolynvs): Can't use Ctx.LoadProject until dep doesn't require a manifest.json at the project root or it also looks for lock.json + // TODO(carolynvs): Can't use Ctx.LoadProject until dep doesn't require a manifest at the project root or it also looks for lock var err error var m *Manifest mp := pc.getManifestPath() diff --git a/txn_writer.go b/txn_writer.go index cc97a6c2a5..f6daef812c 100644 --- a/txn_writer.go +++ b/txn_writer.go @@ -364,7 +364,7 @@ fail: func (sw *SafeWriter) PrintPreparedActions() error { if sw.Payload.HasManifest() { - fmt.Println("Would have written the following manifest.json:") + fmt.Println("Would have written the following manifest.toml:") m, err := sw.Payload.Manifest.MarshalTOML() if err != nil { return errors.Wrap(err, "ensure DryRun cannot serialize manifest") @@ -374,14 +374,14 @@ func (sw *SafeWriter) PrintPreparedActions() error { if sw.Payload.HasLock() { if sw.Payload.LockDiff == nil { - fmt.Println("Would have written the following lock.json:") + fmt.Println("Would have written the following lock.toml:") l, err := sw.Payload.Lock.MarshalTOML() if err != nil { return errors.Wrap(err, "ensure DryRun cannot serialize lock") } fmt.Println(string(l)) } else { - fmt.Println("Would have written the following changes to lock.json:") + fmt.Println("Would have written the following changes to lock.toml:") diff, err := sw.Payload.LockDiff.Format() if err != nil { return errors.Wrap(err, "ensure DryRun cannot serialize the lock diff") From 12e713b5463096493f4b43b1521d11f73c660388 Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Tue, 21 Mar 2017 11:23:53 -0500 Subject: [PATCH 06/20] Update test files from JSON to TOML --- analyzer_test.go | 2 +- .../ensure/empty/case1/final/lock.json | 13 ----------- .../ensure/empty/case1/final/lock.toml | 7 ++++++ .../ensure/empty/case1/final/manifest.json | 1 - .../ensure/empty/case1/final/manifest.toml | 0 .../ensure/empty/case2/final/lock.json | 13 ----------- .../ensure/empty/case2/final/lock.toml | 7 ++++++ .../ensure/empty/case2/final/manifest.json | 7 ------ .../ensure/empty/case2/final/manifest.toml | 4 ++++ .../ensure/empty/case2/initial/manifest.json | 7 ------ .../ensure/empty/case2/initial/manifest.toml | 3 +++ .../ensure/override/case1/final/lock.json | 13 ----------- .../ensure/override/case1/final/lock.toml | 7 ++++++ .../ensure/override/case1/final/manifest.json | 7 ------ .../ensure/override/case1/final/manifest.toml | 4 ++++ .../ensure/update/case1/final/lock.json | 21 ----------------- .../ensure/update/case1/final/lock.toml | 13 +++++++++++ .../ensure/update/case1/final/manifest.json | 7 ------ .../ensure/update/case1/final/manifest.toml | 3 +++ .../ensure/update/case1/initial/lock.json | 21 ----------------- .../ensure/update/case1/initial/lock.toml | 13 +++++++++++ .../ensure/update/case1/initial/manifest.json | 7 ------ .../ensure/update/case1/initial/manifest.toml | 3 +++ .../ensure/update/case2/final/lock.json | 21 ----------------- .../ensure/update/case2/final/lock.toml | 13 +++++++++++ .../ensure/update/case2/final/manifest.json | 7 ------ .../ensure/update/case2/final/manifest.toml | 3 +++ .../ensure/update/case2/initial/lock.json | 21 ----------------- .../ensure/update/case2/initial/lock.toml | 13 +++++++++++ .../ensure/update/case2/initial/manifest.json | 7 ------ .../ensure/update/case2/initial/manifest.toml | 3 +++ .../harness_tests/init/case1/final/lock.json | 20 ---------------- .../harness_tests/init/case1/final/lock.toml | 12 ++++++++++ .../init/case1/final/manifest.json | 10 -------- .../init/case1/final/manifest.toml | 8 +++++++ .../harness_tests/init/case2/final/lock.json | 21 ----------------- .../harness_tests/init/case2/final/lock.toml | 13 +++++++++++ .../init/case2/final/manifest.json | 7 ------ .../init/case2/final/manifest.toml | 4 ++++ .../harness_tests/init/case3/final/lock.json | 20 ---------------- .../harness_tests/init/case3/final/lock.toml | 12 ++++++++++ .../init/case3/final/manifest.json | 10 -------- .../init/case3/final/manifest.toml | 8 +++++++ .../init/skip-hidden/final/lock.json | 13 ----------- .../init/skip-hidden/final/lock.toml | 7 ++++++ .../init/skip-hidden/final/manifest.json | 1 - .../init/skip-hidden/final/manifest.toml | 0 .../remove/force/case1/final/lock.json | 21 ----------------- .../remove/force/case1/final/lock.toml | 13 +++++++++++ .../remove/force/case1/final/manifest.json | 7 ------ .../remove/force/case1/final/manifest.toml | 4 ++++ .../remove/force/case1/initial/manifest.json | 13 ----------- .../remove/force/case1/initial/manifest.toml | 11 +++++++++ .../remove/specific/case1/final/lock.json | 20 ---------------- .../remove/specific/case1/final/lock.toml | 12 ++++++++++ .../remove/specific/case1/final/manifest.json | 10 -------- .../remove/specific/case1/final/manifest.toml | 8 +++++++ .../specific/case1/initial/manifest.json | 13 ----------- .../specific/case1/initial/manifest.toml | 11 +++++++++ .../remove/specific/case2/final/lock.json | 13 ----------- .../remove/specific/case2/final/lock.toml | 7 ++++++ .../remove/specific/case2/final/manifest.json | 10 -------- .../remove/specific/case2/final/manifest.toml | 8 +++++++ .../specific/case2/initial/manifest.json | 13 ----------- .../specific/case2/initial/manifest.toml | 11 +++++++++ .../remove/unused/case1/final/lock.json | 20 ---------------- .../remove/unused/case1/final/lock.toml | 12 ++++++++++ .../remove/unused/case1/final/manifest.json | 10 -------- .../remove/unused/case1/final/manifest.toml | 8 +++++++ .../remove/unused/case1/initial/manifest.json | 13 ----------- .../remove/unused/case1/initial/manifest.toml | 11 +++++++++ context_test.go | 22 +++++++++--------- lock_test.go | 10 ++++---- manifest_test.go | 4 ++-- testdata/analyzer/manifest.json | 10 -------- testdata/analyzer/manifest.toml | 8 +++++++ testdata/lock/error0.json | 14 ----------- testdata/lock/error0.toml | 8 +++++++ testdata/lock/error1.json | 13 ----------- testdata/lock/error1.toml | 7 ++++++ testdata/lock/error2.json | 11 --------- testdata/lock/error2.toml | 5 ++++ testdata/lock/golden0.json | 13 ----------- testdata/lock/golden1.json | 13 ----------- testdata/manifest/error.json | 21 ----------------- testdata/manifest/error.toml | 15 ++++++++++++ testdata/manifest/golden.json | 19 --------------- testdata/rootfind/manifest.toml | 0 testdata/txn_writer/expected_lock.json | 13 ----------- testdata/txn_writer/expected_manifest.json | 7 ------ testdata/txn_writer/expected_manifest.toml | 4 ++++ testdata/txn_writer/original_lock.json | 22 ------------------ testdata/txn_writer/original_lock.toml | 13 +++++++++++ testdata/txn_writer/updated_lock.json | 23 ------------------- testdata/txn_writer/updated_lock.toml | 14 +++++++++++ txn_writer_test.go | 6 ++--- 96 files changed, 372 insertions(+), 639 deletions(-) delete mode 100644 cmd/dep/testdata/harness_tests/ensure/empty/case1/final/lock.json create mode 100644 cmd/dep/testdata/harness_tests/ensure/empty/case1/final/lock.toml delete mode 100644 cmd/dep/testdata/harness_tests/ensure/empty/case1/final/manifest.json rename testdata/rootfind/manifest.json => cmd/dep/testdata/harness_tests/ensure/empty/case1/final/manifest.toml (100%) delete mode 100644 cmd/dep/testdata/harness_tests/ensure/empty/case2/final/lock.json create mode 100644 cmd/dep/testdata/harness_tests/ensure/empty/case2/final/lock.toml delete mode 100644 cmd/dep/testdata/harness_tests/ensure/empty/case2/final/manifest.json create mode 100644 cmd/dep/testdata/harness_tests/ensure/empty/case2/final/manifest.toml delete mode 100644 cmd/dep/testdata/harness_tests/ensure/empty/case2/initial/manifest.json create mode 100644 cmd/dep/testdata/harness_tests/ensure/empty/case2/initial/manifest.toml delete mode 100644 cmd/dep/testdata/harness_tests/ensure/override/case1/final/lock.json create mode 100644 cmd/dep/testdata/harness_tests/ensure/override/case1/final/lock.toml delete mode 100644 cmd/dep/testdata/harness_tests/ensure/override/case1/final/manifest.json create mode 100644 cmd/dep/testdata/harness_tests/ensure/override/case1/final/manifest.toml delete mode 100644 cmd/dep/testdata/harness_tests/ensure/update/case1/final/lock.json create mode 100644 cmd/dep/testdata/harness_tests/ensure/update/case1/final/lock.toml delete mode 100644 cmd/dep/testdata/harness_tests/ensure/update/case1/final/manifest.json create mode 100644 cmd/dep/testdata/harness_tests/ensure/update/case1/final/manifest.toml delete mode 100644 cmd/dep/testdata/harness_tests/ensure/update/case1/initial/lock.json create mode 100644 cmd/dep/testdata/harness_tests/ensure/update/case1/initial/lock.toml delete mode 100644 cmd/dep/testdata/harness_tests/ensure/update/case1/initial/manifest.json create mode 100644 cmd/dep/testdata/harness_tests/ensure/update/case1/initial/manifest.toml delete mode 100644 cmd/dep/testdata/harness_tests/ensure/update/case2/final/lock.json create mode 100644 cmd/dep/testdata/harness_tests/ensure/update/case2/final/lock.toml delete mode 100644 cmd/dep/testdata/harness_tests/ensure/update/case2/final/manifest.json create mode 100644 cmd/dep/testdata/harness_tests/ensure/update/case2/final/manifest.toml delete mode 100644 cmd/dep/testdata/harness_tests/ensure/update/case2/initial/lock.json create mode 100644 cmd/dep/testdata/harness_tests/ensure/update/case2/initial/lock.toml delete mode 100644 cmd/dep/testdata/harness_tests/ensure/update/case2/initial/manifest.json create mode 100644 cmd/dep/testdata/harness_tests/ensure/update/case2/initial/manifest.toml delete mode 100644 cmd/dep/testdata/harness_tests/init/case1/final/lock.json create mode 100644 cmd/dep/testdata/harness_tests/init/case1/final/lock.toml delete mode 100644 cmd/dep/testdata/harness_tests/init/case1/final/manifest.json create mode 100644 cmd/dep/testdata/harness_tests/init/case1/final/manifest.toml delete mode 100644 cmd/dep/testdata/harness_tests/init/case2/final/lock.json create mode 100644 cmd/dep/testdata/harness_tests/init/case2/final/lock.toml delete mode 100644 cmd/dep/testdata/harness_tests/init/case2/final/manifest.json create mode 100644 cmd/dep/testdata/harness_tests/init/case2/final/manifest.toml delete mode 100644 cmd/dep/testdata/harness_tests/init/case3/final/lock.json create mode 100644 cmd/dep/testdata/harness_tests/init/case3/final/lock.toml delete mode 100644 cmd/dep/testdata/harness_tests/init/case3/final/manifest.json create mode 100644 cmd/dep/testdata/harness_tests/init/case3/final/manifest.toml delete mode 100644 cmd/dep/testdata/harness_tests/init/skip-hidden/final/lock.json create mode 100644 cmd/dep/testdata/harness_tests/init/skip-hidden/final/lock.toml delete mode 100644 cmd/dep/testdata/harness_tests/init/skip-hidden/final/manifest.json create mode 100644 cmd/dep/testdata/harness_tests/init/skip-hidden/final/manifest.toml delete mode 100644 cmd/dep/testdata/harness_tests/remove/force/case1/final/lock.json create mode 100644 cmd/dep/testdata/harness_tests/remove/force/case1/final/lock.toml delete mode 100644 cmd/dep/testdata/harness_tests/remove/force/case1/final/manifest.json create mode 100644 cmd/dep/testdata/harness_tests/remove/force/case1/final/manifest.toml delete mode 100644 cmd/dep/testdata/harness_tests/remove/force/case1/initial/manifest.json create mode 100644 cmd/dep/testdata/harness_tests/remove/force/case1/initial/manifest.toml delete mode 100644 cmd/dep/testdata/harness_tests/remove/specific/case1/final/lock.json create mode 100644 cmd/dep/testdata/harness_tests/remove/specific/case1/final/lock.toml delete mode 100644 cmd/dep/testdata/harness_tests/remove/specific/case1/final/manifest.json create mode 100644 cmd/dep/testdata/harness_tests/remove/specific/case1/final/manifest.toml delete mode 100644 cmd/dep/testdata/harness_tests/remove/specific/case1/initial/manifest.json create mode 100644 cmd/dep/testdata/harness_tests/remove/specific/case1/initial/manifest.toml delete mode 100644 cmd/dep/testdata/harness_tests/remove/specific/case2/final/lock.json create mode 100644 cmd/dep/testdata/harness_tests/remove/specific/case2/final/lock.toml delete mode 100644 cmd/dep/testdata/harness_tests/remove/specific/case2/final/manifest.json create mode 100644 cmd/dep/testdata/harness_tests/remove/specific/case2/final/manifest.toml delete mode 100644 cmd/dep/testdata/harness_tests/remove/specific/case2/initial/manifest.json create mode 100644 cmd/dep/testdata/harness_tests/remove/specific/case2/initial/manifest.toml delete mode 100644 cmd/dep/testdata/harness_tests/remove/unused/case1/final/lock.json create mode 100644 cmd/dep/testdata/harness_tests/remove/unused/case1/final/lock.toml delete mode 100644 cmd/dep/testdata/harness_tests/remove/unused/case1/final/manifest.json create mode 100644 cmd/dep/testdata/harness_tests/remove/unused/case1/final/manifest.toml delete mode 100644 cmd/dep/testdata/harness_tests/remove/unused/case1/initial/manifest.json create mode 100644 cmd/dep/testdata/harness_tests/remove/unused/case1/initial/manifest.toml delete mode 100644 testdata/analyzer/manifest.json create mode 100644 testdata/analyzer/manifest.toml delete mode 100644 testdata/lock/error0.json create mode 100644 testdata/lock/error0.toml delete mode 100644 testdata/lock/error1.json create mode 100644 testdata/lock/error1.toml delete mode 100644 testdata/lock/error2.json create mode 100644 testdata/lock/error2.toml delete mode 100644 testdata/lock/golden0.json delete mode 100644 testdata/lock/golden1.json delete mode 100644 testdata/manifest/error.json create mode 100644 testdata/manifest/error.toml delete mode 100644 testdata/manifest/golden.json create mode 100644 testdata/rootfind/manifest.toml delete mode 100644 testdata/txn_writer/expected_lock.json delete mode 100644 testdata/txn_writer/expected_manifest.json create mode 100644 testdata/txn_writer/expected_manifest.toml delete mode 100644 testdata/txn_writer/original_lock.json create mode 100644 testdata/txn_writer/original_lock.toml delete mode 100644 testdata/txn_writer/updated_lock.json create mode 100644 testdata/txn_writer/updated_lock.toml diff --git a/analyzer_test.go b/analyzer_test.go index ac8fe39882..645d230da0 100644 --- a/analyzer_test.go +++ b/analyzer_test.go @@ -18,7 +18,7 @@ func TestDeriveManifestAndLock(t *testing.T) { defer h.Cleanup() h.TempDir("dep") - golden := "analyzer/manifest.json" + golden := "analyzer/manifest.toml" want := h.GetTestFileString(golden) h.TempCopy(filepath.Join("dep", ManifestName), golden) diff --git a/cmd/dep/testdata/harness_tests/ensure/empty/case1/final/lock.json b/cmd/dep/testdata/harness_tests/ensure/empty/case1/final/lock.json deleted file mode 100644 index 4af31ffe93..0000000000 --- a/cmd/dep/testdata/harness_tests/ensure/empty/case1/final/lock.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "memo": "4b36ae008ef4be09dee7e2ae00606d44fd75f4310fd0d0ef6e744690290569de", - "projects": [ - { - "name": "github.com/sdboyer/deptest", - "version": "v1.0.0", - "revision": "ff2948a2ac8f538c4ecd55962e919d1e13e74baf", - "packages": [ - "." - ] - } - ] -} diff --git a/cmd/dep/testdata/harness_tests/ensure/empty/case1/final/lock.toml b/cmd/dep/testdata/harness_tests/ensure/empty/case1/final/lock.toml new file mode 100644 index 0000000000..3897b39726 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/ensure/empty/case1/final/lock.toml @@ -0,0 +1,7 @@ +memo = "4b36ae008ef4be09dee7e2ae00606d44fd75f4310fd0d0ef6e744690290569de" + +[[projects]] + name = "github.com/sdboyer/deptest" + packages = ["."] + revision = "ff2948a2ac8f538c4ecd55962e919d1e13e74baf" + version = "v1.0.0" diff --git a/cmd/dep/testdata/harness_tests/ensure/empty/case1/final/manifest.json b/cmd/dep/testdata/harness_tests/ensure/empty/case1/final/manifest.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/cmd/dep/testdata/harness_tests/ensure/empty/case1/final/manifest.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/testdata/rootfind/manifest.json b/cmd/dep/testdata/harness_tests/ensure/empty/case1/final/manifest.toml similarity index 100% rename from testdata/rootfind/manifest.json rename to cmd/dep/testdata/harness_tests/ensure/empty/case1/final/manifest.toml diff --git a/cmd/dep/testdata/harness_tests/ensure/empty/case2/final/lock.json b/cmd/dep/testdata/harness_tests/ensure/empty/case2/final/lock.json deleted file mode 100644 index 21f628ed00..0000000000 --- a/cmd/dep/testdata/harness_tests/ensure/empty/case2/final/lock.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "memo": "e7725ea56516a42a641aaaf5d48754258d9f3c59949cb8a0e8a21b1ab6e07179", - "projects": [ - { - "name": "github.com/sdboyer/deptest", - "version": "v1.0.0", - "revision": "ff2948a2ac8f538c4ecd55962e919d1e13e74baf", - "packages": [ - "." - ] - } - ] -} diff --git a/cmd/dep/testdata/harness_tests/ensure/empty/case2/final/lock.toml b/cmd/dep/testdata/harness_tests/ensure/empty/case2/final/lock.toml new file mode 100644 index 0000000000..3c588e4d62 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/ensure/empty/case2/final/lock.toml @@ -0,0 +1,7 @@ +memo = "e7725ea56516a42a641aaaf5d48754258d9f3c59949cb8a0e8a21b1ab6e07179" + +[[projects]] + name = "github.com/sdboyer/deptest" + packages = ["."] + revision = "ff2948a2ac8f538c4ecd55962e919d1e13e74baf" + version = "v1.0.0" diff --git a/cmd/dep/testdata/harness_tests/ensure/empty/case2/final/manifest.json b/cmd/dep/testdata/harness_tests/ensure/empty/case2/final/manifest.json deleted file mode 100644 index 9b87ac9751..0000000000 --- a/cmd/dep/testdata/harness_tests/ensure/empty/case2/final/manifest.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "dependencies": { - "github.com/sdboyer/deptest": { - "version": "^0.8.0" - } - } -} diff --git a/cmd/dep/testdata/harness_tests/ensure/empty/case2/final/manifest.toml b/cmd/dep/testdata/harness_tests/ensure/empty/case2/final/manifest.toml new file mode 100644 index 0000000000..6deaa21764 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/ensure/empty/case2/final/manifest.toml @@ -0,0 +1,4 @@ + +[[dependencies]] + name = "github.com/sdboyer/deptest" + version = "^0.8.0" diff --git a/cmd/dep/testdata/harness_tests/ensure/empty/case2/initial/manifest.json b/cmd/dep/testdata/harness_tests/ensure/empty/case2/initial/manifest.json deleted file mode 100644 index dfc83c31bc..0000000000 --- a/cmd/dep/testdata/harness_tests/ensure/empty/case2/initial/manifest.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "dependencies": { - "github.com/sdboyer/deptest": { - "version": "~0.8.0" - } - } -} diff --git a/cmd/dep/testdata/harness_tests/ensure/empty/case2/initial/manifest.toml b/cmd/dep/testdata/harness_tests/ensure/empty/case2/initial/manifest.toml new file mode 100644 index 0000000000..d327c51ade --- /dev/null +++ b/cmd/dep/testdata/harness_tests/ensure/empty/case2/initial/manifest.toml @@ -0,0 +1,3 @@ +[[dependencies]] + name = "github.com/sdboyer/deptest" + version = "~0.8.0" \ No newline at end of file diff --git a/cmd/dep/testdata/harness_tests/ensure/override/case1/final/lock.json b/cmd/dep/testdata/harness_tests/ensure/override/case1/final/lock.json deleted file mode 100644 index 71cd0988aa..0000000000 --- a/cmd/dep/testdata/harness_tests/ensure/override/case1/final/lock.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "memo": "8bca9526e654e56e05d9075d1f33fa5b649bf6d58aa7d71ca39e7fbea8468e07", - "projects": [ - { - "name": "github.com/sdboyer/deptest", - "version": "v1.0.0", - "revision": "ff2948a2ac8f538c4ecd55962e919d1e13e74baf", - "packages": [ - "." - ] - } - ] -} diff --git a/cmd/dep/testdata/harness_tests/ensure/override/case1/final/lock.toml b/cmd/dep/testdata/harness_tests/ensure/override/case1/final/lock.toml new file mode 100644 index 0000000000..e045b6b22c --- /dev/null +++ b/cmd/dep/testdata/harness_tests/ensure/override/case1/final/lock.toml @@ -0,0 +1,7 @@ +memo = "8bca9526e654e56e05d9075d1f33fa5b649bf6d58aa7d71ca39e7fbea8468e07" + +[[projects]] + name = "github.com/sdboyer/deptest" + packages = ["."] + revision = "ff2948a2ac8f538c4ecd55962e919d1e13e74baf" + version = "v1.0.0" diff --git a/cmd/dep/testdata/harness_tests/ensure/override/case1/final/manifest.json b/cmd/dep/testdata/harness_tests/ensure/override/case1/final/manifest.json deleted file mode 100644 index 9ce6e06136..0000000000 --- a/cmd/dep/testdata/harness_tests/ensure/override/case1/final/manifest.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "overrides": { - "github.com/sdboyer/deptest": { - "version": "1.0.0" - } - } -} diff --git a/cmd/dep/testdata/harness_tests/ensure/override/case1/final/manifest.toml b/cmd/dep/testdata/harness_tests/ensure/override/case1/final/manifest.toml new file mode 100644 index 0000000000..7f784a4c56 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/ensure/override/case1/final/manifest.toml @@ -0,0 +1,4 @@ + +[[overrides]] + name = "github.com/sdboyer/deptest" + version = "1.0.0" diff --git a/cmd/dep/testdata/harness_tests/ensure/update/case1/final/lock.json b/cmd/dep/testdata/harness_tests/ensure/update/case1/final/lock.json deleted file mode 100644 index f54aca1056..0000000000 --- a/cmd/dep/testdata/harness_tests/ensure/update/case1/final/lock.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "memo": "1b381263a360eafafe3ef7f9be626672668d17250a3c9a8debd169d1b5e2eebb", - "projects": [ - { - "name": "github.com/sdboyer/deptest", - "version": "v1.0.0", - "revision": "ff2948a2ac8f538c4ecd55962e919d1e13e74baf", - "packages": [ - "." - ] - }, - { - "name": "github.com/sdboyer/deptestdos", - "version": "v2.0.0", - "revision": "5c607206be5decd28e6263ffffdcee067266015e", - "packages": [ - "." - ] - } - ] -} diff --git a/cmd/dep/testdata/harness_tests/ensure/update/case1/final/lock.toml b/cmd/dep/testdata/harness_tests/ensure/update/case1/final/lock.toml new file mode 100644 index 0000000000..b808a70fc4 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/ensure/update/case1/final/lock.toml @@ -0,0 +1,13 @@ +memo = "1b381263a360eafafe3ef7f9be626672668d17250a3c9a8debd169d1b5e2eebb" + +[[projects]] + name = "github.com/sdboyer/deptest" + packages = ["."] + revision = "ff2948a2ac8f538c4ecd55962e919d1e13e74baf" + version = "v1.0.0" + +[[projects]] + name = "github.com/sdboyer/deptestdos" + packages = ["."] + revision = "5c607206be5decd28e6263ffffdcee067266015e" + version = "v2.0.0" diff --git a/cmd/dep/testdata/harness_tests/ensure/update/case1/final/manifest.json b/cmd/dep/testdata/harness_tests/ensure/update/case1/final/manifest.json deleted file mode 100644 index dfc83c31bc..0000000000 --- a/cmd/dep/testdata/harness_tests/ensure/update/case1/final/manifest.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "dependencies": { - "github.com/sdboyer/deptest": { - "version": "~0.8.0" - } - } -} diff --git a/cmd/dep/testdata/harness_tests/ensure/update/case1/final/manifest.toml b/cmd/dep/testdata/harness_tests/ensure/update/case1/final/manifest.toml new file mode 100644 index 0000000000..d327c51ade --- /dev/null +++ b/cmd/dep/testdata/harness_tests/ensure/update/case1/final/manifest.toml @@ -0,0 +1,3 @@ +[[dependencies]] + name = "github.com/sdboyer/deptest" + version = "~0.8.0" \ No newline at end of file diff --git a/cmd/dep/testdata/harness_tests/ensure/update/case1/initial/lock.json b/cmd/dep/testdata/harness_tests/ensure/update/case1/initial/lock.json deleted file mode 100644 index 47cfd344d7..0000000000 --- a/cmd/dep/testdata/harness_tests/ensure/update/case1/initial/lock.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "memo": "9a5243dd3fa20feeaa20398e7283d6c566532e2af1aae279a010df34793761c5", - "projects": [ - { - "name": "github.com/sdboyer/deptest", - "version": "v0.8.0", - "revision": "ff2948a2ac8f538c4ecd55962e919d1e13e74baf", - "packages": [ - "." - ] - }, - { - "name": "github.com/sdboyer/deptestdos", - "version": "v2.0.0", - "revision": "5c607206be5decd28e6263ffffdcee067266015e", - "packages": [ - "." - ] - } - ] -} diff --git a/cmd/dep/testdata/harness_tests/ensure/update/case1/initial/lock.toml b/cmd/dep/testdata/harness_tests/ensure/update/case1/initial/lock.toml new file mode 100644 index 0000000000..04268862a1 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/ensure/update/case1/initial/lock.toml @@ -0,0 +1,13 @@ +memo = "9a5243dd3fa20feeaa20398e7283d6c566532e2af1aae279a010df34793761c5" + +[[projects]] + name = "github.com/sdboyer/deptest" + version = "v0.8.0" + revision = "ff2948a2ac8f538c4ecd55962e919d1e13e74baf" + packages = ["."] + +[[projects]] + name = "github.com/sdboyer/deptestdos" + version = "v2.0.0" + revision = "5c607206be5decd28e6263ffffdcee067266015e" + packages = ["."] diff --git a/cmd/dep/testdata/harness_tests/ensure/update/case1/initial/manifest.json b/cmd/dep/testdata/harness_tests/ensure/update/case1/initial/manifest.json deleted file mode 100644 index dfc83c31bc..0000000000 --- a/cmd/dep/testdata/harness_tests/ensure/update/case1/initial/manifest.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "dependencies": { - "github.com/sdboyer/deptest": { - "version": "~0.8.0" - } - } -} diff --git a/cmd/dep/testdata/harness_tests/ensure/update/case1/initial/manifest.toml b/cmd/dep/testdata/harness_tests/ensure/update/case1/initial/manifest.toml new file mode 100644 index 0000000000..d327c51ade --- /dev/null +++ b/cmd/dep/testdata/harness_tests/ensure/update/case1/initial/manifest.toml @@ -0,0 +1,3 @@ +[[dependencies]] + name = "github.com/sdboyer/deptest" + version = "~0.8.0" \ No newline at end of file diff --git a/cmd/dep/testdata/harness_tests/ensure/update/case2/final/lock.json b/cmd/dep/testdata/harness_tests/ensure/update/case2/final/lock.json deleted file mode 100644 index 47cfd344d7..0000000000 --- a/cmd/dep/testdata/harness_tests/ensure/update/case2/final/lock.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "memo": "9a5243dd3fa20feeaa20398e7283d6c566532e2af1aae279a010df34793761c5", - "projects": [ - { - "name": "github.com/sdboyer/deptest", - "version": "v0.8.0", - "revision": "ff2948a2ac8f538c4ecd55962e919d1e13e74baf", - "packages": [ - "." - ] - }, - { - "name": "github.com/sdboyer/deptestdos", - "version": "v2.0.0", - "revision": "5c607206be5decd28e6263ffffdcee067266015e", - "packages": [ - "." - ] - } - ] -} diff --git a/cmd/dep/testdata/harness_tests/ensure/update/case2/final/lock.toml b/cmd/dep/testdata/harness_tests/ensure/update/case2/final/lock.toml new file mode 100644 index 0000000000..362b3ce3c1 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/ensure/update/case2/final/lock.toml @@ -0,0 +1,13 @@ +memo = "9a5243dd3fa20feeaa20398e7283d6c566532e2af1aae279a010df34793761c5" + +[[projects]] + name = "github.com/sdboyer/deptest" + version = "v0.8.0" + revision = "ff2948a2ac8f538c4ecd55962e919d1e13e74baf" + packages = ["."] + +[[projects]] + name = "github.com/sdboyer/deptestdos" + version = "v2.0.0" + revision = "5c607206be5decd28e6263ffffdcee067266015e" + packages = ["."] diff --git a/cmd/dep/testdata/harness_tests/ensure/update/case2/final/manifest.json b/cmd/dep/testdata/harness_tests/ensure/update/case2/final/manifest.json deleted file mode 100644 index dfc83c31bc..0000000000 --- a/cmd/dep/testdata/harness_tests/ensure/update/case2/final/manifest.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "dependencies": { - "github.com/sdboyer/deptest": { - "version": "~0.8.0" - } - } -} diff --git a/cmd/dep/testdata/harness_tests/ensure/update/case2/final/manifest.toml b/cmd/dep/testdata/harness_tests/ensure/update/case2/final/manifest.toml new file mode 100644 index 0000000000..d327c51ade --- /dev/null +++ b/cmd/dep/testdata/harness_tests/ensure/update/case2/final/manifest.toml @@ -0,0 +1,3 @@ +[[dependencies]] + name = "github.com/sdboyer/deptest" + version = "~0.8.0" \ No newline at end of file diff --git a/cmd/dep/testdata/harness_tests/ensure/update/case2/initial/lock.json b/cmd/dep/testdata/harness_tests/ensure/update/case2/initial/lock.json deleted file mode 100644 index 47cfd344d7..0000000000 --- a/cmd/dep/testdata/harness_tests/ensure/update/case2/initial/lock.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "memo": "9a5243dd3fa20feeaa20398e7283d6c566532e2af1aae279a010df34793761c5", - "projects": [ - { - "name": "github.com/sdboyer/deptest", - "version": "v0.8.0", - "revision": "ff2948a2ac8f538c4ecd55962e919d1e13e74baf", - "packages": [ - "." - ] - }, - { - "name": "github.com/sdboyer/deptestdos", - "version": "v2.0.0", - "revision": "5c607206be5decd28e6263ffffdcee067266015e", - "packages": [ - "." - ] - } - ] -} diff --git a/cmd/dep/testdata/harness_tests/ensure/update/case2/initial/lock.toml b/cmd/dep/testdata/harness_tests/ensure/update/case2/initial/lock.toml new file mode 100644 index 0000000000..362b3ce3c1 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/ensure/update/case2/initial/lock.toml @@ -0,0 +1,13 @@ +memo = "9a5243dd3fa20feeaa20398e7283d6c566532e2af1aae279a010df34793761c5" + +[[projects]] + name = "github.com/sdboyer/deptest" + version = "v0.8.0" + revision = "ff2948a2ac8f538c4ecd55962e919d1e13e74baf" + packages = ["."] + +[[projects]] + name = "github.com/sdboyer/deptestdos" + version = "v2.0.0" + revision = "5c607206be5decd28e6263ffffdcee067266015e" + packages = ["."] diff --git a/cmd/dep/testdata/harness_tests/ensure/update/case2/initial/manifest.json b/cmd/dep/testdata/harness_tests/ensure/update/case2/initial/manifest.json deleted file mode 100644 index dfc83c31bc..0000000000 --- a/cmd/dep/testdata/harness_tests/ensure/update/case2/initial/manifest.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "dependencies": { - "github.com/sdboyer/deptest": { - "version": "~0.8.0" - } - } -} diff --git a/cmd/dep/testdata/harness_tests/ensure/update/case2/initial/manifest.toml b/cmd/dep/testdata/harness_tests/ensure/update/case2/initial/manifest.toml new file mode 100644 index 0000000000..d327c51ade --- /dev/null +++ b/cmd/dep/testdata/harness_tests/ensure/update/case2/initial/manifest.toml @@ -0,0 +1,3 @@ +[[dependencies]] + name = "github.com/sdboyer/deptest" + version = "~0.8.0" \ No newline at end of file diff --git a/cmd/dep/testdata/harness_tests/init/case1/final/lock.json b/cmd/dep/testdata/harness_tests/init/case1/final/lock.json deleted file mode 100644 index 7d1ccffab4..0000000000 --- a/cmd/dep/testdata/harness_tests/init/case1/final/lock.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "memo": "", - "projects": [ - { - "name": "github.com/sdboyer/deptest", - "version": "v0.8.0", - "revision": "ff2948a2ac8f538c4ecd55962e919d1e13e74baf", - "packages": [ - "." - ] - }, - { - "name": "github.com/sdboyer/deptestdos", - "revision": "a0196baa11ea047dd65037287451d36b861b00ea", - "packages": [ - "." - ] - } - ] -} diff --git a/cmd/dep/testdata/harness_tests/init/case1/final/lock.toml b/cmd/dep/testdata/harness_tests/init/case1/final/lock.toml new file mode 100644 index 0000000000..20091c76a5 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/init/case1/final/lock.toml @@ -0,0 +1,12 @@ +memo = "" + +[[projects]] + name = "github.com/sdboyer/deptest" + packages = ["."] + revision = "ff2948a2ac8f538c4ecd55962e919d1e13e74baf" + version = "v0.8.0" + +[[projects]] + name = "github.com/sdboyer/deptestdos" + packages = ["."] + revision = "a0196baa11ea047dd65037287451d36b861b00ea" diff --git a/cmd/dep/testdata/harness_tests/init/case1/final/manifest.json b/cmd/dep/testdata/harness_tests/init/case1/final/manifest.json deleted file mode 100644 index edbbfc579e..0000000000 --- a/cmd/dep/testdata/harness_tests/init/case1/final/manifest.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "dependencies": { - "github.com/sdboyer/deptest": { - "version": ">=0.8.0, <1.0.0" - }, - "github.com/sdboyer/deptestdos": { - "revision": "a0196baa11ea047dd65037287451d36b861b00ea" - } - } -} diff --git a/cmd/dep/testdata/harness_tests/init/case1/final/manifest.toml b/cmd/dep/testdata/harness_tests/init/case1/final/manifest.toml new file mode 100644 index 0000000000..05db85d196 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/init/case1/final/manifest.toml @@ -0,0 +1,8 @@ + +[[dependencies]] + name = "github.com/sdboyer/deptest" + version = ">=0.8.0, <1.0.0" + +[[dependencies]] + name = "github.com/sdboyer/deptestdos" + revision = "a0196baa11ea047dd65037287451d36b861b00ea" diff --git a/cmd/dep/testdata/harness_tests/init/case2/final/lock.json b/cmd/dep/testdata/harness_tests/init/case2/final/lock.json deleted file mode 100644 index 876df85036..0000000000 --- a/cmd/dep/testdata/harness_tests/init/case2/final/lock.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "memo": "88d2718cda70cce45158f953d2c6ead79c1db38e67e9704aff72be8fddb096e7", - "projects": [ - { - "name": "github.com/sdboyer/deptest", - "version": "v0.8.0", - "revision": "ff2948a2ac8f538c4ecd55962e919d1e13e74baf", - "packages": [ - "." - ] - }, - { - "name": "github.com/sdboyer/deptestdos", - "version": "v2.0.0", - "revision": "5c607206be5decd28e6263ffffdcee067266015e", - "packages": [ - "." - ] - } - ] -} diff --git a/cmd/dep/testdata/harness_tests/init/case2/final/lock.toml b/cmd/dep/testdata/harness_tests/init/case2/final/lock.toml new file mode 100644 index 0000000000..9b7e4cbf29 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/init/case2/final/lock.toml @@ -0,0 +1,13 @@ +memo = "88d2718cda70cce45158f953d2c6ead79c1db38e67e9704aff72be8fddb096e7" + +[[projects]] + name = "github.com/sdboyer/deptest" + packages = ["."] + revision = "ff2948a2ac8f538c4ecd55962e919d1e13e74baf" + version = "v0.8.0" + +[[projects]] + name = "github.com/sdboyer/deptestdos" + packages = ["."] + revision = "5c607206be5decd28e6263ffffdcee067266015e" + version = "v2.0.0" diff --git a/cmd/dep/testdata/harness_tests/init/case2/final/manifest.json b/cmd/dep/testdata/harness_tests/init/case2/final/manifest.json deleted file mode 100644 index b3046136e3..0000000000 --- a/cmd/dep/testdata/harness_tests/init/case2/final/manifest.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "dependencies": { - "github.com/sdboyer/deptest": { - "version": ">=0.8.0, <1.0.0" - } - } -} diff --git a/cmd/dep/testdata/harness_tests/init/case2/final/manifest.toml b/cmd/dep/testdata/harness_tests/init/case2/final/manifest.toml new file mode 100644 index 0000000000..a5284b92c0 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/init/case2/final/manifest.toml @@ -0,0 +1,4 @@ + +[[dependencies]] + name = "github.com/sdboyer/deptest" + version = ">=0.8.0, <1.0.0" diff --git a/cmd/dep/testdata/harness_tests/init/case3/final/lock.json b/cmd/dep/testdata/harness_tests/init/case3/final/lock.json deleted file mode 100644 index 0552e42c05..0000000000 --- a/cmd/dep/testdata/harness_tests/init/case3/final/lock.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "memo": "", - "projects": [ - { - "name": "github.com/sdboyer/deptest", - "branch": "master", - "revision": "3f4c3bea144e112a69bbe5d8d01c1b09a544253f", - "packages": [ - "." - ] - }, - { - "name": "github.com/sdboyer/deptestdos", - "revision": "a0196baa11ea047dd65037287451d36b861b00ea", - "packages": [ - "." - ] - } - ] -} diff --git a/cmd/dep/testdata/harness_tests/init/case3/final/lock.toml b/cmd/dep/testdata/harness_tests/init/case3/final/lock.toml new file mode 100644 index 0000000000..66d52b35ae --- /dev/null +++ b/cmd/dep/testdata/harness_tests/init/case3/final/lock.toml @@ -0,0 +1,12 @@ +memo = "" + +[[projects]] + branch = "master" + name = "github.com/sdboyer/deptest" + packages = ["."] + revision = "3f4c3bea144e112a69bbe5d8d01c1b09a544253f" + +[[projects]] + name = "github.com/sdboyer/deptestdos" + packages = ["."] + revision = "a0196baa11ea047dd65037287451d36b861b00ea" diff --git a/cmd/dep/testdata/harness_tests/init/case3/final/manifest.json b/cmd/dep/testdata/harness_tests/init/case3/final/manifest.json deleted file mode 100644 index 7d73f23995..0000000000 --- a/cmd/dep/testdata/harness_tests/init/case3/final/manifest.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "dependencies": { - "github.com/sdboyer/deptest": { - "branch": "master" - }, - "github.com/sdboyer/deptestdos": { - "revision": "a0196baa11ea047dd65037287451d36b861b00ea" - } - } -} diff --git a/cmd/dep/testdata/harness_tests/init/case3/final/manifest.toml b/cmd/dep/testdata/harness_tests/init/case3/final/manifest.toml new file mode 100644 index 0000000000..74acf5e6a6 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/init/case3/final/manifest.toml @@ -0,0 +1,8 @@ + +[[dependencies]] + branch = "master" + name = "github.com/sdboyer/deptest" + +[[dependencies]] + name = "github.com/sdboyer/deptestdos" + revision = "a0196baa11ea047dd65037287451d36b861b00ea" diff --git a/cmd/dep/testdata/harness_tests/init/skip-hidden/final/lock.json b/cmd/dep/testdata/harness_tests/init/skip-hidden/final/lock.json deleted file mode 100644 index 4af31ffe93..0000000000 --- a/cmd/dep/testdata/harness_tests/init/skip-hidden/final/lock.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "memo": "4b36ae008ef4be09dee7e2ae00606d44fd75f4310fd0d0ef6e744690290569de", - "projects": [ - { - "name": "github.com/sdboyer/deptest", - "version": "v1.0.0", - "revision": "ff2948a2ac8f538c4ecd55962e919d1e13e74baf", - "packages": [ - "." - ] - } - ] -} diff --git a/cmd/dep/testdata/harness_tests/init/skip-hidden/final/lock.toml b/cmd/dep/testdata/harness_tests/init/skip-hidden/final/lock.toml new file mode 100644 index 0000000000..3897b39726 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/init/skip-hidden/final/lock.toml @@ -0,0 +1,7 @@ +memo = "4b36ae008ef4be09dee7e2ae00606d44fd75f4310fd0d0ef6e744690290569de" + +[[projects]] + name = "github.com/sdboyer/deptest" + packages = ["."] + revision = "ff2948a2ac8f538c4ecd55962e919d1e13e74baf" + version = "v1.0.0" diff --git a/cmd/dep/testdata/harness_tests/init/skip-hidden/final/manifest.json b/cmd/dep/testdata/harness_tests/init/skip-hidden/final/manifest.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/cmd/dep/testdata/harness_tests/init/skip-hidden/final/manifest.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/cmd/dep/testdata/harness_tests/init/skip-hidden/final/manifest.toml b/cmd/dep/testdata/harness_tests/init/skip-hidden/final/manifest.toml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cmd/dep/testdata/harness_tests/remove/force/case1/final/lock.json b/cmd/dep/testdata/harness_tests/remove/force/case1/final/lock.json deleted file mode 100644 index 309f43cbe6..0000000000 --- a/cmd/dep/testdata/harness_tests/remove/force/case1/final/lock.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "memo": "88d2718cda70cce45158f953d2c6ead79c1db38e67e9704aff72be8fddb096e7", - "projects": [ - { - "name": "github.com/sdboyer/deptest", - "version": "v1.0.0", - "revision": "ff2948a2ac8f538c4ecd55962e919d1e13e74baf", - "packages": [ - "." - ] - }, - { - "name": "github.com/sdboyer/deptestdos", - "version": "v2.0.0", - "revision": "5c607206be5decd28e6263ffffdcee067266015e", - "packages": [ - "." - ] - } - ] -} diff --git a/cmd/dep/testdata/harness_tests/remove/force/case1/final/lock.toml b/cmd/dep/testdata/harness_tests/remove/force/case1/final/lock.toml new file mode 100644 index 0000000000..03b152c335 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/remove/force/case1/final/lock.toml @@ -0,0 +1,13 @@ +memo = "88d2718cda70cce45158f953d2c6ead79c1db38e67e9704aff72be8fddb096e7" + +[[projects]] + name = "github.com/sdboyer/deptest" + packages = ["."] + revision = "ff2948a2ac8f538c4ecd55962e919d1e13e74baf" + version = "v1.0.0" + +[[projects]] + name = "github.com/sdboyer/deptestdos" + packages = ["."] + revision = "5c607206be5decd28e6263ffffdcee067266015e" + version = "v2.0.0" diff --git a/cmd/dep/testdata/harness_tests/remove/force/case1/final/manifest.json b/cmd/dep/testdata/harness_tests/remove/force/case1/final/manifest.json deleted file mode 100644 index b3046136e3..0000000000 --- a/cmd/dep/testdata/harness_tests/remove/force/case1/final/manifest.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "dependencies": { - "github.com/sdboyer/deptest": { - "version": ">=0.8.0, <1.0.0" - } - } -} diff --git a/cmd/dep/testdata/harness_tests/remove/force/case1/final/manifest.toml b/cmd/dep/testdata/harness_tests/remove/force/case1/final/manifest.toml new file mode 100644 index 0000000000..a5284b92c0 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/remove/force/case1/final/manifest.toml @@ -0,0 +1,4 @@ + +[[dependencies]] + name = "github.com/sdboyer/deptest" + version = ">=0.8.0, <1.0.0" diff --git a/cmd/dep/testdata/harness_tests/remove/force/case1/initial/manifest.json b/cmd/dep/testdata/harness_tests/remove/force/case1/initial/manifest.json deleted file mode 100644 index 25d5d51ffa..0000000000 --- a/cmd/dep/testdata/harness_tests/remove/force/case1/initial/manifest.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "dependencies": { - "github.com/not/used": { - "version": "2.0.0" - }, - "github.com/sdboyer/deptest": { - "version": ">=0.8.0, <1.0.0" - }, - "github.com/sdboyer/deptestdos": { - "revision": "a0196baa11ea047dd65037287451d36b861b00ea" - } - } -} diff --git a/cmd/dep/testdata/harness_tests/remove/force/case1/initial/manifest.toml b/cmd/dep/testdata/harness_tests/remove/force/case1/initial/manifest.toml new file mode 100644 index 0000000000..413feb4eb0 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/remove/force/case1/initial/manifest.toml @@ -0,0 +1,11 @@ +[[dependencies]] + name = "github.com/not/used" + version = "2.0.0" + +[[dependencies]] + name = "github.com/sdboyer/deptest" + version = ">=0.8.0, <1.0.0" + +[[dependencies]] + name = "github.com/sdboyer/deptestdos" + revision = "a0196baa11ea047dd65037287451d36b861b00ea" diff --git a/cmd/dep/testdata/harness_tests/remove/specific/case1/final/lock.json b/cmd/dep/testdata/harness_tests/remove/specific/case1/final/lock.json deleted file mode 100644 index 8563f21501..0000000000 --- a/cmd/dep/testdata/harness_tests/remove/specific/case1/final/lock.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "memo": "d414dbf5fc668c1085effa68372d02e54b23d058cc66f9fd19ba094c6a946d9b", - "projects": [ - { - "name": "github.com/sdboyer/deptest", - "version": "v1.0.0", - "revision": "ff2948a2ac8f538c4ecd55962e919d1e13e74baf", - "packages": [ - "." - ] - }, - { - "name": "github.com/sdboyer/deptestdos", - "revision": "a0196baa11ea047dd65037287451d36b861b00ea", - "packages": [ - "." - ] - } - ] -} diff --git a/cmd/dep/testdata/harness_tests/remove/specific/case1/final/lock.toml b/cmd/dep/testdata/harness_tests/remove/specific/case1/final/lock.toml new file mode 100644 index 0000000000..89372cc518 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/remove/specific/case1/final/lock.toml @@ -0,0 +1,12 @@ +memo = "d414dbf5fc668c1085effa68372d02e54b23d058cc66f9fd19ba094c6a946d9b" + +[[projects]] + name = "github.com/sdboyer/deptest" + packages = ["."] + revision = "ff2948a2ac8f538c4ecd55962e919d1e13e74baf" + version = "v1.0.0" + +[[projects]] + name = "github.com/sdboyer/deptestdos" + packages = ["."] + revision = "a0196baa11ea047dd65037287451d36b861b00ea" diff --git a/cmd/dep/testdata/harness_tests/remove/specific/case1/final/manifest.json b/cmd/dep/testdata/harness_tests/remove/specific/case1/final/manifest.json deleted file mode 100644 index edbbfc579e..0000000000 --- a/cmd/dep/testdata/harness_tests/remove/specific/case1/final/manifest.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "dependencies": { - "github.com/sdboyer/deptest": { - "version": ">=0.8.0, <1.0.0" - }, - "github.com/sdboyer/deptestdos": { - "revision": "a0196baa11ea047dd65037287451d36b861b00ea" - } - } -} diff --git a/cmd/dep/testdata/harness_tests/remove/specific/case1/final/manifest.toml b/cmd/dep/testdata/harness_tests/remove/specific/case1/final/manifest.toml new file mode 100644 index 0000000000..05db85d196 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/remove/specific/case1/final/manifest.toml @@ -0,0 +1,8 @@ + +[[dependencies]] + name = "github.com/sdboyer/deptest" + version = ">=0.8.0, <1.0.0" + +[[dependencies]] + name = "github.com/sdboyer/deptestdos" + revision = "a0196baa11ea047dd65037287451d36b861b00ea" diff --git a/cmd/dep/testdata/harness_tests/remove/specific/case1/initial/manifest.json b/cmd/dep/testdata/harness_tests/remove/specific/case1/initial/manifest.json deleted file mode 100644 index 25d5d51ffa..0000000000 --- a/cmd/dep/testdata/harness_tests/remove/specific/case1/initial/manifest.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "dependencies": { - "github.com/not/used": { - "version": "2.0.0" - }, - "github.com/sdboyer/deptest": { - "version": ">=0.8.0, <1.0.0" - }, - "github.com/sdboyer/deptestdos": { - "revision": "a0196baa11ea047dd65037287451d36b861b00ea" - } - } -} diff --git a/cmd/dep/testdata/harness_tests/remove/specific/case1/initial/manifest.toml b/cmd/dep/testdata/harness_tests/remove/specific/case1/initial/manifest.toml new file mode 100644 index 0000000000..26653704de --- /dev/null +++ b/cmd/dep/testdata/harness_tests/remove/specific/case1/initial/manifest.toml @@ -0,0 +1,11 @@ +[[dependencies]] + name = "github.com/not/used" + version = "2.0.0" + +[[dependencies]] +name = "github.com/sdboyer/deptest" + version = ">=0.8.0, <1.0.0" + +[[dependencies]] +name = "github.com/sdboyer/deptestdos" + revision = "a0196baa11ea047dd65037287451d36b861b00ea" \ No newline at end of file diff --git a/cmd/dep/testdata/harness_tests/remove/specific/case2/final/lock.json b/cmd/dep/testdata/harness_tests/remove/specific/case2/final/lock.json deleted file mode 100644 index 1764a031d8..0000000000 --- a/cmd/dep/testdata/harness_tests/remove/specific/case2/final/lock.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "memo": "38d8431865759ee3bf28fbdfc464f98ee8b56319394ec717df45e9969544cfca", - "projects": [ - { - "name": "github.com/sdboyer/deptest", - "version": "v1.0.0", - "revision": "ff2948a2ac8f538c4ecd55962e919d1e13e74baf", - "packages": [ - "." - ] - } - ] -} diff --git a/cmd/dep/testdata/harness_tests/remove/specific/case2/final/lock.toml b/cmd/dep/testdata/harness_tests/remove/specific/case2/final/lock.toml new file mode 100644 index 0000000000..cb091e429d --- /dev/null +++ b/cmd/dep/testdata/harness_tests/remove/specific/case2/final/lock.toml @@ -0,0 +1,7 @@ +memo = "38d8431865759ee3bf28fbdfc464f98ee8b56319394ec717df45e9969544cfca" + +[[projects]] + name = "github.com/sdboyer/deptest" + packages = ["."] + revision = "ff2948a2ac8f538c4ecd55962e919d1e13e74baf" + version = "v1.0.0" diff --git a/cmd/dep/testdata/harness_tests/remove/specific/case2/final/manifest.json b/cmd/dep/testdata/harness_tests/remove/specific/case2/final/manifest.json deleted file mode 100644 index edbbfc579e..0000000000 --- a/cmd/dep/testdata/harness_tests/remove/specific/case2/final/manifest.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "dependencies": { - "github.com/sdboyer/deptest": { - "version": ">=0.8.0, <1.0.0" - }, - "github.com/sdboyer/deptestdos": { - "revision": "a0196baa11ea047dd65037287451d36b861b00ea" - } - } -} diff --git a/cmd/dep/testdata/harness_tests/remove/specific/case2/final/manifest.toml b/cmd/dep/testdata/harness_tests/remove/specific/case2/final/manifest.toml new file mode 100644 index 0000000000..05db85d196 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/remove/specific/case2/final/manifest.toml @@ -0,0 +1,8 @@ + +[[dependencies]] + name = "github.com/sdboyer/deptest" + version = ">=0.8.0, <1.0.0" + +[[dependencies]] + name = "github.com/sdboyer/deptestdos" + revision = "a0196baa11ea047dd65037287451d36b861b00ea" diff --git a/cmd/dep/testdata/harness_tests/remove/specific/case2/initial/manifest.json b/cmd/dep/testdata/harness_tests/remove/specific/case2/initial/manifest.json deleted file mode 100644 index 25d5d51ffa..0000000000 --- a/cmd/dep/testdata/harness_tests/remove/specific/case2/initial/manifest.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "dependencies": { - "github.com/not/used": { - "version": "2.0.0" - }, - "github.com/sdboyer/deptest": { - "version": ">=0.8.0, <1.0.0" - }, - "github.com/sdboyer/deptestdos": { - "revision": "a0196baa11ea047dd65037287451d36b861b00ea" - } - } -} diff --git a/cmd/dep/testdata/harness_tests/remove/specific/case2/initial/manifest.toml b/cmd/dep/testdata/harness_tests/remove/specific/case2/initial/manifest.toml new file mode 100644 index 0000000000..0bb0ab1d1b --- /dev/null +++ b/cmd/dep/testdata/harness_tests/remove/specific/case2/initial/manifest.toml @@ -0,0 +1,11 @@ +[[dependencies]] + name = "github.com/not/used" + version = "2.0.0" + +[[dependencies]] + name = "github.com/sdboyer/deptest" + version = ">=0.8.0, <1.0.0" + +[[dependencies]] + name = "github.com/sdboyer/deptestdos" + revision = "a0196baa11ea047dd65037287451d36b861b00ea" \ No newline at end of file diff --git a/cmd/dep/testdata/harness_tests/remove/unused/case1/final/lock.json b/cmd/dep/testdata/harness_tests/remove/unused/case1/final/lock.json deleted file mode 100644 index 8563f21501..0000000000 --- a/cmd/dep/testdata/harness_tests/remove/unused/case1/final/lock.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "memo": "d414dbf5fc668c1085effa68372d02e54b23d058cc66f9fd19ba094c6a946d9b", - "projects": [ - { - "name": "github.com/sdboyer/deptest", - "version": "v1.0.0", - "revision": "ff2948a2ac8f538c4ecd55962e919d1e13e74baf", - "packages": [ - "." - ] - }, - { - "name": "github.com/sdboyer/deptestdos", - "revision": "a0196baa11ea047dd65037287451d36b861b00ea", - "packages": [ - "." - ] - } - ] -} diff --git a/cmd/dep/testdata/harness_tests/remove/unused/case1/final/lock.toml b/cmd/dep/testdata/harness_tests/remove/unused/case1/final/lock.toml new file mode 100644 index 0000000000..89372cc518 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/remove/unused/case1/final/lock.toml @@ -0,0 +1,12 @@ +memo = "d414dbf5fc668c1085effa68372d02e54b23d058cc66f9fd19ba094c6a946d9b" + +[[projects]] + name = "github.com/sdboyer/deptest" + packages = ["."] + revision = "ff2948a2ac8f538c4ecd55962e919d1e13e74baf" + version = "v1.0.0" + +[[projects]] + name = "github.com/sdboyer/deptestdos" + packages = ["."] + revision = "a0196baa11ea047dd65037287451d36b861b00ea" diff --git a/cmd/dep/testdata/harness_tests/remove/unused/case1/final/manifest.json b/cmd/dep/testdata/harness_tests/remove/unused/case1/final/manifest.json deleted file mode 100644 index edbbfc579e..0000000000 --- a/cmd/dep/testdata/harness_tests/remove/unused/case1/final/manifest.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "dependencies": { - "github.com/sdboyer/deptest": { - "version": ">=0.8.0, <1.0.0" - }, - "github.com/sdboyer/deptestdos": { - "revision": "a0196baa11ea047dd65037287451d36b861b00ea" - } - } -} diff --git a/cmd/dep/testdata/harness_tests/remove/unused/case1/final/manifest.toml b/cmd/dep/testdata/harness_tests/remove/unused/case1/final/manifest.toml new file mode 100644 index 0000000000..05db85d196 --- /dev/null +++ b/cmd/dep/testdata/harness_tests/remove/unused/case1/final/manifest.toml @@ -0,0 +1,8 @@ + +[[dependencies]] + name = "github.com/sdboyer/deptest" + version = ">=0.8.0, <1.0.0" + +[[dependencies]] + name = "github.com/sdboyer/deptestdos" + revision = "a0196baa11ea047dd65037287451d36b861b00ea" diff --git a/cmd/dep/testdata/harness_tests/remove/unused/case1/initial/manifest.json b/cmd/dep/testdata/harness_tests/remove/unused/case1/initial/manifest.json deleted file mode 100644 index 25d5d51ffa..0000000000 --- a/cmd/dep/testdata/harness_tests/remove/unused/case1/initial/manifest.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "dependencies": { - "github.com/not/used": { - "version": "2.0.0" - }, - "github.com/sdboyer/deptest": { - "version": ">=0.8.0, <1.0.0" - }, - "github.com/sdboyer/deptestdos": { - "revision": "a0196baa11ea047dd65037287451d36b861b00ea" - } - } -} diff --git a/cmd/dep/testdata/harness_tests/remove/unused/case1/initial/manifest.toml b/cmd/dep/testdata/harness_tests/remove/unused/case1/initial/manifest.toml new file mode 100644 index 0000000000..0bb0ab1d1b --- /dev/null +++ b/cmd/dep/testdata/harness_tests/remove/unused/case1/initial/manifest.toml @@ -0,0 +1,11 @@ +[[dependencies]] + name = "github.com/not/used" + version = "2.0.0" + +[[dependencies]] + name = "github.com/sdboyer/deptest" + version = ">=0.8.0, <1.0.0" + +[[dependencies]] + name = "github.com/sdboyer/deptestdos" + revision = "a0196baa11ea047dd65037287451d36b861b00ea" \ No newline at end of file diff --git a/context_test.go b/context_test.go index e71c0a879d..634d6f1bf8 100644 --- a/context_test.go +++ b/context_test.go @@ -159,11 +159,11 @@ func TestLoadProject(t *testing.T) { tg.TempDir("src") tg.TempDir("src/test1") tg.TempDir("src/test1/sub") - tg.TempFile("src/test1/manifest.json", `{"dependencies":{}}`) - tg.TempFile("src/test1/lock.json", `{"memo":"cdafe8641b28cd16fe025df278b0a49b9416859345d8b6ba0ace0272b74925ee","projects":[]}`) + tg.TempFile("src/test1/manifest.toml", "") + tg.TempFile("src/test1/lock.toml", `memo = "cdafe8641b28cd16fe025df278b0a49b9416859345d8b6ba0ace0272b74925ee"`) tg.TempDir("src/test2") tg.TempDir("src/test2/sub") - tg.TempFile("src/test2/manifest.json", `{"dependencies":{}}`) + tg.TempFile("src/test2/manifest.toml", "") tg.Setenv("GOPATH", tg.Path(".")) var testcases = []struct { @@ -251,8 +251,8 @@ func TestLoadProjectManifestParseError(t *testing.T) { tg.TempDir("src") tg.TempDir("src/test1") - tg.TempFile("src/test1/manifest.json", ` "dependencies":{} `) - tg.TempFile("src/test1/lock.json", `{"memo":"cdafe8641b28cd16fe025df278b0a49b9416859345d8b6ba0ace0272b74925ee","projects":[]}`) + tg.TempFile("src/test1/manifest.toml", `[[dependencies]]`) + tg.TempFile("src/test1/lock.toml", `memo = "cdafe8641b28cd16fe025df278b0a49b9416859345d8b6ba0ace0272b74925ee"\n\n[[projects]]`) tg.Setenv("GOPATH", tg.Path(".")) ctx := &Ctx{GOPATH: tg.Path(".")} @@ -271,8 +271,8 @@ func TestLoadProjectLockParseError(t *testing.T) { tg.TempDir("src") tg.TempDir("src/test1") - tg.TempFile("src/test1/manifest.json", `{"dependencies":{}}`) - tg.TempFile("src/test1/lock.json", ` "memo":"cdafe8641b28cd16fe025df278b0a49b9416859345d8b6ba0ace0272b74925ee","projects":[] `) + tg.TempFile("src/test1/manifest.toml", `[[dependencies]]`) + tg.TempFile("src/test1/lock.toml", `memo = "cdafe8641b28cd16fe025df278b0a49b9416859345d8b6ba0ace0272b74925ee"\n\n[[projects]]`) tg.Setenv("GOPATH", tg.Path(".")) ctx := &Ctx{GOPATH: tg.Path(".")} @@ -290,15 +290,15 @@ func TestLoadProjectNoSrcDir(t *testing.T) { defer tg.Cleanup() tg.TempDir("test1") - tg.TempFile("test1/manifest.json", `{"dependencies":{}}`) - tg.TempFile("test1/lock.json", `{"memo":"cdafe8641b28cd16fe025df278b0a49b9416859345d8b6ba0ace0272b74925ee","projects":[]}`) + tg.TempFile("test1/manifest.toml", `[[dependencies]]`) + tg.TempFile("test1/lock.toml", `memo = "cdafe8641b28cd16fe025df278b0a49b9416859345d8b6ba0ace0272b74925ee"\n\n[[projects]]`) tg.Setenv("GOPATH", tg.Path(".")) ctx := &Ctx{GOPATH: tg.Path(".")} path := filepath.Join("test1") tg.Cd(tg.Path(path)) - f, _ := os.OpenFile(filepath.Join(ctx.GOPATH, "src", "test1", "lock.json"), os.O_WRONLY, os.ModePerm) + f, _ := os.OpenFile(filepath.Join(ctx.GOPATH, "src", "test1", "lock.toml"), os.O_WRONLY, os.ModePerm) defer f.Close() _, err := ctx.LoadProject("") @@ -319,7 +319,7 @@ func TestCaseInsentitiveGOPATH(t *testing.T) { h.TempDir("src") h.TempDir("src/test1") - h.TempFile("src/test1/manifest.json", ` "dependencies":{} `) + h.TempFile("src/test1/manifest.toml", `[[dependencies]]`) // Shuffle letter case rs := []rune(strings.ToLower(h.Path("."))) diff --git a/lock_test.go b/lock_test.go index 613e2290f5..ba61372666 100644 --- a/lock_test.go +++ b/lock_test.go @@ -18,7 +18,7 @@ func TestReadLock(t *testing.T) { h := test.NewHelper(t) defer h.Cleanup() - golden := "lock/golden0.json" + golden := "lock/golden0.toml" g0f := h.GetTestFile(golden) defer g0f.Close() got, err := readLock(g0f) @@ -42,7 +42,7 @@ func TestReadLock(t *testing.T) { t.Error("Valid lock did not parse as expected") } - golden = "lock/golden1.json" + golden = "lock/golden1.toml" g1f := h.GetTestFile(golden) defer g1f.Close() got, err = readLock(g1f) @@ -139,9 +139,9 @@ func TestReadLockErrors(t *testing.T) { name string file string }{ - {"specified both", "lock/error0.json"}, - {"invalid hash", "lock/error1.json"}, - {"no branch or version", "lock/error2.json"}, + {"specified both", "lock/error0.toml"}, + {"invalid hash", "lock/error1.toml"}, + {"no branch or version", "lock/error2.toml"}, } for _, tst := range tests { diff --git a/manifest_test.go b/manifest_test.go index 8bbfce9907..9304b814c0 100644 --- a/manifest_test.go +++ b/manifest_test.go @@ -17,7 +17,7 @@ func TestReadManifest(t *testing.T) { h := test.NewHelper(t) defer h.Cleanup() - mf := h.GetTestFile("manifest/golden.json") + mf := h.GetTestFile("manifest/golden.toml") defer mf.Close() got, err := readManifest(mf) if err != nil { @@ -104,7 +104,7 @@ func TestReadManifestErrors(t *testing.T) { name string file string }{ - {"multiple constraints", "manifest/error.json"}, + {"multiple constraints", "manifest/error.toml"}, } for _, tst := range tests { diff --git a/testdata/analyzer/manifest.json b/testdata/analyzer/manifest.json deleted file mode 100644 index b1d3c47733..0000000000 --- a/testdata/analyzer/manifest.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "dependencies": { - "github.com/pkg/errors": { - "version": ">=0.8.0, <1.0.0" - }, - "github.com/sdboyer/gps": { - "version": ">=0.12.0, <1.0.0" - } - } -} diff --git a/testdata/analyzer/manifest.toml b/testdata/analyzer/manifest.toml new file mode 100644 index 0000000000..c24d239d9a --- /dev/null +++ b/testdata/analyzer/manifest.toml @@ -0,0 +1,8 @@ + +[[dependencies]] + name = "github.com/pkg/errors" + version = ">=0.8.0, <1.0.0" + +[[dependencies]] + name = "github.com/sdboyer/gps" + version = ">=0.12.0, <1.0.0" diff --git a/testdata/lock/error0.json b/testdata/lock/error0.json deleted file mode 100644 index 6bb77cc9f2..0000000000 --- a/testdata/lock/error0.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "memo": "2252a285ab27944a4d7adcba8dbd03980f59ba652f12db39fa93b927c345593e", - "projects": [ - { - "name": "github.com/sdboyer/gps", - "branch": "master", - "version": "v0.12.0", - "revision": "d05d5aca9f895d19e9265839bffeadd74a2d2ecb", - "packages": [ - "." - ] - } - ] -} diff --git a/testdata/lock/error0.toml b/testdata/lock/error0.toml new file mode 100644 index 0000000000..2e5bc427ed --- /dev/null +++ b/testdata/lock/error0.toml @@ -0,0 +1,8 @@ +memo = "2252a285ab27944a4d7adcba8dbd03980f59ba652f12db39fa93b927c345593e" + +[[projects]] + name = "github.com/sdboyer/gps" + branch = "master" + version = "v0.12.0" + revision = "d05d5aca9f895d19e9265839bffeadd74a2d2ecb" + packages = ["."] diff --git a/testdata/lock/error1.json b/testdata/lock/error1.json deleted file mode 100644 index 0f47f0d90a..0000000000 --- a/testdata/lock/error1.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "memo": "000aaa2a285ab27944a4d7adcba8dbd03980f59ba652f12db39fa93b927c345593e", - "projects": [ - { - "name": "github.com/sdboyer/gps", - "branch": "master", - "revision": "d05d5aca9f895d19e9265839bffeadd74a2d2ecb", - "packages": [ - "." - ] - } - ] -} diff --git a/testdata/lock/error1.toml b/testdata/lock/error1.toml new file mode 100644 index 0000000000..fb20e9b39d --- /dev/null +++ b/testdata/lock/error1.toml @@ -0,0 +1,7 @@ +memo = "000aaa2a285ab27944a4d7adcba8dbd03980f59ba652f12db39fa93b927c345593e" + +[[projects]] + name = "github.com/sdboyer/gps" + branch = "master" + revision = "d05d5aca9f895d19e9265839bffeadd74a2d2ecb" + packages = ["."] diff --git a/testdata/lock/error2.json b/testdata/lock/error2.json deleted file mode 100644 index 429f922d7b..0000000000 --- a/testdata/lock/error2.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "memo": "2252a285ab27944a4d7adcba8dbd03980f59ba652f12db39fa93b927c345593e", - "projects": [ - { - "name": "github.com/sdboyer/gps", - "packages": [ - "." - ] - } - ] -} diff --git a/testdata/lock/error2.toml b/testdata/lock/error2.toml new file mode 100644 index 0000000000..7a38e96044 --- /dev/null +++ b/testdata/lock/error2.toml @@ -0,0 +1,5 @@ +memo = "2252a285ab27944a4d7adcba8dbd03980f59ba652f12db39fa93b927c345593e" + +[[projects]] + name = "github.com/sdboyer/gps" + packages = ["."] \ No newline at end of file diff --git a/testdata/lock/golden0.json b/testdata/lock/golden0.json deleted file mode 100644 index 540c612565..0000000000 --- a/testdata/lock/golden0.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "memo": "2252a285ab27944a4d7adcba8dbd03980f59ba652f12db39fa93b927c345593e", - "projects": [ - { - "name": "github.com/sdboyer/gps", - "branch": "master", - "revision": "d05d5aca9f895d19e9265839bffeadd74a2d2ecb", - "packages": [ - "." - ] - } - ] -} diff --git a/testdata/lock/golden1.json b/testdata/lock/golden1.json deleted file mode 100644 index 2eaeadd5ab..0000000000 --- a/testdata/lock/golden1.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "memo": "2252a285ab27944a4d7adcba8dbd03980f59ba652f12db39fa93b927c345593e", - "projects": [ - { - "name": "github.com/sdboyer/gps", - "version": "0.12.2", - "revision": "d05d5aca9f895d19e9265839bffeadd74a2d2ecb", - "packages": [ - "." - ] - } - ] -} diff --git a/testdata/manifest/error.json b/testdata/manifest/error.json deleted file mode 100644 index 33b6a9bb36..0000000000 --- a/testdata/manifest/error.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "dependencies": { - "github.com/sdboyer/gps": { - "branch": "master", - "revision": "d05d5aca9f895d19e9265839bffeadd74a2d2ecb", - "version": "^v0.12.0", - "source": "https://github.com/sdboyer/gps" - } - }, - "overrides": { - "github.com/sdboyer/gps": { - "branch": "master", - "revision": "d05d5aca9f895d19e9265839bffeadd74a2d2ecb", - "version": "^v0.12.0", - "source": "https://github.com/sdboyer/gps" - } - }, - "ignores": [ - "github.com/foo/bar" - ] -} diff --git a/testdata/manifest/error.toml b/testdata/manifest/error.toml new file mode 100644 index 0000000000..136beec05b --- /dev/null +++ b/testdata/manifest/error.toml @@ -0,0 +1,15 @@ +ignores = ["github.com/foo/bar"] + +[[dependencies]] + name = "github.com/sdboyer/gps" + branch = "master" + revision = "d05d5aca9f895d19e9265839bffeadd74a2d2ecb" + version = "^v0.12.0" + source = "https://github.com/sdboyer/gps" + +[[overrides]] + name = "github.com/sdboyer/gps" + branch = "master" + revision = "d05d5aca9f895d19e9265839bffeadd74a2d2ecb" + version = "^v0.12.0" + source = "https://github.com/sdboyer/gps" diff --git a/testdata/manifest/golden.json b/testdata/manifest/golden.json deleted file mode 100644 index b406d144f0..0000000000 --- a/testdata/manifest/golden.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "dependencies": { - "github.com/babble/brook": { - "revision": "d05d5aca9f895d19e9265839bffeadd74a2d2ecb" - }, - "github.com/sdboyer/gps": { - "version": ">=0.12.0, <1.0.0" - } - }, - "overrides": { - "github.com/sdboyer/gps": { - "branch": "master", - "source": "https://github.com/sdboyer/gps" - } - }, - "ignores": [ - "github.com/foo/bar" - ] -} diff --git a/testdata/rootfind/manifest.toml b/testdata/rootfind/manifest.toml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/testdata/txn_writer/expected_lock.json b/testdata/txn_writer/expected_lock.json deleted file mode 100644 index 40b8c8f836..0000000000 --- a/testdata/txn_writer/expected_lock.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "memo": "595716d270828e763c811ef79c9c41f85b1d1bfbdfe85280036405c03772206c", - "projects": [ - { - "name": "github.com/sdboyer/dep-test", - "version": "1.0.0", - "revision": "2a3a211e171803acb82d1d5d42ceb53228f51751", - "packages": [ - "." - ] - } - ] -} diff --git a/testdata/txn_writer/expected_manifest.json b/testdata/txn_writer/expected_manifest.json deleted file mode 100644 index 4ba1517ee1..0000000000 --- a/testdata/txn_writer/expected_manifest.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "dependencies": { - "github.com/sdboyer/dep-test": { - "version": "1.0.0" - } - } -} diff --git a/testdata/txn_writer/expected_manifest.toml b/testdata/txn_writer/expected_manifest.toml new file mode 100644 index 0000000000..d1057a0f57 --- /dev/null +++ b/testdata/txn_writer/expected_manifest.toml @@ -0,0 +1,4 @@ + +[[dependencies]] + name = "github.com/sdboyer/dep-test" + version = "1.0.0" diff --git a/testdata/txn_writer/original_lock.json b/testdata/txn_writer/original_lock.json deleted file mode 100644 index 6e0effd2e7..0000000000 --- a/testdata/txn_writer/original_lock.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "memo": "595716d270828e763c811ef79c9c41f85b1d1bfbdfe85280036405c03772206c", - "projects": [ - { - "name": "github.com/foo/bar", - "branch": "master", - "revision": "f24338400f072ef18125ae0fbe6b06fe6d1783e7", - "packages": [ - "placeholder", - "util" - ] - }, - { - "name": "github.com/stuff/placeholder", - "version": "2.0.0", - "revision": "6694017eeb4e20fd277b049bf29dba4895c97234", - "packages": [ - "." - ] - } - ] -} diff --git a/testdata/txn_writer/original_lock.toml b/testdata/txn_writer/original_lock.toml new file mode 100644 index 0000000000..512df734c7 --- /dev/null +++ b/testdata/txn_writer/original_lock.toml @@ -0,0 +1,13 @@ +memo = "595716d270828e763c811ef79c9c41f85b1d1bfbdfe85280036405c03772206c" + +[[projects]] + name = "github.com/foo/bar" + branch = "master" + revision = "f24338400f072ef18125ae0fbe6b06fe6d1783e7" + packages = ["placeholder", "util"] + +[[packages]] + name = "github.com/stuff/placeholder" + version = "2.0.0" + revision = "6694017eeb4e20fd277b049bf29dba4895c97234" + packages = ["."] diff --git a/testdata/txn_writer/updated_lock.json b/testdata/txn_writer/updated_lock.json deleted file mode 100644 index 91d801d458..0000000000 --- a/testdata/txn_writer/updated_lock.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "memo": "2252a285ab27944a4d7adcba8dbd03980f59ba652f12db39fa93b927c345593e", - "projects": [ - { - "name": "github.com/foo/bar", - "source": "http://github.example.com/foo/bar", - "version": "1.2.0", - "revision": "2a3a211e171803acb82d1d5d42ceb53228f51751", - "packages": [ - "thing", - "util" - ] - }, - { - "name": "github.com/stuff/realthing", - "version": "2.0.0", - "revision": "1f02e52d6bac308da54ab84a234c58a98ca82347", - "packages": [ - "." - ] - } - ] -} diff --git a/testdata/txn_writer/updated_lock.toml b/testdata/txn_writer/updated_lock.toml new file mode 100644 index 0000000000..028627cd3d --- /dev/null +++ b/testdata/txn_writer/updated_lock.toml @@ -0,0 +1,14 @@ +memo = "2252a285ab27944a4d7adcba8dbd03980f59ba652f12db39fa93b927c345593e" + +[[projects]] + name = "github.com/foo/bar" + source = "http://github.example.com/foo/bar" + version = "1.2.0" + revision = "2a3a211e171803acb82d1d5d42ceb53228f51751" + packages = ["thing","util"] + +[[packages]] + name = "github.com/stuff/realthing" + version = "2.0.0" + revision = "1f02e52d6bac308da54ab84a234c58a98ca82347" + packages = ["."] diff --git a/txn_writer_test.go b/txn_writer_test.go index 07aad9cb36..c0e569a21a 100644 --- a/txn_writer_test.go +++ b/txn_writer_test.go @@ -14,7 +14,7 @@ import ( ) const safeWriterProject = "safewritertest" -const safeWriterGoldenManifest = "txn_writer/expected_manifest.json" +const safeWriterGoldenManifest = "txn_writer/expected_manifest.toml" const safeWriterGoldenLock = "txn_writer/expected_lock.toml" func TestSafeWriter_BadInput_MissingRoot(t *testing.T) { @@ -498,10 +498,10 @@ func TestSafeWriter_DiffLocks(t *testing.T) { pc := NewTestProjectContext(h, safeWriterProject) defer pc.Release() - pc.CopyFile(LockName, "txn_writer/original_lock.json") + pc.CopyFile(LockName, "txn_writer/original_lock.toml") pc.Load() - ulf := h.GetTestFile("txn_writer/updated_lock.json") + ulf := h.GetTestFile("txn_writer/updated_lock.toml") defer ulf.Close() updatedLock, err := readLock(ulf) h.Must(err) From d82a114f1b678b51ba87c1b356616d25c3731a7f Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Tue, 21 Mar 2017 11:29:48 -0500 Subject: [PATCH 07/20] Update dep's own manifest and lock to TOML --- lock.json | 48 ------------------------------------------------ lock.toml | 42 ++++++++++++++++++++++++++++++++++++++++++ manifest.json | 16 ---------------- manifest.toml | 20 ++++++++++++++++++++ 4 files changed, 62 insertions(+), 64 deletions(-) delete mode 100644 lock.json create mode 100644 lock.toml delete mode 100644 manifest.json create mode 100644 manifest.toml diff --git a/lock.json b/lock.json deleted file mode 100644 index 070f270f20..0000000000 --- a/lock.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "memo": "31a7162c06758e4619ed89b91e1f48bf94ad14f394bbee79299ed0bb5150e409", - "projects": [ - { - "name": "github.com/Masterminds/semver", - "branch": "2.x", - "revision": "94ad6eaf8457cf85a68c9b53fa42e9b1b8683783", - "packages": [ - "." - ] - }, - { - "name": "github.com/Masterminds/vcs", - "version": "v1.11.0", - "revision": "795e20f901c3d561de52811fb3488a2cb2c8588b", - "packages": [ - "." - ] - }, - { - "name": "github.com/armon/go-radix", - "branch": "master", - "revision": "4239b77079c7b5d1243b7b4736304ce8ddb6f0f2", - "packages": [ - "." - ] - }, - { - "name": "github.com/pkg/errors", - "version": "v0.8.0", - "revision": "645ef00459ed84a119197bfb8d8205042c6df63d", - "packages": [ - "." - ] - }, - { - "name": "github.com/sdboyer/gps", - "version": "v0.15.0", - "revision": "b0f646b744e74543c094023d05339ffb82458e35", - "packages": [ - ".", - "internal", - "internal/fs", - "pkgtree" - ] - } - ] -} diff --git a/lock.toml b/lock.toml new file mode 100644 index 0000000000..c6a24bfc44 --- /dev/null +++ b/lock.toml @@ -0,0 +1,42 @@ +memo = "31a7162c06758e4619ed89b91e1f48bf94ad14f394bbee79299ed0bb5150e409" + +[[projects]] + branch = "2.x" + name = "github.com/Masterminds/semver" + packages = ["."] + revision = "94ad6eaf8457cf85a68c9b53fa42e9b1b8683783" + +[[projects]] + name = "github.com/Masterminds/vcs" + packages = ["."] + revision = "fbe9fb6ad5b5f35b3e82a7c21123cfc526cbf895" + version = "v1.11.0" + +[[projects]] + branch = "master" + name = "github.com/armon/go-radix" + packages = ["."] + revision = "4239b77079c7b5d1243b7b4736304ce8ddb6f0f2" + +[[projects]] + name = "github.com/pelletier/go-buffruneio" + packages = ["."] + revision = "c37440a7cf42ac63b919c752ca73a85067e05992" + version = "v0.2.0" + +[[projects]] + name = "github.com/pelletier/go-toml" + revision = "fee7787d3f811af92276f5ff10107092e95b7a1d" + packages = ["."] + +[[projects]] + name = "github.com/pkg/errors" + packages = ["."] + revision = "645ef00459ed84a119197bfb8d8205042c6df63d" + version = "v0.8.0" + +[[projects]] + name = "github.com/sdboyer/gps" + packages = [".","internal","internal/fs","pkgtree"] + revision = "b0f646b744e74543c094023d05339ffb82458e35" + version = "v0.15.0" diff --git a/manifest.json b/manifest.json deleted file mode 100644 index fdbed6a4d1..0000000000 --- a/manifest.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "dependencies": { - "github.com/Masterminds/semver": { - "branch": "2.x" - }, - "github.com/Masterminds/vcs": { - "version": "^1.8.0" - }, - "github.com/pkg/errors": { - "version": ">=0.8.0, <1.0.0" - }, - "github.com/sdboyer/gps": { - "version": ">=0.15.0, <1.0.0" - } - } -} diff --git a/manifest.toml b/manifest.toml new file mode 100644 index 0000000000..44a51fa4f8 --- /dev/null +++ b/manifest.toml @@ -0,0 +1,20 @@ + +[[dependencies]] + branch = "2.x" + name = "github.com/Masterminds/semver" + +[[dependencies]] + name = "github.com/Masterminds/vcs" + version = "^1.8.0" + +[[dependencies]] + name = "github.com/pelletier/go-toml" + revision = "fee7787d3f811af92276f5ff10107092e95b7a1d" + +[[dependencies]] + name = "github.com/pkg/errors" + version = ">=0.8.0, <1.0.0" + +[[dependencies]] + name = "github.com/sdboyer/gps" + version = ">=0.15.0, <1.0.0" From 56476c3d49c3304d14088054de98862ed47114c7 Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Tue, 21 Mar 2017 11:33:45 -0500 Subject: [PATCH 08/20] Remove JSON marshaling for lock and manifest --- lock.go | 29 ++++++++--------------------- manifest.go | 35 +++++++++++------------------------ 2 files changed, 19 insertions(+), 45 deletions(-) diff --git a/lock.go b/lock.go index 72c5b0d588..e6bc5de723 100644 --- a/lock.go +++ b/lock.go @@ -5,7 +5,6 @@ package dep import ( - "bytes" "encoding/hex" "encoding/json" "io" @@ -24,17 +23,17 @@ type Lock struct { } type rawLock struct { - Memo string `json:"memo"` - P []lockedDep `json:"projects"` + Memo string + P []lockedDep } type lockedDep struct { - Name string `json:"name"` - Version string `json:"version,omitempty"` - Branch string `json:"branch,omitempty"` - Revision string `json:"revision"` - Source string `json:"source,omitempty"` - Packages []string `json:"packages"` + Name string + Version string + Branch string + Revision string + Source string + Packages []string } func readLock(r io.Reader) (*Lock, error) { @@ -114,18 +113,6 @@ func (l *Lock) toRaw() rawLock { return raw } -func (l *Lock) MarshalJSON() ([]byte, error) { - raw := l.toRaw() - - var buf bytes.Buffer - enc := json.NewEncoder(&buf) - enc.SetIndent("", " ") - enc.SetEscapeHTML(false) - err := enc.Encode(raw) - - return buf.Bytes(), err -} - func (l *Lock) MarshalTOML() (string, error) { raw := l.toRaw() diff --git a/manifest.go b/manifest.go index e890a15370..6106d64ee1 100644 --- a/manifest.go +++ b/manifest.go @@ -5,7 +5,6 @@ package dep import ( - "bytes" "encoding/json" "io" @@ -24,17 +23,10 @@ type Manifest struct { } type rawManifest struct { - Dependencies map[string]possibleProps `json:"dependencies,omitempty"` - Overrides map[string]possibleProps `json:"overrides,omitempty"` - Ignores []string `json:"ignores,omitempty"` - Required []string `json:"required,omitempty"` -} - -type possibleProps struct { - Branch string `json:"branch,omitempty"` - Revision string `json:"revision,omitempty"` - Version string `json:"version,omitempty"` - Source string `json:"source,omitempty"` + Dependencies map[string]possibleProps + Overrides map[string]possibleProps + Ignores []string + Required []string } func newRawManifest() rawManifest { @@ -46,6 +38,13 @@ func newRawManifest() rawManifest { } } +type possibleProps struct { + Branch string + Revision string + Version string + Source string +} + func readManifest(r io.Reader) (*Manifest, error) { rm := rawManifest{} err := json.NewDecoder(r).Decode(&rm) @@ -126,18 +125,6 @@ func (m *Manifest) toRaw() rawManifest { return raw } -func (m *Manifest) MarshalJSON() ([]byte, error) { - raw := m.toRaw() - - var buf bytes.Buffer - enc := json.NewEncoder(&buf) - enc.SetIndent("", " ") - enc.SetEscapeHTML(false) - err := enc.Encode(raw) - - return buf.Bytes(), err -} - func (m *Manifest) MarshalTOML() (string, error) { raw := m.toRaw() From 28c2316fba50b0c94423fa48a3ad47084b84e139 Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Tue, 21 Mar 2017 14:53:53 -0500 Subject: [PATCH 09/20] Map manifest and lock TOML to structs This is a bit of a poor man's TOML mapping while we wait for go-toml to get reflection-based mapping implemented. --- lock.go | 55 ++++++---- manifest.go | 193 ++++++++++++++++++++-------------- testdata/manifest/golden.toml | 8 +- toml.go | 177 +++++++++++++++++++++++++++++++ 4 files changed, 328 insertions(+), 105 deletions(-) create mode 100644 toml.go diff --git a/lock.go b/lock.go index e6bc5de723..46dc2bff69 100644 --- a/lock.go +++ b/lock.go @@ -6,7 +6,6 @@ package dep import ( "encoding/hex" - "encoding/json" "io" "sort" @@ -23,36 +22,50 @@ type Lock struct { } type rawLock struct { - Memo string - P []lockedDep + Memo string + Projects []rawLockedProject } -type lockedDep struct { +type rawLockedProject struct { Name string - Version string Branch string Revision string + Version string Source string Packages []string } func readLock(r io.Reader) (*Lock, error) { - rl := rawLock{} - err := json.NewDecoder(r).Decode(&rl) + tree, err := toml.LoadReader(r) if err != nil { - return nil, err + return nil, errors.Wrap(err, "Unable to parse the lock as TOML") } - b, err := hex.DecodeString(rl.Memo) - if err != nil { - return nil, errors.Errorf("invalid hash digest in lock's memo field") + mapper := &tomlMapper{Tree: tree} + + raw := rawLock{ + Memo: readKeyAsString(mapper, "memo"), + Projects: readTableAsLockedProjects(mapper, "projects"), + } + + if mapper.Error != nil { + return nil, errors.Wrap(mapper.Error, "Invalid lock structure") } + return fromRawLock(raw) +} + +func fromRawLock(raw rawLock) (*Lock, error) { + var err error l := &Lock{ - Memo: b, - P: make([]gps.LockedProject, len(rl.P)), + P: make([]gps.LockedProject, len(raw.Projects)), } - for i, ld := range rl.P { + l.Memo, err = hex.DecodeString(raw.Memo) + if err != nil { + return nil, errors.Errorf("invalid hash digest in lock's memo field") + } + + for i, ld := range raw.Projects { r := gps.Revision(ld.Revision) var v gps.Version = r @@ -73,7 +86,6 @@ func readLock(r io.Reader) (*Lock, error) { } l.P[i] = gps.NewLockedProject(id, v, ld.Packages) } - return l, nil } @@ -88,15 +100,15 @@ func (l *Lock) Projects() []gps.LockedProject { // toRaw converts the manifest into a representation suitable to write to the lock file func (l *Lock) toRaw() rawLock { raw := rawLock{ - Memo: hex.EncodeToString(l.Memo), - P: make([]lockedDep, len(l.P)), + Memo: hex.EncodeToString(l.Memo), + Projects: make([]rawLockedProject, len(l.P)), } sort.Sort(SortedLockedProjects(l.P)) for k, lp := range l.P { id := lp.Ident() - ld := lockedDep{ + ld := rawLockedProject{ Name: string(id.ProjectRoot), Source: id.Source, Packages: lp.Packages(), @@ -105,7 +117,7 @@ func (l *Lock) toRaw() rawLock { v := lp.Version() ld.Revision, ld.Branch, ld.Version = getVersionInfo(v) - raw.P[k] = ld + raw.Projects[k] = ld } // TODO sort output - #15 @@ -116,12 +128,11 @@ func (l *Lock) toRaw() rawLock { func (l *Lock) MarshalTOML() (string, error) { raw := l.toRaw() - // TODO(carolynvs) Consider adding reflection-based marshal functionality to go-toml m := make(map[string]interface{}) m["memo"] = raw.Memo - p := make([]map[string]interface{}, len(raw.P)) + p := make([]map[string]interface{}, len(raw.Projects)) for i := 0; i < len(p); i++ { - srcPrj := raw.P[i] + srcPrj := raw.Projects[i] prj := make(map[string]interface{}) prj["name"] = srcPrj.Name prj["revision"] = srcPrj.Revision diff --git a/manifest.go b/manifest.go index 6106d64ee1..054976242c 100644 --- a/manifest.go +++ b/manifest.go @@ -5,8 +5,8 @@ package dep import ( - "encoding/json" "io" + "sort" "github.com/pelletier/go-toml" "github.com/pkg/errors" @@ -23,22 +23,14 @@ type Manifest struct { } type rawManifest struct { - Dependencies map[string]possibleProps - Overrides map[string]possibleProps + Dependencies []rawProject + Overrides []rawProject Ignores []string Required []string } -func newRawManifest() rawManifest { - return rawManifest{ - Dependencies: make(map[string]possibleProps), - Overrides: make(map[string]possibleProps), - Ignores: make([]string, 0), - Required: make([]string, 0), - } -} - -type possibleProps struct { +type rawProject struct { + Name string Branch string Revision string Version string @@ -46,108 +38,150 @@ type possibleProps struct { } func readManifest(r io.Reader) (*Manifest, error) { - rm := rawManifest{} - err := json.NewDecoder(r).Decode(&rm) + tree, err := toml.LoadReader(r) if err != nil { - return nil, err + return nil, errors.Wrap(err, "Unable to parse the manifest as TOML") } + + mapper := &tomlMapper{Tree: tree} + raw := rawManifest{ + Dependencies: readTableAsProjects(mapper, "dependencies"), + Overrides: readTableAsProjects(mapper, "overrides"), + Required: readKeyAsStringList(mapper, "required"), + Ignores: readKeyAsStringList(mapper, "ignores"), + } + + if mapper.Error != nil { + return nil, errors.Wrap(mapper.Error, "Invalid manifest structure") + } + return fromRawManifest(raw) +} + +func fromRawManifest(raw rawManifest) (*Manifest, error) { m := &Manifest{ - Dependencies: make(gps.ProjectConstraints, len(rm.Dependencies)), - Ovr: make(gps.ProjectConstraints, len(rm.Overrides)), - Ignores: rm.Ignores, - Required: rm.Required, + Dependencies: make(gps.ProjectConstraints, len(raw.Dependencies)), + Ovr: make(gps.ProjectConstraints, len(raw.Overrides)), + Ignores: raw.Ignores, + Required: raw.Required, } - for n, pp := range rm.Dependencies { - m.Dependencies[gps.ProjectRoot(n)], err = toProps(n, pp) + for i := 0; i < len(raw.Dependencies); i++ { + name, prj, err := toProject(raw.Dependencies[i]) if err != nil { return nil, err } + m.Dependencies[name] = prj } - for n, pp := range rm.Overrides { - m.Ovr[gps.ProjectRoot(n)], err = toProps(n, pp) + for i := 0; i < len(raw.Overrides); i++ { + name, prj, err := toProject(raw.Overrides[i]) if err != nil { return nil, err } + m.Ovr[name] = prj } return m, nil } -// toProps interprets the string representations of project information held in -// a possibleProps, converting them into a proper gps.ProjectProperties. An -// error is returned if the possibleProps contains some invalid combination - +// toProject interprets the string representations of project information held in +// a rawProject, converting them into a proper gps.ProjectProperties. An +// error is returned if the rawProject contains some invalid combination - // for example, if both a branch and version constraint are specified. -func toProps(n string, p possibleProps) (pp gps.ProjectProperties, err error) { - if p.Branch != "" { - if p.Version != "" || p.Revision != "" { - return pp, errors.Errorf("multiple constraints specified for %s, can only specify one", n) +func toProject(raw rawProject) (n gps.ProjectRoot, pp gps.ProjectProperties, err error) { + n = gps.ProjectRoot(raw.Name) + if raw.Branch != "" { + if raw.Version != "" || raw.Revision != "" { + return n, pp, errors.Errorf("multiple constraints specified for %s, can only specify one", n) } - pp.Constraint = gps.NewBranch(p.Branch) - } else if p.Version != "" { - if p.Revision != "" { - return pp, errors.Errorf("multiple constraints specified for %s, can only specify one", n) + pp.Constraint = gps.NewBranch(raw.Branch) + } else if raw.Version != "" { + if raw.Revision != "" { + return n, pp, errors.Errorf("multiple constraints specified for %s, can only specify one", n) } // always semver if we can - pp.Constraint, err = gps.NewSemverConstraint(p.Version) + pp.Constraint, err = gps.NewSemverConstraint(raw.Version) if err != nil { // but if not, fall back on plain versions - pp.Constraint = gps.NewVersion(p.Version) + pp.Constraint = gps.NewVersion(raw.Version) } - } else if p.Revision != "" { - pp.Constraint = gps.Revision(p.Revision) + } else if raw.Revision != "" { + pp.Constraint = gps.Revision(raw.Revision) } else { // If the user specifies nothing, it means an open constraint (accept // anything). pp.Constraint = gps.Any() } - pp.Source = p.Source - return pp, nil + pp.Source = raw.Source + return n, pp, nil } // toRaw converts the manifest into a representation suitable to write to the manifest file func (m *Manifest) toRaw() rawManifest { raw := rawManifest{ - Dependencies: make(map[string]possibleProps, len(m.Dependencies)), - Overrides: make(map[string]possibleProps, len(m.Ovr)), + Dependencies: make([]rawProject, 0, len(m.Dependencies)), + Overrides: make([]rawProject, 0, len(m.Ovr)), Ignores: m.Ignores, Required: m.Required, } - for n, pp := range m.Dependencies { - raw.Dependencies[string(n)] = toPossible(pp) + for n, prj := range m.Dependencies { + raw.Dependencies = append(raw.Dependencies, toRawProject(n, prj)) } - for n, pp := range m.Ovr { - raw.Overrides[string(n)] = toPossible(pp) + sort.Sort(sortedRawProjects(raw.Dependencies)) + + for n, prj := range m.Ovr { + raw.Overrides = append(raw.Overrides, toRawProject(n, prj)) } + sort.Sort(sortedRawProjects(raw.Overrides)) + return raw } +// TODO(carolynvs) when gps is moved, we can use the unexported gps.sortedConstraints +type sortedRawProjects []rawProject + +func (s sortedRawProjects) Len() int { return len(s) } +func (s sortedRawProjects) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s sortedRawProjects) Less(i, j int) bool { + l, r := s[i], s[j] + + if l.Name < r.Name { + return true + } + if r.Name < l.Name { + return false + } + + return l.Source < r.Source +} + func (m *Manifest) MarshalTOML() (string, error) { raw := m.toRaw() - // TODO(carolynvs) Consider adding reflection-based marshal functionality to go-toml - copyProjects := func(src map[string]possibleProps) []map[string]interface{} { - dest := make([]map[string]interface{}, 0, len(src)) - for prjName, srcPrj := range src { - prj := make(map[string]interface{}) - prj["name"] = prjName - if srcPrj.Source != "" { - prj["source"] = srcPrj.Source - } - if srcPrj.Branch != "" { - prj["branch"] = srcPrj.Branch - } - if srcPrj.Version != "" { - prj["version"] = srcPrj.Version - } - if srcPrj.Revision != "" { - prj["revision"] = srcPrj.Revision - } - dest = append(dest, prj) + mapRawProject := func(raw rawProject) map[string]interface{} { + prj := make(map[string]interface{}) + prj["name"] = raw.Name + if raw.Source != "" { + prj["source"] = raw.Source + } + if raw.Branch != "" { + prj["branch"] = raw.Branch + } + if raw.Version != "" { + prj["version"] = raw.Version + } + if raw.Revision != "" { + prj["revision"] = raw.Revision + } + return prj + } + mapRawProjects := func(src []rawProject) []map[string]interface{} { + dest := make([]map[string]interface{}, len(src)) + for i := 0; i < len(src); i++ { + dest[i] = mapRawProject(src[i]) } return dest } @@ -162,10 +196,10 @@ func (m *Manifest) MarshalTOML() (string, error) { data := make(map[string]interface{}) if len(raw.Dependencies) > 0 { - data["dependencies"] = copyProjects(raw.Dependencies) + data["dependencies"] = mapRawProjects(raw.Dependencies) } if len(raw.Overrides) > 0 { - data["overrides"] = copyProjects(raw.Overrides) + data["overrides"] = mapRawProjects(raw.Overrides) } if len(raw.Ignores) > 0 { data["ignores"] = copyProjectRefs(raw.Ignores) @@ -182,21 +216,22 @@ func (m *Manifest) MarshalTOML() (string, error) { return result, errors.Wrap(err, "Unable to marshal the lock to a TOML string") } -func toPossible(pp gps.ProjectProperties) possibleProps { - p := possibleProps{ - Source: pp.Source, +func toRawProject(name gps.ProjectRoot, project gps.ProjectProperties) rawProject { + raw := rawProject{ + Name: string(name), + Source: project.Source, } - if v, ok := pp.Constraint.(gps.Version); ok { + if v, ok := project.Constraint.(gps.Version); ok { switch v.Type() { case gps.IsRevision: - p.Revision = v.String() + raw.Revision = v.String() case gps.IsBranch: - p.Branch = v.String() + raw.Branch = v.String() case gps.IsSemver, gps.IsVersion: - p.Version = v.String() + raw.Version = v.String() } - return p + return raw } // We simply don't allow for a case where the user could directly @@ -204,11 +239,11 @@ func toPossible(pp gps.ProjectProperties) possibleProps { // the 'any' case, because that's the other possibility, and it's what // we interpret not having any constraint expressions at all to mean. // if !gps.IsAny(pp.Constraint) && !gps.IsNone(pp.Constraint) { - if !gps.IsAny(pp.Constraint) && pp.Constraint != nil { + if !gps.IsAny(project.Constraint) && project.Constraint != nil { // Has to be a semver range. - p.Version = pp.Constraint.String() + raw.Version = project.Constraint.String() } - return p + return raw } func (m *Manifest) DependencyConstraints() gps.ProjectConstraints { diff --git a/testdata/manifest/golden.toml b/testdata/manifest/golden.toml index f3c4759d04..7de52e5089 100644 --- a/testdata/manifest/golden.toml +++ b/testdata/manifest/golden.toml @@ -1,13 +1,13 @@ ignores = ["github.com/foo/bar"] -[[dependencies]] - name = "github.com/sdboyer/gps" - version = ">=0.12.0, <1.0.0" - [[dependencies]] name = "github.com/babble/brook" revision = "d05d5aca9f895d19e9265839bffeadd74a2d2ecb" +[[dependencies]] + name = "github.com/sdboyer/gps" + version = ">=0.12.0, <1.0.0" + [[overrides]] branch = "master" name = "github.com/sdboyer/gps" diff --git a/toml.go b/toml.go new file mode 100644 index 0000000000..fb5324f477 --- /dev/null +++ b/toml.go @@ -0,0 +1,177 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package dep + +import ( + "github.com/pelletier/go-toml" + "github.com/pkg/errors" +) + +type tomlMapper struct { + Tree *toml.TomlTree + Error error +} + +func readTableAsProjects(mapper *tomlMapper, table string) []rawProject { + if mapper.Error != nil { // Stop mapping if an error has already occurred + return nil + } + + query, err := mapper.Tree.Query("$." + table) + if err != nil { + mapper.Error = errors.Wrapf(err, "Unable to query for [[%s]]", table) + return nil + } + + matches := query.Values() + if len(matches) == 0 { + return nil + } + + tables, ok := matches[0].([]*toml.TomlTree) + if !ok { + mapper.Error = errors.Errorf("Invalid query result type for [[%s]], should be a TOML array of tables but got %T", table, matches[0]) + return nil + } + + subMapper := &tomlMapper{} + projects := make([]rawProject, len(tables)) + for i := 0; i < len(tables); i++ { + subMapper.Tree = tables[i] + projects[i] = mapProject(subMapper) + } + + if subMapper.Error != nil { + mapper.Error = subMapper.Error + return nil + } + return projects +} + +func readTableAsLockedProjects(mapper *tomlMapper, table string) []rawLockedProject { + if mapper.Error != nil { // Stop mapping if an error has already occurred + return nil + } + + query, err := mapper.Tree.Query("$." + table) + if err != nil { + mapper.Error = errors.Wrapf(err, "Unable to query for [[%s]]", table) + return nil + } + + matches := query.Values() + if len(matches) == 0 { + return nil + } + + tables, ok := matches[0].([]*toml.TomlTree) + if !ok { + mapper.Error = errors.Errorf("Invalid query result type for [[%s]], should be a TOML array of tables but got %T", table, matches[0]) + return nil + } + + subMapper := &tomlMapper{} + projects := make([]rawLockedProject, len(tables)) + for i := 0; i < len(tables); i++ { + subMapper.Tree = tables[i] + projects[i] = mapLockedProject(subMapper) + } + + if subMapper.Error != nil { + mapper.Error = subMapper.Error + return nil + } + return projects +} + +func mapProject(mapper *tomlMapper) rawProject { + if mapper.Error != nil { // Stop mapping if an error has already occurred + return rawProject{} + } + + prj := rawProject{ + Name: readKeyAsString(mapper, "name"), + Branch: readKeyAsString(mapper, "branch"), + Revision: readKeyAsString(mapper, "revision"), + Version: readKeyAsString(mapper, "version"), + Source: readKeyAsString(mapper, "source"), + } + + if mapper.Error != nil { + return rawProject{} + } + + return prj +} + +func mapLockedProject(mapper *tomlMapper) rawLockedProject { + if mapper.Error != nil { // Stop mapping if an error has already occurred + return rawLockedProject{} + } + + prj := rawLockedProject{ + Name: readKeyAsString(mapper, "name"), + Branch: readKeyAsString(mapper, "branch"), + Revision: readKeyAsString(mapper, "revision"), + Version: readKeyAsString(mapper, "version"), + Source: readKeyAsString(mapper, "source"), + Packages: readKeyAsStringList(mapper, "packages"), + } + + if mapper.Error != nil { + return rawLockedProject{} + } + + return prj +} + +func readKeyAsString(mapper *tomlMapper, key string) string { + if mapper.Error != nil { // Stop mapping if an error has already occurred + return "" + } + + rawValue := mapper.Tree.GetDefault(key, "") + value, ok := rawValue.(string) + if !ok { + mapper.Error = errors.Errorf("Invalid type for %s, should be a string, but it is a %T", key, rawValue) + return "" + } + + return value +} + +func readKeyAsStringList(mapper *tomlMapper, key string) []string { + if mapper.Error != nil { // Stop mapping if an error has already occurred + return nil + } + + query, err := mapper.Tree.Query("$." + key) + if err != nil { + mapper.Error = errors.Wrapf(err, "Unable to query for [%s]", key) + return nil + } + + matches := query.Values() + if len(matches) == 0 { + return nil + } + + lists, ok := matches[0].([]interface{}) + if !ok { + mapper.Error = errors.Errorf("Invalid query result type for [%s], should be a TOML list ([]interface{}) but got %T", key, matches[0]) + return nil + } + + results := make([]string, len(lists)) + for i := range lists { + ref, ok := lists[i].(string) + if !ok { + mapper.Error = errors.Errorf("Invalid query result item type for [%s], should be a TOML list of strings([]string) but got %T", key, lists[i]) + return nil + } + results[i] = ref + } + return results +} From 23facf8bbf5f99be1fc2d79fd84ff4ec73ad2285 Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Wed, 22 Mar 2017 17:11:43 -0500 Subject: [PATCH 10/20] Move lock diff to TOML * Expanded diff test case to verify that multiple projects are formatted properly --- testdata/txn_writer/expected_diff_output.txt | 63 ++++++------ testdata/txn_writer/original_lock.toml | 2 +- testdata/txn_writer/updated_lock.toml | 8 +- txn_writer.go | 101 ++++++++++++------- txn_writer_test.go | 14 ++- 5 files changed, 113 insertions(+), 75 deletions(-) diff --git a/testdata/txn_writer/expected_diff_output.txt b/testdata/txn_writer/expected_diff_output.txt index 531d01aca6..bbfe78f82b 100644 --- a/testdata/txn_writer/expected_diff_output.txt +++ b/testdata/txn_writer/expected_diff_output.txt @@ -1,34 +1,31 @@ Memo: 595716d270828e763c811ef79c9c41f85b1d1bfbdfe85280036405c03772206c -> 2252a285ab27944a4d7adcba8dbd03980f59ba652f12db39fa93b927c345593e -Add: [ - { - "name": "github.com/stuff/realthing", - "version": "2.0.0", - "revision": "1f02e52d6bac308da54ab84a234c58a98ca82347", - "packages": [ - "." - ] - } -] -Remove: [ - { - "name": "github.com/stuff/placeholder", - "version": "2.0.0", - "revision": "6694017eeb4e20fd277b049bf29dba4895c97234", - "packages": [ - "." - ] - } -] -Modify: [ - { - "name": "github.com/foo/bar", - "source": "+ http://github.example.com/foo/bar", - "version": "+ 1.2.0", - "branch": "- master", - "revision": "f24338400f072ef18125ae0fbe6b06fe6d1783e7 -> 2a3a211e171803acb82d1d5d42ceb53228f51751", - "packages": [ - "- placeholder", - "+ thing" - ] - } -] + +Add: +[[projects]] + name = "github.com/sdboyer/deptest" + packages = ["."] + revision = "ff2948a2ac8f538c4ecd55962e919d1e13e74baf" + version = "v1.0.0" + +[[projects]] + name = "github.com/stuff/realthing" + packages = ["."] + revision = "1f02e52d6bac308da54ab84a234c58a98ca82347" + version = "2.0.0" + +Remove: +[[projects]] + name = "github.com/stuff/placeholder" + packages = ["."] + revision = "6694017eeb4e20fd277b049bf29dba4895c97234" + version = "2.0.0" + +Modify: +[[projects]] + branch = "- master" + name = "github.com/foo/bar" + packages = ["- placeholder","+ thing"] + revision = "f24338400f072ef18125ae0fbe6b06fe6d1783e7 -> 2a3a211e171803acb82d1d5d42ceb53228f51751" + source = "+ http://github.example.com/foo/bar" + version = "+ 1.2.0" + diff --git a/testdata/txn_writer/original_lock.toml b/testdata/txn_writer/original_lock.toml index 512df734c7..1a9384efa7 100644 --- a/testdata/txn_writer/original_lock.toml +++ b/testdata/txn_writer/original_lock.toml @@ -6,7 +6,7 @@ memo = "595716d270828e763c811ef79c9c41f85b1d1bfbdfe85280036405c03772206c" revision = "f24338400f072ef18125ae0fbe6b06fe6d1783e7" packages = ["placeholder", "util"] -[[packages]] +[[projects]] name = "github.com/stuff/placeholder" version = "2.0.0" revision = "6694017eeb4e20fd277b049bf29dba4895c97234" diff --git a/testdata/txn_writer/updated_lock.toml b/testdata/txn_writer/updated_lock.toml index 028627cd3d..da44aa9a21 100644 --- a/testdata/txn_writer/updated_lock.toml +++ b/testdata/txn_writer/updated_lock.toml @@ -7,8 +7,14 @@ memo = "2252a285ab27944a4d7adcba8dbd03980f59ba652f12db39fa93b927c345593e" revision = "2a3a211e171803acb82d1d5d42ceb53228f51751" packages = ["thing","util"] -[[packages]] +[[projects]] name = "github.com/stuff/realthing" version = "2.0.0" revision = "1f02e52d6bac308da54ab84a234c58a98ca82347" packages = ["."] + +[[projects]] + name = "github.com/sdboyer/deptest" + packages = ["."] + revision = "ff2948a2ac8f538c4ecd55962e919d1e13e74baf" + version = "v1.0.0" diff --git a/txn_writer.go b/txn_writer.go index f6daef812c..4774dd4685 100644 --- a/txn_writer.go +++ b/txn_writer.go @@ -7,7 +7,6 @@ package dep import ( "bytes" "encoding/hex" - "encoding/json" "fmt" "io/ioutil" "os" @@ -15,6 +14,7 @@ import ( "sort" "strings" + "github.com/pelletier/go-toml" "github.com/pkg/errors" "github.com/sdboyer/gps" ) @@ -67,40 +67,40 @@ func (diff *LockDiff) Format() (string, error) { var buf bytes.Buffer if diff.HashDiff != nil { - buf.WriteString(fmt.Sprintf("Memo: %s\n", diff.HashDiff)) + buf.WriteString(fmt.Sprintf("Memo: %s\n\n", diff.HashDiff)) } - if len(diff.Add) > 0 { - buf.WriteString("Add: ") + writeDiffs := func(diffs []LockedProjectDiff) error { + for i := 0; i < len(diffs); i++ { + chunk, err := diffs[i].MarshalTOML() + if err != nil { + return err + } + buf.WriteString(chunk) + } + buf.WriteString("\n") + return nil + } - enc := json.NewEncoder(&buf) - enc.SetIndent("", " ") - enc.SetEscapeHTML(false) - err := enc.Encode(diff.Add) + if len(diff.Add) > 0 { + buf.WriteString("Add:") + err := writeDiffs(diff.Add) if err != nil { return "", errors.Wrap(err, "Unable to format LockDiff.Add") } } if len(diff.Remove) > 0 { - buf.WriteString("Remove: ") - - enc := json.NewEncoder(&buf) - enc.SetIndent("", " ") - enc.SetEscapeHTML(false) - err := enc.Encode(diff.Remove) + buf.WriteString("Remove:") + err := writeDiffs(diff.Remove) if err != nil { return "", errors.Wrap(err, "Unable to format LockDiff.Remove") } } if len(diff.Modify) > 0 { - buf.WriteString("Modify: ") - - enc := json.NewEncoder(&buf) - enc.SetIndent("", " ") - enc.SetEscapeHTML(false) - err := enc.Encode(diff.Modify) + buf.WriteString("Modify:") + err := writeDiffs(diff.Modify) if err != nil { return "", errors.Wrap(err, "Unable to format LockDiff.Modify") } @@ -113,12 +113,52 @@ func (diff *LockDiff) Format() (string, error) { // Fields are only populated when there is a difference, otherwise they are empty. // TODO(carolynvs) this should be moved to gps type LockedProjectDiff struct { - Name gps.ProjectRoot `json:"name"` - Source *StringDiff `json:"source,omitempty"` - Version *StringDiff `json:"version,omitempty"` - Branch *StringDiff `json:"branch,omitempty"` - Revision *StringDiff `json:"revision,omitempty"` - Packages []StringDiff `json:"packages,omitempty"` + Name gps.ProjectRoot + Source *StringDiff + Version *StringDiff + Branch *StringDiff + Revision *StringDiff + Packages []StringDiff +} + +func (diff *LockedProjectDiff) MarshalTOML() (string, error) { + prj := make(map[string]interface{}) + prj["name"] = string(diff.Name) + + if diff.Source != nil { + prj["source"] = diff.Source.String() + } + + if diff.Version != nil { + prj["version"] = diff.Version.String() + } + + if diff.Branch != nil { + prj["branch"] = diff.Branch.String() + } + + if diff.Revision != nil { + prj["revision"] = diff.Revision.String() + } + + if len(diff.Packages) > 0 { + p := make([]interface{}, len(diff.Packages)) + for i := 0; i < len(diff.Packages); i++ { + p[i] = diff.Packages[i].String() + } + prj["packages"] = p + } + + m := make(map[string]interface{}) + m["projects"] = []map[string]interface{}{prj} + + t, err := toml.TreeFromMap(m) + if err != nil { + return "", errors.Wrap(err, "Unable to marshal lock diff to TOML tree") + } + + result, err := t.ToTomlString() + return result, errors.Wrap(err, "Unable to marshal lock diff to TOML string") } type StringDiff struct { @@ -142,15 +182,6 @@ func (diff StringDiff) String() string { return diff.Current } -func (diff StringDiff) MarshalJSON() ([]byte, error) { - var buf bytes.Buffer - enc := json.NewEncoder(&buf) - enc.SetEscapeHTML(false) - err := enc.Encode(diff.String()) - - return buf.Bytes(), err -} - // VendorBehavior defines when the vendor directory should be written. type VendorBehavior int diff --git a/txn_writer_test.go b/txn_writer_test.go index c0e569a21a..bd1be862a1 100644 --- a/txn_writer_test.go +++ b/txn_writer_test.go @@ -518,12 +518,16 @@ func TestSafeWriter_DiffLocks(t *testing.T) { t.Fatalf("Expected the lock diff to contain the updated hash: expected %s, got %s", pc.Project.Lock.Memo, updatedLock.Memo) } - if len(diff.Add) != 1 { - t.Fatalf("Expected the lock diff to contain 1 added project, got %d", len(diff.Add)) + if len(diff.Add) != 2 { + t.Fatalf("Expected the lock diff to contain 2 added projects, got %d", len(diff.Add)) } else { - add := diff.Add[0] - if add.Name != "github.com/stuff/realthing" { - t.Errorf("expected new project github.com/stuff/realthing, got %s", add.Name) + add1 := diff.Add[0] + if add1.Name != "github.com/sdboyer/deptest" { + t.Errorf("expected new project[0] github.com/sdboyer/deptest, got %s", add1.Name) + } + add2 := diff.Add[1] + if add2.Name != "github.com/stuff/realthing" { + t.Errorf("expected new project[1] github.com/stuff/realthing, got %s", add2.Name) } } From 2cfa3c72d38582b9cee9d33bbfdceb3dd8d3b7c9 Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Wed, 29 Mar 2017 19:00:26 -0500 Subject: [PATCH 11/20] Update vendored go-toml Get the latest version which has reflection-based marshaling --- lock.toml | 3 +- manifest.toml | 2 +- .../github.com/pelletier/go-toml/marshal.go | 459 +++++++++++++++ .../pelletier/go-toml/marshal_test.go | 535 ++++++++++++++++++ .../pelletier/go-toml/marshal_test.toml | 38 ++ .../pelletier/go-toml/parser_test.go | 3 +- .../pelletier/go-toml/tomltree_create.go | 14 +- .../pelletier/go-toml/tomltree_create_test.go | 49 +- .../pelletier/go-toml/tomltree_write.go | 13 +- .../pelletier/go-toml/tomltree_write_test.go | 13 - 10 files changed, 1096 insertions(+), 33 deletions(-) create mode 100644 vendor/github.com/pelletier/go-toml/marshal.go create mode 100644 vendor/github.com/pelletier/go-toml/marshal_test.go create mode 100644 vendor/github.com/pelletier/go-toml/marshal_test.toml diff --git a/lock.toml b/lock.toml index c6a24bfc44..4e079213c4 100644 --- a/lock.toml +++ b/lock.toml @@ -25,8 +25,9 @@ memo = "31a7162c06758e4619ed89b91e1f48bf94ad14f394bbee79299ed0bb5150e409" version = "v0.2.0" [[projects]] + branch = "master" name = "github.com/pelletier/go-toml" - revision = "fee7787d3f811af92276f5ff10107092e95b7a1d" + revision = "e32a2e04744250647a72bf17da1b09befc03b6b1" packages = ["."] [[projects]] diff --git a/manifest.toml b/manifest.toml index 44a51fa4f8..5c6b8a42f1 100644 --- a/manifest.toml +++ b/manifest.toml @@ -8,8 +8,8 @@ version = "^1.8.0" [[dependencies]] + branch = "master" name = "github.com/pelletier/go-toml" - revision = "fee7787d3f811af92276f5ff10107092e95b7a1d" [[dependencies]] name = "github.com/pkg/errors" diff --git a/vendor/github.com/pelletier/go-toml/marshal.go b/vendor/github.com/pelletier/go-toml/marshal.go new file mode 100644 index 0000000000..4301a4513f --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/marshal.go @@ -0,0 +1,459 @@ +package toml + +import ( + "errors" + "fmt" + "reflect" + "strings" + "time" +) + +/* +TomlTree structural types and corresponding marshal types +------------------------------------------------------------------------------- +*TomlTree (*)struct, (*)map[string]interface{} +[]*TomlTree (*)[](*)struct, (*)[](*)map[string]interface{} +[]interface{} (as interface{}) (*)[]primitive, (*)[]([]interface{}) +interface{} (*)primitive + +TomlTree primitive types and corresponding marshal types +----------------------------------------------------------- +uint64 uint, uint8-uint64, pointers to same +int64 int, int8-uint64, pointers to same +float64 float32, float64, pointers to same +string string, pointers to same +bool bool, pointers to same +time.Time time.Time{}, pointers to same +*/ + +type tomlOpts struct { + name string + include bool + omitempty bool +} + +var timeType = reflect.TypeOf(time.Time{}) + +// Check if the given marshall type maps to a TomlTree primitive +func isPrimitive(mtype reflect.Type) bool { + switch mtype.Kind() { + case reflect.Ptr: + return isPrimitive(mtype.Elem()) + case reflect.Bool: + return true + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return true + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return true + case reflect.Float32, reflect.Float64: + return true + case reflect.String: + return true + case reflect.Struct: + return mtype == timeType + default: + return false + } +} + +// Check if the given marshall type maps to a TomlTree slice +func isTreeSlice(mtype reflect.Type) bool { + switch mtype.Kind() { + case reflect.Slice: + return !isOtherSlice(mtype) + default: + return false + } +} + +// Check if the given marshall type maps to a non-TomlTree slice +func isOtherSlice(mtype reflect.Type) bool { + switch mtype.Kind() { + case reflect.Ptr: + return isOtherSlice(mtype.Elem()) + case reflect.Slice: + return isPrimitive(mtype.Elem()) || isOtherSlice(mtype.Elem()) + default: + return false + } +} + +// Check if the given marshall type maps to a TomlTree +func isTree(mtype reflect.Type) bool { + switch mtype.Kind() { + case reflect.Map: + return true + case reflect.Struct: + return !isPrimitive(mtype) + default: + return false + } +} + +/* +Marshal returns the TOML encoding of v. Behavior is similar to the Go json +encoder, except that there is no concept of a Marshaler interface or MarshalTOML +function for sub-structs, and currently only definite types can be marshaled +(i.e. no `interface{}`). + +Note that pointers are automatically assigned the "omitempty" option, as TOML +explicity does not handle null values (saying instead the label should be +dropped). +*/ +func Marshal(v interface{}) ([]byte, error) { + mtype := reflect.TypeOf(v) + if mtype.Kind() != reflect.Struct { + return []byte{}, errors.New("Only a struct can be marshaled to TOML") + } + sval := reflect.ValueOf(v) + t, err := valueToTree(mtype, sval) + if err != nil { + return []byte{}, err + } + s, err := t.ToTomlString() + return []byte(s), err +} + +// Convert given marshal struct or map value to toml tree +func valueToTree(mtype reflect.Type, mval reflect.Value) (*TomlTree, error) { + if mtype.Kind() == reflect.Ptr { + return valueToTree(mtype.Elem(), mval.Elem()) + } + tval := newTomlTree() + switch mtype.Kind() { + case reflect.Struct: + for i := 0; i < mtype.NumField(); i++ { + mtypef, mvalf := mtype.Field(i), mval.Field(i) + opts := tomlOptions(mtypef) + if opts.include && (!opts.omitempty || !isZero(mvalf)) { + val, err := valueToToml(mtypef.Type, mvalf) + if err != nil { + return nil, err + } + tval.Set(opts.name, val) + } + } + case reflect.Map: + for _, key := range mval.MapKeys() { + mvalf := mval.MapIndex(key) + val, err := valueToToml(mtype.Elem(), mvalf) + if err != nil { + return nil, err + } + tval.Set(key.String(), val) + } + } + return tval, nil +} + +// Convert given marshal slice to slice of Toml trees +func valueToTreeSlice(mtype reflect.Type, mval reflect.Value) ([]*TomlTree, error) { + tval := make([]*TomlTree, mval.Len(), mval.Len()) + for i := 0; i < mval.Len(); i++ { + val, err := valueToTree(mtype.Elem(), mval.Index(i)) + if err != nil { + return nil, err + } + tval[i] = val + } + return tval, nil +} + +// Convert given marshal slice to slice of toml values +func valueToOtherSlice(mtype reflect.Type, mval reflect.Value) (interface{}, error) { + tval := make([]interface{}, mval.Len(), mval.Len()) + for i := 0; i < mval.Len(); i++ { + val, err := valueToToml(mtype.Elem(), mval.Index(i)) + if err != nil { + return nil, err + } + tval[i] = val + } + return tval, nil +} + +// Convert given marshal value to toml value +func valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) { + if mtype.Kind() == reflect.Ptr { + return valueToToml(mtype.Elem(), mval.Elem()) + } + switch { + case isTree(mtype): + return valueToTree(mtype, mval) + case isTreeSlice(mtype): + return valueToTreeSlice(mtype, mval) + case isOtherSlice(mtype): + return valueToOtherSlice(mtype, mval) + default: + switch mtype.Kind() { + case reflect.Bool: + return mval.Bool(), nil + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return mval.Int(), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return mval.Uint(), nil + case reflect.Float32, reflect.Float64: + return mval.Float(), nil + case reflect.String: + return mval.String(), nil + case reflect.Struct: + return mval.Interface().(time.Time), nil + default: + return nil, fmt.Errorf("Marshal can't handle %v(%v)", mtype, mtype.Kind()) + } + } +} + +/* +Unmarshal parses the TOML-encoded data and stores the result in the value +pointed to by v. Behavior is similar to the Go json encoder, except that there +is no concept of an Unmarshaler interface or UnmarshalTOML function for +sub-structs, and currently only definite types can be unmarshaled to (i.e. no +`interface{}`). +*/ +func Unmarshal(data []byte, v interface{}) error { + mtype := reflect.TypeOf(v) + if mtype.Kind() != reflect.Ptr || mtype.Elem().Kind() != reflect.Struct { + return errors.New("Only a pointer to struct can be unmarshaled from TOML") + } + + t, err := Load(string(data)) + if err != nil { + return err + } + + sval, err := valueFromTree(mtype.Elem(), t) + if err != nil { + return err + } + reflect.ValueOf(v).Elem().Set(sval) + return nil +} + +// Convert toml tree to marshal struct or map, using marshal type +func valueFromTree(mtype reflect.Type, tval *TomlTree) (reflect.Value, error) { + if mtype.Kind() == reflect.Ptr { + return unwrapPointer(mtype, tval) + } + var mval reflect.Value + switch mtype.Kind() { + case reflect.Struct: + mval = reflect.New(mtype).Elem() + for i := 0; i < mtype.NumField(); i++ { + mtypef := mtype.Field(i) + opts := tomlOptions(mtypef) + if opts.include { + key := opts.name + exists := tval.Has(key) + if exists { + val := tval.Get(key) + mvalf, err := valueFromToml(mtypef.Type, val) + if err != nil { + return mval, formatError(err, tval.GetPosition(key)) + } + mval.Field(i).Set(mvalf) + } + } + } + case reflect.Map: + mval = reflect.MakeMap(mtype) + for _, key := range tval.Keys() { + val := tval.Get(key) + mvalf, err := valueFromToml(mtype.Elem(), val) + if err != nil { + return mval, formatError(err, tval.GetPosition(key)) + } + mval.SetMapIndex(reflect.ValueOf(key), mvalf) + } + } + return mval, nil +} + +// Convert toml value to marshal struct/map slice, using marshal type +func valueFromTreeSlice(mtype reflect.Type, tval []*TomlTree) (reflect.Value, error) { + mval := reflect.MakeSlice(mtype, len(tval), len(tval)) + for i := 0; i < len(tval); i++ { + val, err := valueFromTree(mtype.Elem(), tval[i]) + if err != nil { + return mval, err + } + mval.Index(i).Set(val) + } + return mval, nil +} + +// Convert toml value to marshal primitive slice, using marshal type +func valueFromOtherSlice(mtype reflect.Type, tval []interface{}) (reflect.Value, error) { + mval := reflect.MakeSlice(mtype, len(tval), len(tval)) + for i := 0; i < len(tval); i++ { + val, err := valueFromToml(mtype.Elem(), tval[i]) + if err != nil { + return mval, err + } + mval.Index(i).Set(val) + } + return mval, nil +} + +// Convert toml value to marshal value, using marshal type +func valueFromToml(mtype reflect.Type, tval interface{}) (reflect.Value, error) { + if mtype.Kind() == reflect.Ptr { + return unwrapPointer(mtype, tval) + } + switch { + case isTree(mtype): + return valueFromTree(mtype, tval.(*TomlTree)) + case isTreeSlice(mtype): + return valueFromTreeSlice(mtype, tval.([]*TomlTree)) + case isOtherSlice(mtype): + return valueFromOtherSlice(mtype, tval.([]interface{})) + default: + switch mtype.Kind() { + case reflect.Bool: + val, ok := tval.(bool) + if !ok { + return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to bool", tval, tval) + } + return reflect.ValueOf(val), nil + case reflect.Int: + val, ok := tval.(int64) + if !ok { + return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval) + } + return reflect.ValueOf(int(val)), nil + case reflect.Int8: + val, ok := tval.(int64) + if !ok { + return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval) + } + return reflect.ValueOf(int8(val)), nil + case reflect.Int16: + val, ok := tval.(int64) + if !ok { + return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval) + } + return reflect.ValueOf(int16(val)), nil + case reflect.Int32: + val, ok := tval.(int64) + if !ok { + return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval) + } + return reflect.ValueOf(int32(val)), nil + case reflect.Int64: + val, ok := tval.(int64) + if !ok { + return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval) + } + return reflect.ValueOf(val), nil + case reflect.Uint: + val, ok := tval.(int64) + if !ok { + return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval) + } + return reflect.ValueOf(uint(val)), nil + case reflect.Uint8: + val, ok := tval.(int64) + if !ok { + return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval) + } + return reflect.ValueOf(uint8(val)), nil + case reflect.Uint16: + val, ok := tval.(int64) + if !ok { + return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval) + } + return reflect.ValueOf(uint16(val)), nil + case reflect.Uint32: + val, ok := tval.(int64) + if !ok { + return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval) + } + return reflect.ValueOf(uint32(val)), nil + case reflect.Uint64: + val, ok := tval.(int64) + if !ok { + return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval) + } + return reflect.ValueOf(uint64(val)), nil + case reflect.Float32: + val, ok := tval.(float64) + if !ok { + return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to float", tval, tval) + } + return reflect.ValueOf(float32(val)), nil + case reflect.Float64: + val, ok := tval.(float64) + if !ok { + return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to float", tval, tval) + } + return reflect.ValueOf(val), nil + case reflect.String: + val, ok := tval.(string) + if !ok { + return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to string", tval, tval) + } + return reflect.ValueOf(val), nil + case reflect.Struct: + val, ok := tval.(time.Time) + if !ok { + return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to time", tval, tval) + } + return reflect.ValueOf(val), nil + default: + return reflect.ValueOf(nil), fmt.Errorf("Unmarshal can't handle %v(%v)", mtype, mtype.Kind()) + } + } +} + +func unwrapPointer(mtype reflect.Type, tval interface{}) (reflect.Value, error) { + val, err := valueFromToml(mtype.Elem(), tval) + if err != nil { + return reflect.ValueOf(nil), err + } + mval := reflect.New(mtype.Elem()) + mval.Elem().Set(val) + return mval, nil +} + +func tomlOptions(vf reflect.StructField) tomlOpts { + tag := vf.Tag.Get("toml") + parse := strings.Split(tag, ",") + result := tomlOpts{vf.Name, true, false} + if parse[0] != "" { + if parse[0] == "-" && len(parse) == 1 { + result.include = false + } else { + result.name = strings.Trim(parse[0], " ") + } + } + if vf.PkgPath != "" { + result.include = false + } + if len(parse) > 1 && strings.Trim(parse[1], " ") == "omitempty" { + result.omitempty = true + } + if vf.Type.Kind() == reflect.Ptr { + result.omitempty = true + } + return result +} + +func isZero(val reflect.Value) bool { + switch val.Type().Kind() { + case reflect.Map: + fallthrough + case reflect.Array: + fallthrough + case reflect.Slice: + return val.Len() == 0 + default: + return reflect.DeepEqual(val.Interface(), reflect.Zero(val.Type()).Interface()) + } +} + +func formatError(err error, pos Position) error { + if err.Error()[0] == '(' { // Error already contains position information + return err + } + return fmt.Errorf("%s: %s", pos, err) +} diff --git a/vendor/github.com/pelletier/go-toml/marshal_test.go b/vendor/github.com/pelletier/go-toml/marshal_test.go new file mode 100644 index 0000000000..c8dee94ded --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/marshal_test.go @@ -0,0 +1,535 @@ +package toml + +import ( + "bytes" + "encoding/json" + "io/ioutil" + "reflect" + "testing" + "time" +) + +type basicMarshalTestStruct struct { + String string `toml:"string"` + StringList []string `toml:"strlist"` + Sub basicMarshalTestSubStruct `toml:"subdoc"` + SubList []basicMarshalTestSubStruct `toml:"sublist"` +} + +type basicMarshalTestSubStruct struct { + String2 string +} + +var basicTestData = basicMarshalTestStruct{ + String: "Hello", + StringList: []string{"Howdy", "Hey There"}, + Sub: basicMarshalTestSubStruct{"One"}, + SubList: []basicMarshalTestSubStruct{{"Two"}, {"Three"}}, +} + +var basicTestToml = []byte(`string = "Hello" +strlist = ["Howdy","Hey There"] + +[subdoc] + String2 = "One" + +[[sublist]] + String2 = "Two" + +[[sublist]] + String2 = "Three" +`) + +func TestBasicMarshal(t *testing.T) { + result, err := Marshal(basicTestData) + if err != nil { + t.Fatal(err) + } + expected := basicTestToml + if !bytes.Equal(result, expected) { + t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) + } +} + +func TestBasicUnmarshal(t *testing.T) { + result := basicMarshalTestStruct{} + err := Unmarshal(basicTestToml, &result) + expected := basicTestData + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(result, expected) { + t.Errorf("Bad unmarshal: expected %v, got %v", expected, result) + } +} + +type testDoc struct { + Title string `toml:"title"` + Basics testDocBasics `toml:"basic"` + BasicLists testDocBasicLists `toml:"basic_lists"` + BasicMap map[string]string `toml:"basic_map"` + Subdocs testDocSubs `toml:"subdoc"` + SubDocList []testSubDoc `toml:"subdoclist"` + SubDocPtrs []*testSubDoc `toml:"subdocptrs"` + err int `toml:"shouldntBeHere"` + unexported int `toml:"shouldntBeHere"` + Unexported2 int `toml:"-"` +} + +type testDocBasics struct { + Bool bool `toml:"bool"` + Date time.Time `toml:"date"` + Float float32 `toml:"float"` + Int int `toml:"int"` + Uint uint `toml:"uint"` + String *string `toml:"string"` + unexported int `toml:"shouldntBeHere"` +} + +type testDocBasicLists struct { + Bools []bool `toml:"bools"` + Dates []time.Time `toml:"dates"` + Floats []*float32 `toml:"floats"` + Ints []int `toml:"ints"` + Strings []string `toml:"strings"` + UInts []uint `toml:"uints"` +} + +type testDocSubs struct { + First testSubDoc `toml:"first"` + Second *testSubDoc `toml:"second"` +} + +type testSubDoc struct { + Name string `toml:"name"` + unexported int `toml:"shouldntBeHere"` +} + +var biteMe = "Bite me" +var float1 float32 = 12.3 +var float2 float32 = 45.6 +var float3 float32 = 78.9 +var subdoc = testSubDoc{"Second", 0} + +var docData = testDoc{ + Title: "TOML Marshal Testing", + unexported: 0, + Unexported2: 0, + Basics: testDocBasics{ + Bool: true, + Date: time.Date(1979, 5, 27, 7, 32, 0, 0, time.UTC), + Float: 123.4, + Int: 5000, + Uint: 5001, + String: &biteMe, + unexported: 0, + }, + BasicLists: testDocBasicLists{ + Bools: []bool{true, false, true}, + Dates: []time.Time{ + time.Date(1979, 5, 27, 7, 32, 0, 0, time.UTC), + time.Date(1980, 5, 27, 7, 32, 0, 0, time.UTC), + }, + Floats: []*float32{&float1, &float2, &float3}, + Ints: []int{8001, 8001, 8002}, + Strings: []string{"One", "Two", "Three"}, + UInts: []uint{5002, 5003}, + }, + BasicMap: map[string]string{ + "one": "one", + "two": "two", + }, + Subdocs: testDocSubs{ + First: testSubDoc{"First", 0}, + Second: &subdoc, + }, + SubDocList: []testSubDoc{ + testSubDoc{"List.First", 0}, + testSubDoc{"List.Second", 0}, + }, + SubDocPtrs: []*testSubDoc{&subdoc}, +} + +func TestDocMarshal(t *testing.T) { + result, err := Marshal(docData) + if err != nil { + t.Fatal(err) + } + expected, _ := ioutil.ReadFile("marshal_test.toml") + if !bytes.Equal(result, expected) { + t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) + } +} + +func TestDocUnmarshal(t *testing.T) { + result := testDoc{} + tomlData, _ := ioutil.ReadFile("marshal_test.toml") + err := Unmarshal(tomlData, &result) + expected := docData + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(result, expected) { + resStr, _ := json.MarshalIndent(result, "", " ") + expStr, _ := json.MarshalIndent(expected, "", " ") + t.Errorf("Bad unmarshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expStr, resStr) + } +} + +type tomlTypeCheckTest struct { + name string + item interface{} + typ int //0=primitive, 1=otherslice, 2=treeslice, 3=tree +} + +func TestTypeChecks(t *testing.T) { + tests := []tomlTypeCheckTest{ + {"integer", 2, 0}, + {"time", time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC), 0}, + {"stringlist", []string{"hello", "hi"}, 1}, + {"timelist", []time.Time{time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC)}, 1}, + {"objectlist", []tomlTypeCheckTest{}, 2}, + {"object", tomlTypeCheckTest{}, 3}, + } + + for _, test := range tests { + expected := []bool{false, false, false, false} + expected[test.typ] = true + result := []bool{ + isPrimitive(reflect.TypeOf(test.item)), + isOtherSlice(reflect.TypeOf(test.item)), + isTreeSlice(reflect.TypeOf(test.item)), + isTree(reflect.TypeOf(test.item)), + } + if !reflect.DeepEqual(expected, result) { + t.Errorf("Bad type check on %q: expected %v, got %v", test.name, expected, result) + } + } +} + +type unexportedMarshalTestStruct struct { + String string `toml:"string"` + StringList []string `toml:"strlist"` + Sub basicMarshalTestSubStruct `toml:"subdoc"` + SubList []basicMarshalTestSubStruct `toml:"sublist"` + unexported int `toml:"shouldntBeHere"` + Unexported2 int `toml:"-"` +} + +var unexportedTestData = unexportedMarshalTestStruct{ + String: "Hello", + StringList: []string{"Howdy", "Hey There"}, + Sub: basicMarshalTestSubStruct{"One"}, + SubList: []basicMarshalTestSubStruct{{"Two"}, {"Three"}}, + unexported: 0, + Unexported2: 0, +} + +var unexportedTestToml = []byte(`string = "Hello" +strlist = ["Howdy","Hey There"] +unexported = 1 +shouldntBeHere = 2 + +[subdoc] + String2 = "One" + +[[sublist]] + String2 = "Two" + +[[sublist]] + String2 = "Three" +`) + +func TestUnexportedUnmarshal(t *testing.T) { + result := unexportedMarshalTestStruct{} + err := Unmarshal(unexportedTestToml, &result) + expected := unexportedTestData + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(result, expected) { + t.Errorf("Bad unexported unmarshal: expected %v, got %v", expected, result) + } +} + +type errStruct struct { + Bool bool `toml:"bool"` + Date time.Time `toml:"date"` + Float float64 `toml:"float"` + Int int16 `toml:"int"` + String *string `toml:"string"` +} + +var errTomls = []string{ + "bool = truly\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"", + "bool = true\ndate = 1979-05-27T07:3200Z\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"", + "bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123a4\nint = 5000\nstring = \"Bite me\"", + "bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = j000\nstring = \"Bite me\"", + "bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = Bite me", + "bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = Bite me", + "bool = 1\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"", + "bool = true\ndate = 1\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"", + "bool = true\ndate = 1979-05-27T07:32:00Z\n\"sorry\"\nint = 5000\nstring = \"Bite me\"", + "bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = \"sorry\"\nstring = \"Bite me\"", + "bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = 1", +} + +type mapErr struct { + Vals map[string]float64 +} + +type intErr struct { + Int1 int + Int2 int8 + Int3 int16 + Int4 int32 + Int5 int64 + UInt1 uint + UInt2 uint8 + UInt3 uint16 + UInt4 uint32 + UInt5 uint64 + Flt1 float32 + Flt2 float64 +} + +var intErrTomls = []string{ + "Int1 = []\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0", + "Int1 = 1\nInt2 = []\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0", + "Int1 = 1\nInt2 = 2\nInt3 = []\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0", + "Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = []\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0", + "Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = []\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0", + "Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = []\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0", + "Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = []\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0", + "Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = []\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0", + "Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = []\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0", + "Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = []\nFlt1 = 1.0\nFlt2 = 2.0", + "Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = []\nFlt2 = 2.0", + "Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = []", +} + +func TestErrUnmarshal(t *testing.T) { + for ind, toml := range errTomls { + result := errStruct{} + err := Unmarshal([]byte(toml), &result) + if err == nil { + t.Errorf("Expected err from case %d\n", ind) + } + } + result2 := mapErr{} + err := Unmarshal([]byte("[Vals]\nfred=\"1.2\""), &result2) + if err == nil { + t.Errorf("Expected err from map") + } + for ind, toml := range intErrTomls { + result3 := intErr{} + err := Unmarshal([]byte(toml), &result3) + if err == nil { + t.Errorf("Expected int err from case %d\n", ind) + } + } +} + +type emptyMarshalTestStruct struct { + Title string `toml:"title"` + Bool bool `toml:"bool"` + Int int `toml:"int"` + String string `toml:"string"` + StringList []string `toml:"stringlist"` + Ptr *basicMarshalTestStruct `toml:"ptr"` + Map map[string]string `toml:"map"` +} + +var emptyTestData = emptyMarshalTestStruct{ + Title: "Placeholder", + Bool: false, + Int: 0, + String: "", + StringList: []string{}, + Ptr: nil, + Map: map[string]string{}, +} + +var emptyTestToml = []byte(`bool = false +int = 0 +string = "" +stringlist = [] +title = "Placeholder" + +[map] +`) + +type emptyMarshalTestStruct2 struct { + Title string `toml:"title"` + Bool bool `toml:"bool,omitempty"` + Int int `toml:"int, omitempty"` + String string `toml:"string,omitempty "` + StringList []string `toml:"stringlist,omitempty"` + Ptr *basicMarshalTestStruct `toml:"ptr,omitempty"` + Map map[string]string `toml:"map,omitempty"` +} + +var emptyTestData2 = emptyMarshalTestStruct2{ + Title: "Placeholder", + Bool: false, + Int: 0, + String: "", + StringList: []string{}, + Ptr: nil, + Map: map[string]string{}, +} + +var emptyTestToml2 = []byte(`title = "Placeholder" +`) + +func TestEmptyMarshal(t *testing.T) { + result, err := Marshal(emptyTestData) + if err != nil { + t.Fatal(err) + } + expected := emptyTestToml + if !bytes.Equal(result, expected) { + t.Errorf("Bad empty marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) + } +} + +func TestEmptyMarshalOmit(t *testing.T) { + result, err := Marshal(emptyTestData2) + if err != nil { + t.Fatal(err) + } + expected := emptyTestToml2 + if !bytes.Equal(result, expected) { + t.Errorf("Bad empty omit marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) + } +} + +func TestEmptyUnmarshal(t *testing.T) { + result := emptyMarshalTestStruct{} + err := Unmarshal(emptyTestToml, &result) + expected := emptyTestData + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(result, expected) { + t.Errorf("Bad empty unmarshal: expected %v, got %v", expected, result) + } +} + +func TestEmptyUnmarshalOmit(t *testing.T) { + result := emptyMarshalTestStruct2{} + err := Unmarshal(emptyTestToml, &result) + expected := emptyTestData2 + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(result, expected) { + t.Errorf("Bad empty omit unmarshal: expected %v, got %v", expected, result) + } +} + +type pointerMarshalTestStruct struct { + Str *string + List *[]string + ListPtr *[]*string + Map *map[string]string + MapPtr *map[string]*string + EmptyStr *string + EmptyList *[]string + EmptyMap *map[string]string + DblPtr *[]*[]*string +} + +var pointerStr = "Hello" +var pointerList = []string{"Hello back"} +var pointerListPtr = []*string{&pointerStr} +var pointerMap = map[string]string{"response": "Goodbye"} +var pointerMapPtr = map[string]*string{"alternate": &pointerStr} +var pointerTestData = pointerMarshalTestStruct{ + Str: &pointerStr, + List: &pointerList, + ListPtr: &pointerListPtr, + Map: &pointerMap, + MapPtr: &pointerMapPtr, + EmptyStr: nil, + EmptyList: nil, + EmptyMap: nil, +} + +var pointerTestToml = []byte(`List = ["Hello back"] +ListPtr = ["Hello"] +Str = "Hello" + +[Map] + response = "Goodbye" + +[MapPtr] + alternate = "Hello" +`) + +func TestPointerMarshal(t *testing.T) { + result, err := Marshal(pointerTestData) + if err != nil { + t.Fatal(err) + } + expected := pointerTestToml + if !bytes.Equal(result, expected) { + t.Errorf("Bad pointer marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) + } +} + +func TestPointerUnmarshal(t *testing.T) { + result := pointerMarshalTestStruct{} + err := Unmarshal(pointerTestToml, &result) + expected := pointerTestData + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(result, expected) { + t.Errorf("Bad pointer unmarshal: expected %v, got %v", expected, result) + } +} + +type nestedMarshalTestStruct struct { + String [][]string + //Struct [][]basicMarshalTestSubStruct + StringPtr *[]*[]*string + // StructPtr *[]*[]*basicMarshalTestSubStruct +} + +var str1 = "Three" +var str2 = "Four" +var strPtr = []*string{&str1, &str2} +var strPtr2 = []*[]*string{&strPtr} + +var nestedTestData = nestedMarshalTestStruct{ + String: [][]string{[]string{"Five", "Six"}, []string{"One", "Two"}}, + StringPtr: &strPtr2, +} + +var nestedTestToml = []byte(`String = [["Five","Six"],["One","Two"]] +StringPtr = [["Three","Four"]] +`) + +func TestNestedMarshal(t *testing.T) { + result, err := Marshal(nestedTestData) + if err != nil { + t.Fatal(err) + } + expected := nestedTestToml + if !bytes.Equal(result, expected) { + t.Errorf("Bad nested marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) + } +} + +func TestNestedUnmarshal(t *testing.T) { + result := nestedMarshalTestStruct{} + err := Unmarshal(nestedTestToml, &result) + expected := nestedTestData + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(result, expected) { + t.Errorf("Bad nested unmarshal: expected %v, got %v", expected, result) + } +} diff --git a/vendor/github.com/pelletier/go-toml/marshal_test.toml b/vendor/github.com/pelletier/go-toml/marshal_test.toml new file mode 100644 index 0000000000..1c5f98e7a8 --- /dev/null +++ b/vendor/github.com/pelletier/go-toml/marshal_test.toml @@ -0,0 +1,38 @@ +title = "TOML Marshal Testing" + +[basic] + bool = true + date = 1979-05-27T07:32:00Z + float = 123.4 + int = 5000 + string = "Bite me" + uint = 5001 + +[basic_lists] + bools = [true,false,true] + dates = [1979-05-27T07:32:00Z,1980-05-27T07:32:00Z] + floats = [12.3,45.6,78.9] + ints = [8001,8001,8002] + strings = ["One","Two","Three"] + uints = [5002,5003] + +[basic_map] + one = "one" + two = "two" + +[subdoc] + + [subdoc.first] + name = "First" + + [subdoc.second] + name = "Second" + +[[subdoclist]] + name = "List.First" + +[[subdoclist]] + name = "List.Second" + +[[subdocptrs]] + name = "Second" diff --git a/vendor/github.com/pelletier/go-toml/parser_test.go b/vendor/github.com/pelletier/go-toml/parser_test.go index 61a3a7cc13..58aae203a6 100644 --- a/vendor/github.com/pelletier/go-toml/parser_test.go +++ b/vendor/github.com/pelletier/go-toml/parser_test.go @@ -500,7 +500,8 @@ func TestFloatsWithoutLeadingZeros(t *testing.T) { func TestMissingFile(t *testing.T) { _, err := LoadFile("foo.toml") - if err.Error() != "open foo.toml: no such file or directory" { + if err.Error() != "open foo.toml: no such file or directory" && + err.Error() != "open foo.toml: The system cannot find the file specified." { t.Error("Bad error message:", err.Error()) } } diff --git a/vendor/github.com/pelletier/go-toml/tomltree_create.go b/vendor/github.com/pelletier/go-toml/tomltree_create.go index d447755a62..c6054f358b 100644 --- a/vendor/github.com/pelletier/go-toml/tomltree_create.go +++ b/vendor/github.com/pelletier/go-toml/tomltree_create.go @@ -48,6 +48,8 @@ func simpleValueCoercion(object interface{}) (interface{}, error) { return uint64(original), nil case float32: return float64(original), nil + case fmt.Stringer: + return original.String(), nil default: return nil, fmt.Errorf("cannot convert type %T to TomlTree", object) } @@ -63,6 +65,9 @@ func sliceToTree(object interface{}) (interface{}, error) { value := reflect.ValueOf(object) insideType := value.Type().Elem() length := value.Len() + if length > 0 { + insideType = reflect.ValueOf(value.Index(0).Interface()).Type() + } if insideType.Kind() == reflect.Map { // this is considered as an array of tables tablesArray := make([]*TomlTree, 0, length) @@ -102,9 +107,10 @@ func toTree(object interface{}) (interface{}, error) { values := map[string]interface{}{} keys := value.MapKeys() for _, key := range keys { - k, ok := key.Interface().(string) - if !ok { - return nil, fmt.Errorf("map key needs to be a string, not %T", key.Interface()) + if key.Kind() != reflect.String { + if _, ok := key.Interface().(string); !ok { + return nil, fmt.Errorf("map key needs to be a string, not %T (%v)", key.Interface(), key.Kind()) + } } v := value.MapIndex(key) @@ -112,7 +118,7 @@ func toTree(object interface{}) (interface{}, error) { if err != nil { return nil, err } - values[k] = newValue + values[key.String()] = newValue } return &TomlTree{values, Position{}}, nil } diff --git a/vendor/github.com/pelletier/go-toml/tomltree_create_test.go b/vendor/github.com/pelletier/go-toml/tomltree_create_test.go index 8523f9ee5c..6c1496835e 100644 --- a/vendor/github.com/pelletier/go-toml/tomltree_create_test.go +++ b/vendor/github.com/pelletier/go-toml/tomltree_create_test.go @@ -3,8 +3,17 @@ package toml import ( "testing" "time" + "strconv" ) +type customString string + +type stringer struct{} + +func (s stringer) String() string { + return "stringer" +} + func validate(t *testing.T, path string, object interface{}) { switch o := object.(type) { case *TomlTree: @@ -13,20 +22,19 @@ func validate(t *testing.T, path string, object interface{}) { } case []*TomlTree: for index, tree := range o { - validate(t, path+"."+string(index), tree) + validate(t, path+"."+strconv.Itoa(index), tree) } case *tomlValue: switch o.value.(type) { case int64, uint64, bool, string, float64, time.Time, []int64, []uint64, []bool, []string, []float64, []time.Time: - return // ok default: t.Fatalf("tomlValue at key %s containing incorrect type %T", path, o.value) } default: t.Fatalf("value at key %s is of incorrect type %T", path, object) } - t.Log("validation ok", path) + t.Logf("validation ok %s as %T", path, object) } func validateTree(t *testing.T, tree *TomlTree) { @@ -46,14 +54,16 @@ func TestTomlTreeCreateToTree(t *testing.T) { "uint32": uint32(2), "float32": float32(2), "a_bool": false, + "stringer": stringer{}, "nested": map[string]interface{}{ "foo": "bar", }, - "array": []string{"a", "b", "c"}, - "array_uint": []uint{uint(1), uint(2)}, - "array_table": []map[string]interface{}{map[string]interface{}{"sub_map": 52}}, - "array_times": []time.Time{time.Now(), time.Now()}, - "map_times": map[string]time.Time{"now": time.Now()}, + "array": []string{"a", "b", "c"}, + "array_uint": []uint{uint(1), uint(2)}, + "array_table": []map[string]interface{}{map[string]interface{}{"sub_map": 52}}, + "array_times": []time.Time{time.Now(), time.Now()}, + "map_times": map[string]time.Time{"now": time.Now()}, + "custom_string_map_key": map[customString]interface{}{customString("custom"): "custom"}, } tree, err := TreeFromMap(data) if err != nil { @@ -72,7 +82,7 @@ func TestTomlTreeCreateToTreeInvalidLeafType(t *testing.T) { func TestTomlTreeCreateToTreeInvalidMapKeyType(t *testing.T) { _, err := TreeFromMap(map[string]interface{}{"foo": map[int]interface{}{2: 1}}) - expected := "map key needs to be a string, not int" + expected := "map key needs to be a string, not int (int)" if err.Error() != expected { t.Fatalf("expected error %s, got %s", expected, err.Error()) } @@ -93,3 +103,24 @@ func TestTomlTreeCreateToTreeInvalidTableGroupType(t *testing.T) { t.Fatalf("expected error %s, got %s", expected, err.Error()) } } + +func TestRoundTripArrayOfTables(t *testing.T) { + orig := "\n[[stuff]]\n name = \"foo\"\n things = [\"a\",\"b\"]\n" + tree, err := Load(orig) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + m := tree.ToMap() + + tree, err = TreeFromMap(m) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + want := orig + got := tree.String() + + if got != want { + t.Errorf("want:\n%s\ngot:\n%s", want, got) + } +} diff --git a/vendor/github.com/pelletier/go-toml/tomltree_write.go b/vendor/github.com/pelletier/go-toml/tomltree_write.go index b50b549720..89c3c42292 100644 --- a/vendor/github.com/pelletier/go-toml/tomltree_write.go +++ b/vendor/github.com/pelletier/go-toml/tomltree_write.go @@ -8,6 +8,7 @@ import ( "strconv" "strings" "time" + "reflect" ) // encodes a string to a TOML-compliant string value @@ -60,9 +61,14 @@ func tomlValueStringRepresentation(v interface{}) (string, error) { return value.Format(time.RFC3339), nil case nil: return "", nil - case []interface{}: + } + + rv := reflect.ValueOf(v) + + if rv.Kind() == reflect.Slice { values := []string{} - for _, item := range value { + for i := 0; i < rv.Len(); i++ { + item := rv.Index(i).Interface() itemRepr, err := tomlValueStringRepresentation(item) if err != nil { return "", err @@ -70,9 +76,8 @@ func tomlValueStringRepresentation(v interface{}) (string, error) { values = append(values, itemRepr) } return "[" + strings.Join(values, ",") + "]", nil - default: - return "", fmt.Errorf("unsupported value type %T: %v", value, value) } + return "", fmt.Errorf("unsupported value type %T: %v", v, v) } func (t *TomlTree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (int64, error) { diff --git a/vendor/github.com/pelletier/go-toml/tomltree_write_test.go b/vendor/github.com/pelletier/go-toml/tomltree_write_test.go index 6344b1c014..b5ad8db7c0 100644 --- a/vendor/github.com/pelletier/go-toml/tomltree_write_test.go +++ b/vendor/github.com/pelletier/go-toml/tomltree_write_test.go @@ -119,19 +119,6 @@ func testMaps(t *testing.T, actual, expected map[string]interface{}) { } } -func TestToTomlStringTypeConversionError(t *testing.T) { - tree := TomlTree{ - values: map[string]interface{}{ - "thing": &tomlValue{[]string{"unsupported"}, Position{}}, - }, - } - _, err := tree.ToTomlString() - expected := errors.New("unsupported value type []string: [unsupported]") - if err.Error() != expected.Error() { - t.Errorf("expecting error %s, but got %s instead", expected, err) - } -} - func TestTomlTreeWriteToMapSimple(t *testing.T) { tree, _ := Load("a = 42\nb = 17") From fb7c3fadf9842f4252f777eb4cf96cf57fc18c6d Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Wed, 29 Mar 2017 19:01:16 -0500 Subject: [PATCH 12/20] Replace manual toml mapping --- lock.go | 73 ++++++---------------- manifest.go | 94 ++++++---------------------- toml.go | 177 ---------------------------------------------------- 3 files changed, 37 insertions(+), 307 deletions(-) delete mode 100644 toml.go diff --git a/lock.go b/lock.go index 46dc2bff69..7716e0660f 100644 --- a/lock.go +++ b/lock.go @@ -9,6 +9,7 @@ import ( "io" "sort" + "bytes" "github.com/pelletier/go-toml" "github.com/pkg/errors" "github.com/sdboyer/gps" @@ -22,35 +23,32 @@ type Lock struct { } type rawLock struct { - Memo string - Projects []rawLockedProject + Memo string `toml:"memo"` + Projects []rawLockedProject `toml:"projects"` } type rawLockedProject struct { - Name string - Branch string - Revision string - Version string - Source string - Packages []string + Name string `toml:"name"` + Branch string `toml:"branch,omitempty"` + Revision string `toml:"revision"` + Version string `toml:"version,omitempty"` + Source string `toml:"source,omitempty"` + Packages []string `toml:"packages"` } func readLock(r io.Reader) (*Lock, error) { - tree, err := toml.LoadReader(r) + buf := &bytes.Buffer{} + _, err := buf.ReadFrom(r) if err != nil { - return nil, errors.Wrap(err, "Unable to parse the lock as TOML") + return nil, errors.Wrap(err, "Unable to read byte stream") } - mapper := &tomlMapper{Tree: tree} - - raw := rawLock{ - Memo: readKeyAsString(mapper, "memo"), - Projects: readTableAsLockedProjects(mapper, "projects"), + raw := rawLock{} + err = toml.Unmarshal(buf.Bytes(), &raw) + if err != nil { + return nil, errors.Wrap(err, "Unable to parse the lock as TOML") } - if mapper.Error != nil { - return nil, errors.Wrap(mapper.Error, "Invalid lock structure") - } return fromRawLock(raw) } @@ -127,43 +125,8 @@ func (l *Lock) toRaw() rawLock { func (l *Lock) MarshalTOML() (string, error) { raw := l.toRaw() - - m := make(map[string]interface{}) - m["memo"] = raw.Memo - p := make([]map[string]interface{}, len(raw.Projects)) - for i := 0; i < len(p); i++ { - srcPrj := raw.Projects[i] - prj := make(map[string]interface{}) - prj["name"] = srcPrj.Name - prj["revision"] = srcPrj.Revision - - if srcPrj.Source != "" { - prj["source"] = srcPrj.Source - } - if srcPrj.Branch != "" { - prj["branch"] = srcPrj.Branch - } - if srcPrj.Version != "" { - prj["version"] = srcPrj.Version - } - - pkgs := make([]interface{}, len(srcPrj.Packages)) - for j := range srcPrj.Packages { - pkgs[j] = srcPrj.Packages[j] - } - prj["packages"] = pkgs - - p[i] = prj - } - m["projects"] = p - - t, err := toml.TreeFromMap(m) - if err != nil { - return "", errors.Wrap(err, "Unable to marshal lock to TOML tree") - } - - result, err := t.ToTomlString() - return result, errors.Wrap(err, "Unable to marshal lock to TOML string") + result, err := toml.Marshal(raw) + return string(result), errors.Wrap(err, "Unable to marshal lock to TOML string") } // TODO(carolynvs) this should be moved to gps diff --git a/manifest.go b/manifest.go index 054976242c..f9202b8277 100644 --- a/manifest.go +++ b/manifest.go @@ -8,6 +8,7 @@ import ( "io" "sort" + "bytes" "github.com/pelletier/go-toml" "github.com/pkg/errors" "github.com/sdboyer/gps" @@ -23,37 +24,33 @@ type Manifest struct { } type rawManifest struct { - Dependencies []rawProject - Overrides []rawProject - Ignores []string - Required []string + Dependencies []rawProject `toml:"dependencies,omitempty"` + Overrides []rawProject `toml:"overrides,omitempty"` + Ignores []string `toml:"ignores,omitempty"` + Required []string `toml:"required,omitempty"` } type rawProject struct { - Name string - Branch string - Revision string - Version string - Source string + Name string `toml:"name"` + Branch string `toml:"branch,omitempty"` + Revision string `toml:"revision,omitempty"` + Version string `toml:"version,omitempty"` + Source string `toml:"source,omitempty"` } func readManifest(r io.Reader) (*Manifest, error) { - tree, err := toml.LoadReader(r) + buf := &bytes.Buffer{} + _, err := buf.ReadFrom(r) if err != nil { - return nil, errors.Wrap(err, "Unable to parse the manifest as TOML") + return nil, errors.Wrap(err, "Unable to read byte stream") } - mapper := &tomlMapper{Tree: tree} - raw := rawManifest{ - Dependencies: readTableAsProjects(mapper, "dependencies"), - Overrides: readTableAsProjects(mapper, "overrides"), - Required: readKeyAsStringList(mapper, "required"), - Ignores: readKeyAsStringList(mapper, "ignores"), + raw := rawManifest{} + err = toml.Unmarshal(buf.Bytes(), &raw) + if err != nil { + return nil, errors.Wrap(err, "Unable to parse the manifest as TOML") } - if mapper.Error != nil { - return nil, errors.Wrap(mapper.Error, "Invalid manifest structure") - } return fromRawManifest(raw) } @@ -159,61 +156,8 @@ func (s sortedRawProjects) Less(i, j int) bool { func (m *Manifest) MarshalTOML() (string, error) { raw := m.toRaw() - - mapRawProject := func(raw rawProject) map[string]interface{} { - prj := make(map[string]interface{}) - prj["name"] = raw.Name - if raw.Source != "" { - prj["source"] = raw.Source - } - if raw.Branch != "" { - prj["branch"] = raw.Branch - } - if raw.Version != "" { - prj["version"] = raw.Version - } - if raw.Revision != "" { - prj["revision"] = raw.Revision - } - return prj - } - - mapRawProjects := func(src []rawProject) []map[string]interface{} { - dest := make([]map[string]interface{}, len(src)) - for i := 0; i < len(src); i++ { - dest[i] = mapRawProject(src[i]) - } - return dest - } - - copyProjectRefs := func(src []string) []interface{} { - dest := make([]interface{}, len(src)) - for i := range src { - dest[i] = src[i] - } - return dest - } - - data := make(map[string]interface{}) - if len(raw.Dependencies) > 0 { - data["dependencies"] = mapRawProjects(raw.Dependencies) - } - if len(raw.Overrides) > 0 { - data["overrides"] = mapRawProjects(raw.Overrides) - } - if len(raw.Ignores) > 0 { - data["ignores"] = copyProjectRefs(raw.Ignores) - } - if len(raw.Required) > 0 { - data["required"] = copyProjectRefs(raw.Required) - } - - tree, err := toml.TreeFromMap(data) - if err != nil { - return "", errors.Wrap(err, "Unable to marshal the lock to a TOML tree") - } - result, err := tree.ToTomlString() - return result, errors.Wrap(err, "Unable to marshal the lock to a TOML string") + result, err := toml.Marshal(raw) + return string(result), errors.Wrap(err, "Unable to marshal the lock to a TOML string") } func toRawProject(name gps.ProjectRoot, project gps.ProjectProperties) rawProject { diff --git a/toml.go b/toml.go deleted file mode 100644 index fb5324f477..0000000000 --- a/toml.go +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package dep - -import ( - "github.com/pelletier/go-toml" - "github.com/pkg/errors" -) - -type tomlMapper struct { - Tree *toml.TomlTree - Error error -} - -func readTableAsProjects(mapper *tomlMapper, table string) []rawProject { - if mapper.Error != nil { // Stop mapping if an error has already occurred - return nil - } - - query, err := mapper.Tree.Query("$." + table) - if err != nil { - mapper.Error = errors.Wrapf(err, "Unable to query for [[%s]]", table) - return nil - } - - matches := query.Values() - if len(matches) == 0 { - return nil - } - - tables, ok := matches[0].([]*toml.TomlTree) - if !ok { - mapper.Error = errors.Errorf("Invalid query result type for [[%s]], should be a TOML array of tables but got %T", table, matches[0]) - return nil - } - - subMapper := &tomlMapper{} - projects := make([]rawProject, len(tables)) - for i := 0; i < len(tables); i++ { - subMapper.Tree = tables[i] - projects[i] = mapProject(subMapper) - } - - if subMapper.Error != nil { - mapper.Error = subMapper.Error - return nil - } - return projects -} - -func readTableAsLockedProjects(mapper *tomlMapper, table string) []rawLockedProject { - if mapper.Error != nil { // Stop mapping if an error has already occurred - return nil - } - - query, err := mapper.Tree.Query("$." + table) - if err != nil { - mapper.Error = errors.Wrapf(err, "Unable to query for [[%s]]", table) - return nil - } - - matches := query.Values() - if len(matches) == 0 { - return nil - } - - tables, ok := matches[0].([]*toml.TomlTree) - if !ok { - mapper.Error = errors.Errorf("Invalid query result type for [[%s]], should be a TOML array of tables but got %T", table, matches[0]) - return nil - } - - subMapper := &tomlMapper{} - projects := make([]rawLockedProject, len(tables)) - for i := 0; i < len(tables); i++ { - subMapper.Tree = tables[i] - projects[i] = mapLockedProject(subMapper) - } - - if subMapper.Error != nil { - mapper.Error = subMapper.Error - return nil - } - return projects -} - -func mapProject(mapper *tomlMapper) rawProject { - if mapper.Error != nil { // Stop mapping if an error has already occurred - return rawProject{} - } - - prj := rawProject{ - Name: readKeyAsString(mapper, "name"), - Branch: readKeyAsString(mapper, "branch"), - Revision: readKeyAsString(mapper, "revision"), - Version: readKeyAsString(mapper, "version"), - Source: readKeyAsString(mapper, "source"), - } - - if mapper.Error != nil { - return rawProject{} - } - - return prj -} - -func mapLockedProject(mapper *tomlMapper) rawLockedProject { - if mapper.Error != nil { // Stop mapping if an error has already occurred - return rawLockedProject{} - } - - prj := rawLockedProject{ - Name: readKeyAsString(mapper, "name"), - Branch: readKeyAsString(mapper, "branch"), - Revision: readKeyAsString(mapper, "revision"), - Version: readKeyAsString(mapper, "version"), - Source: readKeyAsString(mapper, "source"), - Packages: readKeyAsStringList(mapper, "packages"), - } - - if mapper.Error != nil { - return rawLockedProject{} - } - - return prj -} - -func readKeyAsString(mapper *tomlMapper, key string) string { - if mapper.Error != nil { // Stop mapping if an error has already occurred - return "" - } - - rawValue := mapper.Tree.GetDefault(key, "") - value, ok := rawValue.(string) - if !ok { - mapper.Error = errors.Errorf("Invalid type for %s, should be a string, but it is a %T", key, rawValue) - return "" - } - - return value -} - -func readKeyAsStringList(mapper *tomlMapper, key string) []string { - if mapper.Error != nil { // Stop mapping if an error has already occurred - return nil - } - - query, err := mapper.Tree.Query("$." + key) - if err != nil { - mapper.Error = errors.Wrapf(err, "Unable to query for [%s]", key) - return nil - } - - matches := query.Values() - if len(matches) == 0 { - return nil - } - - lists, ok := matches[0].([]interface{}) - if !ok { - mapper.Error = errors.Errorf("Invalid query result type for [%s], should be a TOML list ([]interface{}) but got %T", key, matches[0]) - return nil - } - - results := make([]string, len(lists)) - for i := range lists { - ref, ok := lists[i].(string) - if !ok { - mapper.Error = errors.Errorf("Invalid query result item type for [%s], should be a TOML list of strings([]string) but got %T", key, lists[i]) - return nil - } - results[i] = ref - } - return results -} From 0f9b94178b85840fb6aca10f82d3c61ef76a6782 Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Sun, 2 Apr 2017 14:36:22 -0500 Subject: [PATCH 13/20] Use filepath.Join and filename constants instead of hardcoding test file paths --- analyzer_test.go | 2 +- context_test.go | 22 +++++++++++----------- txn_writer.go | 6 +++--- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/analyzer_test.go b/analyzer_test.go index 645d230da0..0d3f4a6a82 100644 --- a/analyzer_test.go +++ b/analyzer_test.go @@ -18,7 +18,7 @@ func TestDeriveManifestAndLock(t *testing.T) { defer h.Cleanup() h.TempDir("dep") - golden := "analyzer/manifest.toml" + golden := filepath.Join("analyzer", ManifestName) want := h.GetTestFileString(golden) h.TempCopy(filepath.Join("dep", ManifestName), golden) diff --git a/context_test.go b/context_test.go index 634d6f1bf8..ceaad7a068 100644 --- a/context_test.go +++ b/context_test.go @@ -159,11 +159,11 @@ func TestLoadProject(t *testing.T) { tg.TempDir("src") tg.TempDir("src/test1") tg.TempDir("src/test1/sub") - tg.TempFile("src/test1/manifest.toml", "") - tg.TempFile("src/test1/lock.toml", `memo = "cdafe8641b28cd16fe025df278b0a49b9416859345d8b6ba0ace0272b74925ee"`) + tg.TempFile(filepath.Join("src/test1", ManifestName), "") + tg.TempFile(filepath.Join("src/test1", LockName), `memo = "cdafe8641b28cd16fe025df278b0a49b9416859345d8b6ba0ace0272b74925ee"`) tg.TempDir("src/test2") tg.TempDir("src/test2/sub") - tg.TempFile("src/test2/manifest.toml", "") + tg.TempFile(filepath.Join("src/test2", ManifestName), "") tg.Setenv("GOPATH", tg.Path(".")) var testcases = []struct { @@ -251,8 +251,8 @@ func TestLoadProjectManifestParseError(t *testing.T) { tg.TempDir("src") tg.TempDir("src/test1") - tg.TempFile("src/test1/manifest.toml", `[[dependencies]]`) - tg.TempFile("src/test1/lock.toml", `memo = "cdafe8641b28cd16fe025df278b0a49b9416859345d8b6ba0ace0272b74925ee"\n\n[[projects]]`) + tg.TempFile(filepath.Join("src/test1", ManifestName), `[[dependencies]]`) + tg.TempFile(filepath.Join("src/test1", LockName), `memo = "cdafe8641b28cd16fe025df278b0a49b9416859345d8b6ba0ace0272b74925ee"\n\n[[projects]]`) tg.Setenv("GOPATH", tg.Path(".")) ctx := &Ctx{GOPATH: tg.Path(".")} @@ -271,8 +271,8 @@ func TestLoadProjectLockParseError(t *testing.T) { tg.TempDir("src") tg.TempDir("src/test1") - tg.TempFile("src/test1/manifest.toml", `[[dependencies]]`) - tg.TempFile("src/test1/lock.toml", `memo = "cdafe8641b28cd16fe025df278b0a49b9416859345d8b6ba0ace0272b74925ee"\n\n[[projects]]`) + tg.TempFile(filepath.Join("src/test1", ManifestName), `[[dependencies]]`) + tg.TempFile(filepath.Join("src/test1", LockName), `memo = "cdafe8641b28cd16fe025df278b0a49b9416859345d8b6ba0ace0272b74925ee"\n\n[[projects]]`) tg.Setenv("GOPATH", tg.Path(".")) ctx := &Ctx{GOPATH: tg.Path(".")} @@ -290,15 +290,15 @@ func TestLoadProjectNoSrcDir(t *testing.T) { defer tg.Cleanup() tg.TempDir("test1") - tg.TempFile("test1/manifest.toml", `[[dependencies]]`) - tg.TempFile("test1/lock.toml", `memo = "cdafe8641b28cd16fe025df278b0a49b9416859345d8b6ba0ace0272b74925ee"\n\n[[projects]]`) + tg.TempFile(filepath.Join("test1", ManifestName), `[[dependencies]]`) + tg.TempFile(filepath.Join("test1", LockName), `memo = "cdafe8641b28cd16fe025df278b0a49b9416859345d8b6ba0ace0272b74925ee"\n\n[[projects]]`) tg.Setenv("GOPATH", tg.Path(".")) ctx := &Ctx{GOPATH: tg.Path(".")} path := filepath.Join("test1") tg.Cd(tg.Path(path)) - f, _ := os.OpenFile(filepath.Join(ctx.GOPATH, "src", "test1", "lock.toml"), os.O_WRONLY, os.ModePerm) + f, _ := os.OpenFile(filepath.Join(ctx.GOPATH, "src", "test1", LockName), os.O_WRONLY, os.ModePerm) defer f.Close() _, err := ctx.LoadProject("") @@ -319,7 +319,7 @@ func TestCaseInsentitiveGOPATH(t *testing.T) { h.TempDir("src") h.TempDir("src/test1") - h.TempFile("src/test1/manifest.toml", `[[dependencies]]`) + h.TempFile(filepath.Join("src/test1", ManifestName), `[[dependencies]]`) // Shuffle letter case rs := []rune(strings.ToLower(h.Path("."))) diff --git a/txn_writer.go b/txn_writer.go index 4774dd4685..102e1dbbf8 100644 --- a/txn_writer.go +++ b/txn_writer.go @@ -395,7 +395,7 @@ fail: func (sw *SafeWriter) PrintPreparedActions() error { if sw.Payload.HasManifest() { - fmt.Println("Would have written the following manifest.toml:") + fmt.Printf("Would have written the following %s:\n", ManifestName) m, err := sw.Payload.Manifest.MarshalTOML() if err != nil { return errors.Wrap(err, "ensure DryRun cannot serialize manifest") @@ -405,14 +405,14 @@ func (sw *SafeWriter) PrintPreparedActions() error { if sw.Payload.HasLock() { if sw.Payload.LockDiff == nil { - fmt.Println("Would have written the following lock.toml:") + fmt.Printf("Would have written the following %s:\n", LockName) l, err := sw.Payload.Lock.MarshalTOML() if err != nil { return errors.Wrap(err, "ensure DryRun cannot serialize lock") } fmt.Println(string(l)) } else { - fmt.Println("Would have written the following changes to lock.toml:") + fmt.Printf("Would have written the following changes to %s:\n", LockName) diff, err := sw.Payload.LockDiff.Format() if err != nil { return errors.Wrap(err, "ensure DryRun cannot serialize the lock diff") From 9065775696f3317c7202f60db35d5a003c4ecfb9 Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Sun, 2 Apr 2017 15:20:21 -0500 Subject: [PATCH 14/20] Do not export the TOML marshaler interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is a temporary interface that we don’t want to expose because it will eventually be implemented in the go-toml package --- fs.go | 12 ++++++------ lock.go | 4 ++-- manifest.go | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/fs.go b/fs.go index 83d568981a..d623350d3e 100644 --- a/fs.go +++ b/fs.go @@ -15,11 +15,11 @@ import ( "github.com/pkg/errors" ) -// Marshaler is the interface implemented by types that +// tomlMarshaler is the interface implemented by types that // can marshal themselves into valid TOML. -// TODO(carolynvs) Consider adding this to go-toml? -type Marshaler interface { - MarshalTOML() (string, error) +// TODO(carolynvs) Add this (and an unmarshaler) to go-toml, implemented using the same patterns in encoding/json +type tomlMarshaler interface { + MarshalTOML() ([]byte, error) } func IsRegular(name string) (bool, error) { @@ -65,7 +65,7 @@ func IsNonEmptyDir(name string) (bool, error) { return len(files) != 0, nil } -func writeFile(path string, in Marshaler) error { +func writeFile(path string, in tomlMarshaler) error { f, err := os.Create(path) if err != nil { return err @@ -77,7 +77,7 @@ func writeFile(path string, in Marshaler) error { return err } - _, err = f.WriteString(s) + _, err = f.Write(s) return err } diff --git a/lock.go b/lock.go index 7716e0660f..ed5dce03ee 100644 --- a/lock.go +++ b/lock.go @@ -123,10 +123,10 @@ func (l *Lock) toRaw() rawLock { return raw } -func (l *Lock) MarshalTOML() (string, error) { +func (l *Lock) MarshalTOML() ([]byte, error) { raw := l.toRaw() result, err := toml.Marshal(raw) - return string(result), errors.Wrap(err, "Unable to marshal lock to TOML string") + return result, errors.Wrap(err, "Unable to marshal lock to TOML string") } // TODO(carolynvs) this should be moved to gps diff --git a/manifest.go b/manifest.go index f9202b8277..2ed012136d 100644 --- a/manifest.go +++ b/manifest.go @@ -154,10 +154,10 @@ func (s sortedRawProjects) Less(i, j int) bool { return l.Source < r.Source } -func (m *Manifest) MarshalTOML() (string, error) { +func (m *Manifest) MarshalTOML() ([]byte, error) { raw := m.toRaw() result, err := toml.Marshal(raw) - return string(result), errors.Wrap(err, "Unable to marshal the lock to a TOML string") + return result, errors.Wrap(err, "Unable to marshal the lock to a TOML string") } func toRawProject(name gps.ProjectRoot, project gps.ProjectProperties) rawProject { From f67fc9804a7a9e2a7ea83cd2128ea0577c60a019 Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Sun, 2 Apr 2017 15:30:56 -0500 Subject: [PATCH 15/20] Validate manifest for duplicate dependencies --- manifest.go | 3 +++ manifest_test.go | 3 ++- testdata/manifest/{error.toml => error1.toml} | 0 testdata/manifest/error2.toml | 9 +++++++++ 4 files changed, 14 insertions(+), 1 deletion(-) rename testdata/manifest/{error.toml => error1.toml} (100%) create mode 100644 testdata/manifest/error2.toml diff --git a/manifest.go b/manifest.go index 2ed012136d..31138e7bd3 100644 --- a/manifest.go +++ b/manifest.go @@ -67,6 +67,9 @@ func fromRawManifest(raw rawManifest) (*Manifest, error) { if err != nil { return nil, err } + if _, exists := m.Dependencies[name]; exists { + return nil, errors.Errorf("multiple dependencies specified for %s, can only specify one", name) + } m.Dependencies[name] = prj } diff --git a/manifest_test.go b/manifest_test.go index 9304b814c0..04726d304b 100644 --- a/manifest_test.go +++ b/manifest_test.go @@ -104,7 +104,8 @@ func TestReadManifestErrors(t *testing.T) { name string file string }{ - {"multiple constraints", "manifest/error.toml"}, + {"multiple constraints", "manifest/error1.toml"}, + {"multiple dependencies", "manifest/error2.toml"}, } for _, tst := range tests { diff --git a/testdata/manifest/error.toml b/testdata/manifest/error1.toml similarity index 100% rename from testdata/manifest/error.toml rename to testdata/manifest/error1.toml diff --git a/testdata/manifest/error2.toml b/testdata/manifest/error2.toml new file mode 100644 index 0000000000..c29276622e --- /dev/null +++ b/testdata/manifest/error2.toml @@ -0,0 +1,9 @@ +ignores = ["github.com/foo/bar"] + +[[dependencies]] + name = "github.com/sdboyer/gps" + branch = "master" + +[[dependencies]] + name = "github.com/sdboyer/gps" + branch = "master" From 9b835ca0c8b6cb4343d3a7c48f902eb1b50a7f19 Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Sun, 2 Apr 2017 15:36:14 -0500 Subject: [PATCH 16/20] Remove TODO comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Even when gps is moved into dep, sortedConstraints won’t be exported --- manifest.go | 1 - 1 file changed, 1 deletion(-) diff --git a/manifest.go b/manifest.go index 31138e7bd3..072f110fef 100644 --- a/manifest.go +++ b/manifest.go @@ -139,7 +139,6 @@ func (m *Manifest) toRaw() rawManifest { return raw } -// TODO(carolynvs) when gps is moved, we can use the unexported gps.sortedConstraints type sortedRawProjects []rawProject func (s sortedRawProjects) Len() int { return len(s) } From b30a25cd66853b4721e6da6fd32ebf875f73db8a Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Sun, 2 Apr 2017 15:39:48 -0500 Subject: [PATCH 17/20] Use reflection-based TOML mapping for the LockDiff --- txn_writer.go | 56 ++++++++------------------------------------------- 1 file changed, 8 insertions(+), 48 deletions(-) diff --git a/txn_writer.go b/txn_writer.go index 102e1dbbf8..1a13c2b77d 100644 --- a/txn_writer.go +++ b/txn_writer.go @@ -72,11 +72,11 @@ func (diff *LockDiff) Format() (string, error) { writeDiffs := func(diffs []LockedProjectDiff) error { for i := 0; i < len(diffs); i++ { - chunk, err := diffs[i].MarshalTOML() + chunk, err := toml.Marshal(diffs[i]) if err != nil { return err } - buf.WriteString(chunk) + buf.Write(chunk) } buf.WriteString("\n") return nil @@ -113,52 +113,12 @@ func (diff *LockDiff) Format() (string, error) { // Fields are only populated when there is a difference, otherwise they are empty. // TODO(carolynvs) this should be moved to gps type LockedProjectDiff struct { - Name gps.ProjectRoot - Source *StringDiff - Version *StringDiff - Branch *StringDiff - Revision *StringDiff - Packages []StringDiff -} - -func (diff *LockedProjectDiff) MarshalTOML() (string, error) { - prj := make(map[string]interface{}) - prj["name"] = string(diff.Name) - - if diff.Source != nil { - prj["source"] = diff.Source.String() - } - - if diff.Version != nil { - prj["version"] = diff.Version.String() - } - - if diff.Branch != nil { - prj["branch"] = diff.Branch.String() - } - - if diff.Revision != nil { - prj["revision"] = diff.Revision.String() - } - - if len(diff.Packages) > 0 { - p := make([]interface{}, len(diff.Packages)) - for i := 0; i < len(diff.Packages); i++ { - p[i] = diff.Packages[i].String() - } - prj["packages"] = p - } - - m := make(map[string]interface{}) - m["projects"] = []map[string]interface{}{prj} - - t, err := toml.TreeFromMap(m) - if err != nil { - return "", errors.Wrap(err, "Unable to marshal lock diff to TOML tree") - } - - result, err := t.ToTomlString() - return result, errors.Wrap(err, "Unable to marshal lock diff to TOML string") + Name gps.ProjectRoot `toml:"name"` + Source *StringDiff `toml:"source"` + Version *StringDiff `toml:"version"` + Branch *StringDiff `toml:"branch"` + Revision *StringDiff `toml:"revision"` + Packages []StringDiff `toml:"packages"` } type StringDiff struct { From 0afa554494dd4f6d443a17569643ad4a17d41b37 Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Tue, 4 Apr 2017 20:47:09 -0500 Subject: [PATCH 18/20] Update go-toml for nested custom Marshaler support --- fs.go | 10 +--- lock.toml | 6 +-- txn_writer.go | 29 ++++++----- .../github.com/pelletier/go-toml/marshal.go | 22 ++++++++- .../pelletier/go-toml/marshal_test.go | 48 +++++++++++++++++++ .../pelletier/go-toml/tomltree_write.go | 3 ++ 6 files changed, 95 insertions(+), 23 deletions(-) diff --git a/fs.go b/fs.go index d623350d3e..5837342590 100644 --- a/fs.go +++ b/fs.go @@ -12,16 +12,10 @@ import ( "runtime" "syscall" + "github.com/pelletier/go-toml" "github.com/pkg/errors" ) -// tomlMarshaler is the interface implemented by types that -// can marshal themselves into valid TOML. -// TODO(carolynvs) Add this (and an unmarshaler) to go-toml, implemented using the same patterns in encoding/json -type tomlMarshaler interface { - MarshalTOML() ([]byte, error) -} - func IsRegular(name string) (bool, error) { // TODO: lstat? fi, err := os.Stat(name) @@ -65,7 +59,7 @@ func IsNonEmptyDir(name string) (bool, error) { return len(files) != 0, nil } -func writeFile(path string, in tomlMarshaler) error { +func writeFile(path string, in toml.Marshaler) error { f, err := os.Create(path) if err != nil { return err diff --git a/lock.toml b/lock.toml index 4e079213c4..37c5c92044 100644 --- a/lock.toml +++ b/lock.toml @@ -1,4 +1,4 @@ -memo = "31a7162c06758e4619ed89b91e1f48bf94ad14f394bbee79299ed0bb5150e409" +memo = "2f117dcf1ebe1cff7acbddb851d29b87554d2249f1033f2a4cca3b33dc3fecc2" [[projects]] branch = "2.x" @@ -9,7 +9,7 @@ memo = "31a7162c06758e4619ed89b91e1f48bf94ad14f394bbee79299ed0bb5150e409" [[projects]] name = "github.com/Masterminds/vcs" packages = ["."] - revision = "fbe9fb6ad5b5f35b3e82a7c21123cfc526cbf895" + revision = "795e20f901c3d561de52811fb3488a2cb2c8588b" version = "v1.11.0" [[projects]] @@ -27,8 +27,8 @@ memo = "31a7162c06758e4619ed89b91e1f48bf94ad14f394bbee79299ed0bb5150e409" [[projects]] branch = "master" name = "github.com/pelletier/go-toml" - revision = "e32a2e04744250647a72bf17da1b09befc03b6b1" packages = ["."] + revision = "fe206efb84b2bc8e8cfafe6b4c1826622be969e3" [[projects]] name = "github.com/pkg/errors" diff --git a/txn_writer.go b/txn_writer.go index 1a13c2b77d..141fa5954c 100644 --- a/txn_writer.go +++ b/txn_writer.go @@ -59,6 +59,10 @@ type LockDiff struct { Modify []LockedProjectDiff } +type rawLockedProjectDiffs struct { + Projects []LockedProjectDiff `toml:"projects"` +} + func (diff *LockDiff) Format() (string, error) { if diff == nil { return "", nil @@ -71,13 +75,12 @@ func (diff *LockDiff) Format() (string, error) { } writeDiffs := func(diffs []LockedProjectDiff) error { - for i := 0; i < len(diffs); i++ { - chunk, err := toml.Marshal(diffs[i]) - if err != nil { - return err - } - buf.Write(chunk) + raw := rawLockedProjectDiffs{diffs} + chunk, err := toml.Marshal(raw) + if err != nil { + return err } + buf.Write(chunk) buf.WriteString("\n") return nil } @@ -114,11 +117,11 @@ func (diff *LockDiff) Format() (string, error) { // TODO(carolynvs) this should be moved to gps type LockedProjectDiff struct { Name gps.ProjectRoot `toml:"name"` - Source *StringDiff `toml:"source"` - Version *StringDiff `toml:"version"` - Branch *StringDiff `toml:"branch"` - Revision *StringDiff `toml:"revision"` - Packages []StringDiff `toml:"packages"` + Source *StringDiff `toml:"source,omitempty"` + Version *StringDiff `toml:"version,omitempty"` + Branch *StringDiff `toml:"branch,omitempty"` + Revision *StringDiff `toml:"revision,omitempty"` + Packages []StringDiff `toml:"packages,omitempty"` } type StringDiff struct { @@ -142,6 +145,10 @@ func (diff StringDiff) String() string { return diff.Current } +func (diff StringDiff) MarshalTOML() ([]byte, error) { + return []byte(diff.String()), nil +} + // VendorBehavior defines when the vendor directory should be written. type VendorBehavior int diff --git a/vendor/github.com/pelletier/go-toml/marshal.go b/vendor/github.com/pelletier/go-toml/marshal.go index 4301a4513f..a1d7010468 100644 --- a/vendor/github.com/pelletier/go-toml/marshal.go +++ b/vendor/github.com/pelletier/go-toml/marshal.go @@ -33,6 +33,7 @@ type tomlOpts struct { } var timeType = reflect.TypeOf(time.Time{}) +var marshalerType = reflect.TypeOf(new(Marshaler)).Elem() // Check if the given marshall type maps to a TomlTree primitive func isPrimitive(mtype reflect.Type) bool { @@ -50,7 +51,7 @@ func isPrimitive(mtype reflect.Type) bool { case reflect.String: return true case reflect.Struct: - return mtype == timeType + return mtype == timeType || isCustomMarshaler(mtype) default: return false } @@ -90,6 +91,20 @@ func isTree(mtype reflect.Type) bool { } } +func isCustomMarshaler(mtype reflect.Type) bool { + return mtype.Implements(marshalerType) +} + +func callCustomMarshaler(mval reflect.Value) ([]byte, error) { + return mval.Interface().(Marshaler).MarshalTOML() +} + +// Marshaler is the interface implemented by types that +// can marshal themselves into valid TOML. +type Marshaler interface { + MarshalTOML() ([]byte, error) +} + /* Marshal returns the TOML encoding of v. Behavior is similar to the Go json encoder, except that there is no concept of a Marshaler interface or MarshalTOML @@ -106,6 +121,9 @@ func Marshal(v interface{}) ([]byte, error) { return []byte{}, errors.New("Only a struct can be marshaled to TOML") } sval := reflect.ValueOf(v) + if isCustomMarshaler(mtype) { + return callCustomMarshaler(sval) + } t, err := valueToTree(mtype, sval) if err != nil { return []byte{}, err @@ -178,6 +196,8 @@ func valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) { return valueToToml(mtype.Elem(), mval.Elem()) } switch { + case isCustomMarshaler(mtype): + return callCustomMarshaler(mval) case isTree(mtype): return valueToTree(mtype, mval) case isTreeSlice(mtype): diff --git a/vendor/github.com/pelletier/go-toml/marshal_test.go b/vendor/github.com/pelletier/go-toml/marshal_test.go index c8dee94ded..891222e9b1 100644 --- a/vendor/github.com/pelletier/go-toml/marshal_test.go +++ b/vendor/github.com/pelletier/go-toml/marshal_test.go @@ -3,6 +3,7 @@ package toml import ( "bytes" "encoding/json" + "fmt" "io/ioutil" "reflect" "testing" @@ -533,3 +534,50 @@ func TestNestedUnmarshal(t *testing.T) { t.Errorf("Bad nested unmarshal: expected %v, got %v", expected, result) } } + +type customMarshalerParent struct { + Self customMarshaler `toml:"me"` + Friends []customMarshaler `toml:"friends"` +} + +type customMarshaler struct { + FirsName string + LastName string +} + +func (c customMarshaler) MarshalTOML() ([]byte, error) { + fullName := fmt.Sprintf("%s %s", c.FirsName, c.LastName) + return []byte(fullName), nil +} + +var customMarshalerData = customMarshaler{FirsName: "Sally", LastName: "Fields"} +var customMarshalerToml = []byte(`Sally Fields`) +var nestedCustomMarshalerData = customMarshalerParent{ + Self: customMarshaler{FirsName: "Maiku", LastName: "Suteda"}, + Friends: []customMarshaler{customMarshalerData}, +} +var nestedCustomMarshalerToml = []byte(`friends = ["Sally Fields"] +me = "Maiku Suteda" +`) + +func TestCustomMarshaler(t *testing.T) { + result, err := Marshal(customMarshalerData) + if err != nil { + t.Fatal(err) + } + expected := customMarshalerToml + if !bytes.Equal(result, expected) { + t.Errorf("Bad custom marshaler: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) + } +} + +func TestNestedCustomMarshaler(t *testing.T) { + result, err := Marshal(nestedCustomMarshalerData) + if err != nil { + t.Fatal(err) + } + expected := nestedCustomMarshalerToml + if !bytes.Equal(result, expected) { + t.Errorf("Bad nested custom marshaler: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result) + } +} diff --git a/vendor/github.com/pelletier/go-toml/tomltree_write.go b/vendor/github.com/pelletier/go-toml/tomltree_write.go index 89c3c42292..6a7fa17458 100644 --- a/vendor/github.com/pelletier/go-toml/tomltree_write.go +++ b/vendor/github.com/pelletier/go-toml/tomltree_write.go @@ -52,6 +52,9 @@ func tomlValueStringRepresentation(v interface{}) (string, error) { return strconv.FormatFloat(value, 'f', -1, 32), nil case string: return "\"" + encodeTomlString(value) + "\"", nil + case []byte: + b, _ := v.([]byte) + return tomlValueStringRepresentation(string(b)) case bool: if value { return "true", nil From a068a3c63726acce709e0e59cf16a3e0a09e5015 Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Tue, 4 Apr 2017 21:05:53 -0500 Subject: [PATCH 19/20] Use a constant for the manifest/lock file names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can’t reference dep.ManifestName/LockName because it would create a circular reference --- test/test.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/test.go b/test/test.go index 3ea6668196..ba3a780145 100644 --- a/test/test.go +++ b/test/test.go @@ -29,6 +29,11 @@ var ( PrintLogs *bool = flag.Bool("logs", false, "log stdin/stdout of test commands") ) +const ( + manifestName string = "manifest.toml" + lockName string = "lock.toml" +) + func init() { switch runtime.GOOS { case "windows": @@ -584,7 +589,7 @@ func (h *Helper) Cleanup() { // ReadManifest returns the manifest in the current directory. func (h *Helper) ReadManifest() string { - m := filepath.Join(h.pwd(), "manifest.toml") + m := filepath.Join(h.pwd(), manifestName) h.MustExist(m) f, err := ioutil.ReadFile(m) @@ -594,7 +599,7 @@ func (h *Helper) ReadManifest() string { // ReadLock returns the lock in the current directory. func (h *Helper) ReadLock() string { - l := filepath.Join(h.pwd(), "lock.toml") + l := filepath.Join(h.pwd(), lockName) h.MustExist(l) f, err := ioutil.ReadFile(l) From e31a18608e32472efd02a5565af9e1664e20e0c8 Mon Sep 17 00:00:00 2001 From: Carolyn Van Slyck Date: Thu, 6 Apr 2017 10:15:54 -0500 Subject: [PATCH 20/20] New filenames: Gopkg.toml and Gopkg.lock --- lock.toml => Gopkg.lock | 0 manifest.toml => Gopkg.toml | 0 cmd/dep/testdata/harness_tests/README.md | 6 +++--- .../ensure/empty/case1/final/{lock.toml => Gopkg.lock} | 0 .../ensure/empty/case1/final/{manifest.toml => Gopkg.toml} | 0 .../ensure/empty/case2/final/{lock.toml => Gopkg.lock} | 0 .../ensure/empty/case2/final/{manifest.toml => Gopkg.toml} | 0 .../empty/case2/initial/{manifest.toml => Gopkg.toml} | 0 .../ensure/override/case1/final/{lock.toml => Gopkg.lock} | 0 .../override/case1/final/{manifest.toml => Gopkg.toml} | 0 .../ensure/update/case1/final/{lock.toml => Gopkg.lock} | 0 .../ensure/update/case1/final/{manifest.toml => Gopkg.toml} | 0 .../ensure/update/case1/initial/{lock.toml => Gopkg.lock} | 0 .../update/case1/initial/{manifest.toml => Gopkg.toml} | 0 .../ensure/update/case2/final/{lock.toml => Gopkg.lock} | 0 .../ensure/update/case2/final/{manifest.toml => Gopkg.toml} | 0 .../ensure/update/case2/initial/{lock.toml => Gopkg.lock} | 0 .../update/case2/initial/{manifest.toml => Gopkg.toml} | 0 .../init/case1/final/{lock.toml => Gopkg.lock} | 0 .../init/case1/final/{manifest.toml => Gopkg.toml} | 0 .../init/case2/final/{lock.toml => Gopkg.lock} | 0 .../init/case2/final/{manifest.toml => Gopkg.toml} | 0 .../init/case3/final/{lock.toml => Gopkg.lock} | 0 .../init/case3/final/{manifest.toml => Gopkg.toml} | 0 .../init/skip-hidden/final/{lock.toml => Gopkg.lock} | 0 .../init/skip-hidden/final/{manifest.toml => Gopkg.toml} | 0 .../remove/force/case1/final/{lock.toml => Gopkg.lock} | 0 .../remove/force/case1/final/{manifest.toml => Gopkg.toml} | 0 .../force/case1/initial/{manifest.toml => Gopkg.toml} | 0 .../remove/specific/case1/final/{lock.toml => Gopkg.lock} | 0 .../specific/case1/final/{manifest.toml => Gopkg.toml} | 0 .../specific/case1/initial/{manifest.toml => Gopkg.toml} | 0 .../remove/specific/case2/final/{lock.toml => Gopkg.lock} | 0 .../specific/case2/final/{manifest.toml => Gopkg.toml} | 0 .../specific/case2/initial/{manifest.toml => Gopkg.toml} | 0 .../remove/unused/case1/final/{lock.toml => Gopkg.lock} | 0 .../remove/unused/case1/final/{manifest.toml => Gopkg.toml} | 0 .../unused/case1/initial/{manifest.toml => Gopkg.toml} | 0 context.go | 2 +- hack/validate-vendor.bash | 4 ++-- lock.go | 2 +- manifest.go | 2 +- test/test.go | 4 ++-- testdata/analyzer/{manifest.toml => Gopkg.toml} | 0 testdata/rootfind/{manifest.toml => Gopkg.toml} | 0 45 files changed, 10 insertions(+), 10 deletions(-) rename lock.toml => Gopkg.lock (100%) rename manifest.toml => Gopkg.toml (100%) rename cmd/dep/testdata/harness_tests/ensure/empty/case1/final/{lock.toml => Gopkg.lock} (100%) rename cmd/dep/testdata/harness_tests/ensure/empty/case1/final/{manifest.toml => Gopkg.toml} (100%) rename cmd/dep/testdata/harness_tests/ensure/empty/case2/final/{lock.toml => Gopkg.lock} (100%) rename cmd/dep/testdata/harness_tests/ensure/empty/case2/final/{manifest.toml => Gopkg.toml} (100%) rename cmd/dep/testdata/harness_tests/ensure/empty/case2/initial/{manifest.toml => Gopkg.toml} (100%) rename cmd/dep/testdata/harness_tests/ensure/override/case1/final/{lock.toml => Gopkg.lock} (100%) rename cmd/dep/testdata/harness_tests/ensure/override/case1/final/{manifest.toml => Gopkg.toml} (100%) rename cmd/dep/testdata/harness_tests/ensure/update/case1/final/{lock.toml => Gopkg.lock} (100%) rename cmd/dep/testdata/harness_tests/ensure/update/case1/final/{manifest.toml => Gopkg.toml} (100%) rename cmd/dep/testdata/harness_tests/ensure/update/case1/initial/{lock.toml => Gopkg.lock} (100%) rename cmd/dep/testdata/harness_tests/ensure/update/case1/initial/{manifest.toml => Gopkg.toml} (100%) rename cmd/dep/testdata/harness_tests/ensure/update/case2/final/{lock.toml => Gopkg.lock} (100%) rename cmd/dep/testdata/harness_tests/ensure/update/case2/final/{manifest.toml => Gopkg.toml} (100%) rename cmd/dep/testdata/harness_tests/ensure/update/case2/initial/{lock.toml => Gopkg.lock} (100%) rename cmd/dep/testdata/harness_tests/ensure/update/case2/initial/{manifest.toml => Gopkg.toml} (100%) rename cmd/dep/testdata/harness_tests/init/case1/final/{lock.toml => Gopkg.lock} (100%) rename cmd/dep/testdata/harness_tests/init/case1/final/{manifest.toml => Gopkg.toml} (100%) rename cmd/dep/testdata/harness_tests/init/case2/final/{lock.toml => Gopkg.lock} (100%) rename cmd/dep/testdata/harness_tests/init/case2/final/{manifest.toml => Gopkg.toml} (100%) rename cmd/dep/testdata/harness_tests/init/case3/final/{lock.toml => Gopkg.lock} (100%) rename cmd/dep/testdata/harness_tests/init/case3/final/{manifest.toml => Gopkg.toml} (100%) rename cmd/dep/testdata/harness_tests/init/skip-hidden/final/{lock.toml => Gopkg.lock} (100%) rename cmd/dep/testdata/harness_tests/init/skip-hidden/final/{manifest.toml => Gopkg.toml} (100%) rename cmd/dep/testdata/harness_tests/remove/force/case1/final/{lock.toml => Gopkg.lock} (100%) rename cmd/dep/testdata/harness_tests/remove/force/case1/final/{manifest.toml => Gopkg.toml} (100%) rename cmd/dep/testdata/harness_tests/remove/force/case1/initial/{manifest.toml => Gopkg.toml} (100%) rename cmd/dep/testdata/harness_tests/remove/specific/case1/final/{lock.toml => Gopkg.lock} (100%) rename cmd/dep/testdata/harness_tests/remove/specific/case1/final/{manifest.toml => Gopkg.toml} (100%) rename cmd/dep/testdata/harness_tests/remove/specific/case1/initial/{manifest.toml => Gopkg.toml} (100%) rename cmd/dep/testdata/harness_tests/remove/specific/case2/final/{lock.toml => Gopkg.lock} (100%) rename cmd/dep/testdata/harness_tests/remove/specific/case2/final/{manifest.toml => Gopkg.toml} (100%) rename cmd/dep/testdata/harness_tests/remove/specific/case2/initial/{manifest.toml => Gopkg.toml} (100%) rename cmd/dep/testdata/harness_tests/remove/unused/case1/final/{lock.toml => Gopkg.lock} (100%) rename cmd/dep/testdata/harness_tests/remove/unused/case1/final/{manifest.toml => Gopkg.toml} (100%) rename cmd/dep/testdata/harness_tests/remove/unused/case1/initial/{manifest.toml => Gopkg.toml} (100%) rename testdata/analyzer/{manifest.toml => Gopkg.toml} (100%) rename testdata/rootfind/{manifest.toml => Gopkg.toml} (100%) diff --git a/lock.toml b/Gopkg.lock similarity index 100% rename from lock.toml rename to Gopkg.lock diff --git a/manifest.toml b/Gopkg.toml similarity index 100% rename from manifest.toml rename to Gopkg.toml diff --git a/cmd/dep/testdata/harness_tests/README.md b/cmd/dep/testdata/harness_tests/README.md index 9cd5cf3c2a..b7713d3aa8 100644 --- a/cmd/dep/testdata/harness_tests/README.md +++ b/cmd/dep/testdata/harness_tests/README.md @@ -14,11 +14,11 @@ The directory structure is as follows: testcase.json initial/ file1.go - manifest.toml + Gopkg.toml ... final/ - manifest.toml - lock.toml + Gopkg.toml + Gopkg.lock case2/ ... diff --git a/cmd/dep/testdata/harness_tests/ensure/empty/case1/final/lock.toml b/cmd/dep/testdata/harness_tests/ensure/empty/case1/final/Gopkg.lock similarity index 100% rename from cmd/dep/testdata/harness_tests/ensure/empty/case1/final/lock.toml rename to cmd/dep/testdata/harness_tests/ensure/empty/case1/final/Gopkg.lock diff --git a/cmd/dep/testdata/harness_tests/ensure/empty/case1/final/manifest.toml b/cmd/dep/testdata/harness_tests/ensure/empty/case1/final/Gopkg.toml similarity index 100% rename from cmd/dep/testdata/harness_tests/ensure/empty/case1/final/manifest.toml rename to cmd/dep/testdata/harness_tests/ensure/empty/case1/final/Gopkg.toml diff --git a/cmd/dep/testdata/harness_tests/ensure/empty/case2/final/lock.toml b/cmd/dep/testdata/harness_tests/ensure/empty/case2/final/Gopkg.lock similarity index 100% rename from cmd/dep/testdata/harness_tests/ensure/empty/case2/final/lock.toml rename to cmd/dep/testdata/harness_tests/ensure/empty/case2/final/Gopkg.lock diff --git a/cmd/dep/testdata/harness_tests/ensure/empty/case2/final/manifest.toml b/cmd/dep/testdata/harness_tests/ensure/empty/case2/final/Gopkg.toml similarity index 100% rename from cmd/dep/testdata/harness_tests/ensure/empty/case2/final/manifest.toml rename to cmd/dep/testdata/harness_tests/ensure/empty/case2/final/Gopkg.toml diff --git a/cmd/dep/testdata/harness_tests/ensure/empty/case2/initial/manifest.toml b/cmd/dep/testdata/harness_tests/ensure/empty/case2/initial/Gopkg.toml similarity index 100% rename from cmd/dep/testdata/harness_tests/ensure/empty/case2/initial/manifest.toml rename to cmd/dep/testdata/harness_tests/ensure/empty/case2/initial/Gopkg.toml diff --git a/cmd/dep/testdata/harness_tests/ensure/override/case1/final/lock.toml b/cmd/dep/testdata/harness_tests/ensure/override/case1/final/Gopkg.lock similarity index 100% rename from cmd/dep/testdata/harness_tests/ensure/override/case1/final/lock.toml rename to cmd/dep/testdata/harness_tests/ensure/override/case1/final/Gopkg.lock diff --git a/cmd/dep/testdata/harness_tests/ensure/override/case1/final/manifest.toml b/cmd/dep/testdata/harness_tests/ensure/override/case1/final/Gopkg.toml similarity index 100% rename from cmd/dep/testdata/harness_tests/ensure/override/case1/final/manifest.toml rename to cmd/dep/testdata/harness_tests/ensure/override/case1/final/Gopkg.toml diff --git a/cmd/dep/testdata/harness_tests/ensure/update/case1/final/lock.toml b/cmd/dep/testdata/harness_tests/ensure/update/case1/final/Gopkg.lock similarity index 100% rename from cmd/dep/testdata/harness_tests/ensure/update/case1/final/lock.toml rename to cmd/dep/testdata/harness_tests/ensure/update/case1/final/Gopkg.lock diff --git a/cmd/dep/testdata/harness_tests/ensure/update/case1/final/manifest.toml b/cmd/dep/testdata/harness_tests/ensure/update/case1/final/Gopkg.toml similarity index 100% rename from cmd/dep/testdata/harness_tests/ensure/update/case1/final/manifest.toml rename to cmd/dep/testdata/harness_tests/ensure/update/case1/final/Gopkg.toml diff --git a/cmd/dep/testdata/harness_tests/ensure/update/case1/initial/lock.toml b/cmd/dep/testdata/harness_tests/ensure/update/case1/initial/Gopkg.lock similarity index 100% rename from cmd/dep/testdata/harness_tests/ensure/update/case1/initial/lock.toml rename to cmd/dep/testdata/harness_tests/ensure/update/case1/initial/Gopkg.lock diff --git a/cmd/dep/testdata/harness_tests/ensure/update/case1/initial/manifest.toml b/cmd/dep/testdata/harness_tests/ensure/update/case1/initial/Gopkg.toml similarity index 100% rename from cmd/dep/testdata/harness_tests/ensure/update/case1/initial/manifest.toml rename to cmd/dep/testdata/harness_tests/ensure/update/case1/initial/Gopkg.toml diff --git a/cmd/dep/testdata/harness_tests/ensure/update/case2/final/lock.toml b/cmd/dep/testdata/harness_tests/ensure/update/case2/final/Gopkg.lock similarity index 100% rename from cmd/dep/testdata/harness_tests/ensure/update/case2/final/lock.toml rename to cmd/dep/testdata/harness_tests/ensure/update/case2/final/Gopkg.lock diff --git a/cmd/dep/testdata/harness_tests/ensure/update/case2/final/manifest.toml b/cmd/dep/testdata/harness_tests/ensure/update/case2/final/Gopkg.toml similarity index 100% rename from cmd/dep/testdata/harness_tests/ensure/update/case2/final/manifest.toml rename to cmd/dep/testdata/harness_tests/ensure/update/case2/final/Gopkg.toml diff --git a/cmd/dep/testdata/harness_tests/ensure/update/case2/initial/lock.toml b/cmd/dep/testdata/harness_tests/ensure/update/case2/initial/Gopkg.lock similarity index 100% rename from cmd/dep/testdata/harness_tests/ensure/update/case2/initial/lock.toml rename to cmd/dep/testdata/harness_tests/ensure/update/case2/initial/Gopkg.lock diff --git a/cmd/dep/testdata/harness_tests/ensure/update/case2/initial/manifest.toml b/cmd/dep/testdata/harness_tests/ensure/update/case2/initial/Gopkg.toml similarity index 100% rename from cmd/dep/testdata/harness_tests/ensure/update/case2/initial/manifest.toml rename to cmd/dep/testdata/harness_tests/ensure/update/case2/initial/Gopkg.toml diff --git a/cmd/dep/testdata/harness_tests/init/case1/final/lock.toml b/cmd/dep/testdata/harness_tests/init/case1/final/Gopkg.lock similarity index 100% rename from cmd/dep/testdata/harness_tests/init/case1/final/lock.toml rename to cmd/dep/testdata/harness_tests/init/case1/final/Gopkg.lock diff --git a/cmd/dep/testdata/harness_tests/init/case1/final/manifest.toml b/cmd/dep/testdata/harness_tests/init/case1/final/Gopkg.toml similarity index 100% rename from cmd/dep/testdata/harness_tests/init/case1/final/manifest.toml rename to cmd/dep/testdata/harness_tests/init/case1/final/Gopkg.toml diff --git a/cmd/dep/testdata/harness_tests/init/case2/final/lock.toml b/cmd/dep/testdata/harness_tests/init/case2/final/Gopkg.lock similarity index 100% rename from cmd/dep/testdata/harness_tests/init/case2/final/lock.toml rename to cmd/dep/testdata/harness_tests/init/case2/final/Gopkg.lock diff --git a/cmd/dep/testdata/harness_tests/init/case2/final/manifest.toml b/cmd/dep/testdata/harness_tests/init/case2/final/Gopkg.toml similarity index 100% rename from cmd/dep/testdata/harness_tests/init/case2/final/manifest.toml rename to cmd/dep/testdata/harness_tests/init/case2/final/Gopkg.toml diff --git a/cmd/dep/testdata/harness_tests/init/case3/final/lock.toml b/cmd/dep/testdata/harness_tests/init/case3/final/Gopkg.lock similarity index 100% rename from cmd/dep/testdata/harness_tests/init/case3/final/lock.toml rename to cmd/dep/testdata/harness_tests/init/case3/final/Gopkg.lock diff --git a/cmd/dep/testdata/harness_tests/init/case3/final/manifest.toml b/cmd/dep/testdata/harness_tests/init/case3/final/Gopkg.toml similarity index 100% rename from cmd/dep/testdata/harness_tests/init/case3/final/manifest.toml rename to cmd/dep/testdata/harness_tests/init/case3/final/Gopkg.toml diff --git a/cmd/dep/testdata/harness_tests/init/skip-hidden/final/lock.toml b/cmd/dep/testdata/harness_tests/init/skip-hidden/final/Gopkg.lock similarity index 100% rename from cmd/dep/testdata/harness_tests/init/skip-hidden/final/lock.toml rename to cmd/dep/testdata/harness_tests/init/skip-hidden/final/Gopkg.lock diff --git a/cmd/dep/testdata/harness_tests/init/skip-hidden/final/manifest.toml b/cmd/dep/testdata/harness_tests/init/skip-hidden/final/Gopkg.toml similarity index 100% rename from cmd/dep/testdata/harness_tests/init/skip-hidden/final/manifest.toml rename to cmd/dep/testdata/harness_tests/init/skip-hidden/final/Gopkg.toml diff --git a/cmd/dep/testdata/harness_tests/remove/force/case1/final/lock.toml b/cmd/dep/testdata/harness_tests/remove/force/case1/final/Gopkg.lock similarity index 100% rename from cmd/dep/testdata/harness_tests/remove/force/case1/final/lock.toml rename to cmd/dep/testdata/harness_tests/remove/force/case1/final/Gopkg.lock diff --git a/cmd/dep/testdata/harness_tests/remove/force/case1/final/manifest.toml b/cmd/dep/testdata/harness_tests/remove/force/case1/final/Gopkg.toml similarity index 100% rename from cmd/dep/testdata/harness_tests/remove/force/case1/final/manifest.toml rename to cmd/dep/testdata/harness_tests/remove/force/case1/final/Gopkg.toml diff --git a/cmd/dep/testdata/harness_tests/remove/force/case1/initial/manifest.toml b/cmd/dep/testdata/harness_tests/remove/force/case1/initial/Gopkg.toml similarity index 100% rename from cmd/dep/testdata/harness_tests/remove/force/case1/initial/manifest.toml rename to cmd/dep/testdata/harness_tests/remove/force/case1/initial/Gopkg.toml diff --git a/cmd/dep/testdata/harness_tests/remove/specific/case1/final/lock.toml b/cmd/dep/testdata/harness_tests/remove/specific/case1/final/Gopkg.lock similarity index 100% rename from cmd/dep/testdata/harness_tests/remove/specific/case1/final/lock.toml rename to cmd/dep/testdata/harness_tests/remove/specific/case1/final/Gopkg.lock diff --git a/cmd/dep/testdata/harness_tests/remove/specific/case1/final/manifest.toml b/cmd/dep/testdata/harness_tests/remove/specific/case1/final/Gopkg.toml similarity index 100% rename from cmd/dep/testdata/harness_tests/remove/specific/case1/final/manifest.toml rename to cmd/dep/testdata/harness_tests/remove/specific/case1/final/Gopkg.toml diff --git a/cmd/dep/testdata/harness_tests/remove/specific/case1/initial/manifest.toml b/cmd/dep/testdata/harness_tests/remove/specific/case1/initial/Gopkg.toml similarity index 100% rename from cmd/dep/testdata/harness_tests/remove/specific/case1/initial/manifest.toml rename to cmd/dep/testdata/harness_tests/remove/specific/case1/initial/Gopkg.toml diff --git a/cmd/dep/testdata/harness_tests/remove/specific/case2/final/lock.toml b/cmd/dep/testdata/harness_tests/remove/specific/case2/final/Gopkg.lock similarity index 100% rename from cmd/dep/testdata/harness_tests/remove/specific/case2/final/lock.toml rename to cmd/dep/testdata/harness_tests/remove/specific/case2/final/Gopkg.lock diff --git a/cmd/dep/testdata/harness_tests/remove/specific/case2/final/manifest.toml b/cmd/dep/testdata/harness_tests/remove/specific/case2/final/Gopkg.toml similarity index 100% rename from cmd/dep/testdata/harness_tests/remove/specific/case2/final/manifest.toml rename to cmd/dep/testdata/harness_tests/remove/specific/case2/final/Gopkg.toml diff --git a/cmd/dep/testdata/harness_tests/remove/specific/case2/initial/manifest.toml b/cmd/dep/testdata/harness_tests/remove/specific/case2/initial/Gopkg.toml similarity index 100% rename from cmd/dep/testdata/harness_tests/remove/specific/case2/initial/manifest.toml rename to cmd/dep/testdata/harness_tests/remove/specific/case2/initial/Gopkg.toml diff --git a/cmd/dep/testdata/harness_tests/remove/unused/case1/final/lock.toml b/cmd/dep/testdata/harness_tests/remove/unused/case1/final/Gopkg.lock similarity index 100% rename from cmd/dep/testdata/harness_tests/remove/unused/case1/final/lock.toml rename to cmd/dep/testdata/harness_tests/remove/unused/case1/final/Gopkg.lock diff --git a/cmd/dep/testdata/harness_tests/remove/unused/case1/final/manifest.toml b/cmd/dep/testdata/harness_tests/remove/unused/case1/final/Gopkg.toml similarity index 100% rename from cmd/dep/testdata/harness_tests/remove/unused/case1/final/manifest.toml rename to cmd/dep/testdata/harness_tests/remove/unused/case1/final/Gopkg.toml diff --git a/cmd/dep/testdata/harness_tests/remove/unused/case1/initial/manifest.toml b/cmd/dep/testdata/harness_tests/remove/unused/case1/initial/Gopkg.toml similarity index 100% rename from cmd/dep/testdata/harness_tests/remove/unused/case1/initial/manifest.toml rename to cmd/dep/testdata/harness_tests/remove/unused/case1/initial/Gopkg.toml diff --git a/context.go b/context.go index 54e60811e9..6005381559 100644 --- a/context.go +++ b/context.go @@ -48,7 +48,7 @@ func (c *Ctx) SourceManager() (*gps.SourceMgr, error) { // a project root. If an absolute path is given, the search begins in that // directory. If a relative or empty path is given, the search start is computed // from the current working directory. The search stops when a file with the -// name ManifestName (manifest.toml, by default) is located. +// name ManifestName (Gopkg.toml, by default) is located. // // The Project contains the parsed manifest as well as a parsed lock file, if // present. The import path is calculated as the remaining path segment diff --git a/hack/validate-vendor.bash b/hack/validate-vendor.bash index 6f4d2c458e..5c605239b7 100755 --- a/hack/validate-vendor.bash +++ b/hack/validate-vendor.bash @@ -21,7 +21,7 @@ fi VALIDATE_HEAD="$(git rev-parse --verify HEAD)" IFS=$'\n' -files=( $(git diff "$TRAVIS_BRANCH...$VALIDATE_HEAD" --diff-filter=ACMR --name-only -- 'manifest.toml' 'lock.toml' 'vendor/' || true) ) +files=( $(git diff "$TRAVIS_BRANCH...$VALIDATE_HEAD" --diff-filter=ACMR --name-only -- 'Gopkg.toml' 'Gopkg.lock' 'vendor/' || true) ) unset IFS if [ ${#files[@]} -gt 0 ]; then @@ -29,7 +29,7 @@ if [ ${#files[@]} -gt 0 ]; then go build ./dep ensure # Let see if the working directory is clean - diffs="$(git status --porcelain -- vendor manifest.toml lock.toml 2>/dev/null)" + diffs="$(git status --porcelain -- vendor Gopkg.toml Gopkg.lock 2>/dev/null)" if [ "$diffs" ]; then { echo 'The result of ensure differs' diff --git a/lock.go b/lock.go index ed5dce03ee..aaa561daab 100644 --- a/lock.go +++ b/lock.go @@ -15,7 +15,7 @@ import ( "github.com/sdboyer/gps" ) -const LockName = "lock.toml" +const LockName = "Gopkg.lock" type Lock struct { Memo []byte diff --git a/manifest.go b/manifest.go index 072f110fef..b6187c583c 100644 --- a/manifest.go +++ b/manifest.go @@ -14,7 +14,7 @@ import ( "github.com/sdboyer/gps" ) -const ManifestName = "manifest.toml" +const ManifestName = "Gopkg.toml" type Manifest struct { Dependencies gps.ProjectConstraints diff --git a/test/test.go b/test/test.go index ba3a780145..31da596b8b 100644 --- a/test/test.go +++ b/test/test.go @@ -30,8 +30,8 @@ var ( ) const ( - manifestName string = "manifest.toml" - lockName string = "lock.toml" + manifestName string = "Gopkg.toml" + lockName string = "Gopkg.lock" ) func init() { diff --git a/testdata/analyzer/manifest.toml b/testdata/analyzer/Gopkg.toml similarity index 100% rename from testdata/analyzer/manifest.toml rename to testdata/analyzer/Gopkg.toml diff --git a/testdata/rootfind/manifest.toml b/testdata/rootfind/Gopkg.toml similarity index 100% rename from testdata/rootfind/manifest.toml rename to testdata/rootfind/Gopkg.toml