upgrade gopkg.in/editorconfig/editorconfig-core-go.v1 (#8501)

editorconfig-core-go made breaking api changes and has recently released
v2.1.1. This change consumes the new api and fixes up any breaking
references.
This commit is contained in:
Colin Arnott 2019-10-15 21:24:16 +00:00 committed by zeripath
parent 80655026d2
commit 66e99d722a
23 changed files with 394 additions and 121 deletions

View file

@ -0,0 +1,14 @@
; http://editorconfig.org/
root = true
[*]
insert_final_newline = true
charset = utf-8
trim_trailing_whitespace = true
indent_style = space
indent_size = 2
[{Makefile,go.mod,go.sum,*.go}]
indent_style = tab
indent_size = 8

View file

@ -0,0 +1 @@
* text=auto

View file

@ -0,0 +1,29 @@
# ---> Go
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
# EditorConfig
/editorconfig

View file

@ -0,0 +1,3 @@
[submodule "core-test"]
path = core-test
url = https://github.com/editorconfig/editorconfig-core-test.git

View file

@ -0,0 +1,30 @@
---
language: go
dist: xenial
sudo: true
go:
- '1.11.x'
- '1.12.x'
compiler:
- gcc
install:
# first we create a directory for the CMake binaries
- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
- mkdir ${DEPS_DIR} && cd ${DEPS_DIR}
# we use wget to fetch the cmake binaries
- travis_retry wget --no-check-certificate https://cmake.org/files/v3.14/cmake-3.14.6-Linux-x86_64.tar.gz
- echo "82e08e50ba921035efa82b859c74c5fbe27d3e49a4003020e3c77618a4e912cd cmake-3.14.6-Linux-x86_64.tar.gz" > sha256sum.txt
- sha256sum -c sha256sum.txt
- tar -xvf cmake-3.14.6-Linux-x86_64.tar.gz > /dev/null
- mv cmake-3.14.6-Linux-x86_64 cmake-install
- PATH=${DEPS_DIR}/cmake-install:${DEPS_DIR}/cmake-install/bin:$PATH
- cd ${TRAVIS_BUILD_DIR}
env:
- GO111MODULE=on
script:
- make test

View file

@ -0,0 +1,20 @@
# Change log
## v2.1.1 - 2019-08-18
- Fix a small path bug
([#17](https://github.com/editorconfig/editorconfig-core-go/issues/17),
[#18](https://github.com/editorconfig/editorconfig-core-go/pull/18)).
## v2.1.0 - 2019-08-10
- This package is now *way* more compliant with the Editorconfig definition
thanks to a refactor work made by [@greut](https://github.com/greut)
([#15](https://github.com/editorconfig/editorconfig-core-go/pull/15)).
## v2.0.0 - 2019-07-14
- This project now uses [Go Modules](https://blog.golang.org/using-go-modules)
([#14](https://github.com/editorconfig/editorconfig-core-go/pull/14)).
- The import path has been changed from `gopkg.in/editorconfig/editorconfig-core-go.v1`
to `github.com/editorconfig/editorconfig-core-go/v2`.

View file

@ -0,0 +1,5 @@
project(editorconfig-core-go)
cmake_minimum_required(VERSION 3.14)
enable_testing()
set(EDITORCONFIG_CMD ${CMAKE_CURRENT_LIST_DIR}/editorconfig)
add_subdirectory(core-test)

View file

@ -0,0 +1,8 @@
MIT License
Copyright (c) 2016 The Editorconfig Team
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.

View file

@ -0,0 +1,19 @@
PROJECT_ROOT_DIR := $(CURDIR)
SRC := $(shell git ls-files *.go */*.go)
.PHONY: bin test test-go test-core submodule
test: test-go test-core
submodule:
git submodule update --init
editorconfig: $(SRC)
go build ./cmd/editorconfig
test-go:
go test -v ./...
test-core: editorconfig
cd core-test; cmake ..
cd core-test; ctest -E "(comments_after_section|octothorpe|unset_|_pre_0.9.0|max_|root_file_mixed_case)" --output-on-failure .

View file

@ -0,0 +1,125 @@
<!-- Currently tests against core-test are not done so hide build status badge for now -->
<!-- [![Build Status](https://travis-ci.org/editorconfig/editorconfig-core-go.svg?branch=master)](https://travis-ci.org/editorconfig/editorconfig-core-go) -->
[![GoDoc](https://godoc.org/github.com/editorconfig/editorconfig-core-go?status.svg)](https://godoc.org/github.com/editorconfig/editorconfig-core-go)
[![Go Report Card](https://goreportcard.com/badge/github.com/editorconfig/editorconfig-core-go)](https://goreportcard.com/report/github.com/editorconfig/editorconfig-core-go)
# Editorconfig Core Go
A [Editorconfig][editorconfig] file parser and manipulator for Go.
> Currently this package does some basic work but does not fully support
> EditorConfig specs, so using it in "real world" is not recommended.
## Missing features
- `unset`
- escaping comments in values, probably in [go-ini/ini](https://github.com/go-ini/ini)
## Installing
We recommend the use of Go 1.11+ modules for this package.
Import by the same path. The package name you will use to access it is
`editorconfig`.
```go
import (
"github.com/editorconfig/editorconfig-core-go/v2"
)
```
## Usage
### Parse from file
```go
editorConfig, err := editorconfig.ParseFile("path/to/.editorconfig")
if err != nil {
log.Fatal(err)
}
```
### Parse from slice of bytes
```go
data := []byte("...")
editorConfig, err := editorconfig.ParseBytes(data)
if err != nil {
log.Fatal(err)
}
```
### Get definition to a given filename
This method builds a definition to a given filename.
This definition is a merge of the properties with selectors that matched the
given filename.
The lasts sections of the file have preference over the priors.
```go
def := editorConfig.GetDefinitionForFilename("my/file.go")
```
This definition have the following properties:
```go
type Definition struct {
Selector string
Charset string
IndentStyle string
IndentSize string
TabWidth int
EndOfLine string
TrimTrailingWhitespace bool
InsertFinalNewline bool
Raw map[string]string
}
```
#### Automatic search for `.editorconfig` files
If you want a definition of a file without having to manually
parse the `.editorconfig` files, you can then use the static version
of `GetDefinitionForFilename`:
```go
def, err := editorconfig.GetDefinitionForFilename("foo/bar/baz/my-file.go")
```
In the example above, the package will automatically search for
`.editorconfig` files on:
- `foo/bar/baz/.editorconfig`
- `foo/baz/.editorconfig`
- `foo/.editorconfig`
Until it reaches a file with `root = true` or the root of the filesystem.
### Generating a .editorconfig file
You can easily convert a Editorconfig struct to a compatible INI file:
```go
// serialize to slice of bytes
data, err := editorConfig.Serialize()
if err != nil {
log.Fatal(err)
}
// save directly to file
err := editorConfig.Save("path/to/.editorconfig")
if err != nil {
log.Fatal(err)
}
```
## Contributing
To run the tests:
```bash
go test -v ./...
```
[editorconfig]: http://editorconfig.org/

View file

@ -0,0 +1,315 @@
// Package editorconfig can be used to parse and generate editorconfig files.
// For more information about editorconfig, see http://editorconfig.org/
package editorconfig
import (
"bytes"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"gopkg.in/ini.v1"
)
const (
// ConfigNameDefault represents the name of the configuration file
ConfigNameDefault = ".editorconfig"
)
// IndentStyle possible values
const (
IndentStyleTab = "tab"
IndentStyleSpaces = "space"
)
// EndOfLine possible values
const (
EndOfLineLf = "lf"
EndOfLineCr = "cr"
EndOfLineCrLf = "crlf"
)
// Charset possible values
const (
CharsetLatin1 = "latin1"
CharsetUTF8 = "utf-8"
CharsetUTF16BE = "utf-16be"
CharsetUTF16LE = "utf-16le"
CharsetUTF8BOM = "utf-8 bom"
)
// Definition represents a definition inside the .editorconfig file.
// E.g. a section of the file.
// The definition is composed of the selector ("*", "*.go", "*.{js.css}", etc),
// plus the properties of the selected files.
type Definition struct {
Selector string `ini:"-" json:"-"`
Charset string `ini:"charset" json:"charset,omitempty"`
IndentStyle string `ini:"indent_style" json:"indent_style,omitempty"`
IndentSize string `ini:"indent_size" json:"indent_size,omitempty"`
TabWidth int `ini:"tab_width" json:"tab_width,omitempty"`
EndOfLine string `ini:"end_of_line" json:"end_of_line,omitempty"`
TrimTrailingWhitespace bool `ini:"trim_trailing_whitespace" json:"trim_trailing_whitespace,omitempty"`
InsertFinalNewline bool `ini:"insert_final_newline" json:"insert_final_newline,omitempty"`
Raw map[string]string `ini:"-" json:"-"`
}
// Editorconfig represents a .editorconfig file.
// It is composed by a "root" property, plus the definitions defined in the
// file.
type Editorconfig struct {
Root bool
Definitions []*Definition
}
// ParseBytes parses from a slice of bytes.
func ParseBytes(data []byte) (*Editorconfig, error) {
iniFile, err := ini.Load(data)
if err != nil {
return nil, err
}
editorConfig := &Editorconfig{}
editorConfig.Root = iniFile.Section(ini.DEFAULT_SECTION).Key("root").MustBool(false)
for _, sectionStr := range iniFile.SectionStrings() {
if sectionStr == ini.DEFAULT_SECTION {
continue
}
var (
iniSection = iniFile.Section(sectionStr)
definition = &Definition{}
raw = make(map[string]string)
)
err := iniSection.MapTo(&definition)
if err != nil {
return nil, err
}
// Shallow copy all properties
for k, v := range iniSection.KeysHash() {
raw[strings.ToLower(k)] = v
}
definition.Selector = sectionStr
definition.Raw = raw
definition.normalize()
editorConfig.Definitions = append(editorConfig.Definitions, definition)
}
return editorConfig, nil
}
// ParseFile parses from a file.
func ParseFile(f string) (*Editorconfig, error) {
data, err := ioutil.ReadFile(f)
if err != nil {
return nil, err
}
return ParseBytes(data)
}
var (
regexpBraces = regexp.MustCompile("{.*}")
)
// normalize fixes some values to their lowercaes value
func (d *Definition) normalize() {
d.Charset = strings.ToLower(d.Charset)
d.EndOfLine = strings.ToLower(d.EndOfLine)
d.IndentStyle = strings.ToLower(d.IndentStyle)
// tab_width defaults to indent_size:
// https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties#tab_width
num, err := strconv.Atoi(d.IndentSize)
if err == nil && d.TabWidth <= 0 {
d.TabWidth = num
}
}
func (d *Definition) merge(md *Definition) {
if len(d.Charset) == 0 {
d.Charset = md.Charset
}
if len(d.IndentStyle) == 0 {
d.IndentStyle = md.IndentStyle
}
if len(d.IndentSize) == 0 {
d.IndentSize = md.IndentSize
}
if d.TabWidth <= 0 {
d.TabWidth = md.TabWidth
}
if len(d.EndOfLine) == 0 {
d.EndOfLine = md.EndOfLine
}
if !d.TrimTrailingWhitespace {
d.TrimTrailingWhitespace = md.TrimTrailingWhitespace
}
if !d.InsertFinalNewline {
d.InsertFinalNewline = md.InsertFinalNewline
}
for k, v := range md.Raw {
if _, ok := d.Raw[k]; !ok {
d.Raw[k] = v
}
}
}
// InsertToIniFile ... TODO
func (d *Definition) InsertToIniFile(iniFile *ini.File) {
iniSec := iniFile.Section(d.Selector)
for k, v := range d.Raw {
if k == "insert_final_newline" {
iniSec.Key(k).SetValue(strconv.FormatBool(d.InsertFinalNewline))
} else if k == "trim_trailing_whitespace" {
iniSec.Key(k).SetValue(strconv.FormatBool(d.TrimTrailingWhitespace))
} else if k == "charset" {
iniSec.Key(k).SetValue(d.Charset)
} else if k == "end_of_line" {
iniSec.Key(k).SetValue(d.EndOfLine)
} else if k == "indent_style" {
iniSec.Key(k).SetValue(d.IndentStyle)
} else if k == "tab_width" {
iniSec.Key(k).SetValue(strconv.Itoa(d.TabWidth))
} else if k == "indent_size" {
iniSec.Key(k).SetValue(d.IndentSize)
} else {
iniSec.Key(k).SetValue(v)
}
}
if _, ok := d.Raw["indent_size"]; !ok {
if d.TabWidth > 0 {
iniSec.Key("indent_size").SetValue(strconv.Itoa(d.TabWidth))
} else if d.IndentStyle == IndentStyleTab {
iniSec.Key("indent_size").SetValue(IndentStyleTab)
}
}
if _, ok := d.Raw["tab_width"]; !ok && len(d.IndentSize) > 0 {
if _, err := strconv.Atoi(d.IndentSize); err == nil {
iniSec.Key("tab_width").SetValue(d.IndentSize)
}
}
}
// GetDefinitionForFilename returns a definition for the given filename.
// The result is a merge of the selectors that matched the file.
// The last section has preference over the priors.
func (e *Editorconfig) GetDefinitionForFilename(name string) (*Definition, error) {
def := &Definition{}
def.Raw = make(map[string]string)
for i := len(e.Definitions) - 1; i >= 0; i-- {
actualDef := e.Definitions[i]
selector := actualDef.Selector
if !strings.HasPrefix(selector, "/") {
if strings.ContainsRune(selector, '/') {
selector = "/" + selector
} else {
selector = "/**/" + selector
}
}
if !strings.HasPrefix(name, "/") {
name = "/" + name
}
ok, err := FnmatchCase(selector, name)
if err != nil {
return nil, err
}
if ok {
def.merge(actualDef)
}
}
return def, nil
}
func boolToString(b bool) string {
if b {
return "true"
}
return "false"
}
// Serialize converts the Editorconfig to a slice of bytes, containing the
// content of the file in the INI format.
func (e *Editorconfig) Serialize() ([]byte, error) {
var (
iniFile = ini.Empty()
buffer = bytes.NewBuffer(nil)
)
iniFile.Section(ini.DEFAULT_SECTION).Comment = "http://editorconfig.org"
if e.Root {
iniFile.Section(ini.DEFAULT_SECTION).Key("root").SetValue(boolToString(e.Root))
}
for _, d := range e.Definitions {
d.InsertToIniFile(iniFile)
}
_, err := iniFile.WriteTo(buffer)
if err != nil {
return nil, err
}
return buffer.Bytes(), nil
}
// Save saves the Editorconfig to a compatible INI file.
func (e *Editorconfig) Save(filename string) error {
data, err := e.Serialize()
if err != nil {
return err
}
return ioutil.WriteFile(filename, data, 0666)
}
// GetDefinitionForFilename given a filename, searches
// for .editorconfig files, starting from the file folder,
// walking through the previous folders, until it reaches a
// folder with `root = true`, and returns the right editorconfig
// definition for the given file.
func GetDefinitionForFilename(filename string) (*Definition, error) {
return GetDefinitionForFilenameWithConfigname(filename, ConfigNameDefault)
}
func GetDefinitionForFilenameWithConfigname(filename string, configname string) (*Definition, error) {
abs, err := filepath.Abs(filename)
if err != nil {
return nil, err
}
definition := &Definition{}
definition.Raw = make(map[string]string)
dir := abs
for dir != filepath.Dir(dir) {
dir = filepath.Dir(dir)
ecFile := filepath.Join(dir, configname)
if _, err := os.Stat(ecFile); os.IsNotExist(err) {
continue
}
ec, err := ParseFile(ecFile)
if err != nil {
return nil, err
}
relativeFilename := filename
if len(dir) < len(abs) {
relativeFilename = abs[len(dir):]
}
def, err := ec.GetDefinitionForFilename(relativeFilename)
if err != nil {
return nil, err
}
definition.merge(def)
if ec.Root {
break
}
}
return definition, nil
}

View file

@ -0,0 +1,177 @@
package editorconfig
import (
"fmt"
"regexp"
"strconv"
"strings"
)
var (
// findLeftBrackets matches the opening left bracket {
findLeftBrackets = regexp.MustCompile(`(^|[^\\])\{`)
// findLeftBrackets matches the closing right bracket {
findRightBrackets = regexp.MustCompile(`(^|[^\\])\}`)
// findNumericRange matches a range of number, e.g. -2..5
findNumericRange = regexp.MustCompile(`^([+-]?\d+)\.\.([+-]?\d+)$`)
)
// FnmatchCase tests whether the name matches the given pattern case included.
func FnmatchCase(pattern, name string) (bool, error) {
p, err := translate(pattern)
if err != nil {
return false, err
}
r, err := regexp.Compile(fmt.Sprintf("^%s$", p))
if err != nil {
return false, err
}
return r.MatchString(name), nil
}
func translate(pattern string) (string, error) {
index := 0
pat := []rune(pattern)
length := len(pat)
result := strings.Builder{}
braceLevel := 0
isEscaped := false
inBrackets := false
matchesBraces := len(findLeftBrackets.FindAllString(pattern, -1)) == len(findRightBrackets.FindAllString(pattern, -1))
for index < length {
r := pat[index]
index++
if r == '*' {
p := index
if p < length && pat[p] == '*' {
result.WriteString(".*")
index++
} else {
result.WriteString("[^/]*")
}
} else if r == '/' {
p := index
if p+2 < length && pat[p] == '*' && pat[p+1] == '*' && pat[p+2] == '/' {
result.WriteString("(?:/|/.*/)")
index += 3
} else {
result.WriteRune(r)
}
} else if r == '?' {
result.WriteString("[^/]")
} else if r == '[' {
if inBrackets {
result.WriteString("\\[")
} else {
hasSlash := false
res := strings.Builder{}
p := index
for p < length {
if pat[p] == ']' && pat[p-1] != '\\' {
break
}
res.WriteRune(pat[p])
if pat[p] == '/' && pat[p-1] != '\\' {
hasSlash = true
break
}
p++
}
if hasSlash {
result.WriteString("\\[" + res.String())
index = p + 1
} else {
inBrackets = true
if index < length && pat[index] == '!' || pat[index] == '^' {
index++
result.WriteString("[^")
} else {
result.WriteRune('[')
}
}
}
} else if r == ']' {
if inBrackets && pat[index-2] == '\\' {
result.WriteString("\\]")
} else {
result.WriteRune(r)
inBrackets = false
}
} else if r == '{' {
hasComma := false
p := index
res := strings.Builder{}
for p < length {
if pat[p] == '}' && pat[p-1] != '\\' {
break
}
res.WriteRune(pat[p])
if pat[p] == ',' && pat[p-1] != '\\' {
hasComma = true
break
}
p++
}
if !hasComma && p < length {
inner := res.String()
sub := findNumericRange.FindStringSubmatch(inner)
if len(sub) == 3 {
from, _ := strconv.Atoi(sub[1])
to, _ := strconv.Atoi(sub[2])
result.WriteString("(?:")
// XXX does not scale well
for i := from; i < to; i++ {
result.WriteString(strconv.Itoa(i))
result.WriteRune('|')
}
result.WriteString(strconv.Itoa(to))
result.WriteRune(')')
} else {
r, _ := translate(inner)
result.WriteString(fmt.Sprintf("\\{%s\\}", r))
}
index = p + 1
} else if matchesBraces {
result.WriteString("(?:")
braceLevel++
} else {
result.WriteString("\\{")
}
} else if r == '}' {
if braceLevel > 0 {
if isEscaped {
result.WriteRune('}')
isEscaped = false
} else {
result.WriteRune(')')
braceLevel--
}
} else {
result.WriteString("\\}")
}
} else if r == ',' {
if braceLevel == 0 || isEscaped {
result.WriteRune(r)
} else {
result.WriteRune('|')
}
} else if r != '\\' || isEscaped {
result.WriteString(regexp.QuoteMeta(string(r)))
isEscaped = false
} else {
isEscaped = true
}
}
return result.String(), nil
}

View file

@ -0,0 +1,9 @@
module github.com/editorconfig/editorconfig-core-go/v2
go 1.12
require (
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a // indirect
github.com/stretchr/testify v1.3.0
gopkg.in/ini.v1 v1.42.0
)

View file

@ -0,0 +1,22 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk=
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=