<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package resumer_test

import (
	stdtesting "testing"
	"time"

	. "launchpad.net/gocheck"
	"launchpad.net/juju-core/juju/testing"
	coretesting "launchpad.net/juju-core/testing"
	"launchpad.net/juju-core/worker/resumer"
)

func TestPackage(t *stdtesting.T) {
	coretesting.MgoTestPackage(t)
}

type ResumerSuite struct {
	testing.JujuConnSuite
}

var _ = Suite(&ResumerSuite{})

func (s *ResumerSuite) TestRunStopWithState(c *C) {
	// Test with state ensures that state fulfills the
	// TransactionResumer interface.
	rr := resumer.NewResumer(s.State)

	c.Assert(rr.Stop(), IsNil)
}

func (s *ResumerSuite) TestResumerCalls(c *C) {
	// Shorter interval and mock help to count
	// the resumer calls in a given timespan.
	resumer.SetInterval(10 * time.Millisecond)
	defer resumer.RestoreInterval()

	tr := &transactionResumerMock{0}
	rr := resumer.NewResumer(tr)
	defer func() { c.Assert(rr.Stop(), IsNil) }()

	time.Sleep(55 * time.Millisecond)
	c.Assert(tr.counter, Equals, 5)
}

// transactionResumerMock is used to check the
// calls of ResumeTransactions().
type transactionResumerMock struct {
	counter int
}

func (t *transactionResumerMock) ResumeTransactions() error {
	t.counter++
	return nil
}
<commit_msg>[r=themue] resumer: fix test race<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package resumer_test

import (
	stdtesting "testing"
	"time"

	. "launchpad.net/gocheck"
	"launchpad.net/juju-core/juju/testing"
	coretesting "launchpad.net/juju-core/testing"
	"launchpad.net/juju-core/worker/resumer"
)

func TestPackage(t *stdtesting.T) {
	coretesting.MgoTestPackage(t)
}

type ResumerSuite struct {
	testing.JujuConnSuite
}

var _ = Suite(&ResumerSuite{})

func (s *ResumerSuite) TestRunStopWithState(c *C) {
	// Test with state ensures that state fulfills the
	// TransactionResumer interface.
	rr := resumer.NewResumer(s.State)

	c.Assert(rr.Stop(), IsNil)
}

func (s *ResumerSuite) TestResumerCalls(c *C) {
	// Shorter interval and mock help to count
	// the resumer calls in a given timespan.
	testInterval := 10 * time.Millisecond
	resumer.SetInterval(testInterval)
	defer resumer.RestoreInterval()

	tr := &transactionResumerMock{[]time.Time{}}
	rr := resumer.NewResumer(tr)
	defer func() { c.Assert(rr.Stop(), IsNil) }()

	time.Sleep(10 * testInterval)

	// Check that a numner of calls has happened with a time
	// difference somewhere between the interval and twice the
	// interval. A more precise time behavior cannot be
	// specified due to the load during the test.
	c.Assert(len(tr.timestamps) > 0, Equals, true)
	for i := 1; i < len(tr.timestamps); i++ {
		diff := tr.timestamps[i].Sub(tr.timestamps[i-1])

		c.Assert(diff >= testInterval, Equals, true)
		c.Assert(diff <= 2*testInterval, Equals, true)
	}
}

// transactionResumerMock is used to check the
// calls of ResumeTransactions().
type transactionResumerMock struct {
	timestamps []time.Time
}

func (tr *transactionResumerMock) ResumeTransactions() error {
	tr.timestamps = append(tr.timestamps, time.Now())
	return nil
}
<|endoftext|>


<commit_before>package stripe

import "encoding/json"

// EphemeralKeyParams is the set of parameters that can be used when creating
// an ephemeral key.
// For more details see https://stripe.com/docs/api#ephemeral_keys.
type EphemeralKeyParams struct {
	Params        `form:"*"`
	Customer      *string `form:"customer"`
	IssuingCard   *string `form:"issuing_card"`
	StripeVersion *string `form:"-"` // This goes in the `Stripe-Version` header
}

// EphemeralKey is the resource representing a Stripe ephemeral key.
// For more details see https://stripe.com/docs/api#ephemeral_keys.
type EphemeralKey struct {
	AssociatedObjects []struct {
		ID   string `json:"id"`
		Type string `json:"type"`
	} `json:"associated_objects"`

	Created  int64  `json:"created"`
	Expires  int64  `json:"expires"`
	ID       string `json:"id"`
	Livemode bool   `json:"livemode"`

	// RawJSON is provided so that it may be passed back to the frontend
	// unchanged.  Ephemeral keys are issued on behalf of another client which
	// may be running a different version of the bindings and thus expect a
	// different JSON structure.  This ensures that if the structure differs
	// from the version of these bindings, we can still pass back a compatible
	// key.
	RawJSON []byte `json:"-"`
}

// UnmarshalJSON handles deserialization of an EphemeralKey.
// This custom unmarshaling is needed because we need to store the
// raw JSON on the object so it may be passed back to the frontend.
func (e *EphemeralKey) UnmarshalJSON(data []byte) error {
	type ephemeralKey EphemeralKey
	var ee ephemeralKey
	err := json.Unmarshal(data, &ee)
	if err == nil {
		*e = EphemeralKey(ee)
	}

	e.RawJSON = data

	return nil
}
<commit_msg>Improve docs for ephemeral keys<commit_after>package stripe

import "encoding/json"

// EphemeralKeyParams is the set of parameters that can be used when creating
// an ephemeral key.
type EphemeralKeyParams struct {
	Params        `form:"*"`
	Customer      *string `form:"customer"`
	IssuingCard   *string `form:"issuing_card"`
	StripeVersion *string `form:"-"` // This goes in the `Stripe-Version` header
}

// EphemeralKey is the resource representing a Stripe ephemeral key. This is used by Mobile SDKs
// to for example manage a Customer's payment methods.
type EphemeralKey struct {
	AssociatedObjects []struct {
		ID   string `json:"id"`
		Type string `json:"type"`
	} `json:"associated_objects"`

	Created  int64  `json:"created"`
	Expires  int64  `json:"expires"`
	ID       string `json:"id"`
	Livemode bool   `json:"livemode"`

	// RawJSON is provided so that it may be passed back to the frontend
	// unchanged.  Ephemeral keys are issued on behalf of another client which
	// may be running a different version of the bindings and thus expect a
	// different JSON structure.  This ensures that if the structure differs
	// from the version of these bindings, we can still pass back a compatible
	// key.
	RawJSON []byte `json:"-"`
}

// UnmarshalJSON handles deserialization of an EphemeralKey.
// This custom unmarshaling is needed because we need to store the
// raw JSON on the object so it may be passed back to the frontend.
func (e *EphemeralKey) UnmarshalJSON(data []byte) error {
	type ephemeralKey EphemeralKey
	var ee ephemeralKey
	err := json.Unmarshal(data, &ee)
	if err == nil {
		*e = EphemeralKey(ee)
	}

	e.RawJSON = data

	return nil
}
<|endoftext|>


<commit_before>package api

import (
	"errors"
	"fmt"
)

var ErrAudienceTooLong = errors.New("the API only supports at most one element in the audience")

type OidcToken struct {
	Token string `json:"token"`
}

func (c *Client) OidcToken(jobId string, audience ...string) (*OidcToken, *Response, error) {
	type oidcTokenRequest struct {
		Audience string `json:"audience"`
	}

	var m *oidcTokenRequest
	switch len(audience) {
	case 0:
		m = nil
	case 1:
		m = &oidcTokenRequest{Audience: audience[0]}
	default:
		// While the spec supports multiple audiences in an Id JWT, our API does
		// not support issuing them.
		// See: https://openid.net/specs/openid-connect-core-1_0.html#IDToken.
		return nil, nil, ErrAudienceTooLong
	}

	u := fmt.Sprintf("jobs/%s/oidc/tokens", jobId)
	req, err := c.newRequest("POST", u, m)
	if err != nil {
		return nil, nil, err
	}

	t := &OidcToken{}
	resp, err := c.doRequest(req, t)
	return t, resp, err
}
<commit_msg>Fix empty object instead of no body for default audience<commit_after>package api

import (
	"errors"
	"fmt"
)

var ErrAudienceTooLong = errors.New("the API only supports at most one element in the audience")

type OidcToken struct {
	Token string `json:"token"`
}

func (c *Client) OidcToken(jobId string, audience ...string) (*OidcToken, *Response, error) {
	type oidcTokenRequest struct {
		Audience string `json:"audience,omitempty"`
	}

	m := &oidcTokenRequest{}
	switch len(audience) {
	case 0:
	case 1:
		m.Audience = audience[0]
	default:
		// While the spec supports multiple audiences in an Id JWT, our API does
		// not support issuing them.
		// See: https://openid.net/specs/openid-connect-core-1_0.html#IDToken.
		return nil, nil, ErrAudienceTooLong
	}

	u := fmt.Sprintf("jobs/%s/oidc/tokens", jobId)
	req, err := c.newRequest("POST", u, m)
	if err != nil {
		return nil, nil, err
	}

	t := &OidcToken{}
	resp, err := c.doRequest(req, t)
	return t, resp, err
}
<|endoftext|>


<commit_before>package alerts

import (
	"fmt"
	log "github.com/Sirupsen/logrus"
	mailgun "github.com/mailgun/mailgun-go"
	constants "github.com/megamsys/libgo/utils"
	"strings"
)

const (
	LAUNCHED EventAction = iota
	DESTROYED
	STATUS
	DEDUCT
	ONBOARD
	RESET
	INVITE
	BALANCE
	INVOICE
	TRANSACTION
	DESCRIPTION
	SNAPSHOTTING
	SNAPSHOTTED
	RUNNING
	FAILURE
)

type Notifier interface {
	Notify(eva EventAction, edata EventData) error
	satisfied(eva EventAction) bool
}

// Extra information about an event.
type EventData struct {
	M map[string]string
	D []string
}

type EventAction int

func (v *EventAction) String() string {
	switch *v {
	case LAUNCHED:
		return "launched"
	case DESTROYED:
		return "destroyed"
	case STATUS:
		return "status"
	case DEDUCT:
		return "deduct"
	case ONBOARD:
		return "onboard"
	case RESET:
		return "reset"
	case INVITE:
		return "invite"
	case BALANCE:
		return "balance"
	case DESCRIPTION:
		return "description"
	case SNAPSHOTTING:
		return "snapshotting"
	case SNAPSHOTTED:
		return "snapshotted"
	case RUNNING:
		return "running"
	case FAILURE:
		return "failure"
	default:
		return "arrgh"
	}
}

type mailgunner struct {
	api_key string
	domain  string
	sender  string
	nilavu  string
	logo    string
	home    string
	dir     string
}

func NewMailgun(m map[string]string, n map[string]string) Notifier {
	return &mailgunner{
		api_key: m[constants.API_KEY],
		sender:  m[constants.SENDER],
		domain:  m[constants.DOMAIN],
		nilavu:  m[constants.NILAVU],
		logo:    m[constants.LOGO],
		home:    n[constants.HOME],
		dir:     n[constants.DIR],
	}
}

func (m *mailgunner) satisfied(eva EventAction) bool {
	if eva == STATUS {
		return false
	}
	return true
}

/*{
		"email":     "nkishore@megam.io",
		"logo":      "vertice.png",
		"nilavu":    "console.megam.io",
		"appname": "vertice.megambox.com"
		"type": "torpedo"
		"token": "9090909090",
		"days":      "20",
		"cost":      "$12",
}*/

func (m *mailgunner) Notify(eva EventAction, edata EventData) error {
	fmt.Println("********************",edata)
	if !m.satisfied(eva) {
		return nil
	}
	edata.M[constants.NILAVU] = m.nilavu
	edata.M[constants.LOGO] = m.logo

	bdy, err := body(eva.String(), edata.M, m.dir)
	if err != nil {
		return err
	}
	m.Send(bdy, "", subject(eva), edata.M[constants.EMAIL])
	return nil
}

func (m *mailgunner) Send(msg string, sender string, subject string, to string) error {

	if len(strings.TrimSpace(sender)) <= 0 {
		sender = m.sender
	}
	mg := mailgun.NewMailgun(m.domain, m.api_key, "")
	g := mailgun.NewMessage(
		sender,
		subject,
		"You are in !",
		to,
	)
			fmt.Println("***********msg*********",sender,subject,to)
	g.SetHtml(msg)
	g.SetTracking(false)
	//g.SetTrackingClicks(false)
	//g.SetTrackingOpens(false)
	_, id, err := mg.Send(g)
	if err != nil {
		fmt.Println("***********msg*********",err)
		return err
	}
	log.Infof("Mailgun sent %s", id)
	return nil
}

func subject(eva EventAction) string {
	var sub string
	switch eva {
	case ONBOARD:
		sub = "Ahoy. Welcome aboard!"
	case RESET:
		sub = "You have fat finger.!"
	case INVITE:
		sub = "Lets party!"
	case BALANCE:
		sub = "Piggy bank!"
	case LAUNCHED:
		sub = "Up!"
	case RUNNING:
		sub = "Ahoy! Your application is running "
	case DESTROYED:
		sub = "Nuked"
	case SNAPSHOTTING:
		sub = "Snapshot creating!"
	case SNAPSHOTTED:
		sub = "Ahoy! Snapshot created"
	case FAILURE:
		sub = "Your application failure"
	default:
		break
	}
	return sub
}
<commit_msg>rm fmt.println<commit_after>package alerts

import (
	log "github.com/Sirupsen/logrus"
	mailgun "github.com/mailgun/mailgun-go"
	constants "github.com/megamsys/libgo/utils"
	"strings"
)

const (
	LAUNCHED EventAction = iota
	DESTROYED
	STATUS
	DEDUCT
	ONBOARD
	RESET
	INVITE
	BALANCE
	INVOICE
	TRANSACTION
	DESCRIPTION
	SNAPSHOTTING
	SNAPSHOTTED
	RUNNING
	FAILURE
)

type Notifier interface {
	Notify(eva EventAction, edata EventData) error
	satisfied(eva EventAction) bool
}

// Extra information about an event.
type EventData struct {
	M map[string]string
	D []string
}

type EventAction int

func (v *EventAction) String() string {
	switch *v {
	case LAUNCHED:
		return "launched"
	case DESTROYED:
		return "destroyed"
	case STATUS:
		return "status"
	case DEDUCT:
		return "deduct"
	case ONBOARD:
		return "onboard"
	case RESET:
		return "reset"
	case INVITE:
		return "invite"
	case BALANCE:
		return "balance"
	case DESCRIPTION:
		return "description"
	case SNAPSHOTTING:
		return "snapshotting"
	case SNAPSHOTTED:
		return "snapshotted"
	case RUNNING:
		return "running"
	case FAILURE:
		return "failure"
	default:
		return "arrgh"
	}
}

type mailgunner struct {
	api_key string
	domain  string
	sender  string
	nilavu  string
	logo    string
	home    string
	dir     string
}

func NewMailgun(m map[string]string, n map[string]string) Notifier {
	return &mailgunner{
		api_key: m[constants.API_KEY],
		sender:  m[constants.SENDER],
		domain:  m[constants.DOMAIN],
		nilavu:  m[constants.NILAVU],
		logo:    m[constants.LOGO],
		home:    n[constants.HOME],
		dir:     n[constants.DIR],
	}
}

func (m *mailgunner) satisfied(eva EventAction) bool {
	if eva == STATUS {
		return false
	}
	return true
}

/*{
		"email":     "nkishore@megam.io",
		"logo":      "vertice.png",
		"nilavu":    "console.megam.io",
		"appname": "vertice.megambox.com"
		"type": "torpedo"
		"token": "9090909090",
		"days":      "20",
		"cost":      "$12",
}*/

func (m *mailgunner) Notify(eva EventAction, edata EventData) error {
	if !m.satisfied(eva) {
		return nil
	}
	edata.M[constants.NILAVU] = m.nilavu
	edata.M[constants.LOGO] = m.logo

	bdy, err := body(eva.String(), edata.M, m.dir)
	if err != nil {
		return err
	}
	m.Send(bdy, "", subject(eva), edata.M[constants.EMAIL])
	return nil
}

func (m *mailgunner) Send(msg string, sender string, subject string, to string) error {

	if len(strings.TrimSpace(sender)) <= 0 {
		sender = m.sender
	}
	mg := mailgun.NewMailgun(m.domain, m.api_key, "")
	g := mailgun.NewMessage(
		sender,
		subject,
		"You are in !",
		to,
	)
	g.SetHtml(msg)
	g.SetTracking(false)
	//g.SetTrackingClicks(false)
	//g.SetTrackingOpens(false)
	_, id, err := mg.Send(g)
	if err != nil {
		return err
	}
	log.Infof("Mailgun sent %s", id)
	return nil
}

func subject(eva EventAction) string {
	var sub string
	switch eva {
	case ONBOARD:
		sub = "Ahoy. Welcome aboard!"
	case RESET:
		sub = "You have fat finger.!"
	case INVITE:
		sub = "Lets party!"
	case BALANCE:
		sub = "Piggy bank!"
	case LAUNCHED:
		sub = "Up!"
	case RUNNING:
		sub = "Ahoy! Your application is running "
	case DESTROYED:
		sub = "Nuked"
	case SNAPSHOTTING:
		sub = "Snapshot creating!"
	case SNAPSHOTTED:
		sub = "Ahoy! Snapshot created"
	case FAILURE:
		sub = "Your application failure"
	default:
		break
	}
	return sub
}
<|endoftext|>


<commit_before>package utils

import (
	// Go Builtin Packages
	"context"
	"encoding/json"
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	// Google OAuth2/Drive Packages
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/github"
	"golang.org/x/oauth2/google"

	// The Gorilla Web Toolkit
	"github.com/gorilla/securecookie"
	"github.com/gorilla/sessions"
)

func Http404(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusNotFound)
	var tmpl = template.Must(template.ParseFiles("templates/404.tmpl"))
	if err := tmpl.Execute(w, nil); err != nil {
		http.Error(w, "Meep! We were trying to make the '404' page but something went wrong.", http.StatusInternalServerError)
	}
}

// http://andyrees.github.io/2015/your-code-a-mess-maybe-its-time-to-bring-in-the-decorators/
func ExtraSugar(f http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		ctx := context.WithValue(r.Context(), "staticDomain", os.Getenv("StaticDomain"))

		if session, err := sessionStore().Get(r, "_app_session"); err != nil {
			log.Printf("WARNING: sessionStore.Get call failed for _app_session, %v", err)
			ClearAppSession(w)
		} else {
			userID := session.Values["userID"]
			if userID != nil {
				ctx = context.WithValue(ctx, "userID", userID)
				if err := InitAppSession(w, r, userID.(string)); err != nil {
					log.Printf("WARNING: InitAppSession call failed in context, %v", err)
				}
			}
		}

		r = r.WithContext(ctx)

		w.Header().Set("Ada", "*skips about* Hi! <3 ^_^")
		w.Header().Set("X-Content-Type-Options", "nosniff")
		w.Header().Set("Content-Security-Policy", "default-src 'self' "+os.Getenv("StaticDomain")+"; font-src netdna.bootstrapcdn.com fonts.gstatic.com; script-src 'self' netdna.bootstrapcdn.com ajax.googleapis.com linkhelp.clients.google.com www.google-analytics.com cdnjs.cloudflare.com https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/ "+os.Getenv("StaticDomain")+"; style-src 'self' netdna.bootstrapcdn.com cdnjs.cloudflare.com "+os.Getenv("StaticDomain")+" 'unsafe-inline'; img-src 'self' data: www.google-analytics.com stats.g.doubleclick.net "+os.Getenv("StaticDomain")+"; object-src 'none'; media-src 'none'; connect-src 'self' *.googleusercontent.com; frame-src 'self' "+os.Getenv("StaticDomain")+" blob: https://www.google.com/recaptcha/; frame-ancestors 'none'")
		w.Header().Set("Strict-Transport-Security", "max-age=15552000")

		if strings.Contains(strings.ToLower(r.UserAgent()), "msie") {
			w.Header().Set("X-UA-Compatible", "IE=edge,chrome=1")
			w.Header().Set("X-XSS-Protection", "1; mode=block")
		}

		f(w, r)
	}
}

func sessionStore() *sessions.CookieStore {
	CSRFAuthKey := []byte(os.Getenv("CSRFAuthKey"))
	EncryptionK := []byte(os.Getenv("EncryptionK"))
	ss := sessions.NewCookieStore(CSRFAuthKey, EncryptionK)
	return ss
}

func UpdateSession(w http.ResponseWriter, r *http.Request, paste_id string, remove bool) error {
	if session, err := sessionStore().Get(r, "_pb_session"); err != nil {
		return err
	} else {
		session.Options = &sessions.Options{
			Path:     "/pastebin/",
			MaxAge:   0,
			HttpOnly: true,
			Secure:   os.Getenv("CSRFSecureC") == "true",
		}

		if remove == true {
			_paste_id := paste_id[1:]
			delete(session.Values, _paste_id)
		} else {
			session.Values[paste_id] = time.Now().Format(time.RFC3339)
			if len(session.Values) > 10 { // remember up to 10 pastes only
				var popindex string
				_time := time.Now().Format(time.RFC3339)
				for key, value := range session.Values {
					if value.(string) < _time {
						_time = value.(string)
						popindex = key.(string)
					}
				}
				delete(session.Values, popindex)
			}
		}

		return session.Save(r, w)
	}
}

func CheckSession(r *http.Request, paste_id string) (bool, error) {
	if session, err := sessionStore().Get(r, "_pb_session"); err != nil {
		return false, err
	} else {
		if session.Values[paste_id] != nil {
			return true, nil
		}
	}
	return false, nil
}

func InitAppSession(w http.ResponseWriter, r *http.Request, userID string) error {
	if session, err := sessionStore().Get(r, "_app_session"); err != nil {
		return err
	} else {
		session.Options = &sessions.Options{
			Path:     "/pastebin/",
			MaxAge:   86400 * 3,
			HttpOnly: true,
			Secure:   os.Getenv("CSRFSecureC") == "true",
		}

		session.Values["userID"] = userID
		return session.Save(r, w)
	}
}

func ClearAppSession(w http.ResponseWriter) {
	http.SetCookie(w, &http.Cookie{
		Path:     "/pastebin/",
		Name:     "_app_session",
		Value:    "",
		MaxAge:   -1,
		HttpOnly: true,
		Secure:   os.Getenv("CSRFSecureC") == "true",
	})
}

func ClearOauthCookie(w http.ResponseWriter) {
	http.SetCookie(w, &http.Cookie{ // That was a HALF A KILO cookie!! :O
		Path:     "/pastebin/",
		Name:     "_oauth2_gdrive",
		Value:    "",
		MaxAge:   -1,
		HttpOnly: true,
		Secure:   os.Getenv("CSRFSecureC") == "true",
	})
}

func ProcessForm(r *http.Request) error {
	var err error
	if strings.Contains(strings.ToLower(r.Header.Get("content-type")), "multipart") {
		err = r.ParseMultipartForm(32 << 20) // 32 MB - http.defaultMaxMemory
	} else {
		err = r.ParseForm()
	}
	return err
}

func SC() *securecookie.SecureCookie {
	CSRFAuthKey := []byte(os.Getenv("CSRFAuthKey"))
	EncryptionK := []byte(os.Getenv("EncryptionK"))
	sc := securecookie.New(CSRFAuthKey, EncryptionK)
	return sc
}

func OAuthConfigDance(provider string, redirectURL string, scopes ...string) (*oauth2.Config, error) {
	if provider == "google" {
		GCPOAuthCID := []byte(os.Getenv("GCPOAuthCID"))
		if config, err := google.ConfigFromJSON([]byte(GCPOAuthCID), scopes...); err == nil {
			config.RedirectURL = redirectURL
			return config, nil
		} else {
			return config, err
		}
	} else if provider == "github" {
		GitHubClientID := os.Getenv("GitHubClientID")
		GitHubClientSecret := os.Getenv("GitHubClientSecret")
		return &oauth2.Config{
			ClientID:     GitHubClientID,
			ClientSecret: GitHubClientSecret,
			Endpoint:     github.Endpoint,
		}, nil
	}
	return nil, fmt.Errorf("No provider specified for oauth config")
}

type reCaptchaResponse struct {
	Success bool    `json:"success"`
	Score   float64 `json:"score,number"`
}

func ValidateCaptcha(recaptchaResponse string, remoteip string) (float64, error) {
	gRecaptchaRequest := url.Values{}
	gRecaptchaRequest.Add("secret", os.Getenv("ReCAPTCHASecrt"))
	gRecaptchaRequest.Add("response", recaptchaResponse)
	gRecaptchaRequest.Add("remoteip", remoteip)

	if !(len(recaptchaResponse) > 0) {
		log.Println("WARNING: missing reCAPTCHA token")
		return 0.0, nil
	}

	rvCall := &http.Client{}
	if response, err := rvCall.PostForm("https://www.google.com/recaptcha/api/siteverify", gRecaptchaRequest); err == nil {
		defer response.Body.Close()
		if rContent, err := ioutil.ReadAll(response.Body); err == nil {
			rvResponse := &reCaptchaResponse{}
			if err := json.Unmarshal(rContent, &rvResponse); err == nil {
				if rvResponse.Success {
					return rvResponse.Score, nil
				} else {
					log.Println("WARNING: invalid reCAPTCHA token")
					return 0.0, nil
				}
			} else {
				return 0.0, err
			}
		} else {
			return 0.0, err
		}
	} else {
		return 0.0, err
	}
}
<commit_msg>No wonder GitHub doesn't complain!<commit_after>package utils

import (
	// Go Builtin Packages
	"context"
	"encoding/json"
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	// Google OAuth2/Drive Packages
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/github"
	"golang.org/x/oauth2/google"

	// The Gorilla Web Toolkit
	"github.com/gorilla/securecookie"
	"github.com/gorilla/sessions"
)

func Http404(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusNotFound)
	var tmpl = template.Must(template.ParseFiles("templates/404.tmpl"))
	if err := tmpl.Execute(w, nil); err != nil {
		http.Error(w, "Meep! We were trying to make the '404' page but something went wrong.", http.StatusInternalServerError)
	}
}

// http://andyrees.github.io/2015/your-code-a-mess-maybe-its-time-to-bring-in-the-decorators/
func ExtraSugar(f http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		ctx := context.WithValue(r.Context(), "staticDomain", os.Getenv("StaticDomain"))

		if session, err := sessionStore().Get(r, "_app_session"); err != nil {
			log.Printf("WARNING: sessionStore.Get call failed for _app_session, %v", err)
			ClearAppSession(w)
		} else {
			userID := session.Values["userID"]
			if userID != nil {
				ctx = context.WithValue(ctx, "userID", userID)
				if err := InitAppSession(w, r, userID.(string)); err != nil {
					log.Printf("WARNING: InitAppSession call failed in context, %v", err)
				}
			}
		}

		r = r.WithContext(ctx)

		w.Header().Set("Ada", "*skips about* Hi! <3 ^_^")
		w.Header().Set("X-Content-Type-Options", "nosniff")
		w.Header().Set("Content-Security-Policy", "default-src 'self' "+os.Getenv("StaticDomain")+"; font-src netdna.bootstrapcdn.com fonts.gstatic.com; script-src 'self' netdna.bootstrapcdn.com ajax.googleapis.com linkhelp.clients.google.com www.google-analytics.com cdnjs.cloudflare.com https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/ "+os.Getenv("StaticDomain")+"; style-src 'self' netdna.bootstrapcdn.com cdnjs.cloudflare.com "+os.Getenv("StaticDomain")+" 'unsafe-inline'; img-src 'self' data: www.google-analytics.com stats.g.doubleclick.net "+os.Getenv("StaticDomain")+"; object-src 'none'; media-src 'none'; connect-src 'self' *.googleusercontent.com; frame-src 'self' "+os.Getenv("StaticDomain")+" blob: https://www.google.com/recaptcha/; frame-ancestors 'none'")
		w.Header().Set("Strict-Transport-Security", "max-age=15552000")

		if strings.Contains(strings.ToLower(r.UserAgent()), "msie") {
			w.Header().Set("X-UA-Compatible", "IE=edge,chrome=1")
			w.Header().Set("X-XSS-Protection", "1; mode=block")
		}

		f(w, r)
	}
}

func sessionStore() *sessions.CookieStore {
	CSRFAuthKey := []byte(os.Getenv("CSRFAuthKey"))
	EncryptionK := []byte(os.Getenv("EncryptionK"))
	ss := sessions.NewCookieStore(CSRFAuthKey, EncryptionK)
	return ss
}

func UpdateSession(w http.ResponseWriter, r *http.Request, paste_id string, remove bool) error {
	if session, err := sessionStore().Get(r, "_pb_session"); err != nil {
		return err
	} else {
		session.Options = &sessions.Options{
			Path:     "/pastebin/",
			MaxAge:   0,
			HttpOnly: true,
			Secure:   os.Getenv("CSRFSecureC") == "true",
		}

		if remove == true {
			_paste_id := paste_id[1:]
			delete(session.Values, _paste_id)
		} else {
			session.Values[paste_id] = time.Now().Format(time.RFC3339)
			if len(session.Values) > 10 { // remember up to 10 pastes only
				var popindex string
				_time := time.Now().Format(time.RFC3339)
				for key, value := range session.Values {
					if value.(string) < _time {
						_time = value.(string)
						popindex = key.(string)
					}
				}
				delete(session.Values, popindex)
			}
		}

		return session.Save(r, w)
	}
}

func CheckSession(r *http.Request, paste_id string) (bool, error) {
	if session, err := sessionStore().Get(r, "_pb_session"); err != nil {
		return false, err
	} else {
		if session.Values[paste_id] != nil {
			return true, nil
		}
	}
	return false, nil
}

func InitAppSession(w http.ResponseWriter, r *http.Request, userID string) error {
	if session, err := sessionStore().Get(r, "_app_session"); err != nil {
		return err
	} else {
		session.Options = &sessions.Options{
			Path:     "/pastebin/",
			MaxAge:   86400 * 3,
			HttpOnly: true,
			Secure:   os.Getenv("CSRFSecureC") == "true",
		}

		session.Values["userID"] = userID
		return session.Save(r, w)
	}
}

func ClearAppSession(w http.ResponseWriter) {
	http.SetCookie(w, &http.Cookie{
		Path:     "/pastebin/",
		Name:     "_app_session",
		Value:    "",
		MaxAge:   -1,
		HttpOnly: true,
		Secure:   os.Getenv("CSRFSecureC") == "true",
	})
}

func ClearOauthCookie(w http.ResponseWriter) {
	http.SetCookie(w, &http.Cookie{ // That was a HALF A KILO cookie!! :O
		Path:     "/pastebin/",
		Name:     "_oauth2_gdrive",
		Value:    "",
		MaxAge:   -1,
		HttpOnly: true,
		Secure:   os.Getenv("CSRFSecureC") == "true",
	})
}

func ProcessForm(r *http.Request) error {
	var err error
	if strings.Contains(strings.ToLower(r.Header.Get("content-type")), "multipart") {
		err = r.ParseMultipartForm(32 << 20) // 32 MB - http.defaultMaxMemory
	} else {
		err = r.ParseForm()
	}
	return err
}

func SC() *securecookie.SecureCookie {
	CSRFAuthKey := []byte(os.Getenv("CSRFAuthKey"))
	EncryptionK := []byte(os.Getenv("EncryptionK"))
	sc := securecookie.New(CSRFAuthKey, EncryptionK)
	return sc
}

func OAuthConfigDance(provider string, redirectURL string, scopes ...string) (*oauth2.Config, error) {
	if provider == "google" {
		GCPOAuthCID := []byte(os.Getenv("GCPOAuthCID"))
		if config, err := google.ConfigFromJSON([]byte(GCPOAuthCID), scopes...); err == nil {
			config.RedirectURL = redirectURL
			return config, nil
		} else {
			return config, err
		}
	} else if provider == "github" {
		GitHubClientID := os.Getenv("GitHubClientID")
		GitHubClientSecret := os.Getenv("GitHubClientSecret")
		return &oauth2.Config{
			ClientID:     GitHubClientID,
			ClientSecret: GitHubClientSecret,
			Endpoint:     github.Endpoint,
			RedirectURL:  redirectURL,
		}, nil
	}
	return nil, fmt.Errorf("No provider specified for oauth config")
}

type reCaptchaResponse struct {
	Success bool    `json:"success"`
	Score   float64 `json:"score,number"`
}

func ValidateCaptcha(recaptchaResponse string, remoteip string) (float64, error) {
	gRecaptchaRequest := url.Values{}
	gRecaptchaRequest.Add("secret", os.Getenv("ReCAPTCHASecrt"))
	gRecaptchaRequest.Add("response", recaptchaResponse)
	gRecaptchaRequest.Add("remoteip", remoteip)

	if !(len(recaptchaResponse) > 0) {
		log.Println("WARNING: missing reCAPTCHA token")
		return 0.0, nil
	}

	rvCall := &http.Client{}
	if response, err := rvCall.PostForm("https://www.google.com/recaptcha/api/siteverify", gRecaptchaRequest); err == nil {
		defer response.Body.Close()
		if rContent, err := ioutil.ReadAll(response.Body); err == nil {
			rvResponse := &reCaptchaResponse{}
			if err := json.Unmarshal(rContent, &rvResponse); err == nil {
				if rvResponse.Success {
					return rvResponse.Score, nil
				} else {
					log.Println("WARNING: invalid reCAPTCHA token")
					return 0.0, nil
				}
			} else {
				return 0.0, err
			}
		} else {
			return 0.0, err
		}
	} else {
		return 0.0, err
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2021 The Vitess Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package planbuilder

import (
	"fmt"
	"sync"
	"testing"

	"github.com/stretchr/testify/require"

	"vitess.io/vitess/go/vt/sqlparser"
	"vitess.io/vitess/go/vt/vtgate/semantics"
)

func TestSimplifyUnsupportedQuery(t *testing.T) {
	query := "select user.id+user.foo, count(*), unsharded.name from user join unsharded where unsharded.id = 42"
	vschema := &vschemaWrapper{
		v: loadSchema(t, "schema_test.json", true),
	}
	vschema.version = Gen4
	stmt, reserved, err := sqlparser.Parse2(query)
	require.NoError(t, err)
	result, _ := sqlparser.RewriteAST(stmt, vschema.currentDb(), sqlparser.SQLSelectLimitUnset)
	vschema.currentDb()

	reservedVars := sqlparser.NewReservedVars("vtg", reserved)
	plan, err := BuildFromStmt(query, result.AST, reservedVars, vschema, result.BindVarNeeds, true, true)
	out := getPlanOrErrorOutput(err, plan)

	simplified := simplifyStatement(result.AST.(sqlparser.SelectStatement), vschema.currentDb(), vschema, func(statement sqlparser.SelectStatement) bool {
		plan, err := BuildFromStmt(query, statement, reservedVars, vschema, result.BindVarNeeds, true, true)
		out2 := getPlanOrErrorOutput(err, plan)
		return out == out2
	})

	t.Fatal(sqlparser.String(simplified))
}

func TestFindAllExpressions(t *testing.T) {
	query := "select user.id, count(*), unsharded.name from user join unsharded where unsharded.id = 42 and name = 'foo' and user.id = unsharded.id"
	ast, err := sqlparser.Parse(query)
	require.NoError(t, err)
	ch := make(chan cursorItem)
	findExpressions(ast.(sqlparser.SelectStatement), ch)
	for cursor := range ch {
		fmt.Println(sqlparser.String(cursor.expr))
		cursor.replace(sqlparser.NewIntLiteral("1"))
		fmt.Println(sqlparser.String(ast))
		cursor.replace(cursor.expr)
		cursor.wg.Done()
	}
}

func simplifyStatement(
	in sqlparser.SelectStatement,
	currentDB string,
	si semantics.SchemaInformation,
	test func(sqlparser.SelectStatement) bool,
) sqlparser.SelectStatement {
	semTable, err := semantics.Analyze(in, currentDB, si)
	if err != nil {
		return nil
	}

	// we start by removing one table at a time, and see if we still have an interesting plan
	for idx := range semTable.Tables {
		clone := sqlparser.CloneSelectStatement(in)
		inner, err := semantics.Analyze(clone, currentDB, si)
		if err != nil {
			panic(err) // this should never happen
		}
		searchedTS := semantics.SingleTableSet(idx)
		simplified := removeTable(clone, searchedTS, inner)
		if simplified && test(clone) {
			return simplifyStatement(clone, currentDB, si, test)
		}
	}

	// if we get here, we couldn't find a simpler query by just removing one table,
	// we try to remove select expressions next
	ch := make(chan cursorItem)
	findExpressions(in, ch)
	for cursor := range ch {
		s := &sqlparser.Shrinker{Orig: cursor.expr}
		newExpr := s.Next()
		for newExpr != nil {
			cursor.replace(newExpr)
			if test(in) {
				return simplifyStatement(in, currentDB, si, test)
			}
			newExpr = s.Next()
		}
		// if we get here, we failed to simplify this expression,
		// so we put back in the original expression
		cursor.replace(cursor.expr)
		cursor.wg.Done()
	}

	return in
}

// removeTable removes the table with the given index from the select statement, which includes the FROM clause
// but also all expressions and predicates that depend on the table
func removeTable(clone sqlparser.SelectStatement, searchedTS semantics.TableSet, inner *semantics.SemTable) bool {
	simplified := false
	sqlparser.Rewrite(clone, func(cursor *sqlparser.Cursor) bool {
		switch node := cursor.Node().(type) {
		case *sqlparser.JoinTableExpr:
			lft, ok := node.LeftExpr.(*sqlparser.AliasedTableExpr)
			if ok {
				ts := inner.TableSetFor(lft)
				if ts == searchedTS {
					cursor.Replace(node.RightExpr)
					simplified = true
				}
			}
			rgt, ok := node.RightExpr.(*sqlparser.AliasedTableExpr)
			if ok {
				ts := inner.TableSetFor(rgt)
				if ts == searchedTS {
					cursor.Replace(node.LeftExpr)
					simplified = true
				}
			}
		case *sqlparser.Select:
			if len(node.From) == 1 {
				return true
			}
			for i, tbl := range node.From {
				lft, ok := tbl.(*sqlparser.AliasedTableExpr)
				if ok {
					ts := inner.TableSetFor(lft)
					if ts == searchedTS {
						node.From = append(node.From[:i], node.From[i+1:]...)
						simplified = true
						return true
					}
				}
			}
		case *sqlparser.Where:
			exprs := sqlparser.SplitAndExpression(nil, node.Expr)
			var newPredicate sqlparser.Expr
			for _, expr := range exprs {
				if !inner.RecursiveDeps(expr).IsOverlapping(searchedTS) {
					newPredicate = sqlparser.AndExpressions(newPredicate, expr)
				}
			}
			node.Expr = newPredicate
		case sqlparser.SelectExprs:
			_, isSel := cursor.Parent().(*sqlparser.Select)
			if !isSel {
				return true
			}

			var newExprs sqlparser.SelectExprs
			for _, ae := range node {
				expr, ok := ae.(*sqlparser.AliasedExpr)
				if !ok {
					newExprs = append(newExprs, ae)
					continue
				}
				if !inner.RecursiveDeps(expr.Expr).IsOverlapping(searchedTS) || sqlparser.ContainsAggregation(expr.Expr) {
					newExprs = append(newExprs, ae)
				}
			}
			cursor.Replace(newExprs)
		}
		return true
	}, nil)
	return simplified
}

type cursorItem struct {
	expr    sqlparser.Expr
	replace func(replaceWith sqlparser.Expr)
	wg      *sync.WaitGroup
}

func newCursorItem(ch chan<- cursorItem, expr sqlparser.Expr, replace func(replaceWith sqlparser.Expr)) {
	wg := &sync.WaitGroup{}
	wg.Add(1)
	ch <- cursorItem{
		expr:    expr,
		replace: replace,
		wg:      wg,
	}
	wg.Wait()
}

func findExpressions(clone sqlparser.SelectStatement, ch chan<- cursorItem) {
	go func() {
		sqlparser.Rewrite(clone, func(cursor *sqlparser.Cursor) bool {
			switch node := cursor.Node().(type) {
			case sqlparser.SelectExprs:
				_, isSel := cursor.Parent().(*sqlparser.Select)
				if !isSel {
					return true
				}
				for _, ae := range node {
					expr, ok := ae.(*sqlparser.AliasedExpr)
					if !ok {
						continue
					}
					newCursorItem(ch, expr.Expr, func(replaceWith sqlparser.Expr) {
						expr.Expr = replaceWith
					})
				}

			case *sqlparser.Where:
				exprs := sqlparser.SplitAndExpression(nil, node.Expr)
				for idx := 0; idx < len(exprs); idx++ {
					expr := exprs[idx]
					newCursorItem(ch, expr, func(replaceWith sqlparser.Expr) {
						exprs[idx] = replaceWith
						node.Expr = sqlparser.AndExpressions(exprs...)
					})
				}
			}
			return true
		}, nil)
		close(ch)
	}()
}
<commit_msg>feat: make it possible to abort the find expressions walker<commit_after>/*
Copyright 2021 The Vitess Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package planbuilder

import (
	"fmt"
	"sync"
	"testing"

	"vitess.io/vitess/go/sync2"
	"vitess.io/vitess/go/vt/log"

	"github.com/stretchr/testify/require"

	"vitess.io/vitess/go/vt/sqlparser"
	"vitess.io/vitess/go/vt/vtgate/semantics"
)

func TestSimplifyUnsupportedQuery(t *testing.T) {
	query := "select user.id, user.name, count(*), unsharded.name from user join unsharded where unsharded.id = 42 group by user.id"
	vschema := &vschemaWrapper{
		v: loadSchema(t, "schema_test.json", true),
	}
	vschema.version = Gen4
	stmt, reserved, err := sqlparser.Parse2(query)
	require.NoError(t, err)
	result, _ := sqlparser.RewriteAST(stmt, vschema.currentDb(), sqlparser.SQLSelectLimitUnset)
	vschema.currentDb()

	reservedVars := sqlparser.NewReservedVars("vtg", reserved)
	plan, err := BuildFromStmt(query, result.AST, reservedVars, vschema, result.BindVarNeeds, true, true)
	out := getPlanOrErrorOutput(err, plan)

	simplified := simplifyStatement(result.AST.(sqlparser.SelectStatement), vschema.currentDb(), vschema, func(statement sqlparser.SelectStatement) bool {
		plan, err := BuildFromStmt(query, statement, reservedVars, vschema, result.BindVarNeeds, true, true)
		out2 := getPlanOrErrorOutput(err, plan)
		return out == out2
	})

	t.Fatal(sqlparser.String(simplified))
}

func TestFindAllExpressions(t *testing.T) {
	query := "select user.id, count(*), unsharded.name from user join unsharded where unsharded.id = 42 and name = 'foo' and user.id = unsharded.id"
	ast, err := sqlparser.Parse(query)
	require.NoError(t, err)
	ch := make(chan cursorItem)
	abort := &sync2.AtomicBool{}
	findExpressions(ast.(sqlparser.SelectStatement), ch, abort)
	for cursor := range ch {
		fmt.Println(sqlparser.String(cursor.expr))
		cursor.replace(sqlparser.NewIntLiteral("1"))
		fmt.Println(sqlparser.String(ast))
		cursor.replace(cursor.expr)
		if _, ok := cursor.expr.(*sqlparser.FuncExpr); ok {
			abort.Set(true)
			break
		}
		cursor.wg.Done()
	}
}

func simplifyStatement(
	in sqlparser.SelectStatement,
	currentDB string,
	si semantics.SchemaInformation,
	test func(sqlparser.SelectStatement) bool,
) sqlparser.SelectStatement {
	semTable, err := semantics.Analyze(in, currentDB, si)
	if err != nil {
		return nil
	}

	// we start by removing one table at a time, and see if we still have an interesting plan
	for idx := range semTable.Tables {
		clone := sqlparser.CloneSelectStatement(in)
		inner, err := semantics.Analyze(clone, currentDB, si)
		if err != nil {
			panic(err) // this should never happen
		}
		searchedTS := semantics.SingleTableSet(idx)
		simplified := removeTable(clone, searchedTS, inner)
		if simplified && test(clone) {
			name, _ := semTable.Tables[idx].Name()
			log.Errorf("removed table %s", name)
			return simplifyStatement(clone, currentDB, si, test)
		}
	}

	// if we get here, we couldn't find a simpler query by just removing one table,
	// we try to remove select expressions next
	ch := make(chan cursorItem)
	abort := &sync2.AtomicBool{}
	findExpressions(in, ch, abort)
	for cursor := range ch {
		s := &sqlparser.Shrinker{Orig: cursor.expr}
		newExpr := s.Next()
		for newExpr != nil {
			cursor.replace(newExpr)
			if test(in) {
				log.Errorf("simplified expression: %s -> %s", sqlparser.String(cursor.expr), sqlparser.String(newExpr))
				return simplifyStatement(in, currentDB, si, test)
			}
			newExpr = s.Next()
		}
		// if we get here, we failed to simplify this expression,
		// so we put back in the original expression
		cursor.replace(cursor.expr)
		cursor.wg.Done()
	}

	return in
}

// removeTable removes the table with the given index from the select statement, which includes the FROM clause
// but also all expressions and predicates that depend on the table
func removeTable(clone sqlparser.SelectStatement, searchedTS semantics.TableSet, inner *semantics.SemTable) bool {
	simplified := false
	sqlparser.Rewrite(clone, func(cursor *sqlparser.Cursor) bool {
		switch node := cursor.Node().(type) {
		case *sqlparser.JoinTableExpr:
			lft, ok := node.LeftExpr.(*sqlparser.AliasedTableExpr)
			if ok {
				ts := inner.TableSetFor(lft)
				if ts == searchedTS {
					cursor.Replace(node.RightExpr)
					simplified = true
				}
			}
			rgt, ok := node.RightExpr.(*sqlparser.AliasedTableExpr)
			if ok {
				ts := inner.TableSetFor(rgt)
				if ts == searchedTS {
					cursor.Replace(node.LeftExpr)
					simplified = true
				}
			}
		case *sqlparser.Select:
			if len(node.From) == 1 {
				return true
			}
			for i, tbl := range node.From {
				lft, ok := tbl.(*sqlparser.AliasedTableExpr)
				if ok {
					ts := inner.TableSetFor(lft)
					if ts == searchedTS {
						node.From = append(node.From[:i], node.From[i+1:]...)
						simplified = true
						return true
					}
				}
			}
		case *sqlparser.Where:
			exprs := sqlparser.SplitAndExpression(nil, node.Expr)
			var newPredicate sqlparser.Expr
			for _, expr := range exprs {
				if !inner.RecursiveDeps(expr).IsOverlapping(searchedTS) {
					newPredicate = sqlparser.AndExpressions(newPredicate, expr)
				}
			}
			node.Expr = newPredicate
		case sqlparser.SelectExprs:
			_, isSel := cursor.Parent().(*sqlparser.Select)
			if !isSel {
				return true
			}

			var newExprs sqlparser.SelectExprs
			for _, ae := range node {
				expr, ok := ae.(*sqlparser.AliasedExpr)
				if !ok {
					newExprs = append(newExprs, ae)
					continue
				}
				if !inner.RecursiveDeps(expr.Expr).IsOverlapping(searchedTS) || sqlparser.ContainsAggregation(expr.Expr) {
					newExprs = append(newExprs, ae)
				}
			}
			cursor.Replace(newExprs)
		case sqlparser.GroupBy:
			var newExprs sqlparser.GroupBy
			for _, expr := range node {
				if !inner.RecursiveDeps(expr).IsOverlapping(searchedTS) || sqlparser.ContainsAggregation(expr) {
					newExprs = append(newExprs, expr)
				}
			}
			cursor.Replace(newExprs)
		case sqlparser.OrderBy:
			var newExprs sqlparser.OrderBy
			for _, expr := range node {
				if !inner.RecursiveDeps(expr.Expr).IsOverlapping(searchedTS) || sqlparser.ContainsAggregation(expr.Expr) {
					newExprs = append(newExprs, expr)
				}
			}

			cursor.Replace(newExprs)
		}
		return true
	}, nil)
	return simplified
}

type cursorItem struct {
	expr    sqlparser.Expr
	replace func(replaceWith sqlparser.Expr)
	wg      *sync.WaitGroup
}

func newCursorItem(ch chan<- cursorItem, expr sqlparser.Expr, replace func(replaceWith sqlparser.Expr)) {
	wg := &sync.WaitGroup{}
	wg.Add(1)
	ch <- cursorItem{
		expr:    expr,
		replace: replace,
		wg:      wg,
	}
	wg.Wait()
}

func findExpressions(clone sqlparser.SelectStatement, ch chan<- cursorItem, abort *sync2.AtomicBool) {
	go func() {
		sqlparser.Rewrite(clone, func(cursor *sqlparser.Cursor) bool {
			switch node := cursor.Node().(type) {
			case sqlparser.SelectExprs:
				_, isSel := cursor.Parent().(*sqlparser.Select)
				if !isSel {
					return true
				}
				for _, ae := range node {
					expr, ok := ae.(*sqlparser.AliasedExpr)
					if !ok {
						continue
					}
					newCursorItem(ch, expr.Expr, func(replaceWith sqlparser.Expr) {
						expr.Expr = replaceWith
					})
					if abort.Get() {
						close(ch)
						return false
					}
				}

			case *sqlparser.Where:
				exprs := sqlparser.SplitAndExpression(nil, node.Expr)
				for idx := 0; idx < len(exprs); idx++ {
					expr := exprs[idx]
					newCursorItem(ch, expr, func(replaceWith sqlparser.Expr) {
						exprs[idx] = replaceWith
						node.Expr = sqlparser.AndExpressions(exprs...)
					})
					if abort.Get() {
						close(ch)
						return false
					}
				}
			}
			return true
		}, nil)
		close(ch)
	}()
}
<|endoftext|>


<commit_before>// Copyright © 2017 PolySwarm <info@polyswarm.io>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/spf13/cobra"

	"github.com/swarmdotmarket/perigord/templates"
)

var compileCmd = &cobra.Command{
	Use:   "compile",
	Short: "Compile contract source files",
	Run: func(cmd *cobra.Command, args []string) {
		err := RunInRoot(func() error {
			if err := compileContracts(); err != nil {
				return err
			}

			return generateBindings()
		})
		if err != nil {
			Fatal(err)
		}
	},
}

var buildCmd = &cobra.Command{
	Use:   "build",
	Short: "(alias for compile)",
	Run:   compileCmd.Run,
}

var generateCmd = &cobra.Command{
	Use:   "generate",
	Short: "(alias for compile)",
	Run:   compileCmd.Run,
}

func init() {
	RootCmd.AddCommand(compileCmd)
	RootCmd.AddCommand(buildCmd)
	RootCmd.AddCommand(generateCmd)
}

func compileContracts() error {
	if err := os.Chdir(ContractsDirectory); err != nil {
		return err
	}

	matches := make([]string, 0)
	err := filepath.Walk(".", func(path string, f os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		if strings.HasSuffix(path, ".sol") {
			matches = append(matches, path)
		}
		return nil
	})

	if err != nil {
		return err
	}

	if len(matches) == 0 {
		Fatal("No contracts found, create one with `perigord add contract NAME`")
	}

	command := "solc"
	_, err = exec.LookPath(command)
	if err != nil {
		return errors.New("Can't locate solc, is it installed and in your path")
	}

	dir, err := os.Getwd()
	if err != nil {
		return err
	}

	compilerConfig, err := templates.ExecuteTemplate("solc/solc.json.tpl", matches)
	if err != nil {
		return err
	}

	args := []string{"--allow-paths", dir, "--standard-json"}
	outputJson, err := ExecWithPipes(command, compilerConfig.Bytes(), args...)
	if err != nil {
		return err
	}

	if err = os.Chdir(".."); err != nil {
		return err
	}

	var output map[string]interface{}
	if err = json.Unmarshal(outputJson, &output); err != nil {
		return err
	}

	if err = handleErrors(output); err != nil {
		return err
	}

	return saveArtifacts(output)
}

func handleErrors(output map[string]interface{}) error {
	hasFatal := false
	compilerErrors, ok := output["errors"].([]interface{})
	if !ok {
		return errors.New("Invalid json")
	}

	for _, value := range compilerErrors {
		compilerErr, ok := value.(map[string]interface{})
		if !ok {
			return errors.New("Invalid json")
		}

		severity, ok := compilerErr["severity"].(string)
		if !ok {
			return errors.New("Invalid json")
		}

		message, ok := compilerErr["formattedMessage"].(string)
		if !ok {
			return errors.New("Invalid json")
		}

		if severity != "warning" {
			hasFatal = true
		}

		fmt.Println(message)
	}

	if hasFatal {
		return errors.New("Error detected, aborting. Please check solidity output for more details.")
	}

	return nil
}

func saveArtifacts(output map[string]interface{}) error {
	if err := os.MkdirAll(BuildDirectory, os.FileMode(0755)); err != nil {
		return err
	}

	contracts, ok := output["contracts"].(map[string]interface{})
	if !ok {
		return errors.New("Invalid json")
	}

	for _, value := range contracts {
		contract, ok := value.(map[string]interface{})
		if !ok {
			return errors.New("Invalid json")
		}

		for name, value := range contract {
			data, ok := value.(map[string]interface{})
			if !ok {
				return errors.New("Invalid json")
			}

			// Get ABI as a json blob
			abi, err := json.Marshal(data["abi"])
			if err != nil {
				return err
			}

			evm, ok := data["evm"].(map[string]interface{})
			if !ok {
				return errors.New("Invalid json")
			}

			bytecodeObject, ok := evm["bytecode"].(map[string]interface{})
			if !ok {
				return errors.New("Invalid json")
			}

			// Get bytecode as a bin
			bytecode, ok := bytecodeObject["object"].(string)
			if !ok {
				return errors.New("Invalid json")
			}

			// Get link references as a json blob
			linkReferences, err := json.Marshal(bytecodeObject["linkReferences"])
			if err != nil {
				return err
			}

			ioutil.WriteFile(filepath.Join(BuildDirectory, name+".abi"), abi, 0644)
			ioutil.WriteFile(filepath.Join(BuildDirectory, name+".bin"), []byte(bytecode), 0644)
			ioutil.WriteFile(filepath.Join(BuildDirectory, name+".link"), linkReferences, 0644)
		}
	}

	return nil
}

func generateBindings() error {
	return nil
	//	matches, err := filepath.Glob(BuildDirectory + "/*.abi")
	//	if err != nil {
	//		return err
	//	}
	//
	//	if err := os.MkdirAll(BindingsDirectory, os.FileMode(0755)); err != nil {
	//		return err
	//	}
	//
	//	for _, match := range matches {
	//		if err := generateBinding(strings.TrimSuffix(match, filepath.Ext(match))); err != nil {
	//			return err
	//		}
	//	}
	//
	//	return nil
}

func generateBinding(path string) error {
	return nil
	//	// TODO: Allow alternate binding directories / package names, in config file
	//	command := "abigen"
	//	_, err := exec.LookPath(command)
	//	if err != nil {
	//		return errors.New("Can't locate abigen, is it installed and in your path")
	//	}
	//
	//	name := filepath.Base(path)
	//	abifile := path + ".abi"
	//	binfile := path + ".bin"
	//	outfile := filepath.Join(BindingsDirectory, filepath.Base(name)) + ".go"
	//	args := []string{"--abi", abifile, "--bin", binfile, "--pkg", "bindings", "--type", name, "--out", outfile}
	//	return ExecWithOutput(command, args...)
}
<commit_msg>Fix more rebranding breakage<commit_after>// Copyright © 2017 PolySwarm <info@polyswarm.io>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/spf13/cobra"

	"github.com/polyswarm/perigord/templates"
)

var compileCmd = &cobra.Command{
	Use:   "compile",
	Short: "Compile contract source files",
	Run: func(cmd *cobra.Command, args []string) {
		err := RunInRoot(func() error {
			if err := compileContracts(); err != nil {
				return err
			}

			return generateBindings()
		})
		if err != nil {
			Fatal(err)
		}
	},
}

var buildCmd = &cobra.Command{
	Use:   "build",
	Short: "(alias for compile)",
	Run:   compileCmd.Run,
}

var generateCmd = &cobra.Command{
	Use:   "generate",
	Short: "(alias for compile)",
	Run:   compileCmd.Run,
}

func init() {
	RootCmd.AddCommand(compileCmd)
	RootCmd.AddCommand(buildCmd)
	RootCmd.AddCommand(generateCmd)
}

func compileContracts() error {
	if err := os.Chdir(ContractsDirectory); err != nil {
		return err
	}

	matches := make([]string, 0)
	err := filepath.Walk(".", func(path string, f os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		if strings.HasSuffix(path, ".sol") {
			matches = append(matches, path)
		}
		return nil
	})

	if err != nil {
		return err
	}

	if len(matches) == 0 {
		Fatal("No contracts found, create one with `perigord add contract NAME`")
	}

	command := "solc"
	_, err = exec.LookPath(command)
	if err != nil {
		return errors.New("Can't locate solc, is it installed and in your path")
	}

	dir, err := os.Getwd()
	if err != nil {
		return err
	}

	compilerConfig, err := templates.ExecuteTemplate("solc/solc.json.tpl", matches)
	if err != nil {
		return err
	}

	args := []string{"--allow-paths", dir, "--standard-json"}
	outputJson, err := ExecWithPipes(command, compilerConfig.Bytes(), args...)
	if err != nil {
		return err
	}

	if err = os.Chdir(".."); err != nil {
		return err
	}

	var output map[string]interface{}
	if err = json.Unmarshal(outputJson, &output); err != nil {
		return err
	}

	if err = handleErrors(output); err != nil {
		return err
	}

	return saveArtifacts(output)
}

func handleErrors(output map[string]interface{}) error {
	hasFatal := false
	compilerErrors, ok := output["errors"].([]interface{})
	if !ok {
		return errors.New("Invalid json")
	}

	for _, value := range compilerErrors {
		compilerErr, ok := value.(map[string]interface{})
		if !ok {
			return errors.New("Invalid json")
		}

		severity, ok := compilerErr["severity"].(string)
		if !ok {
			return errors.New("Invalid json")
		}

		message, ok := compilerErr["formattedMessage"].(string)
		if !ok {
			return errors.New("Invalid json")
		}

		if severity != "warning" {
			hasFatal = true
		}

		fmt.Println(message)
	}

	if hasFatal {
		return errors.New("Error detected, aborting. Please check solidity output for more details.")
	}

	return nil
}

func saveArtifacts(output map[string]interface{}) error {
	if err := os.MkdirAll(BuildDirectory, os.FileMode(0755)); err != nil {
		return err
	}

	contracts, ok := output["contracts"].(map[string]interface{})
	if !ok {
		return errors.New("Invalid json")
	}

	for _, value := range contracts {
		contract, ok := value.(map[string]interface{})
		if !ok {
			return errors.New("Invalid json")
		}

		for name, value := range contract {
			data, ok := value.(map[string]interface{})
			if !ok {
				return errors.New("Invalid json")
			}

			// Get ABI as a json blob
			abi, err := json.Marshal(data["abi"])
			if err != nil {
				return err
			}

			evm, ok := data["evm"].(map[string]interface{})
			if !ok {
				return errors.New("Invalid json")
			}

			bytecodeObject, ok := evm["bytecode"].(map[string]interface{})
			if !ok {
				return errors.New("Invalid json")
			}

			// Get bytecode as a bin
			bytecode, ok := bytecodeObject["object"].(string)
			if !ok {
				return errors.New("Invalid json")
			}

			// Get link references as a json blob
			linkReferences, err := json.Marshal(bytecodeObject["linkReferences"])
			if err != nil {
				return err
			}

			ioutil.WriteFile(filepath.Join(BuildDirectory, name+".abi"), abi, 0644)
			ioutil.WriteFile(filepath.Join(BuildDirectory, name+".bin"), []byte(bytecode), 0644)
			ioutil.WriteFile(filepath.Join(BuildDirectory, name+".link"), linkReferences, 0644)
		}
	}

	return nil
}

func generateBindings() error {
	return nil
	//	matches, err := filepath.Glob(BuildDirectory + "/*.abi")
	//	if err != nil {
	//		return err
	//	}
	//
	//	if err := os.MkdirAll(BindingsDirectory, os.FileMode(0755)); err != nil {
	//		return err
	//	}
	//
	//	for _, match := range matches {
	//		if err := generateBinding(strings.TrimSuffix(match, filepath.Ext(match))); err != nil {
	//			return err
	//		}
	//	}
	//
	//	return nil
}

func generateBinding(path string) error {
	return nil
	//	// TODO: Allow alternate binding directories / package names, in config file
	//	command := "abigen"
	//	_, err := exec.LookPath(command)
	//	if err != nil {
	//		return errors.New("Can't locate abigen, is it installed and in your path")
	//	}
	//
	//	name := filepath.Base(path)
	//	abifile := path + ".abi"
	//	binfile := path + ".bin"
	//	outfile := filepath.Join(BindingsDirectory, filepath.Base(name)) + ".go"
	//	args := []string{"--abi", abifile, "--bin", binfile, "--pkg", "bindings", "--type", name, "--out", outfile}
	//	return ExecWithOutput(command, args...)
}
<|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"path/filepath"
	"strings"

	"github.com/andygrunwald/perseus/config"
	"github.com/andygrunwald/perseus/downloader"
	"github.com/andygrunwald/perseus/packagist"
	"github.com/andygrunwald/perseus/perseus"
)

// AddCommand reflects the business logic and the Command interface to add a new package.
// This command is independent from an human interface (CLI, HTTP, etc.)
// The human interfaces will interact with this command.
type AddCommand struct {
	// WithDependencies decides if the dependencies of an external package needs to be mirrored as well
	WithDependencies bool
	// Package is the package to mirror
	Package string
	// Config is the main medusa configuration
	Config *config.Medusa
	// Log represents a logger to log messages
	Log *log.Logger
}

// downloadResult represents the result of a download
type downloadResult struct {
	Package string
	Error   error
}

// Run is the business logic of AddCommand.
func (c *AddCommand) Run() error {
	p, err := perseus.NewPackage(c.Package)
	if err != nil {
		return err
	}

	var satisRepositories []string

	// We don't respect the error here.
	// OH: "WTF? Why? You claim 'Serious error handling' in the README!"
	// Yep, you are right. And we still do.
	// In this case, it is okay, if p is not configured or no repositories are configured at all.
	// When this happen, we will ask Packagist fot the repository url.
	// If this package is not available on packagist, this will be shift to an error.
	p.Repository, _ = c.Config.GetRepositoryURLOfPackage(p)
	if p.Repository == nil {

		dependencies := []*perseus.Package{p}
		if c.WithDependencies {
			pUrl := "https://packagist.org/"
			c.Log.Printf("Loading dependencies for package \"%s\" from %s", c.Package, pUrl)
			packagistClient, err := packagist.New(pUrl, nil)
			if err != nil {
				return err
			}

			// TODO Okay, here we don't take error handling serious.
			//	Why? Easy. If an API request fails, we don't know it.
			//	Why? Easy. Which packages will be skipped? e.g. "php" ?
			//	We really have to refactor this. Checkout the articles / links
			//	That are mentioned IN the dependency resolver comments
			//	But you know. 1. Make it work. 2. Make it fast. 3. Make it beautiful
			// 	And this works for now.
			// TODO Make number of worker configurable
			d, err := perseus.NewDependencyResolver(p.Name, 3, packagistClient)
			if err != nil {
				return err
			}
			results := d.GetResultStream()
			go d.Start()

			dependencies := []string{}
			// Finally we collect all the results of the work.
			for v := range results {
				dependencies = append(dependencies, v.Package.Name)
			}

			// TODO List all deps here instead of the number
			c.Log.Printf("%d dependencies found for package \"%s\" on %s", len(dependencies), c.Package, pUrl)
		}

		// Download package incl. dependencies concurrent
		dependencyCount := len(dependencies)
		// TODO Check: Make it a difference to put a buffer in it vs. no buffer at all? Ask gopher channel!
		downloadsChan := make(chan downloadResult, dependencyCount)
		defer close(downloadsChan)
		c.startConcurrentDownloads(dependencies, downloadsChan)

		// Check which dependencies where download successful and which not
		satisRepositories = c.processFinishedDownloads(downloadsChan, dependencyCount)

	} else {
		c.Log.Printf("Mirroring of package \"%s\" from repository \"%s\" started", p.Name, p.Repository)
		// TODO: downloadPackage will write to p (name + Repository url), we should test this with a package that is deprecated.
		// Afaik Packagist will forward you to the new one.
		// Facebook SDK is one of those
		err := c.downloadPackage(p)
		if err != nil {
			if os.IsExist(err) {
				c.Log.Printf("Package \"%s\" exists on disk. Try updating it instead. Skipping.", p.Name)
			} else {
				return err
			}
		} else {
			c.Log.Printf("Mirroring of package \"%s\" successful", p.Name)
		}

		satisRepositories = append(satisRepositories, c.getLocalUrlForRepository(p.Name))
	}

	// Write Satis file
	satisConfig := c.Config.GetString("satisconfig")
	if len(satisConfig) == 0 {
		c.Log.Print("No Satis configuration specified. Skipping to write a satis configuration.")
		return nil
	}

	satisContent, err := ioutil.ReadFile(satisConfig)
	if err != nil {
		return fmt.Errorf("Can't read Satis configuration %s: %s", satisConfig, err)
	}

	j, err := config.NewJSONProvider(satisContent)
	if err != nil {
		return fmt.Errorf("Error while creating JSONProvider: %s", err)
	}

	s, err := config.NewSatis(j)
	if err != nil {
		return fmt.Errorf("Error while creating Satis object: %s", err)
	}

	s.AddRepositories(satisRepositories...)
	err = s.WriteFile(satisConfig, 0644)
	if err != nil {
		return fmt.Errorf("Writing Satis configuration to %s failed: %s", satisConfig, err)
	}

	c.Log.Printf("Satis configuration successful written to %s", satisConfig)

	return nil
}

func (c *AddCommand) getLocalUrlForRepository(p string) string {
	var r string

	satisURL := c.Config.GetString("satisurl")
	repoDir := c.Config.GetString("repodir")

	if len(satisURL) > 0 {
		r = fmt.Sprintf("%s/%s.git", satisURL, p)
	} else {
		t := fmt.Sprintf("%s/%s.git", repoDir, p)
		t = strings.TrimLeft(filepath.Clean(t), "/")
		r = fmt.Sprintf("file:///%s", t)
	}

	return r
}

func (c *AddCommand) downloadPackage(p *perseus.Package) error {
	repoDir := c.Config.GetString("repodir")
	// TODO Path traversal in p.Name possible?
	targetDir := fmt.Sprintf("%s/%s.git", repoDir, p.Name)

	// Does targetDir already exist?
	if _, err := os.Stat(targetDir); err != nil {
		if !os.IsNotExist(err) {
			return err
		}
	} else {
		return os.ErrExist
	}

	if p.Repository == nil {
		packagistClient, err := packagist.New("https://packagist.org/", nil)
		if err != nil {
			return fmt.Errorf("Packagist client creation failed: %s", err)
		}
		packagistPackage, resp, err := packagistClient.GetPackage(p.Name)
		if err != nil {
			return fmt.Errorf("Failed to retrieve information about package \"%s\" from Packagist. Called %s. Error: %s", p.Name, resp.Request.URL.String(), err)
		}

		// Check if URL is empty
		if len(packagistPackage.Repository) == 0 {
			// TODO What happens if Packagist rewrite the package? E.g. the facebook example? We should output here both names
			return fmt.Errorf("Received empty URL for package %s from Packagist", p.Name)
		}

		// Overwriting values from Packagist
		p.Name = packagistPackage.Name
		u, err := url.Parse(packagistPackage.Repository)
		if err != nil {
			return fmt.Errorf("URL conversion of %s to a net/url.URL object failed: %s", packagistPackage.Repository, err)
		}
		p.Repository = u
	}

	downloadClient, err := downloader.NewGit(p.Repository.String())
	if err != nil {
		return fmt.Errorf("Downloader client creation failed for package %s: %s", p.Name, err)
	}
	return downloadClient.Download(targetDir)
}

func (c *AddCommand) startConcurrentDownloads(dependencies []*perseus.Package, downloadChan chan<- downloadResult) {
	// Loop over all dependencies and download them concurrent
	for _, packet := range dependencies {
		c.Log.Printf("Mirroring of package \"%s\" started", packet.Name)

		go func(singlePacket *perseus.Package, ch chan<- downloadResult) {
			err := c.downloadPackage(singlePacket)
			ch <- downloadResult{
				Package: singlePacket.Name,
				Error:   err,
			}
		}(packet, downloadChan)
	}
}

func (c *AddCommand) processFinishedDownloads(ch <-chan downloadResult, dependencyCount int) []string {
	var success []string
	for i := 0; i < dependencyCount; i++ {
		download := <-ch
		if download.Error == nil {
			c.Log.Printf("Mirroring of package \"%s\" successful", download.Package)
			success = append(success, c.getLocalUrlForRepository(download.Package))
		} else {
			if os.IsExist(download.Error) {
				c.Log.Printf("Package \"%s\" exists on disk. Try updating it instead. Skipping.", download.Package)
			} else {
				c.Log.Printf("Error while mirroring package \"%s\": %s", download.Package, download.Error)
			}
		}
	}

	return success
}
<commit_msg>List all found dependencies<commit_after>package commands

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"path/filepath"
	"strings"

	"github.com/andygrunwald/perseus/config"
	"github.com/andygrunwald/perseus/downloader"
	"github.com/andygrunwald/perseus/packagist"
	"github.com/andygrunwald/perseus/perseus"
)

// AddCommand reflects the business logic and the Command interface to add a new package.
// This command is independent from an human interface (CLI, HTTP, etc.)
// The human interfaces will interact with this command.
type AddCommand struct {
	// WithDependencies decides if the dependencies of an external package needs to be mirrored as well
	WithDependencies bool
	// Package is the package to mirror
	Package string
	// Config is the main medusa configuration
	Config *config.Medusa
	// Log represents a logger to log messages
	Log *log.Logger
}

// downloadResult represents the result of a download
type downloadResult struct {
	Package string
	Error   error
}

// Run is the business logic of AddCommand.
func (c *AddCommand) Run() error {
	p, err := perseus.NewPackage(c.Package)
	if err != nil {
		return err
	}

	var satisRepositories []string

	// We don't respect the error here.
	// OH: "WTF? Why? You claim 'Serious error handling' in the README!"
	// Yep, you are right. And we still do.
	// In this case, it is okay, if p is not configured or no repositories are configured at all.
	// When this happen, we will ask Packagist fot the repository url.
	// If this package is not available on packagist, this will be shift to an error.
	p.Repository, _ = c.Config.GetRepositoryURLOfPackage(p)
	if p.Repository == nil {

		dependencies := []*perseus.Package{p}
		if c.WithDependencies {
			pUrl := "https://packagist.org/"
			c.Log.Printf("Loading dependencies for package \"%s\" from %s", c.Package, pUrl)
			packagistClient, err := packagist.New(pUrl, nil)
			if err != nil {
				return err
			}

			// TODO Okay, here we don't take error handling serious.
			//	Why? Easy. If an API request fails, we don't know it.
			//	Why? Easy. Which packages will be skipped? e.g. "php" ?
			//	We really have to refactor this. Checkout the articles / links
			//	That are mentioned IN the dependency resolver comments
			//	But you know. 1. Make it work. 2. Make it fast. 3. Make it beautiful
			// 	And this works for now.
			// TODO Make number of worker configurable
			d, err := perseus.NewDependencyResolver(p.Name, 3, packagistClient)
			if err != nil {
				return err
			}
			results := d.GetResultStream()
			go d.Start()

			dependencies := []string{}
			// Finally we collect all the results of the work.
			for v := range results {
				dependencies = append(dependencies, v.Package.Name)
			}

			c.Log.Printf("%d dependencies found for package \"%s\" on %s: %s", len(dependencies), c.Package, pUrl, strings.Join(dependencies, ", "))
		}

		// Download package incl. dependencies concurrent
		dependencyCount := len(dependencies)
		// TODO Check: Make it a difference to put a buffer in it vs. no buffer at all? Ask gopher channel!
		downloadsChan := make(chan downloadResult, dependencyCount)
		defer close(downloadsChan)
		c.startConcurrentDownloads(dependencies, downloadsChan)

		// Check which dependencies where download successful and which not
		satisRepositories = c.processFinishedDownloads(downloadsChan, dependencyCount)

	} else {
		c.Log.Printf("Mirroring of package \"%s\" from repository \"%s\" started", p.Name, p.Repository)
		// TODO: downloadPackage will write to p (name + Repository url), we should test this with a package that is deprecated.
		// Afaik Packagist will forward you to the new one.
		// Facebook SDK is one of those
		err := c.downloadPackage(p)
		if err != nil {
			if os.IsExist(err) {
				c.Log.Printf("Package \"%s\" exists on disk. Try updating it instead. Skipping.", p.Name)
			} else {
				return err
			}
		} else {
			c.Log.Printf("Mirroring of package \"%s\" successful", p.Name)
		}

		satisRepositories = append(satisRepositories, c.getLocalUrlForRepository(p.Name))
	}

	// Write Satis file
	satisConfig := c.Config.GetString("satisconfig")
	if len(satisConfig) == 0 {
		c.Log.Print("No Satis configuration specified. Skipping to write a satis configuration.")
		return nil
	}

	satisContent, err := ioutil.ReadFile(satisConfig)
	if err != nil {
		return fmt.Errorf("Can't read Satis configuration %s: %s", satisConfig, err)
	}

	j, err := config.NewJSONProvider(satisContent)
	if err != nil {
		return fmt.Errorf("Error while creating JSONProvider: %s", err)
	}

	s, err := config.NewSatis(j)
	if err != nil {
		return fmt.Errorf("Error while creating Satis object: %s", err)
	}

	s.AddRepositories(satisRepositories...)
	err = s.WriteFile(satisConfig, 0644)
	if err != nil {
		return fmt.Errorf("Writing Satis configuration to %s failed: %s", satisConfig, err)
	}

	c.Log.Printf("Satis configuration successful written to %s", satisConfig)

	return nil
}

func (c *AddCommand) getLocalUrlForRepository(p string) string {
	var r string

	satisURL := c.Config.GetString("satisurl")
	repoDir := c.Config.GetString("repodir")

	if len(satisURL) > 0 {
		r = fmt.Sprintf("%s/%s.git", satisURL, p)
	} else {
		t := fmt.Sprintf("%s/%s.git", repoDir, p)
		t = strings.TrimLeft(filepath.Clean(t), "/")
		r = fmt.Sprintf("file:///%s", t)
	}

	return r
}

func (c *AddCommand) downloadPackage(p *perseus.Package) error {
	repoDir := c.Config.GetString("repodir")
	// TODO Path traversal in p.Name possible?
	targetDir := fmt.Sprintf("%s/%s.git", repoDir, p.Name)

	// Does targetDir already exist?
	if _, err := os.Stat(targetDir); err != nil {
		if !os.IsNotExist(err) {
			return err
		}
	} else {
		return os.ErrExist
	}

	if p.Repository == nil {
		packagistClient, err := packagist.New("https://packagist.org/", nil)
		if err != nil {
			return fmt.Errorf("Packagist client creation failed: %s", err)
		}
		packagistPackage, resp, err := packagistClient.GetPackage(p.Name)
		if err != nil {
			return fmt.Errorf("Failed to retrieve information about package \"%s\" from Packagist. Called %s. Error: %s", p.Name, resp.Request.URL.String(), err)
		}

		// Check if URL is empty
		if len(packagistPackage.Repository) == 0 {
			// TODO What happens if Packagist rewrite the package? E.g. the facebook example? We should output here both names
			return fmt.Errorf("Received empty URL for package %s from Packagist", p.Name)
		}

		// Overwriting values from Packagist
		p.Name = packagistPackage.Name
		u, err := url.Parse(packagistPackage.Repository)
		if err != nil {
			return fmt.Errorf("URL conversion of %s to a net/url.URL object failed: %s", packagistPackage.Repository, err)
		}
		p.Repository = u
	}

	downloadClient, err := downloader.NewGit(p.Repository.String())
	if err != nil {
		return fmt.Errorf("Downloader client creation failed for package %s: %s", p.Name, err)
	}
	return downloadClient.Download(targetDir)
}

func (c *AddCommand) startConcurrentDownloads(dependencies []*perseus.Package, downloadChan chan<- downloadResult) {
	// Loop over all dependencies and download them concurrent
	for _, packet := range dependencies {
		c.Log.Printf("Mirroring of package \"%s\" started", packet.Name)

		go func(singlePacket *perseus.Package, ch chan<- downloadResult) {
			err := c.downloadPackage(singlePacket)
			ch <- downloadResult{
				Package: singlePacket.Name,
				Error:   err,
			}
		}(packet, downloadChan)
	}
}

func (c *AddCommand) processFinishedDownloads(ch <-chan downloadResult, dependencyCount int) []string {
	var success []string
	for i := 0; i < dependencyCount; i++ {
		download := <-ch
		if download.Error == nil {
			c.Log.Printf("Mirroring of package \"%s\" successful", download.Package)
			success = append(success, c.getLocalUrlForRepository(download.Package))
		} else {
			if os.IsExist(download.Error) {
				c.Log.Printf("Package \"%s\" exists on disk. Try updating it instead. Skipping.", download.Package)
			} else {
				c.Log.Printf("Error while mirroring package \"%s\": %s", download.Package, download.Error)
			}
		}
	}

	return success
}
<|endoftext|>


<commit_before>package oauth2

import (
	"context"
	"database/sql"
	"sync"

	"github.com/vardius/go-api-boilerplate/pkg/errors"
	"github.com/vardius/golog"
	oauth2 "gopkg.in/oauth2.v3"
	oauth2_errors "gopkg.in/oauth2.v3/errors"
	oauth2_server "gopkg.in/oauth2.v3/server"
)

var (
	gServer    *oauth2_server.Server
	onceServer sync.Once
)

// InitServer initialize the oauth2 server instance
func InitServer(manager oauth2.Manager, db *sql.DB, logger golog.Logger, secretKey string) *oauth2_server.Server {
	onceServer.Do(func() {
		gServer = oauth2_server.NewDefaultServer(manager)

		gServer.SetAllowedGrantType(oauth2.PasswordCredentials, oauth2.Refreshing)
		gServer.SetClientInfoHandler(oauth2_server.ClientFormHandler)

		gServer.SetPasswordAuthorizationHandler(func(email, password string) (userID string, err error) {
			// we allow password grant only within our system, due to email passwordless authentication
			// password value here should contain secretKey
			if password == secretKey {
				userID, err = getUserIDByEmail(context.Background(), db, email)
			} else {
				err = errors.Wrap(err, errors.UNAUTHORIZED, "Invalid client, user password does not match secret key")
			}

			if err != nil {
				logger.Error(context.Background(), "oAuth2 PasswordAuthorizationHandler Error [email <%s> password <%s> secretKey <%s>] %v\n", email, password, secretKey, err)
			}
			return
		})

		gServer.SetInternalErrorHandler(func(err error) (re *oauth2_errors.Response) {
			logger.Error(context.Background(), "oAuth2 Internal Error: %v\n", err)
			return
		})

		gServer.SetResponseErrorHandler(func(re *oauth2_errors.Response) {
			logger.Error(context.Background(), "oAuth2 Response Error %v\n", re.Error)
		})
	})

	return gServer
}

func getUserIDByEmail(ctx context.Context, db *sql.DB, email string) (id string, err error) {
	row := db.QueryRowContext(ctx, `SELECT id FROM users WHERE emailAddress=?`, email)
	e := row.Scan(&id)

	switch {
	case e == sql.ErrNoRows:
		err = errors.Wrap(err, errors.NOTFOUND, "User ID not found")
	case e != nil:
		err = errors.Wrap(err, errors.INTERNAL, "Error while scanning users table")
	}

	return
}
<commit_msg>Wrap errors<commit_after>package oauth2

import (
	"context"
	"database/sql"
	"sync"

	"github.com/vardius/go-api-boilerplate/pkg/errors"
	"github.com/vardius/golog"
	oauth2 "gopkg.in/oauth2.v3"
	oauth2_errors "gopkg.in/oauth2.v3/errors"
	oauth2_server "gopkg.in/oauth2.v3/server"
)

var (
	gServer    *oauth2_server.Server
	onceServer sync.Once
)

// InitServer initialize the oauth2 server instance
func InitServer(manager oauth2.Manager, db *sql.DB, logger golog.Logger, secretKey string) *oauth2_server.Server {
	onceServer.Do(func() {
		gServer = oauth2_server.NewDefaultServer(manager)

		gServer.SetAllowedGrantType(oauth2.PasswordCredentials, oauth2.Refreshing)
		gServer.SetClientInfoHandler(oauth2_server.ClientFormHandler)

		gServer.SetPasswordAuthorizationHandler(func(email, password string) (string, error) {
			// we allow password grant only within our system, due to email passwordless authentication
			// password value here should contain secretKey
			if password != secretKey {
				return "", errors.New(errors.UNAUTHORIZED, "Invalid client, user password does not match secret key")
			}

			userID, err := getUserIDByEmail(context.Background(), db, email)
			if err != nil {
				return "", errors.Wrapf(err, errors.UNAUTHORIZED, "Could not find user id for given email (%s)", email)
			}

			return userID, nil
		})

		gServer.SetInternalErrorHandler(func(err error) (re *oauth2_errors.Response) {
			logger.Error(context.Background(), "oAuth2 Server internal error: %s\n", err.Error())
			return &oauth2_errors.Response{
				Error: errors.Wrap(err, errors.INTERNAL, "Internal error"),
			}
		})

		gServer.SetResponseErrorHandler(func(re *oauth2_errors.Response) {
			logger.Error(context.Background(), "oAuth2 Server response error: %s\n%v\n", re.Error.Error(), re)
		})
	})

	return gServer
}

func getUserIDByEmail(ctx context.Context, db *sql.DB, email string) (id string, err error) {
	row := db.QueryRowContext(ctx, `SELECT id FROM users WHERE emailAddress=?`, email)
	e := row.Scan(&id)

	switch {
	case e == sql.ErrNoRows:
		err = errors.Wrap(err, errors.NOTFOUND, "User ID not found")
	case e != nil:
		err = errors.Wrap(err, errors.INTERNAL, "Error while scanning users table")
	}

	return
}
<|endoftext|>


<commit_before>package admin

import (
	"errors"
	"fmt"

	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/app"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/app/args"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/app/with"
	"github.com/BytemarkHosting/bytemark-client/lib"
	"github.com/BytemarkHosting/bytemark-client/lib/billing"
	"github.com/BytemarkHosting/bytemark-client/lib/brain"
	billingMethods "github.com/BytemarkHosting/bytemark-client/lib/requests/billing"
	brainMethods "github.com/BytemarkHosting/bytemark-client/lib/requests/brain"
	"github.com/BytemarkHosting/bytemark-client/util/log"
	"github.com/urfave/cli"
)

func init() {
	readUpdateFlags := func(c *app.Context) (usageStrategy *string, overcommitRatio *int, label *string) {
		if c.Context.IsSet("usage-strategy") {
			v := c.String("usage-strategy")
			usageStrategy = &v
		}

		if c.Context.IsSet("overcommit-ratio") {
			v := c.Int("overcommit-ratio")
			overcommitRatio = &v
		}

		if c.Context.IsSet("label") {
			v := c.String("label")
			label = &v
		}

		return
	}

	Commands = append(Commands, cli.Command{
		Name:   "update",
		Action: cli.ShowSubcommandHelp,
		Subcommands: []cli.Command{
			{
				Name:      "billing-definition",
				Usage:     "update a bmbilling definition",
				UsageText: "bytemark --admin update billing-definition [flags] [name] [value]",
				Flags: []cli.Flag{
					cli.StringFlag{
						Name:  "name",
						Usage: "the name of the definition to set",
					},
					cli.StringFlag{
						Name:  "value",
						Usage: "the value of the definition to set",
					},
					cli.StringFlag{
						Name:  "group",
						Usage: "the group a user must be in to update the definition",
					},
				},
				Action: app.Action(args.Optional("name", "value"), with.RequiredFlags("name", "value"), with.Auth, func(ctx *app.Context) error {
					def := billing.Definition{
						Name:           ctx.String("name"),
						Value:          ctx.String("value"),
						UpdateGroupReq: ctx.String("group"),
					}
					if _, err := billingMethods.GetDefinition(ctx.Client(), def.Name); err != nil {
						if _, ok := err.(lib.NotFoundError); ok {
							ctx.LogErr("Couldn't find a definition called %s - aborting.", def.Name)
							return nil
						}
						return err
					}
					err := billingMethods.UpdateDefinition(ctx.Client(), def)
					if err == nil {
						ctx.LogErr("Updated %s to %s", def.Name, def.Value)
					}
					return err

				}),
			}, {
				Name:      "head",
				Usage:     "update the settings of a head",
				UsageText: "bytemark --admin update head <head> [--usage-strategy] [--overcommit-ratio] [--label]",
				Flags: []cli.Flag{
					cli.StringFlag{
						Name:  "head",
						Usage: "the ID or label of the head to be updated",
					},
					cli.StringFlag{
						Name:  "usage-strategy",
						Usage: "the usage strategy of the head",
					},
					cli.IntFlag{
						Name:  "overcommit-ratio",
						Usage: "the overcommit ratio of the head",
					},
					cli.StringFlag{
						Name:  "label",
						Usage: "the label of the head",
					},
				},
				Action: app.Action(args.Optional("head", "usage-strategy", "overcommit-ratio", "label"), with.RequiredFlags("head"), with.Auth, func(c *app.Context) error {
					usageStrategy, overcommitRatio, label := readUpdateFlags(c)

					options := lib.UpdateHead{
						UsageStrategy:   usageStrategy,
						OvercommitRatio: overcommitRatio,
						Label:           label,
					}

					if err := c.Client().UpdateHead(c.String("head"), options); err != nil {
						return err
					}

					log.Outputf("Head %s updated\n", c.String("head"))

					return nil
				}),
			},
			{
				Name:      "tail",
				Usage:     "update the settings of a tail",
				UsageText: "bytemark --admin update tail <tail> [--usage-strategy] [--overcommit-ratio] [--label]",
				Flags: []cli.Flag{
					cli.StringFlag{
						Name:  "tail",
						Usage: "the ID or label of the tail to be updated",
					},
					cli.StringFlag{
						Name:  "usage-strategy",
						Usage: "the usage strategy of the tail",
					},
					cli.IntFlag{
						Name:  "overcommit-ratio",
						Usage: "the overcommit ratio of the tail",
					},
					cli.StringFlag{
						Name:  "label",
						Usage: "the label of the tail",
					},
				},
				Action: app.Action(args.Optional("tail", "usage-strategy", "overcommit-ratio", "label"), with.RequiredFlags("tail"), with.Auth, func(c *app.Context) error {
					usageStrategy, overcommitRatio, label := readUpdateFlags(c)

					options := lib.UpdateTail{
						UsageStrategy:   usageStrategy,
						OvercommitRatio: overcommitRatio,
						Label:           label,
					}

					if err := c.Client().UpdateTail(c.String("tail"), options); err != nil {
						return err
					}

					log.Outputf("Tail %s updated\n", c.String("tail"))

					return nil
				}),
			},
			{
				Name:      "storage pool",
				Usage:     "update the settings of a storage pool",
				UsageText: "bytemark --admin update storage pool [--usage-strategy new-strategy] [--overcommit-ratio new-ratio] [--label new-label] [--migration-concurrency new-limit] <storage pool>",
				Flags: []cli.Flag{
					cli.StringFlag{
						Name:  "storage-pool",
						Usage: "the ID or label of the storage pool to be updated",
					},
					cli.StringFlag{
						Name:  "usage-strategy",
						Usage: "the usage strategy of the storage pool",
					},
					cli.IntFlag{
						Name:  "overcommit-ratio",
						Usage: "the overcommit ratio of the storage pool",
					},
					cli.StringFlag{
						Name:  "label",
						Usage: "the label of the storage pool",
					},
					cli.IntFlag{
						Name:  "migration-concurrency",
						Usage: "the number of concurrent migrations the storage pool can handle",
					},
				},
				Action: app.Action(args.Optional("storage-pool", "usage-strategy", "overcommit-ratio"), with.RequiredFlags("storage-pool"), with.Auth, func(c *app.Context) error {

					options := brain.StoragePool{
						UsageStrategy:        c.String("usage-strategy"),
						OvercommitRatio:      c.Int("overcommit-ratio"),
						Label:                c.String("label"),
						MigrationConcurrency: c.Int("migration-concurrency"),
					}

					if err := c.Client().UpdateStoragePool(c.String("storage-pool"), options); err != nil {
						return err
					}

					log.Outputf("Storage pool %s updated\n", c.String("storage-pool"))

					return nil
				}),
			},
			{
				Name:    "server",
				Aliases: []string{"vm"},
				Action:  cli.ShowSubcommandHelp,
				Subcommands: []cli.Command{
					{
						Name:        "migration",
						Usage:       "update the settings of an in-progress migration",
						UsageText:   "bytemark --admin update server migration <name> [--migrate-speed] [--migrate-downtime]",
						Description: `This command migrates a server to a new head. If a new head isn't supplied, a new one is picked automatically.`,
						Flags: []cli.Flag{
							cli.GenericFlag{
								Name:  "server",
								Usage: "the server to migrate",
								Value: new(app.VirtualMachineNameFlag),
							},
							cli.Int64Flag{
								Name:  "migrate-speed",
								Usage: "the max speed to migrate the server at",
							},
							cli.IntFlag{
								Name:  "migrate-downtime",
								Usage: "the max allowed downtime",
							},
						},
						Action: app.Action(args.Optional("server", "migrate-speed", "migrate-downtime"), with.RequiredFlags("server"), with.Auth, func(c *app.Context) error {
							vm := c.VirtualMachineName("server")

							var speed *int64
							var downtime *int

							if c.Context.IsSet("migrate-speed") {
								s := c.Int64("migrate-speed")
								speed = &s
							}
							if c.Context.IsSet("migrate-downtime") {
								d := c.Int("migrate-downtime")
								downtime = &d
							}

							if speed == nil && downtime == nil {
								return errors.New("Nothing to update")
							}

							if err := c.Client().UpdateVMMigration(vm, speed, downtime); err != nil {
								return err
							}

							log.Outputf("Migration for server %s updated\n", vm.String())

							return nil
						}),
					},
				},
			},
			{
				Name:        "migration",
				Usage:       "update a migration",
				UsageText:   "bbytemark --admin update migration --id 123 --priority 10 --cancel-disc disc1 --cancel-pool pool2 --cancel-tail tail3 | --cancel-all",
				Description: `This command allows you to update an ongoing migration job by altering its priority, cancelling migrating discs, pools, tails, or canceling everything for the current job`,
				Flags: []cli.Flag{
					cli.IntFlag{
						Name:  "id",
						Usage: "the id of the migration job",
					},
					cli.IntFlag{
						Name:  "priority",
						Usage: "the priority of the current job",
					},
					cli.StringSliceFlag{
						Name:  "cancel-disc",
						Usage: "the disc(s) to cancel migration of",
					},
					cli.StringSliceFlag{
						Name:  "cancel-pool",
						Usage: "the pool(s) to cancel migration of",
					},
					cli.StringSliceFlag{
						Name:  "cancel-tail",
						Usage: "the tail(s) to cancel migration of",
					},
					cli.BoolFlag{
						Name:  "cancel-all",
						Usage: "cancel the all migrations of the job",
					},
				},
				Action: app.Action(with.RequiredFlags("id"), with.Auth, func(c *app.Context) error {
					// read all flags?
					discs := c.Context.StringSlice("cancel-disc")
					pools := c.Context.StringSlice("cancel-pool")
					tails := c.Context.StringSlice("cancel-tail")

					totalLength := append(discs, pools...)
					totalLength = append(totalLength, tails...)

					// check the presence of cancel all first
					if c.Context.IsSet("cancel-all") {
						if len(totalLength) > 0 {

							return fmt.Errorf("You have set additional flags as well as --cancel-all. Nothing else can be specified when --cancel-all has been set.")
						}

						err := brainMethods.CancelMigrationJob(c.Client(), c.Context.Int("id"))
						if err != nil {
							return err
						}
						c.LogErr("All migrations for job %d have been cancelled.", c.Context.Int("id"))

						// make the call to the cancel all migration.
					}

					modifications := brain.MigrationJobModification{
						Cancel: brain.MigrationJobLocations{
							Discs: stringsToJsonNumbers(discs),
							Pools: stringsToJsonNumbers(pools),
							Tails: stringsToJsonNumbers(tails),
						},
						Options: brain.MigrationJobOptions{
							Priority: c.Context.Int("priority"),
						},
					}

					err := brainMethods.EditMigrationJob(c.Client(), c.Context.Int("id"), modifications)
					if err != nil {
						return err
					}

					// if we have set a new priority, show a message.
					c.LogErr("Priority updated for Job %d", c.Context.Int("id"))

					// not really sure if we should be showing a confirmation message for all individual things that have been cancelled.
					return err
				}),
			},
		},
	})
}
<commit_msg>add an id variable seeing as though it is used a lot<commit_after>package admin

import (
	"errors"
	"fmt"

	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/app"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/app/args"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/app/with"
	"github.com/BytemarkHosting/bytemark-client/lib"
	"github.com/BytemarkHosting/bytemark-client/lib/billing"
	"github.com/BytemarkHosting/bytemark-client/lib/brain"
	billingMethods "github.com/BytemarkHosting/bytemark-client/lib/requests/billing"
	brainMethods "github.com/BytemarkHosting/bytemark-client/lib/requests/brain"
	"github.com/BytemarkHosting/bytemark-client/util/log"
	"github.com/urfave/cli"
)

func init() {
	readUpdateFlags := func(c *app.Context) (usageStrategy *string, overcommitRatio *int, label *string) {
		if c.Context.IsSet("usage-strategy") {
			v := c.String("usage-strategy")
			usageStrategy = &v
		}

		if c.Context.IsSet("overcommit-ratio") {
			v := c.Int("overcommit-ratio")
			overcommitRatio = &v
		}

		if c.Context.IsSet("label") {
			v := c.String("label")
			label = &v
		}

		return
	}

	Commands = append(Commands, cli.Command{
		Name:   "update",
		Action: cli.ShowSubcommandHelp,
		Subcommands: []cli.Command{
			{
				Name:      "billing-definition",
				Usage:     "update a bmbilling definition",
				UsageText: "bytemark --admin update billing-definition [flags] [name] [value]",
				Flags: []cli.Flag{
					cli.StringFlag{
						Name:  "name",
						Usage: "the name of the definition to set",
					},
					cli.StringFlag{
						Name:  "value",
						Usage: "the value of the definition to set",
					},
					cli.StringFlag{
						Name:  "group",
						Usage: "the group a user must be in to update the definition",
					},
				},
				Action: app.Action(args.Optional("name", "value"), with.RequiredFlags("name", "value"), with.Auth, func(ctx *app.Context) error {
					def := billing.Definition{
						Name:           ctx.String("name"),
						Value:          ctx.String("value"),
						UpdateGroupReq: ctx.String("group"),
					}
					if _, err := billingMethods.GetDefinition(ctx.Client(), def.Name); err != nil {
						if _, ok := err.(lib.NotFoundError); ok {
							ctx.LogErr("Couldn't find a definition called %s - aborting.", def.Name)
							return nil
						}
						return err
					}
					err := billingMethods.UpdateDefinition(ctx.Client(), def)
					if err == nil {
						ctx.LogErr("Updated %s to %s", def.Name, def.Value)
					}
					return err

				}),
			}, {
				Name:      "head",
				Usage:     "update the settings of a head",
				UsageText: "bytemark --admin update head <head> [--usage-strategy] [--overcommit-ratio] [--label]",
				Flags: []cli.Flag{
					cli.StringFlag{
						Name:  "head",
						Usage: "the ID or label of the head to be updated",
					},
					cli.StringFlag{
						Name:  "usage-strategy",
						Usage: "the usage strategy of the head",
					},
					cli.IntFlag{
						Name:  "overcommit-ratio",
						Usage: "the overcommit ratio of the head",
					},
					cli.StringFlag{
						Name:  "label",
						Usage: "the label of the head",
					},
				},
				Action: app.Action(args.Optional("head", "usage-strategy", "overcommit-ratio", "label"), with.RequiredFlags("head"), with.Auth, func(c *app.Context) error {
					usageStrategy, overcommitRatio, label := readUpdateFlags(c)

					options := lib.UpdateHead{
						UsageStrategy:   usageStrategy,
						OvercommitRatio: overcommitRatio,
						Label:           label,
					}

					if err := c.Client().UpdateHead(c.String("head"), options); err != nil {
						return err
					}

					log.Outputf("Head %s updated\n", c.String("head"))

					return nil
				}),
			},
			{
				Name:      "tail",
				Usage:     "update the settings of a tail",
				UsageText: "bytemark --admin update tail <tail> [--usage-strategy] [--overcommit-ratio] [--label]",
				Flags: []cli.Flag{
					cli.StringFlag{
						Name:  "tail",
						Usage: "the ID or label of the tail to be updated",
					},
					cli.StringFlag{
						Name:  "usage-strategy",
						Usage: "the usage strategy of the tail",
					},
					cli.IntFlag{
						Name:  "overcommit-ratio",
						Usage: "the overcommit ratio of the tail",
					},
					cli.StringFlag{
						Name:  "label",
						Usage: "the label of the tail",
					},
				},
				Action: app.Action(args.Optional("tail", "usage-strategy", "overcommit-ratio", "label"), with.RequiredFlags("tail"), with.Auth, func(c *app.Context) error {
					usageStrategy, overcommitRatio, label := readUpdateFlags(c)

					options := lib.UpdateTail{
						UsageStrategy:   usageStrategy,
						OvercommitRatio: overcommitRatio,
						Label:           label,
					}

					if err := c.Client().UpdateTail(c.String("tail"), options); err != nil {
						return err
					}

					log.Outputf("Tail %s updated\n", c.String("tail"))

					return nil
				}),
			},
			{
				Name:      "storage pool",
				Usage:     "update the settings of a storage pool",
				UsageText: "bytemark --admin update storage pool [--usage-strategy new-strategy] [--overcommit-ratio new-ratio] [--label new-label] [--migration-concurrency new-limit] <storage pool>",
				Flags: []cli.Flag{
					cli.StringFlag{
						Name:  "storage-pool",
						Usage: "the ID or label of the storage pool to be updated",
					},
					cli.StringFlag{
						Name:  "usage-strategy",
						Usage: "the usage strategy of the storage pool",
					},
					cli.IntFlag{
						Name:  "overcommit-ratio",
						Usage: "the overcommit ratio of the storage pool",
					},
					cli.StringFlag{
						Name:  "label",
						Usage: "the label of the storage pool",
					},
					cli.IntFlag{
						Name:  "migration-concurrency",
						Usage: "the number of concurrent migrations the storage pool can handle",
					},
				},
				Action: app.Action(args.Optional("storage-pool", "usage-strategy", "overcommit-ratio"), with.RequiredFlags("storage-pool"), with.Auth, func(c *app.Context) error {

					options := brain.StoragePool{
						UsageStrategy:        c.String("usage-strategy"),
						OvercommitRatio:      c.Int("overcommit-ratio"),
						Label:                c.String("label"),
						MigrationConcurrency: c.Int("migration-concurrency"),
					}

					if err := c.Client().UpdateStoragePool(c.String("storage-pool"), options); err != nil {
						return err
					}

					log.Outputf("Storage pool %s updated\n", c.String("storage-pool"))

					return nil
				}),
			},
			{
				Name:    "server",
				Aliases: []string{"vm"},
				Action:  cli.ShowSubcommandHelp,
				Subcommands: []cli.Command{
					{
						Name:        "migration",
						Usage:       "update the settings of an in-progress migration",
						UsageText:   "bytemark --admin update server migration <name> [--migrate-speed] [--migrate-downtime]",
						Description: `This command migrates a server to a new head. If a new head isn't supplied, a new one is picked automatically.`,
						Flags: []cli.Flag{
							cli.GenericFlag{
								Name:  "server",
								Usage: "the server to migrate",
								Value: new(app.VirtualMachineNameFlag),
							},
							cli.Int64Flag{
								Name:  "migrate-speed",
								Usage: "the max speed to migrate the server at",
							},
							cli.IntFlag{
								Name:  "migrate-downtime",
								Usage: "the max allowed downtime",
							},
						},
						Action: app.Action(args.Optional("server", "migrate-speed", "migrate-downtime"), with.RequiredFlags("server"), with.Auth, func(c *app.Context) error {
							vm := c.VirtualMachineName("server")

							var speed *int64
							var downtime *int

							if c.Context.IsSet("migrate-speed") {
								s := c.Int64("migrate-speed")
								speed = &s
							}
							if c.Context.IsSet("migrate-downtime") {
								d := c.Int("migrate-downtime")
								downtime = &d
							}

							if speed == nil && downtime == nil {
								return errors.New("Nothing to update")
							}

							if err := c.Client().UpdateVMMigration(vm, speed, downtime); err != nil {
								return err
							}

							log.Outputf("Migration for server %s updated\n", vm.String())

							return nil
						}),
					},
				},
			},
			{
				Name:        "migration",
				Usage:       "update a migration",
				UsageText:   "bbytemark --admin update migration --id 123 --priority 10 --cancel-disc disc1 --cancel-pool pool2 --cancel-tail tail3 | --cancel-all",
				Description: `This command allows you to update an ongoing migration job by altering its priority, cancelling migrating discs, pools, tails, or canceling everything for the current job`,
				Flags: []cli.Flag{
					cli.IntFlag{
						Name:  "id",
						Usage: "the id of the migration job",
					},
					cli.IntFlag{
						Name:  "priority",
						Usage: "the priority of the current job",
					},
					cli.StringSliceFlag{
						Name:  "cancel-disc",
						Usage: "the disc(s) to cancel migration of",
					},
					cli.StringSliceFlag{
						Name:  "cancel-pool",
						Usage: "the pool(s) to cancel migration of",
					},
					cli.StringSliceFlag{
						Name:  "cancel-tail",
						Usage: "the tail(s) to cancel migration of",
					},
					cli.BoolFlag{
						Name:  "cancel-all",
						Usage: "cancel the all migrations of the job",
					},
				},
				Action: app.Action(with.RequiredFlags("id"), with.Auth, func(c *app.Context) error {
					// read all flags?
					id := c.Context.Int("id")
					discs := c.Context.StringSlice("cancel-disc")
					pools := c.Context.StringSlice("cancel-pool")
					tails := c.Context.StringSlice("cancel-tail")

					totalLength := append(discs, pools...)
					totalLength = append(totalLength, tails...)

					// check the presence of cancel all first
					if c.Context.IsSet("cancel-all") {
						if len(totalLength) > 0 {

							return fmt.Errorf("You have set additional flags as well as --cancel-all. Nothing else can be specified when --cancel-all has been set.")
						}

						err := brainMethods.CancelMigrationJob(c.Client(), id)
						if err != nil {
							return err
						}
						c.LogErr("All migrations for job %d have been cancelled.", id)

						// make the call to the cancel all migration.
					}

					modifications := brain.MigrationJobModification{
						Cancel: brain.MigrationJobLocations{
							Discs: stringsToJsonNumbers(discs),
							Pools: stringsToJsonNumbers(pools),
							Tails: stringsToJsonNumbers(tails),
						},
						Options: brain.MigrationJobOptions{
							Priority: c.Context.Int("priority"),
						},
					}

					err := brainMethods.EditMigrationJob(c.Client(), id, modifications)
					if err != nil {
						return err
					}

					// if we have set a new priority, show a message.
					c.LogErr("Priority updated for Job %d", id)

					// not really sure if we should be showing a confirmation message for all individual things that have been cancelled.
					return err
				}),
			},
		},
	})
}
<|endoftext|>