<commit_before>package account

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/cozy/cozy-stack/model/instance"
	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/couchdb/mango"
)

var accountsClient = &http.Client{
	Timeout: 15 * time.Second,
}

// This file contains the account_type object as defined in
// docs/konnectors-workflow.md

// Various grant types
// - AuthorizationCode is the server-side grant type.
// - ImplicitGrant is the implicit grant type
// - ImplicitGrantRedirectURL is the implicit grant type but with redirect_url
//    											  instead of redirect_uri
const (
	AuthorizationCode        = "authorization_code"
	ImplicitGrant            = "token"
	ImplicitGrantRedirectURL = "token_redirect_url"
)

// Token Request authentication modes for AuthorizationCode grant type
// normal is through form parameters
// some services requires it as Basic
const (
	FormTokenAuthMode  = "form"
	BasicTokenAuthMode = "basic"
	GetTokenAuthMode   = "get"
)

// RefreshToken is the refresh grant type
var RefreshToken = "refresh_token"

// ErrUnrefreshable is the error when an account type or information
// within an account does not allow refreshing it.
var ErrUnrefreshable = errors.New("this account can not be refreshed")

// AccountType holds configuration information for
type AccountType struct {
	DocID                 string            `json:"_id,omitempty"`
	DocRev                string            `json:"_rev,omitempty"`
	GrantMode             string            `json:"grant_mode,omitempty"`
	ClientID              string            `json:"client_id,omitempty"`
	ClientSecret          string            `json:"client_secret,omitempty"`
	AuthEndpoint          string            `json:"auth_endpoint,omitempty"`
	TokenEndpoint         string            `json:"token_endpoint,omitempty"`
	TokenAuthMode         string            `json:"token_mode,omitempty"`
	RegisteredRedirectURI string            `json:"redirect_uri,omitempty"`
	ExtraAuthQuery        map[string]string `json:"extras,omitempty"`
	Slug                  string            `json:"slug,omitempty"`
	Secret                interface{}       `json:"secret,omitempty"`
	SkipRedirectURI       bool              `json:"skip_redirect_uri_on_authorize,omitempty"`
	SkipState             bool              `json:"skip_state_on_token,omitempty"`
}

// ID is used to implement the couchdb.Doc interface
func (at *AccountType) ID() string { return at.DocID }

// Rev is used to implement the couchdb.Doc interface
func (at *AccountType) Rev() string { return at.DocRev }

// SetID is used to implement the couchdb.Doc interface
func (at *AccountType) SetID(id string) { at.DocID = id }

// SetRev is used to implement the couchdb.Doc interface
func (at *AccountType) SetRev(rev string) { at.DocRev = rev }

// DocType implements couchdb.Doc
func (at *AccountType) DocType() string { return consts.AccountTypes }

// Clone implements couchdb.Doc
func (at *AccountType) Clone() couchdb.Doc {
	cloned := *at
	cloned.ExtraAuthQuery = make(map[string]string)
	for k, v := range at.ExtraAuthQuery {
		cloned.ExtraAuthQuery[k] = v
	}
	return &cloned
}

// ensure AccountType implements couchdb.Doc
var _ couchdb.Doc = (*AccountType)(nil)

type tokenEndpointResponse struct {
	RefreshToken     string `json:"refresh_token"`
	AccessToken      string `json:"access_token"`
	IDToken          string `json:"id_token"` // alternative name for access_token
	ExpiresIn        int    `json:"expires_in"`
	TokenType        string `json:"token_type"`
	Error            string `json:"error"`
	ErrorDescription string `json:"error_description"`
}

// RedirectURI returns the redirectURI for an account,
// it can be either the
func (at *AccountType) RedirectURI(i *instance.Instance) string {
	redirectURI := i.PageURL("/accounts/"+at.ID()+"/redirect", nil)
	if at.RegisteredRedirectURI != "" {
		redirectURI = at.RegisteredRedirectURI
	}
	return redirectURI
}

// MakeOauthStartURL returns the url at which direct the user to start
// the oauth flow
func (at *AccountType) MakeOauthStartURL(i *instance.Instance, scope string, state string) (string, error) {
	u, err := url.Parse(at.AuthEndpoint)
	if err != nil {
		return "", err
	}
	vv := u.Query()
	redirectURI := at.RedirectURI(i)

	// In theory, the scope and redirect_uri are mandatory, but some services
	// don't support them and can even have an error 500 if they are present.
	// See https://forum.cozy.io/t/custom-oauth/6835/3
	if scope != "" {
		vv.Add("scope", scope)
	}
	if !at.SkipRedirectURI && at.GrantMode != ImplicitGrantRedirectURL {
		vv.Add("redirect_uri", redirectURI)
	}

	switch at.GrantMode {
	case AuthorizationCode:
		vv.Add("response_type", "code")
		vv.Add("client_id", at.ClientID)
	case ImplicitGrant:
		vv.Add("response_type", "token")
		vv.Add("client_id", at.ClientID)
	case ImplicitGrantRedirectURL:
		vv.Add("response_type", "token")
		vv.Add("redirect_url", redirectURI)
	default:
		return "", errors.New("Wrong account type")
	}

	vv.Add("state", state)
	for k, v := range at.ExtraAuthQuery {
		vv.Add(k, v)
	}

	u.RawQuery = vv.Encode()
	return u.String(), nil
}

// RequestAccessToken asks the service an access token
// https://tools.ietf.org/html/rfc6749#section-4
func (at *AccountType) RequestAccessToken(i *instance.Instance, accessCode, state, nonce string) (*Account, error) {
	data := url.Values{
		"grant_type":   []string{AuthorizationCode},
		"code":         []string{accessCode},
		"redirect_uri": []string{at.RedirectURI(i)},
	}

	// Some OAuth providers require the state, and some others throw an error
	// if it present. By default, the stack adds the state to the access token
	// request, but this behavior can be disabled with an option on the account
	// type. See https://forum.cozy.io/t/custom-oauth/6835/15
	if !at.SkipState {
		data.Add("state", state)
	}

	if nonce != "" {
		data.Add("nonce", nonce)
	}

	if at.TokenAuthMode != BasicTokenAuthMode {
		data.Add("client_id", at.ClientID)
		data.Add("client_secret", at.ClientSecret)
	}

	body := data.Encode()
	var req *http.Request
	var err error
	if at.TokenAuthMode == GetTokenAuthMode {
		urlWithParams := at.TokenEndpoint + "?" + body
		req, err = http.NewRequest("GET", urlWithParams, nil)
		if err != nil {
			return nil, err
		}
	} else {
		req, err = http.NewRequest("POST", at.TokenEndpoint, strings.NewReader(body))
		if err != nil {
			return nil, err
		}

		req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
		req.Header.Add("Accept", "application/json")
	}

	if at.TokenAuthMode == BasicTokenAuthMode {
		auth := []byte(at.ClientID + ":" + at.ClientSecret)
		req.Header.Add("Authorization", "Basic "+base64.StdEncoding.EncodeToString(auth))
	}

	res, err := accountsClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	resBody, err := ioutil.ReadAll(res.Body)
	if res.StatusCode != 200 {
		return nil, errors.New("oauth services responded with non-200 res: " + string(resBody))
	}
	if err != nil {
		return nil, err
	}

	var out struct {
		RefreshToken     string `json:"refresh_token"`
		AccessToken      string `json:"access_token"`
		IDToken          string `json:"id_token"` // alternative name for access_token
		ExpiresIn        int    `json:"expires_in"`
		TokenType        string `json:"token_type"`
		Error            string `json:"error"`
		ErrorDescription string `json:"error_description"`
	}
	err = json.Unmarshal(resBody, &out)
	if err != nil {
		return nil, err
	}
	if out.Error != "" {
		return nil, fmt.Errorf("OauthError(%s) %s", out.Error, out.ErrorDescription)
	}

	var ExpiresAt time.Time
	if out.ExpiresIn != 0 {
		ExpiresAt = time.Now().Add(time.Duration(out.ExpiresIn) * time.Second)
	}

	account := &Account{
		AccountType: at.ID(),
		Oauth:       &OauthInfo{ExpiresAt: ExpiresAt},
	}

	if out.AccessToken == "" {
		out.AccessToken = out.IDToken
	}

	if out.AccessToken == "" {
		return nil, errors.New("server responded without access token")
	}

	account.Oauth.AccessToken = out.AccessToken
	account.Oauth.RefreshToken = out.RefreshToken
	account.Oauth.TokenType = out.TokenType

	// decode same resBody into a map for non-standard fields
	var extras map[string]interface{}
	_ = json.Unmarshal(resBody, &extras)
	delete(extras, "access_token")
	delete(extras, "refresh_token")
	delete(extras, "token_type")
	delete(extras, "expires_in")

	if len(extras) > 0 {
		account.Extras = extras
	}

	return account, nil
}

// RefreshAccount requires a new AccessToken using the RefreshToken
// as specified in https://tools.ietf.org/html/rfc6749#section-6
func (at *AccountType) RefreshAccount(a Account) error {
	if a.Oauth == nil {
		return ErrUnrefreshable
	}

	// If no endpoint is specified for the account type, the stack just sends
	// the client ID and client secret to the konnector and let it fetch the
	// token its-self.
	if a.Oauth.RefreshToken == "" {
		a.Oauth.ClientID = at.ClientID
		a.Oauth.ClientSecret = at.ClientSecret
		return nil
	}

	res, err := http.PostForm(at.TokenEndpoint, url.Values{
		"grant_type":    []string{RefreshToken},
		"refresh_token": []string{a.Oauth.RefreshToken},
		"client_id":     []string{at.ClientID},
		"client_secret": []string{at.ClientSecret},
	})

	if err != nil {
		return err
	}

	if res.StatusCode != 200 {
		resBody, _ := ioutil.ReadAll(res.Body)
		return errors.New("oauth services responded with non-200 res: " + string(resBody))
	}

	var out tokenEndpointResponse
	err = json.NewDecoder(res.Body).Decode(&out)
	if err != nil {
		return err
	}

	if out.Error != "" {
		return fmt.Errorf("OauthError(%s) %s", out.Error, out.ErrorDescription)
	}

	if out.AccessToken != "" {
		a.Oauth.AccessToken = out.AccessToken
	}

	if out.ExpiresIn != 0 {
		a.Oauth.ExpiresAt = time.Now().Add(time.Duration(out.ExpiresIn) * time.Second)
	}

	if out.RefreshToken != "" {
		a.Oauth.RefreshToken = out.RefreshToken
	}

	return nil
}

// TypeInfo returns the AccountType document for a given id
func TypeInfo(id, contextName string) (*AccountType, error) {
	if id == "" {
		return nil, errors.New("no account type id provided")
	}
	var a AccountType
	err := couchdb.GetDoc(couchdb.GlobalSecretsDB, consts.AccountTypes, contextName+"/"+id, &a)
	if couchdb.IsNotFoundError(err) {
		err = couchdb.GetDoc(couchdb.GlobalSecretsDB, consts.AccountTypes, id, &a)
	}
	if err != nil {
		return nil, err
	}
	return &a, nil
}

// FindAccountTypesBySlug returns the AccountType documents for the given slug
func FindAccountTypesBySlug(slug, contextName string) ([]*AccountType, error) {
	var docs []*AccountType
	req := &couchdb.FindRequest{
		UseIndex: "by-slug",
		Selector: mango.Equal("slug", slug),
	}
	err := couchdb.FindDocs(couchdb.GlobalSecretsDB, consts.AccountTypes, req, &docs)
	if err != nil {
		return nil, err
	}
	return docs, nil
}

func filterByContext(types []*AccountType, contextName string) []*AccountType {
	var filtered []*AccountType

	// First, take the account types specific to this context
	for _, t := range types {
		parts := strings.SplitN(t.DocID, "/", 2)
		if len(parts) == 2 && parts[0] == contextName {
			filtered = append(filtered, t)
		}
	}

	// Then, take the global account types that have not been overloaded
	for _, t := range types {
		parts := strings.SplitN(t.DocID, "/", 2)
		if len(parts) == 1 {
			overloaded := false
			for _, typ := range filtered {
				if typ.DocID == contextName+"/"+t.DocID {
					overloaded = true
					break
				}
			}
			if !overloaded {
				filtered = append(filtered, t)
			}
		}
	}

	return filtered
}
<commit_msg>Fix the selection of account type per context (#2582)<commit_after>package account

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/cozy/cozy-stack/model/instance"
	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/couchdb/mango"
)

var accountsClient = &http.Client{
	Timeout: 15 * time.Second,
}

// This file contains the account_type object as defined in
// docs/konnectors-workflow.md

// Various grant types
// - AuthorizationCode is the server-side grant type.
// - ImplicitGrant is the implicit grant type
// - ImplicitGrantRedirectURL is the implicit grant type but with redirect_url
//    											  instead of redirect_uri
const (
	AuthorizationCode        = "authorization_code"
	ImplicitGrant            = "token"
	ImplicitGrantRedirectURL = "token_redirect_url"
)

// Token Request authentication modes for AuthorizationCode grant type
// normal is through form parameters
// some services requires it as Basic
const (
	FormTokenAuthMode  = "form"
	BasicTokenAuthMode = "basic"
	GetTokenAuthMode   = "get"
)

// RefreshToken is the refresh grant type
var RefreshToken = "refresh_token"

// ErrUnrefreshable is the error when an account type or information
// within an account does not allow refreshing it.
var ErrUnrefreshable = errors.New("this account can not be refreshed")

// AccountType holds configuration information for
type AccountType struct {
	DocID                 string            `json:"_id,omitempty"`
	DocRev                string            `json:"_rev,omitempty"`
	GrantMode             string            `json:"grant_mode,omitempty"`
	ClientID              string            `json:"client_id,omitempty"`
	ClientSecret          string            `json:"client_secret,omitempty"`
	AuthEndpoint          string            `json:"auth_endpoint,omitempty"`
	TokenEndpoint         string            `json:"token_endpoint,omitempty"`
	TokenAuthMode         string            `json:"token_mode,omitempty"`
	RegisteredRedirectURI string            `json:"redirect_uri,omitempty"`
	ExtraAuthQuery        map[string]string `json:"extras,omitempty"`
	Slug                  string            `json:"slug,omitempty"`
	Secret                interface{}       `json:"secret,omitempty"`
	SkipRedirectURI       bool              `json:"skip_redirect_uri_on_authorize,omitempty"`
	SkipState             bool              `json:"skip_state_on_token,omitempty"`
}

// ID is used to implement the couchdb.Doc interface
func (at *AccountType) ID() string { return at.DocID }

// Rev is used to implement the couchdb.Doc interface
func (at *AccountType) Rev() string { return at.DocRev }

// SetID is used to implement the couchdb.Doc interface
func (at *AccountType) SetID(id string) { at.DocID = id }

// SetRev is used to implement the couchdb.Doc interface
func (at *AccountType) SetRev(rev string) { at.DocRev = rev }

// DocType implements couchdb.Doc
func (at *AccountType) DocType() string { return consts.AccountTypes }

// Clone implements couchdb.Doc
func (at *AccountType) Clone() couchdb.Doc {
	cloned := *at
	cloned.ExtraAuthQuery = make(map[string]string)
	for k, v := range at.ExtraAuthQuery {
		cloned.ExtraAuthQuery[k] = v
	}
	return &cloned
}

// ensure AccountType implements couchdb.Doc
var _ couchdb.Doc = (*AccountType)(nil)

type tokenEndpointResponse struct {
	RefreshToken     string `json:"refresh_token"`
	AccessToken      string `json:"access_token"`
	IDToken          string `json:"id_token"` // alternative name for access_token
	ExpiresIn        int    `json:"expires_in"`
	TokenType        string `json:"token_type"`
	Error            string `json:"error"`
	ErrorDescription string `json:"error_description"`
}

// RedirectURI returns the redirectURI for an account,
// it can be either the
func (at *AccountType) RedirectURI(i *instance.Instance) string {
	redirectURI := i.PageURL("/accounts/"+at.ID()+"/redirect", nil)
	if at.RegisteredRedirectURI != "" {
		redirectURI = at.RegisteredRedirectURI
	}
	return redirectURI
}

// MakeOauthStartURL returns the url at which direct the user to start
// the oauth flow
func (at *AccountType) MakeOauthStartURL(i *instance.Instance, scope string, state string) (string, error) {
	u, err := url.Parse(at.AuthEndpoint)
	if err != nil {
		return "", err
	}
	vv := u.Query()
	redirectURI := at.RedirectURI(i)

	// In theory, the scope and redirect_uri are mandatory, but some services
	// don't support them and can even have an error 500 if they are present.
	// See https://forum.cozy.io/t/custom-oauth/6835/3
	if scope != "" {
		vv.Add("scope", scope)
	}
	if !at.SkipRedirectURI && at.GrantMode != ImplicitGrantRedirectURL {
		vv.Add("redirect_uri", redirectURI)
	}

	switch at.GrantMode {
	case AuthorizationCode:
		vv.Add("response_type", "code")
		vv.Add("client_id", at.ClientID)
	case ImplicitGrant:
		vv.Add("response_type", "token")
		vv.Add("client_id", at.ClientID)
	case ImplicitGrantRedirectURL:
		vv.Add("response_type", "token")
		vv.Add("redirect_url", redirectURI)
	default:
		return "", errors.New("Wrong account type")
	}

	vv.Add("state", state)
	for k, v := range at.ExtraAuthQuery {
		vv.Add(k, v)
	}

	u.RawQuery = vv.Encode()
	return u.String(), nil
}

// RequestAccessToken asks the service an access token
// https://tools.ietf.org/html/rfc6749#section-4
func (at *AccountType) RequestAccessToken(i *instance.Instance, accessCode, state, nonce string) (*Account, error) {
	data := url.Values{
		"grant_type":   []string{AuthorizationCode},
		"code":         []string{accessCode},
		"redirect_uri": []string{at.RedirectURI(i)},
	}

	// Some OAuth providers require the state, and some others throw an error
	// if it present. By default, the stack adds the state to the access token
	// request, but this behavior can be disabled with an option on the account
	// type. See https://forum.cozy.io/t/custom-oauth/6835/15
	if !at.SkipState {
		data.Add("state", state)
	}

	if nonce != "" {
		data.Add("nonce", nonce)
	}

	if at.TokenAuthMode != BasicTokenAuthMode {
		data.Add("client_id", at.ClientID)
		data.Add("client_secret", at.ClientSecret)
	}

	body := data.Encode()
	var req *http.Request
	var err error
	if at.TokenAuthMode == GetTokenAuthMode {
		urlWithParams := at.TokenEndpoint + "?" + body
		req, err = http.NewRequest("GET", urlWithParams, nil)
		if err != nil {
			return nil, err
		}
	} else {
		req, err = http.NewRequest("POST", at.TokenEndpoint, strings.NewReader(body))
		if err != nil {
			return nil, err
		}

		req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
		req.Header.Add("Accept", "application/json")
	}

	if at.TokenAuthMode == BasicTokenAuthMode {
		auth := []byte(at.ClientID + ":" + at.ClientSecret)
		req.Header.Add("Authorization", "Basic "+base64.StdEncoding.EncodeToString(auth))
	}

	res, err := accountsClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	resBody, err := ioutil.ReadAll(res.Body)
	if res.StatusCode != 200 {
		return nil, errors.New("oauth services responded with non-200 res: " + string(resBody))
	}
	if err != nil {
		return nil, err
	}

	var out struct {
		RefreshToken     string `json:"refresh_token"`
		AccessToken      string `json:"access_token"`
		IDToken          string `json:"id_token"` // alternative name for access_token
		ExpiresIn        int    `json:"expires_in"`
		TokenType        string `json:"token_type"`
		Error            string `json:"error"`
		ErrorDescription string `json:"error_description"`
	}
	err = json.Unmarshal(resBody, &out)
	if err != nil {
		return nil, err
	}
	if out.Error != "" {
		return nil, fmt.Errorf("OauthError(%s) %s", out.Error, out.ErrorDescription)
	}

	var ExpiresAt time.Time
	if out.ExpiresIn != 0 {
		ExpiresAt = time.Now().Add(time.Duration(out.ExpiresIn) * time.Second)
	}

	account := &Account{
		AccountType: at.ID(),
		Oauth:       &OauthInfo{ExpiresAt: ExpiresAt},
	}

	if out.AccessToken == "" {
		out.AccessToken = out.IDToken
	}

	if out.AccessToken == "" {
		return nil, errors.New("server responded without access token")
	}

	account.Oauth.AccessToken = out.AccessToken
	account.Oauth.RefreshToken = out.RefreshToken
	account.Oauth.TokenType = out.TokenType

	// decode same resBody into a map for non-standard fields
	var extras map[string]interface{}
	_ = json.Unmarshal(resBody, &extras)
	delete(extras, "access_token")
	delete(extras, "refresh_token")
	delete(extras, "token_type")
	delete(extras, "expires_in")

	if len(extras) > 0 {
		account.Extras = extras
	}

	return account, nil
}

// RefreshAccount requires a new AccessToken using the RefreshToken
// as specified in https://tools.ietf.org/html/rfc6749#section-6
func (at *AccountType) RefreshAccount(a Account) error {
	if a.Oauth == nil {
		return ErrUnrefreshable
	}

	// If no endpoint is specified for the account type, the stack just sends
	// the client ID and client secret to the konnector and let it fetch the
	// token its-self.
	if a.Oauth.RefreshToken == "" {
		a.Oauth.ClientID = at.ClientID
		a.Oauth.ClientSecret = at.ClientSecret
		return nil
	}

	res, err := http.PostForm(at.TokenEndpoint, url.Values{
		"grant_type":    []string{RefreshToken},
		"refresh_token": []string{a.Oauth.RefreshToken},
		"client_id":     []string{at.ClientID},
		"client_secret": []string{at.ClientSecret},
	})

	if err != nil {
		return err
	}

	if res.StatusCode != 200 {
		resBody, _ := ioutil.ReadAll(res.Body)
		return errors.New("oauth services responded with non-200 res: " + string(resBody))
	}

	var out tokenEndpointResponse
	err = json.NewDecoder(res.Body).Decode(&out)
	if err != nil {
		return err
	}

	if out.Error != "" {
		return fmt.Errorf("OauthError(%s) %s", out.Error, out.ErrorDescription)
	}

	if out.AccessToken != "" {
		a.Oauth.AccessToken = out.AccessToken
	}

	if out.ExpiresIn != 0 {
		a.Oauth.ExpiresAt = time.Now().Add(time.Duration(out.ExpiresIn) * time.Second)
	}

	if out.RefreshToken != "" {
		a.Oauth.RefreshToken = out.RefreshToken
	}

	return nil
}

// TypeInfo returns the AccountType document for a given id
func TypeInfo(id, contextName string) (*AccountType, error) {
	if id == "" {
		return nil, errors.New("no account type id provided")
	}
	var a AccountType
	err := couchdb.GetDoc(couchdb.GlobalSecretsDB, consts.AccountTypes, contextName+"/"+id, &a)
	if couchdb.IsNotFoundError(err) {
		err = couchdb.GetDoc(couchdb.GlobalSecretsDB, consts.AccountTypes, id, &a)
	}
	if err != nil {
		return nil, err
	}
	return &a, nil
}

// FindAccountTypesBySlug returns the AccountType documents for the given slug
func FindAccountTypesBySlug(slug, contextName string) ([]*AccountType, error) {
	var docs []*AccountType
	req := &couchdb.FindRequest{
		UseIndex: "by-slug",
		Selector: mango.Equal("slug", slug),
	}
	err := couchdb.FindDocs(couchdb.GlobalSecretsDB, consts.AccountTypes, req, &docs)
	if err != nil {
		return nil, err
	}
	return filterByContext(docs, contextName), nil
}

func filterByContext(types []*AccountType, contextName string) []*AccountType {
	var filtered []*AccountType

	// First, take the account types specific to this context
	for _, t := range types {
		parts := strings.SplitN(t.DocID, "/", 2)
		if len(parts) == 2 && parts[0] == contextName {
			filtered = append(filtered, t)
		}
	}

	// Then, take the global account types that have not been overloaded
	for _, t := range types {
		parts := strings.SplitN(t.DocID, "/", 2)
		if len(parts) == 1 {
			overloaded := false
			for _, typ := range filtered {
				if typ.DocID == contextName+"/"+t.DocID {
					overloaded = true
					break
				}
			}
			if !overloaded {
				filtered = append(filtered, t)
			}
		}
	}

	return filtered
}
<|endoftext|>


<commit_before><commit_msg>Refactoring Chdir in test<commit_after><|endoftext|>


<commit_before><commit_msg>[login] Don't log an error for anonymous users<commit_after><|endoftext|>


<commit_before>package cmd

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// depsCmd represents the deps command
var depsCmd = &cobra.Command{
	Use:   "deps",
	Short: "Download and optionally update all abcweb dependencies",
	Long: `Download and optionally update all abcweb dependencies used by
your generated app or the abcweb tool by executing "go get" commands`,
	Example: "abcweb deps -u",
	RunE:    depsCmdRun,
}

func init() {
	depsCmd.Flags().BoolP("update", "u", false, "Also update already installed dependencies")

	RootCmd.AddCommand(depsCmd)
	viper.BindPFlags(depsCmd.Flags())
}

func depsCmdRun(cmd *cobra.Command, args []string) error {
	var err error

	goGetArgs := [][]string{
		{"-t", "github.com/vattle/sqlboiler"},
		{"github.com/pressly/goose"},
		{"github.com/satori/go.uuid"},
		{"github.com/pkg/errors"},
		{"github.com/lib/pq"},
		{"github.com/go-sql-driver/mysql"},
		{"github.com/djherbis/times"},
		{"github.com/uber-go/zap"},
		{"github.com/spf13/cobra"},
		{"github.com/spf13/viper"},
		{"github.com/pressly/chi"},
		{"github.com/kat-co/vala"},
		{"github.com/goware/cors"},
		{"github.com/unrolled/render"},
	}

	npmInstallArgs := [][]string{
		{"gulp-cli"},
	}

	// Prefix Go args with "get" and optionally "-u"
	if viper.GetBool("update") {
		for i := 0; i < len(goGetArgs); i++ {
			goGetArgs[i] = append([]string{"get", "-u"}, goGetArgs[i]...)
		}
	} else {
		for i := 0; i < len(goGetArgs); i++ {
			goGetArgs[i] = append([]string{"get"}, goGetArgs[i]...)
		}
	}

	fmt.Printf("Retrieving all Go dependencies using \"go get\":\n\n")

	for _, goGetArg := range goGetArgs {
		fmt.Printf("%s ... ", goGetArg[len(goGetArg)-1])

		exc := exec.Command("go", goGetArg...)
		err := exc.Run()

		if err != nil {
			fmt.Printf("ERROR\n\n")
			fmt.Println(err)
			os.Exit(-1)
		}

		fmt.Printf("SUCCESS\n")
	}

	// Prefix NPM args with "install --global"
	for i := 0; i < len(npmInstallArgs); i++ {
		npmInstallArgs[i] = append([]string{"install", "--global"}, npmInstallArgs[i]...)
	}

	fmt.Printf("\nRetrieving all Nodejs dependencies using \"npm install --global\":\n\n")

	_, err = exec.LookPath("npm")
	if err != nil {
		fmt.Printf(`Error: npm could not be found in your $PATH. If you have not already installed nodejs
and npm you must do so before proceeding. Please follow the instructions at:
https://docs.npmjs.com/getting-started/installing-node

If you receive permission related errors, please apply the following fix:
https://docs.npmjs.com/getting-started/fixing-npm-permissions
`)
		os.Exit(-1)
	}

	for _, npmInstallArg := range npmInstallArgs {
		fmt.Printf("%s ... ", npmInstallArg[len(npmInstallArg)-1])

		var out bytes.Buffer
		exc := exec.Command("npm", npmInstallArg...)
		exc.Stdout = &out
		exc.Stderr = &out

		err := exc.Run()

		if err != nil {
			fmt.Printf("ERROR\n\n")
		} else {
			fmt.Printf("SUCCESS\n\n")
		}

		fmt.Println(out.String())

		if err != nil {
			fmt.Printf("%s\n\n", err)
			fmt.Printf(`Note: If you are receiving a permission related exit status or error, please apply the following fix:
https://docs.npmjs.com/getting-started/fixing-npm-permissions
`)
			os.Exit(-1)
		}
	}

	fmt.Printf("All dependencies successfully installed.\n\n")

	return err
}
<commit_msg>added err/stdout for go command<commit_after>package cmd

import (
	"fmt"
	"os"
	"os/exec"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// depsCmd represents the deps command
var depsCmd = &cobra.Command{
	Use:   "deps",
	Short: "Download and optionally update all abcweb dependencies",
	Long: `Download and optionally update all abcweb dependencies used by
your generated app or the abcweb tool by executing "go get" commands`,
	Example: "abcweb deps -u",
	RunE:    depsCmdRun,
}

func init() {
	depsCmd.Flags().BoolP("update", "u", false, "Also update already installed dependencies")
	depsCmd.Flags().BoolP("verbose", "", false, "Very noisy verbose output")

	RootCmd.AddCommand(depsCmd)
	viper.BindPFlags(depsCmd.Flags())
}

func depsCmdRun(cmd *cobra.Command, args []string) error {
	var err error

	goGetArgs := [][]string{
		{"-t", "github.com/vattle/sqlboiler"},
		{"github.com/pressly/goose"},
		{"github.com/satori/go.uuid"},
		{"github.com/pkg/errors"},
		{"github.com/lib/pq"},
		{"github.com/go-sql-driver/mysql"},
		{"github.com/djherbis/times"},
		{"github.com/uber-go/zap"},
		{"github.com/spf13/cobra"},
		{"github.com/spf13/viper"},
		{"github.com/pressly/chi"},
		{"github.com/kat-co/vala"},
		{"github.com/goware/cors"},
		{"github.com/unrolled/render"},
	}

	npmInstallArgs := [][]string{
		{"gulp-cli"},
	}

	prependArgs := []string{"get"}
	if viper.GetBool("update") {
		prependArgs = append(prependArgs, "-u")
	}
	if viper.GetBool("verbose") {
		prependArgs = append(prependArgs, "-v")
	}

	for i := 0; i < len(goGetArgs); i++ {
		goGetArgs[i] = append(prependArgs, goGetArgs[i]...)
	}

	fmt.Printf("Retrieving all Go dependencies using \"go get\":\n\n")

	for _, goGetArg := range goGetArgs {
		fmt.Printf("%s ... ", goGetArg[len(goGetArg)-1])

		exc := exec.Command("go", goGetArg...)
		out, err := exc.CombinedOutput()

		if err != nil {
			fmt.Printf("ERROR\n\n")
		} else {
			fmt.Printf("SUCCESS\n")
		}

		if len(out) > 0 {
			fmt.Println(string(out))
		}

		if err != nil {
			fmt.Printf("%s\n\n", err)
			os.Exit(-1)
		}
	}

	// Prefix NPM args with "install --global"
	if viper.GetBool("verbose") {
		for i := 0; i < len(npmInstallArgs); i++ {
			npmInstallArgs[i] = append([]string{"install", "--global", "--verbose"}, npmInstallArgs[i]...)
		}
	} else {
		for i := 0; i < len(npmInstallArgs); i++ {
			npmInstallArgs[i] = append([]string{"install", "--global"}, npmInstallArgs[i]...)
		}

	}

	fmt.Printf("\nRetrieving all Nodejs dependencies using \"npm install --global\":\n\n")

	_, err = exec.LookPath("npm")
	if err != nil {
		fmt.Printf(`Error: npm could not be found in your $PATH. If you have not already installed nodejs
and npm you must do so before proceeding. Please follow the instructions at:
https://docs.npmjs.com/getting-started/installing-node

If you receive permission related errors, please apply the following fix:
https://docs.npmjs.com/getting-started/fixing-npm-permissions
`)
		os.Exit(-1)
	}

	for _, npmInstallArg := range npmInstallArgs {
		fmt.Printf("%s ... ", npmInstallArg[len(npmInstallArg)-1])

		exc := exec.Command("npm", npmInstallArg...)
		out, err := exc.CombinedOutput()

		if err != nil {
			fmt.Printf("ERROR\n\n")
		} else {
			fmt.Printf("SUCCESS\n\n")
		}

		if len(out) > 0 {
			fmt.Println(string(out))
		}

		if err != nil {
			fmt.Printf("%s\n\n", err)
			fmt.Printf(`Note: If you are receiving a permission related exit status or error, please apply the following fix:
https://docs.npmjs.com/getting-started/fixing-npm-permissions
`)
			os.Exit(-1)
		}
	}

	fmt.Printf("All dependencies successfully installed.\n\n")

	return err
}
<|endoftext|>


<commit_before>package cmd

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/spf13/cobra"
	"github.com/voidint/gbb/config"
)

var initCmd = &cobra.Command{
	Use:   "init",
	Short: "Help you to creating gbb.json step by step.",
	Long:  ``,
	Run: func(cmd *cobra.Command, args []string) {
		genConfigFile(confFile)
	},
}

func init() {
	RootCmd.AddCommand(initCmd)
}

func genConfigFile(destFilename string) {
	c := gather()

	b, _ := json.MarshalIndent(c, "", "    ")
	fmt.Printf("About to write to %s:\n\n%s\n\nIs this ok?[y/n] ", destFilename, string(b))
	var ok string
	fmt.Scanln(&ok)
	if ok = strings.ToLower(ok); ok == "y" {
		config.Save(c, confFile)
	}
}

func gather() *config.Config {
	fmt.Println(`This utility will walk you through creating a gbb.json file.
It only covers the most common items, and tries to guess sensible defaults.`)
	fmt.Printf("\nPress ^C at any time to quit.\n")

	c := config.Config{
		Version: gatherOne("version", "0.0.1"),
		Tool:    gatherOne("tool", "go_install"),
		Package: gatherOne("package", "main"),
	}
	for {
		c.Variables = append(c.Variables, *gatherOneVar())

		var sContinue string
		fmt.Print("Do you want to continue?[y/n] ")
		fmt.Scanln(&sContinue)
		if sContinue = strings.ToLower(sContinue); sContinue == "n" {
			break
		}
	}
	return &c
}

func gatherOneVar() (v *config.Variable) {
	return &config.Variable{
		Variable: gatherOne("variable", ""),
		Value:    gatherOne("value", ""),
	}
}

func gatherOne(prompt, defaultVal string) (input string) {
	for {
		if defaultVal != "" {
			fmt.Printf("%s: (%s) ", prompt, defaultVal)
		} else {
			fmt.Printf("%s: ", prompt)
		}
		fmt.Scanln(&input) // TODO bug: 无法获取到包含空格的全部输入，如go build
		if input = strings.TrimSpace(input); input == "" {
			if defaultVal == "" {
				continue
			}
			return strings.Replace(defaultVal, "_", " ", -1)
		}
		return strings.Replace(input, "_", " ", -1) // TODO 临时举措，还原实际的空格。如，go_build ==> go build
	}
}
<commit_msg>gbb.json中的version信息改为取自gbb版本号<commit_after>package cmd

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/spf13/cobra"
	"github.com/voidint/gbb/config"
)

var initCmd = &cobra.Command{
	Use:   "init",
	Short: "Help you to creating gbb.json step by step.",
	Long:  ``,
	Run: func(cmd *cobra.Command, args []string) {
		genConfigFile(confFile)
	},
}

func init() {
	RootCmd.AddCommand(initCmd)
}

func genConfigFile(destFilename string) {
	c := gather()

	b, _ := json.MarshalIndent(c, "", "    ")
	fmt.Printf("About to write to %s:\n\n%s\n\nIs this ok?[y/n] ", destFilename, string(b))
	var ok string
	fmt.Scanln(&ok)
	if ok = strings.ToLower(ok); ok == "y" {
		config.Save(c, confFile)
	}
}

func gather() *config.Config {
	fmt.Println(`This utility will walk you through creating a gbb.json file.
It only covers the most common items, and tries to guess sensible defaults.`)
	fmt.Printf("\nPress ^C at any time to quit.\n")

	c := config.Config{
		Version: Version,
		Tool:    gatherOne("tool", "go_install"),
		Package: gatherOne("package", "main"),
	}
	for {
		c.Variables = append(c.Variables, *gatherOneVar())

		var sContinue string
		fmt.Print("Do you want to continue?[y/n] ")
		fmt.Scanln(&sContinue)
		if sContinue = strings.ToLower(sContinue); sContinue == "n" {
			break
		}
	}
	return &c
}

func gatherOneVar() (v *config.Variable) {
	return &config.Variable{
		Variable: gatherOne("variable", ""),
		Value:    gatherOne("value", ""),
	}
}

func gatherOne(prompt, defaultVal string) (input string) {
	for {
		if defaultVal != "" {
			fmt.Printf("%s: (%s) ", prompt, defaultVal)
		} else {
			fmt.Printf("%s: ", prompt)
		}
		fmt.Scanln(&input) // TODO bug: 无法获取到包含空格的全部输入，如go build
		if input = strings.TrimSpace(input); input == "" {
			if defaultVal == "" {
				continue
			}
			return strings.Replace(defaultVal, "_", " ", -1)
		}
		return strings.Replace(input, "_", " ", -1) // TODO 临时举措，还原实际的空格。如，go_build ==> go build
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"os"
	"path"

	kubeClientModels "git.containerum.net/ch/kube-client/pkg/model"
	"github.com/blang/semver"
	"github.com/containerum/chkit/pkg/client"
	"github.com/containerum/chkit/pkg/model"
	"github.com/sirupsen/logrus"
	cli "gopkg.in/urfave/cli.v2"
)

const (
	Version        = "3.0.0-alpha"
	containerumAPI = "https://94.130.09.147:8082"
	FlagConfigFile = "config"
	FlagAPIaddr    = "apiaddr"
)

func Run(args []string) error {
	log := logrus.New()
	log.Formatter = &logrus.TextFormatter{}
	log.Level = logrus.InfoLevel

	configPath, err := configPath()
	if err != nil {
		log.WithError(err).
			Errorf("error while getting homedir path")
		return err
	}
	var App = &cli.App{
		Name:    "chkit",
		Usage:   "containerum cli",
		Version: semver.MustParse(Version).String(),
		Action: func(ctx *cli.Context) error {
			if err := setupConfig(ctx); err != nil && !os.IsNotExist(err) {
				return err
			} else if os.IsNotExist(err) {
				login(ctx)
				config := getConfig(ctx)
				if config.APIaddr == "" {
					config.APIaddr = ctx.String("api")
				}
			} else {
				return err
			}
			if err := setupClient(ctx); err != nil {
				log.Fatal(err)
			}
			persist(ctx)
			clientConfig := getClient(ctx).Config
			log.Infof("logged as %q", clientConfig.Username)
			return mainActivity(ctx)
		},
		After: func(ctx *cli.Context) error {
			return nil
		},
		Metadata: map[string]interface{}{
			"client":     chClient.Client{},
			"configPath": configPath,
			"log":        log,
			"config":     model.ClientConfig{},
			"tokens":     kubeClientModels.Tokens{},
		},
		Commands: []*cli.Command{
			commandLogin,
		},
		Flags: []cli.Flag{
			&cli.StringFlag{
				Name:    "config",
				Usage:   "config file",
				Aliases: []string{"c"},
				Value:   path.Join(configPath, "config.toml"),
			},
			&cli.StringFlag{
				Name:    "api",
				Usage:   "API address",
				Value:   containerumAPI,
				Hidden:  true,
				EnvVars: []string{"CONTAINERUM_API"},
			},
		},
	}
	return App.Run(args)
}
<commit_msg>fix error handling<commit_after>package cmd

import (
	"os"
	"path"

	kubeClientModels "git.containerum.net/ch/kube-client/pkg/model"
	"github.com/blang/semver"
	"github.com/containerum/chkit/pkg/client"
	"github.com/containerum/chkit/pkg/model"
	"github.com/sirupsen/logrus"
	cli "gopkg.in/urfave/cli.v2"
)

const (
	Version        = "3.0.0-alpha"
	containerumAPI = "http://192.168.88.200" //"https://94.130.09.147:8082"
	FlagConfigFile = "config"
	FlagAPIaddr    = "apiaddr"
)

func Run(args []string) error {
	log := logrus.New()
	log.Formatter = &logrus.TextFormatter{}
	log.Level = logrus.InfoLevel

	configPath, err := configPath()
	if err != nil {
		log.WithError(err).
			Errorf("error while getting homedir path")
		return err
	}
	var App = &cli.App{
		Name:    "chkit",
		Usage:   "containerum cli",
		Version: semver.MustParse(Version).String(),
		Action: func(ctx *cli.Context) error {
			log := getLog(ctx)
			if err := setupConfig(ctx); err != nil && !os.IsNotExist(err) {
				log.Fatalf("error while config setup: %v", err)
			} else if os.IsNotExist(err) {
				if err := login(ctx); err != nil {
					log.Fatalf("error while login: %v", err)
				}
				config := getConfig(ctx)
				if config.APIaddr == "" {
					config.APIaddr = ctx.String("api")
				}
			}
			if err := setupClient(ctx); err != nil {
				log.Fatalf("error while client setup: %v", err)
			}
			if err := persist(ctx); err != nil {
				log.Fatalf("%v", err)
			}
			clientConfig := getClient(ctx).Config
			log.Infof("logged as %q", clientConfig.Username)
			if err := mainActivity(ctx); err != nil {
				log.Fatalf("error in main activity: %v", err)
			}
			return nil
		},
		After: func(ctx *cli.Context) error {
			return nil
		},
		Metadata: map[string]interface{}{
			"client":     chClient.Client{},
			"configPath": configPath,
			"log":        log,
			"config":     model.ClientConfig{},
			"tokens":     kubeClientModels.Tokens{},
		},
		Commands: []*cli.Command{
			commandLogin,
		},
		Flags: []cli.Flag{
			&cli.StringFlag{
				Name:    "config",
				Usage:   "config file",
				Aliases: []string{"c"},
				Value:   path.Join(configPath, "config.toml"),
			},
			&cli.StringFlag{
				Name:    "api",
				Usage:   "API address",
				Value:   containerumAPI,
				Hidden:  true,
				EnvVars: []string{"CONTAINERUM_API"},
			},
		},
	}
	return App.Run(args)
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"github.com/spf13/cobra"
	"github.com/whalebrew/whalebrew/packages"
	"os"
	"sort"
	"text/tabwriter"
)

func init() {
	RootCmd.AddCommand(listCommand)
}

var listCommand = &cobra.Command{
	Use:   "list",
	Short: "List installed packages",
	RunE: func(cmd *cobra.Command, args []string) error {
		pm := packages.NewPackageManager("/usr/local/bin")
		packages, err := pm.List()
		if err != nil {
			return err
		}

		packageNames := make([]string, len(packages))
		for k := range packages {
			packageNames = append(packageNames, k)
		}
		sort.Strings(packageNames)

		w := tabwriter.NewWriter(os.Stdout, 10, 2, 2, ' ', 0)
		fmt.Fprintln(w, "COMMAND\tIMAGE")
		for _, name := range packageNames {
			fmt.Fprintf(w, "%s\t%s\n", name, packages[name].Image)
		}
		w.Flush()
		return nil
	},
}
<commit_msg>Fix broken list<commit_after>package cmd

import (
	"fmt"
	"github.com/spf13/cobra"
	"github.com/whalebrew/whalebrew/packages"
	"os"
	"sort"
	"text/tabwriter"
)

func init() {
	RootCmd.AddCommand(listCommand)
}

var listCommand = &cobra.Command{
	Use:   "list",
	Short: "List installed packages",
	RunE: func(cmd *cobra.Command, args []string) error {
		pm := packages.NewPackageManager("/usr/local/bin")
		packages, err := pm.List()
		if err != nil {
			return err
		}

		packageNames := make([]string, 0, len(packages))
		for k := range packages {
			packageNames = append(packageNames, k)
		}
		sort.Strings(packageNames)

		w := tabwriter.NewWriter(os.Stdout, 10, 2, 2, ' ', 0)
		fmt.Fprintln(w, "COMMAND\tIMAGE")
		for _, name := range packageNames {
			fmt.Fprintf(w, "%s\t%s\n", name, packages[name].Image)
		}
		w.Flush()
		return nil
	},
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"

	"github.com/naoty/todo/repository"
	"github.com/naoty/todo/todo"
)

// List represents `list` subcommand.
type List struct {
	cli  CLI
	repo repository.Repository
}

// NewList returns a new List.
func NewList(cli CLI, version string, repo repository.Repository) Command {
	return &List{cli: cli, repo: repo}
}

// Run implements Command interface.
func (c *List) Run(args []string) int {
	todos, err := c.repo.List()
	if err != nil {
		fmt.Fprintln(c.cli.ErrorWriter, err)
		return 1
	}

	for _, td := range todos {
		var mark string
		switch td.State {
		case todo.Undone:
			mark = "[ ]"
		case todo.Done:
			mark = "[x]"
		case todo.Waiting:
			mark = "[w]"
		case todo.Archived:
			mark = "[-]"
		}

		fmt.Fprintf(c.cli.Writer, "%s %03d: %s\n", mark, td.ID, td.Title)
	}

	return 0
}
<commit_msg>Hide archived TODOs<commit_after>package cmd

import (
	"fmt"

	"github.com/naoty/todo/repository"
	"github.com/naoty/todo/todo"
)

// List represents `list` subcommand.
type List struct {
	cli  CLI
	repo repository.Repository
}

// NewList returns a new List.
func NewList(cli CLI, version string, repo repository.Repository) Command {
	return &List{cli: cli, repo: repo}
}

// Run implements Command interface.
func (c *List) Run(args []string) int {
	todos, err := c.repo.List()
	if err != nil {
		fmt.Fprintln(c.cli.ErrorWriter, err)
		return 1
	}

	for _, td := range todos {
		var mark string
		switch td.State {
		case todo.Undone:
			mark = "[ ]"
		case todo.Done:
			mark = "[x]"
		case todo.Waiting:
			mark = "[w]"
		case todo.Archived:
			continue
		}

		fmt.Fprintf(c.cli.Writer, "%s %03d: %s\n", mark, td.ID, td.Title)
	}

	return 0
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/http"
	"time"

	"github.com/gchaincl/httplab"
	"github.com/jroimartin/gocui"
)

func NewHandler(ui *httplab.UI, g *gocui.Gui) http.Handler {
	fn := func(w http.ResponseWriter, req *http.Request) {
		ui.Info(g, "New Request from "+req.Host)
		buf, err := httplab.DumpRequest(req)
		if err != nil {
			ui.Info(g, "%v", err)
		}

		ui.Display(g, "request", buf)

		resp := ui.Response()
		time.Sleep(resp.Delay)
		resp.Write(w)

	}
	return http.HandlerFunc(fn)
}

func main() {
	g, err := gocui.NewGui(gocui.Output256)
	if err != nil {
		log.Fatalln(err)
	}

	ui := httplab.NewUI()
	if err := ui.Init(g); err != nil {
		log.Fatalln(err)
	}

	http.Handle("/", NewHandler(ui, g))
	go func() {
		ui.Info(g, "Listening on :18000")
		if err := http.ListenAndServe(":18000", nil); err != nil {
			log.Fatalln(err)
		}
	}()

	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
		log.Fatalln(err)
	}
}
<commit_msg>Parameterize port<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/gchaincl/httplab"
	"github.com/jroimartin/gocui"
)

func NewHandler(ui *httplab.UI, g *gocui.Gui) http.Handler {
	fn := func(w http.ResponseWriter, req *http.Request) {
		ui.Info(g, "New Request from "+req.Host)
		buf, err := httplab.DumpRequest(req)
		if err != nil {
			ui.Info(g, "%v", err)
		}

		ui.Display(g, "request", buf)

		resp := ui.Response()
		time.Sleep(resp.Delay)
		resp.Write(w)

	}
	return http.HandlerFunc(fn)
}

func main() {
	var port int
	flag.IntVar(&port, "port", 10080, "Specifies the port where HTTPLab will bind to")
	flag.Parse()

	g, err := gocui.NewGui(gocui.Output256)
	if err != nil {
		log.Fatalln(err)
	}
	defer g.Close()

	ui := httplab.NewUI()
	if err := ui.Init(g); err != nil {
		log.Fatalln(err)
	}

	http.Handle("/", NewHandler(ui, g))
	go func() {
		// Make sure gocui has started
		g.Execute(func(g *gocui.Gui) error { return nil })

		ui.Info(g, "Listening on :%d", port)
		if err := http.ListenAndServe(fmt.Sprintf(":%d", port), nil); err != nil {
			log.Fatalln(err)
		}
	}()

	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
		log.Fatalln(err)
	}
}
<|endoftext|>


<commit_before>/*
This program takes a list of domains and queries each against the OpenDNS
Investigate API, optionally outputting a CSV file.

Because querying every endpoint can be very time consuming, this program uses
a TOML file to configure which information should be queried.
*/
package main

import (
	"bufio"
	"encoding/csv"
	"flag"
	"fmt"
	"log"
	"os"
	"runtime"
	"strconv"
	"sync"

	"github.com/dead10ck/domainstats"
	"github.com/dead10ck/goinvestigate"
)

type opt struct {
	verbose       bool
	outFile       string
	configPath    string
	maxGoroutines int
}

var (
	opts              opt
	defaultConfigPath string = os.Getenv("HOME") + "/.domainstats/default.toml"
)

const (
	DEFAULT_MAX_GOROUTINES = 10
)

func init() {
	flag.IntVar(&opts.maxGoroutines, "m", DEFAULT_MAX_GOROUTINES,
		"Maximum number of goroutines to use for parallel HTTP requests")
	flag.BoolVar(&opts.verbose, "v", false, "Print out verbose log messages.")
	flag.StringVar(&opts.outFile, "out", "", "Output matching IPs to the given file")
	flag.StringVar(&opts.configPath, "c", defaultConfigPath, "The config file to use")

	runtime.GOMAXPROCS(runtime.NumCPU())
}

func main() {
	flag.Parse()
	config, err := domainstats.NewConfig(opts.configPath)
	if err != nil {
		log.Fatal(err)
	}
	//spew.Dump(config)
	//os.Exit(0)
	var outWriter *csv.Writer
	var header []string
	domains := readDomainsFrom(flag.Arg(flag.NArg() - 1))
	inv := goinvestigate.New(config.APIKey)

	if opts.verbose {
		inv.SetVerbose(true)
	}

	//header = config.DeriveHeader()
	//fmt.Printf("header: %v\n", header)
	//os.Exit(0)

	if opts.outFile != "" {
		outFile, err := os.Create(opts.outFile)
		if err != nil {
			log.Fatal(err)
		}
		outWriter = csv.NewWriter(outFile)
		outWriter.Comma = rune('\t')
		header = config.DeriveHeader()
		outWriter.Write(header)
		defer func() {
			outWriter.Flush()
			outFile.Close()
		}()
	}

	inChan := make(chan string, len(domains))
	go func() {
		for _, d := range domains {
			inChan <- d
		}
		close(inChan)
	}()

	outChan := getInfo(config, inv, inChan)
	//getInfo(config, inv, inChan)

	numProcessed := 0

	for respRow := range outChan {
		numProcessed++
		fmt.Printf("\r%120s", " ")
		fmt.Printf("\r%d/%d: %s", numProcessed, len(domains), respRow[0])
		if outWriter != nil {
			outWriter.Write(respRow)
		}
	}
	fmt.Println()
}

func floatToStr(v interface{}) string {
	switch val := v.(type) {
	case float64:
		return strconv.FormatFloat(val, 'f', -1, 64)
	default:
		return ""
	}
}

// The goroutine which does the HTTP queries
func query(qChan <-chan *domainstats.DomainQueryMessage) {
	for m := range qChan {
		m.RespChan <- m.Q.Query()
	}
}

func process(inv *goinvestigate.Investigate, config *domainstats.Config,
	domainChan <-chan string,
	qChan chan<- *domainstats.DomainQueryMessage,
	outChan chan<- []string,
	wg *sync.WaitGroup) {
	for domain := range domainChan {

		// generate the list of queries to make for each domain
		queries := config.DeriveMessages(inv, domain)

		// send each query on the query channel for the query goroutines
		// to receive
		for _, q := range queries {
			qChan <- q
		}

		row := []string{domain}
		// receive once for each query that was sent
		for _, q := range queries {
			qmResp := <-q.RespChan
			if qmResp.Err != nil {
				inv.Logf("error during query for %v: %v", domain, qmResp.Err)
				continue
			}
			subRow, err := config.ExtractCSVSubRow(qmResp.Resp)
			if err != nil {
				inv.Logf("error extracting CSV sub row: %v", err)
				continue
			}
			row = append(row, subRow...)
		}

		outChan <- row
	}
	wg.Done()
}

func getInfo(config *domainstats.Config, inv *goinvestigate.Investigate, domainChan <-chan string) <-chan []string {
	outChan := make(chan []string, 100)
	qChan := make(chan *domainstats.DomainQueryMessage)
	wg := new(sync.WaitGroup)
	//fns := config.DeriveFuncCalls(inv)
	//fmt.Printf("fns: %v\n", fns)

	// launch the query goroutines
	for i := 0; i < opts.maxGoroutines; i++ {
		go query(qChan)
	}

	// launch the processor goroutines
	for i := 0; i < opts.maxGoroutines; i++ {
		wg.Add(1)
		go process(inv, config, domainChan, qChan, outChan, wg)
	}

	// launch a goroutine which closes the output channel when the processor
	// goroutines are finished
	go func() {
		wg.Wait()
		close(qChan)
		close(outChan)
	}()

	return outChan
}

func readDomainsFrom(fName string) (domains []string) {
	file, err := os.Open(fName)

	if err != nil {
		log.Fatalf("\nError opening domain list %s: %v\n", fName, err)
	}

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		domains = append(domains, scanner.Text())
	}
	return domains
}
<commit_msg>main: remove commented code<commit_after>/*
This program takes a list of domains and queries each against the OpenDNS
Investigate API, optionally outputting a CSV file.

Because querying every endpoint can be very time consuming, this program uses
a TOML file to configure which information should be queried.
*/
package main

import (
	"bufio"
	"encoding/csv"
	"flag"
	"fmt"
	"log"
	"os"
	"runtime"
	"strconv"
	"sync"

	"github.com/dead10ck/domainstats"
	"github.com/dead10ck/goinvestigate"
)

type opt struct {
	verbose       bool
	outFile       string
	configPath    string
	maxGoroutines int
}

var (
	opts              opt
	defaultConfigPath string = os.Getenv("HOME") + "/.domainstats/default.toml"
)

const (
	DEFAULT_MAX_GOROUTINES = 10
)

func init() {
	flag.IntVar(&opts.maxGoroutines, "m", DEFAULT_MAX_GOROUTINES,
		"Maximum number of goroutines to use for parallel HTTP requests")
	flag.BoolVar(&opts.verbose, "v", false, "Print out verbose log messages.")
	flag.StringVar(&opts.outFile, "out", "", "Output matching IPs to the given file")
	flag.StringVar(&opts.configPath, "c", defaultConfigPath, "The config file to use")

	runtime.GOMAXPROCS(runtime.NumCPU())
}

func main() {
	flag.Parse()
	config, err := domainstats.NewConfig(opts.configPath)
	if err != nil {
		log.Fatal(err)
	}
	var outWriter *csv.Writer
	var header []string
	domains := readDomainsFrom(flag.Arg(flag.NArg() - 1))
	inv := goinvestigate.New(config.APIKey)

	if opts.verbose {
		inv.SetVerbose(true)
	}

	if opts.outFile != "" {
		outFile, err := os.Create(opts.outFile)
		if err != nil {
			log.Fatal(err)
		}
		outWriter = csv.NewWriter(outFile)
		outWriter.Comma = rune('\t')
		header = config.DeriveHeader()
		outWriter.Write(header)
		defer func() {
			outWriter.Flush()
			outFile.Close()
		}()
	}

	inChan := make(chan string, len(domains))
	go func() {
		for _, d := range domains {
			inChan <- d
		}
		close(inChan)
	}()

	outChan := getInfo(config, inv, inChan)

	numProcessed := 0

	for respRow := range outChan {
		numProcessed++
		fmt.Printf("\r%120s", " ")
		fmt.Printf("\r%d/%d: %s", numProcessed, len(domains), respRow[0])
		if outWriter != nil {
			outWriter.Write(respRow)
		}
	}
	fmt.Println()
}

func floatToStr(v interface{}) string {
	switch val := v.(type) {
	case float64:
		return strconv.FormatFloat(val, 'f', -1, 64)
	default:
		return ""
	}
}

// The goroutine which does the HTTP queries
func query(qChan <-chan *domainstats.DomainQueryMessage) {
	for m := range qChan {
		m.RespChan <- m.Q.Query()
	}
}

func process(inv *goinvestigate.Investigate, config *domainstats.Config,
	domainChan <-chan string,
	qChan chan<- *domainstats.DomainQueryMessage,
	outChan chan<- []string,
	wg *sync.WaitGroup) {
	for domain := range domainChan {

		// generate the list of queries to make for each domain
		queries := config.DeriveMessages(inv, domain)

		// send each query on the query channel for the query goroutines
		// to receive
		for _, q := range queries {
			qChan <- q
		}

		row := []string{domain}
		// receive once for each query that was sent
		for _, q := range queries {
			qmResp := <-q.RespChan
			if qmResp.Err != nil {
				inv.Logf("error during query for %v: %v", domain, qmResp.Err)
				continue
			}
			subRow, err := config.ExtractCSVSubRow(qmResp.Resp)
			if err != nil {
				inv.Logf("error extracting CSV sub row: %v", err)
				continue
			}
			row = append(row, subRow...)
		}

		outChan <- row
	}
	wg.Done()
}

func getInfo(config *domainstats.Config, inv *goinvestigate.Investigate, domainChan <-chan string) <-chan []string {
	outChan := make(chan []string, 100)
	qChan := make(chan *domainstats.DomainQueryMessage)
	wg := new(sync.WaitGroup)

	// launch the query goroutines
	for i := 0; i < opts.maxGoroutines; i++ {
		go query(qChan)
	}

	// launch the processor goroutines
	for i := 0; i < opts.maxGoroutines; i++ {
		wg.Add(1)
		go process(inv, config, domainChan, qChan, outChan, wg)
	}

	// launch a goroutine which closes the output channel when the processor
	// goroutines are finished
	go func() {
		wg.Wait()
		close(qChan)
		close(outChan)
	}()

	return outChan
}

func readDomainsFrom(fName string) (domains []string) {
	file, err := os.Open(fName)

	if err != nil {
		log.Fatalf("\nError opening domain list %s: %v\n", fName, err)
	}

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		domains = append(domains, scanner.Text())
	}
	return domains
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors All rights reserved.

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 (
	"fmt"
	"os"
	"strings"

	log "github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
)

// Logrus hooks

// Hook for erroring and exit out on warning
type errorOnWarningHook struct{}

func (errorOnWarningHook) Levels() []log.Level {
	return []log.Level{log.WarnLevel}
}

func (errorOnWarningHook) Fire(entry *log.Entry) error {
	log.Fatalln(entry.Message)
	return nil
}

// TODO: comment
var (
	GlobalBundle           string
	GlobalProvider         string
	GlobalVerbose          bool
	GlobalSuppressWarnings bool
	GlobalErrorOnWarning   bool
	GlobalFiles            []string
)

// RootCmd root level flags and commands
var RootCmd = &cobra.Command{
	Use:   "kompose",
	Short: "A tool helping Docker Compose users move to Kubernetes",
	Long:  `Kompose is a tool to help users who are familiar with docker-compose move to Kubernetes.`,
	// PersistentPreRun will be "inherited" by all children and ran before *every* command unless
	// the child has overridden the functionality. This functionality was implemented to check / modify
	// all global flag calls regardless of app call.
	PersistentPreRun: func(cmd *cobra.Command, args []string) {

		// Add extra logging when verbosity is passed
		if GlobalVerbose {
			log.SetLevel(log.DebugLevel)
		}

		// Disable the timestamp (Kompose is too fast!)
		formatter := new(log.TextFormatter)
		formatter.DisableTimestamp = true
		formatter.ForceColors = true
		log.SetFormatter(formatter)

		// Set the appropriate suppress warnings and error on warning flags
		if GlobalSuppressWarnings {
			log.SetLevel(log.ErrorLevel)
		} else if GlobalErrorOnWarning {
			hook := errorOnWarningHook{}
			log.AddHook(hook)
		}

		// Error out of the user has not chosen Kubernetes or OpenShift
		provider := strings.ToLower(GlobalProvider)
		if provider != "kubernetes" && provider != "openshift" {
			log.Fatalf("%s is an unsupported provider. Supported providers are: 'kubernetes', 'openshift'.", GlobalProvider)
		}

	},
}

// Execute TODO: comment
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	RootCmd.PersistentFlags().BoolVarP(&GlobalVerbose, "verbose", "v", false, "verbose output")
	RootCmd.PersistentFlags().BoolVar(&GlobalSuppressWarnings, "suppress-warnings", false, "Suppress all warnings")
	RootCmd.PersistentFlags().BoolVar(&GlobalErrorOnWarning, "error-on-warning", false, "Treat any warning as an error")
	RootCmd.PersistentFlags().StringArrayVarP(&GlobalFiles, "file", "f", []string{}, "Specify an alternative compose file")
	RootCmd.PersistentFlags().StringVarP(&GlobalBundle, "bundle", "b", "", "Specify a Distributed Application Bundle (DAB) file")
	RootCmd.PersistentFlags().StringVar(&GlobalProvider, "provider", "kubernetes", "Specify a provider. Kubernetes or OpenShift.")

	// Mark DAB / bundle as deprecated, see issue: https://github.com/kubernetes/kompose/issues/390
	// As DAB is still EXPERIMENTAL
	RootCmd.PersistentFlags().MarkDeprecated("bundle", "DAB / Bundle is deprecated, see: https://github.com/kubernetes/kompose/issues/390")
}
<commit_msg>Typo fix: erroring -> error (#1032)<commit_after>/*
Copyright 2017 The Kubernetes Authors All rights reserved.

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 (
	"fmt"
	"os"
	"strings"

	log "github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
)

// Logrus hooks

// Hook for error and exit out on warning
type errorOnWarningHook struct{}

func (errorOnWarningHook) Levels() []log.Level {
	return []log.Level{log.WarnLevel}
}

func (errorOnWarningHook) Fire(entry *log.Entry) error {
	log.Fatalln(entry.Message)
	return nil
}

// TODO: comment
var (
	GlobalBundle           string
	GlobalProvider         string
	GlobalVerbose          bool
	GlobalSuppressWarnings bool
	GlobalErrorOnWarning   bool
	GlobalFiles            []string
)

// RootCmd root level flags and commands
var RootCmd = &cobra.Command{
	Use:   "kompose",
	Short: "A tool helping Docker Compose users move to Kubernetes",
	Long:  `Kompose is a tool to help users who are familiar with docker-compose move to Kubernetes.`,
	// PersistentPreRun will be "inherited" by all children and ran before *every* command unless
	// the child has overridden the functionality. This functionality was implemented to check / modify
	// all global flag calls regardless of app call.
	PersistentPreRun: func(cmd *cobra.Command, args []string) {

		// Add extra logging when verbosity is passed
		if GlobalVerbose {
			log.SetLevel(log.DebugLevel)
		}

		// Disable the timestamp (Kompose is too fast!)
		formatter := new(log.TextFormatter)
		formatter.DisableTimestamp = true
		formatter.ForceColors = true
		log.SetFormatter(formatter)

		// Set the appropriate suppress warnings and error on warning flags
		if GlobalSuppressWarnings {
			log.SetLevel(log.ErrorLevel)
		} else if GlobalErrorOnWarning {
			hook := errorOnWarningHook{}
			log.AddHook(hook)
		}

		// Error out of the user has not chosen Kubernetes or OpenShift
		provider := strings.ToLower(GlobalProvider)
		if provider != "kubernetes" && provider != "openshift" {
			log.Fatalf("%s is an unsupported provider. Supported providers are: 'kubernetes', 'openshift'.", GlobalProvider)
		}

	},
}

// Execute TODO: comment
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	RootCmd.PersistentFlags().BoolVarP(&GlobalVerbose, "verbose", "v", false, "verbose output")
	RootCmd.PersistentFlags().BoolVar(&GlobalSuppressWarnings, "suppress-warnings", false, "Suppress all warnings")
	RootCmd.PersistentFlags().BoolVar(&GlobalErrorOnWarning, "error-on-warning", false, "Treat any warning as an error")
	RootCmd.PersistentFlags().StringArrayVarP(&GlobalFiles, "file", "f", []string{}, "Specify an alternative compose file")
	RootCmd.PersistentFlags().StringVarP(&GlobalBundle, "bundle", "b", "", "Specify a Distributed Application Bundle (DAB) file")
	RootCmd.PersistentFlags().StringVar(&GlobalProvider, "provider", "kubernetes", "Specify a provider. Kubernetes or OpenShift.")

	// Mark DAB / bundle as deprecated, see issue: https://github.com/kubernetes/kompose/issues/390
	// As DAB is still EXPERIMENTAL
	RootCmd.PersistentFlags().MarkDeprecated("bundle", "DAB / Bundle is deprecated, see: https://github.com/kubernetes/kompose/issues/390")
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2016 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package cmd

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/modules/git"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/pprof"
	"code.gitea.io/gitea/modules/private"
	"code.gitea.io/gitea/modules/setting"

	"github.com/Unknwon/com"
	"github.com/dgrijalva/jwt-go"
	version "github.com/mcuadros/go-version"
	"github.com/urfave/cli"
)

const (
	accessDenied        = "Repository does not exist or you do not have access"
	lfsAuthenticateVerb = "git-lfs-authenticate"
)

// CmdServ represents the available serv sub-command.
var CmdServ = cli.Command{
	Name:        "serv",
	Usage:       "This command should only be called by SSH shell",
	Description: `Serv provide access auth for repositories`,
	Action:      runServ,
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name: "enable-pprof",
		},
	},
}

func checkLFSVersion() {
	if setting.LFS.StartServer {
		//Disable LFS client hooks if installed for the current OS user
		//Needs at least git v2.1.2
		binVersion, err := git.BinVersion()
		if err != nil {
			fail("LFS server error", "Error retrieving git version: %v", err)
		}

		if !version.Compare(binVersion, "2.1.2", ">=") {
			setting.LFS.StartServer = false
			println("LFS server support needs at least Git v2.1.2, disabled")
		} else {
			git.GlobalCommandArgs = append(git.GlobalCommandArgs, "-c", "filter.lfs.required=",
				"-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=")
		}
	}
}

func setup(logPath string) {
	log.DelLogger("console")
	setting.NewContext()
	checkLFSVersion()
}

func parseCmd(cmd string) (string, string) {
	ss := strings.SplitN(cmd, " ", 2)
	if len(ss) != 2 {
		return "", ""
	}
	return ss[0], strings.Replace(ss[1], "'/", "'", 1)
}

var (
	allowedCommands = map[string]models.AccessMode{
		"git-upload-pack":    models.AccessModeRead,
		"git-upload-archive": models.AccessModeRead,
		"git-receive-pack":   models.AccessModeWrite,
		lfsAuthenticateVerb:  models.AccessModeNone,
	}
)

func fail(userMessage, logMessage string, args ...interface{}) {
	fmt.Fprintln(os.Stderr, "Gitea:", userMessage)

	if len(logMessage) > 0 {
		if !setting.ProdMode {
			fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
		}
		return
	}

	os.Exit(1)
}

func runServ(c *cli.Context) error {
	// FIXME: This needs to internationalised
	setup("serv.log")

	if setting.SSH.Disabled {
		println("Gitea: SSH has been disabled")
		return nil
	}

	if len(c.Args()) < 1 {
		cli.ShowSubcommandHelp(c)
		return nil
	}

	keys := strings.Split(c.Args()[0], "-")
	if len(keys) != 2 || keys[0] != "key" {
		fail("Key ID format error", "Invalid key argument: %s", c.Args()[0])
	}
	keyID := com.StrTo(keys[1]).MustInt64()

	cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
	if len(cmd) == 0 {
		key, user, err := private.ServNoCommand(keyID)
		if err != nil {
			fail("Internal error", "Failed to check provided key: %v", err)
		}
		if key.Type == models.KeyTypeDeploy {
			println("Hi there! You've successfully authenticated with the deploy key named " + key.Name + ", but Gitea does not provide shell access.")
		} else {
			println("Hi there: " + user.Name + "! You've successfully authenticated with the key named " + key.Name + ", but Gitea does not provide shell access.")
		}
		println("If this is unexpected, please log in with password and setup Gitea under another user.")
		return nil
	}

	verb, args := parseCmd(cmd)

	var lfsVerb string
	if verb == lfsAuthenticateVerb {
		if !setting.LFS.StartServer {
			fail("Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled")
		}

		argsSplit := strings.Split(args, " ")
		if len(argsSplit) >= 2 {
			args = strings.TrimSpace(argsSplit[0])
			lfsVerb = strings.TrimSpace(argsSplit[1])
		}
	}

	repoPath := strings.ToLower(strings.Trim(args, "'"))
	rr := strings.SplitN(repoPath, "/", 2)
	if len(rr) != 2 {
		fail("Invalid repository path", "Invalid repository path: %v", args)
	}

	username := strings.ToLower(rr[0])
	reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))

	if setting.EnablePprof || c.Bool("enable-pprof") {
		if err := os.MkdirAll(setting.PprofDataPath, os.ModePerm); err != nil {
			fail("Error while trying to create PPROF_DATA_PATH", "Error while trying to create PPROF_DATA_PATH: %v", err)
		}

		stopCPUProfiler, err := pprof.DumpCPUProfileForUsername(setting.PprofDataPath, username)
		if err != nil {
			fail("Internal Server Error", "Unable to start CPU profile: %v", err)
		}
		defer func() {
			stopCPUProfiler()
			err := pprof.DumpMemProfileForUsername(setting.PprofDataPath, username)
			if err != nil {
				fail("Internal Server Error", "Unable to dump Mem Profile: %v", err)
			}
		}()
	}

	requestedMode, has := allowedCommands[verb]
	if !has {
		fail("Unknown git command", "Unknown git command %s", verb)
	}

	if verb == lfsAuthenticateVerb {
		if lfsVerb == "upload" {
			requestedMode = models.AccessModeWrite
		} else if lfsVerb == "download" {
			requestedMode = models.AccessModeRead
		} else {
			fail("Unknown LFS verb", "Unknown lfs verb %s", lfsVerb)
		}
	}

	results, err := private.ServCommand(keyID, username, reponame, requestedMode, verb, lfsVerb)
	if err != nil {
		if private.IsErrServCommand(err) {
			errServCommand := err.(private.ErrServCommand)
			if errServCommand.StatusCode != http.StatusInternalServerError {
				fail("Unauthorized", "%s", errServCommand.Error())
			} else {
				fail("Internal Server Error", "%s", errServCommand.Error())
			}
		}
		fail("Internal Server Error", "%s", err.Error())
	}
	os.Setenv(models.EnvRepoIsWiki, strconv.FormatBool(results.IsWiki))
	os.Setenv(models.EnvRepoName, results.RepoName)
	os.Setenv(models.EnvRepoUsername, results.OwnerName)
	os.Setenv(models.EnvPusherName, username)
	os.Setenv(models.EnvPusherID, strconv.FormatInt(results.UserID, 10))
	os.Setenv(models.ProtectedBranchRepoID, strconv.FormatInt(results.RepoID, 10))

	//LFS token authentication
	if verb == lfsAuthenticateVerb {
		url := fmt.Sprintf("%s%s/%s.git/info/lfs", setting.AppURL, url.PathEscape(results.OwnerName), url.PathEscape(results.RepoName))

		now := time.Now()
		claims := jwt.MapClaims{
			"repo": results.RepoID,
			"op":   lfsVerb,
			"exp":  now.Add(setting.LFS.HTTPAuthExpiry).Unix(),
			"nbf":  now.Unix(),
			"user": results.UserID,
		}
		token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

		// Sign and get the complete encoded token as a string using the secret
		tokenString, err := token.SignedString(setting.LFS.JWTSecretBytes)
		if err != nil {
			fail("Internal error", "Failed to sign JWT token: %v", err)
		}

		tokenAuthentication := &models.LFSTokenResponse{
			Header: make(map[string]string),
			Href:   url,
		}
		tokenAuthentication.Header["Authorization"] = fmt.Sprintf("Bearer %s", tokenString)

		enc := json.NewEncoder(os.Stdout)
		err = enc.Encode(tokenAuthentication)
		if err != nil {
			fail("Internal error", "Failed to encode LFS json response: %v", err)
		}
		return nil
	}

	// Special handle for Windows.
	if setting.IsWindows {
		verb = strings.Replace(verb, "-", " ", 1)
	}

	var gitcmd *exec.Cmd
	verbs := strings.Split(verb, " ")
	if len(verbs) == 2 {
		gitcmd = exec.Command(verbs[0], verbs[1], repoPath)
	} else {
		gitcmd = exec.Command(verb, repoPath)
	}

	os.Setenv(models.ProtectedBranchRepoID, fmt.Sprintf("%d", results.RepoID))

	gitcmd.Dir = setting.RepoRootPath
	gitcmd.Stdout = os.Stdout
	gitcmd.Stdin = os.Stdin
	gitcmd.Stderr = os.Stderr
	if err = gitcmd.Run(); err != nil {
		fail("Internal error", "Failed to execute git command: %v", err)
	}

	// Update user key activity.
	if results.KeyID > 0 {
		if err = private.UpdatePublicKeyInRepo(results.KeyID, results.RepoID); err != nil {
			fail("Internal error", "UpdatePublicKeyInRepo: %v", err)
		}
	}

	return nil
}
<commit_msg>fix pusher name via ssh push (#7167)<commit_after>// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2016 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package cmd

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/modules/git"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/pprof"
	"code.gitea.io/gitea/modules/private"
	"code.gitea.io/gitea/modules/setting"

	"github.com/Unknwon/com"
	"github.com/dgrijalva/jwt-go"
	version "github.com/mcuadros/go-version"
	"github.com/urfave/cli"
)

const (
	accessDenied        = "Repository does not exist or you do not have access"
	lfsAuthenticateVerb = "git-lfs-authenticate"
)

// CmdServ represents the available serv sub-command.
var CmdServ = cli.Command{
	Name:        "serv",
	Usage:       "This command should only be called by SSH shell",
	Description: `Serv provide access auth for repositories`,
	Action:      runServ,
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name: "enable-pprof",
		},
	},
}

func checkLFSVersion() {
	if setting.LFS.StartServer {
		//Disable LFS client hooks if installed for the current OS user
		//Needs at least git v2.1.2
		binVersion, err := git.BinVersion()
		if err != nil {
			fail("LFS server error", "Error retrieving git version: %v", err)
		}

		if !version.Compare(binVersion, "2.1.2", ">=") {
			setting.LFS.StartServer = false
			println("LFS server support needs at least Git v2.1.2, disabled")
		} else {
			git.GlobalCommandArgs = append(git.GlobalCommandArgs, "-c", "filter.lfs.required=",
				"-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=")
		}
	}
}

func setup(logPath string) {
	log.DelLogger("console")
	setting.NewContext()
	checkLFSVersion()
}

func parseCmd(cmd string) (string, string) {
	ss := strings.SplitN(cmd, " ", 2)
	if len(ss) != 2 {
		return "", ""
	}
	return ss[0], strings.Replace(ss[1], "'/", "'", 1)
}

var (
	allowedCommands = map[string]models.AccessMode{
		"git-upload-pack":    models.AccessModeRead,
		"git-upload-archive": models.AccessModeRead,
		"git-receive-pack":   models.AccessModeWrite,
		lfsAuthenticateVerb:  models.AccessModeNone,
	}
)

func fail(userMessage, logMessage string, args ...interface{}) {
	fmt.Fprintln(os.Stderr, "Gitea:", userMessage)

	if len(logMessage) > 0 {
		if !setting.ProdMode {
			fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
		}
		return
	}

	os.Exit(1)
}

func runServ(c *cli.Context) error {
	// FIXME: This needs to internationalised
	setup("serv.log")

	if setting.SSH.Disabled {
		println("Gitea: SSH has been disabled")
		return nil
	}

	if len(c.Args()) < 1 {
		cli.ShowSubcommandHelp(c)
		return nil
	}

	keys := strings.Split(c.Args()[0], "-")
	if len(keys) != 2 || keys[0] != "key" {
		fail("Key ID format error", "Invalid key argument: %s", c.Args()[0])
	}
	keyID := com.StrTo(keys[1]).MustInt64()

	cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
	if len(cmd) == 0 {
		key, user, err := private.ServNoCommand(keyID)
		if err != nil {
			fail("Internal error", "Failed to check provided key: %v", err)
		}
		if key.Type == models.KeyTypeDeploy {
			println("Hi there! You've successfully authenticated with the deploy key named " + key.Name + ", but Gitea does not provide shell access.")
		} else {
			println("Hi there: " + user.Name + "! You've successfully authenticated with the key named " + key.Name + ", but Gitea does not provide shell access.")
		}
		println("If this is unexpected, please log in with password and setup Gitea under another user.")
		return nil
	}

	verb, args := parseCmd(cmd)

	var lfsVerb string
	if verb == lfsAuthenticateVerb {
		if !setting.LFS.StartServer {
			fail("Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled")
		}

		argsSplit := strings.Split(args, " ")
		if len(argsSplit) >= 2 {
			args = strings.TrimSpace(argsSplit[0])
			lfsVerb = strings.TrimSpace(argsSplit[1])
		}
	}

	repoPath := strings.ToLower(strings.Trim(args, "'"))
	rr := strings.SplitN(repoPath, "/", 2)
	if len(rr) != 2 {
		fail("Invalid repository path", "Invalid repository path: %v", args)
	}

	username := strings.ToLower(rr[0])
	reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))

	if setting.EnablePprof || c.Bool("enable-pprof") {
		if err := os.MkdirAll(setting.PprofDataPath, os.ModePerm); err != nil {
			fail("Error while trying to create PPROF_DATA_PATH", "Error while trying to create PPROF_DATA_PATH: %v", err)
		}

		stopCPUProfiler, err := pprof.DumpCPUProfileForUsername(setting.PprofDataPath, username)
		if err != nil {
			fail("Internal Server Error", "Unable to start CPU profile: %v", err)
		}
		defer func() {
			stopCPUProfiler()
			err := pprof.DumpMemProfileForUsername(setting.PprofDataPath, username)
			if err != nil {
				fail("Internal Server Error", "Unable to dump Mem Profile: %v", err)
			}
		}()
	}

	requestedMode, has := allowedCommands[verb]
	if !has {
		fail("Unknown git command", "Unknown git command %s", verb)
	}

	if verb == lfsAuthenticateVerb {
		if lfsVerb == "upload" {
			requestedMode = models.AccessModeWrite
		} else if lfsVerb == "download" {
			requestedMode = models.AccessModeRead
		} else {
			fail("Unknown LFS verb", "Unknown lfs verb %s", lfsVerb)
		}
	}

	results, err := private.ServCommand(keyID, username, reponame, requestedMode, verb, lfsVerb)
	if err != nil {
		if private.IsErrServCommand(err) {
			errServCommand := err.(private.ErrServCommand)
			if errServCommand.StatusCode != http.StatusInternalServerError {
				fail("Unauthorized", "%s", errServCommand.Error())
			} else {
				fail("Internal Server Error", "%s", errServCommand.Error())
			}
		}
		fail("Internal Server Error", "%s", err.Error())
	}
	os.Setenv(models.EnvRepoIsWiki, strconv.FormatBool(results.IsWiki))
	os.Setenv(models.EnvRepoName, results.RepoName)
	os.Setenv(models.EnvRepoUsername, results.OwnerName)
	os.Setenv(models.EnvPusherName, results.UserName)
	os.Setenv(models.EnvPusherID, strconv.FormatInt(results.UserID, 10))
	os.Setenv(models.ProtectedBranchRepoID, strconv.FormatInt(results.RepoID, 10))

	//LFS token authentication
	if verb == lfsAuthenticateVerb {
		url := fmt.Sprintf("%s%s/%s.git/info/lfs", setting.AppURL, url.PathEscape(results.OwnerName), url.PathEscape(results.RepoName))

		now := time.Now()
		claims := jwt.MapClaims{
			"repo": results.RepoID,
			"op":   lfsVerb,
			"exp":  now.Add(setting.LFS.HTTPAuthExpiry).Unix(),
			"nbf":  now.Unix(),
			"user": results.UserID,
		}
		token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

		// Sign and get the complete encoded token as a string using the secret
		tokenString, err := token.SignedString(setting.LFS.JWTSecretBytes)
		if err != nil {
			fail("Internal error", "Failed to sign JWT token: %v", err)
		}

		tokenAuthentication := &models.LFSTokenResponse{
			Header: make(map[string]string),
			Href:   url,
		}
		tokenAuthentication.Header["Authorization"] = fmt.Sprintf("Bearer %s", tokenString)

		enc := json.NewEncoder(os.Stdout)
		err = enc.Encode(tokenAuthentication)
		if err != nil {
			fail("Internal error", "Failed to encode LFS json response: %v", err)
		}
		return nil
	}

	// Special handle for Windows.
	if setting.IsWindows {
		verb = strings.Replace(verb, "-", " ", 1)
	}

	var gitcmd *exec.Cmd
	verbs := strings.Split(verb, " ")
	if len(verbs) == 2 {
		gitcmd = exec.Command(verbs[0], verbs[1], repoPath)
	} else {
		gitcmd = exec.Command(verb, repoPath)
	}

	os.Setenv(models.ProtectedBranchRepoID, fmt.Sprintf("%d", results.RepoID))

	gitcmd.Dir = setting.RepoRootPath
	gitcmd.Stdout = os.Stdout
	gitcmd.Stdin = os.Stdin
	gitcmd.Stderr = os.Stderr
	if err = gitcmd.Run(); err != nil {
		fail("Internal error", "Failed to execute git command: %v", err)
	}

	// Update user key activity.
	if results.KeyID > 0 {
		if err = private.UpdatePublicKeyInRepo(results.KeyID, results.RepoID); err != nil {
			fail("Internal error", "UpdatePublicKeyInRepo: %v", err)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"path/filepath"
	"regexp"

	"github.com/dtan4/valec/aws"
	"github.com/dtan4/valec/lib"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

var (
	yamlExtRegexp = regexp.MustCompile(`\.[yY][aA]?[mM][lL]$`)
)

// syncCmd represents the sync command
var syncCmd = &cobra.Command{
	Use:   "sync",
	Short: "Synchronize secrets between local file and DynamoDB",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) != 1 {
			return errors.New("Please specify config file.")
		}
		filename := args[0]

		configs, err := lib.LoadConfigYAML(filename)
		if err != nil {
			return errors.Wrapf(err, "Failed to load configs. filename=%s", filename)
		}

		namespace := yamlExtRegexp.ReplaceAllString(filepath.Base(filename), "")

		if err := aws.DynamoDB().Insert(tableName, namespace, configs); err != nil {
			return errors.Wrapf(err, "Failed to insert configs. namespace=%s", namespace)
		}

		fmt.Printf("%d configs of %q namespace are successfully synchronized!\n", len(configs), namespace)

		return nil
	},
}

func init() {
	RootCmd.AddCommand(syncCmd)
}
<commit_msg>Enable to specify namespace with sync<commit_after>package cmd

import (
	"fmt"
	"path/filepath"
	"regexp"

	"github.com/dtan4/valec/aws"
	"github.com/dtan4/valec/lib"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

var (
	yamlExtRegexp = regexp.MustCompile(`\.[yY][aA]?[mM][lL]$`)
)

// syncCmd represents the sync command
var syncCmd = &cobra.Command{
	Use:   "sync CONFIGFILE [NAMESPACE]",
	Short: "Synchronize secrets between local file and DynamoDB",
	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) < 1 {
			return errors.New("Please specify config file.")
		}
		filename := args[0]

		configs, err := lib.LoadConfigYAML(filename)
		if err != nil {
			return errors.Wrapf(err, "Failed to load configs. filename=%s", filename)
		}

		var namespace string

		if len(args) == 1 {
			namespace = yamlExtRegexp.ReplaceAllString(filepath.Base(filename), "")
		} else {
			namespace = args[1]
		}

		if err := aws.DynamoDB().Insert(tableName, namespace, configs); err != nil {
			return errors.Wrapf(err, "Failed to insert configs. namespace=%s", namespace)
		}

		fmt.Printf("%d configs of %q namespace are successfully synchronized!\n", len(configs), namespace)

		return nil
	},
}

func init() {
	RootCmd.AddCommand(syncCmd)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"path/filepath"

	"github.com/gonuts/commander"
	"github.com/gonuts/flag"
	"github.com/lhcb-org/lbx/lbx"
)

func lbx_make_cmd_init() *commander.Command {
	cmd := &commander.Command{
		Run:       lbx_run_cmd_init,
		UsageLine: "init [options] <project-name> <project-version>",
		Short:     "initialize a local development project.",
		Long: `
init initialize a local development project.

ex:
 $ lbx init Gaudi trunk
 $ lbx init -name mydev Gaudi trunk
`,
		Flag: *flag.NewFlagSet("lbx-init", flag.ExitOnError),
	}
	add_output_level(cmd)
	add_search_path(cmd)

	cmd.Flag.String("name", "", "name of the local project (default: <project>Dev_<version>)")
	return cmd
}

func lbx_run_cmd_init(cmd *commander.Command, args []string) error {
	var err error

	proj := ""
	vers := ""

	switch len(args) {
	case 1:
		proj = args[0]
		vers = "trunk"
	case 2:
		proj = args[0]
		vers = args[1]
	default:
		g_ctx.Errorf("lbx-init: needs 2 args (project+version). got=%d\n", len(args))
		return fmt.Errorf("lbx-init: invalid number of arguments")
	}

	proj = lbx.FixProjectCase(proj)

	dirname := cmd.Flag.Lookup("name").Value.Get().(string)
	local_proj, local_vers := dirname, "HEAD"
	if dirname == "" {
		dirname = proj + "Dev_" + vers
		local_proj = proj + "Dev"
		local_vers = vers
	}

	usr_area := cmd.Flag.Lookup("user-area").Value.Get().(string)
	if usr_area == "" {
		g_ctx.Errorf("lbx-init: user area not defined (env.var. User_release_area or option -user-area)\n")
		return fmt.Errorf("lbx-init: user-area not defined")
	}
	projdir := filepath.Join(usr_area, dirname)
	if path_exists(projdir) {
		g_ctx.Errorf("lbx-init: directory %q already exists\n", projdir)
		return fmt.Errorf("lbx-init: invalid project dir")
	}

	g_ctx.Infof(">>> project=%q version=%q\n", proj, vers)
	g_ctx.Infof("local-proj=%q\n", local_proj)
	g_ctx.Infof("local-vers=%q\n", local_vers)
	g_ctx.Infof("proj-dir=%q\n", projdir)
	return err
}
<commit_msg>lbx-init: add platform flag<commit_after>package main

import (
	"fmt"
	"path/filepath"

	"github.com/gonuts/commander"
	"github.com/gonuts/flag"
	"github.com/lhcb-org/lbx/lbx"
)

func lbx_make_cmd_init() *commander.Command {
	cmd := &commander.Command{
		Run:       lbx_run_cmd_init,
		UsageLine: "init [options] <project-name> <project-version>",
		Short:     "initialize a local development project.",
		Long: `
init initialize a local development project.

ex:
 $ lbx init Gaudi trunk
 $ lbx init -name mydev Gaudi trunk
`,
		Flag: *flag.NewFlagSet("lbx-init", flag.ExitOnError),
	}
	add_output_level(cmd)
	add_search_path(cmd)
	add_platform(cmd)

	cmd.Flag.String("name", "", "name of the local project (default: <project>Dev_<version>)")
	return cmd
}

func lbx_run_cmd_init(cmd *commander.Command, args []string) error {
	var err error

	proj := ""
	vers := ""

	switch len(args) {
	case 1:
		proj = args[0]
		vers = "trunk"
	case 2:
		proj = args[0]
		vers = args[1]
	default:
		g_ctx.Errorf("lbx-init: needs 2 args (project+version). got=%d\n", len(args))
		return fmt.Errorf("lbx-init: invalid number of arguments")
	}

	proj = lbx.FixProjectCase(proj)

	dirname := cmd.Flag.Lookup("name").Value.Get().(string)
	local_proj, local_vers := dirname, "HEAD"
	if dirname == "" {
		dirname = proj + "Dev_" + vers
		local_proj = proj + "Dev"
		local_vers = vers
	}

	usr_area := cmd.Flag.Lookup("user-area").Value.Get().(string)
	if usr_area == "" {
		g_ctx.Errorf("lbx-init: user area not defined (env.var. User_release_area or option -user-area)\n")
		return fmt.Errorf("lbx-init: user-area not defined")
	}
	projdir := filepath.Join(usr_area, dirname)
	if path_exists(projdir) {
		g_ctx.Errorf("lbx-init: directory %q already exists\n", projdir)
		return fmt.Errorf("lbx-init: invalid project dir")
	}

	platform := cmd.Flag.Lookup("c").Value.Get().(string)

	g_ctx.Infof(">>> project=%q version=%q\n", proj, vers)
	g_ctx.Infof("local-proj=%q\n", local_proj)
	g_ctx.Infof("local-vers=%q\n", local_vers)
	g_ctx.Infof("proj-dir=%q\n", projdir)
	g_ctx.Infof("platform=%q\n", platform)

	return err
}
<|endoftext|>


<commit_before>package zip

import (
	"archive/zip"
	"github.com/shinofara/stand/config"
	"github.com/shinofara/stand/find"
	"io/ioutil"
	"os"
)

func Compress(cfg *config.Config) error {
	var zipfile *os.File
	var err error

	// Create a buffer to write our archive to.
	if zipfile, err = os.Create(cfg.ZipName); err != nil {
		return err
	}
	defer zipfile.Close()

	w := zip.NewWriter(zipfile)

	files, _ := find.All(cfg.TargetDir)
	for _, file := range files {
		f, err := w.Create(file)
		if err != nil {
			return err
		}

		contents, _ := ioutil.ReadFile(cfg.TargetDir + "/" + file)
		_, err = f.Write(contents)
		if err != nil {
			return err
		}
	}

	err = w.Close()
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>outputへ移動<commit_after>package zip

import (
	"archive/zip"
	"fmt"
	"github.com/shinofara/stand/config"
	"github.com/shinofara/stand/find"
	"io/ioutil"
	"os"
)

func Compress(cfg *config.Config) error {
	var zipfile *os.File
	var err error

	if err := os.Mkdir(cfg.OutputDir, 0777); err != nil {
		return err
	}

	// Create a buffer to write our archive to.
	output := fmt.Sprintf("%s/%s", cfg.OutputDir, cfg.ZipName)
	if zipfile, err = os.Create(output); err != nil {
		return err
	}
	defer zipfile.Close()

	w := zip.NewWriter(zipfile)

	files, _ := find.All(cfg.TargetDir)
	for _, file := range files {
		f, err := w.Create(file)
		if err != nil {
			return err
		}

		contents, _ := ioutil.ReadFile(cfg.TargetDir + "/" + file)
		_, err = f.Write(contents)
		if err != nil {
			return err
		}
	}

	err = w.Close()
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before><commit_msg>initfuncs: add global var<commit_after><|endoftext|>


<commit_before>package goprismic

import (
	"github.com/SoCloz/goprismic/fragment"
)

// A document is made of fragments of various types
type Document struct {
	Id        string       `json:"id"`
	Type      string       `json:"type"`
	Href      string       `json:"href"`
	Tags      []string     `json:"tags"`
	Slugs     []string     `json:"slugs"`
	Fragments FragmentTree `json:"data"`
}

// Returns the document slug
func (d *Document) GetSlug() string {
	return d.Slugs[0]
}

// Returns the list of fragments of a certain name
func (d *Document) GetFragments(field string) (FragmentList, bool) {
	frags, found := d.Fragments[d.Type]
	if !found {
		return nil, false
	}
	f, found := frags[field]
	return f, found
}

// Returns the nth fragment of a certain name
func (d *Document) GetFragmentAt(field string, index int) (FragmentInterface, bool) {
	frags, found := d.GetFragments(field)
	if !found || len(frags) < index {
		return nil, false
	}
	return frags[index], true
}

// Returns the first fragment of a certain name
func (d *Document) GetFragment(field string) (FragmentInterface, bool) {
	return d.GetFragmentAt(field, 0)
}

// Returns an image fragment (the first found)
func (d *Document) GetImage(field string) (*fragment.Image, bool) {
	f, found := d.GetFragment(field)
	if !found {
		return nil, false
	}
	i, ok := f.(*fragment.Image)
	if !ok {
		return nil, false
	}
	return i, true
}

// Returns s structured text fragment (the first found)
func (d *Document) GetStructuredText(field string) (*fragment.StructuredText, bool) {
	f, found := d.GetFragment(field)
	if !found {
		return nil, false
	}
	st, ok := f.(*fragment.StructuredText)
	if !ok {
		return nil, false
	}
	return st, true
}

// Returns a color fragment (the first found)
func (d *Document) GetColor(field string) (*fragment.Color, bool) {
	f, found := d.GetFragment(field)
	if !found {
		return nil, false
	}
	st, ok := f.(*fragment.Color)
	if !ok {
		return nil, false
	}
	return st, true
}

// Returns a number fragment (the first found)
func (d *Document) GetNumber(field string) (*fragment.Number, bool) {
	f, found := d.GetFragment(field)
	if !found {
		return nil, false
	}
	st, ok := f.(*fragment.Number)
	if !ok {
		return nil, false
	}
	return st, true
}

// Returns a text fragment (the first found)
func (d *Document) GetText(field string) (*fragment.Text, bool) {
	f, found := d.GetFragment(field)
	if !found {
		return nil, false
	}
	st, ok := f.(*fragment.Text)
	if !ok {
		return nil, false
	}
	return st, true
}

// Returns a document link fragment (the first found)
func (d *Document) GetDocumentLink(field string) (*fragment.DocumentLink, bool) {
	f, found := d.GetFragment(field)
	if !found {
		return nil, false
	}
	st, ok := f.(*fragment.DocumentLink)
	if !ok {
		return nil, false
	}
	return st, true
}

// Returns a web link fragment (the first found)
func (d *Document) GetWebLink(field string) (*fragment.WebLink, bool) {
	f, found := d.GetFragment(field)
	if !found {
		return nil, false
	}
	st, ok := f.(*fragment.WebLink)
	if !ok {
		return nil, false
	}
	return st, true
}
<commit_msg>document: add helpers<commit_after>package goprismic

import (
	"time"

	"github.com/SoCloz/goprismic/fragment"
)

// A document is made of fragments of various types
type Document struct {
	Id        string       `json:"id"`
	Type      string       `json:"type"`
	Href      string       `json:"href"`
	Tags      []string     `json:"tags"`
	Slugs     []string     `json:"slugs"`
	Fragments FragmentTree `json:"data"`
}

// Returns the document slug
func (d *Document) GetSlug() string {
	return d.Slugs[0]
}

// Tests if the document has a slug
func (d *Document) HasSlug(slug string) bool {
	for _, v := range d.Slugs {
		if v == slug {
			return true
		}
	}
	return false
}

// Returns the list of fragments of a certain name
func (d *Document) GetFragments(field string) (FragmentList, bool) {
	frags, found := d.Fragments[d.Type]
	if !found {
		return nil, false
	}
	f, found := frags[field]
	return f, found
}

// Returns the nth fragment of a certain name
func (d *Document) GetFragmentAt(field string, index int) (FragmentInterface, bool) {
	frags, found := d.GetFragments(field)
	if !found || len(frags) < index {
		return nil, false
	}
	return frags[index], true
}

// Returns the first fragment of a certain name
func (d *Document) GetFragment(field string) (FragmentInterface, bool) {
	return d.GetFragmentAt(field, 0)
}

// Returns an image fragment (the first found)
func (d *Document) GetImageFragment(field string) (*fragment.Image, bool) {
	f, found := d.GetFragment(field)
	if !found {
		return nil, false
	}
	i, ok := f.(*fragment.Image)
	if !ok {
		return nil, false
	}
	return i, true
}

// Returns s structured text fragment (the first found)
func (d *Document) GetStructuredTextFragment(field string) (*fragment.StructuredText, bool) {
	f, found := d.GetFragment(field)
	if !found {
		return nil, false
	}
	st, ok := f.(*fragment.StructuredText)
	if !ok {
		return nil, false
	}
	return st, true
}

// Returns a color fragment (the first found)
func (d *Document) GetColorFragment(field string) (*fragment.Color, bool) {
	f, found := d.GetFragment(field)
	if !found {
		return nil, false
	}
	c, ok := f.(*fragment.Color)
	if !ok {
		return  nil, false
	}
	return c, true
}

// Returns a color value (the first found)
func (d *Document) GetColor(field string) (string, bool) {
	c, found := d.GetColorFragment(field)
	if !found {
		return "", false
	}
	return string(*c), true
}

// Returns a number fragment (the first found)
func (d *Document) GetNumberFragment(field string) (*fragment.Number, bool) {
	f, found := d.GetFragment(field)
	if !found {
		return nil, false
	}
	n, ok := f.(*fragment.Number)
	if !ok {
		return nil, false
	}
	return n, true
}

// Returns a number value (the first found)
func (d *Document) GetNumber(field string) (float64, bool) {
	n, found := d.GetNumberFragment(field)
	if !found {
		return float64(0), false
	}
	return float64(*n), true
}

// Returns a text fragment (the first found)
func (d *Document) GetTextFragment(field string) (*fragment.Text, bool) {
	f, found := d.GetFragment(field)
	if !found {
		return nil, false
	}
	t, ok := f.(*fragment.Text)
	if !ok {
		return nil, false
	}
	return t, true
}

// Returns a text value (the first found)
func (d *Document) GetText(field string) (string, bool) {
	f, found := d.GetFragment(field)
	if !found {
		return "", false
	}
	return f.AsText(), true
}

// Returns the boolean representation of a fragment (the first found)
func (d *Document) GetBool(field string) (bool, bool) {
	t, found := d.GetText(field)
	return (t == "yes" || t == "true"), found
}

// Returns a date fragment (the first found)
func (d *Document) GetDateFragment(field string) (*fragment.Date, bool) {
	f, found := d.GetFragment(field)
	if !found {
		return nil, false
	}
	t, ok := f.(*fragment.Date)
	if !ok {
		return nil, false
	}
	return t, true
}

// Returns a date value (the first found)
func (d *Document) GetDate(field string) (time.Time, bool) {
	t, found := d.GetDateFragment(field)
	if !found {
		return time.Time{}, false
	}
	return time.Time(*t), true
}

// Returns a document link fragment (the first found)
func (d *Document) GetDocumentLinkFragment(field string) (*fragment.DocumentLink, bool) {
	f, found := d.GetFragment(field)
	if !found {
		return nil, false
	}
	st, ok := f.(*fragment.DocumentLink)
	if !ok {
		return nil, false
	}
	return st, true
}

// Returns a web link fragment (the first found)
func (d *Document) GetWebLinkFragment(field string) (*fragment.WebLink, bool) {
	f, found := d.GetFragment(field)
	if !found {
		return nil, false
	}
	st, ok := f.(*fragment.WebLink)
	if !ok {
		return nil, false
	}
	return st, true
}
<|endoftext|>


<commit_before>package dev

import (
	"fmt"
	"encoding/json"
	"errors"
)

type Move struct {
	origin      *Square
	destination *Square
}

func NewMove(origin, destination *Square) (*Move, error) {
	var m Move
	m.origin = origin
	m.destination = destination

}

func (m *Move)Name() string {
	return fmt.Sprintln(m.origin.piece.GetName(), m.origin.Name(), m.destination.Name())
}

func (m *Move)Apply() error {
	if isValid, err := !m.IsValid(); !isValid {
		return err
	}
	if err := m.destination.NewPiece(m.origin.piece); err != nil {
		return err
	}
	m.origin.piece == nil
	m.origin.isOccupied = false
	return nil
}

func (m *Move)IsValid() (bool, error) {

	d := m.destination
	o := m.origin

	if d == nil {
		return false, errors.New("nil destination")
	}

	if o == nil {
		return false, errors.New("nil origin")
	}

	if !d.IsOccupied() {
		return true
	}

	if d.IsOccupied() && o.GetPiece().GetColor() == d.GetPiece().GetColor() {
		js, err := json.Marshal(o.GetPiece())
		fmt.Println(err, string(js))
		jp, err := json.Marshal(d.GetPiece())
		fmt.Println(err, string(jp))
		return false, errors.New((fmt.Sprintln("Can't capture your own piece: ", string(js), string(jp))))
	}

	if d.IsOccupied() && o.GetPiece().GetColor() != d.GetPiece().GetColor() && d.GetPiece().PieceType() == KingPiece {
		js, err := json.Marshal(o.GetPiece())
		fmt.Println(err, string(js))
		jp, err := json.Marshal(d.GetPiece())
		fmt.Println(err, string(jp))
		return false, errors.New((fmt.Sprintln("Can't capture the king: ", string(js), string(jp))))
	}

	return true
}<commit_msg>basic concept of move<commit_after>package dev

import (
	"fmt"
	"encoding/json"
	"errors"
)

type Move struct {
	origin      *Square
	destination *Square
}

func NewMove(origin, destination *Square) (*Move, error) {
	var m Move
	m.origin = origin
	m.destination = destination
	return &m, nil

}

func (m *Move)Name() string {
	return fmt.Sprintln(m.origin.piece.GetName(), m.origin.Name(), m.destination.Name())
}

func (m *Move)Apply() error {
	if isValid, err := m.IsValid(); !isValid {
		return err
	}
	if err := m.destination.NewPiece(m.origin.piece); err != nil {
		return err
	}
	m.origin.piece = nil
	m.origin.isOccupied = false
	return nil
}

func (m *Move)IsValid() (bool, error) {

	d := m.destination
	o := m.origin

	if d == nil {
		return false, errors.New("nil destination")
	}

	if o == nil {
		return false, errors.New("nil origin")
	}

	if !d.IsOccupied() {
		return true, nil
	}

	if d.IsOccupied() && o.GetPiece().GetColor() == d.GetPiece().GetColor() {
		js, err := json.Marshal(o.GetPiece())
		fmt.Println(err, string(js))
		jp, err := json.Marshal(d.GetPiece())
		fmt.Println(err, string(jp))
		return false, errors.New((fmt.Sprintln("Can't capture your own piece: ", string(js), string(jp))))
	}

	if d.IsOccupied() && o.GetPiece().GetColor() != d.GetPiece().GetColor() && d.GetPiece().PieceType() == KingPiece {
		js, err := json.Marshal(o.GetPiece())
		fmt.Println(err, string(js))
		jp, err := json.Marshal(d.GetPiece())
		fmt.Println(err, string(jp))
		return false, errors.New((fmt.Sprintln("Can't capture the king: ", string(js), string(jp))))
	}

	return true, nil
}<|endoftext|>