Skip to content

Instantly share code, notes, and snippets.

@angelbarrera92
Created April 20, 2021 16:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save angelbarrera92/7868087f3f7a995a9ff340e98a41d8dc to your computer and use it in GitHub Desktop.
Save angelbarrera92/7868087f3f7a995a9ff340e98a41d8dc to your computer and use it in GitHub Desktop.
golang download parsing netrc
package main
import (
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
"strings"
)
func main() {
downloadFile("https://github.com/sighupio/furyctl-provisioners/archive/vsphere.zip", "/tmp/vsphere.zip", "/Users/angelbarrerasanchez-sighup/work/sighup/furyctl/demo/bootstrap/configuration/.netrc")
}
func downloadFile(fileURL string, filepath string, netrcfile string) error {
data, err := ioutil.ReadFile(netrcfile)
authMap := parseNetrc(string(data))
u, err := url.Parse(fileURL)
if err != nil {
panic(err)
}
// Looking for the right user and password
auth := authMap[u.Host]
client := &http.Client{}
req, err := http.NewRequest("GET", fileURL, nil)
req.SetBasicAuth(auth.login, auth.password)
resp, err := client.Do(req)
// // Get the data
if err != nil {
return err
}
defer resp.Body.Close()
// Create the file
out, err := os.Create(filepath)
if err != nil {
return err
}
defer out.Close()
// Write the body to file
_, err = io.Copy(out, resp.Body)
return err
}
// The following functions were extracted from src/cmd/go/internal/web2/web.go
// as of https://golang.org/cl/161698.
type netrcLine struct {
machine string
login string
password string
}
func parseNetrc(data string) map[string]netrcLine {
// See https://www.gnu.org/software/inetutils/manual/html_node/The-_002enetrc-file.html
// for documentation on the .netrc format.
m := make(map[string]netrcLine)
var l netrcLine
inMacro := false
for _, line := range strings.Split(data, "\n") {
if inMacro {
if line == "" {
inMacro = false
}
continue
}
f := strings.Fields(line)
i := 0
for ; i < len(f)-1; i += 2 {
// Reset at each "machine" token.
// “The auto-login process searches the .netrc file for a machine token
// that matches […]. Once a match is made, the subsequent .netrc tokens
// are processed, stopping when the end of file is reached or another
// machine or a default token is encountered.”
switch f[i] {
case "machine":
l = netrcLine{machine: f[i+1]}
case "default":
break
case "login":
l.login = f[i+1]
case "password":
l.password = f[i+1]
case "macdef":
// “A macro is defined with the specified name; its contents begin with
// the next .netrc line and continue until a null line (consecutive
// new-line characters) is encountered.”
inMacro = true
}
if l.machine != "" && l.login != "" && l.password != "" {
m[l.machine] = l
l = netrcLine{}
}
}
if i < len(f) && f[i] == "default" {
// “There can be only one default token, and it must be after all machine tokens.”
break
}
}
return m
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment