<commit_before>package main

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"
)

const statefile = "/data/statefile.json"

type state struct {
	MacIpMap  map[string]string            `json:"Ips"`
	MacEnvMap map[string]map[string]string `json:"Envs"`
}

func main() {
	args := os.Args
	for i, arg := range args {
		log.Printf("arg %v: %s", i, arg)
	}
	dataPrefix := flag.String("prefix", "unik_", "prefix for data sent via udp (for identification purposes")
	enablePersistence := flag.Bool("enablePersistence", true, "assume a persistent volume is mounted to /data")
	flag.Parse()
	for i, arg := range flag.Args() {

		log.Printf("flagarg %v: %s", i, arg)
	}
	if *dataPrefix == "unik_" {
		log.Printf("ERROR: must provide -prefix")
		return
	}
	if *dataPrefix == "" {
		log.Printf("ERROR: -prefix cannot be \"\"")
		return
	}
	if !*enablePersistence {
		os.MkdirAll("/data", 0755)
	}
	ipMapLock := sync.RWMutex{}
	envMapLock := sync.RWMutex{}
	saveLock := sync.Mutex{}
	var s state
	s.MacIpMap = make(map[string]string)
	s.MacEnvMap = make(map[string]map[string]string)

	data, err := ioutil.ReadFile(statefile)
	if err != nil {
		log.Printf("could not read statefile, maybe this is first boot: " + err.Error())
	} else {
		if err := json.Unmarshal(data, &s); err != nil {
			log.Printf("failed to parse state json: " + err.Error())
		}
	}

	listenerIp, listenerIpMask, err := getLocalIp()
	if err != nil {
		log.Printf("ERROR: failed to get local ip: %v", err)
		return
	}

	log.Printf("Starting unik discovery (udp heartbeat broadcast) with ip %s", listenerIp.String())
	info := []byte(*dataPrefix + ":" + listenerIp.String())
	BROADCAST_IPv4 := reverseMask(listenerIp, listenerIpMask)
	if listenerIpMask == nil {
		log.Printf("ERROR: listener-ip: %v; listener-ip-mask: %v; could not calculate broadcast address", listenerIp, listenerIpMask)
		return
	}
	socket, err := net.DialUDP("udp4", nil, &net.UDPAddr{
		IP:   BROADCAST_IPv4,
		Port: 9967,
	})
	if err != nil {
		log.Printf(fmt.Sprintf("ERROR: broadcast-ip: %v; failed to dial udp broadcast connection", BROADCAST_IPv4))
		return
	}
	go func() {
		log.Printf("broadcasting...")
		for {
			_, err = socket.Write(info)
			if err != nil {
				log.Printf("ERROR: broadcast-ip: %v; failed writing to broadcast udp socket: "+err.Error(), BROADCAST_IPv4)
				return
			}
			time.Sleep(1000 * time.Millisecond)
		}
	}()
	m := http.NewServeMux()
	m.HandleFunc("/register", func(res http.ResponseWriter, req *http.Request) {
		if req.Method != "POST" {
			res.WriteHeader(http.StatusNotFound)
			return
		}
		splitAddr := strings.Split(req.RemoteAddr, ":")
		if len(splitAddr) < 1 {
			log.Printf("req.RemoteAddr: %v, could not parse remote addr into ip/port combination", req.RemoteAddr)
			return
		}
		instanceIp := splitAddr[0]
		macAddress := req.URL.Query().Get("mac_address")
		log.Printf("Instance registered")
		log.Printf("ip: %v", instanceIp)
		log.Printf("ip: %v", macAddress)
		//mac address = the instance id in vsphere/vbox
		go func() {
			ipMapLock.Lock()
			defer ipMapLock.Unlock()
			s.MacIpMap[macAddress] = instanceIp
			go save(s, saveLock)
		}()
		envMapLock.RLock()
		defer envMapLock.RUnlock()
		env, ok := s.MacEnvMap[macAddress]
		if !ok {
			env = make(map[string]string)
			log.Printf("mac: %v", macAddress)
			log.Printf("env: %v", s.MacEnvMap)
			log.Printf("no env set for instance, replying with empty map")
		}
		data, err := json.Marshal(env)
		if err != nil {
			log.Printf("could not marshal env to json: " + err.Error())
			return
		}
		log.Printf("responding with data: %s", data)
		fmt.Fprintf(res, "%s", data)
	})
	m.HandleFunc("/set_instance_env", func(res http.ResponseWriter, req *http.Request) {
		if req.Method != "POST" {
			res.WriteHeader(http.StatusNotFound)
			return
		}
		macAddress := req.URL.Query().Get("mac_address")
		data, err := ioutil.ReadAll(req.Body)
		if err != nil {
			res.WriteHeader(http.StatusInternalServerError)
			res.Write([]byte(err.Error()))
			return
		}
		defer req.Body.Close()
		var env map[string]string
		if err := json.Unmarshal(data, &env); err != nil {
			res.WriteHeader(http.StatusInternalServerError)
			res.Write([]byte(err.Error()))
			return
		}
		log.Printf("Env set for instance")
		log.Printf("mac: %v", macAddress)
		log.Printf("env: %v", env)
		envMapLock.Lock()
		defer envMapLock.Unlock()
		s.MacEnvMap[macAddress] = env
		go save(s, saveLock)
		res.WriteHeader(http.StatusAccepted)
	})
	m.HandleFunc("/instances", func(res http.ResponseWriter, req *http.Request) {
		if req.Method != "GET" {
			res.WriteHeader(http.StatusNotFound)
			return
		}
		ipMapLock.RLock()
		defer ipMapLock.RUnlock()
		data, err := json.Marshal(s.MacIpMap)
		if err != nil {
			res.WriteHeader(http.StatusInternalServerError)
			res.Write([]byte(err.Error()))
		}
		res.Write(data)
	})
	log.Printf("listening on port 3000")
	http.ListenAndServe(":3000", m)
}

func getLocalIp() (net.IP, net.IPMask, error) {
	ifaces, err := net.Interfaces()
	if err != nil {
		return net.IP{}, net.IPMask{}, errors.New("retrieving network interfaces" + err.Error())
	}
	for _, iface := range ifaces {
		log.Printf("found an interface: %v\n", iface)
		addrs, err := iface.Addrs()
		if err != nil {
			continue
		}
		for _, addr := range addrs {
			log.Printf("inspecting address: %v", addr)
			switch v := addr.(type) {
			case *net.IPNet:
				if !v.IP.IsLoopback() && v.IP.IsGlobalUnicast() && v.IP.To4() != nil && v.Mask != nil {
					return v.IP.To4(),v.Mask,  nil
				}
			}
		}
	}
	return net.IP{}, net.IPMask{}, errors.New("failed to find ip on ifaces: " + fmt.Sprintf("%v", ifaces))
}

// ReverseMask returns the result of masking the IP address ip with mask.
func reverseMask(ip net.IP, mask net.IPMask) net.IP {
	n := len(ip)
	if n != len(mask) {
		return nil
	}
	out := make(net.IP, n)
	for i := 0; i < n; i++ {
		out[i] = ip[i] | (^mask[i])
	}
	return out
}

func save(s state, l sync.Mutex) {
	if err := func() error {
		l.Lock()
		defer l.Unlock()
		data, err := json.Marshal(s)
		if err != nil {
			return err
		}
		if err := ioutil.WriteFile(statefile, data, 0644); err != nil {
			return err
		}
		return nil
	}(); err != nil {
		log.Printf("failed to save state file %s", statefile)
	}
}
<commit_msg>Fix high CPU usage<commit_after>package main

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"
)

const statefile = "/data/statefile.json"

type state struct {
	MacIpMap  map[string]string            `json:"Ips"`
	MacEnvMap map[string]map[string]string `json:"Envs"`
}

func main() {
	args := os.Args
	for i, arg := range args {
		log.Printf("arg %v: %s", i, arg)
	}
	dataPrefix := flag.String("prefix", "unik_", "prefix for data sent via udp (for identification purposes")
	enablePersistence := flag.Bool("enablePersistence", true, "assume a persistent volume is mounted to /data")
	flag.Parse()
	for i, arg := range flag.Args() {

		log.Printf("flagarg %v: %s", i, arg)
	}
	if *dataPrefix == "unik_" {
		log.Printf("ERROR: must provide -prefix")
		return
	}
	if *dataPrefix == "" {
		log.Printf("ERROR: -prefix cannot be \"\"")
		return
	}
	if !*enablePersistence {
		os.MkdirAll("/data", 0755)
	}
	ipMapLock := sync.RWMutex{}
	envMapLock := sync.RWMutex{}
	saveLock := sync.Mutex{}
	var s state
	s.MacIpMap = make(map[string]string)
	s.MacEnvMap = make(map[string]map[string]string)

	data, err := ioutil.ReadFile(statefile)
	if err != nil {
		log.Printf("could not read statefile, maybe this is first boot: " + err.Error())
	} else {
		if err := json.Unmarshal(data, &s); err != nil {
			log.Printf("failed to parse state json: " + err.Error())
		}
	}

	listenerIp, listenerIpMask, err := getLocalIp()
	if err != nil {
		log.Printf("ERROR: failed to get local ip: %v", err)
		return
	}

	log.Printf("Starting unik discovery (udp heartbeat broadcast) with ip %s", listenerIp.String())
	info := []byte(*dataPrefix + ":" + listenerIp.String())
	BROADCAST_IPv4 := reverseMask(listenerIp, listenerIpMask)
	if listenerIpMask == nil {
		log.Printf("ERROR: listener-ip: %v; listener-ip-mask: %v; could not calculate broadcast address", listenerIp, listenerIpMask)
		return
	}
	socket, err := net.DialUDP("udp4", nil, &net.UDPAddr{
		IP:   BROADCAST_IPv4,
		Port: 9967,
	})
	if err != nil {
		log.Printf(fmt.Sprintf("ERROR: broadcast-ip: %v; failed to dial udp broadcast connection", BROADCAST_IPv4))
		return
	}
	go func() {
		log.Printf("broadcasting...")
		for {
			_, err = socket.Write(info)
			if err != nil {
				log.Printf("ERROR: broadcast-ip: %v; failed writing to broadcast udp socket: "+err.Error(), BROADCAST_IPv4)
				return
			}
			time.Sleep(5000 * time.Millisecond)
		}
	}()
	m := http.NewServeMux()
	m.HandleFunc("/register", func(res http.ResponseWriter, req *http.Request) {
		if req.Method != "POST" {
			res.WriteHeader(http.StatusNotFound)
			return
		}
		splitAddr := strings.Split(req.RemoteAddr, ":")
		if len(splitAddr) < 1 {
			log.Printf("req.RemoteAddr: %v, could not parse remote addr into ip/port combination", req.RemoteAddr)
			return
		}
		instanceIp := splitAddr[0]
		macAddress := req.URL.Query().Get("mac_address")
		log.Printf("Instance registered")
		log.Printf("ip: %v", instanceIp)
		log.Printf("ip: %v", macAddress)
		//mac address = the instance id in vsphere/vbox
		go func() {
			ipMapLock.Lock()
			defer ipMapLock.Unlock()
			s.MacIpMap[macAddress] = instanceIp
			go save(s, saveLock)
		}()
		envMapLock.RLock()
		defer envMapLock.RUnlock()
		env, ok := s.MacEnvMap[macAddress]
		if !ok {
			env = make(map[string]string)
			log.Printf("mac: %v", macAddress)
			log.Printf("env: %v", s.MacEnvMap)
			log.Printf("no env set for instance, replying with empty map")
		}
		data, err := json.Marshal(env)
		if err != nil {
			log.Printf("could not marshal env to json: " + err.Error())
			return
		}
		log.Printf("responding with data: %s", data)
		fmt.Fprintf(res, "%s", data)
	})
	m.HandleFunc("/set_instance_env", func(res http.ResponseWriter, req *http.Request) {
		if req.Method != "POST" {
			res.WriteHeader(http.StatusNotFound)
			return
		}
		macAddress := req.URL.Query().Get("mac_address")
		data, err := ioutil.ReadAll(req.Body)
		if err != nil {
			res.WriteHeader(http.StatusInternalServerError)
			res.Write([]byte(err.Error()))
			return
		}
		defer req.Body.Close()
		var env map[string]string
		if err := json.Unmarshal(data, &env); err != nil {
			res.WriteHeader(http.StatusInternalServerError)
			res.Write([]byte(err.Error()))
			return
		}
		log.Printf("Env set for instance")
		log.Printf("mac: %v", macAddress)
		log.Printf("env: %v", env)
		envMapLock.Lock()
		defer envMapLock.Unlock()
		s.MacEnvMap[macAddress] = env
		go save(s, saveLock)
		res.WriteHeader(http.StatusAccepted)
	})
	m.HandleFunc("/instances", func(res http.ResponseWriter, req *http.Request) {
		if req.Method != "GET" {
			res.WriteHeader(http.StatusNotFound)
			return
		}
		ipMapLock.RLock()
		defer ipMapLock.RUnlock()
		data, err := json.Marshal(s.MacIpMap)
		if err != nil {
			res.WriteHeader(http.StatusInternalServerError)
			res.Write([]byte(err.Error()))
		}
		res.Write(data)
	})
	log.Printf("listening on port 3000")
	http.ListenAndServe(":3000", m)
}

func getLocalIp() (net.IP, net.IPMask, error) {
	ifaces, err := net.Interfaces()
	if err != nil {
		return net.IP{}, net.IPMask{}, errors.New("retrieving network interfaces" + err.Error())
	}
	for _, iface := range ifaces {
		log.Printf("found an interface: %v\n", iface)
		addrs, err := iface.Addrs()
		if err != nil {
			continue
		}
		for _, addr := range addrs {
			log.Printf("inspecting address: %v", addr)
			switch v := addr.(type) {
			case *net.IPNet:
				if !v.IP.IsLoopback() && v.IP.IsGlobalUnicast() && v.IP.To4() != nil && v.Mask != nil {
					return v.IP.To4(),v.Mask,  nil
				}
			}
		}
	}
	return net.IP{}, net.IPMask{}, errors.New("failed to find ip on ifaces: " + fmt.Sprintf("%v", ifaces))
}

// ReverseMask returns the result of masking the IP address ip with mask.
func reverseMask(ip net.IP, mask net.IPMask) net.IP {
	n := len(ip)
	if n != len(mask) {
		return nil
	}
	out := make(net.IP, n)
	for i := 0; i < n; i++ {
		out[i] = ip[i] | (^mask[i])
	}
	return out
}

func save(s state, l sync.Mutex) {
	if err := func() error {
		l.Lock()
		defer l.Unlock()
		data, err := json.Marshal(s)
		if err != nil {
			return err
		}
		if err := ioutil.WriteFile(statefile, data, 0644); err != nil {
			return err
		}
		return nil
	}(); err != nil {
		log.Printf("failed to save state file %s", statefile)
	}
}
<|endoftext|>


<commit_before>// BaruwaAPI Golang bindings for Baruwa REST API
// Copyright (C) 2019 Andrew Colin Kissa <andrew@topdog.za.net>

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

// Package api Golang bindings for Baruwa REST API
package api

// OrgDomain hold alias domain entries
type OrgDomain struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
}

// Organization holds organizations
type Organization struct {
	ID      int         `json:"id,omitempty"`
	Name    string      `json:"name"`
	Domains []OrgDomain `json:"domains,omitempty"`
}

// OrganizationForm used for creation and update of organizations
type OrganizationForm struct {
	ID      int    `json:"id,omitempty"`
	Name    string `json:"name"`
	Domains []int  `json:"domains,omitempty"`
	Admins  []int  `json:"admins,omitempty"`
}

// GetOrganization returns an organization
// https://www.baruwa.com/docs/api/#retrieve-an-existing-organization
func (c *Client) GetOrganization(id int) (org *Organization, err error) {
	return
}

// CreateOrganization creates an organization
// https://www.baruwa.com/docs/api/#create-an-organization
func (c *Client) CreateOrganization(form *OrganizationForm, org Organization) (err error) {
	return
}

// UpdateOrganization updates an organization
// https://www.baruwa.com/docs/api/#update-an-organization
func (c *Client) UpdateOrganization(form *OrganizationForm, org Organization) (err error) {
	return
}

// DeleteOrganization deletes an organization
// https://www.baruwa.com/docs/api/#delete-an-organization
func (c *Client) DeleteOrganization(id int) (err error) {
	return
}
<commit_msg>FET: Organization implementation<commit_after>// BaruwaAPI Golang bindings for Baruwa REST API
// Copyright (C) 2019 Andrew Colin Kissa <andrew@topdog.za.net>

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

// Package api Golang bindings for Baruwa REST API
package api

import (
	"fmt"
	"net/url"

	"github.com/google/go-querystring/query"
)

// OrgDomain hold alias domain entries
type OrgDomain struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
}

// Organization holds organizations
type Organization struct {
	ID      int         `json:"id,omitempty"`
	Name    string      `json:"name"`
	Domains []OrgDomain `json:"domains,omitempty"`
}

// OrganizationForm used for creation and update of organizations
type OrganizationForm struct {
	ID      int    `json:"id,omitempty"`
	Name    string `json:"name"`
	Domains []int  `json:"domains,omitempty"`
	Admins  []int  `json:"admins,omitempty"`
}

// GetOrganization returns an organization
// https://www.baruwa.com/docs/api/#retrieve-an-existing-organization
func (c *Client) GetOrganization(organizationID int) (org *Organization, err error) {
	if organizationID <= 0 {
		err = fmt.Errorf("The organizationID param should be > 0")
		return
	}

	err = c.get(fmt.Sprintf("organizations/%d", organizationID), org)

	return
}

// CreateOrganization creates an organization
// https://www.baruwa.com/docs/api/#create-an-organization
func (c *Client) CreateOrganization(form *OrganizationForm, org Organization) (err error) {
	var v url.Values

	if form == nil {
		err = fmt.Errorf("The form param cannot be nil")
		return
	}

	if v, err = query.Values(form); err != nil {
		return
	}

	err = c.post("organizations", v, org)

	return
}

// UpdateOrganization updates an organization
// https://www.baruwa.com/docs/api/#update-an-organization
func (c *Client) UpdateOrganization(form *OrganizationForm, org Organization) (err error) {
	var v url.Values

	if form == nil {
		err = fmt.Errorf("The form param cannot be nil")
		return
	}

	if form.ID <= 0 {
		err = fmt.Errorf("The form.ID param should be > 0")
		return
	}

	if v, err = query.Values(form); err != nil {
		return
	}

	err = c.put(fmt.Sprintf("organizations/%d", form.ID), v, org)

	return
}

// DeleteOrganization deletes an organization
// https://www.baruwa.com/docs/api/#delete-an-organization
func (c *Client) DeleteOrganization(organizationID int) (err error) {
	if organizationID <= 0 {
		err = fmt.Errorf("The organizationID param should be > 0")
		return
	}

	err = c.delete(fmt.Sprintf("organizations/%d", organizationID), nil)

	return
}
<|endoftext|>


<commit_before>package api

import (
	"reflect"
	"testing"
	"time"
)

func TestRenewer_NewRenewer(t *testing.T) {
	t.Parallel()

	client, err := NewClient(DefaultConfig())
	if err != nil {
		t.Fatal(err)
	}

	cases := []struct {
		name string
		i    *RenewerInput
		e    *Renewer
		err  bool
	}{
		{
			"nil",
			nil,
			nil,
			true,
		},
		{
			"missing_secret",
			&RenewerInput{
				Secret: nil,
			},
			nil,
			true,
		},
		{
			"default_grace",
			&RenewerInput{
				Secret: &Secret{},
			},
			&Renewer{
				secret: &Secret{},
				grace:  DefaultRenewerGrace,
			},
			false,
		},
		{
			"custom_grace",
			&RenewerInput{
				Secret: &Secret{},
				Grace:  30 * time.Second,
			},
			&Renewer{
				secret: &Secret{},
				grace:  30 * time.Second,
			},
			false,
		},
	}

	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			v, err := client.NewRenewer(tc.i)
			if (err != nil) != tc.err {
				t.Fatal(err)
			}

			if v == nil {
				return
			}

			// Zero-out channels because reflect
			v.client = nil
			v.doneCh = nil
			v.renewCh = nil
			v.stopCh = nil

			if !reflect.DeepEqual(tc.e, v) {
				t.Errorf("not equal\nexp: %#v\nact: %#v", tc.e, v)
			}
		})
	}
}
<commit_msg>Fix failing test<commit_after>package api

import (
	"reflect"
	"testing"
	"time"
)

func TestRenewer_NewRenewer(t *testing.T) {
	t.Parallel()

	client, err := NewClient(DefaultConfig())
	if err != nil {
		t.Fatal(err)
	}

	cases := []struct {
		name string
		i    *RenewerInput
		e    *Renewer
		err  bool
	}{
		{
			"nil",
			nil,
			nil,
			true,
		},
		{
			"missing_secret",
			&RenewerInput{
				Secret: nil,
			},
			nil,
			true,
		},
		{
			"default_grace",
			&RenewerInput{
				Secret: &Secret{},
			},
			&Renewer{
				secret: &Secret{},
				grace:  DefaultRenewerGrace,
			},
			false,
		},
		{
			"custom_grace",
			&RenewerInput{
				Secret: &Secret{},
				Grace:  30 * time.Second,
			},
			&Renewer{
				secret: &Secret{},
				grace:  30 * time.Second,
			},
			false,
		},
	}

	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			v, err := client.NewRenewer(tc.i)
			if (err != nil) != tc.err {
				t.Fatal(err)
			}

			if v == nil {
				return
			}

			// Zero-out channels because reflect
			v.client = nil
			v.random = nil
			v.doneCh = nil
			v.renewCh = nil
			v.stopCh = nil

			if !reflect.DeepEqual(tc.e, v) {
				t.Errorf("not equal\nexp: %#v\nact: %#v", tc.e, v)
			}
		})
	}
}
<|endoftext|>


<commit_before>// Package colly implements a HTTP scraping framework
package colly

import (
	"bytes"
	"net/http"
	"net/url"
	"strings"
	"sync"

	"golang.org/x/net/html"

	"github.com/PuerkitoBio/goquery"
)

// Collector provides the scraper instance for a scraping job
type Collector struct {
	// UserAgent is the User-Agent string used by HTTP requests
	UserAgent string
	// MaxDepth limits the recursion depth of visited URLs.
	// Set it to 0 for infinite recursion (default).
	MaxDepth int
	// AllowedDomains is a domain whitelist.
	// Leave it blank to allow any domains to be visited
	AllowedDomains    []string
	visitedURLs       []string
	htmlCallbacks     map[string]HTMLCallback
	requestCallbacks  []RequestCallback
	responseCallbacks []ResponseCallback
	backend           *httpBackend
	wg                *sync.WaitGroup
	lock              *sync.Mutex
}

// Request is the representation of a HTTP request made by a Collector
type Request struct {
	// URL is the parsed URL of the HTTP request
	URL *url.URL
	// Headers contains the Request's HTTP headers
	Headers *http.Header
	// Ctx is a context between a Request and a Response
	Ctx *Context
	// Depth is the number of the parents of this request
	Depth     int
	collector *Collector
}

// Response is the representation of a HTTP response made by a Collector
type Response struct {
	// StatusCode is the status code of the Response
	StatusCode int
	// Body is the content of the Response
	Body []byte
	// Ctx is a context between a Request and a Response
	Ctx *Context
	// Request is the Request object of the response
	Request *Request
	// Headers contains the Response's HTTP headers
	Headers *http.Header
}

// HTMLElement is the representation of a HTML tag.
type HTMLElement struct {
	// Name is the name of the tag
	Name       string
	Text       string
	attributes []html.Attribute
	// Request is the request object of the element's HTML document
	Request *Request
	// Response is the Response object of the element's HTML document
	Response *Response
	// DOM is the goquery parsed DOM object of the page. DOM is relative
	// to the current HTMLElement
	DOM *goquery.Selection
}

// Context provides a tiny layer for passing data between callbacks
type Context struct {
	contextMap map[string]string
	lock       *sync.Mutex
}

// RequestCallback is a type alias for OnRequest callback functions
type RequestCallback func(*Request)

// ResponseCallback is a type alias for OnResponse callback functions
type ResponseCallback func(*Response)

// HTMLCallback is a type alias for OnHTML callback functions
type HTMLCallback func(*HTMLElement)

// NewCollector creates a new Collector instance with default configuration
func NewCollector() *Collector {
	c := &Collector{}
	c.Init()
	return c
}

// NewContext initializes a new Context instance
func NewContext() *Context {
	return &Context{
		contextMap: make(map[string]string),
		lock:       &sync.Mutex{},
	}
}

// Init initializes the Collector's private variables and sets default
// configuration for the Collector
func (c *Collector) Init() {
	c.UserAgent = "colly - https://github.com/asciimoo/colly"
	c.MaxDepth = 0
	c.visitedURLs = make([]string, 0, 8)
	c.htmlCallbacks = make(map[string]HTMLCallback, 0)
	c.requestCallbacks = make([]RequestCallback, 0, 8)
	c.responseCallbacks = make([]ResponseCallback, 0, 8)
	c.backend = &httpBackend{}
	c.backend.Init()
	c.wg = &sync.WaitGroup{}
	c.lock = &sync.Mutex{}
}

// Visit starts Collector's collecting job by creating a
// request to the URL specified in parameter.
// Visit also calls the previously provided OnRequest,
// OnResponse, OnHTML callbacks
func (c *Collector) Visit(URL string) error {
	return c.scrape(URL, "GET", 1, nil)
}

// Post starts collecting job by creating a POST
// request.
// Post also calls the previously provided OnRequest,
// OnResponse, OnHTML callbacks
func (c *Collector) Post(URL string, requestData map[string]string) error {
	return c.scrape(URL, "POST", 1, requestData)
}

func (c *Collector) scrape(u, method string, depth int, requestData map[string]string) error {
	c.wg.Add(1)
	defer c.wg.Done()
	if u == "" {
		return nil
	}
	if c.MaxDepth > 0 && c.MaxDepth < depth {
		return nil
	}
	visited := false
	for _, u2 := range c.visitedURLs {
		if u2 == u {
			visited = true
			break
		}
	}
	if visited {
		return nil
	}
	parsedURL, err := url.Parse(u)
	if err != nil {
		return err
	}
	allowed := false
	if c.AllowedDomains == nil || len(c.AllowedDomains) == 0 {
		allowed = true
	} else {
		for _, d := range c.AllowedDomains {
			if d == parsedURL.Host {
				allowed = true
				break
			}
		}
	}
	if !allowed {
		return nil
	}
	c.lock.Lock()
	c.visitedURLs = append(c.visitedURLs, u)
	c.lock.Unlock()
	var form url.Values
	if method == "POST" {
		form := url.Values{}
		for k, v := range requestData {
			form.Add(k, v)
		}
	}
	req, err := http.NewRequest(method, u, strings.NewReader(form.Encode()))
	if err != nil {
		return err
	}
	req.Header.Set("User-Agent", c.UserAgent)
	if method == "POST" {
		req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	}
	ctx := NewContext()
	request := &Request{
		URL:       parsedURL,
		Headers:   &req.Header,
		Ctx:       ctx,
		Depth:     depth,
		collector: c,
	}
	if len(c.requestCallbacks) > 0 {
		c.handleOnRequest(request)
	}
	response, err := c.backend.Do(req)
	// TODO add OnError callback to handle these cases
	if err != nil {
		return err
	}
	response.Ctx = ctx
	response.Request = request
	if strings.Index(strings.ToLower(response.Headers.Get("Content-Type")), "html") > -1 {
		c.handleOnHTML(response.Body, request, response)
	}
	if len(c.responseCallbacks) > 0 {
		c.handleOnResponse(response)
	}
	return nil
}

// Wait returns when the collector jobs are finished
func (c *Collector) Wait() {
	c.wg.Wait()
}

// OnRequest registers a function. Function will be executed on every
// request made by the Collector
func (c *Collector) OnRequest(f RequestCallback) {
	c.lock.Lock()
	c.requestCallbacks = append(c.requestCallbacks, f)
	c.lock.Unlock()
}

// OnResponse registers a function. Function will be executed on every response
func (c *Collector) OnResponse(f ResponseCallback) {
	c.lock.Lock()
	c.responseCallbacks = append(c.responseCallbacks, f)
	c.lock.Unlock()
}

// OnHTML registers a function. Function will be executed on every HTML
// element matched by the `goquerySelector` parameter.
// `goquerySelector` is a selector used by https://github.com/PuerkitoBio/goquery
func (c *Collector) OnHTML(goquerySelector string, f HTMLCallback) {
	c.lock.Lock()
	c.htmlCallbacks[goquerySelector] = f
	c.lock.Unlock()
}

// WithTransport allows you to set a custom http.Transport for this collector.
func (c *Collector) WithTransport(transport *http.Transport) {
	c.backend.Client.Transport = transport
}

// DisableCookies turns off cookie handling for this collector
func (c *Collector) DisableCookies() {
	c.backend.Client.Jar = nil
}

func (c *Collector) handleOnRequest(r *Request) {
	for _, f := range c.requestCallbacks {
		f(r)
	}
}

func (c *Collector) handleOnResponse(r *Response) {
	for _, f := range c.responseCallbacks {
		f(r)
	}
}

func (c *Collector) handleOnHTML(body []byte, req *Request, resp *Response) {
	doc, err := goquery.NewDocumentFromReader(bytes.NewBuffer(body))
	if err != nil {
		return
	}
	for expr, f := range c.htmlCallbacks {
		doc.Find(expr).Each(func(i int, s *goquery.Selection) {
			for _, n := range s.Nodes {
				e := &HTMLElement{
					Name:       n.Data,
					Request:    req,
					Response:   resp,
					Text:       goquery.NewDocumentFromNode(n).Text(),
					DOM:        s,
					attributes: n.Attr,
				}
				f(e)
			}
		})
	}
}

// Limit adds a new `LimitRule` to the collector
func (c *Collector) Limit(rule *LimitRule) error {
	return c.backend.Limit(rule)
}

// Limits adds new `LimitRule`s to the collector
func (c *Collector) Limits(rules []*LimitRule) error {
	return c.backend.Limits(rules)
}

// Attr returns the selected attribute of a HTMLElement or empty string
// if no attribute found
func (h *HTMLElement) Attr(k string) string {
	for _, a := range h.attributes {
		if a.Key == k {
			return a.Val
		}
	}
	return ""
}

// AbsoluteURL returns with the resolved absolute URL of an URL chunk.
// AbsoluteURL returns empty string if the URL chunk is a fragment or
// could not be parsed
func (r *Request) AbsoluteURL(u string) string {
	if strings.HasPrefix(u, "#") {
		return ""
	}
	absURL, err := r.URL.Parse(u)
	if err != nil {
		return ""
	}
	absURL.Fragment = ""
	if absURL.Scheme == "//" {
		absURL.Scheme = r.URL.Scheme
	}
	return absURL.String()
}

// Visit continues Collector's collecting job by creating a
// request to the URL specified in parameter.
// Visit also calls the previously provided OnRequest,
// OnResponse, OnHTML callbacks
func (r *Request) Visit(URL string) error {
	return r.collector.scrape(r.AbsoluteURL(URL), "GET", r.Depth+1, nil)
}

// Post continues a collector job by creating a POST request.
// Post also calls the previously provided OnRequest, OnResponse, OnHTML callbacks
func (r *Request) Post(URL string, requestData map[string]string) error {
	return r.collector.scrape(r.AbsoluteURL(URL), "GET", r.Depth+1, requestData)
}

// Put stores a value in Context
func (c *Context) Put(key, value string) {
	c.lock.Lock()
	c.contextMap[key] = value
	c.lock.Unlock()
}

// Get retrieves a value from Context. If no value found for `k`
// Get returns an empty string if key not found
func (c *Context) Get(key string) string {
	if v, ok := c.contextMap[key]; ok {
		return v
	}
	return ""
}
<commit_msg>[enh] allow URL revisit + more verbose error handling<commit_after>// Package colly implements a HTTP scraping framework
package colly

import (
	"bytes"
	"errors"
	"net/http"
	"net/url"
	"strings"
	"sync"

	"golang.org/x/net/html"

	"github.com/PuerkitoBio/goquery"
)

// Collector provides the scraper instance for a scraping job
type Collector struct {
	// UserAgent is the User-Agent string used by HTTP requests
	UserAgent string
	// MaxDepth limits the recursion depth of visited URLs.
	// Set it to 0 for infinite recursion (default).
	MaxDepth int
	// AllowedDomains is a domain whitelist.
	// Leave it blank to allow any domains to be visited
	AllowedDomains []string
	// AllowURLRevisit allows multiple downloads of the same URL
	AllowURLRevisit   bool
	visitedURLs       []string
	htmlCallbacks     map[string]HTMLCallback
	requestCallbacks  []RequestCallback
	responseCallbacks []ResponseCallback
	backend           *httpBackend
	wg                *sync.WaitGroup
	lock              *sync.Mutex
}

// Request is the representation of a HTTP request made by a Collector
type Request struct {
	// URL is the parsed URL of the HTTP request
	URL *url.URL
	// Headers contains the Request's HTTP headers
	Headers *http.Header
	// Ctx is a context between a Request and a Response
	Ctx *Context
	// Depth is the number of the parents of this request
	Depth     int
	collector *Collector
}

// Response is the representation of a HTTP response made by a Collector
type Response struct {
	// StatusCode is the status code of the Response
	StatusCode int
	// Body is the content of the Response
	Body []byte
	// Ctx is a context between a Request and a Response
	Ctx *Context
	// Request is the Request object of the response
	Request *Request
	// Headers contains the Response's HTTP headers
	Headers *http.Header
}

// HTMLElement is the representation of a HTML tag.
type HTMLElement struct {
	// Name is the name of the tag
	Name       string
	Text       string
	attributes []html.Attribute
	// Request is the request object of the element's HTML document
	Request *Request
	// Response is the Response object of the element's HTML document
	Response *Response
	// DOM is the goquery parsed DOM object of the page. DOM is relative
	// to the current HTMLElement
	DOM *goquery.Selection
}

// Context provides a tiny layer for passing data between callbacks
type Context struct {
	contextMap map[string]string
	lock       *sync.Mutex
}

// RequestCallback is a type alias for OnRequest callback functions
type RequestCallback func(*Request)

// ResponseCallback is a type alias for OnResponse callback functions
type ResponseCallback func(*Response)

// HTMLCallback is a type alias for OnHTML callback functions
type HTMLCallback func(*HTMLElement)

// NewCollector creates a new Collector instance with default configuration
func NewCollector() *Collector {
	c := &Collector{}
	c.Init()
	return c
}

// NewContext initializes a new Context instance
func NewContext() *Context {
	return &Context{
		contextMap: make(map[string]string),
		lock:       &sync.Mutex{},
	}
}

// Init initializes the Collector's private variables and sets default
// configuration for the Collector
func (c *Collector) Init() {
	c.UserAgent = "colly - https://github.com/asciimoo/colly"
	c.MaxDepth = 0
	c.visitedURLs = make([]string, 0, 8)
	c.htmlCallbacks = make(map[string]HTMLCallback, 0)
	c.requestCallbacks = make([]RequestCallback, 0, 8)
	c.responseCallbacks = make([]ResponseCallback, 0, 8)
	c.backend = &httpBackend{}
	c.backend.Init()
	c.wg = &sync.WaitGroup{}
	c.lock = &sync.Mutex{}
}

// Visit starts Collector's collecting job by creating a
// request to the URL specified in parameter.
// Visit also calls the previously provided OnRequest,
// OnResponse, OnHTML callbacks
func (c *Collector) Visit(URL string) error {
	return c.scrape(URL, "GET", 1, nil)
}

// Post starts collecting job by creating a POST
// request.
// Post also calls the previously provided OnRequest,
// OnResponse, OnHTML callbacks
func (c *Collector) Post(URL string, requestData map[string]string) error {
	return c.scrape(URL, "POST", 1, requestData)
}

func (c *Collector) scrape(u, method string, depth int, requestData map[string]string) error {
	c.wg.Add(1)
	defer c.wg.Done()
	if u == "" {
		return errors.New("Missing URL")
	}
	if c.MaxDepth > 0 && c.MaxDepth < depth {
		return errors.New("Max depth limit reached")
	}
	if !c.AllowURLRevisit {
		visited := false
		for _, u2 := range c.visitedURLs {
			if u2 == u {
				visited = true
				break
			}
		}
		if visited {
			return errors.New("URL already visited")
		}
	}
	parsedURL, err := url.Parse(u)
	if err != nil {
		return err
	}
	allowed := false
	if c.AllowedDomains == nil || len(c.AllowedDomains) == 0 {
		allowed = true
	} else {
		for _, d := range c.AllowedDomains {
			if d == parsedURL.Host {
				allowed = true
				break
			}
		}
	}
	if !allowed {
		return errors.New("Forbidden domain")
	}
	if !c.AllowURLRevisit {
		c.lock.Lock()
		c.visitedURLs = append(c.visitedURLs, u)
		c.lock.Unlock()
	}
	var form url.Values
	if method == "POST" {
		form := url.Values{}
		for k, v := range requestData {
			form.Add(k, v)
		}
	}
	req, err := http.NewRequest(method, u, strings.NewReader(form.Encode()))
	if err != nil {
		return err
	}
	req.Header.Set("User-Agent", c.UserAgent)
	if method == "POST" {
		req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	}
	ctx := NewContext()
	request := &Request{
		URL:       parsedURL,
		Headers:   &req.Header,
		Ctx:       ctx,
		Depth:     depth,
		collector: c,
	}
	if len(c.requestCallbacks) > 0 {
		c.handleOnRequest(request)
	}
	response, err := c.backend.Do(req)
	// TODO add OnError callback to handle these cases
	if err != nil {
		return err
	}
	response.Ctx = ctx
	response.Request = request
	if strings.Index(strings.ToLower(response.Headers.Get("Content-Type")), "html") > -1 {
		c.handleOnHTML(response.Body, request, response)
	}
	if len(c.responseCallbacks) > 0 {
		c.handleOnResponse(response)
	}
	return nil
}

// Wait returns when the collector jobs are finished
func (c *Collector) Wait() {
	c.wg.Wait()
}

// OnRequest registers a function. Function will be executed on every
// request made by the Collector
func (c *Collector) OnRequest(f RequestCallback) {
	c.lock.Lock()
	c.requestCallbacks = append(c.requestCallbacks, f)
	c.lock.Unlock()
}

// OnResponse registers a function. Function will be executed on every response
func (c *Collector) OnResponse(f ResponseCallback) {
	c.lock.Lock()
	c.responseCallbacks = append(c.responseCallbacks, f)
	c.lock.Unlock()
}

// OnHTML registers a function. Function will be executed on every HTML
// element matched by the `goquerySelector` parameter.
// `goquerySelector` is a selector used by https://github.com/PuerkitoBio/goquery
func (c *Collector) OnHTML(goquerySelector string, f HTMLCallback) {
	c.lock.Lock()
	c.htmlCallbacks[goquerySelector] = f
	c.lock.Unlock()
}

// WithTransport allows you to set a custom http.Transport for this collector.
func (c *Collector) WithTransport(transport *http.Transport) {
	c.backend.Client.Transport = transport
}

// DisableCookies turns off cookie handling for this collector
func (c *Collector) DisableCookies() {
	c.backend.Client.Jar = nil
}

func (c *Collector) handleOnRequest(r *Request) {
	for _, f := range c.requestCallbacks {
		f(r)
	}
}

func (c *Collector) handleOnResponse(r *Response) {
	for _, f := range c.responseCallbacks {
		f(r)
	}
}

func (c *Collector) handleOnHTML(body []byte, req *Request, resp *Response) {
	doc, err := goquery.NewDocumentFromReader(bytes.NewBuffer(body))
	if err != nil {
		return
	}
	for expr, f := range c.htmlCallbacks {
		doc.Find(expr).Each(func(i int, s *goquery.Selection) {
			for _, n := range s.Nodes {
				e := &HTMLElement{
					Name:       n.Data,
					Request:    req,
					Response:   resp,
					Text:       goquery.NewDocumentFromNode(n).Text(),
					DOM:        s,
					attributes: n.Attr,
				}
				f(e)
			}
		})
	}
}

// Limit adds a new `LimitRule` to the collector
func (c *Collector) Limit(rule *LimitRule) error {
	return c.backend.Limit(rule)
}

// Limits adds new `LimitRule`s to the collector
func (c *Collector) Limits(rules []*LimitRule) error {
	return c.backend.Limits(rules)
}

// Attr returns the selected attribute of a HTMLElement or empty string
// if no attribute found
func (h *HTMLElement) Attr(k string) string {
	for _, a := range h.attributes {
		if a.Key == k {
			return a.Val
		}
	}
	return ""
}

// AbsoluteURL returns with the resolved absolute URL of an URL chunk.
// AbsoluteURL returns empty string if the URL chunk is a fragment or
// could not be parsed
func (r *Request) AbsoluteURL(u string) string {
	if strings.HasPrefix(u, "#") {
		return ""
	}
	absURL, err := r.URL.Parse(u)
	if err != nil {
		return ""
	}
	absURL.Fragment = ""
	if absURL.Scheme == "//" {
		absURL.Scheme = r.URL.Scheme
	}
	return absURL.String()
}

// Visit continues Collector's collecting job by creating a
// request to the URL specified in parameter.
// Visit also calls the previously provided OnRequest,
// OnResponse, OnHTML callbacks
func (r *Request) Visit(URL string) error {
	return r.collector.scrape(r.AbsoluteURL(URL), "GET", r.Depth+1, nil)
}

// Post continues a collector job by creating a POST request.
// Post also calls the previously provided OnRequest, OnResponse, OnHTML callbacks
func (r *Request) Post(URL string, requestData map[string]string) error {
	return r.collector.scrape(r.AbsoluteURL(URL), "GET", r.Depth+1, requestData)
}

// Put stores a value in Context
func (c *Context) Put(key, value string) {
	c.lock.Lock()
	c.contextMap[key] = value
	c.lock.Unlock()
}

// Get retrieves a value from Context. If no value found for `k`
// Get returns an empty string if key not found
func (c *Context) Get(key string) string {
	if v, ok := c.contextMap[key]; ok {
		return v
	}
	return ""
}
<|endoftext|>


<commit_before>package application_test

import (
	"fmt"
	"time"

	. "github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/generator"
	acceptanceTestHelpers "github.com/cloudfoundry-incubator/cf-test-helpers/helpers"
	gatsHelpers "github.com/cloudfoundry/cli-acceptance-tests/helpers"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("Env", func() {
	const (
		assertionTimeout = 10 * time.Second
		appTimeout       = 2 * time.Minute
		copyAppTimeout   = 3 * time.Minute
	)

	var (
		context *acceptanceTestHelpers.ConfiguredContext
		env     *acceptanceTestHelpers.Environment
	)

	config := acceptanceTestHelpers.LoadConfig()

	BeforeEach(func() {
		context = acceptanceTestHelpers.NewContext(config)
		env = acceptanceTestHelpers.NewEnvironment(context)

		env.Setup()
		AsUser(context.AdminUserContext(), 30*time.Second, func() {
			envVarGroups := Cf("set-staging-environment-variable-group", `{}`).Wait(assertionTimeout)
			Expect(envVarGroups).To(Exit(0))

			envVarGroups = Cf("set-running-environment-variable-group", `{}`).Wait(assertionTimeout)
			Expect(envVarGroups).To(Exit(0))
		})
	})

	AfterEach(func() {
		AsUser(context.AdminUserContext(), 30*time.Second, func() {
			envVarGroups := Cf("set-staging-environment-variable-group", `{}`).Wait(assertionTimeout)
			Expect(envVarGroups).To(Exit(0))

			envVarGroups = Cf("set-running-environment-variable-group", `{}`).Wait(assertionTimeout)
			Expect(envVarGroups).To(Exit(0))
			env.Teardown()
		})
	})

	It("returns ann applications running, staging, system provided and user defined environment variables", func() {
		AsUser(context.AdminUserContext(), 60*time.Second, func() {
			stagingVal := fmt.Sprintf("staging-val-%d", time.Now().Nanosecond())
			runningVal := fmt.Sprintf("running-val-%d", time.Now().Nanosecond())
			setEnvVal := fmt.Sprintf("set-env-val-%d", time.Now().Nanosecond())

			ssevgResult := Cf("set-staging-environment-variable-group", fmt.Sprintf(`{"name":"%s"}`, stagingVal)).Wait(assertionTimeout)
			Expect(ssevgResult).To(Exit(0))
			srevgResult := Cf("set-running-environment-variable-group", fmt.Sprintf(`{"name":"%s"}`, runningVal)).Wait(assertionTimeout)
			Expect(srevgResult).To(Exit(0))

			space := context.RegularUserContext().Space
			org := context.RegularUserContext().Org

			target := Cf("target", "-o", org, "-s", space).Wait(assertionTimeout)
			Expect(target.ExitCode()).To(Equal(0))

			appName := generator.RandomName()
			app := Cf("push", appName, "-p", gatsHelpers.NewAssets().ServiceBroker).Wait(appTimeout)
			Expect(app).To(Exit(0))

			setEnvResult := Cf("set-env", appName, "set-env-key", setEnvVal).Wait(assertionTimeout)
			Expect(setEnvResult).To(Exit(0))

			envResult := Cf("env", appName).Wait(assertionTimeout)
			Expect(envResult).To(Exit(0))

			output := envResult.Out.Contents()
			Expect(output).To(ContainSubstring("\"VCAP_APPLICATION\": {"))
			Expect(output).To(ContainSubstring("User-Provided:\nset-env-key: %s", setEnvVal))
			Expect(output).To(ContainSubstring("Running Environment Variable Groups:\nname: %s", runningVal))
			Expect(output).To(ContainSubstring("Staging Environment Variable Groups:\nname: %s", stagingVal))
		})
	})
})
<commit_msg>Revert "use updated values"<commit_after>package application_test

import (
	"fmt"
	"time"

	. "github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/generator"
	acceptanceTestHelpers "github.com/cloudfoundry-incubator/cf-test-helpers/helpers"
	gatsHelpers "github.com/cloudfoundry/cli-acceptance-tests/helpers"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("Env", func() {
	const (
		assertionTimeout = 10 * time.Second
		appTimeout       = 2 * time.Minute
		copyAppTimeout   = 3 * time.Minute
	)

	var (
		context *acceptanceTestHelpers.ConfiguredContext
		env     *acceptanceTestHelpers.Environment
	)

	config := acceptanceTestHelpers.LoadConfig()

	BeforeEach(func() {
		context = acceptanceTestHelpers.NewContext(config)
		env = acceptanceTestHelpers.NewEnvironment(context)

		env.Setup()
		AsUser(context.AdminUserContext(), 30*time.Second, func() {
			envVarGroups := Cf("set-staging-environment-variable-group", `{}`).Wait(assertionTimeout)
			Expect(envVarGroups).To(Exit(0))

			envVarGroups = Cf("set-running-environment-variable-group", `{}`).Wait(assertionTimeout)
			Expect(envVarGroups).To(Exit(0))
		})
	})

	AfterEach(func() {
		AsUser(context.AdminUserContext(), 30*time.Second, func() {
			envVarGroups := Cf("set-staging-environment-variable-group", `{}`).Wait(assertionTimeout)
			Expect(envVarGroups).To(Exit(0))

			envVarGroups = Cf("set-running-environment-variable-group", `{}`).Wait(assertionTimeout)
			Expect(envVarGroups).To(Exit(0))
			env.Teardown()
		})
	})

	It("returns ann applications running, staging, system provided and user defined environment variables", func() {
		AsUser(context.AdminUserContext(), 60*time.Second, func() {
			stagingVal := fmt.Sprintf("staging-val-%d", time.Now().Nanosecond())
			runningVal := fmt.Sprintf("running-val-%d", time.Now().Nanosecond())
			setEnvVal := fmt.Sprintf("set-env-val-%d", time.Now().Nanosecond())

			ssevgResult := Cf("set-staging-environment-variable-group", fmt.Sprintf(`{"name":"%s"}`, stagingVal)).Wait(assertionTimeout)
			Expect(ssevgResult).To(Exit(0))
			srevgResult := Cf("set-running-environment-variable-group", fmt.Sprintf(`{"name":"%s"}`, runningVal)).Wait(assertionTimeout)
			Expect(srevgResult).To(Exit(0))

			space := context.RegularUserContext().Space
			org := context.RegularUserContext().Org

			target := Cf("target", "-o", org, "-s", space).Wait(assertionTimeout)
			Expect(target.ExitCode()).To(Equal(0))

			appName := generator.RandomName()
			app := Cf("push", appName, "-p", gatsHelpers.NewAssets().ServiceBroker).Wait(appTimeout)
			Expect(app).To(Exit(0))

			setEnvResult := Cf("set-env", appName, "set-env-key", setEnvVal).Wait(assertionTimeout)
			Expect(setEnvResult).To(Exit(0))

			envResult := Cf("env", appName).Wait(assertionTimeout)
			Expect(envResult).To(Exit(0))

			output := envResult.Out.Contents()
			Expect(output).To(ContainSubstring("\"VCAP_APPLICATION\": {"))
			Expect(output).To(ContainSubstring("User-Provided:\nset-env-key: set-env-val"))
			Expect(output).To(ContainSubstring("Running Environment Variable Groups:\nname: running-val"))
			Expect(output).To(ContainSubstring("Staging Environment Variable Groups:\nname: staging-val"))
		})
	})
})
<|endoftext|>


<commit_before>package gentleman

// Originally based on grequests: https://github.com/levigross/grequests
// Apache License Version 2.0

import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"io"
	"net/http"
	"os"
	"runtime"

	"gopkg.in/h2non/gentleman.v1/context"
	"gopkg.in/h2non/gentleman.v1/utils"
)

// Response provides a more convenient and higher level Response struct.
// Implements an io.ReadCloser interface.
type Response struct {
	// Ok is a boolean flag that validates that the server returned a 2xx code.
	Ok bool

	// This is the Go error flag – if something went wrong within the request, this flag will be set.
	Error error

	// Sugar to check if the response status code is a client error (4xx).
	ClientError bool

	// Sugar to check if the response status code is a server error (5xx).
	ServerError bool

	// StatusCode is the HTTP Status Code returned by the HTTP Response. Taken from resp.StatusCode.
	StatusCode int

	// Header stores the response headers as http.Header interface.
	Header http.Header

	// Cookies stores the parsed response cookies.
	Cookies []*http.Cookie

	// Expose the native Go http.Response object for convenience.
	RawResponse *http.Response

	// Expose the native Go http.Request object for convenience.
	RawRequest *http.Request

	// Expose original request Context for convenience.
	Context *context.Context

	// Internal buffer store
	buffer *bytes.Buffer
}

func buildResponse(ctx *context.Context) (*Response, error) {
	resp := ctx.Response
	statusRange := int(resp.StatusCode / 100)

	res := &Response{
		// If your code is within the 2xx range – the response is considered `Ok`
		Ok:          statusRange >= 2 && statusRange <= 3,
		Error:       ctx.Error,
		ClientError: statusRange == 4,
		ServerError: statusRange == 5,
		Context:     ctx,
		RawResponse: resp,
		RawRequest:  ctx.Request,
		StatusCode:  resp.StatusCode,
		Header:      resp.Header,
		Cookies:     resp.Cookies(),
		buffer:      bytes.NewBuffer([]byte{}),
	}
	EnsureResponseFinalized(res)

	return res, res.Error
}

// Read is part of our ability to support io.ReadCloser
// if someone wants to make use of the raw body.
func (r *Response) Read(p []byte) (n int, err error) {
	if r.Error != nil {
		return -1, r.Error
	}
	return r.RawResponse.Body.Read(p)
}

// Close is part of our ability to support io.ReadCloser if
// someone wants to make use of the raw body.
func (r *Response) Close() error {
	if r.Error != nil {
		return r.Error
	}
	return r.RawResponse.Body.Close()
}

// SaveToFile allows you to download the contents
// of the response to a file.
func (r *Response) SaveToFile(fileName string) error {
	if r.Error != nil {
		return r.Error
	}

	fd, err := os.Create(fileName)
	if err != nil {
		return err
	}

	defer r.Close() // This is a noop if we use the internal ByteBuffer
	defer fd.Close()

	_, err = io.Copy(fd, r.getInternalReader())
	if err != nil && err != io.EOF {
		return err
	}

	return nil
}

// JSON is a method that will populate a struct that is provided `userStruct`
// with the JSON returned within the response body.
func (r *Response) JSON(userStruct interface{}) error {
	if r.Error != nil {
		return r.Error
	}

	jsonDecoder := json.NewDecoder(r.getInternalReader())
	defer r.Close()

	err := jsonDecoder.Decode(&userStruct)
	if err != nil && err != io.EOF {
		return err
	}

	return nil
}

// XML is a method that will populate a struct that is provided
// `userStruct` with the XML returned within the response body.
func (r *Response) XML(userStruct interface{}, charsetReader utils.XMLCharDecoder) error {
	if r.Error != nil {
		return r.Error
	}

	xmlDecoder := xml.NewDecoder(r.getInternalReader())
	if charsetReader != nil {
		xmlDecoder.CharsetReader = charsetReader
	}

	defer r.Close()
	if err := xmlDecoder.Decode(&userStruct); err != nil && err != io.EOF {
		return err
	}

	return nil
}

// Bytes returns the response as a byte array.
func (r *Response) Bytes() []byte {
	if r.Error != nil {
		return nil
	}

	r.populateResponseByteBuffer()

	// Are we still empty?
	if r.buffer.Len() == 0 {
		return nil
	}
	return r.buffer.Bytes()
}

// String returns the response as a string.
func (r *Response) String() string {
	if r.Error != nil {
		return ""
	}

	r.populateResponseByteBuffer()
	return r.buffer.String()
}

// ClearInternalBuffer is a function that will clear the internal buffer that we
// use to hold the .String() and .Bytes() data.
// Once you have used these functions you may want to free up the memory.
func (r *Response) ClearInternalBuffer() {
	if r.Error != nil {
		return // This is a noop as we will be dereferencing a null pointer
	}
	r.buffer.Reset()
}

// createResponseBytesBuffer is a utility method that will populate
// the internal byte reader – this is largely used for .String() and .Bytes()
func (r *Response) populateResponseByteBuffer() {
	// Have I done this already?
	if r.buffer.Len() != 0 {
		return
	}
	defer r.Close()

	// Is there any content?
	if r.RawResponse.ContentLength == 0 {
		return
	}

	// Did the server tell us how big the response is going to be?
	if r.RawResponse.ContentLength > 0 {
		r.buffer.Grow(int(r.RawResponse.ContentLength))
	}

	_, err := io.Copy(r.buffer, r)
	if err != nil && err != io.EOF {
		r.Error = err
		r.RawResponse.Body.Close()
	}
}

// getInternalReader because we implement io.ReadCloser and
// optionally hold a large buffer of the response (created by
// the user's request).
func (r *Response) getInternalReader() io.Reader {
	if r.buffer.Len() != 0 {
		return r.buffer
	}
	return r
}

// EnsureResponseFinalized will ensure that when the Response is GCed
// the request body is closed so we aren't leaking fds.
func EnsureResponseFinalized(httpResp *Response) {
	runtime.SetFinalizer(&httpResp, func(httpResponseInt **Response) {
		(*httpResponseInt).RawResponse.Body.Close()
	})
}
<commit_msg>Prevents finalizing chunked responses<commit_after>package gentleman

// Originally based on grequests: https://github.com/levigross/grequests
// Apache License Version 2.0

import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"io"
	"net/http"
	"os"
	"runtime"

	"gopkg.in/h2non/gentleman.v1/context"
	"gopkg.in/h2non/gentleman.v1/utils"
)

// Response provides a more convenient and higher level Response struct.
// Implements an io.ReadCloser interface.
type Response struct {
	// Ok is a boolean flag that validates that the server returned a 2xx code.
	Ok bool

	// This is the Go error flag – if something went wrong within the request, this flag will be set.
	Error error

	// Sugar to check if the response status code is a client error (4xx).
	ClientError bool

	// Sugar to check if the response status code is a server error (5xx).
	ServerError bool

	// StatusCode is the HTTP Status Code returned by the HTTP Response. Taken from resp.StatusCode.
	StatusCode int

	// Header stores the response headers as http.Header interface.
	Header http.Header

	// Cookies stores the parsed response cookies.
	Cookies []*http.Cookie

	// Expose the native Go http.Response object for convenience.
	RawResponse *http.Response

	// Expose the native Go http.Request object for convenience.
	RawRequest *http.Request

	// Expose original request Context for convenience.
	Context *context.Context

	// Internal buffer store
	buffer *bytes.Buffer
}

func buildResponse(ctx *context.Context) (*Response, error) {
	resp := ctx.Response
	statusRange := int(resp.StatusCode / 100)

	res := &Response{
		// If your code is within the 2xx range – the response is considered `Ok`
		Ok:          statusRange >= 2 && statusRange <= 3,
		Error:       ctx.Error,
		ClientError: statusRange == 4,
		ServerError: statusRange == 5,
		Context:     ctx,
		RawResponse: resp,
		RawRequest:  ctx.Request,
		StatusCode:  resp.StatusCode,
		Header:      resp.Header,
		Cookies:     resp.Cookies(),
		buffer:      bytes.NewBuffer([]byte{}),
	}
	if !isChunkedResponse(resp) {
		EnsureResponseFinalized(res)
	}

	return res, res.Error
}

// Read is part of our ability to support io.ReadCloser
// if someone wants to make use of the raw body.
func (r *Response) Read(p []byte) (n int, err error) {
	if r.Error != nil {
		return -1, r.Error
	}
	return r.RawResponse.Body.Read(p)
}

// Close is part of our ability to support io.ReadCloser if
// someone wants to make use of the raw body.
func (r *Response) Close() error {
	if r.Error != nil {
		return r.Error
	}
	return r.RawResponse.Body.Close()
}

// SaveToFile allows you to download the contents
// of the response to a file.
func (r *Response) SaveToFile(fileName string) error {
	if r.Error != nil {
		return r.Error
	}

	fd, err := os.Create(fileName)
	if err != nil {
		return err
	}

	defer r.Close() // This is a noop if we use the internal ByteBuffer
	defer fd.Close()

	_, err = io.Copy(fd, r.getInternalReader())
	if err != nil && err != io.EOF {
		return err
	}

	return nil
}

// JSON is a method that will populate a struct that is provided `userStruct`
// with the JSON returned within the response body.
func (r *Response) JSON(userStruct interface{}) error {
	if r.Error != nil {
		return r.Error
	}

	jsonDecoder := json.NewDecoder(r.getInternalReader())
	defer r.Close()

	err := jsonDecoder.Decode(&userStruct)
	if err != nil && err != io.EOF {
		return err
	}

	return nil
}

// XML is a method that will populate a struct that is provided
// `userStruct` with the XML returned within the response body.
func (r *Response) XML(userStruct interface{}, charsetReader utils.XMLCharDecoder) error {
	if r.Error != nil {
		return r.Error
	}

	xmlDecoder := xml.NewDecoder(r.getInternalReader())
	if charsetReader != nil {
		xmlDecoder.CharsetReader = charsetReader
	}

	defer r.Close()
	if err := xmlDecoder.Decode(&userStruct); err != nil && err != io.EOF {
		return err
	}

	return nil
}

// Bytes returns the response as a byte array.
func (r *Response) Bytes() []byte {
	if r.Error != nil {
		return nil
	}

	r.populateResponseByteBuffer()

	// Are we still empty?
	if r.buffer.Len() == 0 {
		return nil
	}
	return r.buffer.Bytes()
}

// String returns the response as a string.
func (r *Response) String() string {
	if r.Error != nil {
		return ""
	}

	r.populateResponseByteBuffer()
	return r.buffer.String()
}

// ClearInternalBuffer is a function that will clear the internal buffer that we
// use to hold the .String() and .Bytes() data.
// Once you have used these functions you may want to free up the memory.
func (r *Response) ClearInternalBuffer() {
	if r.Error != nil {
		return // This is a noop as we will be dereferencing a null pointer
	}
	r.buffer.Reset()
}

// createResponseBytesBuffer is a utility method that will populate
// the internal byte reader – this is largely used for .String() and .Bytes()
func (r *Response) populateResponseByteBuffer() {
	// Have I done this already?
	if r.buffer.Len() != 0 {
		return
	}
	defer r.Close()

	// Is there any content?
	if r.RawResponse.ContentLength == 0 {
		return
	}

	// Did the server tell us how big the response is going to be?
	if r.RawResponse.ContentLength > 0 {
		r.buffer.Grow(int(r.RawResponse.ContentLength))
	}

	_, err := io.Copy(r.buffer, r)
	if err != nil && err != io.EOF {
		r.Error = err
		r.RawResponse.Body.Close()
	}
}

// getInternalReader because we implement io.ReadCloser and
// optionally hold a large buffer of the response (created by
// the user's request).
func (r *Response) getInternalReader() io.Reader {
	if r.buffer.Len() != 0 {
		return r.buffer
	}
	return r
}

// EnsureResponseFinalized will ensure that when the Response is GCed
// the request body is closed so we aren't leaking fds.
func EnsureResponseFinalized(httpResp *Response) {
	runtime.SetFinalizer(&httpResp, func(httpResponseInt **Response) {
		(*httpResponseInt).RawResponse.Body.Close()
	})
}

// isChunkedResponse iterates over the response's transfer encodings
// and returns either true whether 'chunked' is found, or false, otherwise.
func isChunkedResponse(res *http.Response) bool {
	for _, te := range res.TransferEncoding {
		if te == "chunked" {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package generates_test

import (
	"fmt"
	"testing"
	"time"

	"github.com/dgrijalva/jwt-go"

	"gopkg.in/oauth2.v3"
	"gopkg.in/oauth2.v3/generates"
	"gopkg.in/oauth2.v3/models"

	. "github.com/smartystreets/goconvey/convey"
)

func TestJWTAccess(t *testing.T) {
	Convey("Test JWT Access Generate", t, func() {
		data := &oauth2.GenerateBasic{
			Client: &models.Client{
				ID:     "123456",
				Secret: "123456",
			},
			UserID: "000000",
			TokenInfo: &models.Token{
				AccessCreateAt:  time.Now(),
				AccessExpiresIn: time.Second * 120,
			},
		}

		gen := generates.NewJWTAccessGenerate([]byte("00000000"), jwt.SigningMethodHS512)
		access, refresh, err := gen.Token(data, true)
		So(err, ShouldBeNil)
		So(access, ShouldNotBeEmpty)
		So(refresh, ShouldNotBeEmpty)

		token, err := jwt.ParseWithClaims(access, &generates.JWTAccessClaims{}, func(t *jwt.Token) (interface{}, error) {
			if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
				return nil, fmt.Errorf("parse error")
			}
			return []byte("00000000"), nil
		})
		So(err, ShouldBeNil)

		claims, ok := token.Claims.(*generates.JWTAccessClaims)
		So(ok, ShouldBeTrue)
		So(token.Valid, ShouldBeTrue)
		So(claims.ClientID, ShouldEqual, "123456")
		So(claims.UserID, ShouldEqual, "000000")
	})
}
<commit_msg>Fixed jwt test<commit_after>package generates_test

import (
	"fmt"
	"testing"
	"time"

	"github.com/dgrijalva/jwt-go"
	"gopkg.in/oauth2.v3"
	"gopkg.in/oauth2.v3/generates"
	"gopkg.in/oauth2.v3/models"

	. "github.com/smartystreets/goconvey/convey"
)

func TestJWTAccess(t *testing.T) {
	Convey("Test JWT Access Generate", t, func() {
		data := &oauth2.GenerateBasic{
			Client: &models.Client{
				ID:     "123456",
				Secret: "123456",
			},
			UserID: "000000",
			TokenInfo: &models.Token{
				AccessCreateAt:  time.Now(),
				AccessExpiresIn: time.Second * 120,
			},
		}

		gen := generates.NewJWTAccessGenerate([]byte("00000000"), jwt.SigningMethodHS512)
		access, refresh, err := gen.Token(data, true)
		So(err, ShouldBeNil)
		So(access, ShouldNotBeEmpty)
		So(refresh, ShouldNotBeEmpty)

		token, err := jwt.ParseWithClaims(access, &generates.JWTAccessClaims{}, func(t *jwt.Token) (interface{}, error) {
			if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
				return nil, fmt.Errorf("parse error")
			}
			return []byte("00000000"), nil
		})
		So(err, ShouldBeNil)

		claims, ok := token.Claims.(*generates.JWTAccessClaims)
		So(ok, ShouldBeTrue)
		So(token.Valid, ShouldBeTrue)
		So(claims.Audience, ShouldEqual, "123456")
		So(claims.Subject, ShouldEqual, "000000")
	})
}
<|endoftext|>


<commit_before>package errors

import (
	"bytes"
	"fmt"
	"io"
	"runtime/debug"
	"testing"
)

func TestStackFormatMatches(t *testing.T) {

	defer func() {
		err := recover()
		if err != 'a' {
			t.Fatal(err)
		}

		bs := [][]byte{Errorf("hi").Stack(), debug.Stack()}

		// Ignore the first line (as it contains the PC of the .Stack() call)
		bs[0] = bytes.SplitN(bs[0], []byte("\n"), 2)[1]
		bs[1] = bytes.SplitN(bs[1], []byte("\n"), 2)[1]

		if bytes.Compare(bs[0], bs[1]) != 0 {
			t.Errorf("Stack didn't match")
			t.Errorf("%s", bs[0])
			t.Errorf("%s", bs[1])
		}
	}()

	a()
}

func TestSkipWorks(t *testing.T) {

	defer func() {
		err := recover()
		if err != 'a' {
			t.Fatal(err)
		}

		bs := [][]byte{New("hi", 2).Stack(), debug.Stack()}

		// should skip four lines of debug.Stack()
		bs[1] = bytes.SplitN(bs[1], []byte("\n"), 5)[4]

		if bytes.Compare(bs[0], bs[1]) != 0 {
			t.Errorf("Stack didn't match")
			t.Errorf("%s", bs[0])
			t.Errorf("%s", bs[1])
		}
	}()

	a()
}

func TestNewError(t *testing.T) {

	e := func() error {
		return New("hi", 1)
	}()

	if e.Error() != "hi" {
		t.Errorf("Constructor with a string failed")
	}

	if New(fmt.Errorf("yo"), 0).Error() != "yo" {
		t.Errorf("Constructor with an error failed")
	}

	if New(e, 0) != e {
		t.Errorf("Constructor with an Error failed")
	}

	if New(nil, 0).Error() != "<nil>" {
		t.Errorf("Constructor with nil failed")
	}
}

func ExampleErrorf(x int) (int, error) {
	if x%2 == 1 {
		return 0, Errorf("can only halve even numbers, got %d", x)
	}
	return x / 2, nil
}

func ExampleNewError() (error, error) {
	// Wrap io.EOF with the current stack-trace and return it
	return nil, New(io.EOF, 0)
}

func ExampleNewError_skip() {
	defer func() {
		if err := recover(); err != nil {
			// skip 1 frame (the deferred function) and then return the wrapped err
			err = New(err, 1)
		}
	}()
}

func ExampleError_Stack(err Error) {
	fmt.Printf("Error: %s\n%s", err.Error(), err.Stack())
}

func a() error {
	b(5)
	return nil
}

func b(i int) {
	c()
}

func c() {
	panic('a')
}
<commit_msg>try again<commit_after>package errors

import (
	"bytes"
	"fmt"
	"io"
	"runtime/debug"
	"testing"
)

func TestStackFormatMatches(t *testing.T) {

	defer func() {
		err := recover()
		if err != 'a' {
			t.Fatal(err)
		}

		bs := [][]byte{Errorf("hi").Stack(), debug.Stack()}

		// Ignore the first line (as it contains the PC of the .Stack() call)
		bs[0] = bytes.SplitN(bs[0], []byte("\n"), 2)[1]
		bs[1] = bytes.SplitN(bs[1], []byte("\n"), 2)[1]

		if bytes.Compare(bs[0], bs[1]) != 0 {
			t.Errorf("Stack didn't match")
			t.Errorf("%s", bs[0])
			t.Errorf("%s", bs[1])
		}
	}()

	a()
}

func TestSkipWorks(t *testing.T) {

	defer func() {
		err := recover()
		if err != 'a' {
			t.Fatal(err)
		}

		bs := [][]byte{New("hi", 2).Stack(), debug.Stack()}

		if !bytes.HasSuffix(bs[1], bs[0]) {
			t.Errorf("Stack didn't match")
			t.Errorf("%s", bs[0])
			t.Errorf("%s", bs[1])
		}
	}()

	a()
}

func TestNewError(t *testing.T) {

	e := func() error {
		return New("hi", 1)
	}()

	if e.Error() != "hi" {
		t.Errorf("Constructor with a string failed")
	}

	if New(fmt.Errorf("yo"), 0).Error() != "yo" {
		t.Errorf("Constructor with an error failed")
	}

	if New(e, 0) != e {
		t.Errorf("Constructor with an Error failed")
	}

	if New(nil, 0).Error() != "<nil>" {
		t.Errorf("Constructor with nil failed")
	}
}

func ExampleErrorf(x int) (int, error) {
	if x%2 == 1 {
		return 0, Errorf("can only halve even numbers, got %d", x)
	}
	return x / 2, nil
}

func ExampleNewError() (error, error) {
	// Wrap io.EOF with the current stack-trace and return it
	return nil, New(io.EOF, 0)
}

func ExampleNewError_skip() {
	defer func() {
		if err := recover(); err != nil {
			// skip 1 frame (the deferred function) and then return the wrapped err
			err = New(err, 1)
		}
	}()
}

func ExampleError_Stack(err Error) {
	fmt.Printf("Error: %s\n%s", err.Error(), err.Stack())
}

func a() error {
	b(5)
	return nil
}

func b(i int) {
	c()
}

func c() {
	panic('a')
}
<|endoftext|>


<commit_before><commit_msg>Added extra check such we skip volume backup only ResourcType is not empty and does not contain PVC in it<commit_after><|endoftext|>


<commit_before>package client

import (
	"bytes"
	"crypto/tls"
	"net/http"
	"net/url"
	"os"

	"github.com/apex/log"
	"github.com/google/go-github/github"
	"github.com/goreleaser/goreleaser/internal/tmpl"
	"github.com/goreleaser/goreleaser/pkg/config"
	"github.com/goreleaser/goreleaser/pkg/context"
	"golang.org/x/oauth2"
)

type githubClient struct {
	client *github.Client
}

// NewGitHub returns a github client implementation
func NewGitHub(ctx *context.Context) (Client, error) {
	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: ctx.Token},
	)
	httpClient := oauth2.NewClient(ctx, ts)
	base := httpClient.Transport.(*oauth2.Transport).Base
	if &base != nil {
		base = http.DefaultTransport
	}
	base.(*http.Transport).TLSClientConfig = &tls.Config{
		InsecureSkipVerify: ctx.Config.GitHubURLs.SkipTLSVerify,
	}
	httpClient.Transport.(*oauth2.Transport).Base = base
	client := github.NewClient(httpClient)
	if ctx.Config.GitHubURLs.API != "" {
		api, err := url.Parse(ctx.Config.GitHubURLs.API)
		if err != nil {
			return &githubClient{}, err
		}
		upload, err := url.Parse(ctx.Config.GitHubURLs.Upload)
		if err != nil {
			return &githubClient{}, err
		}
		client.BaseURL = api
		client.UploadURL = upload
	}

	return &githubClient{client: client}, nil
}

func (c *githubClient) CreateFile(
	ctx *context.Context,
	commitAuthor config.CommitAuthor,
	repo config.Repo,
	content bytes.Buffer,
	path string,
	message string,
) error {
	options := &github.RepositoryContentFileOptions{
		Committer: &github.CommitAuthor{
			Name:  github.String(commitAuthor.Name),
			Email: github.String(commitAuthor.Email),
		},
		Content: content.Bytes(),
		Message: github.String(message),
	}

	file, _, res, err := c.client.Repositories.GetContents(
		ctx,
		repo.Owner,
		repo.Name,
		path,
		&github.RepositoryContentGetOptions{},
	)
	if err != nil && res.StatusCode != 404 {
		return err
	}

	if res.StatusCode == 404 {
		_, _, err = c.client.Repositories.CreateFile(
			ctx,
			repo.Owner,
			repo.Name,
			path,
			options,
		)
		return err
	}
	options.SHA = file.SHA
	_, _, err = c.client.Repositories.UpdateFile(
		ctx,
		repo.Owner,
		repo.Name,
		path,
		options,
	)
	return err
}

func (c *githubClient) CreateRelease(ctx *context.Context, body string) (int64, error) {
	var release *github.RepositoryRelease
	title, err := tmpl.New(ctx).Apply(ctx.Config.Release.NameTemplate)
	if err != nil {
		return 0, err
	}

	var data = &github.RepositoryRelease{
		Name:       github.String(title),
		TagName:    github.String(ctx.Git.CurrentTag),
		Body:       github.String(body),
		Draft:      github.Bool(ctx.Config.Release.Draft),
		Prerelease: github.Bool(ctx.PreRelease),
	}
	release, _, err = c.client.Repositories.GetReleaseByTag(
		ctx,
		ctx.Config.Release.GitHub.Owner,
		ctx.Config.Release.GitHub.Name,
		ctx.Git.CurrentTag,
	)
	if err != nil {
		release, _, err = c.client.Repositories.CreateRelease(
			ctx,
			ctx.Config.Release.GitHub.Owner,
			ctx.Config.Release.GitHub.Name,
			data,
		)
	} else {
		release, _, err = c.client.Repositories.EditRelease(
			ctx,
			ctx.Config.Release.GitHub.Owner,
			ctx.Config.Release.GitHub.Name,
			release.GetID(),
			data,
		)
	}
	log.WithField("url", release.GetHTMLURL()).Info("release updated")
	return release.GetID(), err
}

func (c *githubClient) Upload(
	ctx *context.Context,
	releaseID int64,
	name string,
	file *os.File,
) error {
	_, _, err := c.client.Repositories.UploadReleaseAsset(
		ctx,
		ctx.Config.Release.GitHub.Owner,
		ctx.Config.Release.GitHub.Name,
		releaseID,
		&github.UploadOptions{
			Name: name,
		},
		file,
	)
	return err
}
<commit_msg>fix: lint<commit_after>package client

import (
	"bytes"
	"crypto/tls"
	"net/http"
	"net/url"
	"os"

	"github.com/apex/log"
	"github.com/google/go-github/github"
	"github.com/goreleaser/goreleaser/internal/tmpl"
	"github.com/goreleaser/goreleaser/pkg/config"
	"github.com/goreleaser/goreleaser/pkg/context"
	"golang.org/x/oauth2"
)

type githubClient struct {
	client *github.Client
}

// NewGitHub returns a github client implementation
func NewGitHub(ctx *context.Context) (Client, error) {
	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: ctx.Token},
	)
	httpClient := oauth2.NewClient(ctx, ts)
	base := httpClient.Transport.(*oauth2.Transport).Base
	if &base != nil {
		base = http.DefaultTransport
	}
	// nolint: gosec
	base.(*http.Transport).TLSClientConfig = &tls.Config{
		InsecureSkipVerify: ctx.Config.GitHubURLs.SkipTLSVerify,
	}
	httpClient.Transport.(*oauth2.Transport).Base = base
	client := github.NewClient(httpClient)
	if ctx.Config.GitHubURLs.API != "" {
		api, err := url.Parse(ctx.Config.GitHubURLs.API)
		if err != nil {
			return &githubClient{}, err
		}
		upload, err := url.Parse(ctx.Config.GitHubURLs.Upload)
		if err != nil {
			return &githubClient{}, err
		}
		client.BaseURL = api
		client.UploadURL = upload
	}

	return &githubClient{client: client}, nil
}

func (c *githubClient) CreateFile(
	ctx *context.Context,
	commitAuthor config.CommitAuthor,
	repo config.Repo,
	content bytes.Buffer,
	path string,
	message string,
) error {
	options := &github.RepositoryContentFileOptions{
		Committer: &github.CommitAuthor{
			Name:  github.String(commitAuthor.Name),
			Email: github.String(commitAuthor.Email),
		},
		Content: content.Bytes(),
		Message: github.String(message),
	}

	file, _, res, err := c.client.Repositories.GetContents(
		ctx,
		repo.Owner,
		repo.Name,
		path,
		&github.RepositoryContentGetOptions{},
	)
	if err != nil && res.StatusCode != 404 {
		return err
	}

	if res.StatusCode == 404 {
		_, _, err = c.client.Repositories.CreateFile(
			ctx,
			repo.Owner,
			repo.Name,
			path,
			options,
		)
		return err
	}
	options.SHA = file.SHA
	_, _, err = c.client.Repositories.UpdateFile(
		ctx,
		repo.Owner,
		repo.Name,
		path,
		options,
	)
	return err
}

func (c *githubClient) CreateRelease(ctx *context.Context, body string) (int64, error) {
	var release *github.RepositoryRelease
	title, err := tmpl.New(ctx).Apply(ctx.Config.Release.NameTemplate)
	if err != nil {
		return 0, err
	}

	var data = &github.RepositoryRelease{
		Name:       github.String(title),
		TagName:    github.String(ctx.Git.CurrentTag),
		Body:       github.String(body),
		Draft:      github.Bool(ctx.Config.Release.Draft),
		Prerelease: github.Bool(ctx.PreRelease),
	}
	release, _, err = c.client.Repositories.GetReleaseByTag(
		ctx,
		ctx.Config.Release.GitHub.Owner,
		ctx.Config.Release.GitHub.Name,
		ctx.Git.CurrentTag,
	)
	if err != nil {
		release, _, err = c.client.Repositories.CreateRelease(
			ctx,
			ctx.Config.Release.GitHub.Owner,
			ctx.Config.Release.GitHub.Name,
			data,
		)
	} else {
		release, _, err = c.client.Repositories.EditRelease(
			ctx,
			ctx.Config.Release.GitHub.Owner,
			ctx.Config.Release.GitHub.Name,
			release.GetID(),
			data,
		)
	}
	log.WithField("url", release.GetHTMLURL()).Info("release updated")
	return release.GetID(), err
}

func (c *githubClient) Upload(
	ctx *context.Context,
	releaseID int64,
	name string,
	file *os.File,
) error {
	_, _, err := c.client.Repositories.UploadReleaseAsset(
		ctx,
		ctx.Config.Release.GitHub.Owner,
		ctx.Config.Release.GitHub.Name,
		releaseID,
		&github.UploadOptions{
			Name: name,
		},
		file,
	)
	return err
}
<|endoftext|>


<commit_before>package config

import (
	"io/ioutil"
	"path"
	"strings"
	"sync/atomic"
	"unsafe"

	"github.com/kelseyhightower/envconfig"
	"github.com/pkg/errors"
	"gopkg.in/yaml.v2"
)

// prefix is used as a namespace identifier for environment variables.
const prefix = "toglacier"

var config unsafe.Pointer

// Config stores all the necessary information to send backups to the cloud and
// keep track in the local storage.
type Config struct {
	Paths        []string `yaml:"paths" envconfig:"paths"`
	AuditFile    string   `yaml:"audit file" envconfig:"audit"`
	KeepBackups  int      `yaml:"keep backups" envconfig:"keep_backups"`
	BackupSecret aesKey   `yaml:"backup secret" envconfig:"backup_secret"`

	Email struct {
		Server   string    `yaml:"server" envconfig:"server"`
		Port     int       `yaml:"port" envconfig:"port"`
		Username string    `yaml:"username" envconfig:"username"`
		Password encrypted `yaml:"password" envconfig:"password"`
		From     string    `yaml:"from" envconfig:"from"`
		To       []string  `yaml:"to" envconfig:"to"`
	} `yaml:"email" envconfig:"email"`

	AWS struct {
		AccountID       encrypted `yaml:"account id" envconfig:"account_id"`
		AccessKeyID     encrypted `yaml:"access key id" envconfig:"access_key_id"`
		SecretAccessKey encrypted `yaml:"secret access key" envconfig:"secret_access_key"`
		Region          string    `yaml:"region" envconfig:"region"`
		VaultName       string    `yaml:"vault name" envconfig:"vault_name"`
	} `yaml:"aws" envconfig:"aws"`
}

// Current return the actual system configuration, stored internally in a global
// variable.
func Current() *Config {
	return (*Config)(atomic.LoadPointer(&config))
}

// Update modify the current system configuration.
func Update(c *Config) {
	atomic.StorePointer(&config, unsafe.Pointer(c))
}

// Default defines all default configuration values.
func Default() {
	c := Current()
	if c == nil {
		c = new(Config)
	}

	c.AuditFile = path.Join("var", "log", "toglacier", "audit.log")
	c.KeepBackups = 10

	Update(c)
}

// LoadFromFile parse an YAML file and fill the system configuration parameters.
// On error it will return an ConfigError encapsulated in a traceable error. To
// retrieve the desired error you can do:
//
//     type causer interface {
//       Cause() error
//     }
//
//     if causeErr, ok := err.(causer); ok {
//       switch specificErr := causeErr.Cause().(type) {
//       case ConfigError:
//         // handle specifically
//       default:
//         // unknown error
//       }
//     }
func LoadFromFile(filename string) error {
	content, err := ioutil.ReadFile(filename)
	if err != nil {
		return errors.WithStack(newConfigError(filename, ConfigErrorCodeReadingFile, err))
	}

	c := Current()
	if c == nil {
		c = new(Config)
	}

	if err = yaml.Unmarshal(content, c); err != nil {
		return errors.WithStack(newConfigError(filename, ConfigErrorCodeParsingYAML, err))
	}

	Update(c)
	return nil
}

// LoadFromEnvironment analysis all project environment variables. On error it
// will return an ConfigError encapsulated in a traceable error. To retrieve
// the desired error you can do:
//
//     type causer interface {
//       Cause() error
//     }
//
//     if causeErr, ok := err.(causer); ok {
//       switch specificErr := causeErr.Cause().(type) {
//       case ConfigError:
//         // handle specifically
//       default:
//         // unknown error
//       }
//     }
func LoadFromEnvironment() error {
	c := Current()
	if c == nil {
		c = new(Config)
	}

	if err := envconfig.Process(prefix, c); err != nil {
		return errors.WithStack(newConfigError("", ConfigErrorCodeReadingEnvVars, err))
	}

	Update(c)
	return nil
}

type encrypted struct {
	Value string
}

// UnmarshalText automatically decrypts a value from the configuration. On error
// it will return an ConfigError encapsulated in a traceable error. To retrieve
// the desired error you can do:
//
//     type causer interface {
//       Cause() error
//     }
//
//     if causeErr, ok := err.(causer); ok {
//       switch specificErr := causeErr.Cause().(type) {
//       case ConfigError:
//         // handle specifically
//       default:
//         // unknown error
//       }
//     }
func (e *encrypted) UnmarshalText(value []byte) error {
	e.Value = string(value)

	if strings.HasPrefix(e.Value, "encrypted:") {
		var err error
		if e.Value, err = passwordDecrypt(strings.TrimPrefix(e.Value, "encrypted:")); err != nil {
			return errors.WithStack(err)
		}
	}

	return nil
}

type aesKey struct {
	encrypted
}

// UnmarshalText automatically decrypts a value from the configuration. On error
// it will return an ConfigError encapsulated in a traceable error. To retrieve
// the desired error you can do:
//
//     type causer interface {
//       Cause() error
//     }
//
//     if causeErr, ok := err.(causer); ok {
//       switch specificErr := causeErr.Cause().(type) {
//       case ConfigError:
//         // handle specifically
//       default:
//         // unknown error
//       }
//     }
func (a *aesKey) UnmarshalText(value []byte) error {
	if err := a.encrypted.UnmarshalText(value); err != nil {
		return errors.WithStack(err)
	}

	// The key argument should be the AES key, either 16, 24, or 32 bytes to
	// select AES-128, AES-192, or AES-256. We will always force AES-256.
	if a.Value != "" {
		if len(a.Value) < 32 {
			a.Value = a.Value + strings.Repeat("0", 32-len(a.Value))
		} else if len(a.Value) > 32 {
			a.Value = a.Value[:32]
		}
	}

	return nil
}
<commit_msg>Fix typo<commit_after>package config

import (
	"io/ioutil"
	"path"
	"strings"
	"sync/atomic"
	"unsafe"

	"github.com/kelseyhightower/envconfig"
	"github.com/pkg/errors"
	"gopkg.in/yaml.v2"
)

// prefix is used as a namespace identifier for environment variables.
const prefix = "toglacier"

var config unsafe.Pointer

// Config stores all the necessary information to send backups to the cloud and
// keep track in the local storage.
type Config struct {
	Paths        []string `yaml:"paths" envconfig:"paths"`
	AuditFile    string   `yaml:"audit file" envconfig:"audit"`
	KeepBackups  int      `yaml:"keep backups" envconfig:"keep_backups"`
	BackupSecret aesKey   `yaml:"backup secret" envconfig:"backup_secret"`

	Email struct {
		Server   string    `yaml:"server" envconfig:"server"`
		Port     int       `yaml:"port" envconfig:"port"`
		Username string    `yaml:"username" envconfig:"username"`
		Password encrypted `yaml:"password" envconfig:"password"`
		From     string    `yaml:"from" envconfig:"from"`
		To       []string  `yaml:"to" envconfig:"to"`
	} `yaml:"email" envconfig:"email"`

	AWS struct {
		AccountID       encrypted `yaml:"account id" envconfig:"account_id"`
		AccessKeyID     encrypted `yaml:"access key id" envconfig:"access_key_id"`
		SecretAccessKey encrypted `yaml:"secret access key" envconfig:"secret_access_key"`
		Region          string    `yaml:"region" envconfig:"region"`
		VaultName       string    `yaml:"vault name" envconfig:"vault_name"`
	} `yaml:"aws" envconfig:"aws"`
}

// Current return the actual system configuration, stored internally in a global
// variable.
func Current() *Config {
	return (*Config)(atomic.LoadPointer(&config))
}

// Update modify the current system configuration.
func Update(c *Config) {
	atomic.StorePointer(&config, unsafe.Pointer(c))
}

// Default defines all default configuration values.
func Default() {
	c := Current()
	if c == nil {
		c = new(Config)
	}

	c.AuditFile = path.Join("var", "log", "toglacier", "audit.log")
	c.KeepBackups = 10

	Update(c)
}

// LoadFromFile parse an YAML file and fill the system configuration parameters.
// On error it will return a ConfigError encapsulated in a traceable error. To
// retrieve the desired error you can do:
//
//     type causer interface {
//       Cause() error
//     }
//
//     if causeErr, ok := err.(causer); ok {
//       switch specificErr := causeErr.Cause().(type) {
//       case ConfigError:
//         // handle specifically
//       default:
//         // unknown error
//       }
//     }
func LoadFromFile(filename string) error {
	content, err := ioutil.ReadFile(filename)
	if err != nil {
		return errors.WithStack(newConfigError(filename, ConfigErrorCodeReadingFile, err))
	}

	c := Current()
	if c == nil {
		c = new(Config)
	}

	if err = yaml.Unmarshal(content, c); err != nil {
		return errors.WithStack(newConfigError(filename, ConfigErrorCodeParsingYAML, err))
	}

	Update(c)
	return nil
}

// LoadFromEnvironment analysis all project environment variables. On error it
// will return a ConfigError encapsulated in a traceable error. To retrieve
// the desired error you can do:
//
//     type causer interface {
//       Cause() error
//     }
//
//     if causeErr, ok := err.(causer); ok {
//       switch specificErr := causeErr.Cause().(type) {
//       case ConfigError:
//         // handle specifically
//       default:
//         // unknown error
//       }
//     }
func LoadFromEnvironment() error {
	c := Current()
	if c == nil {
		c = new(Config)
	}

	if err := envconfig.Process(prefix, c); err != nil {
		return errors.WithStack(newConfigError("", ConfigErrorCodeReadingEnvVars, err))
	}

	Update(c)
	return nil
}

type encrypted struct {
	Value string
}

// UnmarshalText automatically decrypts a value from the configuration. On error
// it will return a ConfigError encapsulated in a traceable error. To retrieve
// the desired error you can do:
//
//     type causer interface {
//       Cause() error
//     }
//
//     if causeErr, ok := err.(causer); ok {
//       switch specificErr := causeErr.Cause().(type) {
//       case ConfigError:
//         // handle specifically
//       default:
//         // unknown error
//       }
//     }
func (e *encrypted) UnmarshalText(value []byte) error {
	e.Value = string(value)

	if strings.HasPrefix(e.Value, "encrypted:") {
		var err error
		if e.Value, err = passwordDecrypt(strings.TrimPrefix(e.Value, "encrypted:")); err != nil {
			return errors.WithStack(err)
		}
	}

	return nil
}

type aesKey struct {
	encrypted
}

// UnmarshalText automatically decrypts a value from the configuration. On error
// it will return a ConfigError encapsulated in a traceable error. To retrieve
// the desired error you can do:
//
//     type causer interface {
//       Cause() error
//     }
//
//     if causeErr, ok := err.(causer); ok {
//       switch specificErr := causeErr.Cause().(type) {
//       case ConfigError:
//         // handle specifically
//       default:
//         // unknown error
//       }
//     }
func (a *aesKey) UnmarshalText(value []byte) error {
	if err := a.encrypted.UnmarshalText(value); err != nil {
		return errors.WithStack(err)
	}

	// The key argument should be the AES key, either 16, 24, or 32 bytes to
	// select AES-128, AES-192, or AES-256. We will always force AES-256.
	if a.Value != "" {
		if len(a.Value) < 32 {
			a.Value = a.Value + strings.Repeat("0", 32-len(a.Value))
		} else if len(a.Value) > 32 {
			a.Value = a.Value[:32]
		}
	}

	return nil
}
<|endoftext|>