<commit_before>package main

import (
	"fmt"
	"strings"
	"testing"
	"time"

	"github.com/go-openapi/runtime"
	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack"
	"github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes"
	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
	"github.com/gophercloud/gophercloud/openstack/identity/v3/tokens"
	"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/loadbalancers"
	"github.com/gophercloud/gophercloud/openstack/objectstorage/v1/containers"
	"github.com/gophercloud/gophercloud/openstack/objectstorage/v1/objects"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"k8s.io/apimachinery/pkg/util/wait"

	"github.com/sapcc/kubernikus/pkg/api/client/operations"
	"github.com/sapcc/kubernikus/pkg/api/models"
	etcd_util "github.com/sapcc/kubernikus/pkg/util/etcd"
	"github.com/sapcc/kubernikus/test/e2e/framework"
)

const (
	CleanupBackupContainerDeleteInterval = 1 * time.Second
	CleanupBackupContainerDeleteTimeout  = 1 * time.Minute
)

type PyrolisisTests struct {
	Kubernikus *framework.Kubernikus
	OpenStack  *framework.OpenStack
	Reuse      bool
	Isolate    bool
}

func (p *PyrolisisTests) Run(t *testing.T) {
	if p.Reuse == false && p.Isolate == false {
		quota := t.Run("SettingKlustersOnFire", p.SettingKlustersOnFire)
		require.True(t, quota, "Klusters must burn")

		t.Run("Wait", func(t *testing.T) {
			t.Run("Klusters", p.WaitForE2EKlustersTerminated)
		})

		t.Run("CleanupVolumes", p.CleanupVolumes)
		t.Run("CleanupInstances", p.CleanupInstances)
		t.Run("CleanupLoadbalancers", p.CleanupLoadbalancers)
	}

	cleanupStorageContainer := t.Run("CleanupBackupStorageContainers", p.CleanupBackupStorageContainers)
	require.True(t, cleanupStorageContainer, "Etcd backup storage container cleanup failed")
}

func (p *PyrolisisTests) SettingKlustersOnFire(t *testing.T) {
	klusters, err := listKlusters(p.Kubernikus.Client.Operations, p.Kubernikus.AuthInfo)
	require.NoError(t, err, "There should be no error while listing klusters")

	for _, kluster := range klusters {
		if strings.HasPrefix(kluster.Name, "e2e-") {
			t.Run(fmt.Sprintf("TerminatingKluster-%v", kluster.Name), func(t *testing.T) {
				_, err := p.Kubernikus.Client.Operations.TerminateCluster(
					operations.NewTerminateClusterParams().WithName(kluster.Name),
					p.Kubernikus.AuthInfo,
				)
				assert.NoError(t, err, "There should be no error while terminating klusters")
			})
		}
	}
}

func listKlusters(client *operations.Client, authinfo runtime.ClientAuthInfoWriter) ([]*models.Kluster, error) {
	res, err := client.ListClusters(
		operations.NewListClustersParams(),
		authinfo,
	)

	if err != nil {
		return nil, err
	}

	return res.Payload, nil
}

func (p *PyrolisisTests) WaitForE2EKlustersTerminated(t *testing.T) {
	err := p.Kubernikus.WaitForKlusters("e2e-", 0, WaitForKlusterToBeDeletedTimeout)
	assert.NoError(t, err, "E2E Klusters didn't burn down in time")
}

func (p *PyrolisisTests) CleanupBackupStorageContainers(t *testing.T) {
	storageClient, err := openstack.NewObjectStorageV1(p.OpenStack.Provider, gophercloud.EndpointOpts{})
	require.NoError(t, err, "Could not create object storage client")

	containersListOpts := containers.ListOpts{
		Full: false,
	}
	allPages, err := containers.List(storageClient, containersListOpts).AllPages()
	require.NoError(t, err, "There should be no error while listing storage containers")

	allContainers, err := containers.ExtractNames(allPages)
	require.NoError(t, err, "There should be no error while extracting storage containers")

	klusters, err := listKlusters(p.Kubernikus.Client.Operations, p.Kubernikus.AuthInfo)
	require.NoError(t, err, "There should be no error while listing klusters")

	// do not delete containers where there is still a kluster running
	var containersToDelete []string
	for _, container := range allContainers {
		found := false

		for _, kluster := range klusters {
			if strings.HasPrefix(container, fmt.Sprintf("%s-%s", etcd_util.BackupStorageContainerBase, kluster.Name)) {
				found = true
			}
		}

		if !found {
			containersToDelete = append(containersToDelete, container)
		}
	}

	objectsListOpts := objects.ListOpts{
		Full: false,
	}

	for _, container := range containersToDelete {
		if strings.HasPrefix(container, etcd_util.BackupStorageContainerBase) {
			allPages, err := objects.List(storageClient, container, objectsListOpts).AllPages()
			require.NoError(t, err, "There should be no error while lising objetcs in container %s", container)

			allObjects, err := objects.ExtractNames(allPages)
			require.NoError(t, err, "There should be no error while extracting objetcs names for container %s", container)

			for _, object := range allObjects {
				_, err := objects.Delete(storageClient, container, object, objects.DeleteOpts{}).Extract()
				//Ignore 404 from swift, this can happen for a successful delete becase of the eventual consistency
				if _, ok := err.(gophercloud.ErrDefault404); ok {
					continue
				}
				require.NoError(t, err, "There should be no error while deleting object %s/%s", container, object)
			}

			err = wait.PollImmediate(CleanupBackupContainerDeleteInterval, CleanupBackupContainerDeleteTimeout,
				func() (bool, error) {
					_, err := containers.Delete(storageClient, container).Extract()
					if _, ok := err.(gophercloud.ErrDefault409); ok {
						return false, nil
					}
					//Ignore 404 from swift, this can happen for a successful delete becase of the eventual consistency
					if _, ok := err.(gophercloud.ErrDefault404); ok {
						return true, nil
					}
					return true, err
				})
			require.NoError(t, err, "There should be no error while deleting storage container: %s", container)
		}
	}
}

func (p *PyrolisisTests) CleanupVolumes(t *testing.T) {
	storageClient, err := openstack.NewBlockStorageV3(p.OpenStack.Provider, gophercloud.EndpointOpts{})
	require.NoError(t, err, "Could not create block storage client")

	project, err := tokens.Get(p.OpenStack.Identity, p.OpenStack.Provider.Token()).ExtractProject()
	require.NoError(t, err, "There should be no error while extracting the project")

	volumeListOpts := volumes.ListOpts{
		TenantID: project.ID,
	}

	allPages, err := volumes.List(storageClient, volumeListOpts).AllPages()
	require.NoError(t, err, "There should be no error while retrieving volume pages")

	allVolumes, err := volumes.ExtractVolumes(allPages)
	require.NoError(t, err, "There should be no error while extracting volumes")

	for _, vol := range allVolumes {
		// in-tree
		if strings.HasPrefix(vol.Name, "kubernetes-dynamic-pvc-") &&
			strings.HasPrefix(vol.Metadata["kubernetes.io/created-for/pvc/namespace"], "e2e-volumes-") {
			err := volumes.Delete(storageClient, vol.ID, volumes.DeleteOpts{}).ExtractErr()
			require.NoError(t, err, "There should be no error while deleting volume %s (%s)", vol.Name, vol.ID)
		}
		// CSI
		if strings.HasPrefix(vol.Name, "pv-e2e-") &&
			strings.HasPrefix(vol.Metadata["cinder.csi.openstack.org/cluster"], "e2e-") {
			err := volumes.Delete(storageClient, vol.ID, volumes.DeleteOpts{}).ExtractErr()
			require.NoError(t, err, "There should be no error while deleting volume %s (%s)", vol.Name, vol.ID)
		}
	}
}

func (p *PyrolisisTests) CleanupInstances(t *testing.T) {
	computeClient, err := openstack.NewComputeV2(p.OpenStack.Provider, gophercloud.EndpointOpts{})
	require.NoError(t, err, "There should be no error creating compute client")

	project, err := tokens.Get(p.OpenStack.Identity, p.OpenStack.Provider.Token()).ExtractProject()
	require.NoError(t, err, "There should be no error while extracting the project")

	serversListOpts := servers.ListOpts{
		Name:     "e2e-",
		TenantID: project.ID,
	}

	allPages, err := servers.List(computeClient, serversListOpts).AllPages()
	require.NoError(t, err, "There should be no error while listing all servers")

	allServers, err := servers.ExtractServers(allPages)
	require.NoError(t, err, "There should be no error while extracting all servers")

	for _, srv := range allServers {
		err := servers.Delete(computeClient, srv.ID).ExtractErr()
		require.NoError(t, err, "There should be no error while deleting server %s (%s)", srv.Name, srv.ID)
	}
}

func (p *PyrolisisTests) CleanupLoadbalancers(t *testing.T) {
	lbClient, err := openstack.NewLoadBalancerV2(p.OpenStack.Provider, gophercloud.EndpointOpts{})
	require.NoError(t, err, "There should be no error getting a loadbalancer client")

	allPages, err := loadbalancers.List(lbClient, loadbalancers.ListOpts{}).AllPages()
	require.NoError(t, err, "There should be no error while listing loadbalancers")

	allLoadbalancers, err := loadbalancers.ExtractLoadBalancers(allPages)
	require.NoError(t, err, "There should be no error while extracting loadbalancers")

	for _, lb := range allLoadbalancers {
		if strings.HasSuffix(lb.Name, "_e2e-lb") {
			err := loadbalancers.Delete(lbClient, lb.ID, loadbalancers.DeleteOpts{Cascade: true}).ExtractErr()
			require.NoError(t, err, "There should be no error while deleting loadbalancer %s", lb.Name)
		}
	}
}
<commit_msg>Only cleanup loadbalancers for not running klusters in e2e test<commit_after>package main

import (
	"fmt"
	"strings"
	"testing"
	"time"

	"github.com/go-openapi/runtime"
	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack"
	"github.com/gophercloud/gophercloud/openstack/blockstorage/v3/volumes"
	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
	"github.com/gophercloud/gophercloud/openstack/identity/v3/tokens"
	"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/loadbalancers"
	"github.com/gophercloud/gophercloud/openstack/objectstorage/v1/containers"
	"github.com/gophercloud/gophercloud/openstack/objectstorage/v1/objects"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"k8s.io/apimachinery/pkg/util/wait"

	"github.com/sapcc/kubernikus/pkg/api/client/operations"
	"github.com/sapcc/kubernikus/pkg/api/models"
	etcd_util "github.com/sapcc/kubernikus/pkg/util/etcd"
	"github.com/sapcc/kubernikus/test/e2e/framework"
)

const (
	CleanupBackupContainerDeleteInterval = 1 * time.Second
	CleanupBackupContainerDeleteTimeout  = 1 * time.Minute
)

type PyrolisisTests struct {
	Kubernikus *framework.Kubernikus
	OpenStack  *framework.OpenStack
	Reuse      bool
	Isolate    bool
}

func (p *PyrolisisTests) Run(t *testing.T) {
	if p.Reuse == false && p.Isolate == false {
		quota := t.Run("SettingKlustersOnFire", p.SettingKlustersOnFire)
		require.True(t, quota, "Klusters must burn")

		t.Run("Wait", func(t *testing.T) {
			t.Run("Klusters", p.WaitForE2EKlustersTerminated)
		})

		t.Run("CleanupVolumes", p.CleanupVolumes)
		t.Run("CleanupInstances", p.CleanupInstances)
	}

	cleanupStorageContainer := t.Run("CleanupBackupStorageContainers", p.CleanupBackupStorageContainers)
	require.True(t, cleanupStorageContainer, "Etcd backup storage container cleanup failed")

	t.Run("CleanupLoadbalancers", p.CleanupLoadbalancers)
}

func (p *PyrolisisTests) SettingKlustersOnFire(t *testing.T) {
	klusters, err := listKlusters(p.Kubernikus.Client.Operations, p.Kubernikus.AuthInfo)
	require.NoError(t, err, "There should be no error while listing klusters")

	for _, kluster := range klusters {
		if strings.HasPrefix(kluster.Name, "e2e-") {
			t.Run(fmt.Sprintf("TerminatingKluster-%v", kluster.Name), func(t *testing.T) {
				_, err := p.Kubernikus.Client.Operations.TerminateCluster(
					operations.NewTerminateClusterParams().WithName(kluster.Name),
					p.Kubernikus.AuthInfo,
				)
				assert.NoError(t, err, "There should be no error while terminating klusters")
			})
		}
	}
}

func listKlusters(client *operations.Client, authinfo runtime.ClientAuthInfoWriter) ([]*models.Kluster, error) {
	res, err := client.ListClusters(
		operations.NewListClustersParams(),
		authinfo,
	)

	if err != nil {
		return nil, err
	}

	return res.Payload, nil
}

func (p *PyrolisisTests) WaitForE2EKlustersTerminated(t *testing.T) {
	err := p.Kubernikus.WaitForKlusters("e2e-", 0, WaitForKlusterToBeDeletedTimeout)
	assert.NoError(t, err, "E2E Klusters didn't burn down in time")
}

func (p *PyrolisisTests) CleanupBackupStorageContainers(t *testing.T) {
	storageClient, err := openstack.NewObjectStorageV1(p.OpenStack.Provider, gophercloud.EndpointOpts{})
	require.NoError(t, err, "Could not create object storage client")

	containersListOpts := containers.ListOpts{
		Full: false,
	}
	allPages, err := containers.List(storageClient, containersListOpts).AllPages()
	require.NoError(t, err, "There should be no error while listing storage containers")

	allContainers, err := containers.ExtractNames(allPages)
	require.NoError(t, err, "There should be no error while extracting storage containers")

	klusters, err := listKlusters(p.Kubernikus.Client.Operations, p.Kubernikus.AuthInfo)
	require.NoError(t, err, "There should be no error while listing klusters")

	// do not delete containers where there is still a kluster running
	var containersToDelete []string
	for _, container := range allContainers {
		found := false

		for _, kluster := range klusters {
			if strings.HasPrefix(container, fmt.Sprintf("%s-%s", etcd_util.BackupStorageContainerBase, kluster.Name)) {
				found = true
			}
		}

		if !found {
			containersToDelete = append(containersToDelete, container)
		}
	}

	objectsListOpts := objects.ListOpts{
		Full: false,
	}

	for _, container := range containersToDelete {
		if strings.HasPrefix(container, etcd_util.BackupStorageContainerBase) {
			allPages, err := objects.List(storageClient, container, objectsListOpts).AllPages()
			require.NoError(t, err, "There should be no error while lising objetcs in container %s", container)

			allObjects, err := objects.ExtractNames(allPages)
			require.NoError(t, err, "There should be no error while extracting objetcs names for container %s", container)

			for _, object := range allObjects {
				_, err := objects.Delete(storageClient, container, object, objects.DeleteOpts{}).Extract()
				//Ignore 404 from swift, this can happen for a successful delete becase of the eventual consistency
				if _, ok := err.(gophercloud.ErrDefault404); ok {
					continue
				}
				require.NoError(t, err, "There should be no error while deleting object %s/%s", container, object)
			}

			err = wait.PollImmediate(CleanupBackupContainerDeleteInterval, CleanupBackupContainerDeleteTimeout,
				func() (bool, error) {
					_, err := containers.Delete(storageClient, container).Extract()
					if _, ok := err.(gophercloud.ErrDefault409); ok {
						return false, nil
					}
					//Ignore 404 from swift, this can happen for a successful delete becase of the eventual consistency
					if _, ok := err.(gophercloud.ErrDefault404); ok {
						return true, nil
					}
					return true, err
				})
			require.NoError(t, err, "There should be no error while deleting storage container: %s", container)
		}
	}
}

func (p *PyrolisisTests) CleanupVolumes(t *testing.T) {
	storageClient, err := openstack.NewBlockStorageV3(p.OpenStack.Provider, gophercloud.EndpointOpts{})
	require.NoError(t, err, "Could not create block storage client")

	project, err := tokens.Get(p.OpenStack.Identity, p.OpenStack.Provider.Token()).ExtractProject()
	require.NoError(t, err, "There should be no error while extracting the project")

	volumeListOpts := volumes.ListOpts{
		TenantID: project.ID,
	}

	allPages, err := volumes.List(storageClient, volumeListOpts).AllPages()
	require.NoError(t, err, "There should be no error while retrieving volume pages")

	allVolumes, err := volumes.ExtractVolumes(allPages)
	require.NoError(t, err, "There should be no error while extracting volumes")

	for _, vol := range allVolumes {
		// in-tree
		if strings.HasPrefix(vol.Name, "kubernetes-dynamic-pvc-") &&
			strings.HasPrefix(vol.Metadata["kubernetes.io/created-for/pvc/namespace"], "e2e-volumes-") {
			err := volumes.Delete(storageClient, vol.ID, volumes.DeleteOpts{}).ExtractErr()
			require.NoError(t, err, "There should be no error while deleting volume %s (%s)", vol.Name, vol.ID)
		}
		// CSI
		if strings.HasPrefix(vol.Name, "pv-e2e-") &&
			strings.HasPrefix(vol.Metadata["cinder.csi.openstack.org/cluster"], "e2e-") {
			err := volumes.Delete(storageClient, vol.ID, volumes.DeleteOpts{}).ExtractErr()
			require.NoError(t, err, "There should be no error while deleting volume %s (%s)", vol.Name, vol.ID)
		}
	}
}

func (p *PyrolisisTests) CleanupInstances(t *testing.T) {
	computeClient, err := openstack.NewComputeV2(p.OpenStack.Provider, gophercloud.EndpointOpts{})
	require.NoError(t, err, "There should be no error creating compute client")

	project, err := tokens.Get(p.OpenStack.Identity, p.OpenStack.Provider.Token()).ExtractProject()
	require.NoError(t, err, "There should be no error while extracting the project")

	serversListOpts := servers.ListOpts{
		Name:     "e2e-",
		TenantID: project.ID,
	}

	allPages, err := servers.List(computeClient, serversListOpts).AllPages()
	require.NoError(t, err, "There should be no error while listing all servers")

	allServers, err := servers.ExtractServers(allPages)
	require.NoError(t, err, "There should be no error while extracting all servers")

	for _, srv := range allServers {
		err := servers.Delete(computeClient, srv.ID).ExtractErr()
		require.NoError(t, err, "There should be no error while deleting server %s (%s)", srv.Name, srv.ID)
	}
}

func (p *PyrolisisTests) CleanupLoadbalancers(t *testing.T) {
	lbClient, err := openstack.NewLoadBalancerV2(p.OpenStack.Provider, gophercloud.EndpointOpts{})
	require.NoError(t, err, "There should be no error getting a loadbalancer client")

	allPages, err := loadbalancers.List(lbClient, loadbalancers.ListOpts{}).AllPages()
	require.NoError(t, err, "There should be no error while listing loadbalancers")

	allLoadbalancers, err := loadbalancers.ExtractLoadBalancers(allPages)
	require.NoError(t, err, "There should be no error while extracting loadbalancers")

	klusters, err := listKlusters(p.Kubernikus.Client.Operations, p.Kubernikus.AuthInfo)
	require.NoError(t, err, "There should be no error while listing klusters")

	// do not delete loadbalancers where there is still a kluster running
	var lbsToDelete []loadbalancers.LoadBalancer
	for _, lb := range allLoadbalancers {
		found := false

		for _, kluster := range klusters {
			if strings.HasPrefix(lb.Name, fmt.Sprintf("kube_service_%s", kluster.Name)) {
				found = true
			}
		}

		if !found {
			lbsToDelete = append(lbsToDelete, lb)
		}
	}

	for _, lb := range lbsToDelete {
		if strings.HasSuffix(lb.Name, "_e2e-lb") {
			err := loadbalancers.Delete(lbClient, lb.ID, loadbalancers.DeleteOpts{Cascade: true}).ExtractErr()
			require.NoError(t, err, "There should be no error while deleting loadbalancer %s", lb.Name)
		}
	}
}
<|endoftext|>


<commit_before>package auth

type Database struct {
	Realm    string
	username string
	password string
	records  map[string]string
}

func newAuthDB(realm string) *Database {
	if realm == "" {
		realm = "dorsvr streaming server"
	}
	return &Database{
		Realm: realm,
	}
}

func (a *Database) InsertUserRecord(username, password string) {
	if username == "" || password == "" {
		return
	}

	_, existed := a.records[username]
	if !existed {
		a.records[username] = password
	}
}

func (a *Database) RemoveUserRecord(username string) {
	_, existed := a.records[username]
	if existed {
		delete(a.records, username)
	}
}

func (a *Database) LookupPassword(username string) (password string) {
	password, _ = a.records[username]
	return
}
<commit_msg>update auth db<commit_after>package auth

type Database struct {
	Realm    string
	username string
	password string
	records  map[string]string
}

func NewAuthDatabase(realm string) *Database {
	if realm == "" {
		realm = "dorsvr streaming server"
	}
	return &Database{
		Realm: realm,
	}
}

func (d *Database) InsertUserRecord(username, password string) {
	if username == "" || password == "" {
		return
	}

	_, existed := d.records[username]
	if !existed {
		d.records[username] = password
	}
}

func (d *Database) RemoveUserRecord(username string) {
	_, existed := d.records[username]
	if existed {
		delete(d.records, username)
	}
}

func (a *Database) LookupPassword(username string) (password string) {
	password, _ = a.records[username]
	return
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"sync"

	"github.com/zephyyrr/autobot/config"
)

var (
	configuration config.Config
	processes     sync.WaitGroup
	configfile    = flag.String("f", "autobot.toml", "Config filename")
)

func init() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	flag.Parse()
	f, err := os.Open(*configfile)
	if err != nil {
		log.Fatalf("Unable to read open config file %s. %s", *configfile, err)
	}
	configuration, err = config.LoadConfig(f)
	if err != nil {
		log.Fatalln("Unable to parse config file.", err)
	}
}

func main() {
	interrupt := make(chan os.Signal)
	signal.Notify(interrupt, os.Interrupt)

	port := "8080"
	if p := os.Getenv("PORT"); p != "" {
		port = p
	}

	conn, err := net.Listen("tcp", ":"+port)
	if err != nil {
		log.Fatalln("Error listening to port.", err)
	}

	go http.Serve(conn, http.DefaultServeMux)

	select {
	case <-interrupt:
	}

	if err := conn.Close(); err != nil {

	}

	shutdown()
}

func rollOut() {
	// Pull from git
	// Issue build command (read from config)
	// ???
	// Profit!
}

func shutdown() {
	// Allows clean shutdowns.
	processes.Wait()
}

func hookAddress(req *http.Request) string {
	return fmt.Sprintf("%s%s", req.Host, "/hook")
}
<commit_msg>Renamed config variable and config import for shorter code.<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"sync"

	c "github.com/zephyyrr/autobot/config"
)

var (
	config     c.Config
	processes  sync.WaitGroup
	configfile = flag.String("f", "autobot.toml", "Config filename")
)

func init() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	flag.Parse()
	f, err := os.Open(*configfile)
	if err != nil {
		log.Fatalf("Unable to read open config file %s. %s", *configfile, err)
	}
	config, err = c.LoadConfig(f)
	if err != nil {
		log.Fatalln("Unable to parse config file.", err)
	}

}

func main() {
	interrupt := make(chan os.Signal)
	signal.Notify(interrupt, os.Interrupt)

	port := "8080"
	if p := os.Getenv("PORT"); p != "" {
		port = p
	}

	conn, err := net.Listen("tcp", ":"+port)
	if err != nil {
		log.Fatalln("Error listening to port.", err)
	}

	go http.Serve(conn, http.DefaultServeMux)

	select {
	case <-interrupt:
	}

	if err := conn.Close(); err != nil {

	}

	shutdown()
}

func rollOut() {
	// Pull from git
	// Issue build command (read from config)
	// ???
	// Profit!
}

func shutdown() {
	// Allows clean shutdowns.
	processes.Wait()
}

func hookAddress(req *http.Request) string {
	return fmt.Sprintf("%s%s", req.Host, "/hook")
}
<|endoftext|>


<commit_before>package aws

import (
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/fsx"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func describeFsxFileSystem(conn *fsx.FSx, id string) (*fsx.FileSystem, error) {
	input := &fsx.DescribeFileSystemsInput{
		FileSystemIds: []*string{aws.String(id)},
	}
	var filesystem *fsx.FileSystem

	err := conn.DescribeFileSystemsPages(input, func(page *fsx.DescribeFileSystemsOutput, lastPage bool) bool {
		for _, fs := range page.FileSystems {
			if aws.StringValue(fs.FileSystemId) == id {
				filesystem = fs
				return false
			}
		}

		return !lastPage
	})

	return filesystem, err
}

func refreshFsxFileSystemLifecycle(conn *fsx.FSx, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		filesystem, err := describeFsxFileSystem(conn, id)

		if isAWSErr(err, fsx.ErrCodeFileSystemNotFound, "") {
			return nil, "", nil
		}

		if err != nil {
			return nil, "", err
		}

		if filesystem == nil {
			return nil, "", nil
		}

		return filesystem, aws.StringValue(filesystem.Lifecycle), nil
	}
}

func refreshFsxFileSystemLifecycleOptimizing(conn *fsx.FSx, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		filesystem, err := describeFsxFileSystem(conn, id)

		if isAWSErr(err, fsx.ErrCodeFileSystemNotFound, "") {
			return nil, "", nil
		}

		if err != nil {
			return nil, "", err
		}

		if filesystem == nil {
			return nil, "", nil
		}

		return filesystem, aws.StringValue(filesystem.AdministrativeActions[0].Status), nil
	}
}

func waitForFsxFileSystemCreation(conn *fsx.FSx, id string, timeout time.Duration) error {
	stateConf := &resource.StateChangeConf{
		Pending: []string{fsx.FileSystemLifecycleCreating},
		Target:  []string{fsx.FileSystemLifecycleAvailable},
		Refresh: refreshFsxFileSystemLifecycle(conn, id),
		Timeout: timeout,
		Delay:   30 * time.Second,
	}

	_, err := stateConf.WaitForState()

	return err
}

func waitForFsxFileSystemDeletion(conn *fsx.FSx, id string, timeout time.Duration) error {
	stateConf := &resource.StateChangeConf{
		Pending: []string{fsx.FileSystemLifecycleAvailable, fsx.FileSystemLifecycleDeleting},
		Target:  []string{},
		Refresh: refreshFsxFileSystemLifecycle(conn, id),
		Timeout: timeout,
		Delay:   30 * time.Second,
	}

	_, err := stateConf.WaitForState()

	return err
}

func waitForFsxFileSystemUpdate(conn *fsx.FSx, id string, timeout time.Duration) error {
	stateConf := &resource.StateChangeConf{
		Pending: []string{fsx.FileSystemLifecycleUpdating},
		Target:  []string{fsx.FileSystemLifecycleAvailable},
		Refresh: refreshFsxFileSystemLifecycle(conn, id),
		Timeout: timeout,
		Delay:   30 * time.Second,
	}

	_, err := stateConf.WaitForState()

	return err
}

func waitForFsxFileSystemUpdateOptimizing(conn *fsx.FSx, id string, timeout time.Duration) error {
	stateConf := &resource.StateChangeConf{
		Pending: []string{fsx.StatusInProgress},
		Target:  []string{fsx.StatusCompleted},
		Refresh: refreshFsxFileSystemLifecycleOptimizing(conn, id),
		Timeout: timeout,
		Delay:   30 * time.Second,
	}

	_, err := stateConf.WaitForState()

	return err
}
<commit_msg>f/aws_fsx_windows_file_system: allow updating storage and throughout capacity without recreation of resource<commit_after>package aws

import (
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/fsx"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func describeFsxFileSystem(conn *fsx.FSx, id string) (*fsx.FileSystem, error) {
	input := &fsx.DescribeFileSystemsInput{
		FileSystemIds: []*string{aws.String(id)},
	}
	var filesystem *fsx.FileSystem

	err := conn.DescribeFileSystemsPages(input, func(page *fsx.DescribeFileSystemsOutput, lastPage bool) bool {
		for _, fs := range page.FileSystems {
			if aws.StringValue(fs.FileSystemId) == id {
				filesystem = fs
				return false
			}
		}

		return !lastPage
	})

	return filesystem, err
}

func refreshFsxFileSystemLifecycle(conn *fsx.FSx, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		filesystem, err := describeFsxFileSystem(conn, id)

		if isAWSErr(err, fsx.ErrCodeFileSystemNotFound, "") {
			return nil, "", nil
		}

		if err != nil {
			return nil, "", err
		}

		if filesystem == nil {
			return nil, "", nil
		}

		return filesystem, aws.StringValue(filesystem.Lifecycle), nil
	}
}

func refreshFsxFileSystemLifecycleOptimizing(conn *fsx.FSx, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		filesystem, err := describeFsxFileSystem(conn, id)

		if isAWSErr(err, fsx.ErrCodeFileSystemNotFound, "") {
			return nil, "", nil
		}

		if err != nil {
			return nil, "", err
		}

		if filesystem == nil {
			return nil, "", nil
		}

		return filesystem, aws.StringValue(filesystem.AdministrativeActions[0].Status), nil
	}
}

func waitForFsxFileSystemCreation(conn *fsx.FSx, id string, timeout time.Duration) error {
	stateConf := &resource.StateChangeConf{
		Pending: []string{fsx.FileSystemLifecycleCreating},
		Target:  []string{fsx.FileSystemLifecycleAvailable},
		Refresh: refreshFsxFileSystemLifecycle(conn, id),
		Timeout: timeout,
		Delay:   30 * time.Second,
	}

	_, err := stateConf.WaitForState()

	return err
}

func waitForFsxFileSystemDeletion(conn *fsx.FSx, id string, timeout time.Duration) error {
	stateConf := &resource.StateChangeConf{
		Pending: []string{fsx.FileSystemLifecycleAvailable, fsx.FileSystemLifecycleDeleting},
		Target:  []string{},
		Refresh: refreshFsxFileSystemLifecycle(conn, id),
		Timeout: timeout,
		Delay:   30 * time.Second,
	}

	_, err := stateConf.WaitForState()

	return err
}

func waitForFsxFileSystemUpdate(conn *fsx.FSx, id string, timeout time.Duration) error {
	stateConf := &resource.StateChangeConf{
		Pending: []string{fsx.FileSystemLifecycleUpdating},
		Target:  []string{fsx.FileSystemLifecycleAvailable},
		Refresh: refreshFsxFileSystemLifecycle(conn, id),
		Timeout: timeout,
		Delay:   30 * time.Second,
	}

	_, err := stateConf.WaitForState()

	return err
}

func waitForFsxFileSystemUpdateOptimizing(conn *fsx.FSx, id string, timeout time.Duration) error {
	stateConf := &resource.StateChangeConf{
		Pending: []string{fsx.StatusInProgress},
		Target:  []string{fsx.StatusCompleted, fsx.StatusUpdatedOptimizing},
		Refresh: refreshFsxFileSystemLifecycleOptimizing(conn, id),
		Timeout: timeout,
		Delay:   30 * time.Second,
	}

	_, err := stateConf.WaitForState()

	return err
}
<|endoftext|>


<commit_before>package models

import (
	"github.com/astaxie/beego/orm"
	//"o2oadmin/lib"
	"time"
)

func GetActiveActivityList() (activityList []*FeActivityMaster, err error) {
	o := orm.NewOrm()
	sql := "select display_text, image_url, landing_url from fe_activity_master where 1=1 "

	currentDate := time.Now().Format("2006-01-02")
	var paramList []interface{}

	sql += " and ? >= start_date"
	paramList = append(paramList, currentDate)

	sql += " and end_date >= ?"
	paramList = append(paramList, currentDate)

	sql += " and activity_status = '001'"

	sql += " order by priority desc"
	_, err = o.Raw(sql, paramList).QueryRows(activityList)

	return activityList, err
}
<commit_msg>add activity list service<commit_after>package models

import (
	"github.com/astaxie/beego/orm"
	//"o2oadmin/lib"
	"time"
)

func GetActiveActivityList() (activityList []*FeActivityMaster, err error) {
	o := orm.NewOrm()
	sql := "select display_text, image_url, landing_url from fe_activity_master where 1=1 "

	currentDate := time.Now().Format("2006-01-02")
	var paramList []interface{}

	sql += " and ? >= start_date"
	paramList = append(paramList, currentDate)

	sql += " and end_date >= ?"
	paramList = append(paramList, currentDate)

	sql += " and activity_status = 'ACT'"

	sql += " order by priority desc limit 3"
	_, err = o.Raw(sql, paramList).QueryRows(&activityList)

	return activityList, err
}
<|endoftext|>


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

package query

import ()

//  ParsedItem is an implementation of Item using an already parsed Value
//  (typically this is from parsed JSON)
type ParsedItem struct {
	contents Value
	meta     map[string]Value
}

func NewParsedItem(contents Value, meta map[string]Value) *ParsedItem {
	return &ParsedItem{
		contents: convertEmtpyInterfaceToValue(contents),
		meta:     meta,
	}
}

func convertEmtpyInterfaceToValue(input Value) Value {
	switch input := input.(type) {
	case map[string]Value:
		for k, v := range input {
			input[k] = convertEmtpyInterfaceToValue(v)
		}
		return input
	case map[string]interface{}:
		rv := map[string]Value{}
		for k, v := range input {
			rv[k] = convertEmtpyInterfaceToValue(v)
		}
		return rv
	case []Value:
		for i, v := range input {
			input[i] = convertEmtpyInterfaceToValue(v)
		}
		return input
	case []interface{}:
		rv := make([]Value, 0)
		for _, v := range input {
			rv = append(rv, convertEmtpyInterfaceToValue(v))
		}
		return rv
	default:
		return input
	}
}

func (this *ParsedItem) GetPath(path string) (Value, error) {
	contents := this.contents
	switch contents := contents.(type) {
	case map[string]Value:
		value, ok := contents[path]
		if ok {
			return value, nil
		}
	}

	return nil, &Undefined{path}
}

func (this *ParsedItem) GetValue() Value {
	return this.contents
}

func (this *ParsedItem) GetMeta() map[string]Value {
	return this.meta
}
<commit_msg>typo with convertEmptyInterfaceToValue()<commit_after>//  Copyright (c) 2013 Couchbase, Inc.
//  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
//  except in compliance with the License. You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//  Unless required by applicable law or agreed to in writing, software distributed under the
//  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
//  either express or implied. See the License for the specific language governing permissions
//  and limitations under the License.

package query

import ()

//  ParsedItem is an implementation of Item using an already parsed Value
//  (typically this is from parsed JSON)
type ParsedItem struct {
	contents Value
	meta     map[string]Value
}

func NewParsedItem(contents Value, meta map[string]Value) *ParsedItem {
	return &ParsedItem{
		contents: convertEmptyInterfaceToValue(contents),
		meta:     meta,
	}
}

func convertEmptyInterfaceToValue(input Value) Value {
	switch input := input.(type) {
	case map[string]Value:
		for k, v := range input {
			input[k] = convertEmptyInterfaceToValue(v)
		}
		return input
	case map[string]interface{}:
		rv := map[string]Value{}
		for k, v := range input {
			rv[k] = convertEmptyInterfaceToValue(v)
		}
		return rv
	case []Value:
		for i, v := range input {
			input[i] = convertEmptyInterfaceToValue(v)
		}
		return input
	case []interface{}:
		rv := make([]Value, 0)
		for _, v := range input {
			rv = append(rv, convertEmptyInterfaceToValue(v))
		}
		return rv
	default:
		return input
	}
}

func (this *ParsedItem) GetPath(path string) (Value, error) {
	contents := this.contents
	switch contents := contents.(type) {
	case map[string]Value:
		value, ok := contents[path]
		if ok {
			return value, nil
		}
	}

	return nil, &Undefined{path}
}

func (this *ParsedItem) GetValue() Value {
	return this.contents
}

func (this *ParsedItem) GetMeta() map[string]Value {
	return this.meta
}
<|endoftext|>


<commit_before>package querymorpher

import (
	"fmt"
	"net/url"
	"testing"
)

func TestTransform(t *testing.T) {
	tt := []struct {
		name       string
		query      string
		expected   string
		shouldFail bool
	}{
		{"test empty query", "", "", false},
		{"test bool", "fld=true", "fld = true", false},
		{"test float", "fld=4.2", "fld = 4.2", false},
		{"test int", "fld=4", "fld = 4", false},
		{"test string with quotes", "fld='test'", "fld = 'test'", false},
		{"test string without quotes", "fld=test", "fld = 'test'", false},
		{"test multiple strings", "fld=test&fld2='test'", "fld = 'test' AND fld2 = 'test'", false},
		{"test empty key", "=test", "", true},
		{"test empty value", "key=", "", true},
		{"test gt operator", "number__gt=42", "number > 42", false},
		{"test lt operator", "number__lt=42", "number < 42", false},
		{"test gte operator", "number__gte=42", "number >= 42", false},
		{"test lte operator", "number__lte=42", "number <= 42", false},
		{"test non-existing operator", "t__t=test", "t__t = 'test'", false},
	}
	for _, tc := range tt {
		t.Run(tc.name, func(t *testing.T) {
			q, _ := url.ParseQuery(tc.query)
			res, err := Transform(q)
			if !tc.shouldFail && err != nil {
				t.Error(err.Error())
			}
			if tc.shouldFail && err == nil {
				t.Errorf("should fail for '%s' but got '%s'", tc.query, res)
			}
			if res != tc.expected {
				t.Errorf("Expected: '%s', Got: '%s'", res, tc.expected)
			}
		})
	}
}

func ExampleTransform() {
	q, _ := url.ParseQuery("age__gte=18&name=John")
	res, _ := Transform(q)
	fmt.Println(res)
	// Output: age >= 18 AND name = 'John'
}
<commit_msg>Add test case for date string<commit_after>package querymorpher

import (
	"fmt"
	"net/url"
	"testing"
)

func TestTransform(t *testing.T) {
	tt := []struct {
		name       string
		query      string
		expected   string
		shouldFail bool
	}{
		{"test empty query", "", "", false},
		{"test bool", "fld=true", "fld = true", false},
		{"test float", "fld=4.2", "fld = 4.2", false},
		{"test int", "fld=4", "fld = 4", false},
		{"test string with quotes", "fld='test'", "fld = 'test'", false},
		{"test string without quotes", "fld=test", "fld = 'test'", false},
		{"test empty key", "=test", "", true},
		{"test empty value", "key=", "", true},
		{"test gt operator", "number__gt=42", "number > 42", false},
		{"test lt operator", "number__lt=42", "number < 42", false},
		{"test gte operator", "number__gte=42", "number >= 42", false},
		{"test lte operator", "number__lte=42", "number <= 42", false},
		{"test non-existing operator", "t__t=test", "t__t = 'test'", false},
		{"test data", "date=2017-09-09", "date = '2017-09-09'", false},
	}
	for _, tc := range tt {
		t.Run(tc.name, func(t *testing.T) {
			q, _ := url.ParseQuery(tc.query)
			res, err := Transform(q)
			if !tc.shouldFail && err != nil {
				t.Error(err.Error())
			}
			if tc.shouldFail && err == nil {
				t.Errorf("should fail for '%s' but got '%s'", tc.query, res)
			}
			if res != tc.expected {
				t.Errorf("Expected: '%s', Got: '%s'", tc.expected, res)
			}
		})
	}
}

func ExampleTransform() {
	q, _ := url.ParseQuery("age__gte=18&name=John")
	res, _ := Transform(q)
	fmt.Println(res)
	// Output: age >= 18 AND name = 'John'
}
<|endoftext|>


<commit_before>package finiteElement_test

import (
	"fmt"
	"testing"

	"github.com/Konstantin8105/GoFea/solver/dof"
	"github.com/Konstantin8105/GoFea/solver/finiteElement"
	"github.com/Konstantin8105/GoLinAlg/matrix"
)

func TestRemovePanic(t *testing.T) {
	tests := []struct {
		m matrix.T64
		a []dof.AxeNumber
	}{
		{
			m: matrix.NewMatrix64bySize(1, 1),
			a: []dof.AxeNumber{1, 2, 3},
		},
		{
			m: matrix.NewMatrix64bySize(5, 5),
			a: []dof.AxeNumber{1, 2, 3},
		},
	}
	for index, test := range tests {
		t.Run(fmt.Sprintf("Remove-%v", index), func(t *testing.T) {
			defer func() {
				if r := recover(); r == nil {
					t.Errorf("The code did not panic")
				}
			}()
			finiteElement.RemoveZeros(&test.m, &test.a)
		})
	}
}
<commit_msg>add test<commit_after>package finiteElement_test

import (
	"fmt"
	"testing"

	"github.com/Konstantin8105/GoFea/solver/dof"
	"github.com/Konstantin8105/GoFea/solver/finiteElement"
	"github.com/Konstantin8105/GoLinAlg/matrix"
)

func TestRemovePanic(t *testing.T) {
	tests := []struct {
		m matrix.T64
		a []dof.AxeNumber
	}{
		{
			m: matrix.NewMatrix64bySize(1, 1),
			a: []dof.AxeNumber{1, 2, 3},
		},
		{
			m: matrix.NewMatrix64bySize(5, 5),
			a: []dof.AxeNumber{1, 2, 3},
		},
	}
	for index, test := range tests {
		t.Run(fmt.Sprintf("Remove-%v", index), func(t *testing.T) {
			defer func() {
				if r := recover(); r == nil {
					t.Errorf("The code did not panic")
				}
			}()
			finiteElement.RemoveZeros(&test.m, &test.a)
		})
	}
}

func TestNoDiagonal(t *testing.T) {
	m := matrix.NewMatrix64bySize(2, 2)
	m.Set(0, 0, 0.0)
	m.Set(1, 0, 1.0)
	m.Set(0, 1, 1.0)
	m.Set(1, 1, 0.0)
	a := []dof.AxeNumber{1, 2}
	finiteElement.RemoveZeros(&m, &a)
	if len(a) != 2 {
		t.Errorf("Cannot work for diagonal")
	}
}

func TestDiagonal(t *testing.T) {
	m := matrix.NewMatrix64bySize(2, 2)
	m.Set(0, 0, 1.0)
	m.Set(1, 0, 0.0)
	m.Set(0, 1, 0.0)
	m.Set(1, 1, 1.0)
	a := []dof.AxeNumber{1, 2}
	finiteElement.RemoveZeros(&m, &a)
	if len(a) != 2 {
		t.Errorf("Cannot work for diagonal")
	}
}
<|endoftext|>


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

import (
	"fmt"
	"io"
	"sort"
	"strings"
	"text/tabwriter"

	"github.com/aliyun/aliyun-cli/cli"
	"github.com/aliyun/aliyun-cli/i18n"
	"github.com/aliyun/aliyun-cli/meta"
	"github.com/aliyun/aliyun-cli/resource"
)

type Library struct {
	lang        string
	builtinRepo *meta.Repository
	extraRepo   *meta.Repository
	writer      io.Writer
}

func NewLibrary(w io.Writer, lang string) *Library {
	return &Library{
		builtinRepo: meta.LoadRepository(resource.NewReader()),
		extraRepo:   nil,
		lang:        lang,
		writer:      w,
	}
}

func (a *Library) GetProduct(productCode string) (meta.Product, bool) {
	return a.builtinRepo.GetProduct(productCode)
}

func (a *Library) GetApi(productCode string, version string, apiName string) (meta.Api, bool) {
	return a.builtinRepo.GetApi(productCode, version, apiName)
}

func (a *Library) GetStyle(productCode string, version string) (string, bool) {
	return a.builtinRepo.GetStyle(productCode, version)
}

func (a *Library) GetProducts() []meta.Product {
	return a.builtinRepo.Products
}

func (a *Library) PrintProducts() {
	w := tabwriter.NewWriter(a.writer, 8, 0, 1, ' ', 0)
	cli.PrintfWithColor(w, cli.ColorOff, "\nProducts:\n")
	for _, product := range a.builtinRepo.Products {
		cli.PrintfWithColor(w, cli.Cyan, "  %s\t%s\n", strings.ToLower(product.Code), product.Name[i18n.GetLanguage()])
	}
	w.Flush()
}

func (a *Library) printProduct(product meta.Product) {
	cli.Printf(a.writer, "  %s(%s)\t%s\n", product.Code, product.Version, product.Name["zh"])
}

func (a *Library) PrintProductUsage(productCode string, withApi bool) error {
	product, ok := a.GetProduct(productCode)
	if !ok {
		return &InvalidProductError{Code: productCode, library: a}
	}

	if product.ApiStyle == "rpc" {
		cli.Printf(a.writer, "\nUsage:\n  aliyun %s <ApiName> --parameter1 value1 --parameter2 value2 ...\n", product.Code)
	} else {
		cli.Printf(a.writer, "\nUsage 1:\n  aliyun %s [GET|PUT|POST|DELETE] <PathPattern> --body \"...\" \n", product.Code)
		cli.Printf(a.writer, "\nUsage 2 (For API with NO PARAMS in PathPattern only.):\n  aliyun %s <ApiName> --parameter1 value1 --parameter2 value2 ... --body \"...\"\n", product.Code)
	}

	cli.Printf(a.writer, "\nProduct: %s (%s)\n", product.Code, product.Name[i18n.GetLanguage()])
	cli.Printf(a.writer, "Version: %s \n", product.Version)

	if withApi {
		cli.PrintfWithColor(a.writer, cli.ColorOff, "\nAvailable Api List: \n")
		maxNameLen := 0

		for _, apiName := range product.ApiNames {
			if len(apiName) > maxNameLen {
				maxNameLen = len(apiName)
			}
		}

		for _, apiName := range product.ApiNames {
			if product.ApiStyle == "restful" {
				api, _ := a.GetApi(productCode, product.Version, apiName)
				ptn := fmt.Sprintf("  %%-%ds : %%s %%s\n", maxNameLen+1)
				cli.PrintfWithColor(a.writer, cli.Green, ptn, apiName, api.Method, api.PathPattern)
			} else {
				cli.PrintfWithColor(a.writer, cli.Green, "  %s\n", apiName)
			}

		}
		// TODO some ApiName is too long, two column not seems good
		//w := tabwriter.NewWriter(cli.GetOutputWriter(), 8, 0, 1, ' ', 0)
		//for i := 0; i < len(product.ApiNames); i += 2 {
		//	name1 := product.ApiNames[i]
		//	name2 := ""
		//	if i + 1 < len(product.ApiNames) {
		//		name2 = product.ApiNames[i + 1]
		//	}
		//	fmt.Fprintf(w, "  %s\t%s\n", name1, name2)
		//}
		//w.Flush()
	}

	cli.Printf(a.writer, "\nRun `aliyun %s <ApiName> --help` to get more information about this API\n", product.GetLowerCode())
	return nil
}

func (a *Library) PrintApiUsage(productCode string, apiName string) error {
	product, ok := a.builtinRepo.GetProduct(productCode)
	if !ok {
		return &InvalidProductError{Code: productCode, library: a}
	}
	api, ok := a.builtinRepo.GetApi(productCode, product.Version, apiName)
	if !ok {
		return &InvalidApiError{Name: apiName, product: &product}
	}

	if product.ApiStyle == "restful" {
		cli.Printf(a.writer, "\nProduct:     %s (%s)\n", product.Code, product.Name[i18n.GetLanguage()])
		cli.Printf(a.writer, "Method:      %s\n", api.Method)
		cli.Printf(a.writer, "PathPattern: %s\n", api.PathPattern)
	} else {
		cli.Printf(a.writer, "\nProduct: %s (%s)\n", product.Code, product.Name[i18n.GetLanguage()])
	}

	cli.Printf(a.writer, "\nParameters:\n")

	w := tabwriter.NewWriter(a.writer, 8, 0, 1, ' ', 0)
	printParameters(w, api.Parameters, "")
	w.Flush()

	return nil
}

func printParameters(w io.Writer, params []meta.Parameter, prefix string) {

	sort.Sort(meta.ParameterSlice(params))

	for _, param := range params {
		if param.Hidden {
			continue
		}
		if param.Position == "Domain" {
			continue
		}
		if param.Type == "RepeatList" {
			if len(param.SubParameters) > 0 {
				printParameters(w, param.SubParameters, prefix+param.Name+".n.")
			} else {
				fmt.Fprintf(w, "  --%s%s.n\t%s\t%s\t%s\n", prefix, param.Name, param.Type, required(param.Required), getDescription(param.Description))
			}
		} else {
			fmt.Fprintf(w, "  --%s%s\t%s\t%s\t%s\n", prefix, param.Name, param.Type, required(param.Required), getDescription(param.Description))
		}
	}
}

func required(r bool) string {
	if r {
		return "Required"
	} else {
		return "Optional"
	}
}

func getDescription(d map[string]string) string {
	return ""
	// TODO: description too long, need optimize for display
	//if d == nil {
	//	return ""
	//}
	//if v, ok := d[i18n.GetLanguage()]; ok {
	//	return v
	//} else {
	//	return ""
	//}
}

//
//func (a *Helper) printCompactList() {
//	for _, s := range compactList {
//		product, _ := c.products.GetProduct(s)
//		c.PrintProduct(product)
//	}
//	cli.Printf("  ... ")
//}
<commit_msg>ignore header parameters<commit_after>// Copyright (c) 2009-present, Alibaba Cloud All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package openapi

import (
	"fmt"
	"io"
	"sort"
	"strings"
	"text/tabwriter"

	"github.com/aliyun/aliyun-cli/cli"
	"github.com/aliyun/aliyun-cli/i18n"
	"github.com/aliyun/aliyun-cli/meta"
	"github.com/aliyun/aliyun-cli/resource"
)

type Library struct {
	lang        string
	builtinRepo *meta.Repository
	extraRepo   *meta.Repository
	writer      io.Writer
}

func NewLibrary(w io.Writer, lang string) *Library {
	return &Library{
		builtinRepo: meta.LoadRepository(resource.NewReader()),
		extraRepo:   nil,
		lang:        lang,
		writer:      w,
	}
}

func (a *Library) GetProduct(productCode string) (meta.Product, bool) {
	return a.builtinRepo.GetProduct(productCode)
}

func (a *Library) GetApi(productCode string, version string, apiName string) (meta.Api, bool) {
	return a.builtinRepo.GetApi(productCode, version, apiName)
}

func (a *Library) GetStyle(productCode string, version string) (string, bool) {
	return a.builtinRepo.GetStyle(productCode, version)
}

func (a *Library) GetProducts() []meta.Product {
	return a.builtinRepo.Products
}

func (a *Library) PrintProducts() {
	w := tabwriter.NewWriter(a.writer, 8, 0, 1, ' ', 0)
	cli.PrintfWithColor(w, cli.ColorOff, "\nProducts:\n")
	for _, product := range a.builtinRepo.Products {
		cli.PrintfWithColor(w, cli.Cyan, "  %s\t%s\n", strings.ToLower(product.Code), product.Name[i18n.GetLanguage()])
	}
	w.Flush()
}

func (a *Library) printProduct(product meta.Product) {
	cli.Printf(a.writer, "  %s(%s)\t%s\n", product.Code, product.Version, product.Name["zh"])
}

func (a *Library) PrintProductUsage(productCode string, withApi bool) error {
	product, ok := a.GetProduct(productCode)
	if !ok {
		return &InvalidProductError{Code: productCode, library: a}
	}

	if product.ApiStyle == "rpc" {
		cli.Printf(a.writer, "\nUsage:\n  aliyun %s <ApiName> --parameter1 value1 --parameter2 value2 ...\n", product.Code)
	} else {
		cli.Printf(a.writer, "\nUsage 1:\n  aliyun %s [GET|PUT|POST|DELETE] <PathPattern> --body \"...\" \n", product.Code)
		cli.Printf(a.writer, "\nUsage 2 (For API with NO PARAMS in PathPattern only.):\n  aliyun %s <ApiName> --parameter1 value1 --parameter2 value2 ... --body \"...\"\n", product.Code)
	}

	cli.Printf(a.writer, "\nProduct: %s (%s)\n", product.Code, product.Name[i18n.GetLanguage()])
	cli.Printf(a.writer, "Version: %s \n", product.Version)

	if withApi {
		cli.PrintfWithColor(a.writer, cli.ColorOff, "\nAvailable Api List: \n")
		maxNameLen := 0

		for _, apiName := range product.ApiNames {
			if len(apiName) > maxNameLen {
				maxNameLen = len(apiName)
			}
		}

		for _, apiName := range product.ApiNames {
			if product.ApiStyle == "restful" {
				api, _ := a.GetApi(productCode, product.Version, apiName)
				ptn := fmt.Sprintf("  %%-%ds : %%s %%s\n", maxNameLen+1)
				cli.PrintfWithColor(a.writer, cli.Green, ptn, apiName, api.Method, api.PathPattern)
			} else {
				cli.PrintfWithColor(a.writer, cli.Green, "  %s\n", apiName)
			}

		}
		// TODO some ApiName is too long, two column not seems good
		//w := tabwriter.NewWriter(cli.GetOutputWriter(), 8, 0, 1, ' ', 0)
		//for i := 0; i < len(product.ApiNames); i += 2 {
		//	name1 := product.ApiNames[i]
		//	name2 := ""
		//	if i + 1 < len(product.ApiNames) {
		//		name2 = product.ApiNames[i + 1]
		//	}
		//	fmt.Fprintf(w, "  %s\t%s\n", name1, name2)
		//}
		//w.Flush()
	}

	cli.Printf(a.writer, "\nRun `aliyun %s <ApiName> --help` to get more information about this API\n", product.GetLowerCode())
	return nil
}

func (a *Library) PrintApiUsage(productCode string, apiName string) error {
	product, ok := a.builtinRepo.GetProduct(productCode)
	if !ok {
		return &InvalidProductError{Code: productCode, library: a}
	}
	api, ok := a.builtinRepo.GetApi(productCode, product.Version, apiName)
	if !ok {
		return &InvalidApiError{Name: apiName, product: &product}
	}

	if product.ApiStyle == "restful" {
		cli.Printf(a.writer, "\nProduct:     %s (%s)\n", product.Code, product.Name[i18n.GetLanguage()])
		cli.Printf(a.writer, "Method:      %s\n", api.Method)
		cli.Printf(a.writer, "PathPattern: %s\n", api.PathPattern)
	} else {
		cli.Printf(a.writer, "\nProduct: %s (%s)\n", product.Code, product.Name[i18n.GetLanguage()])
	}

	cli.Printf(a.writer, "\nParameters:\n")

	w := tabwriter.NewWriter(a.writer, 8, 0, 1, ' ', 0)
	printParameters(w, api.Parameters, "")
	w.Flush()

	return nil
}

func printParameters(w io.Writer, params []meta.Parameter, prefix string) {

	sort.Sort(meta.ParameterSlice(params))

	for _, param := range params {
		if param.Hidden {
			continue
		}

		if param.Position == "Domain" {
			continue
		}

		if param.Position == "Header" {
			continue
		}

		if param.Type == "RepeatList" {
			if len(param.SubParameters) > 0 {
				printParameters(w, param.SubParameters, prefix+param.Name+".n.")
			} else {
				fmt.Fprintf(w, "  --%s%s.n\t%s\t%s\t%s\n", prefix, param.Name, param.Type, required(param.Required), getDescription(param.Description))
			}
		} else {
			fmt.Fprintf(w, "  --%s%s\t%s\t%s\t%s\n", prefix, param.Name, param.Type, required(param.Required), getDescription(param.Description))
		}
	}
}

func required(r bool) string {
	if r {
		return "Required"
	} else {
		return "Optional"
	}
}

func getDescription(d map[string]string) string {
	return ""
	// TODO: description too long, need optimize for display
	//if d == nil {
	//	return ""
	//}
	//if v, ok := d[i18n.GetLanguage()]; ok {
	//	return v
	//} else {
	//	return ""
	//}
}

//
//func (a *Helper) printCompactList() {
//	for _, s := range compactList {
//		product, _ := c.products.GetProduct(s)
//		c.PrintProduct(product)
//	}
//	cli.Printf("  ... ")
//}
<|endoftext|>


<commit_before>package openpgp

import (
	"code.google.com/p/go.crypto/openpgp"
	//"code.google.com/p/go.crypto/openpgp/packet"
	"bytes"
	"code.google.com/p/go.crypto/openpgp/armor"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

const Version = "0.1.0"

var (
	DefaultPublicKeyRing = filepath.Join(os.Getenv("HOME"), ".gnupg", "pubring.gpg")

	DefaultSecretKeyRing = filepath.Join(os.Getenv("HOME"), ".gnupg", "secring.gpg")
)

var (
	ErrPubRing     = errors.New("openpgp: public keyring")
	ErrSecRing     = errors.New("openpgp: secret keyring")
	ErrSecStore    = errors.New("openpgp: exporting secret keyring isn't supported'")
	ErrKeyNotFound = errors.New("openpgp: key not found")
)

// Paths to the public and secret keyrings.
var (
	PubRingPath string = DefaultPublicKeyRing
	SecRingPath string = DefaultSecretKeyRing
)

// A KeyRing contains a list of entities and the state required to
// maintain the key ring.
type KeyRing struct {
	Entities map[string]*openpgp.Entity
	path     string
	private  bool
}

func (keyRing *KeyRing) Private() bool {
	return keyRing.private
}

// LoadKeyRing reads the unarmoured keyring stored at the named path.
func LoadKeyRing(path string) (keyRing *KeyRing, err error) {
	file, err := os.Open(path)
	if err != nil {
		return
	}
	defer file.Close()

	el, err := openpgp.ReadKeyRing(file)
	if err != nil {
		return
	}

	keyRing = new(KeyRing)
	keyRing.path = path
	keyRing.Entities = map[string]*openpgp.Entity{}
	for _, e := range el {
		if e.PrivateKey != nil {
			keyRing.private = true
		}
		id := fmt.Sprintf("%x", e.PrimaryKey.Fingerprint)
		keyRing.Entities[id] = e
	}
	return
}

// Store writes the keyring to disk as an unarmoured keyring.
func (keyRing *KeyRing) Store() (err error) {
	if keyRing.private {
		err = ErrSecStore
		return
	}
	tempFile, err := ioutil.TempFile(filepath.Dir(keyRing.path), "openpgp")
	if err != nil {
		return
	}
	defer tempFile.Close()

	for _, e := range keyRing.Entities {
		err = e.Serialize(tempFile)
		if err != nil {
			tempFile.Close()
			os.Remove(tempFile.Name())
			return
		}
	}
	tempFile.Close()
	err = os.Rename(tempFile.Name(), keyRing.path)
	if err != nil {
		os.Remove(tempFile.Name())
	}
	return
}

func (keyRing *KeyRing) Import(armoured string) (n int, err error) {
	buf := bytes.NewBufferString(armoured)
	el, err := openpgp.ReadArmoredKeyRing(buf)
	if err != nil {
		return
	}

	for _, e := range el {
		if keyRing.private && e.PrivateKey == nil {
			err = ErrSecRing
			return
		} else if !keyRing.private && e.PrivateKey != nil {
			err = ErrPubRing
			return
		}
	}

	for _, e := range el {
		id := fmt.Sprintf("%x", e.PrimaryKey.Fingerprint)
		if _, ok := keyRing.Entities[id]; !ok {
			keyRing.Entities[id] = e
			n++
		}
	}
	return
}

type armourBuffer struct {
	*bytes.Buffer
}

func (ab *armourBuffer) Close() error {
	return nil
}

func newArmourBuffer() *armourBuffer {
	return &armourBuffer{new(bytes.Buffer)}
}

// Export writes out the named public key, or all public keys if keyID
// is empty. The result is an ASCII-armoured public key.
func (keyRing *KeyRing) Export(keyID string) (armoured string, err error) {
	buf := new(bytes.Buffer)
	blockType := "PGP PUBLIC KEY BLOCK"
	blockHeaders := map[string]string{
		"Version": fmt.Sprintf("Keybase Go client (OpenPGP version %s)", Version),
	}

	armourBuffer, err := armor.Encode(buf, blockType, blockHeaders)
	if err != nil {
		return
	}

	if keyID != "" {
		e, ok := keyRing.Entities[strings.ToLower(keyID)]
		if !ok {
			err = ErrKeyNotFound
			return
		}
		e.Serialize(armourBuffer)
	} else {
		if len(keyRing.Entities) == 0 {
			err = ErrKeyNotFound
			return
		}
		for _, e := range keyRing.Entities {
			e.Serialize(armourBuffer)
		}
	}

	armourBuffer.Close()

	armoured = string(buf.Bytes())
	return
}
<commit_msg>Remove unused code and add more docs.<commit_after>package openpgp

import (
	"code.google.com/p/go.crypto/openpgp"
	//"code.google.com/p/go.crypto/openpgp/packet"
	"bytes"
	"code.google.com/p/go.crypto/openpgp/armor"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

const Version = "0.1.0"

var (
	DefaultPublicKeyRing = filepath.Join(os.Getenv("HOME"), ".gnupg", "pubring.gpg")

	DefaultSecretKeyRing = filepath.Join(os.Getenv("HOME"), ".gnupg", "secring.gpg")
)

var (
	ErrPubRing     = errors.New("openpgp: public keyring")
	ErrSecRing     = errors.New("openpgp: secret keyring")
	ErrSecStore    = errors.New("openpgp: exporting secret keyring isn't supported'")
	ErrKeyNotFound = errors.New("openpgp: key not found")
)

// Paths to the public and secret keyrings.
var (
	PubRingPath string = DefaultPublicKeyRing
	SecRingPath string = DefaultSecretKeyRing
)

// A KeyRing contains a list of entities and the state required to
// maintain the key ring.
type KeyRing struct {
	Entities map[string]*openpgp.Entity
	path     string
	private  bool
}

// Private returns true if the keyring contains secret key material.
func (keyRing *KeyRing) Private() bool {
	return keyRing.private
}

// LoadKeyRing reads the unarmoured keyring stored at the named path.
func LoadKeyRing(path string) (keyRing *KeyRing, err error) {
	file, err := os.Open(path)
	if err != nil {
		return
	}
	defer file.Close()

	el, err := openpgp.ReadKeyRing(file)
	if err != nil {
		return
	}

	keyRing = new(KeyRing)
	keyRing.path = path
	keyRing.Entities = map[string]*openpgp.Entity{}
	for _, e := range el {
		if e.PrivateKey != nil {
			keyRing.private = true
		}
		id := fmt.Sprintf("%x", e.PrimaryKey.Fingerprint)
		keyRing.Entities[id] = e
	}
	return
}

// Store writes the keyring to disk as an unarmoured keyring.
func (keyRing *KeyRing) Store() (err error) {
	if keyRing.private {
		err = ErrSecStore
		return
	}
	tempFile, err := ioutil.TempFile(filepath.Dir(keyRing.path), "openpgp")
	if err != nil {
		return
	}
	defer tempFile.Close()

	for _, e := range keyRing.Entities {
		err = e.Serialize(tempFile)
		if err != nil {
			tempFile.Close()
			os.Remove(tempFile.Name())
			return
		}
	}
	tempFile.Close()
	err = os.Rename(tempFile.Name(), keyRing.path)
	if err != nil {
		os.Remove(tempFile.Name())
	}
	return
}

// Import imports an armoured public key block.
func (keyRing *KeyRing) Import(armoured string) (n int, err error) {
	buf := bytes.NewBufferString(armoured)
	el, err := openpgp.ReadArmoredKeyRing(buf)
	if err != nil {
		return
	}

	for _, e := range el {
		if keyRing.private && e.PrivateKey == nil {
			err = ErrSecRing
			return
		} else if !keyRing.private && e.PrivateKey != nil {
			err = ErrPubRing
			return
		}
	}

	for _, e := range el {
		id := fmt.Sprintf("%x", e.PrimaryKey.Fingerprint)
		if _, ok := keyRing.Entities[id]; !ok {
			keyRing.Entities[id] = e
			n++
		}
	}
	return
}

// Export writes out the named public key, or all public keys if keyID
// is empty. The result is an ASCII-armoured public key.
func (keyRing *KeyRing) Export(keyID string) (armoured string, err error) {
	buf := new(bytes.Buffer)
	blockType := "PGP PUBLIC KEY BLOCK"
	blockHeaders := map[string]string{
		"Version": fmt.Sprintf("Keybase Go client (OpenPGP version %s)", Version),
	}

	armourBuffer, err := armor.Encode(buf, blockType, blockHeaders)
	if err != nil {
		return
	}

	if keyID != "" {
		e, ok := keyRing.Entities[strings.ToLower(keyID)]
		if !ok {
			err = ErrKeyNotFound
			return
		}
		e.Serialize(armourBuffer)
	} else {
		if len(keyRing.Entities) == 0 {
			err = ErrKeyNotFound
			return
		}
		for _, e := range keyRing.Entities {
			e.Serialize(armourBuffer)
		}
	}

	armourBuffer.Close()

	armoured = string(buf.Bytes())
	return
}
<|endoftext|>


<commit_before>// Copyright 2015 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"fmt"
	"os"
	"strings"

	fct "github.com/FactomProject/factoid"
	"github.com/FactomProject/factom"
)

// balance prints the current balance of the specified address
func balance(args []string) error {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) < 2 {
		fmt.Println("Too few arguments")
		man("balance")
		return fmt.Errorf("Too Few Arguments")
	}

	switch args[0] {
	case "ec":
		return ecbalance(args[1])
	case "fct":
		return fctbalance(args[1])
	default:
		fmt.Println("Must specify an address type, either 'ec' or 'fct'")
		man("balance")
		return fmt.Errorf("")
	}

}

func ecbalance(addr string) error {

	if b, err := factom.ECBalance(addr); err != nil {
		fmt.Println(err)
		return err
	} else {
		fmt.Println("Balance of ", addr, " = ", b)
	}

	return nil
}

func fctbalance(addr string) error {

	if b, err := factom.FctBalance(addr); err != nil {
		fmt.Println(err)
		return err
	} else {
		fmt.Println("Balance of ", addr, " = ", fct.ConvertDecimalToString(uint64(b)))
	}

	return nil
}
<commit_msg>Removed unnecessary import<commit_after>// Copyright 2015 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"fmt"
	"os"

	fct "github.com/FactomProject/factoid"
	"github.com/FactomProject/factom"
)

// balance prints the current balance of the specified address
func balance(args []string) error {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) < 2 {
		fmt.Println("Too few arguments")
		man("balance")
		return fmt.Errorf("Too Few Arguments")
	}

	switch args[0] {
	case "ec":
		return ecbalance(args[1])
	case "fct":
		return fctbalance(args[1])
	default:
		fmt.Println("Must specify an address type, either 'ec' or 'fct'")
		man("balance")
		return fmt.Errorf("")
	}

}

func ecbalance(addr string) error {

	if b, err := factom.ECBalance(addr); err != nil {
		fmt.Println(err)
		return err
	} else {
		fmt.Println("Balance of ", addr, " = ", b)
	}

	return nil
}

func fctbalance(addr string) error {

	if b, err := factom.FctBalance(addr); err != nil {
		fmt.Println(err)
		return err
	} else {
		fmt.Println("Balance of ", addr, " = ", fct.ConvertDecimalToString(uint64(b)))
	}

	return nil
}
<|endoftext|>


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

package atomic

import (
	"unsafe"
)

// A Value provides an atomic load and store of a consistently typed value.
// Values can be created as part of other data structures.
// The zero value for a Value returns nil from Load.
// Once Store has been called, a Value must not be copied.
type Value struct {
	v interface{}
}

// ifaceWords is interface{} internal representation.
type ifaceWords struct {
	typ  unsafe.Pointer
	data unsafe.Pointer
}

// Load returns the value set by the most recent Store.
// It returns nil if there has been no call to Store for this Value.
func (v *Value) Load() (x interface{}) {
	vp := (*ifaceWords)(unsafe.Pointer(v))
	typ := LoadPointer(&vp.typ)
	if typ == nil || uintptr(typ) == ^uintptr(0) {
		// First store not yet completed.
		return nil
	}
	data := LoadPointer(&vp.data)
	xp := (*ifaceWords)(unsafe.Pointer(&x))
	xp.typ = typ
	xp.data = data
	return
}

// Store sets the value of the Value to v.
// All calls to Store for a given Value must use values of the same concrete type.
// Store of an inconsistent type panics, as does Store(nil).
func (v *Value) Store(x interface{}) {
	if x == nil {
		panic("sync/atomic: store of nil value into Value")
	}
	vp := (*ifaceWords)(unsafe.Pointer(v))
	xp := (*ifaceWords)(unsafe.Pointer(&x))
	for {
		typ := LoadPointer(&vp.typ)
		if typ == nil {
			// Attempt to start first store.
			// Disable preemption so that other goroutines can use
			// active spin wait to wait for completion; and so that
			// GC does not see the fake type accidentally.
			runtime_procPin()
			if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(^uintptr(0))) {
				runtime_procUnpin()
				continue
			}
			// Complete first store.
			StorePointer(&vp.data, xp.data)
			StorePointer(&vp.typ, xp.typ)
			runtime_procUnpin()
			return
		}
		if uintptr(typ) == ^uintptr(0) {
			// First store in progress. Wait.
			// Since we disable preemption around the first store,
			// we can wait with active spinning.
			continue
		}
		// First store completed. Check type and overwrite data.
		if typ != xp.typ {
			panic("sync/atomic: store of inconsistently typed value into Value")
		}
		StorePointer(&vp.data, xp.data)
		return
	}
}

// Disable/enable preemption, implemented in runtime.
func runtime_procPin()
func runtime_procUnpin()
<commit_msg>sync/atomic: fix comment referencing Value.Store's argument name<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package atomic

import (
	"unsafe"
)

// A Value provides an atomic load and store of a consistently typed value.
// Values can be created as part of other data structures.
// The zero value for a Value returns nil from Load.
// Once Store has been called, a Value must not be copied.
type Value struct {
	v interface{}
}

// ifaceWords is interface{} internal representation.
type ifaceWords struct {
	typ  unsafe.Pointer
	data unsafe.Pointer
}

// Load returns the value set by the most recent Store.
// It returns nil if there has been no call to Store for this Value.
func (v *Value) Load() (x interface{}) {
	vp := (*ifaceWords)(unsafe.Pointer(v))
	typ := LoadPointer(&vp.typ)
	if typ == nil || uintptr(typ) == ^uintptr(0) {
		// First store not yet completed.
		return nil
	}
	data := LoadPointer(&vp.data)
	xp := (*ifaceWords)(unsafe.Pointer(&x))
	xp.typ = typ
	xp.data = data
	return
}

// Store sets the value of the Value to x.
// All calls to Store for a given Value must use values of the same concrete type.
// Store of an inconsistent type panics, as does Store(nil).
func (v *Value) Store(x interface{}) {
	if x == nil {
		panic("sync/atomic: store of nil value into Value")
	}
	vp := (*ifaceWords)(unsafe.Pointer(v))
	xp := (*ifaceWords)(unsafe.Pointer(&x))
	for {
		typ := LoadPointer(&vp.typ)
		if typ == nil {
			// Attempt to start first store.
			// Disable preemption so that other goroutines can use
			// active spin wait to wait for completion; and so that
			// GC does not see the fake type accidentally.
			runtime_procPin()
			if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(^uintptr(0))) {
				runtime_procUnpin()
				continue
			}
			// Complete first store.
			StorePointer(&vp.data, xp.data)
			StorePointer(&vp.typ, xp.typ)
			runtime_procUnpin()
			return
		}
		if uintptr(typ) == ^uintptr(0) {
			// First store in progress. Wait.
			// Since we disable preemption around the first store,
			// we can wait with active spinning.
			continue
		}
		// First store completed. Check type and overwrite data.
		if typ != xp.typ {
			panic("sync/atomic: store of inconsistently typed value into Value")
		}
		StorePointer(&vp.data, xp.data)
		return
	}
}

// Disable/enable preemption, implemented in runtime.
func runtime_procPin()
func runtime_procUnpin()
<|endoftext|>


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

package raft

import pb "github.com/coreos/etcd/raft/raftpb"

// unstable.entries[i] has raft log position i+unstable.offset.
// Note that unstable.offset may be less than the highest log
// position in storage; this means that the next write to storage
// might need to truncate the log before persisting unstable.entries.
type unstable struct {
	// the incoming unstable snapshot, if any.
	snapshot *pb.Snapshot
	// all entries that have not yet been written to storage.
	entries []pb.Entry
	offset  uint64

	logger Logger
}

// maybeFirstIndex returns the index of the first possible entry in entries
// if it has a snapshot.
func (u *unstable) maybeFirstIndex() (uint64, bool) {
	if u.snapshot != nil {
		return u.snapshot.Metadata.Index + 1, true
	}
	return 0, false
}

// maybeLastIndex returns the last index if it has at least one
// unstable entry or snapshot.
func (u *unstable) maybeLastIndex() (uint64, bool) {
	if l := len(u.entries); l != 0 {
		return u.offset + uint64(l) - 1, true
	}
	if u.snapshot != nil {
		return u.snapshot.Metadata.Index, true
	}
	return 0, false
}

// maybeTerm returns the term of the entry at index i, if there
// is any.
func (u *unstable) maybeTerm(i uint64) (uint64, bool) {
	if i < u.offset {
		if u.snapshot == nil {
			return 0, false
		}
		if u.snapshot.Metadata.Index == i {
			return u.snapshot.Metadata.Term, true
		}
		return 0, false
	}

	last, ok := u.maybeLastIndex()
	if !ok {
		return 0, false
	}
	if i > last {
		return 0, false
	}
	return u.entries[i-u.offset].Term, true
}

func (u *unstable) stableTo(i, t uint64) {
	gt, ok := u.maybeTerm(i)
	if !ok {
		return
	}
	// if i < offset, term is matched with the snapshot
	// only update the unstable entries if term is matched with
	// an unstable entry.
	if gt == t && i >= u.offset {
		u.entries = u.entries[i+1-u.offset:]
		u.offset = i + 1
	}
}

func (u *unstable) stableSnapTo(i uint64) {
	if u.snapshot != nil && u.snapshot.Metadata.Index == i {
		u.snapshot = nil
	}
}

func (u *unstable) restore(s pb.Snapshot) {
	u.offset = s.Metadata.Index + 1
	u.entries = nil
	u.snapshot = &s
}

func (u *unstable) truncateAndAppend(ents []pb.Entry) {
	after := ents[0].Index - 1
	switch {
	case after == u.offset+uint64(len(u.entries))-1:
		// after is the last index in the u.entries
		// directly append
		u.entries = append(u.entries, ents...)
	case after < u.offset:
		u.logger.Infof("replace the unstable entries from index %d", after+1)
		// The log is being truncated to before our current offset
		// portion, so set the offset and replace the entries
		u.offset = after + 1
		u.entries = ents
	default:
		// truncate to after and copy to u.entries
		// then append
		u.logger.Infof("truncate the unstable entries to index %d", after)
		u.entries = append([]pb.Entry{}, u.slice(u.offset, after+1)...)
		u.entries = append(u.entries, ents...)
	}
}

func (u *unstable) slice(lo uint64, hi uint64) []pb.Entry {
	u.mustCheckOutOfBounds(lo, hi)
	return u.entries[lo-u.offset : hi-u.offset]
}

// u.offset <= lo <= hi <= u.offset+len(u.offset)
func (u *unstable) mustCheckOutOfBounds(lo, hi uint64) {
	if lo > hi {
		u.logger.Panicf("invalid unstable.slice %d > %d", lo, hi)
	}
	upper := u.offset + uint64(len(u.entries))
	if lo < u.offset || hi > upper {
		u.logger.Panicf("unstable.slice[%d,%d) out of bound [%d,%d]", lo, hi, u.offset, upper)
	}
}
<commit_msg>raft: simplify truncateAndAppend<commit_after>// Copyright 2015 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package raft

import pb "github.com/coreos/etcd/raft/raftpb"

// unstable.entries[i] has raft log position i+unstable.offset.
// Note that unstable.offset may be less than the highest log
// position in storage; this means that the next write to storage
// might need to truncate the log before persisting unstable.entries.
type unstable struct {
	// the incoming unstable snapshot, if any.
	snapshot *pb.Snapshot
	// all entries that have not yet been written to storage.
	entries []pb.Entry
	offset  uint64

	logger Logger
}

// maybeFirstIndex returns the index of the first possible entry in entries
// if it has a snapshot.
func (u *unstable) maybeFirstIndex() (uint64, bool) {
	if u.snapshot != nil {
		return u.snapshot.Metadata.Index + 1, true
	}
	return 0, false
}

// maybeLastIndex returns the last index if it has at least one
// unstable entry or snapshot.
func (u *unstable) maybeLastIndex() (uint64, bool) {
	if l := len(u.entries); l != 0 {
		return u.offset + uint64(l) - 1, true
	}
	if u.snapshot != nil {
		return u.snapshot.Metadata.Index, true
	}
	return 0, false
}

// maybeTerm returns the term of the entry at index i, if there
// is any.
func (u *unstable) maybeTerm(i uint64) (uint64, bool) {
	if i < u.offset {
		if u.snapshot == nil {
			return 0, false
		}
		if u.snapshot.Metadata.Index == i {
			return u.snapshot.Metadata.Term, true
		}
		return 0, false
	}

	last, ok := u.maybeLastIndex()
	if !ok {
		return 0, false
	}
	if i > last {
		return 0, false
	}
	return u.entries[i-u.offset].Term, true
}

func (u *unstable) stableTo(i, t uint64) {
	gt, ok := u.maybeTerm(i)
	if !ok {
		return
	}
	// if i < offset, term is matched with the snapshot
	// only update the unstable entries if term is matched with
	// an unstable entry.
	if gt == t && i >= u.offset {
		u.entries = u.entries[i+1-u.offset:]
		u.offset = i + 1
	}
}

func (u *unstable) stableSnapTo(i uint64) {
	if u.snapshot != nil && u.snapshot.Metadata.Index == i {
		u.snapshot = nil
	}
}

func (u *unstable) restore(s pb.Snapshot) {
	u.offset = s.Metadata.Index + 1
	u.entries = nil
	u.snapshot = &s
}

func (u *unstable) truncateAndAppend(ents []pb.Entry) {
	after := ents[0].Index
	switch {
	case after == u.offset+uint64(len(u.entries)):
		// after is the next index in the u.entries
		// directly append
		u.entries = append(u.entries, ents...)
	case after <= u.offset:
		u.logger.Infof("replace the unstable entries from index %d", after)
		// The log is being truncated to before our current offset
		// portion, so set the offset and replace the entries
		u.offset = after
		u.entries = ents
	default:
		// truncate to after and copy to u.entries
		// then append
		u.logger.Infof("truncate the unstable entries before index %d", after)
		u.entries = append([]pb.Entry{}, u.slice(u.offset, after)...)
		u.entries = append(u.entries, ents...)
	}
}

func (u *unstable) slice(lo uint64, hi uint64) []pb.Entry {
	u.mustCheckOutOfBounds(lo, hi)
	return u.entries[lo-u.offset : hi-u.offset]
}

// u.offset <= lo <= hi <= u.offset+len(u.offset)
func (u *unstable) mustCheckOutOfBounds(lo, hi uint64) {
	if lo > hi {
		u.logger.Panicf("invalid unstable.slice %d > %d", lo, hi)
	}
	upper := u.offset + uint64(len(u.entries))
	if lo < u.offset || hi > upper {
		u.logger.Panicf("unstable.slice[%d,%d) out of bound [%d,%d]", lo, hi, u.offset, upper)
	}
}
<|endoftext|>


<commit_before>// Copyright (C) 2016-2018 Vladimir Bauer
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
	Package decor contains common decorators for "github.com/vbauerster/mpb" package.

    All decorators returned by this package have some closure state. It is ok to use decorators concurrently,
    unless you share the same decorator among multiple *mpb.Bar instances. To avoid data races, create new
    decorator per *mpb.Bar instance.

	Don't:

          p := mpb.New()
          eta := decor.ETA(0, 0)
          p.AddBar(100, mpb.AppendDecorators(eta))
          p.AddBar(100, mpb.AppendDecorators(eta))

	Do:

          p := mpb.New()
          p.AddBar(100, mpb.AppendDecorators(decor.ETA(0, 0)))
          p.AddBar(100, mpb.AppendDecorators(decor.ETA(0, 0)))
*/
package decor
<commit_msg>decor doc upd<commit_after>// Copyright (C) 2016-2018 Vladimir Bauer
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
 Package decor contains common decorators for "github.com/vbauerster/mpb" package.

 All decorators returned by this package have some closure state. It is ok to use
 decorators concurrently, unless you share the same decorator among multiple
 *mpb.Bar instances. To avoid data races, create new decorator per *mpb.Bar
 instance.

 Don't:

	  p := mpb.New()
	  eta := decor.ETA(0, 0)
	  p.AddBar(100, mpb.AppendDecorators(eta))
	  p.AddBar(100, mpb.AppendDecorators(eta))

 Do:

	p := mpb.New()
	p.AddBar(100, mpb.AppendDecorators(decor.ETA(0, 0)))
	p.AddBar(100, mpb.AppendDecorators(decor.ETA(0, 0)))
*/
package decor
<|endoftext|>


<commit_before>package view

import (
	docklistener "github.com/byrnedo/dockdash/docklistener"
	. "github.com/byrnedo/dockdash/logger"
	goDocker "github.com/fsouza/go-dockerclient"
	ui "github.com/gizak/termui"
	"sort"
	"strconv"
	"strings"
	"time"
)

type UIEvent int

const (
	KeyArrowUp UIEvent = 1 << iota
	KeyArrowDown
	KeyArrowLeft
	KeyArrowRight
	KeyCtrlC
	KeyCtrlD
	KeyQ
	Resize
	KeyI
)

type DockerInfoType int

const (
	ImageInfo DockerInfoType = iota
	PortInfo
	BindInfo
	CommandInfo
	EntrypointInfo
	EnvInfo
	VolumesInfo
	TimeInfo
)

var InfoHeaders map[DockerInfoType]string = map[DockerInfoType]string{
	ImageInfo:      "Image",
	PortInfo:       "Ports",
	BindInfo:       "Mounts",
	CommandInfo:    "Command",
	EntrypointInfo: "Entrypoint",
	EnvInfo:        "Envs",
	VolumesInfo:    "Volumes",
	TimeInfo:       "Created At",
}

const MaxContainers = 1000
const MaxHorizPosition = int(TimeInfo)

type View struct {
	Header   *ui.Par
	InfoBar  *ui.Par
	CpuChart *ui.BarChart
	MemChart *ui.BarChart
	NameList *ui.List
	InfoList *ui.List
}

func createContainerList() *ui.List {
	list := ui.NewList()
	list.ItemFgColor = ui.ColorCyan
	list.BorderFg = ui.ColorBlack
	list.Border = true
	return list
}

type ContainerSlice []*goDocker.Container

func (p ContainerSlice) Len() int {
	return len(p)
}

func (p ContainerSlice) Less(i, j int) bool {
	return p[i].State.StartedAt.After(p[j].State.StartedAt)
}

func (p ContainerSlice) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}

func createDockerLineChart() *ui.LineChart {
	lc := ui.NewLineChart()
	lc.BorderLabel = "Container Numbers"
	lc.Height = 10
	lc.AxesColor = ui.ColorWhite
	lc.LineColor = ui.ColorRed | ui.AttrBold
	lc.Mode = "line"
	return lc
}

func NewView() *View {

	var view = View{}

	view.Header = ui.NewPar("Containers")
	view.Header.Border = false
	view.Header.Text = " Dockdash - Interactive realtime container inspector"
	view.Header.Height = 2

	view.InfoBar = ui.NewPar("InfoBar")
	view.InfoBar.Border = false
	view.InfoBar.Text = ""
	view.InfoBar.Height = 2

	view.NameList = createContainerList()
	view.NameList.BorderLabel = "Name"

	view.InfoList = createContainerList()
	view.InfoList.BorderLabel = "Image"

	view.CpuChart = ui.NewBarChart()
	view.CpuChart.Border = true
	view.CpuChart.BorderLabel = "%CPU"
	view.CpuChart.BorderFg = ui.ColorBlack
	view.CpuChart.Height = 8

	view.MemChart = ui.NewBarChart()
	view.MemChart.Border = true
	view.MemChart.BorderLabel = "%MEM"
	view.MemChart.BorderFg = ui.ColorBlack
	view.MemChart.Height = 8
	return &view
}

func (v *View) SetLayout() {
	ui.Body.AddRows(
		ui.NewRow(
			ui.NewCol(12, 0, v.Header),
		),

		ui.NewRow(
			ui.NewCol(12, 0, v.InfoBar),
		),
		ui.NewRow(
			ui.NewCol(12, 0, v.CpuChart),
		),
		ui.NewRow(
			ui.NewCol(12, 0, v.MemChart),
		),
		ui.NewRow(
			ui.NewCol(3, 0, v.NameList),
			ui.NewCol(9, 0, v.InfoList),
		),
	)
}

func (v *View) Align() {
	ui.Body.Align()
}

func (v *View) ResetSize() {
	if ui.TermWidth() > 20 {
		ui.Body.Width = ui.TermWidth()
		ui.Body.Align()
	}
}

func (v *View) Render() {
	ui.Clear()
	ui.Render(ui.Body)
}

func (v *View) UpdateStats(statsCharts *docklistener.StatsMsg, offset int) {
	v.CpuChart.Data = statsCharts.CpuChart.Data[offset:]
	v.CpuChart.DataLabels = statsCharts.CpuChart.DataLabels[offset:]
	v.MemChart.Data = statsCharts.MemChart.Data[offset:]
	v.MemChart.DataLabels = statsCharts.MemChart.DataLabels[offset:]
	//v.Render()
}

func (v *View) RenderContainers(containers map[string]*goDocker.Container, infoType DockerInfoType, listOffset int, inspectMode bool) {
	names, info := getNameAndInfoOfContainers(containers, listOffset, infoType, inspectMode)
	v.NameList.Height = len(names) + 2
	v.NameList.Items = names
	v.InfoList.Height = len(info) + 2
	v.InfoList.Items = info
	v.InfoList.BorderLabel = InfoHeaders[infoType]
	v.Render()
}

func getNameAndInfoOfContainers(containers map[string]*goDocker.Container, offset int, infoType DockerInfoType, inspectMode bool) ([]string, []string) {
	var numContainers = len(containers)
	if offset > numContainers {
		offset = numContainers - 1
	}

	var (
		info                []string
		numContainersSubset = numContainers - offset
		names               = make([]string, numContainersSubset)
		containersSorted    = mapValuesSorted(containers)
		nameStr             = ""
		containerNumber     = 0
	)

	if !inspectMode {
		info = make([]string, numContainersSubset)
	}

	for index, cont := range containersSorted {
		if index < offset {
			continue
		}

		containerNumber = numContainers - index
		nameStr = strconv.Itoa(containerNumber) + ". " + cont.ID[:12] + " " + strings.TrimLeft(cont.Name, "/")

		if inspectMode && index == offset {
			names[index-offset] = "*" + nameStr
			info = createInspectModeData(index, offset, infoType, cont)
		} else {
			names[index-offset] = " " + nameStr
			if !inspectMode {
				info[index-offset] = createRegularModeData(index, offset, infoType, cont)
			}
		}

	}
	return names, info
}

func createInspectModeData(index int, offset int, infoType DockerInfoType, cont *goDocker.Container) (info []string) {
	switch infoType {
	case ImageInfo:
		info = []string{cont.Config.Image}
	case PortInfo:
		info = createPortsSlice(cont.NetworkSettings.Ports)
	case BindInfo:
		info = make([]string, len(cont.HostConfig.Binds))
		for i, binding := range cont.HostConfig.Binds {
			info[i] = binding
		}
	case CommandInfo:
		info = make([]string, len(cont.Args))
		for i, arg := range cont.Args {
			info[i] = arg
		}
	case EnvInfo:
		info = make([]string, len(cont.Config.Env))
		for i, env := range cont.Config.Env {
			info[i] = env
		}
	case EntrypointInfo:
		info = make([]string, len(cont.Config.Entrypoint))
		for i, entrypoint := range cont.Config.Entrypoint {
			info[i] = entrypoint
		}
	case VolumesInfo:
		info = make([]string, len(cont.Volumes))
		i := 0
		for intVol, hostVol := range cont.Volumes {
			info[i] = intVol + ":" + hostVol + ""
			i++
		}
	case TimeInfo:
		info = []string{cont.State.StartedAt.Format(time.RubyDate)}
	default:
		Error.Println("Unhandled info type", infoType)
	}
	return
}

func createRegularModeData(index int, offset int, infoType DockerInfoType, cont *goDocker.Container) (info string) {

	switch infoType {
	case ImageInfo:
		info = cont.Config.Image
	case PortInfo:
		info = createPortsString(cont.NetworkSettings.Ports, ",")
	case BindInfo:
		info = strings.TrimRight(strings.Join(cont.HostConfig.Binds, ","), ",")
	case CommandInfo:
		info = cont.Path + " " + strings.Join(cont.Args, " ")
	case EnvInfo:
		info = strings.TrimRight(strings.Join(cont.Config.Env, ","), ",")
	case EntrypointInfo:
		info = strings.Join(cont.Config.Entrypoint, " ")
	case VolumesInfo:
		volStr := ""
		for intVol, hostVol := range cont.Volumes {
			volStr += intVol + ":" + hostVol + ","
		}
		info = strings.TrimRight(volStr, ",")
	case TimeInfo:
		info = cont.State.StartedAt.Format(time.RubyDate)
	default:
		Error.Println("Unhandled info type", infoType)
	}
	return
}

func mapValuesSorted(mapToSort map[string]*goDocker.Container) (sorted ContainerSlice) {

	sorted = make(ContainerSlice, len(mapToSort))
	var i = 0
	for _, val := range mapToSort {
		sorted[i] = val
		i++
	}
	sort.Sort(sorted)
	return
}

func createPortsString(ports map[goDocker.Port][]goDocker.PortBinding, sep string) (portsStr string) {

	for intPort, extHostPortList := range ports {
		if len(extHostPortList) == 0 {
			portsStr += intPort.Port() + "->N/A" + sep
		}
		for _, extHostPort := range extHostPortList {
			portsStr += intPort.Port() + "->" + extHostPort.HostIP + ":" + extHostPort.HostPort + sep
		}
	}
	return strings.TrimRight(portsStr, sep)
}

func createPortsSlice(ports map[goDocker.Port][]goDocker.PortBinding) (portsSlice []string) {

	portsSlice = make([]string, len(ports))
	i := 0
	for intPort, extHostPortList := range ports {
		if len(extHostPortList) == 0 {
			portsSlice[i] = intPort.Port() + "->N/A"
		}
		for _, extHostPort := range extHostPortList {
			portsSlice[i] = intPort.Port() + "->" + extHostPort.HostIP + ":" + extHostPort.HostPort
		}
		i++
	}
	return
}

func InitUIHandlers(uiEventChan chan<- UIEvent) {

	ui.Handle("/sys/kbd", func(e ui.Event) {
		Info.Printf("%+v\n", e)
	})
	ui.Handle("/sys/kbd/q", func(ui.Event) {
		uiEventChan <- KeyQ
	})

	ui.Handle("/sys/kbd/C-c", func(ui.Event) {
		uiEventChan <- KeyCtrlC
	})

	ui.Handle("/sys/kbd/C-d", func(ui.Event) {
		uiEventChan <- KeyCtrlD
	})

	ui.Handle("/sys/kbd/<left>", func(ui.Event) {
		uiEventChan <- KeyArrowLeft
	})

	ui.Handle("/sys/kbd/<right>", func(ui.Event) {
		uiEventChan <- KeyArrowRight
	})

	ui.Handle("/sys/kbd/<down>", func(ui.Event) {
		uiEventChan <- KeyArrowDown
	})

	ui.Handle("/sys/kbd/<up>", func(ui.Event) {
		uiEventChan <- KeyArrowUp
	})

	ui.Handle("sys/wnd/resize", func(ui.Event) {
		uiEventChan <- Resize
	})

	ui.Handle("/sys/kbd/i", func(ui.Event) {
		uiEventChan <- KeyI
	})

}
<commit_msg>Added full names tab<commit_after>package view

import (
	docklistener "github.com/byrnedo/dockdash/docklistener"
	. "github.com/byrnedo/dockdash/logger"
	goDocker "github.com/fsouza/go-dockerclient"
	ui "github.com/gizak/termui"
	"sort"
	"strconv"
	"strings"
	"time"
)

type UIEvent int

const (
	KeyArrowUp UIEvent = 1 << iota
	KeyArrowDown
	KeyArrowLeft
	KeyArrowRight
	KeyCtrlC
	KeyCtrlD
	KeyQ
	Resize
	KeyI
)

type DockerInfoType int

const (
	ImageInfo DockerInfoType = iota
	Names
	PortInfo
	BindInfo
	CommandInfo
	EntrypointInfo
	EnvInfo
	VolumesInfo
	TimeInfo
)

var InfoHeaders map[DockerInfoType]string = map[DockerInfoType]string{
	ImageInfo:      "Image",
	Names:          "Names",
	PortInfo:       "Ports",
	BindInfo:       "Mounts",
	CommandInfo:    "Command",
	EntrypointInfo: "Entrypoint",
	EnvInfo:        "Envs",
	VolumesInfo:    "Volumes",
	TimeInfo:       "Created At",
}

const MaxContainers = 1000
const MaxHorizPosition = int(TimeInfo)

type View struct {
	Header   *ui.Par
	InfoBar  *ui.Par
	CpuChart *ui.BarChart
	MemChart *ui.BarChart
	NameList *ui.List
	InfoList *ui.List
}

func createContainerList() *ui.List {
	list := ui.NewList()
	list.ItemFgColor = ui.ColorCyan
	list.BorderFg = ui.ColorBlack
	list.Border = true
	return list
}

type ContainerSlice []*goDocker.Container

func (p ContainerSlice) Len() int {
	return len(p)
}

func (p ContainerSlice) Less(i, j int) bool {
	return p[i].State.StartedAt.After(p[j].State.StartedAt)
}

func (p ContainerSlice) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}

func createDockerLineChart() *ui.LineChart {
	lc := ui.NewLineChart()
	lc.BorderLabel = "Container Numbers"
	lc.Height = 10
	lc.AxesColor = ui.ColorWhite
	lc.LineColor = ui.ColorRed | ui.AttrBold
	lc.Mode = "line"
	return lc
}

func NewView() *View {

	var view = View{}

	view.Header = ui.NewPar("Containers")
	view.Header.Border = false
	view.Header.Text = " Dockdash - Interactive realtime container inspector"
	view.Header.Height = 2

	view.InfoBar = ui.NewPar("InfoBar")
	view.InfoBar.Border = false
	view.InfoBar.Text = ""
	view.InfoBar.Height = 2

	view.NameList = createContainerList()
	view.NameList.BorderLabel = "Name"

	view.InfoList = createContainerList()
	view.InfoList.BorderLabel = "Image"

	view.CpuChart = ui.NewBarChart()
	view.CpuChart.Border = true
	view.CpuChart.BorderLabel = "%CPU"
	view.CpuChart.BorderFg = ui.ColorBlack
	view.CpuChart.Height = 8

	view.MemChart = ui.NewBarChart()
	view.MemChart.Border = true
	view.MemChart.BorderLabel = "%MEM"
	view.MemChart.BorderFg = ui.ColorBlack
	view.MemChart.Height = 8
	return &view
}

func (v *View) SetLayout() {
	ui.Body.AddRows(
		ui.NewRow(
			ui.NewCol(12, 0, v.Header),
		),

		ui.NewRow(
			ui.NewCol(12, 0, v.InfoBar),
		),
		ui.NewRow(
			ui.NewCol(12, 0, v.CpuChart),
		),
		ui.NewRow(
			ui.NewCol(12, 0, v.MemChart),
		),
		ui.NewRow(
			ui.NewCol(3, 0, v.NameList),
			ui.NewCol(9, 0, v.InfoList),
		),
	)
}

func (v *View) Align() {
	ui.Body.Align()
}

func (v *View) ResetSize() {
	if ui.TermWidth() > 20 {
		ui.Body.Width = ui.TermWidth()
		ui.Body.Align()
	}
}

func (v *View) Render() {
	ui.Clear()
	ui.Render(ui.Body)
}

func (v *View) UpdateStats(statsCharts *docklistener.StatsMsg, offset int) {
	v.CpuChart.Data = statsCharts.CpuChart.Data[offset:]
	v.CpuChart.DataLabels = statsCharts.CpuChart.DataLabels[offset:]
	v.MemChart.Data = statsCharts.MemChart.Data[offset:]
	v.MemChart.DataLabels = statsCharts.MemChart.DataLabels[offset:]
	//v.Render()
}

func (v *View) RenderContainers(containers map[string]*goDocker.Container, infoType DockerInfoType, listOffset int, inspectMode bool) {
	names, info := getNameAndInfoOfContainers(containers, listOffset, infoType, inspectMode)
	v.NameList.Height = len(names) + 2
	v.NameList.Items = names
	v.InfoList.Height = len(info) + 2
	v.InfoList.Items = info
	v.InfoList.BorderLabel = InfoHeaders[infoType]
	v.Render()
}

func getNameAndInfoOfContainers(containers map[string]*goDocker.Container, offset int, infoType DockerInfoType, inspectMode bool) ([]string, []string) {
	var numContainers = len(containers)
	if offset > numContainers {
		offset = numContainers - 1
	}

	var (
		info                []string
		numContainersSubset = numContainers - offset
		names               = make([]string, numContainersSubset)
		containersSorted    = mapValuesSorted(containers)
		nameStr             = ""
		containerNumber     = 0
	)

	if !inspectMode {
		info = make([]string, numContainersSubset)
	}

	for index, cont := range containersSorted {
		if index < offset {
			continue
		}

		containerNumber = numContainers - index
		nameStr = strconv.Itoa(containerNumber) + ". " + cont.ID[:12] + " " + strings.TrimLeft(cont.Name, "/")

		if inspectMode && index == offset {
			names[index-offset] = "*" + nameStr
			info = createInspectModeData(index, offset, infoType, cont)
		} else {
			names[index-offset] = " " + nameStr
			if !inspectMode {
				info[index-offset] = createRegularModeData(index, offset, infoType, cont)
			}
		}

	}
	return names, info
}

func createInspectModeData(index int, offset int, infoType DockerInfoType, cont *goDocker.Container) (info []string) {
	switch infoType {
	case ImageInfo:
		info = []string{cont.Config.Image}
	case Names:
		info = []string{cont.Name}
	case PortInfo:
		info = createPortsSlice(cont.NetworkSettings.Ports)
	case BindInfo:
		info = make([]string, len(cont.HostConfig.Binds))
		for i, binding := range cont.HostConfig.Binds {
			info[i] = binding
		}
	case CommandInfo:
		info = make([]string, len(cont.Args))
		for i, arg := range cont.Args {
			info[i] = arg
		}
	case EnvInfo:
		info = make([]string, len(cont.Config.Env))
		for i, env := range cont.Config.Env {
			info[i] = env
		}
	case EntrypointInfo:
		info = make([]string, len(cont.Config.Entrypoint))
		for i, entrypoint := range cont.Config.Entrypoint {
			info[i] = entrypoint
		}
	case VolumesInfo:
		info = make([]string, len(cont.Volumes))
		i := 0
		for intVol, hostVol := range cont.Volumes {
			info[i] = intVol + ":" + hostVol + ""
			i++
		}
	case TimeInfo:
		info = []string{cont.State.StartedAt.Format(time.RubyDate)}
	default:
		Error.Println("Unhandled info type", infoType)
	}
	return
}

func createRegularModeData(index int, offset int, infoType DockerInfoType, cont *goDocker.Container) (info string) {

	switch infoType {
	case ImageInfo:
		info = cont.Config.Image
	case Names:
		info = cont.Name
		if cont.Node != nil {
			info = cont.Node.Name + info
		}
	case PortInfo:
		info = createPortsString(cont.NetworkSettings.Ports, ",")
	case BindInfo:
		info = strings.TrimRight(strings.Join(cont.HostConfig.Binds, ","), ",")
	case CommandInfo:
		info = cont.Path + " " + strings.Join(cont.Args, " ")
	case EnvInfo:
		info = strings.TrimRight(strings.Join(cont.Config.Env, ","), ",")
	case EntrypointInfo:
		info = strings.Join(cont.Config.Entrypoint, " ")
	case VolumesInfo:
		volStr := ""
		for intVol, hostVol := range cont.Volumes {
			volStr += intVol + ":" + hostVol + ","
		}
		info = strings.TrimRight(volStr, ",")
	case TimeInfo:
		info = cont.State.StartedAt.Format(time.RubyDate)
	default:
		Error.Println("Unhandled info type", infoType)
	}
	return
}

func mapValuesSorted(mapToSort map[string]*goDocker.Container) (sorted ContainerSlice) {

	sorted = make(ContainerSlice, len(mapToSort))
	var i = 0
	for _, val := range mapToSort {
		sorted[i] = val
		i++
	}
	sort.Sort(sorted)
	return
}

func createPortsString(ports map[goDocker.Port][]goDocker.PortBinding, sep string) (portsStr string) {

	for intPort, extHostPortList := range ports {
		if len(extHostPortList) == 0 {
			portsStr += intPort.Port() + "->N/A" + sep
		}
		for _, extHostPort := range extHostPortList {
			portsStr += intPort.Port() + "->" + extHostPort.HostIP + ":" + extHostPort.HostPort + sep
		}
	}
	return strings.TrimRight(portsStr, sep)
}

func createPortsSlice(ports map[goDocker.Port][]goDocker.PortBinding) (portsSlice []string) {

	portsSlice = make([]string, len(ports))
	i := 0
	for intPort, extHostPortList := range ports {
		if len(extHostPortList) == 0 {
			portsSlice[i] = intPort.Port() + "->N/A"
		}
		for _, extHostPort := range extHostPortList {
			portsSlice[i] = intPort.Port() + "->" + extHostPort.HostIP + ":" + extHostPort.HostPort
		}
		i++
	}
	return
}

func InitUIHandlers(uiEventChan chan<- UIEvent) {

	ui.Handle("/sys/kbd", func(e ui.Event) {
		Info.Printf("%+v\n", e)
	})
	ui.Handle("/sys/kbd/q", func(ui.Event) {
		uiEventChan <- KeyQ
	})

	ui.Handle("/sys/kbd/C-c", func(ui.Event) {
		uiEventChan <- KeyCtrlC
	})

	ui.Handle("/sys/kbd/C-d", func(ui.Event) {
		uiEventChan <- KeyCtrlD
	})

	ui.Handle("/sys/kbd/<left>", func(ui.Event) {
		uiEventChan <- KeyArrowLeft
	})

	ui.Handle("/sys/kbd/<right>", func(ui.Event) {
		uiEventChan <- KeyArrowRight
	})

	ui.Handle("/sys/kbd/<down>", func(ui.Event) {
		uiEventChan <- KeyArrowDown
	})

	ui.Handle("/sys/kbd/<up>", func(ui.Event) {
		uiEventChan <- KeyArrowUp
	})

	ui.Handle("sys/wnd/resize", func(ui.Event) {
		uiEventChan <- Resize
	})

	ui.Handle("/sys/kbd/i", func(ui.Event) {
		uiEventChan <- KeyI
	})

}
<|endoftext|>