<commit_before>package mysql

import (
	"database/sql"
	"fmt"
	"time"

	"github.com/jmoiron/sqlx"
	"github.com/solefaucet/sole-server/errors"
	"github.com/solefaucet/sole-server/models"
)

// GetRewardIncomes get user's reward incomes
func (s Storage) GetRewardIncomes(userID int64, limit, offset int64) ([]models.Income, error) {
	rawSQL := "SELECT * FROM incomes WHERE `user_id` = ? AND `type` = ? ORDER BY `id` DESC LIMIT ? OFFSET ?"
	args := []interface{}{userID, models.IncomeTypeReward, limit, offset}
	incomes := []models.Income{}
	err := s.selects(&incomes, rawSQL, args...)
	return incomes, err
}

// GetNumberOfRewardIncomes gets number of user's reward incomes
func (s Storage) GetNumberOfRewardIncomes(userID int64) (int64, error) {
	var count int64
	err := s.db.QueryRowx("SELECT COUNT(*) FROM incomes WHERE `user_id` = ? AND `type` = ?", userID, models.IncomeTypeReward).Scan(&count)
	return count, err
}

// CreateRewardIncome creates a new reward type income
func (s Storage) CreateRewardIncome(income models.Income, now time.Time) error {
	tx := s.db.MustBegin()

	if err := createRewardIncomeWithTx(tx, income, now); err != nil {
		tx.Rollback()
		return err
	}

	// commit
	if err := tx.Commit(); err != nil {
		return fmt.Errorf("create reward income commit transaction error: %v", err)
	}

	return nil
}

func createRewardIncomeWithTx(tx *sqlx.Tx, income models.Income, now time.Time) error {
	totalReward := income.Income

	// insert income into incomes table
	if _, err := addIncome(tx, income); err != nil {
		return err
	}

	// update user balance, total_income, referer_total_income
	if err := incrementUserBalance(tx, income.UserID, income.Income, income.RefererIncome); err != nil {
		return err
	}

	// update user rewarded_at
	if _, err := tx.Exec("UPDATE users SET `rewarded_at` = ? WHERE `id` = ?", now, income.UserID); err != nil {
		return err
	}

	// update referer balance
	if rowAffected, err := incrementRefererBalance(tx, income.RefererID, income.RefererIncome); err != nil {
		return err
	} else if rowAffected == 1 {
		totalReward += income.RefererIncome
	}

	// update total reward
	if err := incrementTotalReward(tx, totalReward, now); err != nil {
		return err
	}

	return nil
}

// insert reward income into incomes table
func addIncome(tx *sqlx.Tx, income models.Income) (sql.Result, error) {
	result, err := tx.NamedExec("INSERT INTO incomes (`user_id`, `referer_id`, `type`, `income`, `referer_income`) VALUES (:user_id, :referer_id, :type, :income, :referer_income)", income)
	if err != nil {
		return nil, fmt.Errorf("add income error: %v", err)
	}

	return result, nil
}

// increment user balance, total_income, referer_total_income
func incrementUserBalance(tx *sqlx.Tx, userID int64, delta, refererDelta float64) error {
	rawSQL := "UPDATE users SET `balance` = `balance` + ?, `total_income` = `total_income` + ?, `referer_total_income` = `referer_total_income` + ? WHERE id = ?"
	args := []interface{}{delta, delta, refererDelta, userID}
	if result, err := tx.Exec(rawSQL, args...); err != nil {
		return fmt.Errorf("increment user balance error: %v", err)
	} else if rowAffected, _ := result.RowsAffected(); rowAffected != 1 {
		return fmt.Errorf("increment user balance affected %v rows", rowAffected)
	}

	return nil
}

// increment referer balance
func incrementRefererBalance(tx *sqlx.Tx, refererID int64, delta float64) (int64, error) {
	result, err := tx.NamedExec("UPDATE users SET `balance` = `balance` + :delta, `total_income_from_referees` = `total_income_from_referees` + :delta WHERE id = :id", map[string]interface{}{
		"id":    refererID,
		"delta": delta,
	})
	if err != nil {
		return 0, fmt.Errorf("increment referer balance error: %v", err)
	}

	rowAffected, _ := result.RowsAffected()
	return rowAffected, nil
}

// increment total reward
func incrementTotalReward(tx *sqlx.Tx, totalReward float64, now time.Time) error {
	sql := "INSERT INTO total_rewards (`total`, `created_at`) VALUES (:delta, :created_at) ON DUPLICATE KEY UPDATE `total` = `total` + :delta"
	args := map[string]interface{}{
		"delta":      totalReward,
		"created_at": now,
	}

	if _, err := tx.NamedExec(sql, args); err != nil {
		return fmt.Errorf("increment total reward error: %v", err)
	}

	return nil
}

// GetOfferwowEventByID finds offerwow event by event id
func (s Storage) GetOfferwowEventByID(eventID string) (models.OfferwowEvent, error) {
	event := models.OfferwowEvent{}
	err := s.db.Get(&event, "SELECT * FROM `offerwow` WHERE `event_id` = ?", eventID)

	if err != nil {
		if err == sql.ErrNoRows {
			return event, errors.ErrNotFound
		}

		return event, fmt.Errorf("query offerwow event by id error: %v", err)
	}

	return event, nil
}

// CreateOfferwowIncome creates a new offerwow type income
func (s Storage) CreateOfferwowIncome(income models.Income, eventID string) error {
	tx := s.db.MustBegin()

	if err := createOfferwowIncomeWithTx(tx, income, eventID); err != nil {
		tx.Rollback()
		return err
	}

	// commit
	if err := tx.Commit(); err != nil {
		return fmt.Errorf("create offerwow income commit transaction error: %v", err)
	}

	return nil
}

func createOfferwowIncomeWithTx(tx *sqlx.Tx, income models.Income, eventID string) error {
	// insert offerwow income into incomes table
	result, err := addIncome(tx, income)
	if err != nil {
		return err
	}
	id, err := result.LastInsertId()
	if err != nil {
		return err
	}

	// update user balance, total_income, referer_total_income
	if err := incrementUserBalance(tx, income.UserID, income.Income, income.RefererIncome); err != nil {
		return err
	}

	// update referer balance
	if _, err := incrementRefererBalance(tx, income.RefererID, income.RefererIncome); err != nil {
		return err
	}

	// insert offerwow event
	offerwowEvent := models.OfferwowEvent{
		EventID:  eventID,
		IncomeID: id,
		Amount:   income.Income,
	}
	_, err = tx.NamedExec("INSERT INTO `offerwow` (`event_id`, `income_id`, `amount`) VALUE (:event_id, :income_id, :amount)", offerwowEvent)
	return err
}

// GetSuperrewardsOfferByID finds superrewards offer by transaction Id and user id
func (s Storage) GetSuperrewardsOfferByID(transactionID string, userID int64) (models.SuperrewardsOffer, error) {
	offer := models.SuperrewardsOffer{}
	err := s.db.Get(&offer, "SELECT * FROM `superrewards` WHERE `transaction_id` = ? AND `user_id` = ?", transactionID, userID)

	if err != nil {
		if err == sql.ErrNoRows {
			return offer, errors.ErrNotFound
		}

		return offer, fmt.Errorf("query superrewards offer by id error: %v", err)
	}

	return offer, nil
}

// CreateSuperrewardsIncome creates a new superrewards type income
func (s Storage) CreateSuperrewardsIncome(income models.Income, transactionID, offerID string) error {
	tx := s.db.MustBegin()

	if err := createSuperrewardsIncomeWithTx(tx, income, transactionID, offerID); err != nil {
		tx.Rollback()
		return err
	}

	// commit
	if err := tx.Commit(); err != nil {
		return fmt.Errorf("create reward income commit transaction error: %v", err)
	}

	return nil
}

func createSuperrewardsIncomeWithTx(tx *sqlx.Tx, income models.Income, transactionID, offerID string) error {
	// insert superrewards income into incomes table
	result, err := addIncome(tx, income)
	if err != nil {
		return err
	}
	id, err := result.LastInsertId()
	if err != nil {
		return err
	}

	// update user balance, total_income, referer_total_income
	if err := incrementUserBalance(tx, income.UserID, income.Income, income.RefererIncome); err != nil {
		return err
	}

	// update referer balance
	if _, err := incrementRefererBalance(tx, income.RefererID, income.RefererIncome); err != nil {
		return err
	}

	// insert superrewards offer
	offer := models.SuperrewardsOffer{
		IncomeID:      id,
		UserID:        income.UserID,
		TransactionID: transactionID,
		OfferID:       offerID,
		Amount:        income.Income,
	}
	_, err = tx.NamedExec("INSERT INTO `superrewards` (`income_id`, `user_id`, `transaction_id`, `offer_id`, `amount`) VALUE (:income_id, :user_id, :transaction_id, :offer_id, :amount)", offer)
	return err
}
<commit_msg>Fix typo<commit_after>package mysql

import (
	"database/sql"
	"fmt"
	"time"

	"github.com/jmoiron/sqlx"
	"github.com/solefaucet/sole-server/errors"
	"github.com/solefaucet/sole-server/models"
)

// GetRewardIncomes get user's reward incomes
func (s Storage) GetRewardIncomes(userID int64, limit, offset int64) ([]models.Income, error) {
	rawSQL := "SELECT * FROM incomes WHERE `user_id` = ? AND `type` = ? ORDER BY `id` DESC LIMIT ? OFFSET ?"
	args := []interface{}{userID, models.IncomeTypeReward, limit, offset}
	incomes := []models.Income{}
	err := s.selects(&incomes, rawSQL, args...)
	return incomes, err
}

// GetNumberOfRewardIncomes gets number of user's reward incomes
func (s Storage) GetNumberOfRewardIncomes(userID int64) (int64, error) {
	var count int64
	err := s.db.QueryRowx("SELECT COUNT(*) FROM incomes WHERE `user_id` = ? AND `type` = ?", userID, models.IncomeTypeReward).Scan(&count)
	return count, err
}

// CreateRewardIncome creates a new reward type income
func (s Storage) CreateRewardIncome(income models.Income, now time.Time) error {
	tx := s.db.MustBegin()

	if err := createRewardIncomeWithTx(tx, income, now); err != nil {
		tx.Rollback()
		return err
	}

	// commit
	if err := tx.Commit(); err != nil {
		return fmt.Errorf("create reward income commit transaction error: %v", err)
	}

	return nil
}

func createRewardIncomeWithTx(tx *sqlx.Tx, income models.Income, now time.Time) error {
	totalReward := income.Income

	// insert income into incomes table
	if _, err := addIncome(tx, income); err != nil {
		return err
	}

	// update user balance, total_income, referer_total_income
	if err := incrementUserBalance(tx, income.UserID, income.Income, income.RefererIncome); err != nil {
		return err
	}

	// update user rewarded_at
	if _, err := tx.Exec("UPDATE users SET `rewarded_at` = ? WHERE `id` = ?", now, income.UserID); err != nil {
		return err
	}

	// update referer balance
	if rowAffected, err := incrementRefererBalance(tx, income.RefererID, income.RefererIncome); err != nil {
		return err
	} else if rowAffected == 1 {
		totalReward += income.RefererIncome
	}

	// update total reward
	if err := incrementTotalReward(tx, totalReward, now); err != nil {
		return err
	}

	return nil
}

// insert reward income into incomes table
func addIncome(tx *sqlx.Tx, income models.Income) (sql.Result, error) {
	result, err := tx.NamedExec("INSERT INTO incomes (`user_id`, `referer_id`, `type`, `income`, `referer_income`) VALUES (:user_id, :referer_id, :type, :income, :referer_income)", income)
	if err != nil {
		return nil, fmt.Errorf("add income error: %v", err)
	}

	return result, nil
}

// increment user balance, total_income, referer_total_income
func incrementUserBalance(tx *sqlx.Tx, userID int64, delta, refererDelta float64) error {
	rawSQL := "UPDATE users SET `balance` = `balance` + ?, `total_income` = `total_income` + ?, `referer_total_income` = `referer_total_income` + ? WHERE id = ?"
	args := []interface{}{delta, delta, refererDelta, userID}
	if result, err := tx.Exec(rawSQL, args...); err != nil {
		return fmt.Errorf("increment user balance error: %v", err)
	} else if rowAffected, _ := result.RowsAffected(); rowAffected != 1 {
		return fmt.Errorf("increment user balance affected %v rows", rowAffected)
	}

	return nil
}

// increment referer balance
func incrementRefererBalance(tx *sqlx.Tx, refererID int64, delta float64) (int64, error) {
	result, err := tx.NamedExec("UPDATE users SET `balance` = `balance` + :delta, `total_income_from_referees` = `total_income_from_referees` + :delta WHERE id = :id", map[string]interface{}{
		"id":    refererID,
		"delta": delta,
	})
	if err != nil {
		return 0, fmt.Errorf("increment referer balance error: %v", err)
	}

	rowAffected, _ := result.RowsAffected()
	return rowAffected, nil
}

// increment total reward
func incrementTotalReward(tx *sqlx.Tx, totalReward float64, now time.Time) error {
	sql := "INSERT INTO total_rewards (`total`, `created_at`) VALUES (:delta, :created_at) ON DUPLICATE KEY UPDATE `total` = `total` + :delta"
	args := map[string]interface{}{
		"delta":      totalReward,
		"created_at": now,
	}

	if _, err := tx.NamedExec(sql, args); err != nil {
		return fmt.Errorf("increment total reward error: %v", err)
	}

	return nil
}

// GetOfferwowEventByID finds offerwow event by event id
func (s Storage) GetOfferwowEventByID(eventID string) (models.OfferwowEvent, error) {
	event := models.OfferwowEvent{}
	err := s.db.Get(&event, "SELECT * FROM `offerwow` WHERE `event_id` = ?", eventID)

	if err != nil {
		if err == sql.ErrNoRows {
			return event, errors.ErrNotFound
		}

		return event, fmt.Errorf("query offerwow event by id error: %v", err)
	}

	return event, nil
}

// CreateOfferwowIncome creates a new offerwow type income
func (s Storage) CreateOfferwowIncome(income models.Income, eventID string) error {
	tx := s.db.MustBegin()

	if err := createOfferwowIncomeWithTx(tx, income, eventID); err != nil {
		tx.Rollback()
		return err
	}

	// commit
	if err := tx.Commit(); err != nil {
		return fmt.Errorf("create offerwow income commit transaction error: %v", err)
	}

	return nil
}

func createOfferwowIncomeWithTx(tx *sqlx.Tx, income models.Income, eventID string) error {
	// insert offerwow income into incomes table
	result, err := addIncome(tx, income)
	if err != nil {
		return err
	}
	id, err := result.LastInsertId()
	if err != nil {
		return err
	}

	// update user balance, total_income, referer_total_income
	if err := incrementUserBalance(tx, income.UserID, income.Income, income.RefererIncome); err != nil {
		return err
	}

	// update referer balance
	if _, err := incrementRefererBalance(tx, income.RefererID, income.RefererIncome); err != nil {
		return err
	}

	// insert offerwow event
	offerwowEvent := models.OfferwowEvent{
		EventID:  eventID,
		IncomeID: id,
		Amount:   income.Income,
	}
	_, err = tx.NamedExec("INSERT INTO `offerwow` (`event_id`, `income_id`, `amount`) VALUE (:event_id, :income_id, :amount)", offerwowEvent)
	return err
}

// GetSuperrewardsOfferByID finds superrewards offer by transaction Id and user id
func (s Storage) GetSuperrewardsOfferByID(transactionID string, userID int64) (models.SuperrewardsOffer, error) {
	offer := models.SuperrewardsOffer{}
	err := s.db.Get(&offer, "SELECT * FROM `superrewards` WHERE `transaction_id` = ? AND `user_id` = ?", transactionID, userID)

	if err != nil {
		if err == sql.ErrNoRows {
			return offer, errors.ErrNotFound
		}

		return offer, fmt.Errorf("query superrewards offer by id error: %v", err)
	}

	return offer, nil
}

// CreateSuperrewardsIncome creates a new superrewards type income
func (s Storage) CreateSuperrewardsIncome(income models.Income, transactionID, offerID string) error {
	tx := s.db.MustBegin()

	if err := createSuperrewardsIncomeWithTx(tx, income, transactionID, offerID); err != nil {
		tx.Rollback()
		return err
	}

	// commit
	if err := tx.Commit(); err != nil {
		return fmt.Errorf("create superrewards income commit transaction error: %v", err)
	}

	return nil
}

func createSuperrewardsIncomeWithTx(tx *sqlx.Tx, income models.Income, transactionID, offerID string) error {
	// insert superrewards income into incomes table
	result, err := addIncome(tx, income)
	if err != nil {
		return err
	}
	id, err := result.LastInsertId()
	if err != nil {
		return err
	}

	// update user balance, total_income, referer_total_income
	if err := incrementUserBalance(tx, income.UserID, income.Income, income.RefererIncome); err != nil {
		return err
	}

	// update referer balance
	if _, err := incrementRefererBalance(tx, income.RefererID, income.RefererIncome); err != nil {
		return err
	}

	// insert superrewards offer
	offer := models.SuperrewardsOffer{
		IncomeID:      id,
		UserID:        income.UserID,
		TransactionID: transactionID,
		OfferID:       offerID,
		Amount:        income.Income,
	}
	_, err = tx.NamedExec("INSERT INTO `superrewards` (`income_id`, `user_id`, `transaction_id`, `offer_id`, `amount`) VALUE (:income_id, :user_id, :transaction_id, :offer_id, :amount)", offer)
	return err
}
<|endoftext|>


<commit_before>// Package tags manages the tags in a struct.
package tags

import (
	"bytes"
	"fmt"
	"reflect"

	"github.com/xgfone/go-tools/log2"
)

// Tag represents a tag of a field in a struct.
type Tag struct {
	// The field name which the tag belongs to.
	Field string

	// The name of the tag.
	Name string

	// The value of the tag which defined in Field.
	Value string
}

// Tags is a struct to manage the tags of a struct.
type Tags struct {
	debug  bool
	name   string
	caches []*Tag

	f2t map[string]map[string]string
	t2f map[string]map[string]string
}

// New returns a new Tag to manage the tags in a certain struct.
//
// v is a struct variable or a pointer to a struct.
//
// If passing the second argument and it's true, it will enable the debug mode,
// which will output the procedure building the tags.
func New(v interface{}, debug ...bool) *Tags {
	typ := reflect.TypeOf(v)
	if typ.Kind() == reflect.Ptr {
		typ = typ.Elem()
	}
	if typ.Kind() != reflect.Struct {
		return nil
	}

	sname := typ.Name()
	tags := newTag(sname)
	nf := typ.NumField()
	var tag *Tag
	for i := 0; i < nf; i++ {
		field := typ.Field(i)
		fname := field.Name

		tags.f2t[fname] = make(map[string]string)
		for k, v := range GetAllTags(field.Tag) {
			tags.debugf("Struct=%s, Field=%s, TagName=%s, TagValue=%s",
				sname, fname, k, v)

			tag = &Tag{Field: fname, Name: k, Value: v}
			tags.caches = append(tags.caches, tag)
			tags.f2t[fname][k] = v

			if tf, ok := tags.t2f[k]; ok {
				tf[fname] = v
			} else {
				tags.t2f[k] = map[string]string{
					fname: v,
				}
			}
		}
	}

	return tags
}

func newTag(name string) *Tags {
	return &Tags{
		name:   name,
		caches: make([]*Tag, 0),

		f2t: make(map[string]map[string]string),
		t2f: make(map[string]map[string]string),
	}
}

func (t Tags) debugf(format string, args ...interface{}) {
	if t.debug {
		log2.DebugF(format, args...)
	}
}

// Name returns the name of Tag, which is the name of the struct.
func (t Tags) Name() string {
	return t.name
}

// GetAllValuesByTag returns the values of the corresponding tag.
//
// Notice: There are more than one fields that has this tag.
func (t Tags) GetAllValuesByTag(tag string) []string {
	if fv := t.t2f[tag]; fv != nil {
		_len := len(fv)
		i := 0
		vs := make([]string, _len)
		for _, v := range fv {
			vs[i] = v
			i++
		}
		return vs
	}
	return nil
}

// GetAllFieldsAndValuesByTag is the same as GetValuesByTags(),
// but also return the field name as the key.
func (t Tags) GetAllFieldsAndValuesByTag(tag string) map[string]string {
	if v, ok := t.t2f[tag]; ok {
		return v
	}
	return nil
}

// GetValueByFieldAndTag returns the value of the tag in a specified field.
// Return an empty string if the field doesn't have the tag.
func (t Tags) GetValueByFieldAndTag(field, tag string) string {
	if tv, ok := t.f2t[field]; ok {
		for t, v := range tv {
			if tag == t {
				return v
			}
		}
	}

	return ""
}

// GetAllFieldsByTag returns the names of all the field where defined this tag.
// Return nil if no field defines the tag.
func (t Tags) GetAllFieldsByTag(tag string) []string {
	if fv, ok := t.t2f[tag]; ok {
		_len := len(fv)
		i := 0
		fs := make([]string, _len)
		for f := range fv {
			fs[i] = f
			i++
		}
		return fs
	}

	return nil
}

// GetAllTagsAndValuesByField returns all the tags of the field.
// Return nil if the field has no tags.
func (t Tags) GetAllTagsAndValuesByField(field string) map[string]string {
	if v, ok := t.f2t[field]; ok {
		return v
	}
	return nil
}

// GetAll returns all the information parsed by the tag manager.
// Return nil if no tag is parsed. It's almost used to debug or traverse the
// tags in all the fields.
//
// The returned list is sorted on the basis of the order of the field which is
// defined in the struct.
func (t Tags) GetAll() []*Tag {
	return t.caches
}

// Audit the result that the manager parses the tags upon the struct.
// It's almost used to debug. If having a question about the built result, you
// can use it and print the returned value to check.
//
// For the example above, the returned format is like:
// 	Name: TagTest
// 	FieldName=field1, TagName=tag1, TagValue=value1
// 	FieldName=field2, TagName=tag2, TagValue=value2
// 	FieldName=field3, TagName=tag3, TagValue=value3
// 	......
func (t Tags) Audit() string {
	buf := bytes.NewBufferString(fmt.Sprintf("Name: %v\n", t.name))

	for _, tag := range t.caches {
		buf.WriteString(fmt.Sprintf("FieldName=%s, TagName=%s, TagValue=%s\n",
			tag.Field, tag.Name, tag.Value))
	}

	return buf.String()
}

// TravelByTag travels the information of the tag.
//
// The type of the trvaeling function is func(string, string), which needs two
// arguments and no return value. The first argument is the name of the field
// where defined the tag, and the second is the value of the tag.
func (t Tags) TravelByTag(tag string, f func(string, string)) {
	if fs, ok := t.t2f[tag]; ok {
		for field, value := range fs {
			f(field, value)
		}
	}
}

// TravelByField travels the information of the field.
//
// The type of the trvaeling function is func(string, string), which needs two
// arguments and no return value. The first argument is the name of the tag,
// and the second is the value of the tag.
func (t Tags) TravelByField(field string, f func(string, string)) {
	if ts, ok := t.f2t[field]; ok {
		for tag, value := range ts {
			f(tag, value)
		}
	}
}
<commit_msg>Use Tag instead of *Tag<commit_after>// Package tags manages the tags in a struct.
package tags

import (
	"bytes"
	"fmt"
	"reflect"
)

// Tag represents a tag of a field in a struct.
type Tag struct {
	// The field name which the tag belongs to.
	Field string

	// The name of the tag.
	Name string

	// The value of the tag which defined in Field.
	Value string
}

// Tags is a struct to manage the tags of a struct.
type Tags struct {
	debug  bool
	name   string
	caches []Tag

	f2t map[string]map[string]string
	t2f map[string]map[string]string
}

// New returns a new Tag to manage the tags in a certain struct.
//
// v is a struct variable or a pointer to a struct.
//
// If passing the second argument and it's true, it will enable the debug mode,
// which will output the procedure building the tags.
func New(v interface{}, debug ...bool) *Tags {
	typ := reflect.TypeOf(v)
	if typ.Kind() == reflect.Ptr {
		typ = typ.Elem()
	}
	if typ.Kind() != reflect.Struct {
		return nil
	}

	sname := typ.Name()
	tags := newTag(sname)
	nf := typ.NumField()
	var tag Tag
	for i := 0; i < nf; i++ {
		field := typ.Field(i)
		fname := field.Name

		tags.f2t[fname] = make(map[string]string)
		for k, v := range GetAllTags(field.Tag) {
			tags.debugf("Struct=%s, Field=%s, TagName=%s, TagValue=%s",
				sname, fname, k, v)

			tag = Tag{Field: fname, Name: k, Value: v}
			tags.caches = append(tags.caches, tag)
			tags.f2t[fname][k] = v

			if tf, ok := tags.t2f[k]; ok {
				tf[fname] = v
			} else {
				tags.t2f[k] = map[string]string{
					fname: v,
				}
			}
		}
	}

	return tags
}

func newTag(name string) *Tags {
	return &Tags{
		name:   name,
		caches: make([]Tag, 0),

		f2t: make(map[string]map[string]string),
		t2f: make(map[string]map[string]string),
	}
}

func (t Tags) debugf(format string, args ...interface{}) {
	if t.debug {
		fmt.Printf(format, args...)
	}
}

// Name returns the name of Tag, which is the name of the struct.
func (t Tags) Name() string {
	return t.name
}

// GetAllValuesByTag returns the values of the corresponding tag.
//
// Notice: There are more than one fields that has this tag.
func (t Tags) GetAllValuesByTag(tag string) []string {
	if fv := t.t2f[tag]; fv != nil {
		_len := len(fv)
		i := 0
		vs := make([]string, _len)
		for _, v := range fv {
			vs[i] = v
			i++
		}
		return vs
	}
	return nil
}

// GetAllFieldsAndValuesByTag is the same as GetValuesByTags(),
// but also return the field name as the key.
func (t Tags) GetAllFieldsAndValuesByTag(tag string) map[string]string {
	if v, ok := t.t2f[tag]; ok {
		return v
	}
	return nil
}

// GetValueByFieldAndTag returns the value of the tag in a specified field.
// Return an empty string if the field doesn't have the tag.
func (t Tags) GetValueByFieldAndTag(field, tag string) string {
	if tv, ok := t.f2t[field]; ok {
		for t, v := range tv {
			if tag == t {
				return v
			}
		}
	}

	return ""
}

// GetAllFieldsByTag returns the names of all the field where defined this tag.
// Return nil if no field defines the tag.
func (t Tags) GetAllFieldsByTag(tag string) []string {
	if fv, ok := t.t2f[tag]; ok {
		_len := len(fv)
		i := 0
		fs := make([]string, _len)
		for f := range fv {
			fs[i] = f
			i++
		}
		return fs
	}

	return nil
}

// GetAllTagsAndValuesByField returns all the tags of the field.
// Return nil if the field has no tags.
func (t Tags) GetAllTagsAndValuesByField(field string) map[string]string {
	if v, ok := t.f2t[field]; ok {
		return v
	}
	return nil
}

// GetAll returns all the information parsed by the tag manager.
// Return nil if no tag is parsed. It's almost used to debug or traverse the
// tags in all the fields.
//
// The returned list is sorted on the basis of the order of the field which is
// defined in the struct.
func (t Tags) GetAll() []Tag {
	return t.caches
}

// Audit the result that the manager parses the tags upon the struct.
// It's almost used to debug. If having a question about the built result, you
// can use it and print the returned value to check.
//
// For the example above, the returned format is like:
// 	Name: TagTest
// 	FieldName=field1, TagName=tag1, TagValue=value1
// 	FieldName=field2, TagName=tag2, TagValue=value2
// 	FieldName=field3, TagName=tag3, TagValue=value3
// 	......
func (t Tags) Audit() string {
	buf := bytes.NewBufferString(fmt.Sprintf("Name: %v\n", t.name))

	for _, tag := range t.caches {
		buf.WriteString(fmt.Sprintf("FieldName=%s, TagName=%s, TagValue=%s\n",
			tag.Field, tag.Name, tag.Value))
	}

	return buf.String()
}

// TravelByTag travels the information of the tag.
//
// The type of the trvaeling function is func(string, string), which needs two
// arguments and no return value. The first argument is the name of the field
// where defined the tag, and the second is the value of the tag.
func (t Tags) TravelByTag(tag string, f func(string, string)) {
	if fs, ok := t.t2f[tag]; ok {
		for field, value := range fs {
			f(field, value)
		}
	}
}

// TravelByField travels the information of the field.
//
// The type of the trvaeling function is func(string, string), which needs two
// arguments and no return value. The first argument is the name of the tag,
// and the second is the value of the tag.
func (t Tags) TravelByField(field string, f func(string, string)) {
	if ts, ok := t.f2t[field]; ok {
		for tag, value := range ts {
			f(tag, value)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/bmizerany/pat"
	"github.com/globocom/config"
	"github.com/globocom/gandalf/api"
	"log"
	"net/http"
	"os/exec"
)

func startGitDaemon() error {
	bLocation, err := config.GetString("git:bare:location")
	if err != nil {
		return err
	}
	args := []string{"daemon", fmt.Sprintf("--base-path=%s", bLocation), "--syslog"}
	if exportAll, err := config.GetBool("git:daemon:export-all"); err == nil && exportAll {
		args = append(args, "--export-all")
	}
	return exec.Command("git", args...).Run()
}

func main() {
	dry := flag.Bool("dry", false, "dry-run: does not start the server and git daemon (for testing purpose)")
	configFile := flag.String("config", "/etc/gandalf.conf", "Gandalf configuration file")
	flag.Parse()

	err := config.ReadConfigFile(*configFile)
	if err != nil {
		msg := `Could not find gandalf config file. Searched on %s.
For an example conf check gandalf/etc/gandalf.conf file.`
		log.Panicf(msg, *configFile)
	}
	router := pat.New()
	router.Post("/user", http.HandlerFunc(api.NewUser))
	router.Del("/user/:name", http.HandlerFunc(api.RemoveUser))
	router.Post("/repository", http.HandlerFunc(api.NewRepository))
	router.Del("/repository/:name", http.HandlerFunc(api.RemoveRepository))

	port, err := config.GetString("webserver:port")
	if err != nil {
		panic(err)
	}
	if !*dry {
		startGitDaemon()
		log.Fatal(http.ListenAndServe(port, router))
	}
}
<commit_msg>webserver: routing handlers that had no route<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/bmizerany/pat"
	"github.com/globocom/config"
	"github.com/globocom/gandalf/api"
	"log"
	"net/http"
	"os/exec"
)

func startGitDaemon() error {
	bLocation, err := config.GetString("git:bare:location")
	if err != nil {
		return err
	}
	args := []string{"daemon", fmt.Sprintf("--base-path=%s", bLocation), "--syslog"}
	if exportAll, err := config.GetBool("git:daemon:export-all"); err == nil && exportAll {
		args = append(args, "--export-all")
	}
	return exec.Command("git", args...).Run()
}

func main() {
	dry := flag.Bool("dry", false, "dry-run: does not start the server and git daemon (for testing purpose)")
	configFile := flag.String("config", "/etc/gandalf.conf", "Gandalf configuration file")
	flag.Parse()

	err := config.ReadConfigFile(*configFile)
	if err != nil {
		msg := `Could not find gandalf config file. Searched on %s.
For an example conf check gandalf/etc/gandalf.conf file.`
		log.Panicf(msg, *configFile)
	}
	router := pat.New()
	router.Post("/user/:name/key", http.HandlerFunc(api.AddKey))
	router.Del("/user/:name/key/:keyname", http.HandlerFunc(api.RemoveKey))
	router.Post("/user", http.HandlerFunc(api.NewUser))
	router.Del("/user/:name", http.HandlerFunc(api.RemoveUser))
	router.Post("/repository", http.HandlerFunc(api.NewRepository))
	router.Get("/repository/:name/grant/:username", http.HandlerFunc(api.GrantAccess))
	router.Del("/repository/:name/revoke/:username", http.HandlerFunc(api.RevokeAccess))
	router.Del("/repository/:name", http.HandlerFunc(api.RemoveRepository))

	port, err := config.GetString("webserver:port")
	if err != nil {
		panic(err)
	}
	if !*dry {
		startGitDaemon()
		log.Fatal(http.ListenAndServe(port, router))
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/x509"
	"encoding/pem"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"sync"
	"syscall"

	"code.google.com/p/go.crypto/ssh"
	"github.com/flynn/go-shlex"
	"github.com/kr/pty"
)

var host = flag.String("h", "", "host ip to listen on")
var port = flag.String("p", "22", "port to listen on")
var debug = flag.Bool("d", false, "debug mode displays handler output")
var env = flag.Bool("e", false, "pass environment to handlers")
var shell = flag.Bool("s", false, "run exec handler via SHELL")
var keys = flag.String("k", "", "pem file of private keys (read from SSH_PRIVATE_KEYS by default)")

var ErrUnauthorized = errors.New("execd: user is unauthorized")

type exitStatusMsg struct {
	Status uint32
}

func exitStatus(err error) (exitStatusMsg, error) {
	if err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			// There is no platform independent way to retrieve
			// the exit code, but the following will work on Unix
			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				return exitStatusMsg{uint32(status.ExitStatus())}, nil
			}
		}
		return exitStatusMsg{0}, err
	}
	return exitStatusMsg{0}, nil
}

func attachCmd(cmd *exec.Cmd, stdout io.Writer, stderr io.Writer, stdin io.Reader) (*sync.WaitGroup, error) {
	var wg sync.WaitGroup
	wg.Add(2)

	if stdin != nil {
		stdinIn, err := cmd.StdinPipe()
		if err != nil {
			return nil, err
		}
		go func() {
			io.Copy(stdinIn, stdin)
			stdinIn.Close()
			// FIXME: Do we care that this is not part of the WaitGroup?
		}()
	}

	stdoutOut, err := cmd.StdoutPipe()
	if err != nil {
		return nil, err
	}
	go func() {
		io.Copy(stdout, stdoutOut)
		wg.Done()
	}()

	stderrOut, err := cmd.StderrPipe()
	if err != nil {
		return nil, err
	}
	go func() {
		io.Copy(stderr, stderrOut)
		wg.Done()
	}()

	return &wg, nil
}

func attachShell(cmd *exec.Cmd, stdout io.Writer, stdin io.Reader) (*os.File, *sync.WaitGroup, error) {
	var wg sync.WaitGroup
	wg.Add(2)

	// Note that pty merges stdout and stderr.
	cmdPty, err := pty.Start(cmd)
	if err != nil {
		return nil, nil, err
	}
	go func() {
		io.Copy(stdout, cmdPty)
		wg.Done()
	}()
	go func() {
		io.Copy(cmdPty, stdin)
		wg.Done()
	}()

	return cmdPty, &wg, nil
}

func addKey(conf *ssh.ServerConfig, block *pem.Block) (err error) {
	var key interface{}
	switch block.Type {
	case "RSA PRIVATE KEY":
		key, err = x509.ParsePKCS1PrivateKey(block.Bytes)
	case "EC PRIVATE KEY":
		key, err = x509.ParseECPrivateKey(block.Bytes)
	case "DSA PRIVATE KEY":
		key, err = ssh.ParseDSAPrivateKey(block.Bytes)
	default:
		return fmt.Errorf("unsupported key type %q", block.Type)
	}
	if err != nil {
		return err
	}
	signer, err := ssh.NewSignerFromKey(key)
	if err != nil {
		return err
	}
	conf.AddHostKey(signer)
	return nil
}

func parseKeys(conf *ssh.ServerConfig, pemData []byte) error {
	var found bool
	for {
		var block *pem.Block
		block, pemData = pem.Decode(pemData)
		if block == nil {
			if !found {
				return errors.New("no private keys found")
			}
			return nil
		}
		if err := addKey(conf, block); err != nil {
			return err
		}
		found = true
	}
}

func handleAuth(handler []string, conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
	keydata := string(bytes.TrimSpace(ssh.MarshalAuthorizedKey(key)))
	cmd := exec.Command(handler[0], append(handler[1:], conn.User(), keydata)...)
	var output bytes.Buffer
	done, err := attachCmd(cmd, &output, &output, nil)
	if err != nil {
		return nil, err
	}
	err = cmd.Run()
	done.Wait()
	status, err := exitStatus(err)
	if err != nil {
		return nil, err
	}
	if status.Status == 0 {
		return &ssh.Permissions{
			Extensions: map[string]string{
				"environ": strings.Trim(output.String(), "\n"),
				"user":    conn.User(),
			},
		}, nil
	} else {
		log.Println("auth-handler status:", status.Status)
	}
	return nil, ErrUnauthorized
}

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %v [options] <auth-handler> <exec-handler>\n\n", os.Args[0])
		flag.PrintDefaults()
	}
}

func main() {
	flag.Parse()
	if flag.NArg() < 2 {
		flag.Usage()
		os.Exit(64)
	}

	execHandler, err := shlex.Split(flag.Arg(1))
	if err != nil {
		log.Fatalln("Unable to parse receiver command:", err)
	}
	execHandler[0], err = filepath.Abs(execHandler[0])
	if err != nil {
		log.Fatalln("Invalid receiver path:", err)
	}

	authHandler, err := shlex.Split(flag.Arg(0))
	if err != nil {
		log.Fatalln("Unable to parse authchecker command:", err)
	}
	authHandler[0], err = filepath.Abs(authHandler[0])
	if err != nil {
		log.Fatalln("Invalid authchecker path:", err)
	}
	config := &ssh.ServerConfig{
		PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
			return handleAuth(authHandler, conn, key)
		},
	}

	if keyEnv := os.Getenv("SSH_PRIVATE_KEYS"); keyEnv != "" {
		if err := parseKeys(config, []byte(keyEnv)); err != nil {
			log.Fatalln("Failed to parse private keys:", err)
		}
	} else {
		pemBytes, err := ioutil.ReadFile(*keys)
		if err != nil {
			log.Fatalln("Failed to load private keys:", err)
		}
		if err := parseKeys(config, pemBytes); err != nil {
			log.Fatalln("Failed to parse private keys:", err)
		}
	}

	if p := os.Getenv("PORT"); p != "" && *port == "22" {
		*port = p
	}
	listener, err := net.Listen("tcp", *host+":"+*port)
	if err != nil {
		log.Fatalln("Failed to listen for connections:", err)
	}
	for {
		// SSH connections just house multiplexed connections
		conn, err := listener.Accept()
		if err != nil {
			log.Println("Failed to accept incoming connection:", err)
			continue
		}
		go handleConn(conn, config, execHandler)
	}
}

func handleConn(conn net.Conn, conf *ssh.ServerConfig, execHandler []string) {
	defer conn.Close()
	sshConn, chans, reqs, err := ssh.NewServerConn(conn, conf)
	if err != nil {
		log.Println("Failed to handshake:", err)
		return
	}

	go ssh.DiscardRequests(reqs)

	for ch := range chans {
		if ch.ChannelType() != "session" {
			ch.Reject(ssh.UnknownChannelType, "unknown channel type")
			continue
		}
		go handleChannel(sshConn, ch, execHandler)
	}
}

func handleChannel(conn *ssh.ServerConn, newChan ssh.NewChannel, execHandler []string) {
	ch, reqs, err := newChan.Accept()
	if err != nil {
		log.Println("newChan.Accept failed:", err)
		return
	}

	assert := func(at string, err error) bool {
		if err != nil {
			log.Printf("%s failed: %s", at, err)
			ch.Stderr().Write([]byte("Internal error.\n"))
			return true
		}
		return false
	}

	var stdout, stderr io.Writer
	if *debug {
		stdout = io.MultiWriter(ch, os.Stdout)
		stderr = io.MultiWriter(ch.Stderr(), os.Stdout)
	} else {
		stdout = ch
		stderr = ch.Stderr()
	}

	var ptyShell *os.File

	for req := range reqs {
		switch req.Type {
		case "exec":
			defer ch.Close()

			if req.WantReply {
				req.Reply(true, nil)
			}

			cmdline := string(req.Payload[4:])
			var cmd *exec.Cmd
			if *shell {
				shellcmd := flag.Arg(1) + " " + cmdline
				cmd = exec.Command(os.Getenv("SHELL"), "-c", shellcmd)
			} else {
				cmdargs, err := shlex.Split(cmdline)
				if assert("shlex.Split", err) {
					return
				}
				cmd = exec.Command(execHandler[0], append(execHandler[1:], cmdargs...)...)
			}
			if *env {
				cmd.Env = os.Environ()
			} else {
				cmd.Env = []string{}
			}
			if conn.Permissions != nil {
				// Using Permissions.Extensions as a way to get state from PublicKeyCallback
				if conn.Permissions.Extensions["environ"] != "" {
					cmd.Env = append(cmd.Env, strings.Split(conn.Permissions.Extensions["environ"], "\n")...)
				}
				cmd.Env = append(cmd.Env, "USER="+conn.Permissions.Extensions["user"])
			}
			cmd.Env = append(cmd.Env, "SSH_ORIGINAL_COMMAND="+cmdline)
			done, err := attachCmd(cmd, stdout, stderr, ch)
			if assert("attachCmd", err) {
				return
			}
			if assert("cmd.Start", cmd.Start()) {
				return
			}
			done.Wait()
			status, err := exitStatus(cmd.Wait())
			if assert("exitStatus", err) {
				return
			}
			_, err = ch.SendRequest("exit-status", false, ssh.Marshal(&status))
			assert("sendExit", err)
			return
		case "pty-req":
			width, height, okSize := parsePtyRequest(req.Payload)

			var cmd *exec.Cmd
			if *shell {
				cmd = exec.Command(os.Getenv("SHELL"))
			} else {
				cmd = exec.Command(execHandler[0], execHandler[1:]...)
			}
			if *env {
				cmd.Env = os.Environ()
			} else {
				cmd.Env = []string{}
			}
			if conn.Permissions != nil {
				// Using Permissions.Extensions as a way to get state from PublicKeyCallback
				if conn.Permissions.Extensions["environ"] != "" {
					cmd.Env = append(cmd.Env, strings.Split(conn.Permissions.Extensions["environ"], "\n")...)
				}
				cmd.Env = append(cmd.Env, "USER="+conn.Permissions.Extensions["user"])
			}
			ptyShell, _, err := attachShell(cmd, stdout, ch)
			if assert("attachShell", err) {
				ch.Close()
				return
			}
			if okSize {
				setWinsize(ptyShell.Fd(), width, height)
				req.Reply(true, nil)
			}

			go func() {
				status, err := exitStatus(cmd.Wait())
				if !assert("exitStatus", err) {
					_, err := ch.SendRequest("exit-status", false, ssh.Marshal(&status))
					assert("sendExit", err)
				}
				ch.Close()
			}()
		case "window-change":
			width, height, okSize := parsePtyRequest(req.Payload)
			if okSize {
				setWinsize(ptyShell.Fd(), width, height)
			}
		}

		if req.WantReply {
			req.Reply(true, nil)
		}
	}
}
<commit_msg>Replace attachCmd.<commit_after>package main

import (
	"bytes"
	"crypto/x509"
	"encoding/pem"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"sync"
	"syscall"

	"code.google.com/p/go.crypto/ssh"
	"github.com/flynn/go-shlex"
	"github.com/kr/pty"
)

var host = flag.String("h", "", "host ip to listen on")
var port = flag.String("p", "22", "port to listen on")
var debug = flag.Bool("d", false, "debug mode displays handler output")
var env = flag.Bool("e", false, "pass environment to handlers")
var shell = flag.Bool("s", false, "run exec handler via SHELL")
var keys = flag.String("k", "", "pem file of private keys (read from SSH_PRIVATE_KEYS by default)")

var ErrUnauthorized = errors.New("execd: user is unauthorized")

type exitStatusMsg struct {
	Status uint32
}

func exitStatus(err error) (exitStatusMsg, error) {
	if err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			// There is no platform independent way to retrieve
			// the exit code, but the following will work on Unix
			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				return exitStatusMsg{uint32(status.ExitStatus())}, nil
			}
		}
		return exitStatusMsg{0}, err
	}
	return exitStatusMsg{0}, nil
}

func attachShell(cmd *exec.Cmd, stdout io.Writer, stdin io.Reader) (*os.File, *sync.WaitGroup, error) {
	var wg sync.WaitGroup
	wg.Add(2)

	// Note that pty merges stdout and stderr.
	cmdPty, err := pty.Start(cmd)
	if err != nil {
		return nil, nil, err
	}
	go func() {
		io.Copy(stdout, cmdPty)
		wg.Done()
	}()
	go func() {
		io.Copy(cmdPty, stdin)
		wg.Done()
	}()

	return cmdPty, &wg, nil
}

func addKey(conf *ssh.ServerConfig, block *pem.Block) (err error) {
	var key interface{}
	switch block.Type {
	case "RSA PRIVATE KEY":
		key, err = x509.ParsePKCS1PrivateKey(block.Bytes)
	case "EC PRIVATE KEY":
		key, err = x509.ParseECPrivateKey(block.Bytes)
	case "DSA PRIVATE KEY":
		key, err = ssh.ParseDSAPrivateKey(block.Bytes)
	default:
		return fmt.Errorf("unsupported key type %q", block.Type)
	}
	if err != nil {
		return err
	}
	signer, err := ssh.NewSignerFromKey(key)
	if err != nil {
		return err
	}
	conf.AddHostKey(signer)
	return nil
}

func parseKeys(conf *ssh.ServerConfig, pemData []byte) error {
	var found bool
	for {
		var block *pem.Block
		block, pemData = pem.Decode(pemData)
		if block == nil {
			if !found {
				return errors.New("no private keys found")
			}
			return nil
		}
		if err := addKey(conf, block); err != nil {
			return err
		}
		found = true
	}
}

func handleAuth(handler []string, conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
	var output bytes.Buffer

	keydata := string(bytes.TrimSpace(ssh.MarshalAuthorizedKey(key)))
	cmd := exec.Command(handler[0], append(handler[1:], conn.User(), keydata)...)
	cmd.Stdout = &output
	cmd.Stderr = &output
	status, err := exitStatus(cmd.Run())
	if err != nil {
		return nil, err
	}
	if status.Status == 0 {
		return &ssh.Permissions{
			Extensions: map[string]string{
				"environ": strings.Trim(output.String(), "\n"),
				"user":    conn.User(),
			},
		}, nil
	} else {
		log.Println("auth-handler status:", status.Status)
	}
	return nil, ErrUnauthorized
}

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %v [options] <auth-handler> <exec-handler>\n\n", os.Args[0])
		flag.PrintDefaults()
	}
}

func main() {
	flag.Parse()
	if flag.NArg() < 2 {
		flag.Usage()
		os.Exit(64)
	}

	execHandler, err := shlex.Split(flag.Arg(1))
	if err != nil {
		log.Fatalln("Unable to parse receiver command:", err)
	}
	execHandler[0], err = filepath.Abs(execHandler[0])
	if err != nil {
		log.Fatalln("Invalid receiver path:", err)
	}

	authHandler, err := shlex.Split(flag.Arg(0))
	if err != nil {
		log.Fatalln("Unable to parse authchecker command:", err)
	}
	authHandler[0], err = filepath.Abs(authHandler[0])
	if err != nil {
		log.Fatalln("Invalid authchecker path:", err)
	}
	config := &ssh.ServerConfig{
		PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
			return handleAuth(authHandler, conn, key)
		},
	}

	if keyEnv := os.Getenv("SSH_PRIVATE_KEYS"); keyEnv != "" {
		if err := parseKeys(config, []byte(keyEnv)); err != nil {
			log.Fatalln("Failed to parse private keys:", err)
		}
	} else {
		pemBytes, err := ioutil.ReadFile(*keys)
		if err != nil {
			log.Fatalln("Failed to load private keys:", err)
		}
		if err := parseKeys(config, pemBytes); err != nil {
			log.Fatalln("Failed to parse private keys:", err)
		}
	}

	if p := os.Getenv("PORT"); p != "" && *port == "22" {
		*port = p
	}
	listener, err := net.Listen("tcp", *host+":"+*port)
	if err != nil {
		log.Fatalln("Failed to listen for connections:", err)
	}
	for {
		// SSH connections just house multiplexed connections
		conn, err := listener.Accept()
		if err != nil {
			log.Println("Failed to accept incoming connection:", err)
			continue
		}
		go handleConn(conn, config, execHandler)
	}
}

func handleConn(conn net.Conn, conf *ssh.ServerConfig, execHandler []string) {
	defer conn.Close()
	sshConn, chans, reqs, err := ssh.NewServerConn(conn, conf)
	if err != nil {
		log.Println("Failed to handshake:", err)
		return
	}

	go ssh.DiscardRequests(reqs)

	for ch := range chans {
		if ch.ChannelType() != "session" {
			ch.Reject(ssh.UnknownChannelType, "unknown channel type")
			continue
		}
		go handleChannel(sshConn, ch, execHandler)
	}
}

func handleChannel(conn *ssh.ServerConn, newChan ssh.NewChannel, execHandler []string) {
	ch, reqs, err := newChan.Accept()
	if err != nil {
		log.Println("newChan.Accept failed:", err)
		return
	}

	assert := func(at string, err error) bool {
		if err != nil {
			log.Printf("%s failed: %s", at, err)
			ch.Stderr().Write([]byte("Internal error.\n"))
			return true
		}
		return false
	}

	var stdout, stderr io.Writer
	if *debug {
		stdout = io.MultiWriter(ch, os.Stdout)
		stderr = io.MultiWriter(ch.Stderr(), os.Stdout)
	} else {
		stdout = ch
		stderr = ch.Stderr()
	}

	var ptyShell *os.File

	for req := range reqs {
		switch req.Type {
		case "exec":
			if req.WantReply {
				req.Reply(true, nil)
			}

			cmdline := string(req.Payload[4:])
			var cmd *exec.Cmd
			if *shell {
				shellcmd := flag.Arg(1) + " " + cmdline
				cmd = exec.Command(os.Getenv("SHELL"), "-c", shellcmd)
			} else {
				cmdargs, err := shlex.Split(cmdline)
				if assert("shlex.Split", err) {
					ch.Close()
					return
				}
				cmd = exec.Command(execHandler[0], append(execHandler[1:], cmdargs...)...)
			}
			if *env {
				cmd.Env = os.Environ()
			} else {
				cmd.Env = []string{}
			}
			if conn.Permissions != nil {
				// Using Permissions.Extensions as a way to get state from PublicKeyCallback
				if conn.Permissions.Extensions["environ"] != "" {
					cmd.Env = append(cmd.Env, strings.Split(conn.Permissions.Extensions["environ"], "\n")...)
				}
				cmd.Env = append(cmd.Env, "USER="+conn.Permissions.Extensions["user"])
			}
			cmd.Env = append(cmd.Env, "SSH_ORIGINAL_COMMAND="+cmdline)

			// cmd.Wait closes the stdin when it's done, so we need to proxy it through a pipe
			stdinPipe, err := cmd.StdinPipe()
			if assert("cmd.StdinPipe", err) {
				ch.Close()
				return
			}
			go io.Copy(stdinPipe, ch)

			cmd.Stdout = stdout
			cmd.Stderr = stderr

			go func() {
				status, err := exitStatus(cmd.Run())
				if !assert("exec run", err) {
					_, err := ch.SendRequest("exit-status", false, ssh.Marshal(&status))
					assert("exec exit", err)
				}
				ch.Close()
			}()
		case "pty-req":
			width, height, okSize := parsePtyRequest(req.Payload)

			var cmd *exec.Cmd
			if *shell {
				cmd = exec.Command(os.Getenv("SHELL"))
			} else {
				cmd = exec.Command(execHandler[0], execHandler[1:]...)
			}
			if *env {
				cmd.Env = os.Environ()
			} else {
				cmd.Env = []string{}
			}
			if conn.Permissions != nil {
				// Using Permissions.Extensions as a way to get state from PublicKeyCallback
				if conn.Permissions.Extensions["environ"] != "" {
					cmd.Env = append(cmd.Env, strings.Split(conn.Permissions.Extensions["environ"], "\n")...)
				}
				cmd.Env = append(cmd.Env, "USER="+conn.Permissions.Extensions["user"])
			}
			ptyShell, _, err := attachShell(cmd, stdout, ch)
			if assert("attachShell", err) {
				ch.Close()
				return
			}
			if okSize {
				setWinsize(ptyShell.Fd(), width, height)
				req.Reply(true, nil)
			}

			go func() {
				status, err := exitStatus(cmd.Wait())
				if !assert("pty run", err) {
					_, err := ch.SendRequest("exit-status", false, ssh.Marshal(&status))
					assert("pty exit", err)
				}
				ch.Close()
			}()
		case "window-change":
			width, height, okSize := parsePtyRequest(req.Payload)
			if okSize {
				setWinsize(ptyShell.Fd(), width, height)
			}
		}

		if req.WantReply {
			req.Reply(true, nil)
		}
	}
}
<|endoftext|>


<commit_before>package opts

import (
	"fmt"
	"net"
	"net/url"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/docker/docker/api"
	flag "github.com/docker/docker/pkg/mflag"
	"github.com/docker/docker/pkg/parsers"
)

var (
	alphaRegexp  = regexp.MustCompile(`[a-zA-Z]`)
	domainRegexp = regexp.MustCompile(`^(:?(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9]))(:?\.(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])))*)\.?\s*$`)
)

func ListVar(values *[]string, names []string, usage string) {
	flag.Var(newListOptsRef(values, nil), names, usage)
}

func HostListVar(values *[]string, names []string, usage string) {
	flag.Var(newListOptsRef(values, api.ValidateHost), names, usage)
}

func IPListVar(values *[]string, names []string, usage string) {
	flag.Var(newListOptsRef(values, ValidateIPAddress), names, usage)
}

func DnsSearchListVar(values *[]string, names []string, usage string) {
	flag.Var(newListOptsRef(values, ValidateDnsSearch), names, usage)
}

func IPVar(value *net.IP, names []string, defaultValue, usage string) {
	flag.Var(NewIpOpt(value, defaultValue), names, usage)
}

func MirrorListVar(values *[]string, names []string, usage string) {
	flag.Var(newListOptsRef(values, ValidateMirror), names, usage)
}

// ListOpts type
type ListOpts struct {
	values    *[]string
	validator ValidatorFctType
}

func NewListOpts(validator ValidatorFctType) ListOpts {
	var values []string
	return *newListOptsRef(&values, validator)
}

func newListOptsRef(values *[]string, validator ValidatorFctType) *ListOpts {
	return &ListOpts{
		values:    values,
		validator: validator,
	}
}

func (opts *ListOpts) String() string {
	return fmt.Sprintf("%v", []string((*opts.values)))
}

// Set validates if needed the input value and add it to the
// internal slice.
func (opts *ListOpts) Set(value string) error {
	if opts.validator != nil {
		v, err := opts.validator(value)
		if err != nil {
			return err
		}
		value = v
	}
	(*opts.values) = append((*opts.values), value)
	return nil
}

// Delete remove the given element from the slice.
func (opts *ListOpts) Delete(key string) {
	for i, k := range *opts.values {
		if k == key {
			(*opts.values) = append((*opts.values)[:i], (*opts.values)[i+1:]...)
			return
		}
	}
}

// GetMap returns the content of values in a map in order to avoid
// duplicates.
// FIXME: can we remove this?
func (opts *ListOpts) GetMap() map[string]struct{} {
	ret := make(map[string]struct{})
	for _, k := range *opts.values {
		ret[k] = struct{}{}
	}
	return ret
}

// GetAll returns the values' slice.
// FIXME: Can we remove this?
func (opts *ListOpts) GetAll() []string {
	return (*opts.values)
}

// Get checks the existence of the given key.
func (opts *ListOpts) Get(key string) bool {
	for _, k := range *opts.values {
		if k == key {
			return true
		}
	}
	return false
}

// Len returns the amount of element in the slice.
func (opts *ListOpts) Len() int {
	return len((*opts.values))
}

// Validators
type ValidatorFctType func(val string) (string, error)

func ValidateAttach(val string) (string, error) {
	s := strings.ToLower(val)
	for _, str := range []string{"stdin", "stdout", "stderr"} {
		if s == str {
			return s, nil
		}
	}
	return val, fmt.Errorf("valid streams are STDIN, STDOUT and STDERR.")
}

func ValidateLink(val string) (string, error) {
	if _, err := parsers.PartParser("name:alias", val); err != nil {
		return val, err
	}
	return val, nil
}

func ValidatePath(val string) (string, error) {
	var containerPath string

	if strings.Count(val, ":") > 2 {
		return val, fmt.Errorf("bad format for volumes: %s", val)
	}

	splited := strings.SplitN(val, ":", 2)
	if len(splited) == 1 {
		containerPath = splited[0]
		val = filepath.Clean(splited[0])
	} else {
		containerPath = splited[1]
		val = fmt.Sprintf("%s:%s", splited[0], filepath.Clean(splited[1]))
	}

	if !filepath.IsAbs(containerPath) {
		return val, fmt.Errorf("%s is not an absolute path", containerPath)
	}
	return val, nil
}

func ValidateEnv(val string) (string, error) {
	arr := strings.Split(val, "=")
	if len(arr) > 1 {
		return val, nil
	}
	return fmt.Sprintf("%s=%s", val, os.Getenv(val)), nil
}

func ValidateIPAddress(val string) (string, error) {
	var ip = net.ParseIP(strings.TrimSpace(val))
	if ip != nil {
		return ip.String(), nil
	}
	return "", fmt.Errorf("%s is not an ip address", val)
}

// Validates domain for resolvconf search configuration.
// A zero length domain is represented by .
func ValidateDnsSearch(val string) (string, error) {
	if val = strings.Trim(val, " "); val == "." {
		return val, nil
	}
	return validateDomain(val)
}

func validateDomain(val string) (string, error) {
	if alphaRegexp.FindString(val) == "" {
		return "", fmt.Errorf("%s is not a valid domain", val)
	}
	ns := domainRegexp.FindSubmatch([]byte(val))
	if len(ns) > 0 {
		return string(ns[1]), nil
	}
	return "", fmt.Errorf("%s is not a valid domain", val)
}

func ValidateExtraHost(val string) (string, error) {
	arr := strings.Split(val, ":")
	if len(arr) != 2 || len(arr[0]) == 0 {
		return "", fmt.Errorf("bad format for add-host: %s", val)
	}
	if _, err := ValidateIPAddress(arr[1]); err != nil {
		return "", fmt.Errorf("bad format for add-host: %s", val)
	}
	return val, nil
}

// Validates an HTTP(S) registry mirror
func ValidateMirror(val string) (string, error) {
	uri, err := url.Parse(val)
	if err != nil {
		return "", fmt.Errorf("%s is not a valid URI", val)
	}

	if uri.Scheme != "http" && uri.Scheme != "https" {
		return "", fmt.Errorf("Unsupported scheme %s", uri.Scheme)
	}

	if uri.Path != "" || uri.RawQuery != "" || uri.Fragment != "" {
		return "", fmt.Errorf("Unsupported path/query/fragment at end of the URI")
	}

	return fmt.Sprintf("%s://%s/v1/", uri.Scheme, uri.Host), nil
}
<commit_msg>Fix input volume path check on Windows<commit_after>package opts

import (
	"fmt"
	"net"
	"net/url"
	"os"
	"path"
	"regexp"
	"strings"

	"github.com/docker/docker/api"
	flag "github.com/docker/docker/pkg/mflag"
	"github.com/docker/docker/pkg/parsers"
)

var (
	alphaRegexp  = regexp.MustCompile(`[a-zA-Z]`)
	domainRegexp = regexp.MustCompile(`^(:?(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9]))(:?\.(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])))*)\.?\s*$`)
)

func ListVar(values *[]string, names []string, usage string) {
	flag.Var(newListOptsRef(values, nil), names, usage)
}

func HostListVar(values *[]string, names []string, usage string) {
	flag.Var(newListOptsRef(values, api.ValidateHost), names, usage)
}

func IPListVar(values *[]string, names []string, usage string) {
	flag.Var(newListOptsRef(values, ValidateIPAddress), names, usage)
}

func DnsSearchListVar(values *[]string, names []string, usage string) {
	flag.Var(newListOptsRef(values, ValidateDnsSearch), names, usage)
}

func IPVar(value *net.IP, names []string, defaultValue, usage string) {
	flag.Var(NewIpOpt(value, defaultValue), names, usage)
}

func MirrorListVar(values *[]string, names []string, usage string) {
	flag.Var(newListOptsRef(values, ValidateMirror), names, usage)
}

// ListOpts type
type ListOpts struct {
	values    *[]string
	validator ValidatorFctType
}

func NewListOpts(validator ValidatorFctType) ListOpts {
	var values []string
	return *newListOptsRef(&values, validator)
}

func newListOptsRef(values *[]string, validator ValidatorFctType) *ListOpts {
	return &ListOpts{
		values:    values,
		validator: validator,
	}
}

func (opts *ListOpts) String() string {
	return fmt.Sprintf("%v", []string((*opts.values)))
}

// Set validates if needed the input value and add it to the
// internal slice.
func (opts *ListOpts) Set(value string) error {
	if opts.validator != nil {
		v, err := opts.validator(value)
		if err != nil {
			return err
		}
		value = v
	}
	(*opts.values) = append((*opts.values), value)
	return nil
}

// Delete remove the given element from the slice.
func (opts *ListOpts) Delete(key string) {
	for i, k := range *opts.values {
		if k == key {
			(*opts.values) = append((*opts.values)[:i], (*opts.values)[i+1:]...)
			return
		}
	}
}

// GetMap returns the content of values in a map in order to avoid
// duplicates.
// FIXME: can we remove this?
func (opts *ListOpts) GetMap() map[string]struct{} {
	ret := make(map[string]struct{})
	for _, k := range *opts.values {
		ret[k] = struct{}{}
	}
	return ret
}

// GetAll returns the values' slice.
// FIXME: Can we remove this?
func (opts *ListOpts) GetAll() []string {
	return (*opts.values)
}

// Get checks the existence of the given key.
func (opts *ListOpts) Get(key string) bool {
	for _, k := range *opts.values {
		if k == key {
			return true
		}
	}
	return false
}

// Len returns the amount of element in the slice.
func (opts *ListOpts) Len() int {
	return len((*opts.values))
}

// Validators
type ValidatorFctType func(val string) (string, error)

func ValidateAttach(val string) (string, error) {
	s := strings.ToLower(val)
	for _, str := range []string{"stdin", "stdout", "stderr"} {
		if s == str {
			return s, nil
		}
	}
	return val, fmt.Errorf("valid streams are STDIN, STDOUT and STDERR.")
}

func ValidateLink(val string) (string, error) {
	if _, err := parsers.PartParser("name:alias", val); err != nil {
		return val, err
	}
	return val, nil
}

func ValidatePath(val string) (string, error) {
	var containerPath string

	if strings.Count(val, ":") > 2 {
		return val, fmt.Errorf("bad format for volumes: %s", val)
	}

	splited := strings.SplitN(val, ":", 2)
	if len(splited) == 1 {
		containerPath = splited[0]
		val = path.Clean(splited[0])
	} else {
		containerPath = splited[1]
		val = fmt.Sprintf("%s:%s", splited[0], path.Clean(splited[1]))
	}

	if !path.IsAbs(containerPath) {
		return val, fmt.Errorf("%s is not an absolute path", containerPath)
	}
	return val, nil
}

func ValidateEnv(val string) (string, error) {
	arr := strings.Split(val, "=")
	if len(arr) > 1 {
		return val, nil
	}
	return fmt.Sprintf("%s=%s", val, os.Getenv(val)), nil
}

func ValidateIPAddress(val string) (string, error) {
	var ip = net.ParseIP(strings.TrimSpace(val))
	if ip != nil {
		return ip.String(), nil
	}
	return "", fmt.Errorf("%s is not an ip address", val)
}

// Validates domain for resolvconf search configuration.
// A zero length domain is represented by .
func ValidateDnsSearch(val string) (string, error) {
	if val = strings.Trim(val, " "); val == "." {
		return val, nil
	}
	return validateDomain(val)
}

func validateDomain(val string) (string, error) {
	if alphaRegexp.FindString(val) == "" {
		return "", fmt.Errorf("%s is not a valid domain", val)
	}
	ns := domainRegexp.FindSubmatch([]byte(val))
	if len(ns) > 0 {
		return string(ns[1]), nil
	}
	return "", fmt.Errorf("%s is not a valid domain", val)
}

func ValidateExtraHost(val string) (string, error) {
	arr := strings.Split(val, ":")
	if len(arr) != 2 || len(arr[0]) == 0 {
		return "", fmt.Errorf("bad format for add-host: %s", val)
	}
	if _, err := ValidateIPAddress(arr[1]); err != nil {
		return "", fmt.Errorf("bad format for add-host: %s", val)
	}
	return val, nil
}

// Validates an HTTP(S) registry mirror
func ValidateMirror(val string) (string, error) {
	uri, err := url.Parse(val)
	if err != nil {
		return "", fmt.Errorf("%s is not a valid URI", val)
	}

	if uri.Scheme != "http" && uri.Scheme != "https" {
		return "", fmt.Errorf("Unsupported scheme %s", uri.Scheme)
	}

	if uri.Path != "" || uri.RawQuery != "" || uri.Fragment != "" {
		return "", fmt.Errorf("Unsupported path/query/fragment at end of the URI")
	}

	return fmt.Sprintf("%s://%s/v1/", uri.Scheme, uri.Host), nil
}
<|endoftext|>


<commit_before>// Copyright 2014 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with go-ethereum.  If not, see <http://www.gnu.org/licenses/>.

/*

This key store behaves as KeyStorePlain with the difference that
the private key is encrypted and on disk uses another JSON encoding.

The crypto is documented at https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition

*/

package crypto

import (
	"bytes"
	"crypto/aes"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"reflect"

	"code.google.com/p/go-uuid/uuid"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/crypto/randentropy"
	"golang.org/x/crypto/pbkdf2"
	"golang.org/x/crypto/scrypt"
)

const (
	keyHeaderKDF = "scrypt"
	// 2^18 / 8 / 1 uses 256MB memory and approx 1s CPU time on a modern CPU.
	scryptN     = 1 << 18
	scryptr     = 8
	scryptp     = 1
	scryptdkLen = 32
)

type keyStorePassphrase struct {
	keysDirPath string
}

func NewKeyStorePassphrase(path string) KeyStore {
	return &keyStorePassphrase{path}
}

func (ks keyStorePassphrase) GenerateNewKey(rand io.Reader, auth string) (key *Key, err error) {
	return GenerateNewKeyDefault(ks, rand, auth)
}

func (ks keyStorePassphrase) GetKey(keyAddr common.Address, auth string) (key *Key, err error) {
	keyBytes, keyId, err := decryptKeyFromFile(ks.keysDirPath, keyAddr, auth)
	if err == nil {
		key = &Key{
			Id:         uuid.UUID(keyId),
			Address:    keyAddr,
			PrivateKey: ToECDSA(keyBytes),
		}
	}
	return
}

func (ks keyStorePassphrase) Cleanup(keyAddr common.Address) (err error) {
	return cleanup(ks.keysDirPath, keyAddr)
}

func (ks keyStorePassphrase) GetKeyAddresses() (addresses []common.Address, err error) {
	return getKeyAddresses(ks.keysDirPath)
}

func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) {
	authArray := []byte(auth)
	salt := randentropy.GetEntropyCSPRNG(32)
	derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptr, scryptp, scryptdkLen)
	if err != nil {
		return err
	}

	encryptKey := derivedKey[:16]
	keyBytes := FromECDSA(key.PrivateKey)

	iv := randentropy.GetEntropyCSPRNG(aes.BlockSize) // 16
	cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv)
	if err != nil {
		return err
	}

	mac := Sha3(derivedKey[16:32], cipherText)

	scryptParamsJSON := make(map[string]interface{}, 5)
	scryptParamsJSON["n"] = scryptN
	scryptParamsJSON["r"] = scryptr
	scryptParamsJSON["p"] = scryptp
	scryptParamsJSON["dklen"] = scryptdkLen
	scryptParamsJSON["salt"] = hex.EncodeToString(salt)

	cipherParamsJSON := cipherparamsJSON{
		IV: hex.EncodeToString(iv),
	}

	cryptoStruct := cryptoJSON{
		Cipher:       "aes-128-ctr",
		CipherText:   hex.EncodeToString(cipherText),
		CipherParams: cipherParamsJSON,
		KDF:          "scrypt",
		KDFParams:    scryptParamsJSON,
		MAC:          hex.EncodeToString(mac),
	}
	encryptedKeyJSONV3 := encryptedKeyJSONV3{
		hex.EncodeToString(key.Address[:]),
		cryptoStruct,
		key.Id.String(),
		version,
	}
	keyJSON, err := json.Marshal(encryptedKeyJSONV3)
	if err != nil {
		return err
	}

	return writeKeyFile(key.Address, ks.keysDirPath, keyJSON)
}

func (ks keyStorePassphrase) DeleteKey(keyAddr common.Address, auth string) (err error) {
	// only delete if correct passphrase is given
	_, _, err = decryptKeyFromFile(ks.keysDirPath, keyAddr, auth)
	if err != nil {
		return err
	}

	return deleteKey(ks.keysDirPath, keyAddr)
}

func decryptKeyFromFile(keysDirPath string, keyAddr common.Address, auth string) (keyBytes []byte, keyId []byte, err error) {
	fmt.Printf("%v\n", keyAddr.Hex())
	m := make(map[string]interface{})
	err = getKey(keysDirPath, keyAddr, &m)
	if err != nil {
		return
	}

	v := reflect.ValueOf(m["version"])
	if v.Kind() == reflect.String && v.String() == "1" {
		k := new(encryptedKeyJSONV1)
		err = getKey(keysDirPath, keyAddr, &k)
		if err != nil {
			return
		}
		return decryptKeyV1(k, auth)
	} else {
		k := new(encryptedKeyJSONV3)
		err = getKey(keysDirPath, keyAddr, &k)
		if err != nil {
			return
		}
		return decryptKeyV3(k, auth)
	}
}

func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byte, keyId []byte, err error) {
	if keyProtected.Version != version {
		return nil, nil, fmt.Errorf("Version not supported: %v", keyProtected.Version)
	}

	if keyProtected.Crypto.Cipher != "aes-128-ctr" {
		return nil, nil, fmt.Errorf("Cipher not supported: %v", keyProtected.Crypto.Cipher)
	}

	keyId = uuid.Parse(keyProtected.Id)
	mac, err := hex.DecodeString(keyProtected.Crypto.MAC)
	if err != nil {
		return nil, nil, err
	}

	iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV)
	if err != nil {
		return nil, nil, err
	}

	cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText)
	if err != nil {
		return nil, nil, err
	}

	derivedKey, err := getKDFKey(keyProtected.Crypto, auth)
	if err != nil {
		return nil, nil, err
	}

	calculatedMAC := Sha3(derivedKey[16:32], cipherText)
	if !bytes.Equal(calculatedMAC, mac) {
		return nil, nil, errors.New("Decryption failed: MAC mismatch")
	}

	plainText, err := aesCTRXOR(derivedKey[:16], cipherText, iv)
	if err != nil {
		return nil, nil, err
	}
	return plainText, keyId, err
}

func decryptKeyV1(keyProtected *encryptedKeyJSONV1, auth string) (keyBytes []byte, keyId []byte, err error) {
	keyId = uuid.Parse(keyProtected.Id)
	mac, err := hex.DecodeString(keyProtected.Crypto.MAC)
	if err != nil {
		return nil, nil, err
	}

	iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV)
	if err != nil {
		return nil, nil, err
	}

	cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText)
	if err != nil {
		return nil, nil, err
	}

	derivedKey, err := getKDFKey(keyProtected.Crypto, auth)
	if err != nil {
		return nil, nil, err
	}

	calculatedMAC := Sha3(derivedKey[16:32], cipherText)
	if !bytes.Equal(calculatedMAC, mac) {
		return nil, nil, errors.New("Decryption failed: MAC mismatch")
	}

	plainText, err := aesCBCDecrypt(Sha3(derivedKey[:16])[:16], cipherText, iv)
	if err != nil {
		return nil, nil, err
	}
	return plainText, keyId, err
}

func getKDFKey(cryptoJSON cryptoJSON, auth string) ([]byte, error) {
	authArray := []byte(auth)
	salt, err := hex.DecodeString(cryptoJSON.KDFParams["salt"].(string))
	if err != nil {
		return nil, err
	}
	dkLen := ensureInt(cryptoJSON.KDFParams["dklen"])

	if cryptoJSON.KDF == "scrypt" {
		n := ensureInt(cryptoJSON.KDFParams["n"])
		r := ensureInt(cryptoJSON.KDFParams["r"])
		p := ensureInt(cryptoJSON.KDFParams["p"])
		return scrypt.Key(authArray, salt, n, r, p, dkLen)

	} else if cryptoJSON.KDF == "pbkdf2" {
		c := ensureInt(cryptoJSON.KDFParams["c"])
		prf := cryptoJSON.KDFParams["prf"].(string)
		if prf != "hmac-sha256" {
			return nil, fmt.Errorf("Unsupported PBKDF2 PRF: ", prf)
		}
		key := pbkdf2.Key(authArray, salt, c, dkLen, sha256.New)
		return key, nil
	}

	return nil, fmt.Errorf("Unsupported KDF: ", cryptoJSON.KDF)
}

// TODO: can we do without this when unmarshalling dynamic JSON?
// why do integers in KDF params end up as float64 and not int after
// unmarshal?
func ensureInt(x interface{}) int {
	res, ok := x.(int)
	if !ok {
		res = int(x.(float64))
	}
	return res
}
<commit_msg>crypto: remove debug print call after decrypting a key from disk<commit_after>// Copyright 2014 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with go-ethereum.  If not, see <http://www.gnu.org/licenses/>.

/*

This key store behaves as KeyStorePlain with the difference that
the private key is encrypted and on disk uses another JSON encoding.

The crypto is documented at https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition

*/

package crypto

import (
	"bytes"
	"crypto/aes"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"reflect"

	"code.google.com/p/go-uuid/uuid"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/crypto/randentropy"
	"golang.org/x/crypto/pbkdf2"
	"golang.org/x/crypto/scrypt"
)

const (
	keyHeaderKDF = "scrypt"
	// 2^18 / 8 / 1 uses 256MB memory and approx 1s CPU time on a modern CPU.
	scryptN     = 1 << 18
	scryptr     = 8
	scryptp     = 1
	scryptdkLen = 32
)

type keyStorePassphrase struct {
	keysDirPath string
}

func NewKeyStorePassphrase(path string) KeyStore {
	return &keyStorePassphrase{path}
}

func (ks keyStorePassphrase) GenerateNewKey(rand io.Reader, auth string) (key *Key, err error) {
	return GenerateNewKeyDefault(ks, rand, auth)
}

func (ks keyStorePassphrase) GetKey(keyAddr common.Address, auth string) (key *Key, err error) {
	keyBytes, keyId, err := decryptKeyFromFile(ks.keysDirPath, keyAddr, auth)
	if err == nil {
		key = &Key{
			Id:         uuid.UUID(keyId),
			Address:    keyAddr,
			PrivateKey: ToECDSA(keyBytes),
		}
	}
	return
}

func (ks keyStorePassphrase) Cleanup(keyAddr common.Address) (err error) {
	return cleanup(ks.keysDirPath, keyAddr)
}

func (ks keyStorePassphrase) GetKeyAddresses() (addresses []common.Address, err error) {
	return getKeyAddresses(ks.keysDirPath)
}

func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) {
	authArray := []byte(auth)
	salt := randentropy.GetEntropyCSPRNG(32)
	derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptr, scryptp, scryptdkLen)
	if err != nil {
		return err
	}

	encryptKey := derivedKey[:16]
	keyBytes := FromECDSA(key.PrivateKey)

	iv := randentropy.GetEntropyCSPRNG(aes.BlockSize) // 16
	cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv)
	if err != nil {
		return err
	}

	mac := Sha3(derivedKey[16:32], cipherText)

	scryptParamsJSON := make(map[string]interface{}, 5)
	scryptParamsJSON["n"] = scryptN
	scryptParamsJSON["r"] = scryptr
	scryptParamsJSON["p"] = scryptp
	scryptParamsJSON["dklen"] = scryptdkLen
	scryptParamsJSON["salt"] = hex.EncodeToString(salt)

	cipherParamsJSON := cipherparamsJSON{
		IV: hex.EncodeToString(iv),
	}

	cryptoStruct := cryptoJSON{
		Cipher:       "aes-128-ctr",
		CipherText:   hex.EncodeToString(cipherText),
		CipherParams: cipherParamsJSON,
		KDF:          "scrypt",
		KDFParams:    scryptParamsJSON,
		MAC:          hex.EncodeToString(mac),
	}
	encryptedKeyJSONV3 := encryptedKeyJSONV3{
		hex.EncodeToString(key.Address[:]),
		cryptoStruct,
		key.Id.String(),
		version,
	}
	keyJSON, err := json.Marshal(encryptedKeyJSONV3)
	if err != nil {
		return err
	}

	return writeKeyFile(key.Address, ks.keysDirPath, keyJSON)
}

func (ks keyStorePassphrase) DeleteKey(keyAddr common.Address, auth string) (err error) {
	// only delete if correct passphrase is given
	_, _, err = decryptKeyFromFile(ks.keysDirPath, keyAddr, auth)
	if err != nil {
		return err
	}

	return deleteKey(ks.keysDirPath, keyAddr)
}

func decryptKeyFromFile(keysDirPath string, keyAddr common.Address, auth string) (keyBytes []byte, keyId []byte, err error) {
	m := make(map[string]interface{})
	err = getKey(keysDirPath, keyAddr, &m)
	if err != nil {
		return
	}

	v := reflect.ValueOf(m["version"])
	if v.Kind() == reflect.String && v.String() == "1" {
		k := new(encryptedKeyJSONV1)
		err = getKey(keysDirPath, keyAddr, &k)
		if err != nil {
			return
		}
		return decryptKeyV1(k, auth)
	} else {
		k := new(encryptedKeyJSONV3)
		err = getKey(keysDirPath, keyAddr, &k)
		if err != nil {
			return
		}
		return decryptKeyV3(k, auth)
	}
}

func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byte, keyId []byte, err error) {
	if keyProtected.Version != version {
		return nil, nil, fmt.Errorf("Version not supported: %v", keyProtected.Version)
	}

	if keyProtected.Crypto.Cipher != "aes-128-ctr" {
		return nil, nil, fmt.Errorf("Cipher not supported: %v", keyProtected.Crypto.Cipher)
	}

	keyId = uuid.Parse(keyProtected.Id)
	mac, err := hex.DecodeString(keyProtected.Crypto.MAC)
	if err != nil {
		return nil, nil, err
	}

	iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV)
	if err != nil {
		return nil, nil, err
	}

	cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText)
	if err != nil {
		return nil, nil, err
	}

	derivedKey, err := getKDFKey(keyProtected.Crypto, auth)
	if err != nil {
		return nil, nil, err
	}

	calculatedMAC := Sha3(derivedKey[16:32], cipherText)
	if !bytes.Equal(calculatedMAC, mac) {
		return nil, nil, errors.New("Decryption failed: MAC mismatch")
	}

	plainText, err := aesCTRXOR(derivedKey[:16], cipherText, iv)
	if err != nil {
		return nil, nil, err
	}
	return plainText, keyId, err
}

func decryptKeyV1(keyProtected *encryptedKeyJSONV1, auth string) (keyBytes []byte, keyId []byte, err error) {
	keyId = uuid.Parse(keyProtected.Id)
	mac, err := hex.DecodeString(keyProtected.Crypto.MAC)
	if err != nil {
		return nil, nil, err
	}

	iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV)
	if err != nil {
		return nil, nil, err
	}

	cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText)
	if err != nil {
		return nil, nil, err
	}

	derivedKey, err := getKDFKey(keyProtected.Crypto, auth)
	if err != nil {
		return nil, nil, err
	}

	calculatedMAC := Sha3(derivedKey[16:32], cipherText)
	if !bytes.Equal(calculatedMAC, mac) {
		return nil, nil, errors.New("Decryption failed: MAC mismatch")
	}

	plainText, err := aesCBCDecrypt(Sha3(derivedKey[:16])[:16], cipherText, iv)
	if err != nil {
		return nil, nil, err
	}
	return plainText, keyId, err
}

func getKDFKey(cryptoJSON cryptoJSON, auth string) ([]byte, error) {
	authArray := []byte(auth)
	salt, err := hex.DecodeString(cryptoJSON.KDFParams["salt"].(string))
	if err != nil {
		return nil, err
	}
	dkLen := ensureInt(cryptoJSON.KDFParams["dklen"])

	if cryptoJSON.KDF == "scrypt" {
		n := ensureInt(cryptoJSON.KDFParams["n"])
		r := ensureInt(cryptoJSON.KDFParams["r"])
		p := ensureInt(cryptoJSON.KDFParams["p"])
		return scrypt.Key(authArray, salt, n, r, p, dkLen)

	} else if cryptoJSON.KDF == "pbkdf2" {
		c := ensureInt(cryptoJSON.KDFParams["c"])
		prf := cryptoJSON.KDFParams["prf"].(string)
		if prf != "hmac-sha256" {
			return nil, fmt.Errorf("Unsupported PBKDF2 PRF: ", prf)
		}
		key := pbkdf2.Key(authArray, salt, c, dkLen, sha256.New)
		return key, nil
	}

	return nil, fmt.Errorf("Unsupported KDF: ", cryptoJSON.KDF)
}

// TODO: can we do without this when unmarshalling dynamic JSON?
// why do integers in KDF params end up as float64 and not int after
// unmarshal?
func ensureInt(x interface{}) int {
	res, ok := x.(int)
	if !ok {
		res = int(x.(float64))
	}
	return res
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
	"sync"

	"github.com/AndrewVos/colour"
	"gopkg.in/yaml.v1"
)

type Config struct {
	ExcludeLines  []*regexp.Regexp
	ExcludeFiles  []*regexp.Regexp
	MinLineLength int
	MinHunkSize   int
}

func LoadConfig() Config {
	config := Config{
		ExcludeLines:  []*regexp.Regexp{},
		ExcludeFiles:  []*regexp.Regexp{},
		MinLineLength: 10,
		MinHunkSize:   2,
	}

	data, err := ioutil.ReadFile(".cccv.yml")
	if err != nil {
		return config
	}

	t := struct {
		ExcludeFiles  []string "exclude-files"
		ExcludeLines  []string "exclude-lines"
		MinLineLength int      "min-line-length"
		MinHunkSize   int      "min-hunk-size"
	}{}
	err = yaml.Unmarshal(data, &t)
	if err != nil {
		log.Fatalf("error: %v", err)
		os.Exit(1)
	}

	for _, s := range t.ExcludeLines {
		r := regexp.MustCompile(s)
		config.ExcludeLines = append(config.ExcludeLines, r)
	}
	for _, s := range t.ExcludeFiles {
		r := regexp.MustCompile(s)
		config.ExcludeFiles = append(config.ExcludeFiles, r)
	}
	if t.MinLineLength != 0 {
		config.MinLineLength = t.MinLineLength
	}
	return config
}

type FileName string

type Change struct {
	FileName
	Line
}

type Line struct {
	Number int
	Text   string
}

type FileResult struct {
	FileName
	Lines []*Line
}

func (fr *FileResult) HasDuplicates() bool {
	return len(fr.Lines) > 0
}

func main() {
	var wg sync.WaitGroup
	config := LoadConfig()

	resultChan := make(chan FileResult)
	results := []FileResult{}

	changes := getChanges(os.Stdin, config)
	gitFiles := gitLsFiles(config)

	go func() {
		for {
			r := <-resultChan
			results = append(results, r)
		}
	}()

	for _, fName := range gitFiles {
		wg.Add(1)
		go func(fName string, resultChan chan FileResult) {
			defer wg.Done()
			r := GenResultForFile(fName, changes, config)
			if r.HasDuplicates() {
				resultChan <- r
			}
		}(fName, resultChan)
	}
	wg.Wait()

	if len(results) > 0 {
		fmt.Printf(colour.White("Possible copy/paste sources:\n"))
		for _, r := range results {
			fmt.Printf(colour.Red("%s:\n"), r.FileName)
			for _, l := range r.Lines {
				fmt.Printf(colour.Yellow("%d: ")+"%s\n", l.Number, l.Text)
			}
		}
		os.Exit(1)
	} else {
		fmt.Printf(colour.Green("Good diff - no copy/pasted code.\n"))
	}
}

func GenResultForFile(fName string, changes *[]*Change, config Config) FileResult {
	file, _ := os.Open(fName)
	scanner := bufio.NewScanner(file)
	currentLineNumber := 0
	result := FileResult{FileName: FileName(fName), Lines: []*Line{}}

LOOP_LINES:
	for scanner.Scan() {
		line := scanner.Text()
		currentLineNumber++

		for _, excludeLinesR := range config.ExcludeLines {
			if excludeLinesR.MatchString(line) {
				continue LOOP_LINES
			}
		}

		for _, change := range *changes {
			if strings.TrimFunc(change.Text, TrimF) == strings.TrimFunc(line, TrimF) {

				// exclude lines from the diff itself
				if string(change.FileName) == fName && change.Line.Number == currentLineNumber {
					continue
				}

				resultAlreadyRecorded := false
				for _, resultLine := range result.Lines {
					if resultLine.Number == currentLineNumber && resultLine.Text == line {
						resultAlreadyRecorded = true
					}
				}

				if !resultAlreadyRecorded {
					result.Lines = append(result.Lines, &Line{Number: currentLineNumber, Text: line})
				}
			}
		}
	}

	result.Lines = filteredByHunkSizeLines(result.Lines, config)
	return result
}

func filteredByHunkSizeLines(lines []*Line, config Config) []*Line {
	var currentHunk []*Line
	hunks := [][]*Line{}

	for i, l := range lines {
		if i == 0 {
			currentHunk = []*Line{l}

			if len(lines) == 1 {
				hunks = append(hunks, currentHunk)
			}
			continue
		}

		if l.Number-1 == lines[i-1].Number {
			currentHunk = append(currentHunk, l)

		} else {
			hunks = append(hunks, currentHunk)
			currentHunk = []*Line{l}
		}

		if i == len(lines)-1 {
			hunks = append(hunks, currentHunk)
		}
	}

	filteredLines := []*Line{}
	for _, h := range hunks {
		if len(h) >= config.MinHunkSize {
			filteredLines = append(filteredLines, h...)
		}
	}
	return filteredLines
}

func gitLsFiles(config Config) []string {
	files := []string{}
	cmd := exec.Command("git", "ls-files")
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		log.Fatal(err)
		os.Exit(1)
	}
	if err := cmd.Start(); err != nil {
		log.Fatal(err)
		os.Exit(1)
	}

	scanner := bufio.NewScanner(stdout)

LOOP_FILES:
	for scanner.Scan() {
		for _, excludeFilesR := range config.ExcludeFiles {
			if excludeFilesR.MatchString(scanner.Text()) {
				continue LOOP_FILES
			}
		}
		files = append(files, scanner.Text())
	}

	return files
}

func getChanges(reader io.Reader, config Config) *[]*Change {
	scanner := bufio.NewScanner(reader)
	var currentFile string
	var currentLineNumber int
	changes := &[]*Change{}

	currentFileR := regexp.MustCompile(`^\+\+\+ ./(.*)$`)
	lineAddedR := regexp.MustCompile(`^\+{1}(.*\w+.*)`)
	lineRemovedR := regexp.MustCompile(`^\-{1}`)
	lineRangeR := regexp.MustCompile(`^@@.*?\+(\d+?),`)

	for scanner.Scan() {
		currentLine := scanner.Text()

		if res := currentFileR.FindStringSubmatch(currentLine); res != nil {
			currentFile = res[1]

		} else if res := lineRangeR.FindStringSubmatch(currentLine); res != nil {
			r, err := strconv.Atoi(res[1])
			if err != nil {
				log.Fatal(err)
				os.Exit(1)
			}
			currentLineNumber = r

		} else if lineAddedR.MatchString(currentLine) {
			res := lineAddedR.FindStringSubmatch(currentLine)

			if len(strings.TrimFunc(res[1], TrimF)) <= config.MinLineLength {
				currentLineNumber++
				continue
			}

			newChange := &Change{
				FileName: FileName(currentFile),
				Line:     Line{Text: res[1], Number: currentLineNumber},
			}
			*changes = append(*changes, newChange)
			currentLineNumber++

		} else if !lineRemovedR.MatchString(currentLine) {
			currentLineNumber++
		}
	}

	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "reading standard input:", err)
		os.Exit(1)
	}

	return changes
}

func TrimF(c rune) bool { return c == 32 || c == 9 }
<commit_msg>reading files in goroutines does not work<commit_after>package main

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"

	"github.com/AndrewVos/colour"
	"gopkg.in/yaml.v1"
)

type Config struct {
	ExcludeLines  []*regexp.Regexp
	ExcludeFiles  []*regexp.Regexp
	MinLineLength int
	MinHunkSize   int
}

func LoadConfig() Config {
	config := Config{
		ExcludeLines:  []*regexp.Regexp{},
		ExcludeFiles:  []*regexp.Regexp{},
		MinLineLength: 10,
		MinHunkSize:   2,
	}

	data, err := ioutil.ReadFile(".cccv.yml")
	if err != nil {
		return config
	}

	t := struct {
		ExcludeFiles  []string "exclude-files"
		ExcludeLines  []string "exclude-lines"
		MinLineLength int      "min-line-length"
		MinHunkSize   int      "min-hunk-size"
	}{}
	err = yaml.Unmarshal(data, &t)
	if err != nil {
		log.Fatalf("error: %v", err)
		os.Exit(1)
	}

	for _, s := range t.ExcludeLines {
		r := regexp.MustCompile(s)
		config.ExcludeLines = append(config.ExcludeLines, r)
	}
	for _, s := range t.ExcludeFiles {
		r := regexp.MustCompile(s)
		config.ExcludeFiles = append(config.ExcludeFiles, r)
	}
	if t.MinLineLength != 0 {
		config.MinLineLength = t.MinLineLength
	}
	return config
}

type FileName string

type Change struct {
	FileName
	Line
}

type Line struct {
	Number int
	Text   string
}

type FileResult struct {
	FileName
	Lines []*Line
}

func (fr *FileResult) HasDuplicates() bool {
	return len(fr.Lines) > 0
}

func main() {
	config := LoadConfig()

	results := []FileResult{}

	changes := getChanges(os.Stdin, config)
	gitFiles := gitLsFiles(config)

	for _, fName := range gitFiles {
		r := GenResultForFile(fName, changes, config)
		if r.HasDuplicates() {
			results = append(results, r)
		}
	}

	if len(results) > 0 {
		fmt.Printf(colour.White("Possible copy/paste sources:\n"))
		for _, r := range results {
			fmt.Printf(colour.Red("%s:\n"), r.FileName)
			for _, l := range r.Lines {
				fmt.Printf(colour.Yellow("%d: ")+"%s\n", l.Number, l.Text)
			}
		}
		os.Exit(1)
	} else {
		fmt.Printf(colour.Green("Good diff - no copy/pasted code.\n"))
	}
}

func GenResultForFile(fName string, changes *[]*Change, config Config) FileResult {
	file, _ := os.Open(fName)
	scanner := bufio.NewScanner(file)
	currentLineNumber := 0
	result := FileResult{FileName: FileName(fName), Lines: []*Line{}}

LOOP_LINES:
	for scanner.Scan() {
		line := scanner.Text()
		currentLineNumber++

		for _, excludeLinesR := range config.ExcludeLines {
			if excludeLinesR.MatchString(line) {
				continue LOOP_LINES
			}
		}

		for _, change := range *changes {
			if strings.TrimFunc(change.Text, TrimF) == strings.TrimFunc(line, TrimF) {

				// exclude lines from the diff itself
				if string(change.FileName) == fName && change.Line.Number == currentLineNumber {
					continue
				}

				resultAlreadyRecorded := false
				for _, resultLine := range result.Lines {
					if resultLine.Number == currentLineNumber && resultLine.Text == line {
						resultAlreadyRecorded = true
					}
				}

				if !resultAlreadyRecorded {
					result.Lines = append(result.Lines, &Line{Number: currentLineNumber, Text: line})
				}
			}
		}
	}

	result.Lines = filteredByHunkSizeLines(result.Lines, config)
	return result
}

func filteredByHunkSizeLines(lines []*Line, config Config) []*Line {
	var currentHunk []*Line
	hunks := [][]*Line{}

	for i, l := range lines {
		if i == 0 {
			currentHunk = []*Line{l}

			if len(lines) == 1 {
				hunks = append(hunks, currentHunk)
			}
			continue
		}

		if l.Number-1 == lines[i-1].Number {
			currentHunk = append(currentHunk, l)

		} else {
			hunks = append(hunks, currentHunk)
			currentHunk = []*Line{l}
		}

		if i == len(lines)-1 {
			hunks = append(hunks, currentHunk)
		}
	}

	filteredLines := []*Line{}
	for _, h := range hunks {
		if len(h) >= config.MinHunkSize {
			filteredLines = append(filteredLines, h...)
		}
	}
	return filteredLines
}

func gitLsFiles(config Config) []string {
	files := []string{}
	cmd := exec.Command("git", "ls-files")
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		log.Fatal(err)
		os.Exit(1)
	}
	if err := cmd.Start(); err != nil {
		log.Fatal(err)
		os.Exit(1)
	}

	scanner := bufio.NewScanner(stdout)

LOOP_FILES:
	for scanner.Scan() {
		for _, excludeFilesR := range config.ExcludeFiles {
			if excludeFilesR.MatchString(scanner.Text()) {
				continue LOOP_FILES
			}
		}
		files = append(files, scanner.Text())
	}

	return files
}

func getChanges(reader io.Reader, config Config) *[]*Change {
	scanner := bufio.NewScanner(reader)
	var currentFile string
	var currentLineNumber int
	changes := &[]*Change{}

	currentFileR := regexp.MustCompile(`^\+\+\+ ./(.*)$`)
	lineAddedR := regexp.MustCompile(`^\+{1}(.*\w+.*)`)
	lineRemovedR := regexp.MustCompile(`^\-{1}`)
	lineRangeR := regexp.MustCompile(`^@@.*?\+(\d+?),`)

	for scanner.Scan() {
		currentLine := scanner.Text()

		if res := currentFileR.FindStringSubmatch(currentLine); res != nil {
			currentFile = res[1]

		} else if res := lineRangeR.FindStringSubmatch(currentLine); res != nil {
			r, err := strconv.Atoi(res[1])
			if err != nil {
				log.Fatal(err)
				os.Exit(1)
			}
			currentLineNumber = r

		} else if lineAddedR.MatchString(currentLine) {
			res := lineAddedR.FindStringSubmatch(currentLine)

			if len(strings.TrimFunc(res[1], TrimF)) <= config.MinLineLength {
				currentLineNumber++
				continue
			}

			newChange := &Change{
				FileName: FileName(currentFile),
				Line:     Line{Text: res[1], Number: currentLineNumber},
			}
			*changes = append(*changes, newChange)
			currentLineNumber++

		} else if !lineRemovedR.MatchString(currentLine) {
			currentLineNumber++
		}
	}

	if err := scanner.Err(); err != nil {
		fmt.Fprintln(os.Stderr, "reading standard input:", err)
		os.Exit(1)
	}

	return changes
}

func TrimF(c rune) bool { return c == 32 || c == 9 }
<|endoftext|>


<commit_before>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 ogletest

// Equals returns a matcher that matches any value v such that v == x, with the
// exception that if x is a numeric type, Equals(x) will match equivalent
// numeric values of any type.
func Equals(x interface{}) Matcher {
}
<commit_msg>Added a stub implementation.<commit_after>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 ogletest

// Equals returns a matcher that matches any value v such that v == x, with the
// exception that if x is a numeric type, Equals(x) will match equivalent
// numeric values of any type.
func Equals(x interface{}) Matcher {
	return &equalsMatcher{x}
}

type equalsMatcher struct {
	expected interface{}
}

func (m *equalsMatcher) Matches(val interface{}) (result MatchResult, err string) {
	return MATCH_UNDEFINED, "TODO"
}

func (m *equalsMatcher) Description() string {
	return "TODO"
}
<|endoftext|>


<commit_before>// +build !appengine,!gopherjs,!windows

package logrus

func (f *TextFormatter) initTerminal(entry *Entry) {
}
<commit_msg>Extended conditions to include non-native builds<commit_after>// +build appengine gopherjs !windows

package logrus

func (f *TextFormatter) initTerminal(entry *Entry) {
}
<|endoftext|>


<commit_before>package main

import (
	"os"

	"github.com/fatih/color"
)

func acceptCommand(flags acceptFlags, testname string) {
	if flags.all {
		acceptAll()
		return
	}

	var path string
	if flags.asm {
		filename := testname + asmExt
		path = buildPath(asmDir, filename)
	} else {
		filename := testname + pikaExt
		path = buildPath(pikaDir, filename)
	}

	if !exists(path) {
		color.Magenta(path + " does not exist")
		os.Exit(1)
		return // not necessary, just to be explicit
	}

	if flags.asm {
		acceptOptimizedStandalone(testname)
	} else {
		acceptCodeGen(testname)
		acceptOptimized(testname)
		acceptCompile(testname)
	}
}

func acceptAll() {
	os.RemoveAll(backupDir)
	os.Rename(expectDir, backupDir)
	os.Rename(resultDir, expectDir)
	initResultDirs()
}

func acceptCompile(testname string) {
	new := buildPath(result.build.compiler, testname+txtExt)
	old := buildPath(expect.build.compiler, testname+txtExt)
	moveIfExists(old, new)

	new = buildPath(result.asm.compiler, testname+asmExt)
	old = buildPath(expect.asm.compiler, testname+asmExt)
	moveIfExists(old, new)

	new = buildPath(result.run.compiler, testname+txtExt)
	old = buildPath(expect.run.compiler, testname+txtExt)
	moveIfExists(old, new)
}

func acceptCodeGen(testname string) {
	new := buildPath(result.build.codegenerator, testname+txtExt)
	old := buildPath(expect.build.codegenerator, testname+txtExt)
	moveIfExists(old, new)

	new = buildPath(result.asm.codegenerator, testname+asmExt)
	old = buildPath(expect.asm.codegenerator, testname+asmExt)
	moveIfExists(old, new)

	new = buildPath(result.run.codegenerator, testname+txtExt)
	old = buildPath(expect.run.codegenerator, testname+txtExt)
	moveIfExists(old, new)
}

func acceptOptimized(testname string) {
	new := buildPath(result.build.optimizer, testname+txtExt)
	old := buildPath(expect.build.optimizer, testname+txtExt)
	moveIfExists(old, new)

	new = buildPath(result.asm.optimizer, testname+asmoExt)
	old = buildPath(expect.asm.optimizer, testname+asmoExt)
	moveIfExists(old, new)

	new = buildPath(result.run.optimizer, testname+txtExt)
	old = buildPath(expect.run.optimizer, testname+txtExt)
	moveIfExists(old, new)
}

func acceptOptimizedStandalone(testname string) {
	new := buildPath(result.build.optimizerStandalone, testname+txtExt)
	old := buildPath(expect.build.optimizerStandalone, testname+txtExt)
	moveIfExists(old, new)

	new = buildPath(result.asm.optimizerStandalone, testname+asmoExt)
	old = buildPath(expect.asm.optimizerStandalone, testname+asmoExt)
	moveIfExists(old, new)

	new = buildPath(result.run.optimizerStandalone, testname+txtExt)
	old = buildPath(expect.run.optimizerStandalone, testname+txtExt)
	moveIfExists(old, new)
}
<commit_msg>fix bug in accepting single tests, and change accept -all for my workflow<commit_after>package main

import (
	"os"
	"os/exec"

	"github.com/fatih/color"
)

func acceptCommand(flags acceptFlags, testname string) {
	if flags.all {
		acceptAll()
		return
	}

	var path string
	if flags.asm {
		filename := testname + asmExt
		path = buildPath(asmDir, filename)
	} else {
		filename := testname + pikaExt
		path = buildPath(pikaDir, filename)
	}

	if !exists(path) {
		color.Magenta(path + " does not exist")
		os.Exit(1)
		return // not necessary, just to be explicit
	}

	if flags.asm {
		acceptOptimizedStandalone(testname)
	} else {
		acceptCodeGen(testname)
		acceptOptimized(testname)
		acceptCompile(testname)
	}
}

func acceptAll() {
	os.RemoveAll(backupDir)
	// os.Rename(expectDir, backupDir)
	// os.Rename(resultDir, expectDir)
	// initResultDirs()
	backup()
	acceptAllPika()
	acceptAllStandalone()
}

func acceptAllPika() {
	files := getAllFiles(pikaDir)
	files = filterOutFiles(files, ".gitignore")

	for _, file := range files {
		testname := replaceExtension(file.Name(), "")
		acceptCodeGen(testname)
		acceptOptimized(testname)
		acceptCompile(testname)
	}
}

func acceptAllStandalone() {
	files := getAllFiles(asmDir)
	files = filterOutFiles(files, ".gitignore")

	for _, file := range files {
		testname := replaceExtension(file.Name(), "")
		acceptOptimizedStandalone(testname)
	}
}

func backup() {
	exec.Command("cp", "-rf", expectDir, backupDir).Run()
}

func acceptTest(testname, oldPath, newPath, ext string) {
	old := buildPath(oldPath, testname+ext)
	new := buildPath(newPath, testname+ext)
	moveIfExists(old, new)
}

func acceptCompile(testname string) {
	acceptTest(testname, result.build.compiler, expect.build.compiler, txtExt)
	acceptTest(testname, result.run.compiler, expect.run.compiler, txtExt)
	acceptTest(testname, result.asm.compiler, expect.asm.compiler, asmExt)

	acceptTest(testname, result.buildo.compiler, expect.buildo.compiler, txtExt)
	acceptTest(testname, result.asmo.compiler, expect.asmo.compiler, asmoExt)
}

func acceptCodeGen(testname string) {
	acceptTest(testname, result.build.codegenerator, expect.build.codegenerator, txtExt)
	acceptTest(testname, result.run.codegenerator, expect.run.codegenerator, txtExt)
	acceptTest(testname, result.asm.codegenerator, expect.asm.codegenerator, asmExt)
}

func acceptOptimized(testname string) {
	acceptTest(testname, result.build.optimizer, expect.build.optimizer, txtExt)
	acceptTest(testname, result.run.optimizer, expect.run.optimizer, txtExt)
	acceptTest(testname, result.asm.optimizer, expect.asm.optimizer, asmoExt)

	acceptTest(testname, result.buildo.optimizer, expect.buildo.optimizer, txtExt)
	acceptTest(testname, result.asmo.optimizer, expect.asmo.optimizer, asmoExt)
}

func acceptOptimizedStandalone(testname string) {
	acceptTest(testname, result.build.optimizerStandalone, expect.build.optimizerStandalone, txtExt)
	acceptTest(testname, result.run.optimizerStandalone, expect.run.optimizerStandalone, txtExt)
	acceptTest(testname, result.asm.optimizerStandalone, expect.asm.optimizerStandalone, asmoExt)

	acceptTest(testname, result.buildo.optimizerStandalone, expect.buildo.optimizerStandalone, txtExt)
	acceptTest(testname, result.asmo.optimizerStandalone, expect.asmo.optimizerStandalone, asmoExt)
}
<|endoftext|>