<commit_before>/*
Copyright 2017 The Kubernetes 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 resourcelock

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

	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
)

// TODO: This is almost a exact replica of Endpoints lock.
// going forwards as we self host more and more components
// and use ConfigMaps as the means to pass that configuration
// data we will likely move to deprecate the Endpoints lock.

type ConfigMapLock struct {
	// ConfigMapMeta should contain a Name and a Namespace of a
	// ConfigMapMeta object that the LeaderElector will attempt to lead.
	ConfigMapMeta metav1.ObjectMeta
	Client        corev1client.ConfigMapsGetter
	LockConfig    ResourceLockConfig
	cm            *v1.ConfigMap
}

// Get returns the election record from a ConfigMap Annotation
func (cml *ConfigMapLock) Get(ctx context.Context) (*LeaderElectionRecord, []byte, error) {
	var record LeaderElectionRecord
	var err error
	cml.cm, err = cml.Client.ConfigMaps(cml.ConfigMapMeta.Namespace).Get(ctx, cml.ConfigMapMeta.Name, metav1.GetOptions{})
	if err != nil {
		return nil, nil, err
	}
	if cml.cm.Annotations == nil {
		cml.cm.Annotations = make(map[string]string)
	}
	recordBytes, found := cml.cm.Annotations[LeaderElectionRecordAnnotationKey]
	if found {
		if err := json.Unmarshal([]byte(recordBytes), &record); err != nil {
			return nil, nil, err
		}
	}
	return &record, []byte(recordBytes), nil
}

// Create attempts to create a LeaderElectionRecord annotation
func (cml *ConfigMapLock) Create(ctx context.Context, ler LeaderElectionRecord) error {
	recordBytes, err := json.Marshal(ler)
	if err != nil {
		return err
	}
	cml.cm, err = cml.Client.ConfigMaps(cml.ConfigMapMeta.Namespace).Create(ctx, &v1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name:      cml.ConfigMapMeta.Name,
			Namespace: cml.ConfigMapMeta.Namespace,
			Annotations: map[string]string{
				LeaderElectionRecordAnnotationKey: string(recordBytes),
			},
		},
	}, metav1.CreateOptions{})
	return err
}

// Update will update an existing annotation on a given resource.
func (cml *ConfigMapLock) Update(ctx context.Context, ler LeaderElectionRecord) error {
	if cml.cm == nil {
		return errors.New("configmap not initialized, call get or create first")
	}
	recordBytes, err := json.Marshal(ler)
	if err != nil {
		return err
	}
	cml.cm.Annotations[LeaderElectionRecordAnnotationKey] = string(recordBytes)
	cml.cm, err = cml.Client.ConfigMaps(cml.ConfigMapMeta.Namespace).Update(ctx, cml.cm, metav1.UpdateOptions{})
	return err
}

// RecordEvent in leader election while adding meta-data
func (cml *ConfigMapLock) RecordEvent(s string) {
	if cml.LockConfig.EventRecorder == nil {
		return
	}
	events := fmt.Sprintf("%v %v", cml.LockConfig.Identity, s)
	cml.LockConfig.EventRecorder.Eventf(&v1.ConfigMap{ObjectMeta: cml.cm.ObjectMeta}, v1.EventTypeNormal, "LeaderElection", events)
}

// Describe is used to convert details on current resource lock
// into a string
func (cml *ConfigMapLock) Describe() string {
	return fmt.Sprintf("%v/%v", cml.ConfigMapMeta.Namespace, cml.ConfigMapMeta.Name)
}

// Identity returns the Identity of the lock
func (cml *ConfigMapLock) Identity() string {
	return cml.LockConfig.Identity
}
<commit_msg>Check Annotations map against nil for ConfigMapLock#Update()<commit_after>/*
Copyright 2017 The Kubernetes 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 resourcelock

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

	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
)

// TODO: This is almost a exact replica of Endpoints lock.
// going forwards as we self host more and more components
// and use ConfigMaps as the means to pass that configuration
// data we will likely move to deprecate the Endpoints lock.

type ConfigMapLock struct {
	// ConfigMapMeta should contain a Name and a Namespace of a
	// ConfigMapMeta object that the LeaderElector will attempt to lead.
	ConfigMapMeta metav1.ObjectMeta
	Client        corev1client.ConfigMapsGetter
	LockConfig    ResourceLockConfig
	cm            *v1.ConfigMap
}

// Get returns the election record from a ConfigMap Annotation
func (cml *ConfigMapLock) Get(ctx context.Context) (*LeaderElectionRecord, []byte, error) {
	var record LeaderElectionRecord
	var err error
	cml.cm, err = cml.Client.ConfigMaps(cml.ConfigMapMeta.Namespace).Get(ctx, cml.ConfigMapMeta.Name, metav1.GetOptions{})
	if err != nil {
		return nil, nil, err
	}
	if cml.cm.Annotations == nil {
		cml.cm.Annotations = make(map[string]string)
	}
	recordBytes, found := cml.cm.Annotations[LeaderElectionRecordAnnotationKey]
	if found {
		if err := json.Unmarshal([]byte(recordBytes), &record); err != nil {
			return nil, nil, err
		}
	}
	return &record, []byte(recordBytes), nil
}

// Create attempts to create a LeaderElectionRecord annotation
func (cml *ConfigMapLock) Create(ctx context.Context, ler LeaderElectionRecord) error {
	recordBytes, err := json.Marshal(ler)
	if err != nil {
		return err
	}
	cml.cm, err = cml.Client.ConfigMaps(cml.ConfigMapMeta.Namespace).Create(ctx, &v1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name:      cml.ConfigMapMeta.Name,
			Namespace: cml.ConfigMapMeta.Namespace,
			Annotations: map[string]string{
				LeaderElectionRecordAnnotationKey: string(recordBytes),
			},
		},
	}, metav1.CreateOptions{})
	return err
}

// Update will update an existing annotation on a given resource.
func (cml *ConfigMapLock) Update(ctx context.Context, ler LeaderElectionRecord) error {
	if cml.cm == nil {
		return errors.New("configmap not initialized, call get or create first")
	}
	recordBytes, err := json.Marshal(ler)
	if err != nil {
		return err
	}
	if cml.cm.Annotations == nil {
		cml.cm.Annotations = make(map[string]string)
	}
	cml.cm.Annotations[LeaderElectionRecordAnnotationKey] = string(recordBytes)
	cml.cm, err = cml.Client.ConfigMaps(cml.ConfigMapMeta.Namespace).Update(ctx, cml.cm, metav1.UpdateOptions{})
	return err
}

// RecordEvent in leader election while adding meta-data
func (cml *ConfigMapLock) RecordEvent(s string) {
	if cml.LockConfig.EventRecorder == nil {
		return
	}
	events := fmt.Sprintf("%v %v", cml.LockConfig.Identity, s)
	cml.LockConfig.EventRecorder.Eventf(&v1.ConfigMap{ObjectMeta: cml.cm.ObjectMeta}, v1.EventTypeNormal, "LeaderElection", events)
}

// Describe is used to convert details on current resource lock
// into a string
func (cml *ConfigMapLock) Describe() string {
	return fmt.Sprintf("%v/%v", cml.ConfigMapMeta.Namespace, cml.ConfigMapMeta.Name)
}

// Identity returns the Identity of the lock
func (cml *ConfigMapLock) Identity() string {
	return cml.LockConfig.Identity
}
<|endoftext|>


<commit_before>package main_test

import (
	"net/http/httptest"
	"os"
	"time"

	"github.com/cloudfoundry-incubator/auction/simulation/simulationrep"
	"github.com/cloudfoundry-incubator/bbs"
	"github.com/cloudfoundry-incubator/bbs/models"
	"github.com/cloudfoundry-incubator/rep"

	"github.com/pivotal-golang/lager"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	executorfakes "github.com/cloudfoundry-incubator/executor/fakes"
	"github.com/cloudfoundry-incubator/rep/evacuation/evacuation_context/fake_evacuation_context"
	rephandlers "github.com/cloudfoundry-incubator/rep/handlers"
	"github.com/cloudfoundry-incubator/rep/lrp_stopper/fake_lrp_stopper"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/rata"
)

type FakeCell struct {
	cellID      string
	stack       string
	server      *httptest.Server
	heartbeater ifrit.Process

	SimulationRep rep.SimClient
}

func SpinUpFakeCell(serviceClient bbs.ServiceClient, cellID string, stack string) *FakeCell {
	fakeRep := &FakeCell{
		cellID: cellID,
		stack:  stack,
	}

	fakeRep.SpinUp(serviceClient)

	return fakeRep
}

func (f *FakeCell) LRPs() ([]rep.LRP, error) {
	state, err := f.SimulationRep.State()
	if err != nil {
		return nil, err
	}
	return state.LRPs, nil
}

func (f *FakeCell) Tasks() ([]rep.Task, error) {
	state, err := f.SimulationRep.State()
	if err != nil {
		return nil, err
	}
	return state.Tasks, nil
}

func (f *FakeCell) SpinUp(serviceClient bbs.ServiceClient) {
	//make a test-friendly AuctionRepDelegate using the auction package's SimulationRepDelegate
	f.SimulationRep = simulationrep.New(f.stack, "Z0", rep.Resources{
		DiskMB:     100,
		MemoryMB:   100,
		Containers: 100,
	})

	//spin up an http auction server
	logger := lager.NewLogger(f.cellID)
	logger.RegisterSink(lager.NewWriterSink(GinkgoWriter, lager.INFO))

	fakeLRPStopper := new(fake_lrp_stopper.FakeLRPStopper)
	fakeExecutorClient := new(executorfakes.FakeClient)
	fakeEvacuatable := new(fake_evacuation_context.FakeEvacuatable)

	handlers := rephandlers.New(f.SimulationRep, fakeLRPStopper, fakeExecutorClient, fakeEvacuatable, logger)
	router, err := rata.NewRouter(rep.Routes, handlers)
	Expect(err).NotTo(HaveOccurred())
	f.server = httptest.NewServer(router)

	presence := models.NewCellPresence(
		f.cellID,
		f.server.URL,
		"az1",
		models.NewCellCapacity(512, 1024, 124),
		[]string{},
		[]string{})

	f.heartbeater = ifrit.Invoke(serviceClient.NewCellPresenceRunner(logger, &presence, time.Second))
}

func (f *FakeCell) Stop() {
	f.server.Close()
	f.heartbeater.Signal(os.Interrupt)
	Eventually(f.heartbeater.Wait()).Should(Receive())
}
<commit_msg>Remove reference to deleted lrp_stopper<commit_after>package main_test

import (
	"net/http/httptest"
	"os"
	"time"

	"github.com/cloudfoundry-incubator/auction/simulation/simulationrep"
	"github.com/cloudfoundry-incubator/bbs"
	"github.com/cloudfoundry-incubator/bbs/models"
	"github.com/cloudfoundry-incubator/rep"

	"github.com/pivotal-golang/lager"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	executorfakes "github.com/cloudfoundry-incubator/executor/fakes"
	"github.com/cloudfoundry-incubator/rep/evacuation/evacuation_context/fake_evacuation_context"
	rephandlers "github.com/cloudfoundry-incubator/rep/handlers"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/rata"
)

type FakeCell struct {
	cellID      string
	stack       string
	server      *httptest.Server
	heartbeater ifrit.Process

	SimulationRep rep.SimClient
}

func SpinUpFakeCell(serviceClient bbs.ServiceClient, cellID string, stack string) *FakeCell {
	fakeRep := &FakeCell{
		cellID: cellID,
		stack:  stack,
	}

	fakeRep.SpinUp(serviceClient)

	return fakeRep
}

func (f *FakeCell) LRPs() ([]rep.LRP, error) {
	state, err := f.SimulationRep.State()
	if err != nil {
		return nil, err
	}
	return state.LRPs, nil
}

func (f *FakeCell) Tasks() ([]rep.Task, error) {
	state, err := f.SimulationRep.State()
	if err != nil {
		return nil, err
	}
	return state.Tasks, nil
}

func (f *FakeCell) SpinUp(serviceClient bbs.ServiceClient) {
	//make a test-friendly AuctionRepDelegate using the auction package's SimulationRepDelegate
	f.SimulationRep = simulationrep.New(f.stack, "Z0", rep.Resources{
		DiskMB:     100,
		MemoryMB:   100,
		Containers: 100,
	})

	//spin up an http auction server
	logger := lager.NewLogger(f.cellID)
	logger.RegisterSink(lager.NewWriterSink(GinkgoWriter, lager.INFO))

	fakeExecutorClient := new(executorfakes.FakeClient)
	fakeEvacuatable := new(fake_evacuation_context.FakeEvacuatable)

	handlers := rephandlers.New(f.SimulationRep, fakeExecutorClient, fakeEvacuatable, logger)
	router, err := rata.NewRouter(rep.Routes, handlers)
	Expect(err).NotTo(HaveOccurred())
	f.server = httptest.NewServer(router)

	presence := models.NewCellPresence(
		f.cellID,
		f.server.URL,
		"az1",
		models.NewCellCapacity(512, 1024, 124),
		[]string{},
		[]string{})

	f.heartbeater = ifrit.Invoke(serviceClient.NewCellPresenceRunner(logger, &presence, time.Second))
}

func (f *FakeCell) Stop() {
	f.server.Close()
	f.heartbeater.Signal(os.Interrupt)
	Eventually(f.heartbeater.Wait()).Should(Receive())
}
<|endoftext|>


<commit_before>// Copyright 2020 The Prometheus 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.
//
//go:build !windows
// +build !windows

package main

import (
	"net/http"
	"os"
	"os/exec"
	"testing"
	"time"
)

// As soon as prometheus starts responding to http request it should be able to
// accept Interrupt signals for a graceful shutdown.
func TestStartupInterrupt(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping test in short mode.")
	}

	prom := exec.Command(promPath, "-test.main", "--config.file="+promConfig, "--storage.tsdb.path="+t.TempDir())
	err := prom.Start()
	if err != nil {
		t.Fatalf("execution error: %v", err)
	}

	done := make(chan error, 1)
	go func() {
		done <- prom.Wait()
	}()

	var startedOk bool
	var stoppedErr error

Loop:
	for x := 0; x < 10; x++ {
		// error=nil means prometheus has started so we can send the interrupt
		// signal and wait for the graceful shutdown.
		if _, err := http.Get("http://localhost:9090/graph"); err == nil {
			startedOk = true
			prom.Process.Signal(os.Interrupt)
			select {
			case stoppedErr = <-done:
				break Loop
			case <-time.After(10 * time.Second):
			}
			break Loop
		}
		time.Sleep(500 * time.Millisecond)
	}

	if !startedOk {
		t.Fatal("prometheus didn't start in the specified timeout")
	}
	if err := prom.Process.Kill(); err == nil {
		t.Errorf("prometheus didn't shutdown gracefully after sending the Interrupt signal")
	} else if stoppedErr != nil && stoppedErr.Error() != "signal: interrupt" { // TODO - find a better way to detect when the process didn't exit as expected!
		t.Errorf("prometheus exited with an unexpected error: %v", stoppedErr)
	}
}
<commit_msg>cmd/prometheus: use random listen port in TestStartupInterrupt test<commit_after>// Copyright 2020 The Prometheus 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.
//
//go:build !windows
// +build !windows

package main

import (
	"fmt"
	"net/http"
	"os"
	"os/exec"
	"testing"
	"time"

	"github.com/prometheus/prometheus/util/testutil"
)

// As soon as prometheus starts responding to http request it should be able to
// accept Interrupt signals for a graceful shutdown.
func TestStartupInterrupt(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping test in short mode.")
	}

	port := fmt.Sprintf(":%d", testutil.RandomUnprivilegedPort(t))

	prom := exec.Command(promPath, "-test.main", "--config.file="+promConfig, "--storage.tsdb.path="+t.TempDir(), "--web.listen-address=0.0.0.0"+port)
	err := prom.Start()
	if err != nil {
		t.Fatalf("execution error: %v", err)
	}

	done := make(chan error, 1)
	go func() {
		done <- prom.Wait()
	}()

	var startedOk bool
	var stoppedErr error

	url := "http://localhost" + port + "/graph"

Loop:
	for x := 0; x < 10; x++ {
		// error=nil means prometheus has started so we can send the interrupt
		// signal and wait for the graceful shutdown.
		if _, err := http.Get(url); err == nil {
			startedOk = true
			prom.Process.Signal(os.Interrupt)
			select {
			case stoppedErr = <-done:
				break Loop
			case <-time.After(10 * time.Second):
			}
			break Loop
		}
		time.Sleep(500 * time.Millisecond)
	}

	if !startedOk {
		t.Fatal("prometheus didn't start in the specified timeout")
	}
	if err := prom.Process.Kill(); err == nil {
		t.Errorf("prometheus didn't shutdown gracefully after sending the Interrupt signal")
	} else if stoppedErr != nil && stoppedErr.Error() != "signal: interrupt" { // TODO - find a better way to detect when the process didn't exit as expected!
		t.Errorf("prometheus exited with an unexpected error: %v", stoppedErr)
	}
}
<|endoftext|>


<commit_before>package assert

import (
	"reflect"
)

type anyTypeAssertImpl struct {
	logFacade *logFacade
	actual    interface{}
}

func (assert *anyTypeAssertImpl) isTrue(condition bool, format string, args ...interface{}) *anyTypeAssertImpl {
	logIfFalse(assert.logFacade, condition, format, args...)
	return assert
}

func (assert *anyTypeAssertImpl) IsEqualTo(expected interface{}) AnyTypeAssert {
	return assert.isTrue(reflect.DeepEqual(assert.actual, expected),
		"Expected <%v>, but was <%v>.", expected, assert.actual)
}

func (assert *anyTypeAssertImpl) IsNotEqualTo(expected interface{}) AnyTypeAssert {
	return assert.isTrue(!reflect.DeepEqual(assert.actual, expected),
		"Expected value not equal to <%v>, but was equal.", expected)
}

func (assert *anyTypeAssertImpl) IsNil() AnyTypeAssert {
	return assert.isTrue(assert.actual == nil,
		"Expected value to be nil, but was <%v>.", assert.actual)
}

func (assert *anyTypeAssertImpl) IsNotNil() AnyTypeAssert {
	return assert.isTrue(assert.actual != nil,
		"Expected value not to be nil, but was.")
}

func (assert *anyTypeAssertImpl) AsBool() BoolAssert {
	if assert.actual != nil {
		val, kind := valueWithKind(assert.actual)
		if kind == reflect.Bool {
			return &boolAssertImpl{assert.logFacade, val.Bool()}
		}
	}
	assert.isTrue(false, "Cannot convert <%v> of type <%T> to <bool>.", assert.actual, assert.actual)
	return &boolAssertImpl{}
}

func (assert *anyTypeAssertImpl) AsInt() IntAssert {
	if assert.actual != nil {
		val, kind := valueWithKind(assert.actual)
		switch kind {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
			return &intAssertImpl{assert.logFacade, int(val.Int())}
		case reflect.Uint8, reflect.Uint16:
			return &intAssertImpl{assert.logFacade, int(val.Uint())}
		}
	}
	assert.isTrue(false, "Cannot convert <%v> of type <%T> to <int>.", assert.actual, assert.actual)
	return &intAssertImpl{}
}

func (assert *anyTypeAssertImpl) AsString() StringAssert {
	if assert.actual != nil {
		val, kind := valueWithKind(assert.actual)
		if kind == reflect.String {
			return &stringAssertImpl{assert.logFacade, val.String()}
		}
	}
	assert.isTrue(false, "Cannot convert <%v> of type <%T> to <string>.", assert.actual, assert.actual)
	return &stringAssertImpl{}
}

func valueWithKind(data interface{}) (val reflect.Value, kind reflect.Kind) {
	val = reflect.ValueOf(data)
	kind = val.Type().Kind()
	return
}
<commit_msg>refactoring: moved if into valueWithKind<commit_after>package assert

import (
	"reflect"
)

type anyTypeAssertImpl struct {
	logFacade *logFacade
	actual    interface{}
}

func (assert *anyTypeAssertImpl) isTrue(condition bool, format string, args ...interface{}) *anyTypeAssertImpl {
	logIfFalse(assert.logFacade, condition, format, args...)
	return assert
}

func (assert *anyTypeAssertImpl) IsEqualTo(expected interface{}) AnyTypeAssert {
	return assert.isTrue(reflect.DeepEqual(assert.actual, expected),
		"Expected <%v>, but was <%v>.", expected, assert.actual)
}

func (assert *anyTypeAssertImpl) IsNotEqualTo(expected interface{}) AnyTypeAssert {
	return assert.isTrue(!reflect.DeepEqual(assert.actual, expected),
		"Expected value not equal to <%v>, but was equal.", expected)
}

func (assert *anyTypeAssertImpl) IsNil() AnyTypeAssert {
	return assert.isTrue(assert.actual == nil,
		"Expected value to be nil, but was <%v>.", assert.actual)
}

func (assert *anyTypeAssertImpl) IsNotNil() AnyTypeAssert {
	return assert.isTrue(assert.actual != nil,
		"Expected value not to be nil, but was.")
}

func (assert *anyTypeAssertImpl) AsBool() BoolAssert {
	val, kind := valueWithKind(assert.actual)
	if kind == reflect.Bool {
		return &boolAssertImpl{assert.logFacade, val.Bool()}
	}
	assert.isTrue(false, "Cannot convert <%v> of type <%T> to <bool>.", assert.actual, assert.actual)
	return &boolAssertImpl{}
}

func (assert *anyTypeAssertImpl) AsInt() IntAssert {
	val, kind := valueWithKind(assert.actual)
	switch kind {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
		return &intAssertImpl{assert.logFacade, int(val.Int())}
	case reflect.Uint8, reflect.Uint16:
		return &intAssertImpl{assert.logFacade, int(val.Uint())}
	}
	assert.isTrue(false, "Cannot convert <%v> of type <%T> to <int>.", assert.actual, assert.actual)
	return &intAssertImpl{}
}

func (assert *anyTypeAssertImpl) AsString() StringAssert {
	val, kind := valueWithKind(assert.actual)
	if kind == reflect.String {
		return &stringAssertImpl{assert.logFacade, val.String()}
	}
	assert.isTrue(false, "Cannot convert <%v> of type <%T> to <string>.", assert.actual, assert.actual)
	return &stringAssertImpl{}
}

func valueWithKind(data interface{}) (val reflect.Value, kind reflect.Kind) {
	if data != nil {
		val = reflect.ValueOf(data)
		kind = val.Type().Kind()
	}
	return
}
<|endoftext|>


<commit_before>package api

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

const testAutoBackupName = "test_libsakuracloud_ab"

func TestAutoBackupCRUD(t *testing.T) {

	currentRegion := client.Zone
	defer func() { client.Zone = currentRegion }()
	client.Zone = "is1b"
	api := client.AutoBackup

	disk := client.Disk.New()
	disk.Name = testAutoBackupName
	disk, err := client.Disk.Create(disk)

	assert.NoError(t, err)
	assert.NotEmpty(t, disk)

	//CREATE
	ab := api.New(testAutoBackupName, disk.ID)

	ab.Description = "before"
	ab.SetBackupHour(0)
	ab.SetBackupMaximumNumberOfArchives(2)
	ab.SetBackupSpanWeekdays([]string{"mon", "tue", "wed"})

	item, err := client.AutoBackup.Create(ab)

	assert.NoError(t, err)
	assert.NotNil(t, item)
	assert.Equal(t, item.Name, testAutoBackupName)
	assert.Equal(t, item.Description, "before")
	assert.Equal(t, item.Settings.Autobackup.BackupHour, 0)
	assert.Equal(t, item.Settings.Autobackup.MaximumNumberOfArchives, 2)
	assert.Equal(t, item.Settings.Autobackup.BackupSpanWeekdays, []string{"mon", "tue", "wed"})

	id := item.ID

	//READ
	item, err = api.Read(id)
	assert.NoError(t, err)
	assert.NotEmpty(t, item)

	//UPDATE
	item.Description = "after"
	item.SetBackupHour(6)
	item.SetBackupMaximumNumberOfArchives(3)
	item.SetBackupSpanWeekdays([]string{"mon", "tue", "sat", "sun"})

	item, err = api.Update(id, item)

	assert.NoError(t, err)
	assert.NotEqual(t, item.Description, "before")
	assert.Equal(t, item.Settings.Autobackup.BackupHour, 6)
	assert.Equal(t, item.Settings.Autobackup.MaximumNumberOfArchives, 3)
	assert.Equal(t, item.Settings.Autobackup.BackupSpanWeekdays, []string{"mon", "tue", "sat", "sun"})

	//Delete
	_, err = api.Delete(id)
	assert.NoError(t, err)
}

func init() {
	testSetupHandlers = append(testSetupHandlers, cleanupAutoBackupCommonServiceItem)
	testTearDownHandlers = append(testTearDownHandlers, cleanupAutoBackupCommonServiceItem)
}

func cleanupAutoBackupCommonServiceItem() {
	currentRegion := client.Zone
	defer func() { client.Zone = currentRegion }()
	client.Zone = "is1b"

	items, _ := client.AutoBackup.Reset().WithNameLike(testAutoBackupName).Find()
	for _, item := range items.CommonServiceAutoBackupItems {
		client.AutoBackup.Delete(item.ID)
	}

	disks, _ := client.Disk.Reset().WithNameLike(testAutoBackupName).Find()
	for _, disk := range disks.Disks {
		client.Disk.Delete(disk.ID)
	}
}
<commit_msg>Fix Autobackup test<commit_after>package api

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

const testAutoBackupName = "test_libsakuracloud_ab"

func TestAutoBackupCRUD(t *testing.T) {

	currentRegion := client.Zone
	defer func() { client.Zone = currentRegion }()
	client.Zone = "is1b"
	api := client.AutoBackup

	disk := client.Disk.New()
	disk.Name = testAutoBackupName
	disk, err := client.Disk.Create(disk)

	assert.NoError(t, err)
	assert.NotEmpty(t, disk)

	//CREATE
	ab := api.New(testAutoBackupName, disk.ID)

	ab.Description = "before"
	ab.SetBackupHour(6)
	ab.SetBackupMaximumNumberOfArchives(2)
	ab.SetBackupSpanWeekdays([]string{"mon", "tue", "wed"})

	item, err := client.AutoBackup.Create(ab)

	assert.NoError(t, err)
	assert.NotNil(t, item)
	assert.Equal(t, item.Name, testAutoBackupName)
	assert.Equal(t, item.Description, "before")
	assert.Equal(t, item.Settings.Autobackup.BackupHour, 6)
	assert.Equal(t, item.Settings.Autobackup.MaximumNumberOfArchives, 2)
	assert.Equal(t, item.Settings.Autobackup.BackupSpanWeekdays, []string{"mon", "tue", "wed"})

	id := item.ID

	//READ
	item, err = api.Read(id)
	assert.NoError(t, err)
	assert.NotEmpty(t, item)

	//UPDATE
	item.Description = "after"
	item.SetBackupHour(12)
	item.SetBackupMaximumNumberOfArchives(3)
	item.SetBackupSpanWeekdays([]string{"mon", "tue", "sat", "sun"})

	item, err = api.Update(id, item)

	assert.NoError(t, err)
	assert.NotEqual(t, item.Description, "before")
	assert.Equal(t, item.Settings.Autobackup.BackupHour, 12)
	assert.Equal(t, item.Settings.Autobackup.MaximumNumberOfArchives, 3)
	assert.Equal(t, item.Settings.Autobackup.BackupSpanWeekdays, []string{"mon", "tue", "sat", "sun"})

	//Delete
	_, err = api.Delete(id)
	assert.NoError(t, err)
}

func init() {
	testSetupHandlers = append(testSetupHandlers, cleanupAutoBackupCommonServiceItem)
	testTearDownHandlers = append(testTearDownHandlers, cleanupAutoBackupCommonServiceItem)
}

func cleanupAutoBackupCommonServiceItem() {
	currentRegion := client.Zone
	defer func() { client.Zone = currentRegion }()
	client.Zone = "is1b"

	items, _ := client.AutoBackup.Reset().WithNameLike(testAutoBackupName).Find()
	for _, item := range items.CommonServiceAutoBackupItems {
		client.AutoBackup.Delete(item.ID)
	}

	disks, _ := client.Disk.Reset().WithNameLike(testAutoBackupName).Find()
	for _, disk := range disks.Disks {
		client.Disk.Delete(disk.ID)
	}
}
<|endoftext|>


<commit_before>package tests

import (
	"github.com/tidwall/pinhole"
	"image/color"
	"nli-go/lib/common"
	"nli-go/lib/global"
	"os"
	"strconv"
	"testing"
)

// Mimics some of SHRDLU's functions, but in the nli-go way

// Using Pinhole https://github.com/tidwall/pinhole to render the scene to a png
//
// go get -u github.com/tidwall/pinhole
//
func TestBlocksWorld(t *testing.T) {
	log := common.NewSystemLog(false)
	system := global.NewSystem(common.Dir() + "/../../resources/blocks", log)
	sessionId := "1"
	actualSessionPath := common.AbsolutePath(common.Dir(), "sessions/" + sessionId + ".json")

	if !log.IsOk() {
		t.Errorf(log.String())
		return
	}

	var tests = [][]struct {
		question      string
		answer        string
	}{
		{
				{"Does the table support the big red block?", "Yes"},
			{"Pick up a big red block", "OK"},
				{"Does the table support the big red block?", "No"},

			// todo "I don't understand which pyramid you mean"
			{"Grasp the pyramid", "I don't understand which one you mean"},

				{"Is the blue block in the box?", "No"},
			// todo "By "it", I assume you mean the block which is taller than the one I am holding"
			{"Find a block which is taller than the one you are holding and put it into the box.", "OK"},
				{"Is the blue block in the box?", "Yes"},

			{"What does the box contain?", "The blue pyramid and the blue block"},
			{"What is the pyramid supported by?", "The box"},
			{"How many blocks are not in the box?", "Four of them"},
			{"Is at least one of them narrower than the one which I told you to pick up?", "Yes, the red cube"},
			{"Is it supported?", "Yes, by the table"},
			{"Can the table pick up blocks?", "No"},
			{"Can a pyramid be supported by a block?", "Yes"},
			// todo: must be: I don't know
			{"Can a pyramid support a pyramid?", "No"},
			{"Stack up two pyramids.", "I can't"},

				//{"Do I own the blue pyramid?", "No"},
			{"The blue pyramid is mine", "I understand"},
				{"Do I own the blue pyramid?", "Yes"},

				{"Do I own a green block?", "No"},
			{"I own blocks which are not red, but I don't own anything which supports a pyramid", "I understand"},
				{"Do I own a green block?", "Yes"},
				{"Do I own all green blocks?", "No"},

			{"Do I own the box?", "No"},

			// todo: must be: Yes, two things: the blue block and the blue pyramid
			{"Do I own anything in the box?", "Yes, the blue block and the blue pyramid"},

				{"Does a green block support a pyramid?", "Yes"},
			{"Will you please stack up both of the red blocks and either a green cube or a pyramid?", "OK"},
				{"Is the small red block supported by a green block?", "Yes"},
				{"Is a green block supported by the big red block?", "Yes"},
				{"Does a green block support a pyramid?", "Yes"},

			{"Which cube is sitting on the table?", "The large green one which supports the red pyramid"},

			//{"Is there a large block behind a pyramid?", "Yes, three of them: a large red one, a large green cube and a blue one"},
		},
		{
		},
	}

	_ = os.Remove(actualSessionPath)

	for _, session := range tests {

		for _, test := range session {

			log.Clear()

			system.PopulateDialogContext(actualSessionPath, false)

			answer, options := system.Answer(test.question)

			if options.HasOptions() {
				answer += options.String()
			}

			system.StoreDialogContext(actualSessionPath)

			if answer != test.answer {
				t.Errorf("Test relationships: got %v, want %v", answer, test.answer)
				t.Error(log.String())
			}
		}
	}

	createImage(system)
}

func createImage(system *global.System) {

	p := pinhole.New()

	data := system.Query("dom:at(E, X, Z, Y) dom:type(E, Type) dom:color(E, Color) dom:size(E, Width, Length, Height)")

	p.DrawCube(-.99, -.99, -.99, .99, .99, .99)

	scale := 500.0

	for _, binding := range data {

		p.Begin()

		x, _ := strconv.ParseFloat(binding["X"].TermValue, 64)
		y, _ := strconv.ParseFloat(binding["Y"].TermValue, 64)
		z, _ := strconv.ParseFloat(binding["Z"].TermValue, 64)
		theType := binding["Type"].TermValue
		theColor := binding["Color"].TermValue
		width, _ := strconv.ParseFloat(binding["Width"].TermValue, 64)
		length, _ := strconv.ParseFloat(binding["Length"].TermValue, 64)
		height, _ := strconv.ParseFloat(binding["Height"].TermValue, 64)

		x1 := (x - 500) / scale
		y1 := (y - 500) / scale
		z1 := (z - 0) / scale

		x2 := x1 + width / scale
		y2 := y1 + height / scale
		z2 := z1 + length / scale

		if theType == "pyramid" {
			drawPyramid(p, x1, y1, z1, width / scale, height / scale)
		} else {
			p.DrawCube(x1, y1, z1, x2, y2, z2)
		}

		switch theColor {
		case "red":
			p.Colorize(color.RGBA{255, 0, 0, 255})
		case "green":
			p.Colorize(color.RGBA{0, 255, 0, 255})
		case "blue":
			p.Colorize(color.RGBA{0, 0, 255, 255})
		default:
			p.Colorize(color.RGBA{0, 0, 0, 255})
		}

		p.End()
	}

	p.SavePNG(common.Dir() + "/blocksworld.png", 1200, 600, nil)
}

func drawPyramid(p *pinhole.Pinhole, x float64, y float64, z float64, width float64, height float64) {
	topX := x + width / 2
	topY := y + height
	topZ := z + width / 2

	p.DrawLine(x, y, z, x + width, y, z)
	p.DrawLine(x + width, y, z, x + width, y, z + width)
	p.DrawLine(x + width, y, z + width, x, y, z + width)
	p.DrawLine(x, y, z + width, x, y, z)

	p.DrawLine(x, y, z, topX, topY, topZ)
	p.DrawLine(x + width, y, z, topX, topY, topZ)
	p.DrawLine(x + width, y, z + width, topX, topY, topZ)
	p.DrawLine(x, y, z + width, topX, topY, topZ)
}<commit_msg>improve image<commit_after>package tests

import (
	"github.com/tidwall/pinhole"
	"image/color"
	"nli-go/lib/common"
	"nli-go/lib/global"
	"os"
	"strconv"
	"testing"
)

// Mimics some of SHRDLU's functions, but in the nli-go way

// Using Pinhole https://github.com/tidwall/pinhole to render the scene to a png
//
// go get -u github.com/tidwall/pinhole
//
func TestBlocksWorld(t *testing.T) {
	log := common.NewSystemLog(false)
	system := global.NewSystem(common.Dir() + "/../../resources/blocks", log)
	sessionId := "1"
	actualSessionPath := common.AbsolutePath(common.Dir(), "sessions/" + sessionId + ".json")

	if !log.IsOk() {
		t.Errorf(log.String())
		return
	}

	var tests = [][]struct {
		question      string
		answer        string
	}{
		{
				{"Does the table support the big red block?", "Yes"},
			{"Pick up a big red block", "OK"},
				{"Does the table support the big red block?", "No"},

			// todo "I don't understand which pyramid you mean"
			{"Grasp the pyramid", "I don't understand which one you mean"},

				{"Is the blue block in the box?", "No"},
			// todo "By "it", I assume you mean the block which is taller than the one I am holding"
			{"Find a block which is taller than the one you are holding and put it into the box.", "OK"},
				{"Is the blue block in the box?", "Yes"},

			{"What does the box contain?", "The blue pyramid and the blue block"},
			{"What is the pyramid supported by?", "The box"},
			{"How many blocks are not in the box?", "Four of them"},
			{"Is at least one of them narrower than the one which I told you to pick up?", "Yes, the red cube"},
			{"Is it supported?", "Yes, by the table"},
			{"Can the table pick up blocks?", "No"},
			{"Can a pyramid be supported by a block?", "Yes"},
			// todo: must be: I don't know
			{"Can a pyramid support a pyramid?", "No"},
			{"Stack up two pyramids.", "I can't"},

				//{"Do I own the blue pyramid?", "No"},
			{"The blue pyramid is mine", "I understand"},
				{"Do I own the blue pyramid?", "Yes"},

				{"Do I own a green block?", "No"},
			{"I own blocks which are not red, but I don't own anything which supports a pyramid", "I understand"},
				{"Do I own a green block?", "Yes"},
				{"Do I own all green blocks?", "No"},

			{"Do I own the box?", "No"},

			// todo: must be: Yes, two things: the blue block and the blue pyramid
			{"Do I own anything in the box?", "Yes, the blue block and the blue pyramid"},

				{"Does a green block support a pyramid?", "Yes"},
			{"Will you please stack up both of the red blocks and either a green cube or a pyramid?", "OK"},
				{"Is the small red block supported by a green block?", "Yes"},
				{"Is a green block supported by the big red block?", "Yes"},
				{"Does a green block support a pyramid?", "Yes"},

			{"Which cube is sitting on the table?", "The large green one which supports the red pyramid"},

			//{"Is there a large block behind a pyramid?", "Yes, three of them: a large red one, a large green cube and a blue one"},
		},
		{
		},
	}

	_ = os.Remove(actualSessionPath)

	for _, session := range tests {

		for _, test := range session {

			log.Clear()

			system.PopulateDialogContext(actualSessionPath, false)

			answer, options := system.Answer(test.question)

			if options.HasOptions() {
				answer += options.String()
			}

			system.StoreDialogContext(actualSessionPath)

			if answer != test.answer {
				t.Errorf("Test relationships: got %v, want %v", answer, test.answer)
				t.Error(log.String())
			}
		}
	}

	createImage(system)
}

func createImage(system *global.System) {

	p := pinhole.New()

	data := system.Query("dom:at(E, X, Z, Y) dom:type(E, Type) dom:color(E, Color) dom:size(E, Width, Length, Height)")

	p.DrawCube(-.99, -.99, -.99, .99, .99, .99)

	scale := 500.0
	zScale := 1200.0

	for _, binding := range data {

		p.Begin()

		x, _ := strconv.ParseFloat(binding["X"].TermValue, 64)
		y, _ := strconv.ParseFloat(binding["Y"].TermValue, 64)
		z, _ := strconv.ParseFloat(binding["Z"].TermValue, 64)
		theType := binding["Type"].TermValue
		theColor := binding["Color"].TermValue
		width, _ := strconv.ParseFloat(binding["Width"].TermValue, 64)
		length, _ := strconv.ParseFloat(binding["Length"].TermValue, 64)
		height, _ := strconv.ParseFloat(binding["Height"].TermValue, 64)

		x1 := (x - 500) / scale
		y1 := (y - 500) / scale
		z1 := (z + 50) / zScale

		x2 := x1 + width / scale
		y2 := y1 + height / scale
		z2 := z1 + length / zScale

		if theType == "pyramid" {
			drawPyramid(p, x1, y1, z1, width / scale, height / scale, length / zScale)
		} else {
			p.DrawCube(x1, y1, z1, x2, y2, z2)
		}

		switch theColor {
		case "red":
			p.Colorize(color.RGBA{255, 0, 0, 255})
		case "green":
			p.Colorize(color.RGBA{0, 255, 0, 255})
		case "blue":
			p.Colorize(color.RGBA{0, 0, 255, 255})
		default:
			p.Colorize(color.RGBA{0, 0, 0, 255})
		}

		p.End()
	}

	p.SavePNG(common.Dir() + "/blocksworld.png", 1200, 600, nil)
}

func drawPyramid(p *pinhole.Pinhole, x float64, y float64, z float64, width float64, height float64, length float64) {
	topX := x + width / 2
	topY := y + height
	topZ := z + length / 2

	p.DrawLine(x, y, z, x + width, y, z)
	p.DrawLine(x + width, y, z, x + width, y, z + length)
	p.DrawLine(x + width, y, z + length, x, y, z + length)
	p.DrawLine(x, y, z + length, x, y, z)

	p.DrawLine(x, y, z, topX, topY, topZ)
	p.DrawLine(x + width, y, z, topX, topY, topZ)
	p.DrawLine(x + width, y, z + length, topX, topY, topZ)
	p.DrawLine(x, y, z + length, topX, topY, topZ)
}<|endoftext|>


<commit_before>package dodosim

import (
	"strings"
)

type SimulatorSync struct {
	Renderer       Renderer
	Speaker        Speaker
	CyclesPerFrame func(cycles uint64)

	Bus     *Bus
	Cpu     *Cpu
	Gamepad *Gamepad
	Resolve *Resolve
	Fram    *Fram

	Cycles              uint64
	LastOp              uint8
	WaitTester          int
	WaitingForInterrupt bool
	MissedFrames        int
}

func (s *SimulatorSync) PumpClock(input string) {
	s.Gamepad.A = strings.Contains(input, "A")
	s.Gamepad.B = strings.Contains(input, "B")
	s.Gamepad.U = strings.Contains(input, "U")
	s.Gamepad.D = strings.Contains(input, "D")
	s.Gamepad.L = strings.Contains(input, "L")
	s.Gamepad.R = strings.Contains(input, "R")

	for {
		opcode := s.Bus.Read(s.Cpu.PC)

		s.Cpu.PC++
		s.Cpu.Status |= Constant
		o := GetOperation(opcode)

		c := o.Cycles

		s.Resolve.Opcode = opcode
		s.Resolve.Mode = o.Mode

		s.Resolve.Resolve()

		pop, rc := o.Handler(s.Resolve)
		c += rc
		if s.Resolve.Penalty && pop {
			c += 1
		}

		s.Cycles += uint64(c)

		if (s.LastOp == 0xA5 && opcode == 0xF0) || (s.LastOp == 0xF0 && opcode == 0xA5) {
			s.WaitTester++
		} else {
			s.WaitTester = 0
		}

		s.LastOp = opcode

		// If Lda, Beq sequences happens 5 times in a row then assume we are waiting for interrupt
		if s.WaitTester == 10 { // Getting in here tells us that a complete game cycle was performed
			s.CyclesPerFrame(uint64(s.MissedFrames*50000) + s.Cycles)
			s.MissedFrames = 0
			s.Cycles = 0
			s.WaitTester = 0
			s.Cpu.Irq(s.Bus)

			return
		} else if s.Cycles >= 50000 { // If we hit 50000 cycles then that means we need to pause for a whole additional interrupt cycle
			s.Cycles = 0
			s.MissedFrames++

			s.Cpu.Irq(s.Bus)

			return
		}
	}
}

func (s *SimulatorSync) SwitchFram(game []byte) {
	s.Fram.New(game)
	s.Cpu.Reset(s.Bus)
}

func (s *SimulatorSync) SimulateSyncInit(firmware, game []byte) {
	s.Bus = new(Bus)
	s.Bus.New()

	s.Resolve = new(Resolve)

	ram := new(Ram)
	s.Bus.Add(ram)

	rom := new(Rom)

	ssd1305 := new(Ssd1305)
	ssd1305.New(ram, s.Renderer)

	s.Bus.Add(ssd1305)

	s.Gamepad = new(Gamepad)
	s.Gamepad.New()

	s.Fram = new(Fram)
	s.Fram.New(game)

	via := new(Via)
	via.New(s.Gamepad, s.Fram, s.Speaker)
	s.Bus.Add(via)

	acia := new(Acia)
	s.Bus.Add(acia)

	for i, b := range firmware {
		rom[i] = b
	}

	s.Bus.Add(rom)

	s.Bus.BuildMap()

	s.Cpu = new(Cpu)
	s.Cpu.Reset(s.Bus)

	s.Resolve.Cpu = s.Cpu
	s.Resolve.Space = s.Bus

	BuildTable()

	s.Cycles = 0
	s.LastOp = 0
	s.WaitTester = 0
	s.WaitingForInterrupt = false
	s.MissedFrames = 0
}
<commit_msg>Updated to be able to swap ROM in addition to FRAM. In support of version switching.<commit_after>package dodosim

import (
	"strings"
)

type SimulatorSync struct {
	Renderer       Renderer
	Speaker        Speaker
	CyclesPerFrame func(cycles uint64)

	Bus     *Bus
	Cpu     *Cpu
	Gamepad *Gamepad
	Resolve *Resolve
	Rom     *Rom
	Fram    *Fram

	Cycles              uint64
	LastOp              uint8
	WaitTester          int
	WaitingForInterrupt bool
	MissedFrames        int
}

func (s *SimulatorSync) PumpClock(input string) {
	s.Gamepad.A = strings.Contains(input, "A")
	s.Gamepad.B = strings.Contains(input, "B")
	s.Gamepad.U = strings.Contains(input, "U")
	s.Gamepad.D = strings.Contains(input, "D")
	s.Gamepad.L = strings.Contains(input, "L")
	s.Gamepad.R = strings.Contains(input, "R")

	for {
		opcode := s.Bus.Read(s.Cpu.PC)

		s.Cpu.PC++
		s.Cpu.Status |= Constant
		o := GetOperation(opcode)

		c := o.Cycles

		s.Resolve.Opcode = opcode
		s.Resolve.Mode = o.Mode

		s.Resolve.Resolve()

		pop, rc := o.Handler(s.Resolve)
		c += rc
		if s.Resolve.Penalty && pop {
			c += 1
		}

		s.Cycles += uint64(c)

		if (s.LastOp == 0xA5 && opcode == 0xF0) || (s.LastOp == 0xF0 && opcode == 0xA5) {
			s.WaitTester++
		} else {
			s.WaitTester = 0
		}

		s.LastOp = opcode

		// If Lda, Beq sequences happens 5 times in a row then assume we are waiting for interrupt
		if s.WaitTester == 10 { // Getting in here tells us that a complete game cycle was performed
			s.CyclesPerFrame(uint64(s.MissedFrames*50000) + s.Cycles)
			s.MissedFrames = 0
			s.Cycles = 0
			s.WaitTester = 0
			s.Cpu.Irq(s.Bus)

			return
		} else if s.Cycles >= 50000 { // If we hit 50000 cycles then that means we need to pause for a whole additional interrupt cycle
			s.Cycles = 0
			s.MissedFrames++

			s.Cpu.Irq(s.Bus)

			return
		}
	}
}

func (s *SimulatorSync) SwitchFram(firmware, game []byte) {
	for i, b := range firmware {
		s.Rom[i] = b
	}

	s.Fram.New(game)
	s.Cpu.Reset(s.Bus)
}

func (s *SimulatorSync) SimulateSyncInit(firmware, game []byte) {
	s.Bus = new(Bus)
	s.Bus.New()

	s.Resolve = new(Resolve)

	ram := new(Ram)
	s.Bus.Add(ram)

	s.Rom = new(Rom)

	ssd1305 := new(Ssd1305)
	ssd1305.New(ram, s.Renderer)

	s.Bus.Add(ssd1305)

	s.Gamepad = new(Gamepad)
	s.Gamepad.New()

	s.Fram = new(Fram)
	s.Fram.New(game)

	via := new(Via)
	via.New(s.Gamepad, s.Fram, s.Speaker)
	s.Bus.Add(via)

	acia := new(Acia)
	s.Bus.Add(acia)

	for i, b := range firmware {
		s.Rom[i] = b
	}

	s.Bus.Add(s.Rom)

	s.Bus.BuildMap()

	s.Cpu = new(Cpu)
	s.Cpu.Reset(s.Bus)

	s.Resolve.Cpu = s.Cpu
	s.Resolve.Space = s.Bus

	BuildTable()

	s.Cycles = 0
	s.LastOp = 0
	s.WaitTester = 0
	s.WaitingForInterrupt = false
	s.MissedFrames = 0
}
<|endoftext|>


<commit_before>package hoverfly_test

import (
	"net/http"

	"github.com/SpectoLabs/hoverfly/functional-tests"
	"github.com/dghubble/sling"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("When I run Hoverfly", func() {

	var (
		hoverfly *functional_tests.Hoverfly
	)

	BeforeEach(func() {
		hoverfly = functional_tests.NewHoverfly()
	})

	Context("using standard configuration", func() {

		BeforeEach(func() {
			hoverfly.Start()
		})

		AfterEach(func() {
			hoverfly.Stop()
		})

		It("should response OK with a query with escaped query parameters", func() {

			hoverfly.ImportSimulation(`{
				"data": {
					"pairs": [
						{
							"request": {
								"query": {
									"exactMatch": "query=something with a space"
								}
							},
							"response": {
								"status": 200,
								"body": "OK"
							}
						}
					]
				},
				"meta": {
					"schemaVersion": "v3"
				}
			}`)
			response := hoverfly.Proxy(sling.New().Get("http://hoverfly.io?query=something%20with%20a%20space"))
			Expect(response.StatusCode).To(Equal(http.StatusOK))
		})
	})
})
<commit_msg>Add functional test for plain http tunneling<commit_after>package hoverfly_test

import (
	"net/http"

	"github.com/SpectoLabs/hoverfly/functional-tests"
	"github.com/dghubble/sling"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("When I run Hoverfly", func() {

	var (
		hoverfly *functional_tests.Hoverfly
	)

	BeforeEach(func() {
		hoverfly = functional_tests.NewHoverfly()
	})

	Context("using standard configuration", func() {

		BeforeEach(func() {
			hoverfly.Start()
		})

		AfterEach(func() {
			hoverfly.Stop()
		})

		It("should response OK with a query with escaped query parameters", func() {

			hoverfly.ImportSimulation(`{
				"data": {
					"pairs": [
						{
							"request": {
								"query": {
									"exactMatch": "query=something with a space"
								}
							},
							"response": {
								"status": 200,
								"body": "OK"
							}
						}
					]
				},
				"meta": {
					"schemaVersion": "v3"
				}
			}`)
			response := hoverfly.Proxy(sling.New().Get("http://hoverfly.io?query=something%20with%20a%20space"))
			Expect(response.StatusCode).To(Equal(http.StatusOK))
		})
	})

	Context("using plain http tunneling", func() {

		BeforeEach(func() {
			hoverfly.Start("-plain-http-tunneling")
		})

		AfterEach(func() {
			hoverfly.Stop()
		})

		It("should response OK on CONNECT request", func() {

			hoverfly.ImportSimulation(`{
				"data": {
					"pairs": [
						{
							"request": {
								"destination": {
									"exactMatch": "hoverfly.io"
								}
							},
							"response": {
								"status": 200,
								"body": "OK"
							}
						}
					]
				},
				"meta": {
					"schemaVersion": "v3"
				}
			}`)
			req, _ := http.NewRequest(http.MethodConnect, "http://hoverfly.io", nil)
			response := hoverfly.ProxyRequest(req)
			Expect(response.StatusCode).To(Equal(http.StatusOK))
		})
	})
})
<|endoftext|>


<commit_before>package resource_test

import (
	"fmt"
	"reflect"
	"testing"

	"github.com/qor/qor"
	"github.com/qor/qor/resource"
	testutils "github.com/qor/qor/test/utils"
	"github.com/qor/qor/utils"
)

func format(value interface{}) string {
	return fmt.Sprint(utils.Indirect(reflect.ValueOf(value)).Interface())
}

func checkMeta(record interface{}, meta *resource.Meta, value interface{}, t *testing.T, expectedValues ...string) {
	var (
		context       = &qor.Context{DB: testutils.TestDB()}
		metaValue     = &resource.MetaValue{Name: meta.Name, Value: value}
		expectedValue = fmt.Sprint(value)
	)

	for _, v := range expectedValues {
		expectedValue = v
	}

	meta.PreInitialize()
	meta.Initialize()

	meta.Setter(record, metaValue, context)
	if context.HasError() {
		t.Errorf("No error should happen, but got %v", context.Errors)
	}

	if result := meta.Valuer(record, context); format(result) != expectedValue {
		t.Errorf("Wrong value, should be %v, but got %v", expectedValue, format(result))
	}
}

func TestStringMetaValuerAndSetter(t *testing.T) {
	user := &struct {
		Name  string
		Name2 *string
	}{}

	res := resource.New(&user)

	meta := &resource.Meta{
		Name:         "Name",
		BaseResource: res,
	}

	checkMeta(&user, meta, "hello world", t)

	meta2 := &resource.Meta{
		Name:         "Name2",
		BaseResource: res,
	}

	checkMeta(&user, meta2, "hello world2", t)
}

func TestIntMetaValuerAndSetter(t *testing.T) {
	user := &struct {
		Age  int
		Age2 uint
		Age3 *int8
		Age4 *uint8
	}{}

	res := resource.New(&user)

	meta := &resource.Meta{
		Name:         "Age",
		BaseResource: res,
	}

	checkMeta(&user, meta, 18, t)

	meta2 := &resource.Meta{
		Name:         "Age2",
		BaseResource: res,
	}

	checkMeta(&user, meta2, "28", t)

	meta3 := &resource.Meta{
		Name:         "Age3",
		BaseResource: res,
	}

	checkMeta(&user, meta3, 38, t)

	meta4 := &resource.Meta{
		Name:         "Age4",
		BaseResource: res,
	}

	checkMeta(&user, meta4, "48", t)
}

func TestFloatMetaValuerAndSetter(t *testing.T) {
	user := &struct {
		Age  float64
		Age2 *float64
	}{}

	res := resource.New(&user)

	meta := &resource.Meta{
		Name:         "Age",
		BaseResource: res,
	}

	checkMeta(&user, meta, 18.5, t)

	meta2 := &resource.Meta{
		Name:         "Age2",
		BaseResource: res,
	}

	checkMeta(&user, meta2, "28.5", t)
}

func TestBoolMetaValuerAndSetter(t *testing.T) {
	user := &struct {
		Actived  bool
		Actived2 *bool
	}{}

	res := resource.New(&user)

	meta := &resource.Meta{
		Name:         "Actived",
		BaseResource: res,
	}

	checkMeta(&user, meta, "true", t)

	meta2 := &resource.Meta{
		Name:         "Actived2",
		BaseResource: res,
	}

	checkMeta(&user, meta2, "true", t)

	meta3 := &resource.Meta{
		Name:         "Actived",
		BaseResource: res,
	}

	checkMeta(&user, meta3, "", t, "false")

	meta4 := &resource.Meta{
		Name:         "Actived2",
		BaseResource: res,
	}

	checkMeta(&user, meta4, "f", t, "false")
}
<commit_msg>Add tests broken meta<commit_after>package resource_test

import (
	"fmt"
	"reflect"
	"testing"

	"github.com/qor/qor"
	"github.com/qor/qor/resource"
	testutils "github.com/qor/qor/test/utils"
	"github.com/qor/qor/utils"
)

func format(value interface{}) string {
	return fmt.Sprint(utils.Indirect(reflect.ValueOf(value)).Interface())
}

func checkMeta(record interface{}, meta *resource.Meta, value interface{}, t *testing.T, expectedValues ...string) {
	var (
		context       = &qor.Context{DB: testutils.TestDB()}
		metaValue     = &resource.MetaValue{Name: meta.Name, Value: value}
		expectedValue = fmt.Sprint(value)
	)

	for _, v := range expectedValues {
		expectedValue = v
	}

	meta.PreInitialize()
	meta.Initialize()

	meta.Setter(record, metaValue, context)
	if context.HasError() {
		t.Errorf("No error should happen, but got %v", context.Errors)
	}

	if result := meta.Valuer(record, context); format(result) != expectedValue {
		t.Errorf("Wrong value, should be %v, but got %v", expectedValue, format(result))
	}
}

func TestStringMetaValuerAndSetter(t *testing.T) {
	user := &struct {
		Name  string
		Name2 *string
	}{}

	res := resource.New(&user)

	meta := &resource.Meta{
		Name:         "Name",
		BaseResource: res,
	}

	checkMeta(&user, meta, "hello world", t)

	meta2 := &resource.Meta{
		Name:         "Name2",
		BaseResource: res,
	}

	checkMeta(&user, meta2, "hello world2", t)
}

func TestIntMetaValuerAndSetter(t *testing.T) {
	user := &struct {
		Age  int
		Age2 uint
		Age3 *int8
		Age4 *uint8
	}{}

	res := resource.New(&user)

	meta := &resource.Meta{
		Name:         "Age",
		BaseResource: res,
	}

	checkMeta(&user, meta, 18, t)

	meta2 := &resource.Meta{
		Name:         "Age2",
		BaseResource: res,
	}

	checkMeta(&user, meta2, "28", t)

	meta3 := &resource.Meta{
		Name:         "Age3",
		BaseResource: res,
	}

	checkMeta(&user, meta3, 38, t)

	meta4 := &resource.Meta{
		Name:         "Age4",
		BaseResource: res,
	}

	checkMeta(&user, meta4, "48", t)
}

func TestFloatMetaValuerAndSetter(t *testing.T) {
	user := &struct {
		Age  float64
		Age2 *float64
	}{}

	res := resource.New(&user)

	meta := &resource.Meta{
		Name:         "Age",
		BaseResource: res,
	}

	checkMeta(&user, meta, 18.5, t)

	meta2 := &resource.Meta{
		Name:         "Age2",
		BaseResource: res,
	}

	checkMeta(&user, meta2, "28.5", t)
}

func TestBoolMetaValuerAndSetter(t *testing.T) {
	user := &struct {
		Actived  bool
		Actived2 *bool
	}{}

	res := resource.New(&user)

	meta := &resource.Meta{
		Name:         "Actived",
		BaseResource: res,
	}

	checkMeta(&user, meta, "true", t)

	meta2 := &resource.Meta{
		Name:         "Actived2",
		BaseResource: res,
	}

	checkMeta(&user, meta2, "true", t)

	meta3 := &resource.Meta{
		Name:         "Actived",
		BaseResource: res,
	}

	checkMeta(&user, meta3, "", t, "false")

	meta4 := &resource.Meta{
		Name:         "Actived2",
		BaseResource: res,
	}

	checkMeta(&user, meta4, "f", t, "false")
}

func TestSliceMetaValuerAndSetter(t *testing.T) {
	t.Skip()

	user := &struct {
		Names  []string
		Names2 []*string
		Names3 *[]string
		Names4 []*string
	}{}

	res := resource.New(&user)

	meta := &resource.Meta{
		Name:         "Name",
		BaseResource: res,
	}

	checkMeta(&user, meta, []string{"name1", "name2"}, t)

	meta2 := &resource.Meta{
		Name:         "Name2",
		BaseResource: res,
	}

	checkMeta(&user, meta2, []string{"name1", "name2"}, t)

	meta3 := &resource.Meta{
		Name:         "Name3",
		BaseResource: res,
	}

	checkMeta(&user, meta3, []string{"name1", "name2"}, t)

	meta4 := &resource.Meta{
		Name:         "Name4",
		BaseResource: res,
	}

	checkMeta(&user, meta4, []string{"name1", "name2"}, t)
}
<|endoftext|>


<commit_before>// These are specialized integration tests. We only build them when we're doing
// a lot of additional work to keep the external docker environment they require
// working.
// +build integration

package main

import (
	"os"
	"testing"

	. "gopkg.in/check.v1"

	"github.com/prometheus/client_golang/prometheus"
	"database/sql"
	_ "github.com/lib/pq"
	"fmt"
)

// Hook up gocheck into the "go test" runner.
func Test(t *testing.T) { TestingT(t) }

type IntegrationSuite struct{
	e *Exporter
}

var _ = Suite(&IntegrationSuite{})

func (s *IntegrationSuite) SetUpSuite(c *C) {
	dsn := os.Getenv("DATA_SOURCE_NAME")
	c.Assert(dsn, Not(Equals), "")

	exporter := NewExporter(dsn)
	c.Assert(exporter, NotNil)
	// Assign the exporter to the suite
	s.e = exporter

	prometheus.MustRegister(exporter)
}

// TODO: it would be nice if this didn't mostly just recreate the scrape function
func (s *IntegrationSuite) TestAllNamespacesReturnResults(c *C) {
	// Setup a dummy channel to consume metrics
	ch := make(chan prometheus.Metric, 100)
	go func() {
		for _ = range ch {}
	}()

	// Open a database connection
	db, err := sql.Open("postgres", s.e.dsn)
	c.Assert(db, NotNil)
	c.Assert(err, IsNil)
	defer db.Close()

	// Do a version update
	err = s.e.checkMapVersions(ch, db)
	c.Assert(err, IsNil)

	// Check the show variables work
	nonFatalErrors := queryShowVariables(ch, db, s.e.variableMap)
	if !c.Check(len(nonFatalErrors), Equals, 0) {
		fmt.Println("## NONFATAL ERRORS FOUND")
		for _, err := range nonFatalErrors {
			fmt.Println(err)
		}
	}

	// This should never happen in our test cases.
	errMap := queryNamespaceMappings(ch, db, s.e.metricMap, s.e.queryOverrides)
	if !c.Check(len(errMap), Equals, 0) {
		fmt.Println("## NAMESPACE ERRORS FOUND")
		for namespace, err := range errMap {
			fmt.Println(namespace, ":", err)
		}
	}
}<commit_msg>Update the integration test.<commit_after>// These are specialized integration tests. We only build them when we're doing
// a lot of additional work to keep the external docker environment they require
// working.
// +build integration

package main

import (
	"os"
	"testing"

	. "gopkg.in/check.v1"

	"github.com/prometheus/client_golang/prometheus"
	"database/sql"
	_ "github.com/lib/pq"
	"fmt"
)

// Hook up gocheck into the "go test" runner.
func Test(t *testing.T) { TestingT(t) }

type IntegrationSuite struct{
	e *Exporter
}

var _ = Suite(&IntegrationSuite{})

func (s *IntegrationSuite) SetUpSuite(c *C) {
	dsn := os.Getenv("DATA_SOURCE_NAME")
	c.Assert(dsn, Not(Equals), "")

	exporter := NewExporter(dsn, "")
	c.Assert(exporter, NotNil)
	// Assign the exporter to the suite
	s.e = exporter

	prometheus.MustRegister(exporter)
}

// TODO: it would be nice if this didn't mostly just recreate the scrape function
func (s *IntegrationSuite) TestAllNamespacesReturnResults(c *C) {
	// Setup a dummy channel to consume metrics
	ch := make(chan prometheus.Metric, 100)
	go func() {
		for _ = range ch {}
	}()

	// Open a database connection
	db, err := sql.Open("postgres", s.e.dsn)
	c.Assert(db, NotNil)
	c.Assert(err, IsNil)
	defer db.Close()

	// Do a version update
	err = s.e.checkMapVersions(ch, db)
	c.Assert(err, IsNil)

	// Check the show variables work
	nonFatalErrors := queryShowVariables(ch, db, s.e.variableMap)
	if !c.Check(len(nonFatalErrors), Equals, 0) {
		fmt.Println("## NONFATAL ERRORS FOUND")
		for _, err := range nonFatalErrors {
			fmt.Println(err)
		}
	}

	// This should never happen in our test cases.
	errMap := queryNamespaceMappings(ch, db, s.e.metricMap, s.e.queryOverrides)
	if !c.Check(len(errMap), Equals, 0) {
		fmt.Println("## NAMESPACE ERRORS FOUND")
		for namespace, err := range errMap {
			fmt.Println(namespace, ":", err)
		}
	}
}<|endoftext|>


<commit_before>package cli

import (
	"context"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/pkg/errors"

	"golang.org/x/crypto/ssh/terminal"

	"github.com/elpinal/coco3/config"
	"github.com/elpinal/coco3/eval"
	"github.com/elpinal/coco3/gate"
	"github.com/elpinal/coco3/parser"

	"github.com/elpinal/coco3/extra"
	eparser "github.com/elpinal/coco3/extra/parser"

	"github.com/jmoiron/sqlx"
	_ "github.com/mattn/go-sqlite3"
)

type CLI struct {
	In  io.Reader
	Out io.Writer
	Err io.Writer

	*config.Config

	db *sqlx.DB

	execute1 func([]byte) (action, error)
}

func (c *CLI) init() {
	if c.Out == nil {
		c.Out = ioutil.Discard
	}
	if c.Err == nil {
		c.Err = ioutil.Discard
	}
	if c.Config == nil {
		c.Config = &config.Config{}
	}
	c.Config.Init()
}

func (c *CLI) Run(args []string) int {
	c.init()

	f := flag.NewFlagSet("coco3", flag.ContinueOnError)
	f.SetOutput(c.Err)
	f.Usage = func() {
		c.Err.Write([]byte("coco3 is a shell.\n"))
		c.Err.Write([]byte("Usage:\n"))
		f.PrintDefaults()
	}

	flagC := f.String("c", "", "take first argument as a command to execute")
	flagE := f.Bool("extra", c.Config.Extra, "switch to extra mode")
	if err := f.Parse(args); err != nil {
		return 2
	}
	return c.run(f.Args(), flagC, flagE)
}

func (c *CLI) run(args []string, flagC *string, flagE *bool) int {
	// Aliases, only available for non-extra mode.
	for _, alias := range c.Config.Alias {
		eval.DefAlias(alias[0], alias[1])
	}

	// Prepare environment.
	for k, v := range c.Config.Env {
		err := os.Setenv(k, v)
		if err != nil {
			c.errorln(err)
			return 1
		}
	}

	setpath(c.Config.Paths)

	if *flagE {
		// If -extra flag is on, enable extra mode on any command executions.
		c.execute1 = c.executeExtra
	} else {
		c.execute1 = c.execute
	}

	if len(c.Config.StartUpCommand) > 0 {
		a, err := c.execute1(c.Config.StartUpCommand)
		if err != nil {
			c.printExecError(err)
			return 1
		}
		if e, ok := a.(exit); ok {
			return e.code
		}
	}

	switch {
	case *flagC != "":
		// The -c flag.
		return c.fromArg(*flagC)
	case len(args) > 0:
		// Execute files.
		return c.executeFiles(args)
	default:
		// Interactive mode.
		return c.runInteractiveMode()
	}
}

func (c *CLI) fromArg(program string) int {
	a, err := c.execute1([]byte(program))
	if err != nil {
		c.printExecError(err)
		return 1
	}
	if e, ok := a.(exit); ok {
		return e.code
	}
	return 0
}

func (c *CLI) executeFiles(args []string) int {
	a, err := c.runFiles(args)
	if err != nil {
		c.printExecError(err)
		return 1
	}
	if e, ok := a.(exit); ok {
		return e.code
	}
	return 0
}

func (c *CLI) runInteractiveMode() int {
	// Inherit history.
	histRunes, err := c.getHistory(c.Config.HistFile)
	if err != nil {
		c.errorln(err)
		return 1
	}

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	g := gate.NewContext(ctx, c.Config, c.In, c.Out, c.Err, histRunes)
	for {
		a, err := c.interact(g)
		if err != nil {
			c.printExecError(err)
		}
		if e, ok := a.(exit); ok {
			return e.code
		}
	}
}

func (c *CLI) errorf(s string, a ...interface{}) {
	fmt.Fprintf(c.Err, s, a...)
}

func (c *CLI) errorln(s ...interface{}) {
	fmt.Fprintln(c.Err, s...)
}

func (c *CLI) errorp(s ...interface{}) {
	fmt.Fprint(c.Err, s...)
}

func (c *CLI) getHistory(filename string) ([][]rune, error) {
	db, err := sqlx.Connect("sqlite3", filename)
	if err != nil {
		return nil, errors.Wrap(err, "connecting history file")
	}
	_, err = db.Exec(schema)
	if err != nil {
		return nil, errors.Wrap(err, "initializing history file")
	}
	var history []string
	err = db.Select(&history, "select line from command_info")
	if err != nil {
		return nil, errors.Wrap(err, "restoring history")
	}
	// TODO: Is this way proper?
	c.db = db
	return sanitizeHistory(history), nil
}

func (c *CLI) printExecError(err error) {
	if pe, ok := err.(*eparser.ParseError); ok {
		c.errorln(pe.Verbose())
	} else {
		c.errorln(err)
	}
}

// setpath sets the PATH environment variable.
func setpath(args []string) {
	if len(args) == 0 {
		return
	}
	paths := filepath.SplitList(os.Getenv("PATH"))
	var newPaths []string
	for _, path := range paths {
		if contains(args, path) {
			continue
		}
		newPaths = append(newPaths, path)
	}
	newPaths = append(args, newPaths...)
	os.Setenv("PATH", strings.Join(newPaths, string(filepath.ListSeparator)))
}

func contains(xs []string, s string) bool {
	for _, x := range xs {
		if x == s {
			return true
		}
	}
	return false
}

func sanitizeHistory(history []string) [][]rune {
	histRunes := make([][]rune, 0, len(history))
	for _, line := range history {
		if line == "" {
			continue
		}
		l := len(histRunes)
		s := []rune(line)
		if l > 0 && compareRunes(histRunes[l-1], s) {
			continue
		}
		histRunes = append(histRunes, s)
	}
	return histRunes
}

func compareRunes(r1, r2 []rune) bool {
	if len(r1) != len(r2) {
		return false
	}
	for i, r := range r1 {
		if r2[i] != r {
			return false
		}
	}
	return true
}

func (c *CLI) interact(g gate.Gate) (action, error) {
	r, end, err := c.read(g)
	if err != nil {
		return nil, err
	}
	if end {
		return exitSuccess, nil
	}
	ch := c.writeHistory(r)
	a, err := c.execute1([]byte(string(r)))
	if err != nil {
		return a, err
	}
	return a, <-ch
}

func (c *CLI) read(g gate.Gate) ([]rune, bool, error) {
	defer c.Out.Write([]byte{'\n'})
	if terminal.IsTerminal(0) {
		oldState, err := terminal.MakeRaw(0)
		if err != nil {
			return nil, false, err
		}
		defer func() {
			if err := terminal.Restore(0, oldState); err != nil {
				c.errorln(err)
			}
		}()
	}
	r, end, err := g.Read()
	if err != nil {
		return nil, false, err
	}
	return r, end, nil
}

func (c *CLI) writeHistory(r []rune) <-chan error {
	startTime := time.Now()
	ch := make(chan error)
	go func() {
		_, err := c.db.Exec("insert into command_info (time, line) values ($1, $2)", startTime, string(r))
		if err != nil {
			ch <- errors.Wrap(err, "saving history")
			return
		}
		ch <- nil
	}()
	return ch
}

const schema = `
create table if not exists command_info (
    time datetime,
    line text
)`

func (c *CLI) execute(b []byte) (action, error) {
	f, err := parser.ParseSrc(b)
	if err != nil {
		return nil, err
	}
	e := eval.New(c.In, c.Out, c.Err, c.db)
	err = e.Eval(f.Lines)
	select {
	case code := <-e.ExitCh:
		return exit{code}, nil
	default:
	}
	return nil, err
}

func (c *CLI) executeExtra(b []byte) (action, error) {
	cmd, err := eparser.Parse(b)
	if err != nil {
		return nil, err
	}
	e := extra.New(extra.Option{DB: c.db})
	err = e.Eval(cmd)
	if err == nil {
		return nil, nil
	}
	if pe, ok := err.(*eparser.ParseError); ok {
		pe.Src = string(b)
	}
	return nil, err
}

func (c *CLI) runFiles(files []string) (action, error) {
	for _, file := range files {
		b, err := ioutil.ReadFile(file)
		if err != nil {
			return nil, err
		}
		a, err := c.execute1(b)
		if err != nil {
			return nil, err
		}
		if a != nil {
			return a, nil
		}
	}
	return nil, nil
}

type action interface {
	act()
}

type exit struct {
	code int
}

func (e exit) act() {}

var exitSuccess = exit{0}
<commit_msg>Document CLI.runInteractiveMode<commit_after>package cli

import (
	"context"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/pkg/errors"

	"golang.org/x/crypto/ssh/terminal"

	"github.com/elpinal/coco3/config"
	"github.com/elpinal/coco3/eval"
	"github.com/elpinal/coco3/gate"
	"github.com/elpinal/coco3/parser"

	"github.com/elpinal/coco3/extra"
	eparser "github.com/elpinal/coco3/extra/parser"

	"github.com/jmoiron/sqlx"
	_ "github.com/mattn/go-sqlite3"
)

type CLI struct {
	In  io.Reader
	Out io.Writer
	Err io.Writer

	*config.Config

	db *sqlx.DB

	execute1 func([]byte) (action, error)
}

func (c *CLI) init() {
	if c.Out == nil {
		c.Out = ioutil.Discard
	}
	if c.Err == nil {
		c.Err = ioutil.Discard
	}
	if c.Config == nil {
		c.Config = &config.Config{}
	}
	c.Config.Init()
}

func (c *CLI) Run(args []string) int {
	c.init()

	f := flag.NewFlagSet("coco3", flag.ContinueOnError)
	f.SetOutput(c.Err)
	f.Usage = func() {
		c.Err.Write([]byte("coco3 is a shell.\n"))
		c.Err.Write([]byte("Usage:\n"))
		f.PrintDefaults()
	}

	flagC := f.String("c", "", "take first argument as a command to execute")
	flagE := f.Bool("extra", c.Config.Extra, "switch to extra mode")
	if err := f.Parse(args); err != nil {
		return 2
	}
	return c.run(f.Args(), flagC, flagE)
}

func (c *CLI) run(args []string, flagC *string, flagE *bool) int {
	// Aliases, only available for non-extra mode.
	for _, alias := range c.Config.Alias {
		eval.DefAlias(alias[0], alias[1])
	}

	// Prepare environment.
	for k, v := range c.Config.Env {
		err := os.Setenv(k, v)
		if err != nil {
			c.errorln(err)
			return 1
		}
	}

	setpath(c.Config.Paths)

	if *flagE {
		// If -extra flag is on, enable extra mode on any command executions.
		c.execute1 = c.executeExtra
	} else {
		c.execute1 = c.execute
	}

	if len(c.Config.StartUpCommand) > 0 {
		a, err := c.execute1(c.Config.StartUpCommand)
		if err != nil {
			c.printExecError(err)
			return 1
		}
		if e, ok := a.(exit); ok {
			return e.code
		}
	}

	switch {
	case *flagC != "":
		// The -c flag.
		return c.fromArg(*flagC)
	case len(args) > 0:
		// Execute files.
		return c.executeFiles(args)
	default:
		// Interactive mode.
		return c.runInteractiveMode()
	}
}

func (c *CLI) fromArg(program string) int {
	a, err := c.execute1([]byte(program))
	if err != nil {
		c.printExecError(err)
		return 1
	}
	if e, ok := a.(exit); ok {
		return e.code
	}
	return 0
}

func (c *CLI) executeFiles(args []string) int {
	a, err := c.runFiles(args)
	if err != nil {
		c.printExecError(err)
		return 1
	}
	if e, ok := a.(exit); ok {
		return e.code
	}
	return 0
}

// runInteractiveMode runs interactive mode.
// It inherits the stored history first, reads the input repeatedly, and
// finally returns an exit code.
func (c *CLI) runInteractiveMode() int {
	// Inherit history.
	histRunes, err := c.getHistory(c.Config.HistFile)
	if err != nil {
		c.errorln(err)
		return 1
	}

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	g := gate.NewContext(ctx, c.Config, c.In, c.Out, c.Err, histRunes)
	for {
		a, err := c.interact(g)
		if err != nil {
			c.printExecError(err)
		}
		if e, ok := a.(exit); ok {
			return e.code
		}
	}
}

func (c *CLI) errorf(s string, a ...interface{}) {
	fmt.Fprintf(c.Err, s, a...)
}

func (c *CLI) errorln(s ...interface{}) {
	fmt.Fprintln(c.Err, s...)
}

func (c *CLI) errorp(s ...interface{}) {
	fmt.Fprint(c.Err, s...)
}

func (c *CLI) getHistory(filename string) ([][]rune, error) {
	db, err := sqlx.Connect("sqlite3", filename)
	if err != nil {
		return nil, errors.Wrap(err, "connecting history file")
	}
	_, err = db.Exec(schema)
	if err != nil {
		return nil, errors.Wrap(err, "initializing history file")
	}
	var history []string
	err = db.Select(&history, "select line from command_info")
	if err != nil {
		return nil, errors.Wrap(err, "restoring history")
	}
	// TODO: Is this way proper?
	c.db = db
	return sanitizeHistory(history), nil
}

func (c *CLI) printExecError(err error) {
	if pe, ok := err.(*eparser.ParseError); ok {
		c.errorln(pe.Verbose())
	} else {
		c.errorln(err)
	}
}

// setpath sets the PATH environment variable.
func setpath(args []string) {
	if len(args) == 0 {
		return
	}
	paths := filepath.SplitList(os.Getenv("PATH"))
	var newPaths []string
	for _, path := range paths {
		if contains(args, path) {
			continue
		}
		newPaths = append(newPaths, path)
	}
	newPaths = append(args, newPaths...)
	os.Setenv("PATH", strings.Join(newPaths, string(filepath.ListSeparator)))
}

func contains(xs []string, s string) bool {
	for _, x := range xs {
		if x == s {
			return true
		}
	}
	return false
}

func sanitizeHistory(history []string) [][]rune {
	histRunes := make([][]rune, 0, len(history))
	for _, line := range history {
		if line == "" {
			continue
		}
		l := len(histRunes)
		s := []rune(line)
		if l > 0 && compareRunes(histRunes[l-1], s) {
			continue
		}
		histRunes = append(histRunes, s)
	}
	return histRunes
}

func compareRunes(r1, r2 []rune) bool {
	if len(r1) != len(r2) {
		return false
	}
	for i, r := range r1 {
		if r2[i] != r {
			return false
		}
	}
	return true
}

func (c *CLI) interact(g gate.Gate) (action, error) {
	r, end, err := c.read(g)
	if err != nil {
		return nil, err
	}
	if end {
		return exitSuccess, nil
	}
	ch := c.writeHistory(r)
	a, err := c.execute1([]byte(string(r)))
	if err != nil {
		return a, err
	}
	return a, <-ch
}

func (c *CLI) read(g gate.Gate) ([]rune, bool, error) {
	defer c.Out.Write([]byte{'\n'})
	if terminal.IsTerminal(0) {
		oldState, err := terminal.MakeRaw(0)
		if err != nil {
			return nil, false, err
		}
		defer func() {
			if err := terminal.Restore(0, oldState); err != nil {
				c.errorln(err)
			}
		}()
	}
	r, end, err := g.Read()
	if err != nil {
		return nil, false, err
	}
	return r, end, nil
}

func (c *CLI) writeHistory(r []rune) <-chan error {
	startTime := time.Now()
	ch := make(chan error)
	go func() {
		_, err := c.db.Exec("insert into command_info (time, line) values ($1, $2)", startTime, string(r))
		if err != nil {
			ch <- errors.Wrap(err, "saving history")
			return
		}
		ch <- nil
	}()
	return ch
}

const schema = `
create table if not exists command_info (
    time datetime,
    line text
)`

func (c *CLI) execute(b []byte) (action, error) {
	f, err := parser.ParseSrc(b)
	if err != nil {
		return nil, err
	}
	e := eval.New(c.In, c.Out, c.Err, c.db)
	err = e.Eval(f.Lines)
	select {
	case code := <-e.ExitCh:
		return exit{code}, nil
	default:
	}
	return nil, err
}

func (c *CLI) executeExtra(b []byte) (action, error) {
	cmd, err := eparser.Parse(b)
	if err != nil {
		return nil, err
	}
	e := extra.New(extra.Option{DB: c.db})
	err = e.Eval(cmd)
	if err == nil {
		return nil, nil
	}
	if pe, ok := err.(*eparser.ParseError); ok {
		pe.Src = string(b)
	}
	return nil, err
}

func (c *CLI) runFiles(files []string) (action, error) {
	for _, file := range files {
		b, err := ioutil.ReadFile(file)
		if err != nil {
			return nil, err
		}
		a, err := c.execute1(b)
		if err != nil {
			return nil, err
		}
		if a != nil {
			return a, nil
		}
	}
	return nil, nil
}

type action interface {
	act()
}

type exit struct {
	code int
}

func (e exit) act() {}

var exitSuccess = exit{0}
<|endoftext|>


<commit_before>package cli

import (
	"gopkg.in/readline.v1"
)

type Readline struct {
	instance *readline.Instance
}

func Init(prompt string) *Readline {
	var (
		r   Readline
		err error
	)
	r.instance, err = readline.New(prompt + "> ")
	if err != nil {
		panic(err)
	}
	return &r
}

func (r *Readline) Run() {
	func() {
		for {
			line, err := r.instance.Readline()
			if err != nil { // io.EOF, readline.ErrInterrupt
				break
			}
			println(line)
		}
	}()
}
<commit_msg>added channel<commit_after>package cli

import (
	"gopkg.in/readline.v1"
)

type Readline struct {
	instance *readline.Instance
}

func Init(prompt string) *Readline {
	var (
		r   Readline
		err error
	)
	r.instance, err = readline.New(prompt + "> ")
	if err != nil {
		panic(err)
	}
	return &r
}

func (r *Readline) Run(out chan<- string) {
	func() {
		for {
			line, err := r.instance.Readline()
			if err != nil { // io.EOF, readline.ErrInterrupt
				break
			}
			out <- line
		}
	}()
}
<|endoftext|>


<commit_before>package cli

import (
	"os"

	"pkg.re/essentialkaos/ek.v9/fmtc"
	"pkg.re/essentialkaos/ek.v9/fmtutil/table"
	"pkg.re/essentialkaos/ek.v9/knf"
	"pkg.re/essentialkaos/ek.v9/options"
	"pkg.re/essentialkaos/ek.v9/terminal"
	"pkg.re/essentialkaos/ek.v9/usage"

	"github.com/gongled/vgrepo/prefs"
	"github.com/gongled/vgrepo/repository"
	"github.com/gongled/vgrepo/storage"
	"github.com/gongled/vgrepo/index"
)

// ////////////////////////////////////////////////////////////////////////////////// //

const (
	APP  = "vgrepo"
	VER  = "2.0.0"
	DESC = "Simple CLI tool for managing Vagrant repositories"
)

const (
	CMD_ADD    = "add"
	CMD_DELETE = "delete"
	CMD_LIST   = "list"
	CMD_INFO   = "info"
	CMD_RENDER = "render"
	CMD_HELP   = "help"

	CMD_ADD_SHORTCUT    = "a"
	CMD_DELETE_SHORTCUT = "d"
	CMD_LIST_SHORTCUT   = "l"
	CMD_INFO_SHORTCUT   = "i"
	CMD_RENDER_SHORTCUT = "r"
)

const (
	KNF_STORAGE_URL  = "storage:url"
	KNF_STORAGE_PATH = "storage:path"
)

const (
	ARG_NO_COLOR = "nc:no-color"
	ARG_HELP     = "h:help"
	ARG_VER      = "v:version"
)

const (
	ERROR_UNSUPPORTED      = 1
	ERROR_INVALID_SETTINGS = 2
)

const CONFIG_FILE = "/etc/vgrepo/vgrepo.knf"

// ////////////////////////////////////////////////////////////////////////////////// //

var optionsMap = options.Map{
	ARG_NO_COLOR: {Type: options.BOOL},
	ARG_HELP:     {Type: options.BOOL, Alias: "u:usage"},
	ARG_VER:      {Type: options.BOOL, Alias: "ver"},
}

var preferences *prefs.Preferences

// ////////////////////////////////////////////////////////////////////////////////// //

func Init() {
	opts, errs := options.Parse(optionsMap)

	if len(errs) != 0 {
		fmtc.Println("Arguments parsing errors:")

		for _, err := range errs {
			fmtc.Printf("  %s\n", err.Error())
		}

		os.Exit(1)
	}

	if options.GetB(ARG_NO_COLOR) {
		fmtc.DisableColors = true
	}

	if options.GetB(ARG_VER) {
		showAbout()
		return
	}

	if options.GetB(ARG_HELP) || len(opts) == 0 {
		showUsage()
		return
	}

	switch len(opts) {
	case 0:
		showUsage()
		return
	case 1:
		processCommand(opts[0], nil)
	default:
		processCommand(opts[0], opts[1:])
	}
}

// ////////////////////////////////////////////////////////////////////////////////// //

func prepare() {
	err := knf.Global(CONFIG_FILE)

	preferences = prefs.NewPreferences(
		knf.GetS(KNF_STORAGE_PATH),
		knf.GetS(KNF_STORAGE_URL),
	)

	if err != nil {
		terminal.PrintErrorMessage(err.Error())
		os.Exit(ERROR_INVALID_SETTINGS)
	}
}

func processCommand(cmd string, args []string) {
	prepare()

	switch cmd {
	case CMD_ADD, CMD_ADD_SHORTCUT:
		addCommand(args)
	case CMD_DELETE, CMD_DELETE_SHORTCUT:
		deleteCommand(args)
	case CMD_LIST, CMD_LIST_SHORTCUT:
		listCommand()
	case CMD_INFO, CMD_INFO_SHORTCUT:
		infoCommand(args)
	case CMD_RENDER, CMD_RENDER_SHORTCUT:
		renderCommand(args)
	case CMD_HELP:
		showUsage()
	default:
		terminal.PrintErrorMessage("Error: unknown command %s", cmd)
		os.Exit(ERROR_UNSUPPORTED)
	}
}

// ////////////////////////////////////////////////////////////////////////////////// //

func addCommand(args []string) {
	if len(args) < 4 {
		terminal.PrintErrorMessage(
			"Error: unable to handle %v arguments",
			len(args),
		)
		os.Exit(1)
	}

	var (
		src      = args[0]
		name     = args[1]
		version  = args[2]
		provider = args[3]
	)

	r := repository.NewRepository(preferences, name)

	terminal.PrintActionMessage("Importing package")
	err := r.AddPackage(src, repository.NewPackage(name, version, provider))

	if err != nil {
		terminal.PrintActionStatus(1)
		terminal.PrintErrorMessage("Error: %s", err.Error())
		os.Exit(1)
	} else {
		terminal.PrintActionStatus(0)
	}
}

func deleteCommand(args []string) {
	if len(args) < 3 {
		terminal.PrintErrorMessage("Error: name, version and provider must be set")
		os.Exit(1)
	}

	var (
		name     = args[0]
		version  = args[1]
		provider = args[2]
	)

	r := repository.NewRepository(preferences, name)

	terminal.PrintActionMessage("Removing package")
	err := r.RemovePackage(repository.NewPackage(name, version, provider))

	if err != nil {
		terminal.PrintActionStatus(1)
		terminal.PrintErrorMessage("Error: %s", err.Error())
		os.Exit(1)
	} else {
		terminal.PrintActionStatus(0)
	}
}

func listCommand() {
	s := storage.NewStorage(preferences)

	listTableRender(s.Repositories())
}

func infoCommand(args []string) {
	if len(args) < 1 {
		terminal.PrintErrorMessage("Error: name must be set")
		os.Exit(1)
	}

	name := args[0]

	infoTableRender(repository.NewRepository(preferences, name))
}

func renderCommand(args []string) {
	if len(args) < 1 {
		terminal.PrintErrorMessage("Error: template must be set")
		os.Exit(1)
	}

	template := args[0]
	output := "index.html"

	if len(args) >= 2 {
		output = args[1]
	}

	terminal.PrintActionMessage("Rendering template")
	err := index.ExportIndex(storage.NewStorage(preferences), template, output)

	if err != nil {
		terminal.PrintActionStatus(1)
		terminal.PrintErrorMessage("Error: unable to render template")
		os.Exit(1)
	}

	terminal.PrintActionStatus(0)
}

// ////////////////////////////////////////////////////////////////////////////////// //

func infoTableRender(r *repository.VRepository) {
	t := table.NewTable("Name", "Provider", "Version", "Checksum")
	table.HeaderCapitalize = true

	t.SetAlignments(table.ALIGN_LEFT, table.ALIGN_LEFT, table.ALIGN_RIGHT, table.ALIGN_LEFT)

	for _, v := range r.Versions {
		for _, p := range v.Providers {
			t.Add(r.Name, p.Name, v.Version, p.Checksum)
		}
	}

	if t.HasData() {
		t.Render()
	} else {
		terminal.PrintWarnMessage("Repository does not exist")
	}
}

func listTableRender(repos repository.VRepositoryList) {
	t := table.NewTable("Name", "Latest", "Metadata URL")
	table.HeaderCapitalize = true

	t.SetAlignments(table.ALIGN_LEFT, table.ALIGN_RIGHT, table.ALIGN_LEFT)
	for _, r := range repos {
		if r.HasMeta() {
			t.Add(r.Name, r.LatestVersion().Version, r.MetaURL())
		}
	}

	if t.HasData() {
		t.Render()
	} else {
		terminal.PrintWarnMessage("No repositories yet")
	}
}

// ////////////////////////////////////////////////////////////////////////////////// //

func setUsageCommands(info *usage.Info) {
	info.AddCommand(
		CMD_ADD,
		"Add image to the Vagrant repository",
		"source",
		"name",
		"version",
		"provider",
	)
	info.AddCommand(
		CMD_LIST,
		"Show the list of available images",
	)
	info.AddCommand(
		CMD_DELETE,
		"Delete the image from the repository",
		"name",
		"version",
		"provider",
	)
	info.AddCommand(
		CMD_INFO,
		"Display info of the particular repository",
		"name",
	)
	info.AddCommand(
		CMD_RENDER,
		"Create index by given template file",
		"template",
		"?output",
	)
	info.AddCommand(
		CMD_HELP,
		"Display the current help message",
	)
}

func setUsageOptions(info *usage.Info) {
	info.AddOption(ARG_NO_COLOR, "Disable colors in output")
	info.AddOption(ARG_HELP, "Show this help message")
	info.AddOption(ARG_VER, "Show version")
}

func setUsageExamples(info *usage.Info) {
	info.AddExample(
		"add $HOME/powerbox-1.0.0.box powerbox 1.1.0 virtualbox",
		"Add image to the Vagrant repository",
	)
	info.AddExample(
		"list",
		"Show the list of available repositories",
	)
	info.AddExample(
		"delete powerbox 1.1.0",
		"Remove the image from the repository",
	)
	info.AddExample(
		"info powerbox",
		"Show detailed info about the repository",
	)
	info.AddExample(
		"render /etc/vgrepo/templates/default.tpl index.html",
		"Create index file by given template with output index.html",
	)
}

func showUsage() {
	info := usage.NewInfo(APP)

	setUsageCommands(info)
	setUsageOptions(info)
	setUsageExamples(info)

	info.Render()
}

func showAbout() {
	about := &usage.About{
		App:     APP,
		Version: VER,
		Desc:    DESC,
		Year:    2014,
		Owner:   "Gleb E Goncharov",
		License: "MIT License",
	}

	about.Render()
}

// ////////////////////////////////////////////////////////////////////////////////// //
<commit_msg>Fix error message to clafiry the reason of fails.<commit_after>package cli

import (
	"os"

	"pkg.re/essentialkaos/ek.v9/fmtc"
	"pkg.re/essentialkaos/ek.v9/fmtutil/table"
	"pkg.re/essentialkaos/ek.v9/knf"
	"pkg.re/essentialkaos/ek.v9/options"
	"pkg.re/essentialkaos/ek.v9/terminal"
	"pkg.re/essentialkaos/ek.v9/usage"

	"github.com/gongled/vgrepo/prefs"
	"github.com/gongled/vgrepo/repository"
	"github.com/gongled/vgrepo/storage"
	"github.com/gongled/vgrepo/index"
)

// ////////////////////////////////////////////////////////////////////////////////// //

const (
	APP  = "vgrepo"
	VER  = "2.0.0"
	DESC = "Simple CLI tool for managing Vagrant repositories"
)

const (
	CMD_ADD    = "add"
	CMD_DELETE = "delete"
	CMD_LIST   = "list"
	CMD_INFO   = "info"
	CMD_RENDER = "render"
	CMD_HELP   = "help"

	CMD_ADD_SHORTCUT    = "a"
	CMD_DELETE_SHORTCUT = "d"
	CMD_LIST_SHORTCUT   = "l"
	CMD_INFO_SHORTCUT   = "i"
	CMD_RENDER_SHORTCUT = "r"
)

const (
	KNF_STORAGE_URL  = "storage:url"
	KNF_STORAGE_PATH = "storage:path"
)

const (
	ARG_NO_COLOR = "nc:no-color"
	ARG_HELP     = "h:help"
	ARG_VER      = "v:version"
)

const (
	ERROR_UNSUPPORTED      = 1
	ERROR_INVALID_SETTINGS = 2
)

const CONFIG_FILE = "/etc/vgrepo/vgrepo.knf"

// ////////////////////////////////////////////////////////////////////////////////// //

var optionsMap = options.Map{
	ARG_NO_COLOR: {Type: options.BOOL},
	ARG_HELP:     {Type: options.BOOL, Alias: "u:usage"},
	ARG_VER:      {Type: options.BOOL, Alias: "ver"},
}

var preferences *prefs.Preferences

// ////////////////////////////////////////////////////////////////////////////////// //

func Init() {
	opts, errs := options.Parse(optionsMap)

	if len(errs) != 0 {
		fmtc.Println("Arguments parsing errors:")

		for _, err := range errs {
			fmtc.Printf("  %s\n", err.Error())
		}

		os.Exit(1)
	}

	if options.GetB(ARG_NO_COLOR) {
		fmtc.DisableColors = true
	}

	if options.GetB(ARG_VER) {
		showAbout()
		return
	}

	if options.GetB(ARG_HELP) || len(opts) == 0 {
		showUsage()
		return
	}

	switch len(opts) {
	case 0:
		showUsage()
		return
	case 1:
		processCommand(opts[0], nil)
	default:
		processCommand(opts[0], opts[1:])
	}
}

// ////////////////////////////////////////////////////////////////////////////////// //

func prepare() {
	err := knf.Global(CONFIG_FILE)

	preferences = prefs.NewPreferences(
		knf.GetS(KNF_STORAGE_PATH),
		knf.GetS(KNF_STORAGE_URL),
	)

	if err != nil {
		terminal.PrintErrorMessage(err.Error())
		os.Exit(ERROR_INVALID_SETTINGS)
	}
}

func processCommand(cmd string, args []string) {
	prepare()

	switch cmd {
	case CMD_ADD, CMD_ADD_SHORTCUT:
		addCommand(args)
	case CMD_DELETE, CMD_DELETE_SHORTCUT:
		deleteCommand(args)
	case CMD_LIST, CMD_LIST_SHORTCUT:
		listCommand()
	case CMD_INFO, CMD_INFO_SHORTCUT:
		infoCommand(args)
	case CMD_RENDER, CMD_RENDER_SHORTCUT:
		renderCommand(args)
	case CMD_HELP:
		showUsage()
	default:
		terminal.PrintErrorMessage("Error: unknown command %s", cmd)
		os.Exit(ERROR_UNSUPPORTED)
	}
}

// ////////////////////////////////////////////////////////////////////////////////// //

func addCommand(args []string) {
	if len(args) < 4 {
		terminal.PrintErrorMessage(
			"Error: unable to handle %v arguments",
			len(args),
		)
		os.Exit(1)
	}

	var (
		src      = args[0]
		name     = args[1]
		version  = args[2]
		provider = args[3]
	)

	r := repository.NewRepository(preferences, name)

	terminal.PrintActionMessage("Importing package")
	err := r.AddPackage(src, repository.NewPackage(name, version, provider))

	if err != nil {
		terminal.PrintActionStatus(1)
		terminal.PrintErrorMessage("Error: %s", err.Error())
		os.Exit(1)
	} else {
		terminal.PrintActionStatus(0)
	}
}

func deleteCommand(args []string) {
	if len(args) < 3 {
		terminal.PrintErrorMessage("Error: name, version and provider must be set")
		os.Exit(1)
	}

	var (
		name     = args[0]
		version  = args[1]
		provider = args[2]
	)

	r := repository.NewRepository(preferences, name)

	terminal.PrintActionMessage("Removing package")
	err := r.RemovePackage(repository.NewPackage(name, version, provider))

	if err != nil {
		terminal.PrintActionStatus(1)
		terminal.PrintErrorMessage("Error: %s", err.Error())
		os.Exit(1)
	} else {
		terminal.PrintActionStatus(0)
	}
}

func listCommand() {
	s := storage.NewStorage(preferences)

	listTableRender(s.Repositories())
}

func infoCommand(args []string) {
	if len(args) < 1 {
		terminal.PrintErrorMessage("Error: name must be set")
		os.Exit(1)
	}

	name := args[0]

	infoTableRender(repository.NewRepository(preferences, name))
}

func renderCommand(args []string) {
	if len(args) < 1 {
		terminal.PrintErrorMessage("Error: template must be set")
		os.Exit(1)
	}

	template := args[0]
	output := "index.html"

	if len(args) >= 2 {
		output = args[1]
	}

	terminal.PrintActionMessage("Rendering template")
	err := index.ExportIndex(storage.NewStorage(preferences), template, output)

	if err != nil {
		terminal.PrintActionStatus(1)
		terminal.PrintErrorMessage("Error: ", err.Error())
		os.Exit(1)
	}

	terminal.PrintActionStatus(0)
}

// ////////////////////////////////////////////////////////////////////////////////// //

func infoTableRender(r *repository.VRepository) {
	t := table.NewTable("Name", "Provider", "Version", "Checksum")
	table.HeaderCapitalize = true

	t.SetAlignments(table.ALIGN_LEFT, table.ALIGN_LEFT, table.ALIGN_RIGHT, table.ALIGN_LEFT)

	for _, v := range r.Versions {
		for _, p := range v.Providers {
			t.Add(r.Name, p.Name, v.Version, p.Checksum)
		}
	}

	if t.HasData() {
		t.Render()
	} else {
		terminal.PrintWarnMessage("Repository does not exist")
	}
}

func listTableRender(repos repository.VRepositoryList) {
	t := table.NewTable("Name", "Latest", "Metadata URL")
	table.HeaderCapitalize = true

	t.SetAlignments(table.ALIGN_LEFT, table.ALIGN_RIGHT, table.ALIGN_LEFT)
	for _, r := range repos {
		if r.HasMeta() {
			t.Add(r.Name, r.LatestVersion().Version, r.MetaURL())
		}
	}

	if t.HasData() {
		t.Render()
	} else {
		terminal.PrintWarnMessage("No repositories yet")
	}
}

// ////////////////////////////////////////////////////////////////////////////////// //

func setUsageCommands(info *usage.Info) {
	info.AddCommand(
		CMD_ADD,
		"Add image to the Vagrant repository",
		"source",
		"name",
		"version",
		"provider",
	)
	info.AddCommand(
		CMD_LIST,
		"Show the list of available images",
	)
	info.AddCommand(
		CMD_DELETE,
		"Delete the image from the repository",
		"name",
		"version",
		"provider",
	)
	info.AddCommand(
		CMD_INFO,
		"Display info of the particular repository",
		"name",
	)
	info.AddCommand(
		CMD_RENDER,
		"Create index by given template file",
		"template",
		"?output",
	)
	info.AddCommand(
		CMD_HELP,
		"Display the current help message",
	)
}

func setUsageOptions(info *usage.Info) {
	info.AddOption(ARG_NO_COLOR, "Disable colors in output")
	info.AddOption(ARG_HELP, "Show this help message")
	info.AddOption(ARG_VER, "Show version")
}

func setUsageExamples(info *usage.Info) {
	info.AddExample(
		"add $HOME/powerbox-1.0.0.box powerbox 1.1.0 virtualbox",
		"Add image to the Vagrant repository",
	)
	info.AddExample(
		"list",
		"Show the list of available repositories",
	)
	info.AddExample(
		"delete powerbox 1.1.0",
		"Remove the image from the repository",
	)
	info.AddExample(
		"info powerbox",
		"Show detailed info about the repository",
	)
	info.AddExample(
		"render /etc/vgrepo/templates/default.tpl index.html",
		"Create index file by given template with output index.html",
	)
}

func showUsage() {
	info := usage.NewInfo(APP)

	setUsageCommands(info)
	setUsageOptions(info)
	setUsageExamples(info)

	info.Render()
}

func showAbout() {
	about := &usage.About{
		App:     APP,
		Version: VER,
		Desc:    DESC,
		Year:    2014,
		Owner:   "Gleb E Goncharov",
		License: "MIT License",
	}

	about.Render()
}

// ////////////////////////////////////////////////////////////////////////////////// //
<|endoftext|>