<commit_before>// Copyright 2017 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package integration

import (
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"math/rand"
	"os"
	"time"

	"google.golang.org/api/container/v1"
	"google.golang.org/api/option"

	"golang.org/x/net/context"
)

const gceClusterStatusRunning = "RUNNING"

var clusterName = fmt.Sprintf("integration-test-%d", randInt())
var zone = os.Getenv("GCE_ZONE")
var projectID = os.Getenv("GCE_PROJECT_ID")
var serviceAccount = os.Getenv("GCE_SERVICE_ACCOUNT")

type gceClusterManager struct {
	client  *gceClient
	cluster *container.Cluster
}

func randInt() int {
	rand.Seed(time.Now().UnixNano())
	return rand.Int()
}

func createTempFile(data []byte, prefix string) (string, error) {
	tmpfile, err := ioutil.TempFile("", prefix)
	if err != nil {
		return "", err
	}
	if _, err := tmpfile.Write(data); err != nil {
		return "", err
	}
	if err := tmpfile.Close(); err != nil {
		return "", err
	}
	return tmpfile.Name(), nil
}

func (g *gceClusterManager) Name() string {
	return "gce"
}

func (g *gceClusterManager) Provisioner() string {
	return "kubernetes"
}

func (g *gceClusterManager) IP(env *Environment) string {
	g.fetchClusterData()
	if g.cluster != nil {
		return g.cluster.Endpoint
	}
	return ""
}

func (g *gceClusterManager) Start(env *Environment) *Result {
	ctx := context.Background()
	serviceAccountFile, err := createTempFile([]byte(serviceAccount), "gce-sa-")
	if err != nil {
		return nil
	}
	client, err := newClient(ctx, projectID, option.WithServiceAccountFile(serviceAccountFile))
	if err != nil {
		return nil
	}
	g.client = client
	g.client.createCluster(clusterName, zone, 1)
	return &Result{ExitCode: 0}
}

func (g *gceClusterManager) Delete(env *Environment) *Result {
	g.client.deleteCluster(g.cluster.Name, zone)
	return &Result{ExitCode: 0}
}

func (g *gceClusterManager) fetchClusterData() {
	if g.cluster != nil && g.cluster.Status == gceClusterStatusRunning {
		return
	}
	retries := 20
	sleepTime := 20 * time.Second
	for i := 0; i < retries; i++ {
		cluster, err := g.client.describeCluster(clusterName, zone)
		if err == nil && cluster.Status == gceClusterStatusRunning {
			g.cluster = cluster
			return
		}
		time.Sleep(sleepTime)
	}
}

func (g *gceClusterManager) credentials(env *Environment) (map[string]string, error) {
	g.fetchClusterData()
	if g.cluster == nil {
		return nil, fmt.Errorf("cluster unavailable")
	}
	credentials := make(map[string]string)
	credentials["username"] = g.cluster.MasterAuth.Username
	credentials["password"] = g.cluster.MasterAuth.Password
	contents, err := base64.StdEncoding.DecodeString(g.cluster.MasterAuth.ClusterCaCertificate)
	if err != nil {
		return credentials, err
	}
	filename, err := createTempFile(contents, "gce-ca-")
	if err != nil {
		return credentials, err
	}
	credentials["certificateFilename"] = filename
	return credentials, nil
}

func (g *gceClusterManager) UpdateParams(env *Environment) []string {
	address := fmt.Sprintf("https://%s", g.IP(env))
	credentials, err := g.credentials(env)
	if err != nil {
		return []string{}
	}
	return []string{
		"--addr", address,
		"--custom", "username=" + credentials["username"],
		"--custom", "password=" + credentials["password"],
		"--cacert", credentials["certificateFilename"],
	}
}
<commit_msg>integration: improve gce cluster verbosity<commit_after>// Copyright 2017 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package integration

import (
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"math/rand"
	"os"
	"time"

	"google.golang.org/api/container/v1"
	"google.golang.org/api/option"

	"golang.org/x/net/context"
)

const gceClusterStatusRunning = "RUNNING"

var clusterName = fmt.Sprintf("integration-test-%d", randInt())
var zone = os.Getenv("GCE_ZONE")
var projectID = os.Getenv("GCE_PROJECT_ID")
var serviceAccount = os.Getenv("GCE_SERVICE_ACCOUNT")

type gceClusterManager struct {
	client  *gceClient
	cluster *container.Cluster
}

func randInt() int {
	rand.Seed(time.Now().UnixNano())
	return rand.Int()
}

func createTempFile(data []byte, prefix string) (string, error) {
	tmpfile, err := ioutil.TempFile("", prefix)
	if err != nil {
		return "", err
	}
	if _, err := tmpfile.Write(data); err != nil {
		return "", err
	}
	if err := tmpfile.Close(); err != nil {
		return "", err
	}
	return tmpfile.Name(), nil
}

func (g *gceClusterManager) Name() string {
	return "gce"
}

func (g *gceClusterManager) Provisioner() string {
	return "kubernetes"
}

func (g *gceClusterManager) IP(env *Environment) string {
	g.fetchClusterData(env)
	if g.cluster != nil {
		return g.cluster.Endpoint
	}
	return ""
}

func (g *gceClusterManager) Start(env *Environment) *Result {
	ctx := context.Background()
	serviceAccountFile, err := createTempFile([]byte(serviceAccount), "gce-sa-")
	if err != nil {
		return nil
	}
	client, err := newClient(ctx, projectID, option.WithServiceAccountFile(serviceAccountFile))
	if err != nil {
		return nil
	}
	g.client = client
	if env.VerboseLevel() > 0 {
		fmt.Fprintf(safeStdout, "[gce] starting cluster %s in zone %s\n", clusterName, zone)
	}
	g.client.createCluster(clusterName, zone, 1)
	return &Result{ExitCode: 0}
}

func (g *gceClusterManager) Delete(env *Environment) *Result {
	if env.VerboseLevel() > 0 {
		fmt.Fprintf(safeStdout, "[gce] deleting cluster %s in zone %s\n", clusterName, zone)
	}
	g.client.deleteCluster(g.cluster.Name, zone)
	return &Result{ExitCode: 0}
}

func (g *gceClusterManager) fetchClusterData(env *Environment) {
	if g.cluster != nil && g.cluster.Status == gceClusterStatusRunning {
		return
	}
	retries := 20
	sleepTime := 20 * time.Second
	for i := 0; i < retries; i++ {
		cluster, err := g.client.describeCluster(clusterName, zone)
		if err == nil && cluster.Status == gceClusterStatusRunning {
			g.cluster = cluster
			if env.VerboseLevel() > 0 {
				fmt.Fprintf(safeStdout, "[gce] cluster %s is running. Endpoint: %s\n", clusterName, cluster.Endpoint)
			}
			return
		}
		if env.VerboseLevel() > 0 {
			if err == nil {
				fmt.Fprintf(safeStdout, "[gce] cluster %s status: %s\n", clusterName, cluster.Status)
			} else {
				fmt.Fprintf(safeStdout, "[gce] error fetching cluster %s: %s\n", clusterName, err)
			}
		}
		time.Sleep(sleepTime)
	}
}

func (g *gceClusterManager) credentials(env *Environment) (map[string]string, error) {
	g.fetchClusterData(env)
	if g.cluster == nil {
		return nil, fmt.Errorf("cluster unavailable")
	}
	credentials := make(map[string]string)
	credentials["username"] = g.cluster.MasterAuth.Username
	credentials["password"] = g.cluster.MasterAuth.Password
	contents, err := base64.StdEncoding.DecodeString(g.cluster.MasterAuth.ClusterCaCertificate)
	if err != nil {
		return credentials, err
	}
	filename, err := createTempFile(contents, "gce-ca-")
	if err != nil {
		return credentials, err
	}
	credentials["certificateFilename"] = filename
	return credentials, nil
}

func (g *gceClusterManager) UpdateParams(env *Environment) []string {
	address := fmt.Sprintf("https://%s", g.IP(env))
	credentials, err := g.credentials(env)
	if err != nil {
		return []string{}
	}
	return []string{
		"--addr", address,
		"--custom", "username=" + credentials["username"],
		"--custom", "password=" + credentials["password"],
		"--cacert", credentials["certificateFilename"],
	}
}
<|endoftext|>


<commit_before>package resque

import (
	"fmt"
	"strings"
	"time"

	"github.com/fiorix/go-redis/redis"
	"github.com/jazibjohar/go-resque"
	"github.com/jazibjohar/go-resque/driver"
)

func init() {
	resque.Register("redis-go", &drv{})
}

type drv struct {
	client *redis.Client
	driver.Enqueuer
	schedule  map[string]struct{}
	nameSpace string
}

func (d *drv) SetClient(name string, client interface{}) {
	d.client = client.(*redis.Client)
	d.schedule = make(map[string]struct{})
	d.nameSpace = name
}

func (d *drv) ListPush(queue string, jobJSON string) (int64, error) {
	listLength, err := d.client.RPush(d.nameSpace+"queue:"+queue, jobJSON)
	if err != nil {
		return -1, err
	}

	return int64(listLength), err
}
func (d *drv) ListPushDelay(t time.Time, queue string, jobJSON string) (bool, error) {
	_, err := d.client.ZAdd(queue, t.UnixNano(), jobJSON)
	if err != nil {
		return false, err
	}
	if _, ok := d.schedule[queue]; !ok {
		d.schedule[queue] = struct{}{}
	}
	return true, nil
}

func (d *drv) Poll() {
	go func(d *drv) {
		for {
			for key := range d.schedule {
				now := time.Now()
				k := fmt.Sprintf("%s -inf %d", key, now.UnixNano())
				jobs, _ := d.client.ZRangeByScore(k, 0, 1, true, true, 0, 1)
				if len(jobs) == 0 {
					continue
				}
				removed, _ := d.client.ZRem(key, jobs[0])
				if removed == 0 {
					queue := strings.TrimPrefix(key, d.nameSpace)
					d.client.LPush(d.nameSpace+"queue:"+queue, jobs[0])
				}
			}
		}
	}(d)
}
<commit_msg>Add sleep to poll loop. (#3)<commit_after>package resque

import (
	"fmt"
	"strings"
	"time"

	"github.com/fiorix/go-redis/redis"
	"github.com/jazibjohar/go-resque"
	"github.com/jazibjohar/go-resque/driver"
)

func init() {
	resque.Register("redis-go", &drv{})
}

type drv struct {
	client *redis.Client
	driver.Enqueuer
	schedule  map[string]struct{}
	nameSpace string
}

func (d *drv) SetClient(name string, client interface{}) {
	d.client = client.(*redis.Client)
	d.schedule = make(map[string]struct{})
	d.nameSpace = name
}

func (d *drv) ListPush(queue string, jobJSON string) (int64, error) {
	listLength, err := d.client.RPush(d.nameSpace+"queue:"+queue, jobJSON)
	if err != nil {
		return -1, err
	}

	return int64(listLength), err
}
func (d *drv) ListPushDelay(t time.Time, queue string, jobJSON string) (bool, error) {
	_, err := d.client.ZAdd(queue, t.UnixNano(), jobJSON)
	if err != nil {
		return false, err
	}
	if _, ok := d.schedule[queue]; !ok {
		d.schedule[queue] = struct{}{}
	}
	return true, nil
}

func (d *drv) Poll() {
	go func(d *drv) {
		for {
			for key := range d.schedule {
				now := time.Now()
				k := fmt.Sprintf("%s -inf %d", key, now.UnixNano())
				jobs, _ := d.client.ZRangeByScore(k, 0, 1, true, true, 0, 1)
				if len(jobs) == 0 {
					continue
				}
				removed, _ := d.client.ZRem(key, jobs[0])
				if removed == 0 {
					queue := strings.TrimPrefix(key, d.nameSpace)
					d.client.LPush(d.nameSpace+"queue:"+queue, jobs[0])
				}
			}
			time.Sleep(100 * time.Millisecond)
		}
	}(d)
}
<|endoftext|>


<commit_before>package libkb

import (
	"crypto/rsa"
	"fmt"
	"golang.org/x/crypto/openpgp"
	"golang.org/x/crypto/openpgp/errors"
	"golang.org/x/crypto/openpgp/packet"
	"strings"
)

type PGPGenArg struct {
	PrimaryBits     int
	SubkeyBits      int
	Ids             Identities
	Config          *packet.Config
	PGPUids         []string
	NoDefPGPUid     bool
	PrimaryLifetime int
	SubkeyLifetime  int
}

func ui32p(i int) *uint32 {
	if i >= 0 {
		tmp := uint32(i)
		return &tmp
	} else {
		return nil
	}
}

// NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a
// single identity composed of the given full name, comment and email, any of
// which may be empty but must not contain any of "()<>\x00".
// If config is nil, sensible defaults will be used.
//
// Modification of: https://code.google.com/p/go/source/browse/openpgp/keys.go?repo=crypto&r=8fec09c61d5d66f460d227fd1df3473d7e015bc6#456
//  From golang.com/x/crypto/openpgp/keys.go
func NewPgpKeyBundle(arg PGPGenArg, logUI LogUI) (*PgpKeyBundle, error) {
	currentTime := arg.Config.Now()

	if len(arg.Ids) == 0 {
		return nil, errors.InvalidArgumentError("No Ids in PgpArg")
	}
	uids, err := arg.PGPUserIDs()
	if err != nil {
		return nil, err
	}
	for i, id := range arg.Ids {
		extra := ""
		if i == 0 {
			extra = "[primary]"
		}
		if logUI != nil {
			logUI.Info("PGP User ID: %s %s", id, extra)
		}
	}

	if logUI != nil {
		logUI.Info("Generating primary key (%d bits)", arg.PrimaryBits)
	}
	masterPriv, err := rsa.GenerateKey(arg.Config.Random(), arg.PrimaryBits)
	if err != nil {
		return nil, err
	}

	if logUI != nil {
		logUI.Info("Generating encryption subkey (%d bits)", arg.SubkeyBits)
	}
	encryptingPriv, err := rsa.GenerateKey(arg.Config.Random(), arg.SubkeyBits)
	if err != nil {
		return nil, err
	}

	e := &openpgp.Entity{
		PrimaryKey: packet.NewRSAPublicKey(currentTime, &masterPriv.PublicKey),
		PrivateKey: packet.NewRSAPrivateKey(currentTime, masterPriv),
		Identities: make(map[string]*openpgp.Identity),
	}
	for i, uid := range uids {
		isPrimaryId := true
		if i > 0 {
			isPrimaryId = false
		}
		id := &openpgp.Identity{
			Name:   uid.Name,
			UserId: uid,
			SelfSignature: &packet.Signature{
				CreationTime: currentTime,
				SigType:      packet.SigTypePositiveCert,
				PubKeyAlgo:   packet.PubKeyAlgoRSA,
				Hash:         arg.Config.Hash(),
				IsPrimaryId:  &isPrimaryId,
				FlagsValid:   true,
				FlagSign:     true,
				FlagCertify:  true,
				IssuerKeyId:  &e.PrimaryKey.KeyId,
			},
		}
		id.SelfSignature.KeyLifetimeSecs = ui32p(arg.PrimaryLifetime)
		e.Identities[uid.Id] = id
	}

	e.Subkeys = make([]openpgp.Subkey, 1)
	e.Subkeys[0] = openpgp.Subkey{
		PublicKey:  packet.NewRSAPublicKey(currentTime, &encryptingPriv.PublicKey),
		PrivateKey: packet.NewRSAPrivateKey(currentTime, encryptingPriv),
		Sig: &packet.Signature{
			CreationTime:              currentTime,
			SigType:                   packet.SigTypeSubkeyBinding,
			PubKeyAlgo:                packet.PubKeyAlgoRSA,
			Hash:                      arg.Config.Hash(),
			FlagsValid:                true,
			FlagEncryptStorage:        true,
			FlagEncryptCommunications: true,
			IssuerKeyId:               &e.PrimaryKey.KeyId,
		},
	}
	e.Subkeys[0].PublicKey.IsSubkey = true
	e.Subkeys[0].PrivateKey.IsSubkey = true
	e.Subkeys[0].Sig.KeyLifetimeSecs = ui32p(arg.SubkeyLifetime)

	return (*PgpKeyBundle)(e), nil
}

// CreateIDs creates identities for KeyGenArg.Ids if none exist.
// It uses PGPUids to determine the set of Ids.  It does not set the
// default keybase.io uid.  AddDefaultUid() does that.
func (a *PGPGenArg) CreatePgpIDs() error {
	if len(a.Ids) > 0 {
		return nil
	}
	for _, id := range a.PGPUids {
		if !strings.Contains(id, "<") && CheckEmail.F(id) {
			a.Ids = append(a.Ids, Identity{Email: id})
			continue
		}
		parsed, err := ParseIdentity(id)
		if err != nil {
			return err
		}
		a.Ids = append(a.Ids, *parsed)
	}
	return nil
}

func (a *PGPGenArg) AddDefaultUid() {
	if a.NoDefPGPUid {
		return
	}
	a.Ids = append(a.Ids, KeybaseIdentity(""))
}

func (a *PGPGenArg) MakeAllIds() {
	a.CreatePgpIDs()
	a.AddDefaultUid()
}

func (a *PGPGenArg) PGPUserIDs() ([]*packet.UserId, error) {
	uids := make([]*packet.UserId, len(a.Ids))
	for i, id := range a.Ids {
		uids[i] = id.ToPgpUserId()
		if uids[i] == nil {
			return nil, fmt.Errorf("Id[%d] failed to convert to PGPUserId (%+v)", i, id)
		}
	}
	return uids, nil
}

func (a *PGPGenArg) Init() (err error) {
	defBits := 4096
	if a.PrimaryBits == 0 {
		a.PrimaryBits = defBits
	}
	if a.SubkeyBits == 0 {
		a.SubkeyBits = defBits
	}
	if a.PrimaryLifetime == 0 {
		a.PrimaryLifetime = KEY_EXPIRE_IN
	}
	if a.SubkeyLifetime == 0 {
		a.SubkeyLifetime = SUBKEY_EXPIRE_IN
	}
	return
}
<commit_msg>Fixed missing PreferredHash, PreferredSymmetric, PreferredCompression fields in pgp Signature.<commit_after>package libkb

import (
	"crypto"
	"crypto/rsa"
	"fmt"
	"strings"

	"golang.org/x/crypto/openpgp"
	"golang.org/x/crypto/openpgp/errors"
	"golang.org/x/crypto/openpgp/packet"
	"golang.org/x/crypto/openpgp/s2k"
)

type PGPGenArg struct {
	PrimaryBits     int
	SubkeyBits      int
	Ids             Identities
	Config          *packet.Config
	PGPUids         []string
	NoDefPGPUid     bool
	PrimaryLifetime int
	SubkeyLifetime  int
}

func ui32p(i int) *uint32 {
	if i >= 0 {
		tmp := uint32(i)
		return &tmp
	} else {
		return nil
	}
}

// NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a
// single identity composed of the given full name, comment and email, any of
// which may be empty but must not contain any of "()<>\x00".
// If config is nil, sensible defaults will be used.
//
// Modification of: https://code.google.com/p/go/source/browse/openpgp/keys.go?repo=crypto&r=8fec09c61d5d66f460d227fd1df3473d7e015bc6#456
//  From golang.com/x/crypto/openpgp/keys.go
func NewPgpKeyBundle(arg PGPGenArg, logUI LogUI) (*PgpKeyBundle, error) {
	currentTime := arg.Config.Now()

	if len(arg.Ids) == 0 {
		return nil, errors.InvalidArgumentError("No Ids in PgpArg")
	}
	uids, err := arg.PGPUserIDs()
	if err != nil {
		return nil, err
	}
	for i, id := range arg.Ids {
		extra := ""
		if i == 0 {
			extra = "[primary]"
		}
		if logUI != nil {
			logUI.Info("PGP User ID: %s %s", id, extra)
		}
	}

	if logUI != nil {
		logUI.Info("Generating primary key (%d bits)", arg.PrimaryBits)
	}
	masterPriv, err := rsa.GenerateKey(arg.Config.Random(), arg.PrimaryBits)
	if err != nil {
		return nil, err
	}

	if logUI != nil {
		logUI.Info("Generating encryption subkey (%d bits)", arg.SubkeyBits)
	}
	encryptingPriv, err := rsa.GenerateKey(arg.Config.Random(), arg.SubkeyBits)
	if err != nil {
		return nil, err
	}

	e := &openpgp.Entity{
		PrimaryKey: packet.NewRSAPublicKey(currentTime, &masterPriv.PublicKey),
		PrivateKey: packet.NewRSAPrivateKey(currentTime, masterPriv),
		Identities: make(map[string]*openpgp.Identity),
	}

	for i, uid := range uids {
		isPrimaryId := true
		if i > 0 {
			isPrimaryId = false
		}
		id := &openpgp.Identity{
			Name:   uid.Name,
			UserId: uid,
			SelfSignature: &packet.Signature{
				CreationTime:         currentTime,
				SigType:              packet.SigTypePositiveCert,
				PubKeyAlgo:           packet.PubKeyAlgoRSA,
				Hash:                 arg.Config.Hash(),
				IsPrimaryId:          &isPrimaryId,
				FlagsValid:           true,
				FlagSign:             true,
				FlagCertify:          true,
				IssuerKeyId:          &e.PrimaryKey.KeyId,
				PreferredSymmetric:   arg.PreferredSymmetric(),
				PreferredHash:        arg.PreferredHash(),
				PreferredCompression: arg.PreferredCompression(),
			},
		}
		id.SelfSignature.KeyLifetimeSecs = ui32p(arg.PrimaryLifetime)
		e.Identities[uid.Id] = id
	}

	e.Subkeys = make([]openpgp.Subkey, 1)
	e.Subkeys[0] = openpgp.Subkey{
		PublicKey:  packet.NewRSAPublicKey(currentTime, &encryptingPriv.PublicKey),
		PrivateKey: packet.NewRSAPrivateKey(currentTime, encryptingPriv),
		Sig: &packet.Signature{
			CreationTime:              currentTime,
			SigType:                   packet.SigTypeSubkeyBinding,
			PubKeyAlgo:                packet.PubKeyAlgoRSA,
			Hash:                      arg.Config.Hash(),
			FlagsValid:                true,
			FlagEncryptStorage:        true,
			FlagEncryptCommunications: true,
			IssuerKeyId:               &e.PrimaryKey.KeyId,
			PreferredSymmetric:        arg.PreferredSymmetric(),
			PreferredHash:             arg.PreferredHash(),
			PreferredCompression:      arg.PreferredCompression(),
		},
	}
	e.Subkeys[0].PublicKey.IsSubkey = true
	e.Subkeys[0].PrivateKey.IsSubkey = true
	e.Subkeys[0].Sig.KeyLifetimeSecs = ui32p(arg.SubkeyLifetime)

	return (*PgpKeyBundle)(e), nil
}

// CreateIDs creates identities for KeyGenArg.Ids if none exist.
// It uses PGPUids to determine the set of Ids.  It does not set the
// default keybase.io uid.  AddDefaultUid() does that.
func (a *PGPGenArg) CreatePgpIDs() error {
	if len(a.Ids) > 0 {
		return nil
	}
	for _, id := range a.PGPUids {
		if !strings.Contains(id, "<") && CheckEmail.F(id) {
			a.Ids = append(a.Ids, Identity{Email: id})
			continue
		}
		parsed, err := ParseIdentity(id)
		if err != nil {
			return err
		}
		a.Ids = append(a.Ids, *parsed)
	}
	return nil
}

func (a *PGPGenArg) AddDefaultUid() {
	if a.NoDefPGPUid {
		return
	}
	a.Ids = append(a.Ids, KeybaseIdentity(""))
}

func (a *PGPGenArg) MakeAllIds() {
	a.CreatePgpIDs()
	a.AddDefaultUid()
}

func (a *PGPGenArg) PGPUserIDs() ([]*packet.UserId, error) {
	uids := make([]*packet.UserId, len(a.Ids))
	for i, id := range a.Ids {
		uids[i] = id.ToPgpUserId()
		if uids[i] == nil {
			return nil, fmt.Errorf("Id[%d] failed to convert to PGPUserId (%+v)", i, id)
		}
	}
	return uids, nil
}

func (a *PGPGenArg) Init() (err error) {
	defBits := 4096
	if a.PrimaryBits == 0 {
		a.PrimaryBits = defBits
	}
	if a.SubkeyBits == 0 {
		a.SubkeyBits = defBits
	}
	if a.PrimaryLifetime == 0 {
		a.PrimaryLifetime = KEY_EXPIRE_IN
	}
	if a.SubkeyLifetime == 0 {
		a.SubkeyLifetime = SUBKEY_EXPIRE_IN
	}
	return
}

func (a *PGPGenArg) PreferredSymmetric() []uint8 {
	return []uint8{
		uint8(packet.CipherAES128),
		uint8(packet.CipherAES256),
		uint8(packet.CipherCAST5),
	}
}

func (a *PGPGenArg) PreferredHash() []uint8 {
	gohash := []crypto.Hash{
		crypto.SHA256,
		crypto.SHA512,
		crypto.SHA1,
		crypto.RIPEMD160,
	}
	var res []uint8
	for _, h := range gohash {
		id, ok := s2k.HashToHashId(h)
		if !ok {
			continue
		}
		res = append(res, id)
	}
	return res
}

func (a *PGPGenArg) PreferredCompression() []uint8 {
	return []uint8{
		uint8(packet.CompressionNone),
		uint8(packet.CompressionZIP),
		uint8(packet.CompressionZLIB),
	}
}
<|endoftext|>


<commit_before>package tracer

import (
	"bytes"
	"errors"
	"reflect"
	"sync"
	"time"

	"github.com/rcrowley/go-metrics"
)

// Tracer is a struct that implements the `metrics.Timer` interface and
// provides hooks for timing blocks of code.
type Tracer struct {
	path     string
	registry metrics.Registry
	timer    metrics.Timer
}

// A function that takes a Tracer
type TracedFunc func(*Tracer)

// TimeFunc times the function passed in, with the path of the current
// Tracer, appending ".pathComponent" to its trace path. The tracer
// passed to `tracedFunc` can be used to further add to the trace.
func (t *Tracer) TimeFunc(pathComponent string, tracedFunc TracedFunc) {
	var buffer bytes.Buffer
	buffer.WriteString(t.path)
	buffer.WriteString(".")
	buffer.WriteString(pathComponent)
	path := buffer.String()
	tracer, _ := t.registry.GetOrRegister(path, tracerGenerator(path)).(*Tracer)
	tracer.timer.Time(func() { tracedFunc(tracer) })
}

// Path of the Tracer
func (t *Tracer) Path() string {
	return t.path
}

func NewTracer(path string) *Tracer {
	return &Tracer{
		path,
		newTracerRegistry(),
		metrics.NewTimer(),
	}
}

func tracerGenerator(path string) func() *Tracer {
	return func() *Tracer {
		return NewTracer(path)
	}
}

// Fulfill `metrics.Timer` interface

func (t *Tracer) Count() int64                         { return t.timer.Count() }
func (t *Tracer) Max() int64                           { return t.timer.Max() }
func (t *Tracer) Mean() float64                        { return t.timer.Mean() }
func (t *Tracer) Min() int64                           { return t.timer.Min() }
func (t *Tracer) Percentile(p float64) float64         { return t.timer.Percentile(p) }
func (t *Tracer) Percentiles(pcts []float64) []float64 { return t.timer.Percentiles(pcts) }
func (t *Tracer) Rate1() float64                       { return t.timer.Rate1() }
func (t *Tracer) Rate5() float64                       { return t.timer.Rate5() }
func (t *Tracer) Rate15() float64                      { return t.timer.Rate15() }
func (t *Tracer) RateMean() float64                    { return t.timer.RateMean() }
func (t *Tracer) Snapshot() metrics.Timer              { return t.timer.Snapshot() }
func (t *Tracer) StdDev() float64                      { return t.timer.StdDev() }
func (t *Tracer) Sum() int64                           { return t.timer.Sum() }
func (t *Tracer) Time(f func())                        { t.timer.Time(f) }
func (t *Tracer) Update(d time.Duration)               { t.timer.Update(d) }
func (t *Tracer) UpdateSince(since time.Time)          { t.timer.UpdateSince(since) }
func (t *Tracer) Variance() float64                    { return t.timer.Variance() }

var _ metrics.Timer = &Tracer{}

func newTracerRegistry() *tracerRegistry {
	return &tracerRegistry{tracePaths: make(map[string]*Tracer)}
}

// A private `metrics.Registry` implementation. Will call all child
// Tracers when iterating using the `metrics.Registry#Each` method.
type tracerRegistry struct {
	tracePaths map[string]*Tracer
	mutex      sync.RWMutex
}

func (tr *tracerRegistry) registered() map[string]*Tracer {
	// No need for a write lock here, despite the confusing method name
	tr.mutex.RLock()
	defer tr.mutex.RUnlock()
	registeredTracers := make(map[string]*Tracer, len(tr.tracePaths))
	for path, t := range tr.tracePaths {
		registeredTracers[path] = t
	}
	return registeredTracers
}

func (tr *tracerRegistry) Each(f func(string, interface{})) {
	for path, tracer := range tr.registered() {
		f(path, tracer)
		tracer.registry.Each(f)
	}
}

func (tr *tracerRegistry) Get(path string) interface{} {
	t, _ := tr.get(path)
	return t
}

// Acquires read lock, no need to wrap this call
func (tr *tracerRegistry) get(path string) (*Tracer, bool) {
	tr.mutex.RLock()
	defer tr.mutex.RUnlock()
	t, ok := tr.tracePaths[path]
	return t, ok
}

func (tr *tracerRegistry) GetOrRegister(path string, i interface{}) interface{} {
	if tracer, ok := tr.get(path); ok {
		return tracer
	}
	var t *Tracer
	if v := reflect.ValueOf(i); v.Kind() == reflect.Func {
		t = v.Call(nil)[0].Interface().(*Tracer)
	}
	tr.register(path, t)
	return t
}

func (tr *tracerRegistry) Register(path string, i interface{}) error {
	t, ok := i.(*Tracer)
	if !ok {
		return errors.New("Cannot register non-Tracer with tracerRegistry")
	}

	return tr.register(path, t)
}

// Acquires write lock, no need to wrap this call
func (tr *tracerRegistry) register(path string, t *Tracer) error {
	tr.mutex.Lock()
	defer tr.mutex.Unlock()

	if _, ok := tr.tracePaths[path]; ok {
		return metrics.DuplicateMetric(path)
	}
	tr.tracePaths[path] = t
	return nil
}

// No-op
func (tr *tracerRegistry) RunHealthchecks() {}

func (tr *tracerRegistry) Unregister(path string) {
	tr.mutex.Lock()
	defer tr.mutex.Unlock()
	delete(tr.tracePaths, path)
}

func (tr *tracerRegistry) UnregisterAll() {
	tr.mutex.Lock()
	defer tr.mutex.Unlock()
	for path, _ := range tr.tracePaths {
		delete(tr.tracePaths, path)
	}
}

var _ metrics.Registry = &tracerRegistry{}
<commit_msg>use tracer time proxy method<commit_after>package tracer

import (
	"bytes"
	"errors"
	"reflect"
	"sync"
	"time"

	"github.com/rcrowley/go-metrics"
)

// Tracer is a struct that implements the `metrics.Timer` interface and
// provides hooks for timing blocks of code.
type Tracer struct {
	path     string
	registry metrics.Registry
	timer    metrics.Timer
}

// A function that takes a Tracer
type TracedFunc func(*Tracer)

// TimeFunc times the function passed in, with the path of the current
// Tracer, appending ".pathComponent" to its trace path. The tracer
// passed to `tracedFunc` can be used to further add to the trace.
func (t *Tracer) TimeFunc(pathComponent string, tracedFunc TracedFunc) {
	var buffer bytes.Buffer
	buffer.WriteString(t.path)
	buffer.WriteString(".")
	buffer.WriteString(pathComponent)
	path := buffer.String()
	tracer, _ := t.registry.GetOrRegister(path, tracerGenerator(path)).(*Tracer)
	tracer.Time(func() { tracedFunc(tracer) })
}

// Path of the Tracer
func (t *Tracer) Path() string {
	return t.path
}

func NewTracer(path string) *Tracer {
	return &Tracer{
		path,
		newTracerRegistry(),
		metrics.NewTimer(),
	}
}

func tracerGenerator(path string) func() *Tracer {
	return func() *Tracer {
		return NewTracer(path)
	}
}

// Fulfill `metrics.Timer` interface

func (t *Tracer) Count() int64                         { return t.timer.Count() }
func (t *Tracer) Max() int64                           { return t.timer.Max() }
func (t *Tracer) Mean() float64                        { return t.timer.Mean() }
func (t *Tracer) Min() int64                           { return t.timer.Min() }
func (t *Tracer) Percentile(p float64) float64         { return t.timer.Percentile(p) }
func (t *Tracer) Percentiles(pcts []float64) []float64 { return t.timer.Percentiles(pcts) }
func (t *Tracer) Rate1() float64                       { return t.timer.Rate1() }
func (t *Tracer) Rate5() float64                       { return t.timer.Rate5() }
func (t *Tracer) Rate15() float64                      { return t.timer.Rate15() }
func (t *Tracer) RateMean() float64                    { return t.timer.RateMean() }
func (t *Tracer) Snapshot() metrics.Timer              { return t.timer.Snapshot() }
func (t *Tracer) StdDev() float64                      { return t.timer.StdDev() }
func (t *Tracer) Sum() int64                           { return t.timer.Sum() }
func (t *Tracer) Time(f func())                        { t.timer.Time(f) }
func (t *Tracer) Update(d time.Duration)               { t.timer.Update(d) }
func (t *Tracer) UpdateSince(since time.Time)          { t.timer.UpdateSince(since) }
func (t *Tracer) Variance() float64                    { return t.timer.Variance() }

var _ metrics.Timer = &Tracer{}

func newTracerRegistry() *tracerRegistry {
	return &tracerRegistry{tracePaths: make(map[string]*Tracer)}
}

// A private `metrics.Registry` implementation. Will call all child
// Tracers when iterating using the `metrics.Registry#Each` method.
type tracerRegistry struct {
	tracePaths map[string]*Tracer
	mutex      sync.RWMutex
}

func (tr *tracerRegistry) registered() map[string]*Tracer {
	// No need for a write lock here, despite the confusing method name
	tr.mutex.RLock()
	defer tr.mutex.RUnlock()
	registeredTracers := make(map[string]*Tracer, len(tr.tracePaths))
	for path, t := range tr.tracePaths {
		registeredTracers[path] = t
	}
	return registeredTracers
}

func (tr *tracerRegistry) Each(f func(string, interface{})) {
	for path, tracer := range tr.registered() {
		f(path, tracer)
		tracer.registry.Each(f)
	}
}

func (tr *tracerRegistry) Get(path string) interface{} {
	t, _ := tr.get(path)
	return t
}

// Acquires read lock, no need to wrap this call
func (tr *tracerRegistry) get(path string) (*Tracer, bool) {
	tr.mutex.RLock()
	defer tr.mutex.RUnlock()
	t, ok := tr.tracePaths[path]
	return t, ok
}

func (tr *tracerRegistry) GetOrRegister(path string, i interface{}) interface{} {
	if tracer, ok := tr.get(path); ok {
		return tracer
	}
	var t *Tracer
	if v := reflect.ValueOf(i); v.Kind() == reflect.Func {
		t = v.Call(nil)[0].Interface().(*Tracer)
	}
	tr.register(path, t)
	return t
}

func (tr *tracerRegistry) Register(path string, i interface{}) error {
	t, ok := i.(*Tracer)
	if !ok {
		return errors.New("Cannot register non-Tracer with tracerRegistry")
	}

	return tr.register(path, t)
}

// Acquires write lock, no need to wrap this call
func (tr *tracerRegistry) register(path string, t *Tracer) error {
	tr.mutex.Lock()
	defer tr.mutex.Unlock()

	if _, ok := tr.tracePaths[path]; ok {
		return metrics.DuplicateMetric(path)
	}
	tr.tracePaths[path] = t
	return nil
}

// No-op
func (tr *tracerRegistry) RunHealthchecks() {}

func (tr *tracerRegistry) Unregister(path string) {
	tr.mutex.Lock()
	defer tr.mutex.Unlock()
	delete(tr.tracePaths, path)
}

func (tr *tracerRegistry) UnregisterAll() {
	tr.mutex.Lock()
	defer tr.mutex.Unlock()
	for path, _ := range tr.tracePaths {
		delete(tr.tracePaths, path)
	}
}

var _ metrics.Registry = &tracerRegistry{}
<|endoftext|>


<commit_before>//go:build ignore
// +build ignore

/*
 * Copyright (c) 2021 The GoPlus Authors (goplus.org). All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package main

import (
	"bytes"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"time"
)

func checkPathExist(path string, isDir bool) bool {
	stat, err := os.Stat(path)
	isExists := !os.IsNotExist(err)
	if isDir {
		return isExists && stat.IsDir()
	}
	return isExists && !stat.IsDir()
}

func trimRight(s string) string {
	return strings.TrimRight(s, " \t\r\n")
}

// Path returns single path to check
type Path struct {
	path  string
	isDir bool
}

func (p *Path) checkExists(rootDir string) bool {
	absPath := filepath.Join(rootDir, p.path)
	return checkPathExist(absPath, p.isDir)
}

func getGopRoot() string {
	pwd, _ := os.Getwd()

	pathsToCheck := []Path{
		{path: "cmd/gop", isDir: true},
		{path: "builtin", isDir: true},
		{path: "go.mod", isDir: false},
		{path: "go.sum", isDir: false},
	}

	for _, path := range pathsToCheck {
		if !path.checkExists(pwd) {
			println("Error: This script should be run at the root directory of gop repository.")
			os.Exit(1)
		}
	}
	return pwd
}

var gopRoot = getGopRoot()
var initCommandExecuteEnv = os.Environ()
var commandExecuteEnv = initCommandExecuteEnv

// Always put `gop` command as the first item, as it will be referenced by below code.
var gopBinFiles = []string{"gop", "gopfmt"}
var versionFile = filepath.Join(gopRoot, "VERSION")

const (
	inWindows = (runtime.GOOS == "windows")
)

func init() {
	if inWindows {
		for index, file := range gopBinFiles {
			file += ".exe"
			gopBinFiles[index] = file
		}
	}
}

func execCommand(command string, arg ...string) (string, string, error) {
	var stdout, stderr bytes.Buffer
	cmd := exec.Command(command, arg...)
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	cmd.Env = commandExecuteEnv
	err := cmd.Run()
	return stdout.String(), stderr.String(), err
}

func getGitBranch() string {
	branch, _, err := execCommand("git", "rev-parse", "--abbrev-ref", "HEAD")
	if err != nil {
		return ""
	}
	return trimRight(branch)
}

func checkoutBranch(branch string) (string, error) {
	_, stderr, err := execCommand("git", "checkout", branch)
	return stderr, err
}

func isGitRepo() bool {
	gitDir, _, err := execCommand("git", "rev-parse", "--git-dir")
	if err != nil {
		return false
	}
	return checkPathExist(filepath.Join(gopRoot, trimRight(gitDir)), true)
}

func getBuildDateTime() string {
	now := time.Now()
	return now.Format("2006-01-02_15-04-05")
}

func getBuildVer() string {
	tagRet, tagErr, err := execCommand("git", "describe", "--tags")
	if err != nil || tagErr != "" {
		return ""
	}
	return trimRight(tagRet)
}

func getGopBuildFlags() string {
	defaultGopRoot := gopRoot
	if gopRootFinal := os.Getenv("GOPROOT_FINAL"); gopRootFinal != "" {
		defaultGopRoot = gopRootFinal
	}
	buildFlags := fmt.Sprintf("-X \"github.com/goplus/gop/env.defaultGopRoot=%s\"", defaultGopRoot)
	buildFlags += fmt.Sprintf(" -X \"github.com/goplus/gop/env.buildDate=%s\"", getBuildDateTime())

	version := findGopVersion()
	buildFlags += fmt.Sprintf(" -X \"github.com/goplus/gop/env.buildVersion=%s\"", version)

	return buildFlags
}

func detectGopBinPath() string {
	return filepath.Join(gopRoot, "bin")
}

func detectGoBinPath() string {
	goBin, ok := os.LookupEnv("GOBIN")
	if ok {
		return goBin
	}

	goPath, ok := os.LookupEnv("GOPATH")
	if ok {
		list := filepath.SplitList(goPath)
		if len(list) > 0 {
			// Put in first directory of $GOPATH.
			return filepath.Join(list[0], "bin")
		}
	}

	homeDir, _ := os.UserHomeDir()
	return filepath.Join(homeDir, "go", "bin")
}

func linkGoplusToLocalBin() string {
	println("Start Linking.")

	gopBinPath := detectGopBinPath()
	goBinPath := detectGoBinPath()
	if !checkPathExist(gopBinPath, true) {
		log.Fatalf("Error: %s is not existed, you should build Go+ before linking.\n", gopBinPath)
	}
	if !checkPathExist(goBinPath, true) {
		if err := os.MkdirAll(goBinPath, 0755); err != nil {
			fmt.Printf("Error: target directory %s is not existed and we can't create one.\n", goBinPath)
			log.Fatalln(err)
		}
	}

	for _, file := range gopBinFiles {
		sourceFile := filepath.Join(gopBinPath, file)
		if !checkPathExist(sourceFile, false) {
			log.Fatalf("Error: %s is not existed, you should build Go+ before linking.\n", sourceFile)
		}
		targetLink := filepath.Join(goBinPath, file)
		if checkPathExist(targetLink, false) {
			// Delete existed one
			if err := os.Remove(targetLink); err != nil {
				log.Fatalln(err)
			}
		}
		if err := os.Symlink(sourceFile, targetLink); err != nil {
			log.Fatalln(err)
		}
		fmt.Printf("Link %s to %s successfully.\n", sourceFile, targetLink)
	}

	println("End linking.")
	return goBinPath
}

func buildGoplusTools(useGoProxy bool) {
	commandsDir := filepath.Join(gopRoot, "cmd")
	buildFlags := getGopBuildFlags()

	if useGoProxy {
		println("Info: we will use goproxy.cn as a Go proxy to accelerate installing process.")
		commandExecuteEnv = append(commandExecuteEnv,
			"GOPROXY=https://goproxy.cn,direct",
		)
	}

	// Install Go+ binary files under current ./bin directory.
	gopBinPath := detectGopBinPath()
	if err := os.Mkdir(gopBinPath, 0755); err != nil && !os.IsExist(err) {
		println("Error: Go+ can't create ./bin directory to put build assets.")
		log.Fatalln(err)
	}

	println("Installing Go+ tools...\n")
	os.Chdir(commandsDir)
	buildOutput, buildErr, err := execCommand("go", "build", "-o", gopBinPath, "-v", "-ldflags", buildFlags, "./...")
	print(buildErr)
	if err != nil {
		log.Fatalln(err)
	}
	print(buildOutput)

	// Clear gop run cache
	cleanGopRunCache()

	installPath := linkGoplusToLocalBin()

	println("\nGo+ tools installed successfully!")

	if _, _, err := execCommand("gop", "version"); err != nil {
		showHelpPostInstall(installPath)
	}
}

func showHelpPostInstall(installPath string) {
	println("\nNEXT STEP:")
	println("\nWe just installed Go+ into the directory: ", installPath)
	message := `
To setup a better Go+ development environment,
we recommend you add the above install directory into your PATH environment variable.
	`
	println(message)
}

func runTestcases() {
	println("Start running testcases.")
	os.Chdir(gopRoot)

	coverage := "-coverprofile=coverage.txt"
	gopCommand := filepath.Join(detectGopBinPath(), gopBinFiles[0])
	if !checkPathExist(gopCommand, false) {
		println("Error: Go+ must be installed before running testcases.")
		os.Exit(1)
	}

	testOutput, testErr, err := execCommand(gopCommand, "test", coverage, "-covermode=atomic", "./...")
	println(testOutput)
	println(testErr)
	if err != nil {
		println(err.Error())
	}

	println("End running testcases.")
}

func clean() {
	gopBinPath := detectGopBinPath()
	goBinPath := detectGoBinPath()

	// Clean links
	for _, file := range gopBinFiles {
		targetLink := filepath.Join(goBinPath, file)
		if checkPathExist(targetLink, false) {
			if err := os.Remove(targetLink); err != nil {
				log.Fatalln(err)
			}
		}
	}

	// Clean build binary files
	if checkPathExist(gopBinPath, true) {
		if err := os.RemoveAll(gopBinPath); err != nil {
			log.Fatalln(err)
		}
	}

	cleanGopRunCache()
}

func cleanGopRunCache() {
	homeDir, _ := os.UserHomeDir()
	runCacheDir := filepath.Join(homeDir, ".gop", "run")
	files := []string{"go.mod", "go.sum"}
	for _, file := range files {
		fullPath := filepath.Join(runCacheDir, file)
		if checkPathExist(fullPath, false) {
			if err := os.Remove(fullPath); err != nil {
				log.Fatalln(err)
			}
		}
	}
}

func uninstall() {
	println("Uninstalling Go+ and related tools.")
	clean()
	println("Go+ and related tools uninstalled successfully.")
}

func isInChina() bool {
	const prefix = "LANG=\""
	out, errMsg, err := execCommand("locale")
	if err != nil || errMsg != "" {
		return false
	}
	if strings.HasPrefix(out, prefix) {
		out = out[len(prefix):]
		return strings.HasPrefix(out, "zh_CN") || strings.HasPrefix(out, "zh_HK")
	}
	return false
}

// findGopVersion returns current version of gop
func findGopVersion() string {
	// Read version from VERSION file
	if checkPathExist(versionFile, false) {
		data, err := os.ReadFile(versionFile)
		if err == nil {
			version := trimRight(string(data))
			return version
		}
	}

	// Read version from git repo
	if !isGitRepo() {
		log.Fatal("Error: must be a git repo or a VERSION file existed.")
	}
	version := getBuildVer() // Closet tag on git log
	return version
}

// releaseNewVersion tags the repo with provided new tag, and writes new tag into VERSION file.
func releaseNewVersion(tag string) {
	if !isGitRepo() {
		log.Fatal("Error: Releasing a new version could only be operated under a git repo.")
	}
	println("Start releasing new version")

	version := tag

	re := regexp.MustCompile(`^v\d+?\.\d+?`)
	releaseBranch := re.FindString(version)
	sourceBranch := getGitBranch()

	if releaseBranch == "" {
		log.Fatal("Error: A valid version should be has form: vx.y.z")
	}

	// Checkout to release breanch
	if stderr, err := checkoutBranch(releaseBranch); err != nil {
		log.Fatalf("Error: checkout to release branch: %s failed with error: %v.", releaseBranch, stderr)
	}

	fmt.Printf("\nReleasing new version: %s\n\n", version)

	// Cache new version
	if err := os.WriteFile(versionFile, []byte(version), 0644); err != nil {
		log.Fatalf("Error: cache new version with error: %v\n", err)
	}

	// Tag the source code
	if _, stderr, err := execCommand("git", "tag", version); err != nil {
		log.Fatalf("Error: tag the source code with error: %v\n", stderr)
	}

	// Checkout back to source branch
	if stderr, err := checkoutBranch(sourceBranch); err != nil {
		log.Fatalf("Error: checkout to source branch: %s failed with error: %v.", sourceBranch, stderr)
	}

	println("End releasing new version:", tag)
}

func main() {
	isInstall := flag.Bool("install", false, "Install Go+")
	isTest := flag.Bool("test", false, "Run testcases")
	isUninstall := flag.Bool("uninstall", false, "Uninstall Go+")
	isGoProxy := flag.Bool("proxy", false, "Set GOPROXY for people in China")
	isAutoProxy := flag.Bool("autoproxy", false, "Check to set GOPROXY automatically")
	tag := flag.String("tag", "", "Release an new version with specified tag")

	flag.Parse()

	useGoProxy := *isGoProxy
	if !useGoProxy && *isAutoProxy {
		useGoProxy = isInChina()
	}
	flagActionMap := map[*bool]func(){
		isInstall:   func() { buildGoplusTools(useGoProxy) },
		isUninstall: uninstall,
		isTest:      runTestcases,
	}

	// Sort flags, for example: install flag should be checked earlier than test flag.
	flags := []*bool{isInstall, isTest, isUninstall}
	hasActionDone := false

	if *tag != "" {
		releaseNewVersion(*tag)
		hasActionDone = true
	}

	for _, flag := range flags {
		if *flag {
			flagActionMap[flag]()
			hasActionDone = true
		}
	}

	if !hasActionDone {
		println("Usage:\n")
		flag.PrintDefaults()
	}
}
<commit_msg>releaseNewVersion bugfix<commit_after>//go:build ignore
// +build ignore

/*
 * Copyright (c) 2021 The GoPlus Authors (goplus.org). All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package main

import (
	"bytes"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"time"
)

func checkPathExist(path string, isDir bool) bool {
	stat, err := os.Stat(path)
	isExists := !os.IsNotExist(err)
	if isDir {
		return isExists && stat.IsDir()
	}
	return isExists && !stat.IsDir()
}

func trimRight(s string) string {
	return strings.TrimRight(s, " \t\r\n")
}

// Path returns single path to check
type Path struct {
	path  string
	isDir bool
}

func (p *Path) checkExists(rootDir string) bool {
	absPath := filepath.Join(rootDir, p.path)
	return checkPathExist(absPath, p.isDir)
}

func getGopRoot() string {
	pwd, _ := os.Getwd()

	pathsToCheck := []Path{
		{path: "cmd/gop", isDir: true},
		{path: "builtin", isDir: true},
		{path: "go.mod", isDir: false},
		{path: "go.sum", isDir: false},
	}

	for _, path := range pathsToCheck {
		if !path.checkExists(pwd) {
			println("Error: This script should be run at the root directory of gop repository.")
			os.Exit(1)
		}
	}
	return pwd
}

var gopRoot = getGopRoot()
var initCommandExecuteEnv = os.Environ()
var commandExecuteEnv = initCommandExecuteEnv

// Always put `gop` command as the first item, as it will be referenced by below code.
var gopBinFiles = []string{"gop", "gopfmt"}

const (
	inWindows = (runtime.GOOS == "windows")
)

func init() {
	if inWindows {
		for index, file := range gopBinFiles {
			file += ".exe"
			gopBinFiles[index] = file
		}
	}
}

type ExecCmdError struct {
	Err    error
	Stderr []byte
}

func (p *ExecCmdError) Error() string {
	if e := p.Stderr; e != nil {
		return string(e)
	}
	return p.Err.Error()
}

func execCommand(command string, arg ...string) (string, error) {
	var stdout, stderr bytes.Buffer
	cmd := exec.Command(command, arg...)
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	cmd.Env = commandExecuteEnv
	err := cmd.Run()
	if err != nil || stderr.Len() > 0 {
		err = &ExecCmdError{Err: err, Stderr: stderr.Bytes()}
	}
	return stdout.String(), err
}

func getTagRev(tag string) string {
	const commit = "commit "
	stdout, err := execCommand("git", "show", tag)
	if err != nil || !strings.HasPrefix(stdout, commit) {
		return ""
	}
	data := stdout[len(commit):]
	if pos := strings.IndexByte(data, '\n'); pos > 0 {
		return data[:pos]
	}
	return ""
}

func getGitRemoteUrl(name string) string {
	stdout, err := execCommand("git", "remote", "get-url", name)
	if err != nil {
		return ""
	}
	return stdout
}

func getGitBranch() string {
	branch, err := execCommand("git", "rev-parse", "--abbrev-ref", "HEAD")
	if err != nil {
		return ""
	}
	return branch
}

func gitTag(tag string) error {
	_, err := execCommand("git", "tag", tag)
	return err
}

func gitTagAndPushTo(tag string, remote string) error {
	if err := gitTag(tag); err != nil {
		return err
	}
	_, err := execCommand("git", "push", remote, tag)
	return err
}

func gitCommit(msg string) error {
	_, err := execCommand("git", "commit", "-a", "-m", msg)
	return err
}

func checkoutBranch(branch string) error {
	_, err := execCommand("git", "checkout", branch)
	return err
}

func isGitRepo() bool {
	gitDir, err := execCommand("git", "rev-parse", "--git-dir")
	if err != nil {
		return false
	}
	return checkPathExist(filepath.Join(gopRoot, trimRight(gitDir)), true)
}

func getBuildDateTime() string {
	now := time.Now()
	return now.Format("2006-01-02_15-04-05")
}

func getBuildVer() string {
	stdout, err := execCommand("git", "describe", "--tags")
	if err != nil {
		return ""
	}
	return stdout
}

func getGopBuildFlags() string {
	defaultGopRoot := gopRoot
	if gopRootFinal := os.Getenv("GOPROOT_FINAL"); gopRootFinal != "" {
		defaultGopRoot = gopRootFinal
	}
	buildFlags := fmt.Sprintf("-X \"github.com/goplus/gop/env.defaultGopRoot=%s\"", defaultGopRoot)
	buildFlags += fmt.Sprintf(" -X \"github.com/goplus/gop/env.buildDate=%s\"", getBuildDateTime())

	version := findGopVersion()
	buildFlags += fmt.Sprintf(" -X \"github.com/goplus/gop/env.buildVersion=%s\"", version)

	return buildFlags
}

func detectGopBinPath() string {
	return filepath.Join(gopRoot, "bin")
}

func detectGoBinPath() string {
	goBin, ok := os.LookupEnv("GOBIN")
	if ok {
		return goBin
	}

	goPath, ok := os.LookupEnv("GOPATH")
	if ok {
		list := filepath.SplitList(goPath)
		if len(list) > 0 {
			// Put in first directory of $GOPATH.
			return filepath.Join(list[0], "bin")
		}
	}

	homeDir, _ := os.UserHomeDir()
	return filepath.Join(homeDir, "go", "bin")
}

func linkGoplusToLocalBin() string {
	println("Start Linking.")

	gopBinPath := detectGopBinPath()
	goBinPath := detectGoBinPath()
	if !checkPathExist(gopBinPath, true) {
		log.Fatalf("Error: %s is not existed, you should build Go+ before linking.\n", gopBinPath)
	}
	if !checkPathExist(goBinPath, true) {
		if err := os.MkdirAll(goBinPath, 0755); err != nil {
			fmt.Printf("Error: target directory %s is not existed and we can't create one.\n", goBinPath)
			log.Fatalln(err)
		}
	}

	for _, file := range gopBinFiles {
		sourceFile := filepath.Join(gopBinPath, file)
		if !checkPathExist(sourceFile, false) {
			log.Fatalf("Error: %s is not existed, you should build Go+ before linking.\n", sourceFile)
		}
		targetLink := filepath.Join(goBinPath, file)
		if checkPathExist(targetLink, false) {
			// Delete existed one
			if err := os.Remove(targetLink); err != nil {
				log.Fatalln(err)
			}
		}
		if err := os.Symlink(sourceFile, targetLink); err != nil {
			log.Fatalln(err)
		}
		fmt.Printf("Link %s to %s successfully.\n", sourceFile, targetLink)
	}

	println("End linking.")
	return goBinPath
}

func buildGoplusTools(useGoProxy bool) {
	commandsDir := filepath.Join(gopRoot, "cmd")
	buildFlags := getGopBuildFlags()

	if useGoProxy {
		println("Info: we will use goproxy.cn as a Go proxy to accelerate installing process.")
		commandExecuteEnv = append(commandExecuteEnv,
			"GOPROXY=https://goproxy.cn,direct",
		)
	}

	// Install Go+ binary files under current ./bin directory.
	gopBinPath := detectGopBinPath()
	if err := os.Mkdir(gopBinPath, 0755); err != nil && !os.IsExist(err) {
		println("Error: Go+ can't create ./bin directory to put build assets.")
		log.Fatalln(err)
	}

	println("Installing Go+ tools...\n")
	os.Chdir(commandsDir)
	buildOutput, err := execCommand("go", "build", "-o", gopBinPath, "-v", "-ldflags", buildFlags, "./...")
	if err != nil {
		log.Fatalln(err)
	}
	print(buildOutput)

	// Clear gop run cache
	cleanGopRunCache()

	installPath := linkGoplusToLocalBin()

	println("\nGo+ tools installed successfully!")

	if _, err := execCommand("gop", "version"); err != nil {
		showHelpPostInstall(installPath)
	}
}

func showHelpPostInstall(installPath string) {
	println("\nNEXT STEP:")
	println("\nWe just installed Go+ into the directory: ", installPath)
	message := `
To setup a better Go+ development environment,
we recommend you add the above install directory into your PATH environment variable.
	`
	println(message)
}

func runTestcases() {
	println("Start running testcases.")
	os.Chdir(gopRoot)

	coverage := "-coverprofile=coverage.txt"
	gopCommand := filepath.Join(detectGopBinPath(), gopBinFiles[0])
	if !checkPathExist(gopCommand, false) {
		println("Error: Go+ must be installed before running testcases.")
		os.Exit(1)
	}

	testOutput, err := execCommand(gopCommand, "test", coverage, "-covermode=atomic", "./...")
	println(testOutput)
	if err != nil {
		println(err.Error())
	}

	println("End running testcases.")
}

func clean() {
	gopBinPath := detectGopBinPath()
	goBinPath := detectGoBinPath()

	// Clean links
	for _, file := range gopBinFiles {
		targetLink := filepath.Join(goBinPath, file)
		if checkPathExist(targetLink, false) {
			if err := os.Remove(targetLink); err != nil {
				log.Fatalln(err)
			}
		}
	}

	// Clean build binary files
	if checkPathExist(gopBinPath, true) {
		if err := os.RemoveAll(gopBinPath); err != nil {
			log.Fatalln(err)
		}
	}

	cleanGopRunCache()
}

func cleanGopRunCache() {
	homeDir, _ := os.UserHomeDir()
	runCacheDir := filepath.Join(homeDir, ".gop", "run")
	files := []string{"go.mod", "go.sum"}
	for _, file := range files {
		fullPath := filepath.Join(runCacheDir, file)
		if checkPathExist(fullPath, false) {
			if err := os.Remove(fullPath); err != nil {
				log.Fatalln(err)
			}
		}
	}
}

func uninstall() {
	println("Uninstalling Go+ and related tools.")
	clean()
	println("Go+ and related tools uninstalled successfully.")
}

func isInChina() bool {
	const prefix = "LANG=\""
	out, err := execCommand("locale")
	if err != nil {
		return false
	}
	if strings.HasPrefix(out, prefix) {
		out = out[len(prefix):]
		return strings.HasPrefix(out, "zh_CN") || strings.HasPrefix(out, "zh_HK")
	}
	return false
}

// findGopVersion returns current version of gop
func findGopVersion() string {
	versionFile := filepath.Join(gopRoot, "VERSION")
	// Read version from VERSION file
	data, err := os.ReadFile(versionFile)
	if err == nil {
		version := trimRight(string(data))
		return version
	}

	// Read version from git repo
	if !isGitRepo() {
		log.Fatal("Error: must be a git repo or a VERSION file existed.")
	}
	version := getBuildVer() // Closet tag on git log
	return version
}

// releaseNewVersion tags the repo with provided new tag, and writes new tag into VERSION file.
func releaseNewVersion(tag string) {
	if !isGitRepo() {
		log.Fatalln("Error: Releasing a new version could only be operated under a git repo.")
	}
	if getGitRemoteUrl("gop") != "" {
		log.Fatalln("Error: git remote gop not found, please use `git remote add gop git@github.com:goplus/gop.git`.")
	}
	if getTagRev(tag) != "" {
		log.Fatalln("Error: tag already exists -", tag)
	}

	version := tag
	re := regexp.MustCompile(`^v\d+?\.\d+?`)
	releaseBranch := re.FindString(version)
	if releaseBranch == "" {
		log.Fatal("Error: A valid version should be has form: vX.Y.Z")
	}

	sourceBranch := getGitBranch()

	// Checkout to release breanch
	if err := checkoutBranch(releaseBranch); err != nil {
		log.Fatalf("Error: checkout to release branch: %s failed with error: %v.", releaseBranch, err)
	}
	defer func() {
		// Checkout back to source branch
		if err := checkoutBranch(sourceBranch); err != nil {
			log.Fatalf("Error: checkout to source branch: %s failed with error: %v.", sourceBranch, err)
		}
	}()

	// Cache new version
	versionFile := filepath.Join(gopRoot, "VERSION")
	if err := os.WriteFile(versionFile, []byte(version), 0644); err != nil {
		log.Fatalf("Error: cache new version with error: %v\n", err)
	}

	// Commit changes
	if err := gitCommit("release version " + version); err != nil {
		log.Fatalf("Error: git commit with error: %v\n", err)
	}

	// Tag the source code
	if err := gitTagAndPushTo(tag, "gop"); err != nil {
		log.Fatalf("Error: gitTagAndPushTo with error: %v\n", err)
	}

	println("Released new version:", version)
}

func main() {
	isInstall := flag.Bool("install", false, "Install Go+")
	isTest := flag.Bool("test", false, "Run testcases")
	isUninstall := flag.Bool("uninstall", false, "Uninstall Go+")
	isGoProxy := flag.Bool("proxy", false, "Set GOPROXY for people in China")
	isAutoProxy := flag.Bool("autoproxy", false, "Check to set GOPROXY automatically")
	tag := flag.String("tag", "", "Release an new version with specified tag")

	flag.Parse()

	useGoProxy := *isGoProxy
	if !useGoProxy && *isAutoProxy {
		useGoProxy = isInChina()
	}
	flagActionMap := map[*bool]func(){
		isInstall:   func() { buildGoplusTools(useGoProxy) },
		isUninstall: uninstall,
		isTest:      runTestcases,
	}

	// Sort flags, for example: install flag should be checked earlier than test flag.
	flags := []*bool{isInstall, isTest, isUninstall}
	hasActionDone := false

	if *tag != "" {
		releaseNewVersion(*tag)
		hasActionDone = true
	}

	for _, flag := range flags {
		if *flag {
			flagActionMap[flag]()
			hasActionDone = true
		}
	}

	if !hasActionDone {
		println("Usage:\n")
		flag.PrintDefaults()
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"strings"
	"time"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/iam"
	"github.com/aws/aws-sdk-go/service/sts"
	"github.com/rebuy-de/aws-nuke/resources"
)

type Nuke struct {
	Parameters NukeParameters
	Config     *NukeConfig

	accountConfig NukeConfigAccount
	accountID     string
	accountAlias  string
	sessions      map[string]*session.Session

	ForceSleep time.Duration

	items Queue
}

func NewNuke(params NukeParameters) *Nuke {
	n := Nuke{
		Parameters: params,
		ForceSleep: 15 * time.Second,
	}

	return &n
}

func (n *Nuke) StartSession() error {
	n.sessions = make(map[string]*session.Session)
	for _, region := range n.Config.Regions {
		fmt.Printf("Create session for region %s \n", region)
		if n.Parameters.hasProfile() {
			n.sessions[region] = session.Must(session.NewSessionWithOptions(session.Options{
			     Config: aws.Config{Region: aws.String(region)},
			     Profile: n.Parameters.Profile,
			}))

			if n.sessions[region] == nil {
				return fmt.Errorf("Unable to create session with profile '%s'.", n.Parameters.Profile)
			}
		}

		if n.Parameters.hasKeys() {
			n.sessions[region] = session.New(&aws.Config{
				Region: &region,
				Credentials: credentials.NewStaticCredentials(
					n.Parameters.AccessKeyID,
					n.Parameters.SecretAccessKey,
					"",
				),
			})

			if n.sessions[region] == nil {
				return fmt.Errorf("Unable to create session with key ID '%s'.", n.Parameters.AccessKeyID)
			}

		}

		fmt.Printf("Create key: %s session for region %s \n", region, *n.sessions[region].Config.Region)
	}

	if len(n.sessions) != 2 {
		return fmt.Errorf("You have to specify a profile or credentials for at least one region.")
	}
	return nil
}

func (n *Nuke) Run() error {
	var err error

	fmt.Printf("aws-nuke version %s - %s - %s\n\n", BuildVersion, BuildDate, BuildHash)

	err = n.ValidateAccount()
	if err != nil {
		return err
	}

	fmt.Printf("Do you really want to nuke the account with "+
		"the ID %s and the alias '%s'?\n", n.accountID, n.accountAlias)
	if n.Parameters.Force {
		fmt.Printf("Waiting %v before continuing.\n", n.ForceSleep)
		time.Sleep(n.ForceSleep)
	} else {
		fmt.Printf("Do you want to continue? Enter account alias to continue.\n")
		err = Prompt(n.accountAlias)
		if err != nil {
			return err
		}
	}

	err = n.Scan()
	if err != nil {
		return err
	}

	if n.items.Count(ItemStateNew) == 0 {
		fmt.Println("No resource to delete.")
		return nil
	}

	if !n.Parameters.NoDryRun {
		fmt.Println("Would delete these resources. Provide --no-dry-run to actually destroy resources.")
		return nil
	}

	fmt.Printf("Do you really want to nuke these resources on the account with "+
		"the ID %s and the alias '%s'?\n", n.accountID, n.accountAlias)
	if n.Parameters.Force {
		fmt.Printf("Waiting %v before continuing.\n", n.ForceSleep)
		time.Sleep(n.ForceSleep)
	} else {
		fmt.Printf("Do you want to continue? Enter account alias to continue.\n")
		err = Prompt(n.accountAlias)
		if err != nil {
			return err
		}
	}

	failCount := 0

	for {
		n.HandleQueue()

		if n.items.Count(ItemStatePending, ItemStateWaiting, ItemStateNew) == 0 && n.items.Count(ItemStateFailed) > 0 {
			if failCount >= 2 {
				return fmt.Errorf("There are resources in failed state, but none are ready for deletion, anymore.")
			}
			failCount = failCount + 1
		} else {
			failCount = 0
		}
		if n.items.Count(ItemStateNew, ItemStatePending, ItemStateFailed, ItemStateWaiting) == 0 {
			break
		}

		time.Sleep(5 * time.Second)
	}

	fmt.Printf("Nuke complete: %d failed, %d skipped, %d finished.\n\n",
		n.items.Count(ItemStateFailed), n.items.Count(ItemStateFiltered), n.items.Count(ItemStateFinished))

	return nil
}

func (n *Nuke) ValidateAccount() error {
	sess := n.sessions[n.Config.Regions[0]]
	identOutput, err := sts.New(sess).GetCallerIdentity(nil)
	if err != nil {
		return err
	}

	aliasesOutput, err := iam.New(sess).ListAccountAliases(nil)
	if err != nil {
		return err
	}

	accountID := *identOutput.Account
	aliases := aliasesOutput.AccountAliases

	if !n.Config.HasBlacklist() {
		return fmt.Errorf("The config file contains an empty blacklist. " +
			"For safety reasons you need to specify at least one account ID. " +
			"This should be you production account.")
	}

	if n.Config.InBlacklist(accountID) {
		return fmt.Errorf("You are trying to nuke the account with the ID %s, "+
			"but it is blacklisted. Aborting.", accountID)
	}

	if len(aliases) == 0 {
		return fmt.Errorf("The specified account doesn't have an alias. " +
			"For safety reasons you need to specify an account alias. " +
			"Your production account should contain the term 'prod'.")
	}

	for _, alias := range aliases {
		if strings.Contains(strings.ToLower(*alias), "prod") {
			return fmt.Errorf("You are trying to nuke a account with the alias '%s', "+
				"but it has the substring 'prod' in it. Aborting.", *aliases[0])
		}
	}

	if _, ok := n.Config.Accounts[accountID]; !ok {
		return fmt.Errorf("Your account ID '%s' isn't listed in the config. "+
			"Aborting.", accountID)
	}

	n.accountConfig = n.Config.Accounts[accountID]
	n.accountID = accountID
	n.accountAlias = *aliases[0]

	return nil
}

func (n *Nuke) Scan() error {
	queue := make(Queue, 0)

	for _, region := range n.Config.Regions {
		sess := n.sessions[region]
		fmt.Printf("Key: %s Scan region %s \n", region, *sess.Config.Region)
		scanner := Scan(sess)
		for item := range scanner.Items {
			if !n.Parameters.WantsTarget(item.Service) {
				continue
			}

			queue = append(queue, item)
			n.Filter(item)
			item.Print()
		}
		if scanner.Error != nil {
			fmt.Printf("Scaner found an error %s \n", scanner.Error)
			return scanner.Error
		}

	}
	fmt.Printf("Scan complete: %d total, %d nukeable, %d filtered.\n\n",
		queue.CountTotal(), queue.Count(ItemStateNew), queue.Count(ItemStateFiltered))

	n.items = queue

	return nil
}

func (n *Nuke) Filter(item *Item) {
	checker, ok := item.Resource.(resources.Filter)
	if ok {
		err := checker.Filter()
		if err != nil {
			item.State = ItemStateFiltered
			item.Reason = err.Error()
			return
		}
	}

	filters, ok := n.accountConfig.Filters[item.Service]
	if !ok {
		return
	}

	for _, filter := range filters {
		if filter == item.Resource.String() {
			item.State = ItemStateFiltered
			item.Reason = "filtered by config"
			return
		}
	}

	return
}

func (n *Nuke) HandleQueue() {
	listCache := make(map[string][]resources.Resource)

	for _, item := range n.items {
		switch item.State {
		case ItemStateNew:
			n.HandleRemove(item)
			item.Print()
		case ItemStateFailed:
			n.HandleRemove(item)
			n.HandleWait(item, listCache)
			item.Print()
		case ItemStatePending:
			n.HandleWait(item, listCache)
			item.State = ItemStateWaiting
			item.Print()
		case ItemStateWaiting:
			n.HandleWait(item, listCache)
			item.Print()
		}

	}

	fmt.Println()
	fmt.Printf("Removal requested: %d waiting, %d failed, %d skipped, %d finished\n\n",
		n.items.Count(ItemStateWaiting, ItemStatePending), n.items.Count(ItemStateFailed),
		n.items.Count(ItemStateFiltered), n.items.Count(ItemStateFinished))
}

func (n *Nuke) HandleRemove(item *Item) {
	err := item.Resource.Remove()
	if err != nil {
		item.State = ItemStateFailed
		item.Reason = err.Error()
		return
	}

	item.State = ItemStatePending
	item.Reason = ""
}

func (n *Nuke) HandleWait(item *Item, cache map[string][]resources.Resource) {
	var err error

	left, ok := cache[item.Service]
	if !ok {
		left, err = item.Lister()
		if err != nil {
			item.State = ItemStateFailed
			item.Reason = err.Error()
			return
		}
		cache[item.Service] = left
	}

	for _, r := range left {
		if r.String() == item.Resource.String() {
			checker, ok := r.(resources.Filter)
			if ok {
				err := checker.Filter()
				if err != nil {
					break
				}
			}

			return
		}
	}

	item.State = ItemStateFinished
	item.Reason = ""
}
<commit_msg>CLOUD-1047: Extend use of new AWS session handling.<commit_after>package cmd

import (
	"fmt"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/iam"
	"github.com/aws/aws-sdk-go/service/sts"
	"github.com/rebuy-de/aws-nuke/resources"
)

type Nuke struct {
	Parameters NukeParameters
	Config     *NukeConfig

	accountConfig NukeConfigAccount
	accountID     string
	accountAlias  string
	sessions      map[string]*session.Session

	ForceSleep time.Duration

	items Queue
}

func NewNuke(params NukeParameters) *Nuke {
	n := Nuke{
		Parameters: params,
		ForceSleep: 15 * time.Second,
	}

	return &n
}

func (n *Nuke) StartSession() error {
	n.sessions = make(map[string]*session.Session)
	for _, region := range n.Config.Regions {
		fmt.Printf("Create session for region %s \n", region)
		if n.Parameters.hasProfile() {
			n.sessions[region] = session.Must(session.NewSessionWithOptions(session.Options{
				Config:  aws.Config{Region: aws.String(region)},
				Profile: n.Parameters.Profile,
			}))

			if n.sessions[region] == nil {
				return fmt.Errorf("Unable to create session with profile '%s'.", n.Parameters.Profile)
			}
		}

		if n.Parameters.hasKeys() {
			n.sessions[region] = session.Must(session.NewSessionWithOptions(session.Options{
				Config: aws.Config{
					Region: aws.String(region),
					Credentials: credentials.NewStaticCredentials(
						n.Parameters.AccessKeyID,
						n.Parameters.SecretAccessKey,
						"",
					)}}))

			if n.sessions[region] == nil {
				return fmt.Errorf("Unable to create session with key ID '%s'.", n.Parameters.AccessKeyID)
			}

		}

		fmt.Printf("Create key: %s session for region %s \n", region, *n.sessions[region].Config.Region)
	}

	if len(n.sessions) != 2 {
		return fmt.Errorf("You have to specify a profile or credentials for at least one region.")
	}
	return nil
}

func (n *Nuke) Run() error {
	var err error

	fmt.Printf("aws-nuke version %s - %s - %s\n\n", BuildVersion, BuildDate, BuildHash)

	err = n.ValidateAccount()
	if err != nil {
		return err
	}

	fmt.Printf("Do you really want to nuke the account with "+
		"the ID %s and the alias '%s'?\n", n.accountID, n.accountAlias)
	if n.Parameters.Force {
		fmt.Printf("Waiting %v before continuing.\n", n.ForceSleep)
		time.Sleep(n.ForceSleep)
	} else {
		fmt.Printf("Do you want to continue? Enter account alias to continue.\n")
		err = Prompt(n.accountAlias)
		if err != nil {
			return err
		}
	}

	err = n.Scan()
	if err != nil {
		return err
	}

	if n.items.Count(ItemStateNew) == 0 {
		fmt.Println("No resource to delete.")
		return nil
	}

	if !n.Parameters.NoDryRun {
		fmt.Println("Would delete these resources. Provide --no-dry-run to actually destroy resources.")
		return nil
	}

	fmt.Printf("Do you really want to nuke these resources on the account with "+
		"the ID %s and the alias '%s'?\n", n.accountID, n.accountAlias)
	if n.Parameters.Force {
		fmt.Printf("Waiting %v before continuing.\n", n.ForceSleep)
		time.Sleep(n.ForceSleep)
	} else {
		fmt.Printf("Do you want to continue? Enter account alias to continue.\n")
		err = Prompt(n.accountAlias)
		if err != nil {
			return err
		}
	}

	failCount := 0

	for {
		n.HandleQueue()

		if n.items.Count(ItemStatePending, ItemStateWaiting, ItemStateNew) == 0 && n.items.Count(ItemStateFailed) > 0 {
			if failCount >= 2 {
				return fmt.Errorf("There are resources in failed state, but none are ready for deletion, anymore.")
			}
			failCount = failCount + 1
		} else {
			failCount = 0
		}
		if n.items.Count(ItemStateNew, ItemStatePending, ItemStateFailed, ItemStateWaiting) == 0 {
			break
		}

		time.Sleep(5 * time.Second)
	}

	fmt.Printf("Nuke complete: %d failed, %d skipped, %d finished.\n\n",
		n.items.Count(ItemStateFailed), n.items.Count(ItemStateFiltered), n.items.Count(ItemStateFinished))

	return nil
}

func (n *Nuke) ValidateAccount() error {
	sess := n.sessions[n.Config.Regions[0]]
	identOutput, err := sts.New(sess).GetCallerIdentity(nil)
	if err != nil {
		return err
	}

	aliasesOutput, err := iam.New(sess).ListAccountAliases(nil)
	if err != nil {
		return err
	}

	accountID := *identOutput.Account
	aliases := aliasesOutput.AccountAliases

	if !n.Config.HasBlacklist() {
		return fmt.Errorf("The config file contains an empty blacklist. " +
			"For safety reasons you need to specify at least one account ID. " +
			"This should be you production account.")
	}

	if n.Config.InBlacklist(accountID) {
		return fmt.Errorf("You are trying to nuke the account with the ID %s, "+
			"but it is blacklisted. Aborting.", accountID)
	}

	if len(aliases) == 0 {
		return fmt.Errorf("The specified account doesn't have an alias. " +
			"For safety reasons you need to specify an account alias. " +
			"Your production account should contain the term 'prod'.")
	}

	for _, alias := range aliases {
		if strings.Contains(strings.ToLower(*alias), "prod") {
			return fmt.Errorf("You are trying to nuke a account with the alias '%s', "+
				"but it has the substring 'prod' in it. Aborting.", *aliases[0])
		}
	}

	if _, ok := n.Config.Accounts[accountID]; !ok {
		return fmt.Errorf("Your account ID '%s' isn't listed in the config. "+
			"Aborting.", accountID)
	}

	n.accountConfig = n.Config.Accounts[accountID]
	n.accountID = accountID
	n.accountAlias = *aliases[0]

	return nil
}

func (n *Nuke) Scan() error {
	queue := make(Queue, 0)

	for _, region := range n.Config.Regions {
		sess := n.sessions[region]
		fmt.Printf("Key: %s Scan region %s \n", region, *sess.Config.Region)
		scanner := Scan(sess)
		for item := range scanner.Items {
			if !n.Parameters.WantsTarget(item.Service) {
				continue
			}

			queue = append(queue, item)
			n.Filter(item)
			item.Print()
		}
		if scanner.Error != nil {
			fmt.Printf("Scaner found an error %s \n", scanner.Error)
			return scanner.Error
		}

	}
	fmt.Printf("Scan complete: %d total, %d nukeable, %d filtered.\n\n",
		queue.CountTotal(), queue.Count(ItemStateNew), queue.Count(ItemStateFiltered))

	n.items = queue

	return nil
}

func (n *Nuke) Filter(item *Item) {
	checker, ok := item.Resource.(resources.Filter)
	if ok {
		err := checker.Filter()
		if err != nil {
			item.State = ItemStateFiltered
			item.Reason = err.Error()
			return
		}
	}

	filters, ok := n.accountConfig.Filters[item.Service]
	if !ok {
		return
	}

	for _, filter := range filters {
		if filter == item.Resource.String() {
			item.State = ItemStateFiltered
			item.Reason = "filtered by config"
			return
		}
	}

	return
}

func (n *Nuke) HandleQueue() {
	listCache := make(map[string][]resources.Resource)

	for _, item := range n.items {
		switch item.State {
		case ItemStateNew:
			n.HandleRemove(item)
			item.Print()
		case ItemStateFailed:
			n.HandleRemove(item)
			n.HandleWait(item, listCache)
			item.Print()
		case ItemStatePending:
			n.HandleWait(item, listCache)
			item.State = ItemStateWaiting
			item.Print()
		case ItemStateWaiting:
			n.HandleWait(item, listCache)
			item.Print()
		}

	}

	fmt.Println()
	fmt.Printf("Removal requested: %d waiting, %d failed, %d skipped, %d finished\n\n",
		n.items.Count(ItemStateWaiting, ItemStatePending), n.items.Count(ItemStateFailed),
		n.items.Count(ItemStateFiltered), n.items.Count(ItemStateFinished))
}

func (n *Nuke) HandleRemove(item *Item) {
	err := item.Resource.Remove()
	if err != nil {
		item.State = ItemStateFailed
		item.Reason = err.Error()
		return
	}

	item.State = ItemStatePending
	item.Reason = ""
}

func (n *Nuke) HandleWait(item *Item, cache map[string][]resources.Resource) {
	var err error

	left, ok := cache[item.Service]
	if !ok {
		left, err = item.Lister()
		if err != nil {
			item.State = ItemStateFailed
			item.Reason = err.Error()
			return
		}
		cache[item.Service] = left
	}

	for _, r := range left {
		if r.String() == item.Resource.String() {
			checker, ok := r.(resources.Filter)
			if ok {
				err := checker.Filter()
				if err != nil {
					break
				}
			}

			return
		}
	}

	item.State = ItemStateFinished
	item.Reason = ""
}
<|endoftext|>


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

package cmd

import (
	"fmt"
	"os"

	"github.com/zerobotlabs/nestor-cli/Godeps/_workspace/src/github.com/spf13/cobra"
	"github.com/zerobotlabs/nestor-cli/Godeps/_workspace/src/github.com/spf13/viper"
)

var cfgFile string

// This represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "nestor-cli",
	Short: "A brief description of your application",
	Long: `A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
	// Uncomment the following line if your bare application
	// has an action associated with it:
	//	Run: func(cmd *cobra.Command, args []string) { },
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	// Here you will define your flags and configuration settings.
	// Cobra supports Persistent Flags, which, if defined here,
	// will be global for your application.

	RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.nestor-cli.yaml)")
	// Cobra also supports local flags, which will only run
	// when this action is called directly.
	RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(cfgFile)
	}

	viper.SetConfigName(".nestor-cli") // name of config file (without extension)
	viper.AddConfigPath("$HOME")       // adding home directory as first search path
	viper.AutomaticEnv()               // read in environment variables that match

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}
}
<commit_msg>Edit short and long description<commit_after>// Copyright © 2016 NAME HERE <EMAIL ADDRESS>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"fmt"
	"os"

	"github.com/zerobotlabs/nestor-cli/Godeps/_workspace/src/github.com/spf13/cobra"
	"github.com/zerobotlabs/nestor-cli/Godeps/_workspace/src/github.com/spf13/viper"
)

var cfgFile string

// This represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "nestor",
	Short: "nestor lets you Create, Debug and Deploy Bot Apps at https://www.asknestor.me",
	Long:  "nestor lets you Create, Debug and Deploy Bot Apps at https://www.asknestor.me",
	// Uncomment the following line if your bare application
	// has an action associated with it:
	//	Run: func(cmd *cobra.Command, args []string) { },
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	// Here you will define your flags and configuration settings.
	// Cobra supports Persistent Flags, which, if defined here,
	// will be global for your application.

	RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.nestor-cli.yaml)")
	// Cobra also supports local flags, which will only run
	// when this action is called directly.
	RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(cfgFile)
	}

	viper.SetConfigName(".nestor-cli") // name of config file (without extension)
	viper.AddConfigPath("$HOME")       // adding home directory as first search path
	viper.AutomaticEnv()               // read in environment variables that match

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}
}
<|endoftext|>


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

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
	"log"
	"os"
	"strings"
	"time"

	composeAPI "github.com/compose/gocomposeapi"
)

func getComposeAPI() (client *composeAPI.Client) {
	if apiToken == "Your API Token" {
		ostoken := os.Getenv("COMPOSEAPITOKEN")
		if ostoken == "" {
			log.Fatal("Token not set and COMPOSEAPITOKEN environment variable not set")
		}
		apiToken = ostoken
	}

	var err error
	client, err = composeAPI.NewClient(apiToken)
	if err != nil {
		log.Fatalf("Could not create compose client: %s", err.Error())
	}
	return client
}

func resolveDepID(client *composeAPI.Client, arg string) (depid string, err error) {
	// Test for being just deployment id
	if len(arg) == 24 && isHexString(arg) {
		return arg, nil
	}

	// Get all the deployments and search
	deployments, errs := client.GetDeployments()

	if errs != nil {
		bailOnErrs(errs)
		return "", errs[0]
	}

	for _, deployment := range *deployments {
		if deployment.Name == arg {
			return deployment.ID, nil
		}
	}

	return "", fmt.Errorf("deployment not found: %s", arg)
}

func isHexString(s string) bool {
	_, err := hex.DecodeString(s)
	if err == nil {
		return true
	}
	return false
}

func watchRecipeTillComplete(client *composeAPI.Client, recipeid string) {
	var lastRecipe *composeAPI.Recipe

	for {
		time.Sleep(time.Duration(5) * time.Second)
		recipe, errs := client.GetRecipe(recipeid)
		bailOnErrs(errs)

		if lastRecipe == nil {
			lastRecipe = recipe
			if !recipewait {
				fmt.Println()
				printShortRecipe(*recipe)
			}
		} else {
			if lastRecipe.Status == recipe.Status &&
				lastRecipe.UpdatedAt == recipe.UpdatedAt &&
				lastRecipe.StatusDetail == recipe.StatusDetail {
				if !recipewait {
					fmt.Print(".")
				}
			} else {
				lastRecipe = recipe
				if !recipewait {
					fmt.Println()
					printShortRecipe(*recipe)
				}
			}
		}

		if recipe.Status == "complete" || recipe.Status == "failed" {
			return
		}
	}
}

func bailOnErrs(errs []error) {
	if errs != nil {
		log.Fatal(errs)
	}
}

func printAsJSON(toprint interface{}) {
	jsonstr, _ := json.MarshalIndent(toprint, "", " ")
	fmt.Println(string(jsonstr))
}

func getLink(link composeAPI.Link) string {
	return strings.Replace(link.HREF, "{?embed}", "", -1) // TODO: This should mangle the HREF properly
}

var savedVersion string

//SaveVersion called from outside to retain version string
func SaveVersion(version string) {
	savedVersion = version
}

func getVersion() string {
	return savedVersion
}
<commit_msg>Format fix for package<commit_after>// Copyright © 2017 Compose, an IBM Company
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
	"log"
	"os"
	"strings"
	"time"

	composeAPI "github.com/compose/gocomposeapi"
)

func getComposeAPI() (client *composeAPI.Client) {
	if apiToken == "Your API Token" {
		ostoken := os.Getenv("COMPOSEAPITOKEN")
		if ostoken == "" {
			log.Fatal("Token not set and COMPOSEAPITOKEN environment variable not set")
		}
		apiToken = ostoken
	}

	var err error
	client, err = composeAPI.NewClient(apiToken)
	if err != nil {
		log.Fatalf("Could not create compose client: %s", err.Error())
	}
	return client
}

func resolveDepID(client *composeAPI.Client, arg string) (depid string, err error) {
	// Test for being just deployment id
	if len(arg) == 24 && isHexString(arg) {
		return arg, nil
	}

	// Get all the deployments and search
	deployments, errs := client.GetDeployments()

	if errs != nil {
		bailOnErrs(errs)
		return "", errs[0]
	}

	for _, deployment := range *deployments {
		if deployment.Name == arg {
			return deployment.ID, nil
		}
	}

	return "", fmt.Errorf("deployment not found: %s", arg)
}

func isHexString(s string) bool {
	_, err := hex.DecodeString(s)
	if err == nil {
		return true
	}
	return false
}

func watchRecipeTillComplete(client *composeAPI.Client, recipeid string) {
	var lastRecipe *composeAPI.Recipe

	for {
		time.Sleep(time.Duration(5) * time.Second)
		recipe, errs := client.GetRecipe(recipeid)
		bailOnErrs(errs)

		if lastRecipe == nil {
			lastRecipe = recipe
			if !recipewait {
				fmt.Println()
				printShortRecipe(*recipe)
			}
		} else {
			if lastRecipe.Status == recipe.Status &&
				lastRecipe.UpdatedAt == recipe.UpdatedAt &&
				lastRecipe.StatusDetail == recipe.StatusDetail {
				if !recipewait {
					fmt.Print(".")
				}
			} else {
				lastRecipe = recipe
				if !recipewait {
					fmt.Println()
					printShortRecipe(*recipe)
				}
			}
		}

		if recipe.Status == "complete" || recipe.Status == "failed" {
			return
		}
	}
}

func bailOnErrs(errs []error) {
	if errs != nil {
		log.Fatal(errs)
	}
}

func printAsJSON(toprint interface{}) {
	jsonstr, _ := json.MarshalIndent(toprint, "", " ")
	fmt.Println(string(jsonstr))
}

func getLink(link composeAPI.Link) string {
	return strings.Replace(link.HREF, "{?embed}", "", -1) // TODO: This should mangle the HREF properly
}

var savedVersion string

//SaveVersion called from outside to retain version string
func SaveVersion(version string) {
	savedVersion = version
}

func getVersion() string {
	return savedVersion
}
<|endoftext|>


<commit_before>package main

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

	"github.com/gonuts/commander"
	"github.com/gonuts/flag"
)

func hwaf_make_cmd_init() *commander.Command {
	cmd := &commander.Command{
		Run:       hwaf_run_cmd_init,
		UsageLine: "init [options] <workarea>",
		Short:     "initialize a new workarea",
		Long: `
init initializes a new workarea.

ex:
 $ hwaf init
 $ hwaf init .
 $ hwaf init my-work-area
`,
		Flag: *flag.NewFlagSet("hwaf-init", flag.ExitOnError),
	}
	cmd.Flag.Bool("q", true, "only print error and warning messages, all other output will be suppressed")
	cmd.Flag.String("name", "", "workarea/project name (default: directory-name)")
	return cmd
}

func hwaf_run_cmd_init(cmd *commander.Command, args []string) {
	var err error
	n := "hwaf-" + cmd.Name()
	dirname := ""

	switch len(args) {
	case 0:
		dirname = "."
	case 1:
		dirname = args[0]
	default:
		err = fmt.Errorf("%s: you need to give a directory name", n)
		handle_err(err)
	}

	dirname = os.ExpandEnv(dirname)
	dirname = filepath.Clean(dirname)

	quiet := cmd.Flag.Lookup("q").Value.Get().(bool)
	proj_name := cmd.Flag.Lookup("name").Value.Get().(string)
	if proj_name == "" {
		proj_name = filepath.Base(dirname)
	}
	if proj_name == "." {
		pwd, err := os.Getwd()
		handle_err(err)
		proj_name = filepath.Base(pwd)
	}

	if !quiet {
		fmt.Printf("%s: creating workarea [%s]...\n", n, dirname)
	}

	if !path_exists(dirname) {
		err = os.MkdirAll(dirname, 0700)
		handle_err(err)
	}

	pwd, err := os.Getwd()
	handle_err(err)
	defer os.Chdir(pwd)

	err = os.Chdir(dirname)
	handle_err(err)

	// init a git repository in dirname
	if !quiet {
		fmt.Printf("%s: initialize git workarea repository...\n", n)
	}
	git := exec.Command("git", "init", ".")
	if !quiet {
		git.Stdout = os.Stdout
		git.Stderr = os.Stderr
	}
	err = git.Run()
	handle_err(err)

	// add hep-waf-tools
	if !quiet {
		fmt.Printf("%s: add .hwaf/tools...\n", n)
	}
	hwaf_tools_dir := ""
	if g_ctx.Root != "" {
		hwaf_tools_dir = filepath.Join(g_ctx.Root, "share", "hwaf", "tools")
	} else {
		hwaf_tools_dir = filepath.Join("${HOME}", ".config", "hwaf", "tools")
	}
	hwaf_tools_dir = os.ExpandEnv(hwaf_tools_dir)
	if !path_exists(hwaf_tools_dir) {
		// first try the r/w url...
		git = exec.Command(
			"git", "clone", "git@github.com:mana-fwk/hep-waftools",
			hwaf_tools_dir,
		)
		if !quiet {
			git.Stdout = os.Stdout
			git.Stderr = os.Stderr
		}

		if git.Run() != nil {
			git := exec.Command(
				"git", "clone", "git://github.com/mana-fwk/hep-waftools",
				hwaf_tools_dir,
			)
			if !quiet {
				git.Stdout = os.Stdout
				git.Stderr = os.Stderr
			}
			err = git.Run()
			handle_err(err)
		}
	}
	if !path_exists(".hwaf") {
		err = os.MkdirAll(".hwaf", 0700)
		handle_err(err)
	}
	if path_exists(".hwaf/tools") {
		err = os.RemoveAll(".hwaf/tools")
		handle_err(err)
	}
	err = os.Symlink(hwaf_tools_dir, ".hwaf/tools")
	handle_err(err)

	git = exec.Command("git", "add", ".hwaf/tools")
	if !quiet {
		git.Stdout = os.Stdout
		git.Stderr = os.Stderr
	}
	err = git.Run()
	handle_err(err)

	// add waf-bin
	{
		if !quiet {
			fmt.Printf("%s: add .hwaf/bin...\n", n)
		}
		hwaf_bin_dir := ""
		if g_ctx.Root != "" {
			hwaf_bin_dir = filepath.Join(g_ctx.Root, "bin")
		} else {
			hwaf_bin_dir = filepath.Join("${HOME}", ".config", "hwaf", "bin")
		}
		hwaf_bin_dir = os.ExpandEnv(hwaf_bin_dir)
		if !path_exists(hwaf_bin_dir) {
			err = fmt.Errorf("no such hwaf-bin dir [%s]", hwaf_bin_dir)
			handle_err(err)
		}
		src_waf, err := os.Open(filepath.Join(hwaf_bin_dir, "waf"))
		handle_err(err)
		defer src_waf.Close()

		if !path_exists(".hwaf/bin") {
			err = os.MkdirAll(".hwaf/bin", 0700)
			handle_err(err)
		}

		waf_bin, err := os.Create(filepath.Join(".hwaf", "bin", "waf"))
		handle_err(err)
		defer waf_bin.Close()

		err = waf_bin.Chmod(0755)
		handle_err(err)

		_, err = io.Copy(waf_bin, src_waf)
		handle_err(err)

		err = waf_bin.Sync()
		handle_err(err)
	}

	// add pkgdb
	err = ioutil.WriteFile(
		filepath.Join(".hwaf", "pkgdb.json"),
		[]byte("{}\n"),
		0755,
	)
	handle_err(err)
	git = exec.Command("git", "add", filepath.Join(".hwaf", "pkgdb.json"))
	if !quiet {
		git.Stdout = os.Stdout
		git.Stderr = os.Stderr
	}
	err = git.Run()
	handle_err(err)

	// add template wscript
	if !quiet {
		fmt.Printf("%s: add top-level wscript...\n", n)
	}

	if !path_exists("wscript") {
		wscript_tmpl, err := os.Open(".hwaf/tools/hwaf-wscript")
		handle_err(err)
		defer wscript_tmpl.Close()

		wscript_b, err := ioutil.ReadAll(wscript_tmpl)
		handle_err(err)

		// replace 'hwaf-workarea' with workarea name
		wscript_s := strings.Replace(
			string(wscript_b),
			"APPNAME = 'hwaf-workarea'",
			fmt.Sprintf("APPNAME = '%s'", proj_name),
			-1)

		wscript, err := os.Create("wscript")
		handle_err(err)
		defer wscript.Close()

		_, err = io.WriteString(wscript, wscript_s)
		handle_err(err)
		handle_err(wscript.Sync())
		handle_err(wscript.Close())
	}

	git = exec.Command("git", "add", "wscript")
	if !quiet {
		git.Stdout = os.Stdout
		git.Stderr = os.Stderr
	}
	err = git.Run()
	handle_err(err)

	// create 'src' directory
	if !path_exists("src") {
		err = os.MkdirAll("src", 0700)
		handle_err(err)
	}

	// add a default .gitignore
	gitignore_tmpl, err := os.Open(".hwaf/tools/.gitignore")
	handle_err(err)
	defer gitignore_tmpl.Close()

	gitignore, err := os.Create(".gitignore")
	handle_err(err)
	defer gitignore.Close()

	_, err = io.Copy(gitignore, gitignore_tmpl)
	handle_err(err)
	handle_err(gitignore.Sync())
	handle_err(gitignore.Close())

	git = exec.Command("git", "add", ".gitignore")
	if !quiet {
		git.Stdout = os.Stdout
		git.Stderr = os.Stderr
	}
	err = git.Run()
	handle_err(err)

	// check whether we need to commit
	err = exec.Command("git", "diff", "--exit-code", "--quiet", "HEAD").Run()
	if err != nil {
		// commit
		if !quiet {
			fmt.Printf("%s: commit workarea...\n", n)
		}
		git = exec.Command(
			"git", "commit", "-m",
			fmt.Sprintf("init hwaf project [%s]", proj_name),
		)
		if !quiet {
			git.Stdout = os.Stdout
			git.Stderr = os.Stderr
		}
		err = git.Run()
		handle_err(err)
	}

	if !quiet {
		fmt.Printf("%s: creating workarea [%s]... [ok]\n", n, dirname)
	}
}

// EOF
<commit_msg>init: git add -f b/c of new entries in gitignore<commit_after>package main

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

	"github.com/gonuts/commander"
	"github.com/gonuts/flag"
)

func hwaf_make_cmd_init() *commander.Command {
	cmd := &commander.Command{
		Run:       hwaf_run_cmd_init,
		UsageLine: "init [options] <workarea>",
		Short:     "initialize a new workarea",
		Long: `
init initializes a new workarea.

ex:
 $ hwaf init
 $ hwaf init .
 $ hwaf init my-work-area
`,
		Flag: *flag.NewFlagSet("hwaf-init", flag.ExitOnError),
	}
	cmd.Flag.Bool("q", true, "only print error and warning messages, all other output will be suppressed")
	cmd.Flag.String("name", "", "workarea/project name (default: directory-name)")
	return cmd
}

func hwaf_run_cmd_init(cmd *commander.Command, args []string) {
	var err error
	n := "hwaf-" + cmd.Name()
	dirname := ""

	switch len(args) {
	case 0:
		dirname = "."
	case 1:
		dirname = args[0]
	default:
		err = fmt.Errorf("%s: you need to give a directory name", n)
		handle_err(err)
	}

	dirname = os.ExpandEnv(dirname)
	dirname = filepath.Clean(dirname)

	quiet := cmd.Flag.Lookup("q").Value.Get().(bool)
	proj_name := cmd.Flag.Lookup("name").Value.Get().(string)
	if proj_name == "" {
		proj_name = filepath.Base(dirname)
	}
	if proj_name == "." {
		pwd, err := os.Getwd()
		handle_err(err)
		proj_name = filepath.Base(pwd)
	}

	if !quiet {
		fmt.Printf("%s: creating workarea [%s]...\n", n, dirname)
	}

	if !path_exists(dirname) {
		err = os.MkdirAll(dirname, 0700)
		handle_err(err)
	}

	pwd, err := os.Getwd()
	handle_err(err)
	defer os.Chdir(pwd)

	err = os.Chdir(dirname)
	handle_err(err)

	// init a git repository in dirname
	if !quiet {
		fmt.Printf("%s: initialize git workarea repository...\n", n)
	}
	git := exec.Command("git", "init", ".")
	if !quiet {
		git.Stdout = os.Stdout
		git.Stderr = os.Stderr
	}
	err = git.Run()
	handle_err(err)

	// add hep-waf-tools
	if !quiet {
		fmt.Printf("%s: add .hwaf/tools...\n", n)
	}
	hwaf_tools_dir := ""
	if g_ctx.Root != "" {
		hwaf_tools_dir = filepath.Join(g_ctx.Root, "share", "hwaf", "tools")
	} else {
		hwaf_tools_dir = filepath.Join("${HOME}", ".config", "hwaf", "tools")
	}
	hwaf_tools_dir = os.ExpandEnv(hwaf_tools_dir)
	if !path_exists(hwaf_tools_dir) {
		// first try the r/w url...
		git = exec.Command(
			"git", "clone", "git@github.com:mana-fwk/hep-waftools",
			hwaf_tools_dir,
		)
		if !quiet {
			git.Stdout = os.Stdout
			git.Stderr = os.Stderr
		}

		if git.Run() != nil {
			git := exec.Command(
				"git", "clone", "git://github.com/mana-fwk/hep-waftools",
				hwaf_tools_dir,
			)
			if !quiet {
				git.Stdout = os.Stdout
				git.Stderr = os.Stderr
			}
			err = git.Run()
			handle_err(err)
		}
	}
	if !path_exists(".hwaf") {
		err = os.MkdirAll(".hwaf", 0700)
		handle_err(err)
	}
	if path_exists(".hwaf/tools") {
		err = os.RemoveAll(".hwaf/tools")
		handle_err(err)
	}
	err = os.Symlink(hwaf_tools_dir, ".hwaf/tools")
	handle_err(err)

	git = exec.Command("git", "add", "-f", ".hwaf/tools")
	if !quiet {
		git.Stdout = os.Stdout
		git.Stderr = os.Stderr
	}
	err = git.Run()
	handle_err(err)

	// add waf-bin
	{
		if !quiet {
			fmt.Printf("%s: add .hwaf/bin...\n", n)
		}
		hwaf_bin_dir := ""
		if g_ctx.Root != "" {
			hwaf_bin_dir = filepath.Join(g_ctx.Root, "bin")
		} else {
			hwaf_bin_dir = filepath.Join("${HOME}", ".config", "hwaf", "bin")
		}
		hwaf_bin_dir = os.ExpandEnv(hwaf_bin_dir)
		if !path_exists(hwaf_bin_dir) {
			err = fmt.Errorf("no such hwaf-bin dir [%s]", hwaf_bin_dir)
			handle_err(err)
		}
		src_waf, err := os.Open(filepath.Join(hwaf_bin_dir, "waf"))
		handle_err(err)
		defer src_waf.Close()

		if !path_exists(".hwaf/bin") {
			err = os.MkdirAll(".hwaf/bin", 0700)
			handle_err(err)
		}

		waf_bin, err := os.Create(filepath.Join(".hwaf", "bin", "waf"))
		handle_err(err)
		defer waf_bin.Close()

		err = waf_bin.Chmod(0755)
		handle_err(err)

		_, err = io.Copy(waf_bin, src_waf)
		handle_err(err)

		err = waf_bin.Sync()
		handle_err(err)
	}

	// add pkgdb
	err = ioutil.WriteFile(
		filepath.Join(".hwaf", "pkgdb.json"),
		[]byte("{}\n"),
		0755,
	)
	handle_err(err)
	git = exec.Command("git", "add", "-f", filepath.Join(".hwaf", "pkgdb.json"))
	if !quiet {
		git.Stdout = os.Stdout
		git.Stderr = os.Stderr
	}
	err = git.Run()
	handle_err(err)

	// add template wscript
	if !quiet {
		fmt.Printf("%s: add top-level wscript...\n", n)
	}

	if !path_exists("wscript") {
		wscript_tmpl, err := os.Open(".hwaf/tools/hwaf-wscript")
		handle_err(err)
		defer wscript_tmpl.Close()

		wscript_b, err := ioutil.ReadAll(wscript_tmpl)
		handle_err(err)

		// replace 'hwaf-workarea' with workarea name
		wscript_s := strings.Replace(
			string(wscript_b),
			"APPNAME = 'hwaf-workarea'",
			fmt.Sprintf("APPNAME = '%s'", proj_name),
			-1)

		wscript, err := os.Create("wscript")
		handle_err(err)
		defer wscript.Close()

		_, err = io.WriteString(wscript, wscript_s)
		handle_err(err)
		handle_err(wscript.Sync())
		handle_err(wscript.Close())
	}

	git = exec.Command("git", "add", "wscript")
	if !quiet {
		git.Stdout = os.Stdout
		git.Stderr = os.Stderr
	}
	err = git.Run()
	handle_err(err)

	// create 'src' directory
	if !path_exists("src") {
		err = os.MkdirAll("src", 0700)
		handle_err(err)
	}

	// add a default .gitignore
	gitignore_tmpl, err := os.Open(".hwaf/tools/.gitignore")
	handle_err(err)
	defer gitignore_tmpl.Close()

	gitignore, err := os.Create(".gitignore")
	handle_err(err)
	defer gitignore.Close()

	_, err = io.Copy(gitignore, gitignore_tmpl)
	handle_err(err)
	handle_err(gitignore.Sync())
	handle_err(gitignore.Close())

	git = exec.Command("git", "add", ".gitignore")
	if !quiet {
		git.Stdout = os.Stdout
		git.Stderr = os.Stderr
	}
	err = git.Run()
	handle_err(err)

	// check whether we need to commit
	err = exec.Command("git", "diff", "--exit-code", "--quiet", "HEAD").Run()
	if err != nil {
		// commit
		if !quiet {
			fmt.Printf("%s: commit workarea...\n", n)
		}
		git = exec.Command(
			"git", "commit", "-m",
			fmt.Sprintf("init hwaf project [%s]", proj_name),
		)
		if !quiet {
			git.Stdout = os.Stdout
			git.Stderr = os.Stderr
		}
		err = git.Run()
		handle_err(err)
	}

	if !quiet {
		fmt.Printf("%s: creating workarea [%s]... [ok]\n", n, dirname)
	}
}

// EOF
<|endoftext|>