Merge pull request #8564 from hashicorp/b-getter-update
vendor: update go-getter
This commit is contained in:
commit
bc0c26585f
|
@ -0,0 +1,20 @@
|
||||||
|
Original version Copyright © 2010 Fazlul Shahriar <fshahriar@gmail.com>. Newer
|
||||||
|
portions Copyright © 2014 Blake Gentry <blakesgentry@gmail.com>.
|
||||||
|
|
||||||
|
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.
|
|
@ -0,0 +1,510 @@
|
||||||
|
package netrc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"unicode"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tkType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
tkMachine tkType = iota
|
||||||
|
tkDefault
|
||||||
|
tkLogin
|
||||||
|
tkPassword
|
||||||
|
tkAccount
|
||||||
|
tkMacdef
|
||||||
|
tkComment
|
||||||
|
tkWhitespace
|
||||||
|
)
|
||||||
|
|
||||||
|
var keywords = map[string]tkType{
|
||||||
|
"machine": tkMachine,
|
||||||
|
"default": tkDefault,
|
||||||
|
"login": tkLogin,
|
||||||
|
"password": tkPassword,
|
||||||
|
"account": tkAccount,
|
||||||
|
"macdef": tkMacdef,
|
||||||
|
"#": tkComment,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Netrc struct {
|
||||||
|
tokens []*token
|
||||||
|
machines []*Machine
|
||||||
|
macros Macros
|
||||||
|
updateLock sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindMachine returns the Machine in n named by name. If a machine named by
|
||||||
|
// name exists, it is returned. If no Machine with name name is found and there
|
||||||
|
// is a ``default'' machine, the ``default'' machine is returned. Otherwise, nil
|
||||||
|
// is returned.
|
||||||
|
func (n *Netrc) FindMachine(name string) (m *Machine) {
|
||||||
|
// TODO(bgentry): not safe for concurrency
|
||||||
|
var def *Machine
|
||||||
|
for _, m = range n.machines {
|
||||||
|
if m.Name == name {
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
if m.IsDefault() {
|
||||||
|
def = m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if def == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText implements the encoding.TextMarshaler interface to encode a
|
||||||
|
// Netrc into text format.
|
||||||
|
func (n *Netrc) MarshalText() (text []byte, err error) {
|
||||||
|
// TODO(bgentry): not safe for concurrency
|
||||||
|
for i := range n.tokens {
|
||||||
|
switch n.tokens[i].kind {
|
||||||
|
case tkComment, tkDefault, tkWhitespace: // always append these types
|
||||||
|
text = append(text, n.tokens[i].rawkind...)
|
||||||
|
default:
|
||||||
|
if n.tokens[i].value != "" { // skip empty-value tokens
|
||||||
|
text = append(text, n.tokens[i].rawkind...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if n.tokens[i].kind == tkMacdef {
|
||||||
|
text = append(text, ' ')
|
||||||
|
text = append(text, n.tokens[i].macroName...)
|
||||||
|
}
|
||||||
|
text = append(text, n.tokens[i].rawvalue...)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Netrc) NewMachine(name, login, password, account string) *Machine {
|
||||||
|
n.updateLock.Lock()
|
||||||
|
defer n.updateLock.Unlock()
|
||||||
|
|
||||||
|
prefix := "\n"
|
||||||
|
if len(n.tokens) == 0 {
|
||||||
|
prefix = ""
|
||||||
|
}
|
||||||
|
m := &Machine{
|
||||||
|
Name: name,
|
||||||
|
Login: login,
|
||||||
|
Password: password,
|
||||||
|
Account: account,
|
||||||
|
|
||||||
|
nametoken: &token{
|
||||||
|
kind: tkMachine,
|
||||||
|
rawkind: []byte(prefix + "machine"),
|
||||||
|
value: name,
|
||||||
|
rawvalue: []byte(" " + name),
|
||||||
|
},
|
||||||
|
logintoken: &token{
|
||||||
|
kind: tkLogin,
|
||||||
|
rawkind: []byte("\n\tlogin"),
|
||||||
|
value: login,
|
||||||
|
rawvalue: []byte(" " + login),
|
||||||
|
},
|
||||||
|
passtoken: &token{
|
||||||
|
kind: tkPassword,
|
||||||
|
rawkind: []byte("\n\tpassword"),
|
||||||
|
value: password,
|
||||||
|
rawvalue: []byte(" " + password),
|
||||||
|
},
|
||||||
|
accounttoken: &token{
|
||||||
|
kind: tkAccount,
|
||||||
|
rawkind: []byte("\n\taccount"),
|
||||||
|
value: account,
|
||||||
|
rawvalue: []byte(" " + account),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
n.insertMachineTokensBeforeDefault(m)
|
||||||
|
for i := range n.machines {
|
||||||
|
if n.machines[i].IsDefault() {
|
||||||
|
n.machines = append(append(n.machines[:i], m), n.machines[i:]...)
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n.machines = append(n.machines, m)
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Netrc) insertMachineTokensBeforeDefault(m *Machine) {
|
||||||
|
newtokens := []*token{m.nametoken}
|
||||||
|
if m.logintoken.value != "" {
|
||||||
|
newtokens = append(newtokens, m.logintoken)
|
||||||
|
}
|
||||||
|
if m.passtoken.value != "" {
|
||||||
|
newtokens = append(newtokens, m.passtoken)
|
||||||
|
}
|
||||||
|
if m.accounttoken.value != "" {
|
||||||
|
newtokens = append(newtokens, m.accounttoken)
|
||||||
|
}
|
||||||
|
for i := range n.tokens {
|
||||||
|
if n.tokens[i].kind == tkDefault {
|
||||||
|
// found the default, now insert tokens before it
|
||||||
|
n.tokens = append(n.tokens[:i], append(newtokens, n.tokens[i:]...)...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// didn't find a default, just add the newtokens to the end
|
||||||
|
n.tokens = append(n.tokens, newtokens...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Netrc) RemoveMachine(name string) {
|
||||||
|
n.updateLock.Lock()
|
||||||
|
defer n.updateLock.Unlock()
|
||||||
|
|
||||||
|
for i := range n.machines {
|
||||||
|
if n.machines[i] != nil && n.machines[i].Name == name {
|
||||||
|
m := n.machines[i]
|
||||||
|
for _, t := range []*token{
|
||||||
|
m.nametoken, m.logintoken, m.passtoken, m.accounttoken,
|
||||||
|
} {
|
||||||
|
n.removeToken(t)
|
||||||
|
}
|
||||||
|
n.machines = append(n.machines[:i], n.machines[i+1:]...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Netrc) removeToken(t *token) {
|
||||||
|
if t != nil {
|
||||||
|
for i := range n.tokens {
|
||||||
|
if n.tokens[i] == t {
|
||||||
|
n.tokens = append(n.tokens[:i], n.tokens[i+1:]...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Machine contains information about a remote machine.
|
||||||
|
type Machine struct {
|
||||||
|
Name string
|
||||||
|
Login string
|
||||||
|
Password string
|
||||||
|
Account string
|
||||||
|
|
||||||
|
nametoken *token
|
||||||
|
logintoken *token
|
||||||
|
passtoken *token
|
||||||
|
accounttoken *token
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsDefault returns true if the machine is a "default" token, denoted by an
|
||||||
|
// empty name.
|
||||||
|
func (m *Machine) IsDefault() bool {
|
||||||
|
return m.Name == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdatePassword sets the password for the Machine m.
|
||||||
|
func (m *Machine) UpdatePassword(newpass string) {
|
||||||
|
m.Password = newpass
|
||||||
|
updateTokenValue(m.passtoken, newpass)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateLogin sets the login for the Machine m.
|
||||||
|
func (m *Machine) UpdateLogin(newlogin string) {
|
||||||
|
m.Login = newlogin
|
||||||
|
updateTokenValue(m.logintoken, newlogin)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateAccount sets the login for the Machine m.
|
||||||
|
func (m *Machine) UpdateAccount(newaccount string) {
|
||||||
|
m.Account = newaccount
|
||||||
|
updateTokenValue(m.accounttoken, newaccount)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateTokenValue(t *token, value string) {
|
||||||
|
oldvalue := t.value
|
||||||
|
t.value = value
|
||||||
|
newraw := make([]byte, len(t.rawvalue))
|
||||||
|
copy(newraw, t.rawvalue)
|
||||||
|
t.rawvalue = append(
|
||||||
|
bytes.TrimSuffix(newraw, []byte(oldvalue)),
|
||||||
|
[]byte(value)...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Macros contains all the macro definitions in a netrc file.
|
||||||
|
type Macros map[string]string
|
||||||
|
|
||||||
|
type token struct {
|
||||||
|
kind tkType
|
||||||
|
macroName string
|
||||||
|
value string
|
||||||
|
rawkind []byte
|
||||||
|
rawvalue []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error represents a netrc file parse error.
|
||||||
|
type Error struct {
|
||||||
|
LineNum int // Line number
|
||||||
|
Msg string // Error message
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error returns a string representation of error e.
|
||||||
|
func (e *Error) Error() string {
|
||||||
|
return fmt.Sprintf("line %d: %s", e.LineNum, e.Msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) BadDefaultOrder() bool {
|
||||||
|
return e.Msg == errBadDefaultOrder
|
||||||
|
}
|
||||||
|
|
||||||
|
const errBadDefaultOrder = "default token must appear after all machine tokens"
|
||||||
|
|
||||||
|
// scanLinesKeepPrefix is a split function for a Scanner that returns each line
|
||||||
|
// of text. The returned token may include newlines if they are before the
|
||||||
|
// first non-space character. The returned line may be empty. The end-of-line
|
||||||
|
// marker is one optional carriage return followed by one mandatory newline. In
|
||||||
|
// regular expression notation, it is `\r?\n`. The last non-empty line of
|
||||||
|
// input will be returned even if it has no newline.
|
||||||
|
func scanLinesKeepPrefix(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||||||
|
if atEOF && len(data) == 0 {
|
||||||
|
return 0, nil, nil
|
||||||
|
}
|
||||||
|
// Skip leading spaces.
|
||||||
|
start := 0
|
||||||
|
for width := 0; start < len(data); start += width {
|
||||||
|
var r rune
|
||||||
|
r, width = utf8.DecodeRune(data[start:])
|
||||||
|
if !unicode.IsSpace(r) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if i := bytes.IndexByte(data[start:], '\n'); i >= 0 {
|
||||||
|
// We have a full newline-terminated line.
|
||||||
|
return start + i, data[0 : start+i], nil
|
||||||
|
}
|
||||||
|
// If we're at EOF, we have a final, non-terminated line. Return it.
|
||||||
|
if atEOF {
|
||||||
|
return len(data), data, nil
|
||||||
|
}
|
||||||
|
// Request more data.
|
||||||
|
return 0, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanWordsKeepPrefix is a split function for a Scanner that returns each
|
||||||
|
// space-separated word of text, with prefixing spaces included. It will never
|
||||||
|
// return an empty string. The definition of space is set by unicode.IsSpace.
|
||||||
|
//
|
||||||
|
// Adapted from bufio.ScanWords().
|
||||||
|
func scanTokensKeepPrefix(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||||||
|
// Skip leading spaces.
|
||||||
|
start := 0
|
||||||
|
for width := 0; start < len(data); start += width {
|
||||||
|
var r rune
|
||||||
|
r, width = utf8.DecodeRune(data[start:])
|
||||||
|
if !unicode.IsSpace(r) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if atEOF && len(data) == 0 || start == len(data) {
|
||||||
|
return len(data), data, nil
|
||||||
|
}
|
||||||
|
if len(data) > start && data[start] == '#' {
|
||||||
|
return scanLinesKeepPrefix(data, atEOF)
|
||||||
|
}
|
||||||
|
// Scan until space, marking end of word.
|
||||||
|
for width, i := 0, start; i < len(data); i += width {
|
||||||
|
var r rune
|
||||||
|
r, width = utf8.DecodeRune(data[i:])
|
||||||
|
if unicode.IsSpace(r) {
|
||||||
|
return i, data[:i], nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we're at EOF, we have a final, non-empty, non-terminated word. Return it.
|
||||||
|
if atEOF && len(data) > start {
|
||||||
|
return len(data), data, nil
|
||||||
|
}
|
||||||
|
// Request more data.
|
||||||
|
return 0, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newToken(rawb []byte) (*token, error) {
|
||||||
|
_, tkind, err := bufio.ScanWords(rawb, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var ok bool
|
||||||
|
t := token{rawkind: rawb}
|
||||||
|
t.kind, ok = keywords[string(tkind)]
|
||||||
|
if !ok {
|
||||||
|
trimmed := strings.TrimSpace(string(tkind))
|
||||||
|
if trimmed == "" {
|
||||||
|
t.kind = tkWhitespace // whitespace-only, should happen only at EOF
|
||||||
|
return &t, nil
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(trimmed, "#") {
|
||||||
|
t.kind = tkComment // this is a comment
|
||||||
|
return &t, nil
|
||||||
|
}
|
||||||
|
return &t, fmt.Errorf("keyword expected; got " + string(tkind))
|
||||||
|
}
|
||||||
|
return &t, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func scanValue(scanner *bufio.Scanner, pos int) ([]byte, string, int, error) {
|
||||||
|
if scanner.Scan() {
|
||||||
|
raw := scanner.Bytes()
|
||||||
|
pos += bytes.Count(raw, []byte{'\n'})
|
||||||
|
return raw, strings.TrimSpace(string(raw)), pos, nil
|
||||||
|
}
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
return nil, "", pos, &Error{pos, err.Error()}
|
||||||
|
}
|
||||||
|
return nil, "", pos, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parse(r io.Reader, pos int) (*Netrc, error) {
|
||||||
|
b, err := ioutil.ReadAll(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nrc := Netrc{machines: make([]*Machine, 0, 20), macros: make(Macros, 10)}
|
||||||
|
|
||||||
|
defaultSeen := false
|
||||||
|
var currentMacro *token
|
||||||
|
var m *Machine
|
||||||
|
var t *token
|
||||||
|
scanner := bufio.NewScanner(bytes.NewReader(b))
|
||||||
|
scanner.Split(scanTokensKeepPrefix)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
rawb := scanner.Bytes()
|
||||||
|
if len(rawb) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
pos += bytes.Count(rawb, []byte{'\n'})
|
||||||
|
t, err = newToken(rawb)
|
||||||
|
if err != nil {
|
||||||
|
if currentMacro == nil {
|
||||||
|
return nil, &Error{pos, err.Error()}
|
||||||
|
}
|
||||||
|
currentMacro.rawvalue = append(currentMacro.rawvalue, rawb...)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if currentMacro != nil && bytes.Contains(rawb, []byte{'\n', '\n'}) {
|
||||||
|
// if macro rawvalue + rawb would contain \n\n, then macro def is over
|
||||||
|
currentMacro.value = strings.TrimLeft(string(currentMacro.rawvalue), "\r\n")
|
||||||
|
nrc.macros[currentMacro.macroName] = currentMacro.value
|
||||||
|
currentMacro = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch t.kind {
|
||||||
|
case tkMacdef:
|
||||||
|
if _, t.macroName, pos, err = scanValue(scanner, pos); err != nil {
|
||||||
|
return nil, &Error{pos, err.Error()}
|
||||||
|
}
|
||||||
|
currentMacro = t
|
||||||
|
case tkDefault:
|
||||||
|
if defaultSeen {
|
||||||
|
return nil, &Error{pos, "multiple default token"}
|
||||||
|
}
|
||||||
|
if m != nil {
|
||||||
|
nrc.machines, m = append(nrc.machines, m), nil
|
||||||
|
}
|
||||||
|
m = new(Machine)
|
||||||
|
m.Name = ""
|
||||||
|
defaultSeen = true
|
||||||
|
case tkMachine:
|
||||||
|
if defaultSeen {
|
||||||
|
return nil, &Error{pos, errBadDefaultOrder}
|
||||||
|
}
|
||||||
|
if m != nil {
|
||||||
|
nrc.machines, m = append(nrc.machines, m), nil
|
||||||
|
}
|
||||||
|
m = new(Machine)
|
||||||
|
if t.rawvalue, m.Name, pos, err = scanValue(scanner, pos); err != nil {
|
||||||
|
return nil, &Error{pos, err.Error()}
|
||||||
|
}
|
||||||
|
t.value = m.Name
|
||||||
|
m.nametoken = t
|
||||||
|
case tkLogin:
|
||||||
|
if m == nil || m.Login != "" {
|
||||||
|
return nil, &Error{pos, "unexpected token login "}
|
||||||
|
}
|
||||||
|
if t.rawvalue, m.Login, pos, err = scanValue(scanner, pos); err != nil {
|
||||||
|
return nil, &Error{pos, err.Error()}
|
||||||
|
}
|
||||||
|
t.value = m.Login
|
||||||
|
m.logintoken = t
|
||||||
|
case tkPassword:
|
||||||
|
if m == nil || m.Password != "" {
|
||||||
|
return nil, &Error{pos, "unexpected token password"}
|
||||||
|
}
|
||||||
|
if t.rawvalue, m.Password, pos, err = scanValue(scanner, pos); err != nil {
|
||||||
|
return nil, &Error{pos, err.Error()}
|
||||||
|
}
|
||||||
|
t.value = m.Password
|
||||||
|
m.passtoken = t
|
||||||
|
case tkAccount:
|
||||||
|
if m == nil || m.Account != "" {
|
||||||
|
return nil, &Error{pos, "unexpected token account"}
|
||||||
|
}
|
||||||
|
if t.rawvalue, m.Account, pos, err = scanValue(scanner, pos); err != nil {
|
||||||
|
return nil, &Error{pos, err.Error()}
|
||||||
|
}
|
||||||
|
t.value = m.Account
|
||||||
|
m.accounttoken = t
|
||||||
|
}
|
||||||
|
|
||||||
|
nrc.tokens = append(nrc.tokens, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if m != nil {
|
||||||
|
nrc.machines, m = append(nrc.machines, m), nil
|
||||||
|
}
|
||||||
|
return &nrc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseFile opens the file at filename and then passes its io.Reader to
|
||||||
|
// Parse().
|
||||||
|
func ParseFile(filename string) (*Netrc, error) {
|
||||||
|
fd, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer fd.Close()
|
||||||
|
return Parse(fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse parses from the the Reader r as a netrc file and returns the set of
|
||||||
|
// machine information and macros defined in it. The ``default'' machine,
|
||||||
|
// which is intended to be used when no machine name matches, is identified
|
||||||
|
// by an empty machine name. There can be only one ``default'' machine.
|
||||||
|
//
|
||||||
|
// If there is a parsing error, an Error is returned.
|
||||||
|
func Parse(r io.Reader) (*Netrc, error) {
|
||||||
|
return parse(r, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindMachine parses the netrc file identified by filename and returns the
|
||||||
|
// Machine named by name. If a problem occurs parsing the file at filename, an
|
||||||
|
// error is returned. If a machine named by name exists, it is returned. If no
|
||||||
|
// Machine with name name is found and there is a ``default'' machine, the
|
||||||
|
// ``default'' machine is returned. Otherwise, nil is returned.
|
||||||
|
func FindMachine(filename, name string) (m *Machine, err error) {
|
||||||
|
n, err := ParseFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return n.FindMachine(name), nil
|
||||||
|
}
|
|
@ -46,7 +46,7 @@ var Getters map[string]Getter
|
||||||
var forcedRegexp = regexp.MustCompile(`^([A-Za-z0-9]+)::(.+)$`)
|
var forcedRegexp = regexp.MustCompile(`^([A-Za-z0-9]+)::(.+)$`)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
httpGetter := new(HttpGetter)
|
httpGetter := &HttpGetter{Netrc: true}
|
||||||
|
|
||||||
Getters = map[string]Getter{
|
Getters = map[string]Getter{
|
||||||
"file": new(FileGetter),
|
"file": new(FileGetter),
|
||||||
|
|
|
@ -32,13 +32,24 @@ import (
|
||||||
// The source URL, whether from the header or meta tag, must be a fully
|
// The source URL, whether from the header or meta tag, must be a fully
|
||||||
// formed URL. The shorthand syntax of "github.com/foo/bar" or relative
|
// formed URL. The shorthand syntax of "github.com/foo/bar" or relative
|
||||||
// paths are not allowed.
|
// paths are not allowed.
|
||||||
type HttpGetter struct{}
|
type HttpGetter struct {
|
||||||
|
// Netrc, if true, will lookup and use auth information found
|
||||||
|
// in the user's netrc file if available.
|
||||||
|
Netrc bool
|
||||||
|
}
|
||||||
|
|
||||||
func (g *HttpGetter) Get(dst string, u *url.URL) error {
|
func (g *HttpGetter) Get(dst string, u *url.URL) error {
|
||||||
// Copy the URL so we can modify it
|
// Copy the URL so we can modify it
|
||||||
var newU url.URL = *u
|
var newU url.URL = *u
|
||||||
u = &newU
|
u = &newU
|
||||||
|
|
||||||
|
if g.Netrc {
|
||||||
|
// Add auth from netrc if we can
|
||||||
|
if err := addAuthFromNetrc(u); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add terraform-get to the parameter.
|
// Add terraform-get to the parameter.
|
||||||
q := u.Query()
|
q := u.Query()
|
||||||
q.Add("terraform-get", "1")
|
q.Add("terraform-get", "1")
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
package getter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/bgentry/go-netrc/netrc"
|
||||||
|
"github.com/mitchellh/go-homedir"
|
||||||
|
)
|
||||||
|
|
||||||
|
// addAuthFromNetrc adds auth information to the URL from the user's
|
||||||
|
// netrc file if it can be found. This will only add the auth info
|
||||||
|
// if the URL doesn't already have auth info specified and the
|
||||||
|
// the username is blank.
|
||||||
|
func addAuthFromNetrc(u *url.URL) error {
|
||||||
|
// If the URL already has auth information, do nothing
|
||||||
|
if u.User != nil && u.User.Username() != "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the netrc file path
|
||||||
|
path := os.Getenv("NETRC")
|
||||||
|
if path == "" {
|
||||||
|
filename := ".netrc"
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
filename = "_netrc"
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
path, err = homedir.Expand("~/" + filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the file is not a file, then do nothing
|
||||||
|
if fi, err := os.Stat(path); err != nil {
|
||||||
|
// File doesn't exist, do nothing
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some other error!
|
||||||
|
return err
|
||||||
|
} else if fi.IsDir() {
|
||||||
|
// File is directory, ignore
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load up the netrc file
|
||||||
|
net, err := netrc.ParseFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error parsing netrc file at %q: %s", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
machine := net.FindMachine(u.Host)
|
||||||
|
if machine == nil {
|
||||||
|
// Machine not found, no problem
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the user info
|
||||||
|
u.User = url.UserPassword(machine.Login, machine.Password)
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -904,6 +904,12 @@
|
||||||
"version": "v1.4.2",
|
"version": "v1.4.2",
|
||||||
"versionExact": "v1.4.2"
|
"versionExact": "v1.4.2"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"checksumSHA1": "nqw2Qn5xUklssHTubS5HDvEL9L4=",
|
||||||
|
"path": "github.com/bgentry/go-netrc/netrc",
|
||||||
|
"revision": "9fd32a8b3d3d3f9d43c341bfe098430e07609480",
|
||||||
|
"revisionTime": "2014-04-22T17:41:19Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "github.com/bgentry/speakeasy",
|
"path": "github.com/bgentry/speakeasy",
|
||||||
"revision": "36e9cfdd690967f4f690c6edcc9ffacd006014a0"
|
"revision": "36e9cfdd690967f4f690c6edcc9ffacd006014a0"
|
||||||
|
@ -1126,10 +1132,10 @@
|
||||||
"revision": "875fb671b3ddc66f8e2f0acc33829c8cb989a38d"
|
"revision": "875fb671b3ddc66f8e2f0acc33829c8cb989a38d"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "MN8EmPozxjt3pyOCYfsO5Pon8V0=",
|
"checksumSHA1": "Qw7bz5IlDicreRjfyiB8QBJi0Fc=",
|
||||||
"path": "github.com/hashicorp/go-getter",
|
"path": "github.com/hashicorp/go-getter",
|
||||||
"revision": "a186869fff81d32bcb4e98c88c7c7d82880271ba",
|
"revision": "0eb633db32e432fabba9eca8fa21192fab2b96be",
|
||||||
"revisionTime": "2016-08-24T23:43:04Z"
|
"revisionTime": "2016-08-30T22:50:22Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "github.com/hashicorp/go-getter/helper/url",
|
"path": "github.com/hashicorp/go-getter/helper/url",
|
||||||
|
|
Loading…
Reference in New Issue