<commit_before>package broker

import (
	"context"
	"errors"
	"strings"
	"sync"

	"code.cloudfoundry.org/lager"
	"github.com/pivotal-cf/brokerapi"
)

type lock interface {
	Lock()
	Unlock()
}

type ServiceBroker struct {
	logger lager.Logger
	client *DeploymentClient
	static staticState
	mutex  lock
}

type staticState struct {
	ServiceName string `json:"service_name"`
	ServiceID   string `json:"service_id"`
}

func New(logger lager.Logger,
	cloudConfig CloudConfig,
	resourceConfig ResourceConfig,
	blockchainConfig BlockchainConfig,
	serviceName string,
	serviceID string) (*ServiceBroker, error) {
	logger = logger.Session("new-blockchain-service-broker")
	logger.Info("start")
	defer logger.Info("end", nil)
	client, err := NewDeploymentClient(logger, cloudConfig, resourceConfig, blockchainConfig)
	if err != nil {
		return nil, err
	}
	serviceBroker := ServiceBroker{
		logger: logger,
		mutex:  &sync.Mutex{},
		client: client,
		static: staticState{
			ServiceID:   serviceID,
			ServiceName: serviceName,
		},
	}
	return &serviceBroker, nil
}

func (b *ServiceBroker) Services(_ context.Context) []brokerapi.Service {
	logger := b.logger.Session("services")
	logger.Info("start")
	defer logger.Info("end")

	return []brokerapi.Service{{
		ID:            b.static.ServiceID,
		Name:          b.static.ServiceName,
		Description:   "Azure Blockchain",
		Bindable:      true,
		PlanUpdatable: false,
		Tags:          []string{"azureblockchain"},
		Requires:      []brokerapi.RequiredPermission{},
		Plans: []brokerapi.ServicePlan{
			{
				Name:        "AzureBlockchain",
				ID:          "7c0b2254-7e68-11e7-bbe1-000d3a818256",
				Description: "Azure Blockchain",
			},
		},
	}}
}

func (b *ServiceBroker) LastOperation(_ context.Context, instanceID string, operationData string) (brokerapi.LastOperation, error) {
	logger := b.logger.Session("last-operation", lager.Data{"instanceID": instanceID, "operationData": operationData})
	logger.Info("start")
	defer logger.Info("end")

	b.mutex.Lock()
	defer b.mutex.Unlock()

	if operationData == "" {
		return brokerapi.LastOperation{}, errors.New("unrecognized operationData")
	}

	client := *(b.client.azureRESTClient)
	client.resourceConfig.ResourceGroupName = instanceID
	operationDataArr := strings.Split(operationData, ":")
	if len(operationDataArr) != 2 {
		return brokerapi.LastOperation{}, errors.New("unrecognized operationData")
	}
	var state string
	var err error
	if operationDataArr[0] == "provision" {
		state, err = client.CheckCompletion(operationDataArr[1])
	} else if operationDataArr[0] == "deprovision" {
		state, err = client.CheckResourceStatus(operationDataArr[1])
	}

	state = strings.ToLower(state)
	logger.Info("check-state", lager.Data{
		"state": state,
	})
	description := ""
	if err != nil {
		return brokerapi.LastOperation{State: brokerapi.Failed, Description: err.Error()}, nil
	}
	if state == "succeeded" {
		return brokerapi.LastOperation{State: brokerapi.Succeeded, Description: description}, nil
	} else if state == "notfound" && operationDataArr[0] == "deprovision" {
		return brokerapi.LastOperation{State: brokerapi.Succeeded, Description: description}, nil
	} else if state == "failed" {
		return brokerapi.LastOperation{State: brokerapi.Failed, Description: description}, nil
	}

	return brokerapi.LastOperation{State: brokerapi.InProgress, Description: description}, nil
}

func (b *ServiceBroker) Provision(context context.Context, instanceID string, details brokerapi.ProvisionDetails, asyncAllowed bool) (_ brokerapi.ProvisionedServiceSpec, e error) {
	logger := b.logger.Session("provision").WithData(lager.Data{"instanceID": instanceID, "details": details, "asyncAllowed": asyncAllowed})
	logger.Info("start")
	defer logger.Info("end")

	// Use async to process blockchain provision
	b.mutex.Lock()
	defer b.mutex.Unlock()

	b.client.azureRESTClient.resourceConfig.ResourceGroupName = instanceID
	err := b.client.Create(instanceID)
	if err != nil {
		logger.Error("create-blockchain-service", err)
		return brokerapi.ProvisionedServiceSpec{}, err
	}
	lastOperation := instanceID
	if err != nil {
		logger.Error("get-status-url", err)
		return brokerapi.ProvisionedServiceSpec{}, err
	}

	return brokerapi.ProvisionedServiceSpec{IsAsync: true, OperationData: "provision:" + lastOperation}, nil
}

func (b *ServiceBroker) Bind(context context.Context, instanceID string, bindingID string, details brokerapi.BindDetails) (_ brokerapi.Binding, e error) {
	logger := b.logger.Session("bind", lager.Data{"instanceID": instanceID})
	logger.Info("start")
	defer logger.Info("end")

	b.mutex.Lock()
	defer b.mutex.Unlock()

	client := *(b.client.azureRESTClient)
	ready, err := client.CheckCompletion(instanceID)
	if err != nil {
		return brokerapi.Binding{}, err
	}
	if strings.ToLower(ready) != "succeeded" {
		return brokerapi.Binding{}, errors.New("Provision has not been finish")
	}

	_, rpcURL, err := client.GetAdminAndRPCUrl(instanceID)
	if err != nil {
		return brokerapi.Binding{}, err
	}
	return brokerapi.Binding{Credentials: rpcURL}, err
}

func (b *ServiceBroker) Update(context context.Context, instanceID string, details brokerapi.UpdateDetails, asyncAllowed bool) (brokerapi.UpdateServiceSpec, error) {
	panic("not implemented")
}

func (b *ServiceBroker) Unbind(context context.Context, instanceID string, bindingID string, details brokerapi.UnbindDetails) (e error) {
	logger := b.logger.Session("unbind")
	logger.Info("start")
	defer logger.Info("end")

	return nil
}

func (b *ServiceBroker) Deprovision(context context.Context, instanceID string, details brokerapi.DeprovisionDetails, asyncAllowed bool) (_ brokerapi.DeprovisionServiceSpec, err error) {
	logger := b.logger.Session("deprovision").WithData(lager.Data{
		"instanceID":   instanceID,
		"details":      details,
		"asyncAllowed": asyncAllowed,
	})
	logger.Info("start")
	defer logger.Info("end")

	b.mutex.Lock()
	defer b.mutex.Unlock()

	client := *(b.client.azureRESTClient)
	client.resourceConfig.ResourceGroupName = instanceID
	_, err = client.DeleteGroup()
	if err != nil {
		return brokerapi.DeprovisionServiceSpec{}, err
	}
	return brokerapi.DeprovisionServiceSpec{IsAsync: false, OperationData: "deprovision:" + instanceID}, nil
}
<commit_msg>[modify] unbinding<commit_after>package broker

import (
	"context"
	"errors"
	"strings"
	"sync"

	"code.cloudfoundry.org/lager"
	"github.com/pivotal-cf/brokerapi"
)

type lock interface {
	Lock()
	Unlock()
}

type ServiceBroker struct {
	logger lager.Logger
	client *DeploymentClient
	static staticState
	mutex  lock
}

type staticState struct {
	ServiceName string `json:"service_name"`
	ServiceID   string `json:"service_id"`
}

func New(logger lager.Logger,
	cloudConfig CloudConfig,
	resourceConfig ResourceConfig,
	blockchainConfig BlockchainConfig,
	serviceName string,
	serviceID string) (*ServiceBroker, error) {
	logger = logger.Session("new-blockchain-service-broker")
	logger.Info("start")
	defer logger.Info("end", nil)
	client, err := NewDeploymentClient(logger, cloudConfig, resourceConfig, blockchainConfig)
	if err != nil {
		return nil, err
	}
	serviceBroker := ServiceBroker{
		logger: logger,
		mutex:  &sync.Mutex{},
		client: client,
		static: staticState{
			ServiceID:   serviceID,
			ServiceName: serviceName,
		},
	}
	return &serviceBroker, nil
}

func (b *ServiceBroker) Services(_ context.Context) []brokerapi.Service {
	logger := b.logger.Session("services")
	logger.Info("start")
	defer logger.Info("end")

	return []brokerapi.Service{{
		ID:            b.static.ServiceID,
		Name:          b.static.ServiceName,
		Description:   "Azure Blockchain",
		Bindable:      true,
		PlanUpdatable: false,
		Tags:          []string{"azureblockchain"},
		Requires:      []brokerapi.RequiredPermission{},
		Plans: []brokerapi.ServicePlan{
			{
				Name:        "AzureBlockchain",
				ID:          "7c0b2254-7e68-11e7-bbe1-000d3a818256",
				Description: "Azure Blockchain",
			},
		},
	}}
}

func (b *ServiceBroker) LastOperation(_ context.Context, instanceID string, operationData string) (brokerapi.LastOperation, error) {
	logger := b.logger.Session("last-operation", lager.Data{"instanceID": instanceID, "operationData": operationData})
	logger.Info("start")
	defer logger.Info("end")

	b.mutex.Lock()
	defer b.mutex.Unlock()

	if operationData == "" {
		return brokerapi.LastOperation{}, errors.New("unrecognized operationData")
	}

	client := *(b.client.azureRESTClient)
	client.resourceConfig.ResourceGroupName = instanceID
	operationDataArr := strings.Split(operationData, ":")
	if len(operationDataArr) != 2 {
		return brokerapi.LastOperation{}, errors.New("unrecognized operationData")
	}
	var state string
	var err error
	if operationDataArr[0] == "provision" {
		state, err = client.CheckCompletion(operationDataArr[1])
	} else if operationDataArr[0] == "deprovision" {
		state, err = client.CheckResourceStatus(operationDataArr[1])
	}

	state = strings.ToLower(state)
	logger.Info("check-state", lager.Data{
		"state": state,
	})
	description := ""
	if err != nil {
		return brokerapi.LastOperation{State: brokerapi.Failed, Description: err.Error()}, nil
	}
	if state == "succeeded" {
		return brokerapi.LastOperation{State: brokerapi.Succeeded, Description: description}, nil
	} else if state == "notfound" && operationDataArr[0] == "deprovision" {
		return brokerapi.LastOperation{State: brokerapi.Succeeded, Description: description}, nil
	} else if state == "failed" {
		return brokerapi.LastOperation{State: brokerapi.Failed, Description: description}, nil
	}

	return brokerapi.LastOperation{State: brokerapi.InProgress, Description: description}, nil
}

func (b *ServiceBroker) Provision(context context.Context, instanceID string, details brokerapi.ProvisionDetails, asyncAllowed bool) (_ brokerapi.ProvisionedServiceSpec, e error) {
	logger := b.logger.Session("provision").WithData(lager.Data{"instanceID": instanceID, "details": details, "asyncAllowed": asyncAllowed})
	logger.Info("start")
	defer logger.Info("end")

	// Use async to process blockchain provision
	b.mutex.Lock()
	defer b.mutex.Unlock()

	b.client.azureRESTClient.resourceConfig.ResourceGroupName = instanceID
	err := b.client.Create(instanceID)
	if err != nil {
		logger.Error("create-blockchain-service", err)
		return brokerapi.ProvisionedServiceSpec{}, err
	}
	lastOperation := instanceID
	if err != nil {
		logger.Error("get-status-url", err)
		return brokerapi.ProvisionedServiceSpec{}, err
	}

	return brokerapi.ProvisionedServiceSpec{IsAsync: true, OperationData: "provision:" + lastOperation}, nil
}

func (b *ServiceBroker) Bind(context context.Context, instanceID string, bindingID string, details brokerapi.BindDetails) (_ brokerapi.Binding, e error) {
	logger := b.logger.Session("bind", lager.Data{"instanceID": instanceID})
	logger.Info("start")
	defer logger.Info("end")

	b.mutex.Lock()
	defer b.mutex.Unlock()

	client := *(b.client.azureRESTClient)
	ready, err := client.CheckCompletion(instanceID)
	if err != nil {
		return brokerapi.Binding{}, err
	}
	if strings.ToLower(ready) != "succeeded" {
		return brokerapi.Binding{}, errors.New("Provision has not been finish")
	}

	_, rpcURL, err := client.GetAdminAndRPCUrl(instanceID)
	if err != nil {
		return brokerapi.Binding{}, err
	}
	return brokerapi.Binding{Credentials: rpcURL}, err
}

func (b *ServiceBroker) Update(context context.Context, instanceID string, details brokerapi.UpdateDetails, asyncAllowed bool) (brokerapi.UpdateServiceSpec, error) {
	panic("not implemented")
}

func (b *ServiceBroker) Unbind(context context.Context, instanceID string, bindingID string, details brokerapi.UnbindDetails) (e error) {
	logger := b.logger.Session("unbind")
	logger.Info("start")
	defer logger.Info("end")

	b.mutex.Lock()
	defer b.mutex.Unlock()

	client := *(b.client.azureRESTClient)
	client.resourceConfig.ResourceGroupName = instanceID
	state, err := client.CheckResourceStatus(instanceID)
	if state == "notfound" {
		return errors.New("binding does not exist.")
	}

	return err
}

func (b *ServiceBroker) Deprovision(context context.Context, instanceID string, details brokerapi.DeprovisionDetails, asyncAllowed bool) (_ brokerapi.DeprovisionServiceSpec, err error) {
	logger := b.logger.Session("deprovision").WithData(lager.Data{
		"instanceID":   instanceID,
		"details":      details,
		"asyncAllowed": asyncAllowed,
	})
	logger.Info("start")
	defer logger.Info("end")

	b.mutex.Lock()
	defer b.mutex.Unlock()

	client := *(b.client.azureRESTClient)
	client.resourceConfig.ResourceGroupName = instanceID
	_, err = client.DeleteGroup()
	if err != nil {
		return brokerapi.DeprovisionServiceSpec{}, err
	}
	return brokerapi.DeprovisionServiceSpec{IsAsync: false, OperationData: "deprovision:" + instanceID}, nil
}
<|endoftext|>


<commit_before>package somatree

import "github.com/satori/go.uuid"

func specRepoCheck(spec RepositorySpec) bool {
	switch {
	case spec.Id == "":
		return false
	case spec.Name == "":
		return false
	case spec.Team == "":
		return false
	}
	if _, err := uuid.FromString(spec.Id); err != nil {
		return false
	}
	if _, err := uuid.FromString(spec.Team); err != nil {
		return false
	}
	return true
}

func specBucketCheck(spec BucketSpec) bool {
	switch {
	case spec.Id == "":
		return false
	case spec.Name == "":
		return false
	case spec.Environment == "":
		return false
	case spec.Team == "":
		return false
	case spec.Repository == "":
		return false
	}
	if _, err := uuid.FromString(spec.Id); err != nil {
		return false
	}
	if _, err := uuid.FromString(spec.Team); err != nil {
		return false
	}
	if _, err := uuid.FromString(spec.Repository); err != nil {
		return false
	}
	return true
}

func specGroupCheck(spec GroupSpec) bool {
	switch {
	case spec.Id == "":
		return false
	case spec.Name == "":
		return false
	case spec.Team == "":
		return false
	}
	if _, err := uuid.FromString(spec.Id); err != nil {
		return false
	}
	if _, err := uuid.FromString(spec.Team); err != nil {
		return false
	}
	return true
}

func specClusterCheck(spec ClusterSpec) bool {
	switch {
	case spec.Id == "":
		return false
	case spec.Name == "":
		return false
	case spec.Team == "":
		return false
	}
	if _, err := uuid.FromString(spec.Id); err != nil {
		return false
	}
	if _, err := uuid.FromString(spec.Team); err != nil {
		return false
	}
	return true
}

func specNodeCheck(spec NodeSpec) bool {
	switch {
	case spec.Id == "":
		return false
	case spec.Name == "":
		return false
	case spec.Team == "":
		return false
	case spec.ServerId == "":
		return false
	}
	if _, err := uuid.FromString(spec.Id); err != nil {
		return false
	}
	if _, err := uuid.FromString(spec.Team); err != nil {
		return false
	}
	if _, err := uuid.FromString(spec.ServerId); err != nil {
		return false
	}
	return true
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<commit_msg>Update validation to check Name lengths (min/max)<commit_after>package somatree

import (
	"unicode/utf8"

	"github.com/satori/go.uuid"
)

func specRepoCheck(spec RepositorySpec) bool {
	switch {
	case spec.Id == "":
		return false
	case spec.Name == "":
		return false
	case spec.Team == "":
		return false
	}
	l := utf8.RuneCountInString(spec.Name)
	switch {
	case l < 4:
		return false
	case l > 128:
		return false
	}
	if _, err := uuid.FromString(spec.Id); err != nil {
		return false
	}
	if _, err := uuid.FromString(spec.Team); err != nil {
		return false
	}
	return true
}

func specBucketCheck(spec BucketSpec) bool {
	switch {
	case spec.Id == "":
		return false
	case spec.Name == "":
		return false
	case spec.Environment == "":
		return false
	case spec.Team == "":
		return false
	case spec.Repository == "":
		return false
	}
	l := utf8.RuneCountInString(spec.Name)
	switch {
	case l < 4:
		return false
	case l > 512:
		return false
	}
	if _, err := uuid.FromString(spec.Id); err != nil {
		return false
	}
	if _, err := uuid.FromString(spec.Team); err != nil {
		return false
	}
	if _, err := uuid.FromString(spec.Repository); err != nil {
		return false
	}
	return true
}

func specGroupCheck(spec GroupSpec) bool {
	switch {
	case spec.Id == "":
		return false
	case spec.Name == "":
		return false
	case spec.Team == "":
		return false
	}
	l := utf8.RuneCountInString(spec.Name)
	switch {
	case l < 4:
		return false
	case l > 256:
		return false
	}
	if _, err := uuid.FromString(spec.Id); err != nil {
		return false
	}
	if _, err := uuid.FromString(spec.Team); err != nil {
		return false
	}
	return true
}

func specClusterCheck(spec ClusterSpec) bool {
	switch {
	case spec.Id == "":
		return false
	case spec.Name == "":
		return false
	case spec.Team == "":
		return false
	}
	l := utf8.RuneCountInString(spec.Name)
	switch {
	case l < 4:
		return false
	case l > 256:
		return false
	}
	if _, err := uuid.FromString(spec.Id); err != nil {
		return false
	}
	if _, err := uuid.FromString(spec.Team); err != nil {
		return false
	}
	return true
}

func specNodeCheck(spec NodeSpec) bool {
	switch {
	case spec.Id == "":
		return false
	case spec.Name == "":
		return false
	case spec.Team == "":
		return false
	case spec.ServerId == "":
		return false
	}
	l := utf8.RuneCountInString(spec.Name)
	switch {
	case l < 4:
		return false
	case l > 256:
		return false
	}
	if _, err := uuid.FromString(spec.Id); err != nil {
		return false
	}
	if _, err := uuid.FromString(spec.Team); err != nil {
		return false
	}
	if _, err := uuid.FromString(spec.ServerId); err != nil {
		return false
	}
	return true
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<|endoftext|>


<commit_before>package singleinstance

import (
	"io/ioutil"
	"os"
	"testing"
)

func createTestLock(t *testing.T) *os.File {
	tmpfile, err := ioutil.TempFile("", "singleinstance")
	if err != nil {
		t.Fatal("Cannot create temporary file:", err)
	}
	tmpfile.Close()

	f, err := CreateLockFile(tmpfile.Name())
	if err != nil {
		t.Fatal("Expected no error while creating lock, got:", err)
	}

	return f
}

func TestCreateLockFile(t *testing.T) {
	f := createTestLock(t)
	defer os.Remove(f.Name())

	if _, err := CreateLockFile(f.Name()); err == nil {
		t.Fatal("Expected an error while trying to lock, got:", err)
	}

	f.Close() // Remove the lock

	if _, err := CreateLockFile(f.Name()); err != nil {
		t.Fatal("Expected no error while trying to lock, got:", err)
	}

	f.Close()
}

func TestGetLockFilePid(t *testing.T) {
	f := createTestLock(t)
	defer os.Remove(f.Name())
	defer f.Close()

	pid, err := GetLockFilePid(f.Name())
	if err != nil {
		t.Fatal("Expected no error while getting PID, got:", err)
	}
	if pid != os.Getpid() {
		t.Errorf("Invalid PID: expected %v but got %v", os.Getpid(), pid)
	}
}
<commit_msg>Properly close files in TestCreateLockFile<commit_after>package singleinstance

import (
	"io/ioutil"
	"os"
	"testing"
)

func createTestLock(t *testing.T) *os.File {
	tmpfile, err := ioutil.TempFile("", "singleinstance")
	if err != nil {
		t.Fatal("Cannot create temporary file:", err)
	}
	tmpfile.Close()

	f, err := CreateLockFile(tmpfile.Name())
	if err != nil {
		t.Fatal("Expected no error while creating lock, got:", err)
	}

	return f
}

func TestCreateLockFile(t *testing.T) {
	f := createTestLock(t)
	defer os.Remove(f.Name())

	_, err := CreateLockFile(f.Name())
	if err == nil {
		t.Fatal("Expected an error while trying to lock, got:", err)
	}

	f.Close() // Remove the lock

	f, err = CreateLockFile(f.Name())
	if err != nil {
		t.Fatal("Expected no error while trying to lock, got:", err)
	}

	f.Close()
}

func TestGetLockFilePid(t *testing.T) {
	f := createTestLock(t)
	defer os.Remove(f.Name())
	defer f.Close()

	pid, err := GetLockFilePid(f.Name())
	if err != nil {
		t.Fatal("Expected no error while getting PID, got:", err)
	}
	if pid != os.Getpid() {
		t.Errorf("Invalid PID: expected %v but got %v", os.Getpid(), pid)
	}
}
<|endoftext|>


<commit_before>package ltcp_test

import (
	"net"
	"testing"

	"github.com/fourcube/ltcp"
)

func TestListen(t *testing.T) {
	listenAddress := "127.0.0.1:12345"
	done := make(chan struct{})

	err := ltcp.Listen(listenAddress, ltcp.EchoHandler, done)
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	close(done)
}

func TestAddressAlreadyInUse(t *testing.T) {
	listenAddress := "127.0.0.1:12345"
	done := make(chan struct{})

	err := ltcp.Listen(listenAddress, ltcp.EchoHandler, done)
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	err = ltcp.Listen(listenAddress, ltcp.EchoHandler, done)
	if err == nil {
		t.Errorf("Expected listen to fail when address is in use, got no error")
	}

	close(done)
}

func TestListenAny(t *testing.T) {
	done := make(chan struct{})

	addr, err := ltcp.ListenAny(ltcp.EchoHandler, done)
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	if addr == nil {
		t.Errorf("Expected server to listen on some address, got nil")
	}

	close(done)
}

func TestServerActuallyResponds(t *testing.T) {
	listenAddress := "127.0.0.1:12345"
	done := make(chan struct{})

	err := ltcp.Listen(listenAddress, ltcp.EchoHandler, done)

	conn, err := net.Dial("tcp", listenAddress)
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	testPayload := "foo"
	recvBuf := make([]byte, 32)
	conn.Write([]byte(testPayload))

	n, err := conn.Read(recvBuf)
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	data := string(recvBuf[:n])
	if data != "foo" {
		t.Errorf("Expected to receive '%s' from the echo handler, got '%s'", testPayload, data)
	}

	close(done)
}

func TestServerActuallyRespondsDuringListenAny(t *testing.T) {
	done := make(chan struct{})
	addr, err := ltcp.ListenAny(ltcp.EchoHandler, done)

	conn, err := net.Dial("tcp", addr.String())
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	testPayload := "foo"
	recvBuf := make([]byte, 32)
	conn.Write([]byte(testPayload))

	n, err := conn.Read(recvBuf)
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	data := string(recvBuf[:n])
	if data != "foo" {
		t.Errorf("Expected to receive '%s' from the echo handler, got '%s'", testPayload, data)
	}

	close(done)
}
<commit_msg>Change port in tests<commit_after>package ltcp_test

import (
	"net"
	"testing"

	"github.com/fourcube/ltcp"
)

func TestListen(t *testing.T) {
	listenAddress := "127.0.0.1:54429"
	done := make(chan struct{})

	err := ltcp.Listen(listenAddress, ltcp.EchoHandler, done)
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	close(done)
}

func TestAddressAlreadyInUse(t *testing.T) {
	listenAddress := "127.0.0.1:54429"
	done := make(chan struct{})

	err := ltcp.Listen(listenAddress, ltcp.EchoHandler, done)
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	err = ltcp.Listen(listenAddress, ltcp.EchoHandler, done)
	if err == nil {
		t.Errorf("Expected listen to fail when address is in use, got no error")
	}

	close(done)
}

func TestListenAny(t *testing.T) {
	done := make(chan struct{})

	addr, err := ltcp.ListenAny(ltcp.EchoHandler, done)
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	if addr == nil {
		t.Errorf("Expected server to listen on some address, got nil")
	}

	close(done)
}

func TestServerActuallyResponds(t *testing.T) {
	listenAddress := "127.0.0.1:54429"
	done := make(chan struct{})

	err := ltcp.Listen(listenAddress, ltcp.EchoHandler, done)

	conn, err := net.Dial("tcp", listenAddress)
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	testPayload := "foo"
	recvBuf := make([]byte, 32)
	conn.Write([]byte(testPayload))

	n, err := conn.Read(recvBuf)
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	data := string(recvBuf[:n])
	if data != "foo" {
		t.Errorf("Expected to receive '%s' from the echo handler, got '%s'", testPayload, data)
	}

	close(done)
}

func TestServerActuallyRespondsDuringListenAny(t *testing.T) {
	done := make(chan struct{})
	addr, err := ltcp.ListenAny(ltcp.EchoHandler, done)

	conn, err := net.Dial("tcp", addr.String())
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	testPayload := "foo"
	recvBuf := make([]byte, 32)
	conn.Write([]byte(testPayload))

	n, err := conn.Read(recvBuf)
	if err != nil {
		t.Errorf("Expected no error, got %v", err)
	}

	data := string(recvBuf[:n])
	if data != "foo" {
		t.Errorf("Expected to receive '%s' from the echo handler, got '%s'", testPayload, data)
	}

	close(done)
}
<|endoftext|>


<commit_before>// $ go run gazel.go -r ./vendor
// $ go run gazel.go -r ./federation
// $ go run gazel.go -r ./contrib
// $ go run gazel.go -r ./plugin
// $ go run gazel.go -r ./test
package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/build"
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"
	"sort"
	"strings"

	bzl "github.com/bazelbuild/buildifier/core"
	"github.com/golang/glog"
)

var kubeRoot = os.Getenv("KUBE_ROOT")

func main() {
	flag.Parse()
	flag.Set("alsologtostderr", "true")
	v := Venderor{
		ctx: &build.Default,
	}
	if len(os.Args) == 2 {
		v.updateSinglePkg(os.Args[1])
	} else {
		v.walkVendor()
		if err := v.walkRepo(); err != nil {
			glog.Fatalf("err: %v", err)
		}
	}
}

type Venderor struct {
	ctx *build.Context
}

func writeHeaders(file *bzl.File) {
	pkgRule := bzl.Rule{
		&bzl.CallExpr{
			X: &bzl.LiteralExpr{Token: "package"},
		},
	}
	pkgRule.SetAttr("default_visibility", asExpr([]string{"//visibility:public"}))

	file.Stmt = append(file.Stmt,
		[]bzl.Expr{
			pkgRule.Call,
			&bzl.CallExpr{
				X:    &bzl.LiteralExpr{Token: "licenses"},
				List: []bzl.Expr{asExpr([]string{"notice"})},
			},
			&bzl.CallExpr{
				X: &bzl.LiteralExpr{Token: "load"},
				List: asExpr([]string{
					"@io_bazel_rules_go//go:def.bzl",
					"go_binary",
					"go_library",
					"go_test",
					"cgo_library",
				}).(*bzl.ListExpr).List,
			},
		}...,
	)
}

func writeRules(file *bzl.File, rules []*bzl.Rule) {
	for _, rule := range rules {
		file.Stmt = append(file.Stmt, rule.Call)
	}
}

func (v *Venderor) resolve(ipath string) Label {
	if strings.HasPrefix(ipath, "k8s.io/kubernetes") {
		return Label{
			pkg: strings.TrimPrefix(ipath, "k8s.io/kubernetes/"),
			tag: "go_default_library",
		}
	}
	return Label{
		pkg: "vendor",
		tag: ipath,
	}
}

func (v *Venderor) walk(root string, f func(path, ipath string, pkg *build.Package) error) error {
	return filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		ipath, err := filepath.Rel(root, path)
		if err != nil {
			return err
		}
		if !info.IsDir() {
			return nil
		}
		pkg, err := v.ctx.ImportDir(filepath.Join(kubeRoot, path), build.ImportComment)
		if err != nil {
			if _, ok := err.(*build.NoGoError); err != nil && ok {
				return nil
			} else {
				return err
			}
		}

		return f(path, ipath, pkg)
	})
}

func (v *Venderor) walkRepo() error {
	for _, root := range []string{
		"./pkg",
		"./cmd",
		"./third_party",
		"./plugin",
		"./test",
		"./federation",
	} {
		if err := v.walk(root, v.updatePkg); err != nil {
			return err
		}
	}
	return nil
}

func (v *Venderor) updateSinglePkg(path string) error {
	pkg, err := v.ctx.ImportDir("./"+path, build.ImportComment)
	if err != nil {
		if _, ok := err.(*build.NoGoError); err != nil && ok {
			return nil
		} else {
			return err
		}
	}
	glog.Infof("here")
	return v.updatePkg(path, "", pkg)
}

func (v *Venderor) updatePkg(path, _ string, pkg *build.Package) error {
	var rules []*bzl.Rule

	var attrs Attrs = make(Attrs)
	srcs := asExpr(merge(pkg.GoFiles, pkg.SFiles)).(*bzl.ListExpr)

	deps := v.extractDeps(pkg.Imports)

	if len(srcs.List) == 0 {
		return nil
	}
	attrs.Set("srcs", srcs)

	if len(deps.List) > 0 {
		attrs.Set("deps", deps)
	}

	if pkg.IsCommand() {
		rules = append(rules, newRule("go_binary", filepath.Base(pkg.Dir), attrs))
	} else {
		rules = append(rules, newRule("go_library", "go_default_library", attrs))
		if len(pkg.TestGoFiles) != 0 {
			rules = append(rules, newRule("go_test", "go_default_test", map[string]bzl.Expr{
				"srcs":    asExpr(pkg.TestGoFiles),
				"deps":    v.extractDeps(pkg.TestImports),
				"library": asExpr("go_default_library"),
			}))
		}
	}

	if len(pkg.XTestGoFiles) != 0 {
		rules = append(rules, newRule("go_test", "go_default_xtest", map[string]bzl.Expr{
			"srcs": asExpr(pkg.XTestGoFiles),
			"deps": v.extractDeps(pkg.XTestImports),
		}))
	}

	wrote, err := ReconcileRules(filepath.Join(path, "BUILD"), rules)
	if err != nil {
		return err
	}
	if wrote {
		fmt.Fprintf(os.Stderr, "wrote BUILD for %q\n", pkg.ImportPath)
	}
	return nil
}

func (v *Venderor) walkVendor() {
	var rules []*bzl.Rule
	if err := v.walk("./vendor", func(path, ipath string, pkg *build.Package) error {
		var attrs Attrs = make(Attrs)

		srcs := asExpr(
			apply(
				merge(pkg.GoFiles, pkg.SFiles),
				mapper(func(s string) string {
					return strings.TrimPrefix(filepath.Join(path, s), "vendor/")
				}),
			),
		).(*bzl.ListExpr)

		cgoSrcs := asExpr(
			apply(
				merge(pkg.CgoFiles, pkg.CFiles, pkg.CXXFiles, pkg.HFiles),
				mapper(func(s string) string {
					return strings.TrimPrefix(filepath.Join(path, s), "vendor/")
				}),
			),
		).(*bzl.ListExpr)

		deps := v.extractDeps(pkg.Imports)
		attrs.Set("srcs", srcs)

		if len(deps.List) > 0 {
			attrs.Set("deps", deps)
		}

		if pkg.IsCommand() {
			rules = append(rules, newRule("go_binary", v.resolve(ipath).tag, attrs))
		} else {
			if len(cgoSrcs.List) != 0 {
				cgoPname := v.resolve(ipath).tag + "_cgo"
				cgoDeps := v.extractDeps(pkg.TestImports)
				cgoRule := newRule("cgo_library", cgoPname, map[string]bzl.Expr{
					"srcs":      cgoSrcs,
					"clinkopts": asExpr([]string{"-ldl", "-lz", "-lm", "-lpthread", "-ldl"}),
				})
				rules = append(rules, cgoRule)
				if len(cgoDeps.List) != 0 {
					cgoRule.SetAttr("deps", cgoDeps)
				}
				attrs["library"] = asExpr(cgoPname)
			}
			rules = append(rules, newRule("go_library", v.resolve(ipath).tag, attrs))
		}
		return nil
	}); err != nil {
		glog.Fatalf("err: %v", err)
	}
	if _, err := ReconcileRules("./vendor/BUILD", rules); err != nil {
		glog.Fatalf("err: %v", err)
	}
}

func (v *Venderor) extractDeps(deps []string) *bzl.ListExpr {
	return asExpr(
		apply(
			merge(deps),
			filterer(func(s string) bool {
				pkg, err := v.ctx.Import(s, kubeRoot, build.ImportComment)
				if err != nil {
					return false
				}
				if pkg.Goroot {
					return false
				}
				return true
			}),
			mapper(func(s string) string {
				return v.resolve(s).String()
			}),
		),
	).(*bzl.ListExpr)
}

type Attrs map[string]bzl.Expr

func (a Attrs) Set(name string, expr bzl.Expr) {
	a[name] = expr
}

type Label struct {
	pkg, tag string
}

func (l Label) String() string {
	return fmt.Sprintf("//%v:%v", l.pkg, l.tag)
}

func asExpr(e interface{}) bzl.Expr {
	rv := reflect.ValueOf(e)
	switch rv.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return &bzl.LiteralExpr{Token: fmt.Sprintf("%d", e)}
	case reflect.Float32, reflect.Float64:
		return &bzl.LiteralExpr{Token: fmt.Sprintf("%f", e)}
	case reflect.String:
		return &bzl.StringExpr{Value: e.(string)}
	case reflect.Slice, reflect.Array:
		var list []bzl.Expr
		for i := 0; i < rv.Len(); i++ {
			list = append(list, asExpr(rv.Index(i).Interface()))
		}
		return &bzl.ListExpr{List: list}
	default:
		glog.Fatalf("Uh oh")
		return nil
	}
}

type Sed func(s []string) []string

func mapString(in []string, f func(string) string) []string {
	var out []string
	for _, s := range in {
		out = append(out, f(s))
	}
	return out
}

func mapper(f func(string) string) Sed {
	return func(in []string) []string {
		return mapString(in, f)
	}
}

func filterString(in []string, f func(string) bool) []string {
	var out []string
	for _, s := range in {
		if f(s) {
			out = append(out, s)
		}
	}
	return out
}

func filterer(f func(string) bool) Sed {
	return func(in []string) []string {
		return filterString(in, f)
	}
}

func apply(stream []string, seds ...Sed) []string {
	for _, sed := range seds {
		stream = sed(stream)
	}
	return stream
}

func merge(streams ...[]string) []string {
	var out []string
	for _, stream := range streams {
		out = append(out, stream...)
	}
	return out
}

func newRule(kind, name string, attrs map[string]bzl.Expr) *bzl.Rule {
	rule := &bzl.Rule{
		Call: &bzl.CallExpr{
			X: &bzl.LiteralExpr{Token: kind},
		},
	}
	rule.SetAttr("name", asExpr(name))
	for _, k := range sortKeys(attrs) {
		rule.SetAttr(k, attrs[k])
	}
	rule.SetAttr("tags", asExpr([]string{"automanaged"}))
	return rule
}

func sortKeys(attrs map[string]bzl.Expr) []string {
	ks := []string{}
	for k, _ := range attrs {
		ks = append(ks, k)
	}
	sort.Sort(orderedAttrs(ks))
	return ks
}

type orderedAttrs []string

var orderedAttrsPriority = map[string]int{
	"name":    1,
	"srcs":    2,
	"deps":    3,
	"library": 4,
	"tags":    5,
}

func (o orderedAttrs) Len() int {
	return len(o)
}

func (o orderedAttrs) Swap(i, j int) {
	o[i], o[j] = o[j], o[i]
}

func (o orderedAttrs) Less(i, j int) bool {
	ip, iok := orderedAttrsPriority[o[i]]
	jp, jok := orderedAttrsPriority[o[j]]
	if iok && jok {
		return ip < jp
	}
	if iok && !jok {
		return false
	}
	if jok && !iok {
		return true
	}
	return o[i] < o[j]
}

func ReconcileRules(path string, rules []*bzl.Rule) (bool, error) {
	info, err := os.Stat(path)
	if err != nil && os.IsNotExist(err) {
		f := &bzl.File{}
		writeHeaders(f)
		writeRules(f, rules)
		return true, ioutil.WriteFile(path, bzl.Format(f), 0644)
	} else if err != nil {
		return false, err
	}
	if info.IsDir() {
		return false, fmt.Errorf("%q cannot be a directory", path)
	}
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return false, err
	}
	f, err := bzl.Parse(path, b)
	if err != nil {
		return false, err
	}
	oldRules := make(map[string]*bzl.Rule)
	for _, r := range f.Rules("") {
		oldRules[r.Name()] = r
	}
	for _, r := range rules {
		o, ok := oldRules[r.Name()]
		if !ok {
			f.Stmt = append(f.Stmt, r.Call)
			continue
		}
		if !RuleIsManaged(o) {
			continue
		}
		reconcileAttr := func(o, n *bzl.Rule, name string) {
			if e := n.Attr(name); e != nil {
				o.SetAttr(name, e)
			} else {
				o.DelAttr(name)
			}
		}
		reconcileAttr(o, r, "srcs")
		reconcileAttr(o, r, "deps")
		reconcileAttr(o, r, "library")
		delete(oldRules, r.Name())
	}
	for _, r := range oldRules {
		if !RuleIsManaged(r) {
			continue
		}
		f.DelRules(r.Kind(), r.Name())
	}
	out := bzl.Format(f)
	orig, err := ioutil.ReadFile(path)
	if err != nil {
		return false, err
	}
	if bytes.Compare(out, orig) == 0 {
		return false, err
	}
	return true, ioutil.WriteFile(path, bzl.Format(f), 0644)
}

func RuleIsManaged(r *bzl.Rule) bool {
	var automanaged bool
	for _, tag := range r.AttrStrings("tags") {
		if tag == "automanaged" {
			automanaged = true
			break
		}
	}
	return automanaged
}
<commit_msg>dry run mode<commit_after>// $ go run gazel.go -r ./vendor
// $ go run gazel.go -r ./federation
// $ go run gazel.go -r ./contrib
// $ go run gazel.go -r ./plugin
// $ go run gazel.go -r ./test
package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/build"
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"
	"sort"
	"strings"

	bzl "github.com/bazelbuild/buildifier/core"
	"github.com/golang/glog"
)

var kubeRoot = os.Getenv("KUBE_ROOT")
var dryRun = flag.Bool("dry-run", false, "run in dry mode")

func main() {
	flag.Parse()
	flag.Set("alsologtostderr", "true")
	v := Venderor{
		ctx: &build.Default,
	}
	if len(os.Args) == 2 {
		v.updateSinglePkg(os.Args[1])
	} else {
		v.walkVendor()
		if err := v.walkRepo(); err != nil {
			glog.Fatalf("err: %v", err)
		}
	}
}

type Venderor struct {
	ctx *build.Context
}

func writeHeaders(file *bzl.File) {
	pkgRule := bzl.Rule{
		&bzl.CallExpr{
			X: &bzl.LiteralExpr{Token: "package"},
		},
	}
	pkgRule.SetAttr("default_visibility", asExpr([]string{"//visibility:public"}))

	file.Stmt = append(file.Stmt,
		[]bzl.Expr{
			pkgRule.Call,
			&bzl.CallExpr{
				X:    &bzl.LiteralExpr{Token: "licenses"},
				List: []bzl.Expr{asExpr([]string{"notice"})},
			},
			&bzl.CallExpr{
				X: &bzl.LiteralExpr{Token: "load"},
				List: asExpr([]string{
					"@io_bazel_rules_go//go:def.bzl",
					"go_binary",
					"go_library",
					"go_test",
					"cgo_library",
				}).(*bzl.ListExpr).List,
			},
		}...,
	)
}

func writeRules(file *bzl.File, rules []*bzl.Rule) {
	for _, rule := range rules {
		file.Stmt = append(file.Stmt, rule.Call)
	}
}

func (v *Venderor) resolve(ipath string) Label {
	if strings.HasPrefix(ipath, "k8s.io/kubernetes") {
		return Label{
			pkg: strings.TrimPrefix(ipath, "k8s.io/kubernetes/"),
			tag: "go_default_library",
		}
	}
	return Label{
		pkg: "vendor",
		tag: ipath,
	}
}

func (v *Venderor) walk(root string, f func(path, ipath string, pkg *build.Package) error) error {
	return filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		ipath, err := filepath.Rel(root, path)
		if err != nil {
			return err
		}
		if !info.IsDir() {
			return nil
		}
		pkg, err := v.ctx.ImportDir(filepath.Join(kubeRoot, path), build.ImportComment)
		if err != nil {
			if _, ok := err.(*build.NoGoError); err != nil && ok {
				return nil
			} else {
				return err
			}
		}

		return f(path, ipath, pkg)
	})
}

func (v *Venderor) walkRepo() error {
	for _, root := range []string{
		"./pkg",
		"./cmd",
		"./third_party",
		"./plugin",
		"./test",
		"./federation",
	} {
		if err := v.walk(root, v.updatePkg); err != nil {
			return err
		}
	}
	return nil
}

func (v *Venderor) updateSinglePkg(path string) error {
	pkg, err := v.ctx.ImportDir("./"+path, build.ImportComment)
	if err != nil {
		if _, ok := err.(*build.NoGoError); err != nil && ok {
			return nil
		} else {
			return err
		}
	}
	return v.updatePkg(path, "", pkg)
}

func (v *Venderor) updatePkg(path, _ string, pkg *build.Package) error {
	var rules []*bzl.Rule

	var attrs Attrs = make(Attrs)
	srcs := asExpr(merge(pkg.GoFiles, pkg.SFiles)).(*bzl.ListExpr)

	deps := v.extractDeps(pkg.Imports)

	if len(srcs.List) == 0 {
		return nil
	}
	attrs.Set("srcs", srcs)

	if len(deps.List) > 0 {
		attrs.Set("deps", deps)
	}

	if pkg.IsCommand() {
		rules = append(rules, newRule("go_binary", filepath.Base(pkg.Dir), attrs))
	} else {
		rules = append(rules, newRule("go_library", "go_default_library", attrs))
		if len(pkg.TestGoFiles) != 0 {
			rules = append(rules, newRule("go_test", "go_default_test", map[string]bzl.Expr{
				"srcs":    asExpr(pkg.TestGoFiles),
				"deps":    v.extractDeps(pkg.TestImports),
				"library": asExpr("go_default_library"),
			}))
		}
	}

	if len(pkg.XTestGoFiles) != 0 {
		rules = append(rules, newRule("go_test", "go_default_xtest", map[string]bzl.Expr{
			"srcs": asExpr(pkg.XTestGoFiles),
			"deps": v.extractDeps(pkg.XTestImports),
		}))
	}

	wrote, err := ReconcileRules(filepath.Join(path, "BUILD"), rules)
	if err != nil {
		return err
	}
	if wrote {
		fmt.Fprintf(os.Stderr, "wrote BUILD for %q\n", pkg.ImportPath)
	}
	return nil
}

func (v *Venderor) walkVendor() {
	var rules []*bzl.Rule
	if err := v.walk("./vendor", func(path, ipath string, pkg *build.Package) error {
		var attrs Attrs = make(Attrs)

		srcs := asExpr(
			apply(
				merge(pkg.GoFiles, pkg.SFiles),
				mapper(func(s string) string {
					return strings.TrimPrefix(filepath.Join(path, s), "vendor/")
				}),
			),
		).(*bzl.ListExpr)

		cgoSrcs := asExpr(
			apply(
				merge(pkg.CgoFiles, pkg.CFiles, pkg.CXXFiles, pkg.HFiles),
				mapper(func(s string) string {
					return strings.TrimPrefix(filepath.Join(path, s), "vendor/")
				}),
			),
		).(*bzl.ListExpr)

		deps := v.extractDeps(pkg.Imports)
		attrs.Set("srcs", srcs)

		if len(deps.List) > 0 {
			attrs.Set("deps", deps)
		}

		if pkg.IsCommand() {
			rules = append(rules, newRule("go_binary", v.resolve(ipath).tag, attrs))
		} else {
			if len(cgoSrcs.List) != 0 {
				cgoPname := v.resolve(ipath).tag + "_cgo"
				cgoDeps := v.extractDeps(pkg.TestImports)
				cgoRule := newRule("cgo_library", cgoPname, map[string]bzl.Expr{
					"srcs":      cgoSrcs,
					"clinkopts": asExpr([]string{"-ldl", "-lz", "-lm", "-lpthread", "-ldl"}),
				})
				rules = append(rules, cgoRule)
				if len(cgoDeps.List) != 0 {
					cgoRule.SetAttr("deps", cgoDeps)
				}
				attrs["library"] = asExpr(cgoPname)
			}
			rules = append(rules, newRule("go_library", v.resolve(ipath).tag, attrs))
		}
		return nil
	}); err != nil {
		glog.Fatalf("err: %v", err)
	}
	if _, err := ReconcileRules("./vendor/BUILD", rules); err != nil {
		glog.Fatalf("err: %v", err)
	}
}

func (v *Venderor) extractDeps(deps []string) *bzl.ListExpr {
	return asExpr(
		apply(
			merge(deps),
			filterer(func(s string) bool {
				pkg, err := v.ctx.Import(s, kubeRoot, build.ImportComment)
				if err != nil {
					return false
				}
				if pkg.Goroot {
					return false
				}
				return true
			}),
			mapper(func(s string) string {
				return v.resolve(s).String()
			}),
		),
	).(*bzl.ListExpr)
}

type Attrs map[string]bzl.Expr

func (a Attrs) Set(name string, expr bzl.Expr) {
	a[name] = expr
}

type Label struct {
	pkg, tag string
}

func (l Label) String() string {
	return fmt.Sprintf("//%v:%v", l.pkg, l.tag)
}

func asExpr(e interface{}) bzl.Expr {
	rv := reflect.ValueOf(e)
	switch rv.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return &bzl.LiteralExpr{Token: fmt.Sprintf("%d", e)}
	case reflect.Float32, reflect.Float64:
		return &bzl.LiteralExpr{Token: fmt.Sprintf("%f", e)}
	case reflect.String:
		return &bzl.StringExpr{Value: e.(string)}
	case reflect.Slice, reflect.Array:
		var list []bzl.Expr
		for i := 0; i < rv.Len(); i++ {
			list = append(list, asExpr(rv.Index(i).Interface()))
		}
		return &bzl.ListExpr{List: list}
	default:
		glog.Fatalf("Uh oh")
		return nil
	}
}

type Sed func(s []string) []string

func mapString(in []string, f func(string) string) []string {
	var out []string
	for _, s := range in {
		out = append(out, f(s))
	}
	return out
}

func mapper(f func(string) string) Sed {
	return func(in []string) []string {
		return mapString(in, f)
	}
}

func filterString(in []string, f func(string) bool) []string {
	var out []string
	for _, s := range in {
		if f(s) {
			out = append(out, s)
		}
	}
	return out
}

func filterer(f func(string) bool) Sed {
	return func(in []string) []string {
		return filterString(in, f)
	}
}

func apply(stream []string, seds ...Sed) []string {
	for _, sed := range seds {
		stream = sed(stream)
	}
	return stream
}

func merge(streams ...[]string) []string {
	var out []string
	for _, stream := range streams {
		out = append(out, stream...)
	}
	return out
}

func newRule(kind, name string, attrs map[string]bzl.Expr) *bzl.Rule {
	rule := &bzl.Rule{
		Call: &bzl.CallExpr{
			X: &bzl.LiteralExpr{Token: kind},
		},
	}
	rule.SetAttr("name", asExpr(name))
	for _, k := range sortKeys(attrs) {
		rule.SetAttr(k, attrs[k])
	}
	rule.SetAttr("tags", asExpr([]string{"automanaged"}))
	return rule
}

func sortKeys(attrs map[string]bzl.Expr) []string {
	ks := []string{}
	for k, _ := range attrs {
		ks = append(ks, k)
	}
	sort.Sort(orderedAttrs(ks))
	return ks
}

type orderedAttrs []string

var orderedAttrsPriority = map[string]int{
	"name":    1,
	"srcs":    2,
	"deps":    3,
	"library": 4,
	"tags":    5,
}

func (o orderedAttrs) Len() int {
	return len(o)
}

func (o orderedAttrs) Swap(i, j int) {
	o[i], o[j] = o[j], o[i]
}

func (o orderedAttrs) Less(i, j int) bool {
	ip, iok := orderedAttrsPriority[o[i]]
	jp, jok := orderedAttrsPriority[o[j]]
	if iok && jok {
		return ip < jp
	}
	if iok && !jok {
		return false
	}
	if jok && !iok {
		return true
	}
	return o[i] < o[j]
}

func ReconcileRules(path string, rules []*bzl.Rule) (bool, error) {
	info, err := os.Stat(path)
	if err != nil && os.IsNotExist(err) {
		f := &bzl.File{}
		writeHeaders(f)
		writeRules(f, rules)
		return true, writeFile(path, bzl.Format(f))
	} else if err != nil {
		return false, err
	}
	if info.IsDir() {
		return false, fmt.Errorf("%q cannot be a directory", path)
	}
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return false, err
	}
	f, err := bzl.Parse(path, b)
	if err != nil {
		return false, err
	}
	oldRules := make(map[string]*bzl.Rule)
	for _, r := range f.Rules("") {
		oldRules[r.Name()] = r
	}
	for _, r := range rules {
		o, ok := oldRules[r.Name()]
		if !ok {
			f.Stmt = append(f.Stmt, r.Call)
			continue
		}
		if !RuleIsManaged(o) {
			continue
		}
		reconcileAttr := func(o, n *bzl.Rule, name string) {
			if e := n.Attr(name); e != nil {
				o.SetAttr(name, e)
			} else {
				o.DelAttr(name)
			}
		}
		reconcileAttr(o, r, "srcs")
		reconcileAttr(o, r, "deps")
		reconcileAttr(o, r, "library")
		delete(oldRules, r.Name())
	}
	for _, r := range oldRules {
		if !RuleIsManaged(r) {
			continue
		}
		f.DelRules(r.Kind(), r.Name())
	}
	out := bzl.Format(f)
	orig, err := ioutil.ReadFile(path)
	if err != nil {
		return false, err
	}
	if bytes.Compare(out, orig) == 0 {
		return false, err
	}
	return true, writeFile(path, bzl.Format(f))
}

func RuleIsManaged(r *bzl.Rule) bool {
	var automanaged bool
	for _, tag := range r.AttrStrings("tags") {
		if tag == "automanaged" {
			automanaged = true
			break
		}
	}
	return automanaged
}

func writeFile(path string, b []byte) error {
	if *dryRun {
		return nil
	}
	return ioutil.WriteFile(path, b, 0644)

}
<|endoftext|>


<commit_before>// Package templateutil features LazyTemplate.
package templateutil

import (
	"bytes"
	"html/template"
	"io"
	"net/http"
	"os"
	"strconv"
	"sync"
	"time"
)

// NewLT constructs LazyTemplate.
func NewLT(readfunc readFunc, infofunc infoFunc, filename string) *LazyTemplate {
	return &LazyTemplate{
		readFunc: readfunc,
		infoFunc: infofunc,
		filename: filename,
	}
}

type readFunc func(string) ([]byte, error)      // shortcut for Asset-type func
type infoFunc func(string) (os.FileInfo, error) // shortcut for AssetInfo-type func

// LazyTemplate encloses template.Template.
// Lazy parse
// , always clone for bin templates
// , sometimes re-parse for dev-bins
// . NewLT is the constructor.
type LazyTemplate struct {
	Mutex    sync.Mutex // protects everything
	Template *template.Template

	// arguments to NewLT (all required)
	readFunc readFunc
	infoFunc infoFunc
	filename string

	// operationals
	nonDev     bool
	devModTime time.Time
	err        error
}

// MustInit is a Must func for LazyTemplate.
func MustInit(lt *LazyTemplate) {
	lt.Mutex.Lock()
	defer lt.Mutex.Unlock()
	lt.init()
	template.Must(lt.Template, lt.err)
}

func (lt *LazyTemplate) init() { // init is internal and lock-free.
	if lt.err != nil {
		return
	}
	if lt.nonDev && lt.Template != nil {
		// allgood#1: non-dev mode & have .Template
		return
	}
	text, err := lt.readFunc(lt.filename)
	if err != nil {
		lt.err = err
		return
	}
	if info, err := lt.infoFunc(lt.filename); err != nil {
		lt.err = err
		return
	} else if modtime := info.ModTime(); modtime == time.Unix(1400000000, 0) {
		lt.nonDev = true
	} else {
		if lt.Template != nil && modtime == lt.devModTime {
			// allgood#2: dev mode + modtime did not change
			return
		}
		lt.devModTime = modtime
	}
	lt.Template, lt.err = template.
		New(lt.filename).
		Option("missingkey=error").
		Delims("[[", "]]").
		Parse(string(text))
}

// Apply executes enclosed template into w.
func (lt *LazyTemplate) Apply(w http.ResponseWriter, data interface{}) {
	clone, err := func() (*template.Template, error) {
		lt.Mutex.Lock()
		defer lt.Mutex.Unlock()
		if lt.init(); lt.err != nil {
			return nil, lt.err
		}
		return lt.Template.Clone()
	}()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	buf := new(bytes.Buffer)
	if err := clone.Execute(buf, data); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	w.Header().Set("Content-Length", strconv.Itoa(buf.Len()))
	if _, err := io.Copy(w, buf); /* or w.Write(buf.Bytes()) */ err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}
<commit_msg>templateutil: read file after modtime checks<commit_after>// Package templateutil features LazyTemplate.
package templateutil

import (
	"bytes"
	"html/template"
	"io"
	"net/http"
	"os"
	"strconv"
	"sync"
	"time"
)

// NewLT constructs LazyTemplate.
func NewLT(readfunc readFunc, infofunc infoFunc, filename string) *LazyTemplate {
	return &LazyTemplate{
		readFunc: readfunc,
		infoFunc: infofunc,
		filename: filename,
	}
}

type readFunc func(string) ([]byte, error)      // shortcut for Asset-type func
type infoFunc func(string) (os.FileInfo, error) // shortcut for AssetInfo-type func

// LazyTemplate encloses template.Template.
// Lazy parse
// , always clone for bin templates
// , sometimes re-parse for dev-bins
// . NewLT is the constructor.
type LazyTemplate struct {
	Mutex    sync.Mutex // protects everything
	Template *template.Template

	// arguments to NewLT (all required)
	readFunc readFunc
	infoFunc infoFunc
	filename string

	// operationals
	nonDev     bool
	devModTime time.Time
	err        error
}

// MustInit is a Must func for LazyTemplate.
func MustInit(lt *LazyTemplate) {
	lt.Mutex.Lock()
	defer lt.Mutex.Unlock()
	lt.init()
	template.Must(lt.Template, lt.err)
}

func (lt *LazyTemplate) init() { // init is internal and lock-free.
	if lt.err != nil {
		return
	}
	if lt.nonDev && lt.Template != nil {
		// allgood#1: non-dev mode & have .Template
		return
	}
	if info, err := lt.infoFunc(lt.filename); err != nil {
		lt.err = err
		return
	} else if modtime := info.ModTime(); modtime == time.Unix(1400000000, 0) {
		lt.nonDev = true
	} else {
		if lt.Template != nil && modtime == lt.devModTime {
			// allgood#2: dev mode + modtime did not change
			return
		}
		lt.devModTime = modtime
	}
	text, err := lt.readFunc(lt.filename)
	if err != nil {
		lt.err = err
		return
	}
	lt.Template, lt.err = template.New(lt.filename).
		Delims("[[", "]]").Option("missingkey=error").
		Parse(string(text))
}

// Apply executes enclosed template into w.
func (lt *LazyTemplate) Apply(w http.ResponseWriter, data interface{}) {
	clone, err := func() (*template.Template, error) {
		lt.Mutex.Lock()
		defer lt.Mutex.Unlock()
		if lt.init(); lt.err != nil {
			return nil, lt.err
		}
		return lt.Template.Clone()
	}()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	buf := new(bytes.Buffer)
	if err := clone.Execute(buf, data); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	w.Header().Set("Content-Length", strconv.Itoa(buf.Len()))
	if _, err := io.Copy(w, buf); /* or w.Write(buf.Bytes()) */ err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}
<|endoftext|>


<commit_before>package main

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

	"github.com/gosexy/gettext"
	"github.com/lxc/lxd"
	"github.com/lxc/lxd/shared"
	"github.com/olekukonko/tablewriter"
	"gopkg.in/yaml.v2"
)

type imageCmd struct{}

func (c *imageCmd) showByDefault() bool {
	return true
}

var imageEditHelp string = gettext.Gettext(
	"### This is a yaml representation of the image properties.\n" +
		"### Any line starting with a '# will be ignored.\n" +
		"###\n" +
		"### Each property is represented by thee lines:\n" +
		"###\n" +
		"###  The first is 'imagetype: ' followed by an integer.  0 means\n" +
		"###  a short string, 1 means a long text value containing newlines.\n" +
		"###\n" +
		"###  This is followed by the key and value\n" +
		"###\n" +
		"###  An example would be:\n" +
		"### - imagetype: 0\n" +
		"###   key: os\n" +
		"###   value: Ubuntu\n")

func (c *imageCmd) usage() string {
	return gettext.Gettext(
		"lxc image import <tarball> [target] [--created-at=ISO-8601] [--expires-at=ISO-8601] [--fingerprint=HASH] [prop=value]\n" +
			"\n" +
			"lxc image delete [resource:]<image>\n" +
			"lxc image edit [resource:]\n" +
			"lxc image export [resource:]<image>\n" +
			"lxc image info [resource:]<image>\n" +
			"lxc image list [resource:] [filter]\n" +
			"\n" +
			"Lists the images at resource, or local images.\n" +
			"Filters are not yet supported.\n" +
			"\n" +
			"lxc image alias create <alias> <target>\n" +
			"lxc image alias delete <alias>\n" +
			"lxc image alias list [resource:]\n" +
			"create, delete, list image aliases\n")
}

func (c *imageCmd) flags() {}

func doImageAlias(config *lxd.Config, args []string) error {
	var remote string
	switch args[1] {
	case "list":
		/* alias list [<remote>:] */
		if len(args) > 2 {
			remote, _ = config.ParseRemoteAndContainer(args[2])
		} else {
			remote = ""
		}
		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}

		resp, err := d.ListAliases()
		if err != nil {
			return err
		}

		for _, url := range resp {
			/* /1.0/images/aliases/ALIAS_NAME */
			alias := fromUrl(url, "/1.0/images/aliases/")
			if alias == "" {
				fmt.Printf(gettext.Gettext("(Bad alias entry: %s\n"), url)
			} else {
				fmt.Println(alias)
			}
		}
		return nil
	case "create":
		/* alias create [<remote>:]<alias> <target> */
		if len(args) < 4 {
			return errArgs
		}
		remote, alias := config.ParseRemoteAndContainer(args[2])
		target := args[3]
		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}
		/* TODO - what about description? */
		err = d.PostAlias(alias, alias, target)
		return err
	case "delete":
		/* alias delete [<remote>:]<alias> */
		if len(args) < 3 {
			return errArgs
		}
		remote, alias := config.ParseRemoteAndContainer(args[2])
		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}
		err = d.DeleteAlias(alias)
		return err
	}
	return errArgs
}

func (c *imageCmd) run(config *lxd.Config, args []string) error {
	var remote string

	if len(args) < 1 {
		return errArgs
	}

	switch args[0] {
	case "alias":
		if len(args) < 2 {
			return errArgs
		}
		return doImageAlias(config, args)

	case "delete":
		/* delete [<remote>:]<image> */
		if len(args) < 2 {
			return errArgs
		}
		remote, inName := config.ParseRemoteAndContainer(args[1])
		if inName == "" {
			return errArgs
		}
		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}
		image := dereferenceAlias(d, inName)
		err = d.DeleteImage(image)
		return err

	case "info":
		if len(args) < 2 {
			return errArgs
		}
		remote, inName := config.ParseRemoteAndContainer(args[1])
		if inName == "" {
			return errArgs
		}
		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}
		image := dereferenceAlias(d, inName)
		info, err := d.GetImageInfo(image)
		if err != nil {
			return err
		}
		fmt.Printf("Hash: %s\n", info.Fingerprint)
		public := "no"
		if info.Public == 1 {
			public = "yes"
		}
		fmt.Printf("Public: %s\n", public)
		fmt.Printf("Properties:\n")
		for _, prop := range info.Properties {
			fmt.Printf("    %s: %s\n", prop.Key, prop.Value)
		}
		fmt.Printf("Aliases:\n")
		for _, alias := range info.Aliases {
			fmt.Printf("    - %s\n", alias.Name)
		}
		return nil

	case "import":
		if len(args) < 2 {
			return errArgs
		}
		imagefile := args[1]

		var properties []string
		if len(args) > 2 {
			split := strings.Split(args[2], "=")
			if len(split) == 1 {
				remote, _ = config.ParseRemoteAndContainer(args[2])
				if len(args) > 3 {
					properties = args[3:]
				} else {
					properties = []string{}
				}
			} else {
				properties = args[2:]
			}
		} else {
			remote = ""
			properties = []string{}
		}

		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}

		_, err = d.PostImage(imagefile, properties)
		if err != nil {
			return err
		}

		return nil

	case "list":
		if len(args) > 1 {
			remote, _ = config.ParseRemoteAndContainer(args[1])
		} else {
			remote = ""
		}
		// XXX TODO if name is not "" we'll want to filter for just that image name

		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}

		imagenames, err := d.ListImages()
		if err != nil {
			return err
		}

		images := []shared.ImageInfo{}
		prefix := "/1.0/images/"
		offset := len(prefix)
		for _, image := range imagenames {
			var plainname string
			if len(image) < offset+1 {
				fmt.Printf(gettext.Gettext("(Bad image entry: %s\n"), image)
				continue
			}
			plainname = image[offset:]
			info, err := d.GetImageInfo(plainname)
			if err != nil {
				// XXX should we warn?  bail?
				continue
			}
			images = append(images, *info)
		}

		return showImages(images)

	case "edit":
		if len(args) < 2 {
			return errArgs
		}
		remote, inName := config.ParseRemoteAndContainer(args[1])
		if inName == "" {
			return errArgs
		}
		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}

		image := dereferenceAlias(d, inName)
		fmt.Printf("for name %s got image %s\n", inName, image)
		if image == "" {
			image = inName
		}

		info, err := d.GetImageInfo(image)
		if err != nil {
			return err
		}

		properties := info.Properties
		editor := os.Getenv("VISUAL")
		if editor == "" {
			editor = os.Getenv("EDITOR")
			if editor == "" {
				editor = "vi"
			}
		}
		data, err := yaml.Marshal(&properties)
		f, err := ioutil.TempFile("", "lxc_image_")
		if err != nil {
			return err
		}
		fname := f.Name()
		if err = f.Chmod(0700); err != nil {
			f.Close()
			os.Remove(fname)
			return err
		}
		f.Write([]byte(imageEditHelp))
		f.Write(data)
		f.Close()
		defer os.Remove(fname)
		cmd := exec.Command(editor, fname)
		cmd.Stdin = os.Stdin
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		err = cmd.Run()
		if err != nil {
			return err
		}
		contents, err := ioutil.ReadFile(fname)
		if err != nil {
			return err
		}
		newdata := shared.ImageProperties{}
		err = yaml.Unmarshal(contents, &newdata)
		if err != nil {
			return err
		}
		err = d.PutImageProperties(image, newdata)
		return err

	case "export":
		if len(args) < 3 {
			return errArgs
		}

		remote, inName := config.ParseRemoteAndContainer(args[1])
		if inName == "" {
			return errArgs
		}
		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}

		image := dereferenceAlias(d, inName)

		_, err = d.ExportImage(image, args[2])
		if err != nil {
			return err
		}

		return nil
	default:
		return fmt.Errorf(gettext.Gettext("Unknown image command %s"), args[0])
	}
}

func fromUrl(url string, prefix string) string {
	offset := len(prefix)
	if len(url) < offset+1 {
		return ""
	}
	return url[offset:]
}

func dereferenceAlias(d *lxd.Client, inName string) string {
	imageList, err := d.ListImages()
	if err != nil {
		return ""
	}
	inLen := len(inName)
	for _, url := range imageList {
		n := fromUrl(url, "/1.0/images/")
		if n == "" {
			continue
		}
		if len(n) < inLen {
			continue
		}
		if n[:inLen] == inName {
			return n
		}
	}

	aliasList, err := d.ListAliases()
	if err == nil {
		for _, url := range aliasList {
			l := fromUrl(url, "/1.0/images/aliases/")
			if l == "" {
				continue
			}
			if l == inName {
				return d.GetAlias(l)
			}
		}
	}

	return ""
}

func shortestAlias(list shared.ImageAliases) string {
	shortest := ""
	for _, l := range list {
		if shortest == "" {
			shortest = l.Name
			continue
		}
		if len(l.Name) != 0 && len(l.Name) < len(shortest) {
			shortest = l.Name
		}
	}

	return shortest
}

func findDescription(props shared.ImageProperties) string {
	for _, p := range props {
		if p.Key == "description" {
			return p.Value
		}
	}
	return ""
}

func showImages(images []shared.ImageInfo) error {
	data := [][]string{}
	for _, image := range images {
		shortest := shortestAlias(image.Aliases)
		fp := image.Fingerprint[0:8]
		public := "no"
		description := findDescription(image.Properties)
		if image.Public == 1 {
			public = "yes"
		}
		data = append(data, []string{shortest, fp, public, description})
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"ALIAS", "HASH", "PUBLIC", "DESCRIPTION"})

	for _, v := range data {
		table.Append(v)
	}
	table.Render()

	return nil
}
<commit_msg>translate image list strings<commit_after>package main

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

	"github.com/gosexy/gettext"
	"github.com/lxc/lxd"
	"github.com/lxc/lxd/shared"
	"github.com/olekukonko/tablewriter"
	"gopkg.in/yaml.v2"
)

type imageCmd struct{}

func (c *imageCmd) showByDefault() bool {
	return true
}

var imageEditHelp string = gettext.Gettext(
	"### This is a yaml representation of the image properties.\n" +
		"### Any line starting with a '# will be ignored.\n" +
		"###\n" +
		"### Each property is represented by thee lines:\n" +
		"###\n" +
		"###  The first is 'imagetype: ' followed by an integer.  0 means\n" +
		"###  a short string, 1 means a long text value containing newlines.\n" +
		"###\n" +
		"###  This is followed by the key and value\n" +
		"###\n" +
		"###  An example would be:\n" +
		"### - imagetype: 0\n" +
		"###   key: os\n" +
		"###   value: Ubuntu\n")

func (c *imageCmd) usage() string {
	return gettext.Gettext(
		"lxc image import <tarball> [target] [--created-at=ISO-8601] [--expires-at=ISO-8601] [--fingerprint=HASH] [prop=value]\n" +
			"\n" +
			"lxc image delete [resource:]<image>\n" +
			"lxc image edit [resource:]\n" +
			"lxc image export [resource:]<image>\n" +
			"lxc image info [resource:]<image>\n" +
			"lxc image list [resource:] [filter]\n" +
			"\n" +
			"Lists the images at resource, or local images.\n" +
			"Filters are not yet supported.\n" +
			"\n" +
			"lxc image alias create <alias> <target>\n" +
			"lxc image alias delete <alias>\n" +
			"lxc image alias list [resource:]\n" +
			"create, delete, list image aliases\n")
}

func (c *imageCmd) flags() {}

func doImageAlias(config *lxd.Config, args []string) error {
	var remote string
	switch args[1] {
	case "list":
		/* alias list [<remote>:] */
		if len(args) > 2 {
			remote, _ = config.ParseRemoteAndContainer(args[2])
		} else {
			remote = ""
		}
		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}

		resp, err := d.ListAliases()
		if err != nil {
			return err
		}

		for _, url := range resp {
			/* /1.0/images/aliases/ALIAS_NAME */
			alias := fromUrl(url, "/1.0/images/aliases/")
			if alias == "" {
				fmt.Printf(gettext.Gettext("(Bad alias entry: %s\n"), url)
			} else {
				fmt.Println(alias)
			}
		}
		return nil
	case "create":
		/* alias create [<remote>:]<alias> <target> */
		if len(args) < 4 {
			return errArgs
		}
		remote, alias := config.ParseRemoteAndContainer(args[2])
		target := args[3]
		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}
		/* TODO - what about description? */
		err = d.PostAlias(alias, alias, target)
		return err
	case "delete":
		/* alias delete [<remote>:]<alias> */
		if len(args) < 3 {
			return errArgs
		}
		remote, alias := config.ParseRemoteAndContainer(args[2])
		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}
		err = d.DeleteAlias(alias)
		return err
	}
	return errArgs
}

func (c *imageCmd) run(config *lxd.Config, args []string) error {
	var remote string

	if len(args) < 1 {
		return errArgs
	}

	switch args[0] {
	case "alias":
		if len(args) < 2 {
			return errArgs
		}
		return doImageAlias(config, args)

	case "delete":
		/* delete [<remote>:]<image> */
		if len(args) < 2 {
			return errArgs
		}
		remote, inName := config.ParseRemoteAndContainer(args[1])
		if inName == "" {
			return errArgs
		}
		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}
		image := dereferenceAlias(d, inName)
		err = d.DeleteImage(image)
		return err

	case "info":
		if len(args) < 2 {
			return errArgs
		}
		remote, inName := config.ParseRemoteAndContainer(args[1])
		if inName == "" {
			return errArgs
		}
		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}
		image := dereferenceAlias(d, inName)
		info, err := d.GetImageInfo(image)
		if err != nil {
			return err
		}
		fmt.Printf(gettext.Gettext("Hash: %s\n"), info.Fingerprint)
		public := "no"
		if info.Public == 1 {
			public = "yes"
		}
		fmt.Printf(gettext.Gettext("Public: %s\n"), public)
		fmt.Printf(gettext.Gettext("Properties:\n"))
		for _, prop := range info.Properties {
			fmt.Printf("    %s: %s\n", prop.Key, prop.Value)
		}
		fmt.Printf(gettext.Gettext("Aliases:\n"))
		for _, alias := range info.Aliases {
			fmt.Printf("    - %s\n", alias.Name)
		}
		return nil

	case "import":
		if len(args) < 2 {
			return errArgs
		}
		imagefile := args[1]

		var properties []string
		if len(args) > 2 {
			split := strings.Split(args[2], "=")
			if len(split) == 1 {
				remote, _ = config.ParseRemoteAndContainer(args[2])
				if len(args) > 3 {
					properties = args[3:]
				} else {
					properties = []string{}
				}
			} else {
				properties = args[2:]
			}
		} else {
			remote = ""
			properties = []string{}
		}

		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}

		_, err = d.PostImage(imagefile, properties)
		if err != nil {
			return err
		}

		return nil

	case "list":
		if len(args) > 1 {
			remote, _ = config.ParseRemoteAndContainer(args[1])
		} else {
			remote = ""
		}
		// XXX TODO if name is not "" we'll want to filter for just that image name

		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}

		imagenames, err := d.ListImages()
		if err != nil {
			return err
		}

		images := []shared.ImageInfo{}
		prefix := "/1.0/images/"
		offset := len(prefix)
		for _, image := range imagenames {
			var plainname string
			if len(image) < offset+1 {
				fmt.Printf(gettext.Gettext("(Bad image entry: %s\n"), image)
				continue
			}
			plainname = image[offset:]
			info, err := d.GetImageInfo(plainname)
			if err != nil {
				// XXX should we warn?  bail?
				continue
			}
			images = append(images, *info)
		}

		return showImages(images)

	case "edit":
		if len(args) < 2 {
			return errArgs
		}
		remote, inName := config.ParseRemoteAndContainer(args[1])
		if inName == "" {
			return errArgs
		}
		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}

		image := dereferenceAlias(d, inName)
		if image == "" {
			image = inName
		}

		info, err := d.GetImageInfo(image)
		if err != nil {
			return err
		}

		properties := info.Properties
		editor := os.Getenv("VISUAL")
		if editor == "" {
			editor = os.Getenv("EDITOR")
			if editor == "" {
				editor = "vi"
			}
		}
		data, err := yaml.Marshal(&properties)
		f, err := ioutil.TempFile("", "lxc_image_")
		if err != nil {
			return err
		}
		fname := f.Name()
		if err = f.Chmod(0700); err != nil {
			f.Close()
			os.Remove(fname)
			return err
		}
		f.Write([]byte(imageEditHelp))
		f.Write(data)
		f.Close()
		defer os.Remove(fname)
		cmd := exec.Command(editor, fname)
		cmd.Stdin = os.Stdin
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		err = cmd.Run()
		if err != nil {
			return err
		}
		contents, err := ioutil.ReadFile(fname)
		if err != nil {
			return err
		}
		newdata := shared.ImageProperties{}
		err = yaml.Unmarshal(contents, &newdata)
		if err != nil {
			return err
		}
		err = d.PutImageProperties(image, newdata)
		return err

	case "export":
		if len(args) < 3 {
			return errArgs
		}

		remote, inName := config.ParseRemoteAndContainer(args[1])
		if inName == "" {
			return errArgs
		}
		d, err := lxd.NewClient(config, remote)
		if err != nil {
			return err
		}

		image := dereferenceAlias(d, inName)

		_, err = d.ExportImage(image, args[2])
		if err != nil {
			return err
		}

		return nil
	default:
		return fmt.Errorf(gettext.Gettext("Unknown image command %s"), args[0])
	}
}

func fromUrl(url string, prefix string) string {
	offset := len(prefix)
	if len(url) < offset+1 {
		return ""
	}
	return url[offset:]
}

func dereferenceAlias(d *lxd.Client, inName string) string {
	imageList, err := d.ListImages()
	if err != nil {
		return ""
	}
	inLen := len(inName)
	for _, url := range imageList {
		n := fromUrl(url, "/1.0/images/")
		if n == "" {
			continue
		}
		if len(n) < inLen {
			continue
		}
		if n[:inLen] == inName {
			return n
		}
	}

	aliasList, err := d.ListAliases()
	if err == nil {
		for _, url := range aliasList {
			l := fromUrl(url, "/1.0/images/aliases/")
			if l == "" {
				continue
			}
			if l == inName {
				return d.GetAlias(l)
			}
		}
	}

	return ""
}

func shortestAlias(list shared.ImageAliases) string {
	shortest := ""
	for _, l := range list {
		if shortest == "" {
			shortest = l.Name
			continue
		}
		if len(l.Name) != 0 && len(l.Name) < len(shortest) {
			shortest = l.Name
		}
	}

	return shortest
}

func findDescription(props shared.ImageProperties) string {
	for _, p := range props {
		if p.Key == "description" {
			return p.Value
		}
	}
	return ""
}

func showImages(images []shared.ImageInfo) error {
	data := [][]string{}
	for _, image := range images {
		shortest := shortestAlias(image.Aliases)
		fp := image.Fingerprint[0:8]
		public := "no"
		description := findDescription(image.Properties)
		if image.Public == 1 {
			public = "yes"
		}
		data = append(data, []string{shortest, fp, public, description})
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"ALIAS", "HASH", "PUBLIC", "DESCRIPTION"})

	for _, v := range data {
		table.Append(v)
	}
	table.Render()

	return nil
}
<|endoftext|>


<commit_before>package controllers

import (
	"encoding/json"
	"krypton-server/errors"
	"krypton-server/models"
	"net/http"

	"strings"

	"github.com/astaxie/beego"
)

type User struct {
	beego.Controller
}

//TODO: session
func (c *User) Login() {
	var params *UserLoginParams
	if json.Unmarshal(c.Ctx.Input.RequestBody, &params) != nil {
		c.Data["json"] = errors.NewErrorResponse(errors.InvalidParameter)
		c.ServeJSON()
		return
	}

	var (
		user *models.UserModel
		err  error
	)

	if strings.Contains(params.Name, "@") {
		user, err = models.User.FindByEmail(params.Name)
		if err != nil {
			c.Data["json"] = errors.NewErrorResponse(errors.InvalidParameter)
			c.ServeJSON()
			return
		}
	} else {
		user, err = models.User.FindByUsername(params.Name)
		if err != nil {
			c.Data["json"] = errors.NewErrorResponse(errors.InvalidParameter)
			c.ServeJSON()
			return
		}
	}

	c.Data["json"] = Newresponse(http.StatusOK, "", user)
	c.ServeJSON()
}

// register
func (c *User) Post() {
	var params *UserRegisterParams
	resp := &Response{}
	err := json.Unmarshal(c.Ctx.Input.RequestBody, &params)
	if err != nil {
		beego.Error(err)

	}

	user := models.User.NewUserModel(params.Username, params.Email, params.Password, "")
	err = user.Save()
	if err != nil {
		beego.Error(err)
	}

	resp.Status = http.StatusOK
	c.Data["json"] = resp
	c.ServeJSON()
}
<commit_msg>modify login<commit_after>package controllers

import (
	"encoding/json"
	"krypton-server/errors"
	"krypton-server/models"
	"net/http"

	"strings"

	"github.com/astaxie/beego"
)

type User struct {
	beego.Controller
}

//TODO: session
func (c *User) Login() {
	var params *UserLoginParams
	if json.Unmarshal(c.Ctx.Input.RequestBody, &params) != nil {
		c.Data["json"] = errors.NewErrorResponse(errors.InvalidParameter)
		c.ServeJSON()
		return
	}

	var (
		user *models.UserModel
		err  error
	)

	if strings.Contains(params.Name, "@") {
		user, err = models.User.FindByEmail(params.Name)
	} else {
		user, err = models.User.FindByUsername(params.Name)
	}
	if err != nil {
		c.Data["json"] = errors.NewErrorResponse(errors.InvalidParameter)
		c.ServeJSON()
		return
	}

	c.Data["json"] = Newresponse(http.StatusOK, "", user)
	c.ServeJSON()
}

// register
func (c *User) Post() {
	var params *UserRegisterParams
	resp := &Response{}
	err := json.Unmarshal(c.Ctx.Input.RequestBody, &params)
	if err != nil {
		beego.Error(err)

	}

	user := models.User.NewUserModel(params.Username, params.Email, params.Password, "")
	err = user.Save()
	if err != nil {
		beego.Error(err)
	}

	resp.Status = http.StatusOK
	c.Data["json"] = resp
	c.ServeJSON()
}
<|endoftext|>


<commit_before>package components

import (
	"fmt"
	"strings"
)

// Rendered - Rendered component.
type Rendered struct {
	// Body - Main body of the rendered component.
	Body string `json:"body,omitempty" yaml:"body,omitempty"`

	// Styles - List of styles.
	// They can be urls or list of css styles with prefix "data:text/css;".
	Styles []string `json:"styles,omitempty" yaml:"styles,omitempty"`

	// Scripts - List of scripts.
	// They can be urls or list of js scripts with prefix "data:text/javascript;".
	Scripts []string `json:"scripts,omitempty" yaml:"scripts,omitempty"`
}

// HTML - Merges styles and scripts into HTML body.
func (r *Rendered) HTML() string {
	// Return if no styles or scripts to add.
	if len(r.Styles) == 0 && len(r.Scripts) == 0 {
		return r.Body
	}

	var extras []string
	for _, src := range r.Styles {
		extras = append(extras, renderStyle(src))
	}
	for _, src := range r.Scripts {
		extras = append(extras, renderScript(src))
	}

	return insertExtras(r.Body, extras)
}

func insertExtras(html string, extras []string) (res string) {
	res, ok := insertBefore(html, "", extras)
	if ok {
		return
	}
	extras = []string{"", strings.Join(extras, ""), ""}
	res, ok = insertBefore(html, "<body", extras)
	if ok {
		return
	}
	return strings.Join([]string{
		"<!DOCTYPE html>",
		strings.Join(extras, ""),
		"", html, "",
	}, "")
}

func insertAfter(input, after string, extras []string) (_ string, ok bool) {
	index := strings.Index(input, after)
	if index == -1 {
		return
	}
	index = index + len(after)
	extra := strings.Join(extras, "")
	return strings.Join([]string{input[:index], extra, input[index:]}, ""), true
}

func insertBefore(input, before string, extras []string) (_ string, ok bool) {
	index := strings.Index(input, before)
	if index == -1 {
		return
	}
	extra := strings.Join(extras, "")
	return strings.Join([]string{input[:index], extra, input[index:]}, ""), true
}

func renderStyle(src string) string {
	if strings.HasPrefix(src, "://") || strings.HasPrefix(src, "http://") || strings.HasPrefix(src, "https://") {
		return fmt.Sprintf(`<link rel="stylesheet" href="%s" />`, src)
	}
	return fmt.Sprintf(`<style type="text/css">%s</style>`, src)
}

func renderScript(src string) string {
	if strings.HasPrefix(src, "://") || strings.HasPrefix(src, "http://") || strings.HasPrefix(src, "https://") {
		return fmt.Sprintf(`<script src="%s"></script>`, src)
	}
	return fmt.Sprintf(`<script type="text/javascript">%s</script>`, src)
}
<commit_msg>rendered: allow file paths in styles and scripts<commit_after>package components

import (
	"fmt"
	"strings"
)

// Rendered - Rendered component.
type Rendered struct {
	// Body - Main body of the rendered component.
	Body string `json:"body,omitempty" yaml:"body,omitempty"`

	// Styles - List of styles.
	// They can be urls or list of css styles with prefix "data:text/css;".
	Styles []string `json:"styles,omitempty" yaml:"styles,omitempty"`

	// Scripts - List of scripts.
	// They can be urls or list of js scripts with prefix "data:text/javascript;".
	Scripts []string `json:"scripts,omitempty" yaml:"scripts,omitempty"`
}

// HTML - Merges styles and scripts into HTML body.
func (r *Rendered) HTML() string {
	// Return if no styles or scripts to add.
	if len(r.Styles) == 0 && len(r.Scripts) == 0 {
		return r.Body
	}

	var extras []string
	for _, src := range r.Styles {
		extras = append(extras, renderStyle(src))
	}
	for _, src := range r.Scripts {
		extras = append(extras, renderScript(src))
	}

	return insertExtras(r.Body, extras)
}

func insertExtras(html string, extras []string) (res string) {
	res, ok := insertBefore(html, "", extras)
	if ok {
		return
	}
	extras = []string{"", strings.Join(extras, ""), ""}
	res, ok = insertBefore(html, "<body", extras)
	if ok {
		return
	}
	return strings.Join([]string{
		"<!DOCTYPE html>",
		strings.Join(extras, ""),
		"", html, "",
	}, "")
}

func insertAfter(input, after string, extras []string) (_ string, ok bool) {
	index := strings.Index(input, after)
	if index == -1 {
		return
	}
	index = index + len(after)
	extra := strings.Join(extras, "")
	return strings.Join([]string{input[:index], extra, input[index:]}, ""), true
}

func insertBefore(input, before string, extras []string) (_ string, ok bool) {
	index := strings.Index(input, before)
	if index == -1 {
		return
	}
	extra := strings.Join(extras, "")
	return strings.Join([]string{input[:index], extra, input[index:]}, ""), true
}

func renderStyle(src string) string {
	if hasURLPrefix(src) {
		return fmt.Sprintf(`<link rel="stylesheet" href="%s" />`, src)
	}
	return fmt.Sprintf(`<style type="text/css">%s</style>`, src)
}

func renderScript(src string) string {
	if hasURLPrefix(src) {
		return fmt.Sprintf(`<script src="%s"></script>`, src)
	}
	return fmt.Sprintf(`<script type="text/javascript">%s</script>`, src)
}

var schemes = []string{
	"http://",
	"https://",
	"://",
}

func hasURLPrefix(src string) bool {
	if strings.HasPrefix(src, "/") && len(src) <= 255 {
		return true
	}
	return strings.HasPrefix(src, "://") || strings.HasPrefix(src, "http://") || strings.HasPrefix(src, "https://")
}
<|endoftext|>


<commit_before>// This is a defensive test against the CC no longer knowing how to find an
// existing app's bits. This can happen if the scheme of the app's paths in
// the blobstore changes without being backwards-compatible.
//
// If this is not caught before a deploy, all running apps will go down, as
// during evacuation of the DEAs, the CC will not know to look in their old
// path format in the blob store.
//
// This tests pushes the app once (checking if it already exists), and then
// just restarts it on later runs.

package apps

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/vito/cmdtest"
	. "github.com/vito/cmdtest/matchers"

	. "github.com/cloudfoundry/cf-acceptance-tests/helpers"
	. "github.com/pivotal-cf-experimental/cf-test-helpers/cf"
)

var _ = Describe("An application that's already been pushed", func() {
	var appName string

	BeforeEach(func() {
		appName = LoadConfig().PersistentAppHost
		Expect(Cf("target", "-s", "persistent-space")).To(ExitWith(0))

		Expect(Cf("app", appName)).To(SayBranches(
			cmdtest.ExpectBranch{
				"not found",
				func() {
					Expect(
						Cf("push", appName, "-p", NewAssets().Dora),
					).To(Say("App started"))
				},
			},
			cmdtest.ExpectBranch{
				"running",
				func() {
				},
			},
		))
	})

	It("can be restarted and still come up", func() {
		Eventually(Curling(appName, "/", LoadConfig().AppsDomain)).Should(Say("Hi, I'm Dora!"))

		Expect(Cf("stop", appName)).To(Say("OK"))

		Eventually(Curling(appName, "/", LoadConfig().AppsDomain)).Should(Say("404"))

		Expect(Cf("start", appName)).To(Say("App started"))

		Eventually(Curling(appName, "/", LoadConfig().AppsDomain)).Should(Say("Hi, I'm Dora!"))
	})
})
<commit_msg>Assert that 'cf stop' exits with a status code zero<commit_after>// This is a defensive test against the CC no longer knowing how to find an
// existing app's bits. This can happen if the scheme of the app's paths in
// the blobstore changes without being backwards-compatible.
//
// If this is not caught before a deploy, all running apps will go down, as
// during evacuation of the DEAs, the CC will not know to look in their old
// path format in the blob store.
//
// This tests pushes the app once (checking if it already exists), and then
// just restarts it on later runs.

package apps

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/vito/cmdtest"
	. "github.com/vito/cmdtest/matchers"

	. "github.com/cloudfoundry/cf-acceptance-tests/helpers"
	. "github.com/pivotal-cf-experimental/cf-test-helpers/cf"
)

var _ = Describe("An application that's already been pushed", func() {
	var appName string

	BeforeEach(func() {
		appName = LoadConfig().PersistentAppHost
		Expect(Cf("target", "-s", "persistent-space")).To(ExitWith(0))

		Expect(Cf("app", appName)).To(SayBranches(
			cmdtest.ExpectBranch{
				"not found",
				func() {
					Expect(
						Cf("push", appName, "-p", NewAssets().Dora),
					).To(Say("App started"))
				},
			},
			cmdtest.ExpectBranch{"running", func() {}},
		))
	})

	It("can be restarted and still come up", func() {
		Eventually(Curling(appName, "/", LoadConfig().AppsDomain)).Should(Say("Hi, I'm Dora!"))

		Expect(Cf("stop", appName)).To(ExitWith(0))

		Eventually(Curling(appName, "/", LoadConfig().AppsDomain)).Should(Say("404"))

		Expect(Cf("start", appName)).To(Say("App started"))

		Eventually(Curling(appName, "/", LoadConfig().AppsDomain)).Should(Say("Hi, I'm Dora!"))
	})
})
<|endoftext|>


<commit_before>package lib

import (
	"fmt"
	"os"
	"os/exec"
	"path"
	"runtime"

	git "github.com/libgit2/git2go"
	"github.com/sirupsen/logrus"
)

var DefaultCheckoutOptions = &git.CheckoutOpts{
	Strategy: git.CheckoutForce,
}

func Build(m *Manifest, args []string) error {
	repo, err := git.OpenRepository(m.Dir)
	if err != nil {
		return err
	}

	oid, err := git.NewOid(m.Sha)
	if err != nil {
		return err
	}

	commit, err := repo.LookupCommit(oid)
	if err != nil {
		return err
	}

	tree, err := commit.Tree()
	if err != nil {
		return err
	}

	// TODO: Confirm the strategy is correct
	err = repo.CheckoutTree(tree, DefaultCheckoutOptions)
	if err != nil {
		return err
	}

	defer checkoutHead(repo)

	for _, a := range m.Applications {
		if !canBuildHere(a) {
			continue
		}

		err := buildOne(m.Dir, a, args)
		if err != nil {
			return err
		}
	}

	return nil
}

func buildOne(dir string, app *Application, args []string) error {
	cmd := exec.Command(app.Build)
	cmd.Env = append(os.Environ(), fmt.Sprintf("MBT_VERSION=%s", app.Version))
	cmd.Dir = path.Join(dir, app.Path)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Args = append(cmd.Args, append(app.Args, args...)...)
	err := cmd.Run()
	return err
}

func canBuildHere(app *Application) bool {
	for _, p := range app.BuildPlatforms {
		if p == runtime.GOOS {
			return true
		}
	}

	return false
}

func checkoutHead(repo *git.Repository) {
	err := repo.CheckoutHead(DefaultCheckoutOptions)
	if err != nil {
		logrus.Warnf("failed to checkout head: %s", err)
	}
}
<commit_msg>populate properties in the env.<commit_after>package lib

import (
	"fmt"
	"os"
	"os/exec"
	"path"
	"runtime"
	"strings"

	git "github.com/libgit2/git2go"
	"github.com/sirupsen/logrus"
)

var DefaultCheckoutOptions = &git.CheckoutOpts{
	Strategy: git.CheckoutForce,
}

func Build(m *Manifest, args []string) error {
	repo, err := git.OpenRepository(m.Dir)
	if err != nil {
		return err
	}

	oid, err := git.NewOid(m.Sha)
	if err != nil {
		return err
	}

	commit, err := repo.LookupCommit(oid)
	if err != nil {
		return err
	}

	tree, err := commit.Tree()
	if err != nil {
		return err
	}

	// TODO: Confirm the strategy is correct
	err = repo.CheckoutTree(tree, DefaultCheckoutOptions)
	if err != nil {
		return err
	}

	defer checkoutHead(repo)

	for _, a := range m.Applications {
		if !canBuildHere(a) {
			continue
		}

		err := buildOne(m.Dir, a, args)
		if err != nil {
			return err
		}
	}

	return nil
}

func setupAppBuildEnvironment(app *Application) []string {
	r := []string{
		fmt.Sprintf("MBT_APP_VERSION=%s", app.Version),
	}

	for k, v := range app.Properties {
		r = append(r, fmt.Sprintf("MBT_APP_PROPERTY_%s=%s", strings.ToUpper(k), v.(string)))
	}

	return r
}

func buildOne(dir string, app *Application, args []string) error {
	cmd := exec.Command(app.Build)
	cmd.Env = append(os.Environ(), setupAppBuildEnvironment(app)...)
	cmd.Dir = path.Join(dir, app.Path)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Args = append(cmd.Args, append(app.Args, args...)...)
	err := cmd.Run()
	return err
}

func canBuildHere(app *Application) bool {
	for _, p := range app.BuildPlatforms {
		if p == runtime.GOOS {
			return true
		}
	}

	return false
}

func checkoutHead(repo *git.Repository) {
	err := repo.CheckoutHead(DefaultCheckoutOptions)
	if err != nil {
		logrus.Warnf("failed to checkout head: %s", err)
	}
}
<|endoftext|>


<commit_before>// Package goawk is an implementation of AWK written in Go.
//
// You can use the command-line "goawk" command or call AWK from your
// Go programs using the "interp" package. The command-line program
// has the same interface as regular awk:
//
//     goawk [-F fs] [-v var=value] [-f progfile | 'prog'] [file ...]
//
// The -F flag specifies the field separator (the default is to split
// on whitespace). The -v flag allows you to set a variable to a
// given value (multiple -v flags allowed). The -f flag allows you to
// read AWK source from a file instead of the 'prog' command-line
// argument. The rest of the arguments are input filenames (default
// is to read from stdin).
//
// To use GoAWK in your Go programs, see README.md or the "interp"
// docs.
//
package main

/*

TODO:
- improve goawk.go docstring and interp docs for GoDoc
- other interp tests
  - tests for recursion, locals vs globals, array params, etc
  - fix broken interp tests due to syntax handling
- performance testing: I/O, allocations, CPU
  + add "go test" benchmarks for various common workloads
  + faster to do switch+case for binary funcs instead of map of funcs?
  + getVar/setVar overhead -- can resolve stuff at compile-time
  + defer in eval/exec -- will this help?

NICE TO HAVE:
- parser: ensure vars aren't used in array context and vice-versa
- interp: flag "unexpected comma-separated expression" at parse time

*/

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"runtime/pprof"
	"strings"

	"github.com/benhoyt/goawk/interp"
	"github.com/benhoyt/goawk/lexer"
	"github.com/benhoyt/goawk/parser"
)

func main() {
	progFile := flag.String("f", "", "load AWK source from `progfile`")
	fieldSep := flag.String("F", " ", "field separator")
	var vars varFlags
	flag.Var(&vars, "v", "variable `assignment` (name=value)")

	debug := flag.Bool("d", false, "debug mode (print parsed AST to stderr)")
	cpuprofile := flag.String("cpuprofile", "", "write CPU profile to `file`")
	memprofile := flag.String("memprofile", "", "write memory profile to `file`")

	flag.Parse()
	args := flag.Args()

	var src []byte
	if *progFile != "" {
		var err error
		src, err = ioutil.ReadFile(*progFile)
		if err != nil {
			errorExit("%s", err)
		}
	} else {
		if len(args) < 1 {
			errorExit("usage: goawk [-F fs] [-v var=value] [-f progfile | 'prog'] [file ...]")
		}
		src = []byte(args[0])
		args = args[1:]
	}

	prog, err := parser.ParseProgram(src)
	if err != nil {
		errMsg := fmt.Sprintf("%s", err)
		if err, ok := err.(*parser.ParseError); ok {
			showSourceLine(src, err.Position, len(errMsg))
		}
		errorExit(errMsg)
	}
	if *debug {
		fmt.Fprintln(os.Stderr, prog)
	}

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			errorExit("could not create CPU profile: %v", err)
		}
		if err := pprof.StartCPUProfile(f); err != nil {
			errorExit("could not start CPU profile: %v", err)
		}
	}

	p := interp.New(nil, nil)
	p.SetVar("FS", *fieldSep)
	for _, v := range vars {
		p.SetVar(v.name, v.value)
	}

	interpArgs := []string{filepath.Base(os.Args[0])}
	interpArgs = append(interpArgs, args...)
	p.SetArgs(interpArgs)
	err = p.Exec(prog, os.Stdin, args)
	if err != nil {
		errorExit("%s", err)
	}

	if *cpuprofile != "" {
		pprof.StopCPUProfile()
	}

	if *memprofile != "" {
		f, err := os.Create(*memprofile)
		if err != nil {
			errorExit("could not create memory profile: %v", err)
		}
		runtime.GC() // get up-to-date statistics
		if err := pprof.WriteHeapProfile(f); err != nil {
			errorExit("could not write memory profile: %v", err)
		}
		f.Close()
	}

	os.Exit(p.ExitStatus())
}

func showSourceLine(src []byte, pos lexer.Position, dividerLen int) {
	divider := strings.Repeat("-", dividerLen)
	if divider != "" {
		fmt.Fprintln(os.Stderr, divider)
	}
	lines := bytes.Split(src, []byte{'\n'})
	srcLine := string(lines[pos.Line-1])
	numTabs := strings.Count(srcLine[:pos.Column-1], "\t")
	fmt.Fprintln(os.Stderr, strings.Replace(srcLine, "\t", "    ", -1))
	fmt.Fprintln(os.Stderr, strings.Repeat(" ", pos.Column-1)+strings.Repeat("   ", numTabs)+"^")
	if divider != "" {
		fmt.Fprintln(os.Stderr, divider)
	}
}

func errorExit(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, format+"\n", args...)
	os.Exit(1)
}

type varFlag struct {
	name  string
	value string
}

type varFlags []varFlag

func (v *varFlags) String() string {
	return ""
}

func (v *varFlags) Set(value string) error {
	parts := strings.SplitN(value, "=", 2)
	if len(parts) != 2 {
		return errors.New("must be name=value")
	}
	*v = append(*v, varFlag{parts[0], parts[1]})
	return nil
}
<commit_msg>TODO tweaks<commit_after>// Package goawk is an implementation of AWK written in Go.
//
// You can use the command-line "goawk" command or call AWK from your
// Go programs using the "interp" package. The command-line program
// has the same interface as regular awk:
//
//     goawk [-F fs] [-v var=value] [-f progfile | 'prog'] [file ...]
//
// The -F flag specifies the field separator (the default is to split
// on whitespace). The -v flag allows you to set a variable to a
// given value (multiple -v flags allowed). The -f flag allows you to
// read AWK source from a file instead of the 'prog' command-line
// argument. The rest of the arguments are input filenames (default
// is to read from stdin).
//
// To use GoAWK in your Go programs, see README.md or the "interp"
// docs.
//
package main

/*

TODO:
- other interp tests
  - tests for recursion, locals vs globals, array params, etc
- performance testing: I/O, allocations, CPU
  + add "go test" benchmarks for various common workloads
  + faster to do switch+case for binary funcs instead of map of funcs?
  + getVar/setVar overhead -- can resolve stuff at compile-time
  + defer in eval/exec -- will this help?

NICE TO HAVE:
- parser: ensure vars aren't used in array context and vice-versa
- interp: flag "unexpected comma-separated expression" at parse time
- fix broken interp tests due to syntax handling

*/

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"runtime/pprof"
	"strings"

	"github.com/benhoyt/goawk/interp"
	"github.com/benhoyt/goawk/lexer"
	"github.com/benhoyt/goawk/parser"
)

func main() {
	progFile := flag.String("f", "", "load AWK source from `progfile`")
	fieldSep := flag.String("F", " ", "field separator")
	var vars varFlags
	flag.Var(&vars, "v", "variable `assignment` (name=value)")

	debug := flag.Bool("d", false, "debug mode (print parsed AST to stderr)")
	cpuprofile := flag.String("cpuprofile", "", "write CPU profile to `file`")
	memprofile := flag.String("memprofile", "", "write memory profile to `file`")

	flag.Parse()
	args := flag.Args()

	var src []byte
	if *progFile != "" {
		var err error
		src, err = ioutil.ReadFile(*progFile)
		if err != nil {
			errorExit("%s", err)
		}
	} else {
		if len(args) < 1 {
			errorExit("usage: goawk [-F fs] [-v var=value] [-f progfile | 'prog'] [file ...]")
		}
		src = []byte(args[0])
		args = args[1:]
	}

	prog, err := parser.ParseProgram(src)
	if err != nil {
		errMsg := fmt.Sprintf("%s", err)
		if err, ok := err.(*parser.ParseError); ok {
			showSourceLine(src, err.Position, len(errMsg))
		}
		errorExit(errMsg)
	}
	if *debug {
		fmt.Fprintln(os.Stderr, prog)
	}

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			errorExit("could not create CPU profile: %v", err)
		}
		if err := pprof.StartCPUProfile(f); err != nil {
			errorExit("could not start CPU profile: %v", err)
		}
	}

	p := interp.New(nil, nil)
	p.SetVar("FS", *fieldSep)
	for _, v := range vars {
		p.SetVar(v.name, v.value)
	}

	interpArgs := []string{filepath.Base(os.Args[0])}
	interpArgs = append(interpArgs, args...)
	p.SetArgs(interpArgs)
	err = p.Exec(prog, os.Stdin, args)
	if err != nil {
		errorExit("%s", err)
	}

	if *cpuprofile != "" {
		pprof.StopCPUProfile()
	}

	if *memprofile != "" {
		f, err := os.Create(*memprofile)
		if err != nil {
			errorExit("could not create memory profile: %v", err)
		}
		runtime.GC() // get up-to-date statistics
		if err := pprof.WriteHeapProfile(f); err != nil {
			errorExit("could not write memory profile: %v", err)
		}
		f.Close()
	}

	os.Exit(p.ExitStatus())
}

func showSourceLine(src []byte, pos lexer.Position, dividerLen int) {
	divider := strings.Repeat("-", dividerLen)
	if divider != "" {
		fmt.Fprintln(os.Stderr, divider)
	}
	lines := bytes.Split(src, []byte{'\n'})
	srcLine := string(lines[pos.Line-1])
	numTabs := strings.Count(srcLine[:pos.Column-1], "\t")
	fmt.Fprintln(os.Stderr, strings.Replace(srcLine, "\t", "    ", -1))
	fmt.Fprintln(os.Stderr, strings.Repeat(" ", pos.Column-1)+strings.Repeat("   ", numTabs)+"^")
	if divider != "" {
		fmt.Fprintln(os.Stderr, divider)
	}
}

func errorExit(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, format+"\n", args...)
	os.Exit(1)
}

type varFlag struct {
	name  string
	value string
}

type varFlags []varFlag

func (v *varFlags) String() string {
	return ""
}

func (v *varFlags) Set(value string) error {
	parts := strings.SplitN(value, "=", 2)
	if len(parts) != 2 {
		return errors.New("must be name=value")
	}
	*v = append(*v, varFlag{parts[0], parts[1]})
	return nil
}
<|endoftext|>


<commit_before>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * io/byte_pool.go                                        *
 *                                                        *
 * byte pool for Go.                                      *
 *                                                        *
 * LastModified: Sep 1, 2016                              *
 * Author: Ma Bingyao <andot@hprose.com>                  *
 *                                                        *
\**********************************************************/

package io

import (
	"sync"
	"time"
)

const (
	poolNum = 20
	maxSize = 1 << (poolNum + 5)
)

type pool struct {
	list   [][]byte
	locker sync.Mutex
}

var bytePool = struct {
	pools [poolNum]pool
	timer *time.Timer
	d     time.Duration
}{}

func init() {
	bytePool.d = time.Second * 4
	if bytePool.d > 0 {
		bytePool.timer = time.AfterFunc(bytePool.d, func() {
			drain()
			bytePool.timer.Reset(bytePool.d)
		})
	}
}

func drain() {
	n := len(bytePool.pools)
	for i := 0; i < n; i++ {
		p := &bytePool.pools[i]
		p.locker.Lock()
		p.list = p.list[:len(p.list)>>1]
		p.locker.Unlock()
	}
}

// Alloc a []byte from pool.
func Alloc(size int) []byte {
	if size < 1 || size > maxSize {
		return make([]byte, size)
	}
	if bytePool.d > 0 {
		bytePool.timer.Reset(bytePool.d)
	}
	var bytes []byte
	capacity := pow2roundup(size)
	if capacity < 64 {
		capacity = 64
	}
	p := &bytePool.pools[log2(capacity)-6]
	p.locker.Lock()
	if n := len(p.list); n > 0 {
		bytes = p.list[n-1]
		p.list[n-1] = nil
		p.list = p.list[:n-1]
	}
	p.locker.Unlock()
	if bytes == nil {
		return make([]byte, size, capacity)
	}
	return bytes[:size]
}

// Recycle a []byte to pool.
func Recycle(bytes []byte) {
	capacity := cap(bytes)
	if capacity < 64 || capacity > maxSize || capacity != pow2roundup(capacity) {
		return
	}
	p := &bytePool.pools[log2(capacity)-6]
	p.locker.Lock()
	p.list = append(p.list, bytes[:capacity])
	p.locker.Unlock()
}
<commit_msg>Fixed drain<commit_after>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * io/byte_pool.go                                        *
 *                                                        *
 * byte pool for Go.                                      *
 *                                                        *
 * LastModified: Sep 1, 2016                              *
 * Author: Ma Bingyao <andot@hprose.com>                  *
 *                                                        *
\**********************************************************/

package io

import (
	"sync"
	"time"
)

const (
	poolNum = 20
	maxSize = 1 << (poolNum + 5)
)

type pool struct {
	list   [][]byte
	locker sync.Mutex
}

var bytePool = struct {
	pools [poolNum]pool
	timer *time.Timer
	d     time.Duration
}{}

func init() {
	bytePool.d = time.Second << 2
	if bytePool.d > 0 {
		bytePool.timer = time.AfterFunc(bytePool.d, func() {
			drain()
			bytePool.timer.Reset(bytePool.d)
		})
	}
}

func drain() {
	n := len(bytePool.pools)
	for i := 0; i < n; i++ {
		p := &bytePool.pools[i]
		p.locker.Lock()
		l := len(p.list)
		for j := l - 1; j >= l>>1; j-- {
			p.list[j] = nil
		}
		p.list = p.list[:l>>1]
		p.locker.Unlock()
	}
}

// Alloc a []byte from pool.
func Alloc(size int) []byte {
	if size < 1 || size > maxSize {
		return make([]byte, size)
	}
	if bytePool.d > 0 {
		bytePool.timer.Reset(bytePool.d)
	}
	var bytes []byte
	capacity := pow2roundup(size)
	if capacity < 64 {
		capacity = 64
	}
	p := &bytePool.pools[log2(capacity)-6]
	p.locker.Lock()
	if n := len(p.list); n > 0 {
		bytes = p.list[n-1]
		p.list[n-1] = nil
		p.list = p.list[:n-1]
	}
	p.locker.Unlock()
	if bytes == nil {
		return make([]byte, size, capacity)
	}
	return bytes[:size]
}

// Recycle a []byte to pool.
func Recycle(bytes []byte) {
	capacity := cap(bytes)
	if capacity < 64 || capacity > maxSize || capacity != pow2roundup(capacity) {
		return
	}
	p := &bytePool.pools[log2(capacity)-6]
	p.locker.Lock()
	p.list = append(p.list, bytes[:capacity])
	p.locker.Unlock()
}
<|endoftext|>