<commit_before>package testing

import (
	"crypto/tls"
	"fmt"
	"log"
	"os"
	"reflect"
	"testing"

	"github.com/hashicorp/vault/api"
	"github.com/hashicorp/vault/http"
	"github.com/hashicorp/vault/logical"
	"github.com/hashicorp/vault/physical"
	"github.com/hashicorp/vault/vault"
)

// TestEnvVar must be set to a non-empty value for acceptance tests to run.
const TestEnvVar = "TF_ACC"

// TestCase is a single set of tests to run for a backend. A TestCase
// should generally map 1:1 to each test method for your acceptance
// tests.
type TestCase struct {
	// Precheck, if non-nil, will be called once before the test case
	// runs at all. This can be used for some validation prior to the
	// test running.
	PreCheck func()

	// Backend is the backend that will be mounted.
	Backend logical.Backend

	// Steps are the set of operations that are run for this test case.
	Steps []TestStep

	// Teardown will be called before the test case is over regardless
	// of if the test succeeded or failed. This should return an error
	// in the case that the test can't guarantee all resources were
	// properly cleaned up.
	Teardown TestTeardownFunc
}

// TestStep is a single step within a TestCase.
type TestStep struct {
	// Operation is the operation to execute
	Operation logical.Operation

	// Path is the request path. The mount prefix will be automatically added.
	Path string

	// Arguments to pass in
	Data map[string]interface{}

	// Check is called after this step is executed in order to test that
	// the step executed successfully. If this is not set, then the next
	// step will be called
	Check TestCheckFunc

	// ErrorOk, if true, will let erroneous responses through to the check
	ErrorOk bool

	// Unauthenticated, if true, will make the request unauthenticated.
	Unauthenticated bool

	// RemoteAddr, if set, will set the remote addr on the request.
	RemoteAddr string

	// ConnState, if set, will set the tls conneciton state
	ConnState *tls.ConnectionState
}

// TestCheckFunc is the callback used for Check in TestStep.
type TestCheckFunc func(*logical.Response) error

// TestTeardownFunc is the callback used for Teardown in TestCase.
type TestTeardownFunc func() error

// Test performs an acceptance test on a backend with the given test case.
//
// Tests are not run unless an environmental variable "TF_ACC" is
// set to some non-empty value. This is to avoid test cases surprising
// a user by creating real resources.
//
// Tests will fail unless the verbose flag (`go test -v`, or explicitly
// the "-test.v" flag) is set. Because some acceptance tests take quite
// long, we require the verbose flag so users are able to see progress
// output.
func Test(t TestT, c TestCase) {
	// We only run acceptance tests if an env var is set because they're
	// slow and generally require some outside configuration.
	if os.Getenv(TestEnvVar) == "" {
		t.Skip(fmt.Sprintf(
			"Acceptance tests skipped unless env '%s' set",
			TestEnvVar))
		return
	}

	// We require verbose mode so that the user knows what is going on.
	if !testTesting && !testing.Verbose() {
		t.Fatal("Acceptance tests must be run with the -v flag on tests")
		return
	}

	// Run the PreCheck if we have it
	if c.PreCheck != nil {
		c.PreCheck()
	}

	// Create an in-memory Vault core
	core, err := vault.NewCore(&vault.CoreConfig{
		Physical: physical.NewInmem(),
		LogicalBackends: map[string]logical.Factory{
			"test": func(map[string]string) (logical.Backend, error) {
				return c.Backend, nil
			},
		},
	})
	if err != nil {
		t.Fatal("error initializing core: ", err)
	}

	// Initialize the core
	init, err := core.Initialize(&vault.SealConfig{
		SecretShares:    1,
		SecretThreshold: 1,
	})
	if err != nil {
		t.Fatal("error initializing core: ", err)
	}

	// Unseal the core
	if unsealed, err := core.Unseal(init.SecretShares[0]); err != nil {
		t.Fatal("error unsealing core: ", err)
	} else if !unsealed {
		t.Fatal("vault shouldn't be sealed")
	}

	// Create an HTTP API server and client
	ln, addr := http.TestServer(nil, core)
	defer ln.Close()
	clientConfig := api.DefaultConfig()
	clientConfig.Address = addr
	client, err := api.NewClient(clientConfig)
	if err != nil {
		t.Fatal("error initializing HTTP client: ", err)
	}

	// Set the token so we're authenticated
	client.SetToken(init.RootToken)

	// Mount the backend
	prefix := "mnt"
	if err := client.Sys().Mount(prefix, "test", "acceptance test"); err != nil {
		t.Fatal("error mounting backend: ", err)
	}

	// Make requests
	var revoke []*logical.Request
	for i, s := range c.Steps {
		log.Printf("[WARN] Executing test step %d", i+1)

		// Make sure to prefix the path with where we mounted the thing
		path := fmt.Sprintf("%s/%s", prefix, s.Path)

		// Create the request
		req := &logical.Request{
			Operation: s.Operation,
			Path:      path,
			Data:      s.Data,
		}
		if !s.Unauthenticated {
			req.ClientToken = client.Token()
		}
		if s.RemoteAddr != "" {
			req.Connection = &logical.Connection{RemoteAddr: s.RemoteAddr}
		}
		if s.ConnState != nil {
			req.Connection = &logical.Connection{ConnState: s.ConnState}
		}

		// Make the request
		resp, err := core.HandleRequest(req)
		if resp != nil && resp.Secret != nil {
			// Revoke this secret later
			revoke = append(revoke, logical.RevokeRequest(
				req.Path,
				resp.Secret,
				resp.Data,
			))
		}
		if err == nil && resp.IsError() && !s.ErrorOk {
			err = fmt.Errorf("Erroneous response:\n\n%#v", resp)
		}
		if err == nil && s.Check != nil {
			// Call the test method
			err = s.Check(resp)
		}
		if err != nil {
			t.Error(fmt.Sprintf("Failed step %d: %s", i+1, err))
			break
		}
	}

	// Revoke any secrets we might have.
	var failedRevokes []*logical.Secret
	for _, req := range revoke {
		log.Printf("[WARN] Revoking secret: %#v", req.Secret)
		req.ClientToken = client.Token()
		resp, err := core.HandleRequest(req)
		if err == nil && resp.IsError() {
			err = fmt.Errorf("Erroneous response:\n\n%#v", resp)
		}
		if err != nil {
			failedRevokes = append(failedRevokes, req.Secret)
			t.Error(fmt.Sprintf("[ERR] Revoke error: %s", err))
		}
	}

	// Perform any rollbacks. This should no-op if there aren't any.
	// We set the "immediate" flag here that any backend can pick up on
	// to do all rollbacks immediately even if the WAL entries are new.
	log.Printf("[WARN] Requesting RollbackOperation")
	req := logical.RollbackRequest(prefix + "/")
	req.Data["immediate"] = true
	req.ClientToken = client.Token()
	resp, err := core.HandleRequest(req)
	if err == nil && resp.IsError() {
		err = fmt.Errorf("Erroneous response:\n\n%#v", resp)
	}
	if err != nil && err != logical.ErrUnsupportedOperation {
		t.Error(fmt.Sprintf("[ERR] Rollback error: %s", err))
	}

	// If we have any failed revokes, log it.
	if len(failedRevokes) > 0 {
		for _, s := range failedRevokes {
			t.Error(fmt.Sprintf(
				"WARNING: Revoking the following secret failed. It may\n"+
					"still exist. Please verify:\n\n%#v",
				s))
		}
	}

	// Cleanup
	if c.Teardown != nil {
		c.Teardown()
	}
}

// TestCheckMulti is a helper to have multiple checks.
func TestCheckMulti(fs ...TestCheckFunc) TestCheckFunc {
	return func(resp *logical.Response) error {
		for _, f := range fs {
			if err := f(resp); err != nil {
				return err
			}
		}

		return nil
	}
}

// TestCheckAuth is a helper to check that a request generated an
// auth token with the proper policies.
func TestCheckAuth(policies []string) TestCheckFunc {
	return func(resp *logical.Response) error {
		if resp == nil || resp.Auth == nil {
			return fmt.Errorf("no auth in response")
		}
		if !reflect.DeepEqual(resp.Auth.Policies, policies) {
			return fmt.Errorf("invalid policies: %#v", resp.Auth.Policies)
		}

		return nil
	}
}

// TestCheckAuthDisplayName is a helper to check that a request generated a
// valid display name.
func TestCheckAuthDisplayName(n string) TestCheckFunc {
	return func(resp *logical.Response) error {
		if resp.Auth == nil {
			return fmt.Errorf("no auth in response")
		}
		if n != "" && resp.Auth.DisplayName != "mnt-"+n {
			return fmt.Errorf("invalid display name: %#v", resp.Auth.DisplayName)
		}

		return nil
	}
}

// TestCheckError is a helper to check that a response is an error.
func TestCheckError() TestCheckFunc {
	return func(resp *logical.Response) error {
		if !resp.IsError() {
			return fmt.Errorf("response should be error")
		}

		return nil
	}
}

// TestT is the interface used to handle the test lifecycle of a test.
//
// Users should just use a *testing.T object, which implements this.
type TestT interface {
	Error(args ...interface{})
	Fatal(args ...interface{})
	Skip(args ...interface{})
}

var testTesting = false
<commit_msg>logical/testing: add return after fatal?<commit_after>package testing

import (
	"crypto/tls"
	"fmt"
	"log"
	"os"
	"reflect"
	"testing"

	"github.com/hashicorp/vault/api"
	"github.com/hashicorp/vault/http"
	"github.com/hashicorp/vault/logical"
	"github.com/hashicorp/vault/physical"
	"github.com/hashicorp/vault/vault"
)

// TestEnvVar must be set to a non-empty value for acceptance tests to run.
const TestEnvVar = "TF_ACC"

// TestCase is a single set of tests to run for a backend. A TestCase
// should generally map 1:1 to each test method for your acceptance
// tests.
type TestCase struct {
	// Precheck, if non-nil, will be called once before the test case
	// runs at all. This can be used for some validation prior to the
	// test running.
	PreCheck func()

	// Backend is the backend that will be mounted.
	Backend logical.Backend

	// Steps are the set of operations that are run for this test case.
	Steps []TestStep

	// Teardown will be called before the test case is over regardless
	// of if the test succeeded or failed. This should return an error
	// in the case that the test can't guarantee all resources were
	// properly cleaned up.
	Teardown TestTeardownFunc
}

// TestStep is a single step within a TestCase.
type TestStep struct {
	// Operation is the operation to execute
	Operation logical.Operation

	// Path is the request path. The mount prefix will be automatically added.
	Path string

	// Arguments to pass in
	Data map[string]interface{}

	// Check is called after this step is executed in order to test that
	// the step executed successfully. If this is not set, then the next
	// step will be called
	Check TestCheckFunc

	// ErrorOk, if true, will let erroneous responses through to the check
	ErrorOk bool

	// Unauthenticated, if true, will make the request unauthenticated.
	Unauthenticated bool

	// RemoteAddr, if set, will set the remote addr on the request.
	RemoteAddr string

	// ConnState, if set, will set the tls conneciton state
	ConnState *tls.ConnectionState
}

// TestCheckFunc is the callback used for Check in TestStep.
type TestCheckFunc func(*logical.Response) error

// TestTeardownFunc is the callback used for Teardown in TestCase.
type TestTeardownFunc func() error

// Test performs an acceptance test on a backend with the given test case.
//
// Tests are not run unless an environmental variable "TF_ACC" is
// set to some non-empty value. This is to avoid test cases surprising
// a user by creating real resources.
//
// Tests will fail unless the verbose flag (`go test -v`, or explicitly
// the "-test.v" flag) is set. Because some acceptance tests take quite
// long, we require the verbose flag so users are able to see progress
// output.
func Test(t TestT, c TestCase) {
	// We only run acceptance tests if an env var is set because they're
	// slow and generally require some outside configuration.
	if os.Getenv(TestEnvVar) == "" {
		t.Skip(fmt.Sprintf(
			"Acceptance tests skipped unless env '%s' set",
			TestEnvVar))
		return
	}

	// We require verbose mode so that the user knows what is going on.
	if !testTesting && !testing.Verbose() {
		t.Fatal("Acceptance tests must be run with the -v flag on tests")
		return
	}

	// Run the PreCheck if we have it
	if c.PreCheck != nil {
		c.PreCheck()
	}

	// Create an in-memory Vault core
	core, err := vault.NewCore(&vault.CoreConfig{
		Physical: physical.NewInmem(),
		LogicalBackends: map[string]logical.Factory{
			"test": func(map[string]string) (logical.Backend, error) {
				return c.Backend, nil
			},
		},
	})
	if err != nil {
		t.Fatal("error initializing core: ", err)
		return
	}

	// Initialize the core
	init, err := core.Initialize(&vault.SealConfig{
		SecretShares:    1,
		SecretThreshold: 1,
	})
	if err != nil {
		t.Fatal("error initializing core: ", err)
	}

	// Unseal the core
	if unsealed, err := core.Unseal(init.SecretShares[0]); err != nil {
		t.Fatal("error unsealing core: ", err)
		return
	} else if !unsealed {
		t.Fatal("vault shouldn't be sealed")
		return
	}

	// Create an HTTP API server and client
	ln, addr := http.TestServer(nil, core)
	defer ln.Close()
	clientConfig := api.DefaultConfig()
	clientConfig.Address = addr
	client, err := api.NewClient(clientConfig)
	if err != nil {
		t.Fatal("error initializing HTTP client: ", err)
		return
	}

	// Set the token so we're authenticated
	client.SetToken(init.RootToken)

	// Mount the backend
	prefix := "mnt"
	if err := client.Sys().Mount(prefix, "test", "acceptance test"); err != nil {
		t.Fatal("error mounting backend: ", err)
		return
	}

	// Make requests
	var revoke []*logical.Request
	for i, s := range c.Steps {
		log.Printf("[WARN] Executing test step %d", i+1)

		// Make sure to prefix the path with where we mounted the thing
		path := fmt.Sprintf("%s/%s", prefix, s.Path)

		// Create the request
		req := &logical.Request{
			Operation: s.Operation,
			Path:      path,
			Data:      s.Data,
		}
		if !s.Unauthenticated {
			req.ClientToken = client.Token()
		}
		if s.RemoteAddr != "" {
			req.Connection = &logical.Connection{RemoteAddr: s.RemoteAddr}
		}
		if s.ConnState != nil {
			req.Connection = &logical.Connection{ConnState: s.ConnState}
		}

		// Make the request
		resp, err := core.HandleRequest(req)
		if resp != nil && resp.Secret != nil {
			// Revoke this secret later
			revoke = append(revoke, logical.RevokeRequest(
				req.Path,
				resp.Secret,
				resp.Data,
			))
		}
		if err == nil && resp.IsError() && !s.ErrorOk {
			err = fmt.Errorf("Erroneous response:\n\n%#v", resp)
		}
		if err == nil && s.Check != nil {
			// Call the test method
			err = s.Check(resp)
		}
		if err != nil {
			t.Error(fmt.Sprintf("Failed step %d: %s", i+1, err))
			break
		}
	}

	// Revoke any secrets we might have.
	var failedRevokes []*logical.Secret
	for _, req := range revoke {
		log.Printf("[WARN] Revoking secret: %#v", req.Secret)
		req.ClientToken = client.Token()
		resp, err := core.HandleRequest(req)
		if err == nil && resp.IsError() {
			err = fmt.Errorf("Erroneous response:\n\n%#v", resp)
		}
		if err != nil {
			failedRevokes = append(failedRevokes, req.Secret)
			t.Error(fmt.Sprintf("[ERR] Revoke error: %s", err))
		}
	}

	// Perform any rollbacks. This should no-op if there aren't any.
	// We set the "immediate" flag here that any backend can pick up on
	// to do all rollbacks immediately even if the WAL entries are new.
	log.Printf("[WARN] Requesting RollbackOperation")
	req := logical.RollbackRequest(prefix + "/")
	req.Data["immediate"] = true
	req.ClientToken = client.Token()
	resp, err := core.HandleRequest(req)
	if err == nil && resp.IsError() {
		err = fmt.Errorf("Erroneous response:\n\n%#v", resp)
	}
	if err != nil && err != logical.ErrUnsupportedOperation {
		t.Error(fmt.Sprintf("[ERR] Rollback error: %s", err))
	}

	// If we have any failed revokes, log it.
	if len(failedRevokes) > 0 {
		for _, s := range failedRevokes {
			t.Error(fmt.Sprintf(
				"WARNING: Revoking the following secret failed. It may\n"+
					"still exist. Please verify:\n\n%#v",
				s))
		}
	}

	// Cleanup
	if c.Teardown != nil {
		c.Teardown()
	}
}

// TestCheckMulti is a helper to have multiple checks.
func TestCheckMulti(fs ...TestCheckFunc) TestCheckFunc {
	return func(resp *logical.Response) error {
		for _, f := range fs {
			if err := f(resp); err != nil {
				return err
			}
		}

		return nil
	}
}

// TestCheckAuth is a helper to check that a request generated an
// auth token with the proper policies.
func TestCheckAuth(policies []string) TestCheckFunc {
	return func(resp *logical.Response) error {
		if resp == nil || resp.Auth == nil {
			return fmt.Errorf("no auth in response")
		}
		if !reflect.DeepEqual(resp.Auth.Policies, policies) {
			return fmt.Errorf("invalid policies: %#v", resp.Auth.Policies)
		}

		return nil
	}
}

// TestCheckAuthDisplayName is a helper to check that a request generated a
// valid display name.
func TestCheckAuthDisplayName(n string) TestCheckFunc {
	return func(resp *logical.Response) error {
		if resp.Auth == nil {
			return fmt.Errorf("no auth in response")
		}
		if n != "" && resp.Auth.DisplayName != "mnt-"+n {
			return fmt.Errorf("invalid display name: %#v", resp.Auth.DisplayName)
		}

		return nil
	}
}

// TestCheckError is a helper to check that a response is an error.
func TestCheckError() TestCheckFunc {
	return func(resp *logical.Response) error {
		if !resp.IsError() {
			return fmt.Errorf("response should be error")
		}

		return nil
	}
}

// TestT is the interface used to handle the test lifecycle of a test.
//
// Users should just use a *testing.T object, which implements this.
type TestT interface {
	Error(args ...interface{})
	Fatal(args ...interface{})
	Skip(args ...interface{})
}

var testTesting = false
<|endoftext|>


<commit_before>// +build linux,cgo,!agent

package db

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

	"github.com/stretchr/testify/suite"

	deviceConfig "github.com/lxc/lxd/lxd/device/config"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/logger"
	"github.com/lxc/lxd/shared/logging"
)

const fixtures string = `
    INSERT INTO instances (node_id, name, architecture, type, project_id) VALUES (1, 'thename', 1, 1, 1);
    INSERT INTO profiles (name, project_id) VALUES ('theprofile', 1);
    INSERT INTO instances_profiles (instance_id, profile_id) VALUES (1, 2);
    INSERT INTO instances_config (instance_id, key, value) VALUES (1, 'thekey', 'thevalue');
    INSERT INTO instances_devices (instance_id, name, type) VALUES (1, 'somename', 1);
    INSERT INTO instances_devices_config (key, value, instance_device_id) VALUES ('configkey', 'configvalue', 1);
    INSERT INTO images (fingerprint, filename, size, architecture, creation_date, expiry_date, upload_date, auto_update, project_id) VALUES ('fingerprint', 'filename', 1024, 0,  1431547174,  1431547175,  1431547176, 1, 1);
    INSERT INTO images_aliases (name, image_id, description, project_id) VALUES ('somealias', 1, 'some description', 1);
    INSERT INTO images_properties (image_id, type, key, value) VALUES (1, 0, 'thekey', 'some value');
    INSERT INTO profiles_config (profile_id, key, value) VALUES (2, 'thekey', 'thevalue');
    INSERT INTO profiles_devices (profile_id, name, type) VALUES (2, 'devicename', 1);
    INSERT INTO profiles_devices_config (profile_device_id, key, value) VALUES (1, 'devicekey', 'devicevalue');
    `

type dbTestSuite struct {
	suite.Suite

	dir     string
	db      *Cluster
	cleanup func()
}

func (s *dbTestSuite) SetupTest() {
	s.db, s.cleanup = s.CreateTestDb()

	tx, commit := s.CreateTestTx()
	defer commit()

	_, err := tx.Exec(fixtures)
	s.Nil(err)
}

func (s *dbTestSuite) TearDownTest() {
	s.cleanup()
}

// Initialize a test in-memory DB.
func (s *dbTestSuite) CreateTestDb() (*Cluster, func()) {
	var err error

	// Setup logging if main() hasn't been called/when testing
	if logger.Log == nil {
		logger.Log, err = logging.GetLogger("", "", true, true, nil)
		s.Nil(err)
	}

	db, cleanup := NewTestCluster(s.T())
	return db, cleanup
}

// Enter a transaction on the test in-memory DB.
func (s *dbTestSuite) CreateTestTx() (*sql.Tx, func()) {
	tx, err := s.db.DB().Begin()
	s.Nil(err)
	commit := func() {
		s.Nil(tx.Commit())
	}
	return tx, commit
}

func TestDBTestSuite(t *testing.T) {
	suite.Run(t, new(dbTestSuite))
}

func (s *dbTestSuite) Test_deleting_a_container_cascades_on_related_tables() {
	var err error
	var count int
	var statements string

	// Drop the container we just created.
	statements = `DELETE FROM instances WHERE name = 'thename';`

	tx, commit := s.CreateTestTx()
	defer commit()

	_, err = tx.Exec(statements)
	s.Nil(err, "Error deleting container!")

	// Make sure there are 0 container_profiles entries left.
	statements = `SELECT count(*) FROM instances_profiles;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a container didn't delete the profile association!")

	// Make sure there are 0 containers_config entries left.
	statements = `SELECT count(*) FROM instances_config;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a container didn't delete the associated container_config!")

	// Make sure there are 0 containers_devices entries left.
	statements = `SELECT count(*) FROM instances_devices;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a container didn't delete the associated container_devices!")

	// Make sure there are 0 containers_devices_config entries left.
	statements = `SELECT count(*) FROM instances_devices_config;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a container didn't delete the associated container_devices_config!")
}

func (s *dbTestSuite) Test_deleting_a_profile_cascades_on_related_tables() {
	var err error
	var count int
	var statements string

	// Drop the profile we just created.
	statements = `DELETE FROM profiles WHERE name = 'theprofile';`

	tx, commit := s.CreateTestTx()
	defer commit()

	_, err = tx.Exec(statements)
	s.Nil(err)

	// Make sure there are 0 container_profiles entries left.
	statements = `SELECT count(*) FROM instances_profiles WHERE profile_id = 2;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a profile didn't delete the container association!")

	// Make sure there are 0 profiles_devices entries left.
	statements = `SELECT count(*) FROM profiles_devices WHERE profile_id == 2;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a profile didn't delete the related profiles_devices!")

	// Make sure there are 0 profiles_config entries left.
	statements = `SELECT count(*) FROM profiles_config WHERE profile_id == 2;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a profile didn't delete the related profiles_config! There are %d left")

	// Make sure there are 0 profiles_devices_config entries left.
	statements = `SELECT count(*) FROM profiles_devices_config WHERE profile_device_id == 3;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a profile didn't delete the related profiles_devices_config!")
}

func (s *dbTestSuite) Test_deleting_an_image_cascades_on_related_tables() {
	var err error
	var count int
	var statements string

	// Drop the image we just created.
	statements = `DELETE FROM images;`

	tx, commit := s.CreateTestTx()
	defer commit()

	_, err = tx.Exec(statements)
	s.Nil(err)
	// Make sure there are 0 images_aliases entries left.
	statements = `SELECT count(*) FROM images_aliases;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting an image didn't delete the image alias association!")

	// Make sure there are 0 images_properties entries left.
	statements = `SELECT count(*) FROM images_properties;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting an image didn't delete the related images_properties!")
}

func (s *dbTestSuite) Test_ImageGet_finds_image_for_fingerprint() {
	var err error
	var result *api.Image

	_, result, err = s.db.ImageGet("default", "fingerprint", false, false)
	s.Nil(err)
	s.NotNil(result)
	s.Equal(result.Filename, "filename")
	s.Equal(result.CreatedAt.UTC(), time.Unix(1431547174, 0).UTC())
	s.Equal(result.ExpiresAt.UTC(), time.Unix(1431547175, 0).UTC())
	s.Equal(result.UploadedAt.UTC(), time.Unix(1431547176, 0).UTC())
}

func (s *dbTestSuite) Test_ImageGet_for_missing_fingerprint() {
	var err error

	_, _, err = s.db.ImageGet("default", "unknown", false, false)
	s.Equal(err, ErrNoSuchObject)
}

func (s *dbTestSuite) Test_ImageExists_true() {
	var err error

	exists, err := s.db.ImageExists("default", "fingerprint")
	s.Nil(err)
	s.True(exists)
}

func (s *dbTestSuite) Test_ImageExists_false() {
	var err error

	exists, err := s.db.ImageExists("default", "foobar")
	s.Nil(err)
	s.False(exists)
}

func (s *dbTestSuite) Test_ImageAliasGet_alias_exists() {
	var err error

	_, alias, err := s.db.ImageAliasGet("default", "somealias", true)
	s.Nil(err)
	s.Equal(alias.Target, "fingerprint")
}

func (s *dbTestSuite) Test_ImageAliasGet_alias_does_not_exists() {
	var err error

	_, _, err = s.db.ImageAliasGet("default", "whatever", true)
	s.Equal(err, ErrNoSuchObject)
}

func (s *dbTestSuite) Test_ImageAliasAdd() {
	var err error

	err = s.db.ImageAliasAdd("default", "Chaosphere", 1, "Someone will like the name")
	s.Nil(err)

	_, alias, err := s.db.ImageAliasGet("default", "Chaosphere", true)
	s.Nil(err)
	s.Equal(alias.Target, "fingerprint")
}

func (s *dbTestSuite) Test_ImageSourceGetCachedFingerprint() {
	imageID, _, err := s.db.ImageGet("default", "fingerprint", false, false)
	s.Nil(err)

	err = s.db.ImageSourceInsert(imageID, "server.remote", "simplestreams", "", "test")
	s.Nil(err)

	fingerprint, err := s.db.ImageSourceGetCachedFingerprint("server.remote", "simplestreams", "test", "container", 0)
	s.Nil(err)
	s.Equal(fingerprint, "fingerprint")
}

func (s *dbTestSuite) Test_ImageSourceGetCachedFingerprint_no_match() {
	imageID, _, err := s.db.ImageGet("default", "fingerprint", false, false)
	s.Nil(err)

	err = s.db.ImageSourceInsert(imageID, "server.remote", "simplestreams", "", "test")
	s.Nil(err)

	_, err = s.db.ImageSourceGetCachedFingerprint("server.remote", "lxd", "test", "container", 0)
	s.Equal(err, ErrNoSuchObject)
}

func (s *dbTestSuite) Test_ContainerConfig() {
	var err error
	var result map[string]string
	var expected map[string]string

	tx, commit := s.CreateTestTx()

	_, err = tx.Exec("INSERT INTO instances_config (instance_id, key, value) VALUES (1, 'something', 'something else');")
	s.Nil(err)

	commit()

	result, err = s.db.ContainerConfig(1)
	s.Nil(err)

	expected = map[string]string{"thekey": "thevalue", "something": "something else"}

	for key, value := range expected {
		s.Equal(result[key], value,
			fmt.Sprintf("Mismatching value for key %s: %s != %s", key, result[key], value))
	}
}

func (s *dbTestSuite) Test_dbProfileConfig() {
	var err error
	var result map[string]string
	var expected map[string]string

	tx, commit := s.CreateTestTx()

	_, err = tx.Exec("INSERT INTO profiles_config (profile_id, key, value) VALUES (2, 'something', 'something else');")
	s.Nil(err)

	commit()

	result, err = s.db.ProfileConfig("default", "theprofile")
	s.Nil(err)

	expected = map[string]string{"thekey": "thevalue", "something": "something else"}

	for key, value := range expected {
		s.Equal(result[key], value,
			fmt.Sprintf("Mismatching value for key %s: %s != %s", key, result[key], value))
	}
}

func (s *dbTestSuite) Test_ContainerProfiles() {
	var err error
	var result []string
	var expected []string

	expected = []string{"theprofile"}
	result, err = s.db.ContainerProfiles(1)
	s.Nil(err)

	for i := range expected {
		s.Equal(expected[i], result[i],
			fmt.Sprintf("Mismatching contents for profile list: %s != %s", result[i], expected[i]))
	}
}

func (s *dbTestSuite) Test_dbDevices_profiles() {
	var err error
	var result deviceConfig.Devices
	var subresult deviceConfig.Device
	var expected deviceConfig.Device

	result, err = s.db.Devices("default", "theprofile", true)
	s.Nil(err)

	expected = deviceConfig.Device{"type": "nic", "devicekey": "devicevalue"}
	subresult = result["devicename"]

	for key, value := range expected {
		s.Equal(subresult[key], value,
			fmt.Sprintf("Mismatching value for key %s: %v != %v", key, subresult[key], value))
	}
}

func (s *dbTestSuite) Test_dbDevices_containers() {
	var err error
	var result deviceConfig.Devices
	var subresult deviceConfig.Device
	var expected deviceConfig.Device

	result, err = s.db.Devices("default", "thename", false)
	s.Nil(err)

	expected = deviceConfig.Device{"type": "nic", "configkey": "configvalue"}
	subresult = result["somename"]

	for key, value := range expected {
		s.Equal(subresult[key], value,
			fmt.Sprintf("Mismatching value for key %s: %s != %s", key, subresult[key], value))
	}
}
<commit_msg>lxd/db: Fix for new testify<commit_after>// +build linux,cgo,!agent

package db

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

	"github.com/stretchr/testify/suite"

	deviceConfig "github.com/lxc/lxd/lxd/device/config"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/logger"
	"github.com/lxc/lxd/shared/logging"
)

const fixtures string = `
    INSERT INTO instances (node_id, name, architecture, type, project_id) VALUES (1, 'thename', 1, 1, 1);
    INSERT INTO profiles (name, project_id) VALUES ('theprofile', 1);
    INSERT INTO instances_profiles (instance_id, profile_id) VALUES (1, 2);
    INSERT INTO instances_config (instance_id, key, value) VALUES (1, 'thekey', 'thevalue');
    INSERT INTO instances_devices (instance_id, name, type) VALUES (1, 'somename', 1);
    INSERT INTO instances_devices_config (key, value, instance_device_id) VALUES ('configkey', 'configvalue', 1);
    INSERT INTO images (fingerprint, filename, size, architecture, creation_date, expiry_date, upload_date, auto_update, project_id) VALUES ('fingerprint', 'filename', 1024, 0,  1431547174,  1431547175,  1431547176, 1, 1);
    INSERT INTO images_aliases (name, image_id, description, project_id) VALUES ('somealias', 1, 'some description', 1);
    INSERT INTO images_properties (image_id, type, key, value) VALUES (1, 0, 'thekey', 'some value');
    INSERT INTO profiles_config (profile_id, key, value) VALUES (2, 'thekey', 'thevalue');
    INSERT INTO profiles_devices (profile_id, name, type) VALUES (2, 'devicename', 1);
    INSERT INTO profiles_devices_config (profile_device_id, key, value) VALUES (1, 'devicekey', 'devicevalue');
    `

type dbTestSuite struct {
	suite.Suite

	dir     string
	db      *Cluster
	cleanup func()
}

func (s *dbTestSuite) SetupTest() {
	s.db, s.cleanup = s.CreateTestDb()

	tx, commit := s.CreateTestTx()
	defer commit()

	_, err := tx.Exec(fixtures)
	s.Nil(err)
}

func (s *dbTestSuite) TearDownTest() {
	s.cleanup()
}

// Initialize a test in-memory DB.
func (s *dbTestSuite) CreateTestDb() (*Cluster, func()) {
	var err error

	// Setup logging if main() hasn't been called/when testing
	if logger.Log == nil {
		logger.Log, err = logging.GetLogger("", "", true, true, nil)
		s.Nil(err)
	}

	db, cleanup := NewTestCluster(s.T().(*testing.T))
	return db, cleanup
}

// Enter a transaction on the test in-memory DB.
func (s *dbTestSuite) CreateTestTx() (*sql.Tx, func()) {
	tx, err := s.db.DB().Begin()
	s.Nil(err)
	commit := func() {
		s.Nil(tx.Commit())
	}
	return tx, commit
}

func TestDBTestSuite(t *testing.T) {
	suite.Run(t, new(dbTestSuite))
}

func (s *dbTestSuite) Test_deleting_a_container_cascades_on_related_tables() {
	var err error
	var count int
	var statements string

	// Drop the container we just created.
	statements = `DELETE FROM instances WHERE name = 'thename';`

	tx, commit := s.CreateTestTx()
	defer commit()

	_, err = tx.Exec(statements)
	s.Nil(err, "Error deleting container!")

	// Make sure there are 0 container_profiles entries left.
	statements = `SELECT count(*) FROM instances_profiles;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a container didn't delete the profile association!")

	// Make sure there are 0 containers_config entries left.
	statements = `SELECT count(*) FROM instances_config;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a container didn't delete the associated container_config!")

	// Make sure there are 0 containers_devices entries left.
	statements = `SELECT count(*) FROM instances_devices;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a container didn't delete the associated container_devices!")

	// Make sure there are 0 containers_devices_config entries left.
	statements = `SELECT count(*) FROM instances_devices_config;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a container didn't delete the associated container_devices_config!")
}

func (s *dbTestSuite) Test_deleting_a_profile_cascades_on_related_tables() {
	var err error
	var count int
	var statements string

	// Drop the profile we just created.
	statements = `DELETE FROM profiles WHERE name = 'theprofile';`

	tx, commit := s.CreateTestTx()
	defer commit()

	_, err = tx.Exec(statements)
	s.Nil(err)

	// Make sure there are 0 container_profiles entries left.
	statements = `SELECT count(*) FROM instances_profiles WHERE profile_id = 2;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a profile didn't delete the container association!")

	// Make sure there are 0 profiles_devices entries left.
	statements = `SELECT count(*) FROM profiles_devices WHERE profile_id == 2;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a profile didn't delete the related profiles_devices!")

	// Make sure there are 0 profiles_config entries left.
	statements = `SELECT count(*) FROM profiles_config WHERE profile_id == 2;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a profile didn't delete the related profiles_config! There are %d left")

	// Make sure there are 0 profiles_devices_config entries left.
	statements = `SELECT count(*) FROM profiles_devices_config WHERE profile_device_id == 3;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting a profile didn't delete the related profiles_devices_config!")
}

func (s *dbTestSuite) Test_deleting_an_image_cascades_on_related_tables() {
	var err error
	var count int
	var statements string

	// Drop the image we just created.
	statements = `DELETE FROM images;`

	tx, commit := s.CreateTestTx()
	defer commit()

	_, err = tx.Exec(statements)
	s.Nil(err)
	// Make sure there are 0 images_aliases entries left.
	statements = `SELECT count(*) FROM images_aliases;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting an image didn't delete the image alias association!")

	// Make sure there are 0 images_properties entries left.
	statements = `SELECT count(*) FROM images_properties;`
	err = tx.QueryRow(statements).Scan(&count)
	s.Nil(err)
	s.Equal(count, 0, "Deleting an image didn't delete the related images_properties!")
}

func (s *dbTestSuite) Test_ImageGet_finds_image_for_fingerprint() {
	var err error
	var result *api.Image

	_, result, err = s.db.ImageGet("default", "fingerprint", false, false)
	s.Nil(err)
	s.NotNil(result)
	s.Equal(result.Filename, "filename")
	s.Equal(result.CreatedAt.UTC(), time.Unix(1431547174, 0).UTC())
	s.Equal(result.ExpiresAt.UTC(), time.Unix(1431547175, 0).UTC())
	s.Equal(result.UploadedAt.UTC(), time.Unix(1431547176, 0).UTC())
}

func (s *dbTestSuite) Test_ImageGet_for_missing_fingerprint() {
	var err error

	_, _, err = s.db.ImageGet("default", "unknown", false, false)
	s.Equal(err, ErrNoSuchObject)
}

func (s *dbTestSuite) Test_ImageExists_true() {
	var err error

	exists, err := s.db.ImageExists("default", "fingerprint")
	s.Nil(err)
	s.True(exists)
}

func (s *dbTestSuite) Test_ImageExists_false() {
	var err error

	exists, err := s.db.ImageExists("default", "foobar")
	s.Nil(err)
	s.False(exists)
}

func (s *dbTestSuite) Test_ImageAliasGet_alias_exists() {
	var err error

	_, alias, err := s.db.ImageAliasGet("default", "somealias", true)
	s.Nil(err)
	s.Equal(alias.Target, "fingerprint")
}

func (s *dbTestSuite) Test_ImageAliasGet_alias_does_not_exists() {
	var err error

	_, _, err = s.db.ImageAliasGet("default", "whatever", true)
	s.Equal(err, ErrNoSuchObject)
}

func (s *dbTestSuite) Test_ImageAliasAdd() {
	var err error

	err = s.db.ImageAliasAdd("default", "Chaosphere", 1, "Someone will like the name")
	s.Nil(err)

	_, alias, err := s.db.ImageAliasGet("default", "Chaosphere", true)
	s.Nil(err)
	s.Equal(alias.Target, "fingerprint")
}

func (s *dbTestSuite) Test_ImageSourceGetCachedFingerprint() {
	imageID, _, err := s.db.ImageGet("default", "fingerprint", false, false)
	s.Nil(err)

	err = s.db.ImageSourceInsert(imageID, "server.remote", "simplestreams", "", "test")
	s.Nil(err)

	fingerprint, err := s.db.ImageSourceGetCachedFingerprint("server.remote", "simplestreams", "test", "container", 0)
	s.Nil(err)
	s.Equal(fingerprint, "fingerprint")
}

func (s *dbTestSuite) Test_ImageSourceGetCachedFingerprint_no_match() {
	imageID, _, err := s.db.ImageGet("default", "fingerprint", false, false)
	s.Nil(err)

	err = s.db.ImageSourceInsert(imageID, "server.remote", "simplestreams", "", "test")
	s.Nil(err)

	_, err = s.db.ImageSourceGetCachedFingerprint("server.remote", "lxd", "test", "container", 0)
	s.Equal(err, ErrNoSuchObject)
}

func (s *dbTestSuite) Test_ContainerConfig() {
	var err error
	var result map[string]string
	var expected map[string]string

	tx, commit := s.CreateTestTx()

	_, err = tx.Exec("INSERT INTO instances_config (instance_id, key, value) VALUES (1, 'something', 'something else');")
	s.Nil(err)

	commit()

	result, err = s.db.ContainerConfig(1)
	s.Nil(err)

	expected = map[string]string{"thekey": "thevalue", "something": "something else"}

	for key, value := range expected {
		s.Equal(result[key], value,
			fmt.Sprintf("Mismatching value for key %s: %s != %s", key, result[key], value))
	}
}

func (s *dbTestSuite) Test_dbProfileConfig() {
	var err error
	var result map[string]string
	var expected map[string]string

	tx, commit := s.CreateTestTx()

	_, err = tx.Exec("INSERT INTO profiles_config (profile_id, key, value) VALUES (2, 'something', 'something else');")
	s.Nil(err)

	commit()

	result, err = s.db.ProfileConfig("default", "theprofile")
	s.Nil(err)

	expected = map[string]string{"thekey": "thevalue", "something": "something else"}

	for key, value := range expected {
		s.Equal(result[key], value,
			fmt.Sprintf("Mismatching value for key %s: %s != %s", key, result[key], value))
	}
}

func (s *dbTestSuite) Test_ContainerProfiles() {
	var err error
	var result []string
	var expected []string

	expected = []string{"theprofile"}
	result, err = s.db.ContainerProfiles(1)
	s.Nil(err)

	for i := range expected {
		s.Equal(expected[i], result[i],
			fmt.Sprintf("Mismatching contents for profile list: %s != %s", result[i], expected[i]))
	}
}

func (s *dbTestSuite) Test_dbDevices_profiles() {
	var err error
	var result deviceConfig.Devices
	var subresult deviceConfig.Device
	var expected deviceConfig.Device

	result, err = s.db.Devices("default", "theprofile", true)
	s.Nil(err)

	expected = deviceConfig.Device{"type": "nic", "devicekey": "devicevalue"}
	subresult = result["devicename"]

	for key, value := range expected {
		s.Equal(subresult[key], value,
			fmt.Sprintf("Mismatching value for key %s: %v != %v", key, subresult[key], value))
	}
}

func (s *dbTestSuite) Test_dbDevices_containers() {
	var err error
	var result deviceConfig.Devices
	var subresult deviceConfig.Device
	var expected deviceConfig.Device

	result, err = s.db.Devices("default", "thename", false)
	s.Nil(err)

	expected = deviceConfig.Device{"type": "nic", "configkey": "configvalue"}
	subresult = result["somename"]

	for key, value := range expected {
		s.Equal(subresult[key], value,
			fmt.Sprintf("Mismatching value for key %s: %s != %s", key, subresult[key], value))
	}
}
<|endoftext|>


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

// +build ignore

package main

// This file generates the godefs needed for the windows version.
// Rebuild is only necessary if additional libpcap functionality is implemented, or a new arch is implemented in golang.
// Call with go run generate_windows.go [-I includepath]
// Needs npcap sdk, go tool cgo, and gofmt to work. Location of npcap includes can be specified with -I

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

const header = `// Copyright 2019 The GoPacket Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.

// This file contains necessary structs/constants generated from libpcap headers with cgo -godefs
// generated with: %s
// DO NOT MODIFY

`

const source = `
package pcap

//#include <pcap.h>
import "C"

import "syscall" // needed for RawSockaddr

const errorBufferSize = C.PCAP_ERRBUF_SIZE

const (
	pcapErrorNotActivated = C.PCAP_ERROR_NOT_ACTIVATED
	pcapErrorActivated    = C.PCAP_ERROR_ACTIVATED
	pcapWarningPromisc    = C.PCAP_WARNING_PROMISC_NOTSUP
	pcapErrorNoSuchDevice = C.PCAP_ERROR_NO_SUCH_DEVICE
	pcapErrorDenied       = C.PCAP_ERROR_PERM_DENIED
	pcapErrorNotUp        = C.PCAP_ERROR_IFACE_NOT_UP
	pcapError             = C.PCAP_ERROR
	pcapWarning           = C.PCAP_WARNING
	pcapDIN               = C.PCAP_D_IN
	pcapDOUT              = C.PCAP_D_OUT
	pcapDINOUT            = C.PCAP_D_INOUT
	pcapNetmaskUnknown    = C.PCAP_NETMASK_UNKNOWN
)

type timeval C.struct_timeval
type pcapPkthdr C.struct_pcap_pkthdr
type pcapTPtr uintptr
type pcapBpfInstruction C.struct_bpf_insn
type pcapBpfProgram C.struct_bpf_program
type pcapStats C.struct_pcap_stat
type pcapCint C.int
type pcapIf C.struct_pcap_if
// +godefs map struct_sockaddr syscall.RawSockaddr
type pcapAddr C.struct_pcap_addr
`

var includes = flag.String("I", "C:\\npcap-sdk-1.01\\Include", "Include path containing libpcap headers")

func main() {
	flag.Parse()

	infile, err := ioutil.TempFile(".", "defs.*.go")
	if err != nil {
		log.Fatal("Couldn't create temporary source file: ", err)
	}
	defer infile.Close()
	defer os.Remove(infile.Name())

	_, err = infile.WriteString(source)
	if err != nil {
		log.Fatalf("Couldn't write definitions to temporary file %s: %s", infile.Name(), err)
	}
	err = infile.Close()
	if err != nil {
		log.Fatalf("Couldn't close temporary source file %s: %s", infile.Name(), err)
	}

	archs := []string{"386", "amd64"}
	for _, arch := range archs {
		env := append(os.Environ(), "GOARCH="+arch)
		cmd := exec.Command("go", "tool", "cgo", "-godefs", "--", "-I", *includes, infile.Name())
		cmd.Env = env
		cmd.Stderr = os.Stderr
		var generated bytes.Buffer
		cmd.Stdout = &generated
		err := cmd.Run()
		if err != nil {
			log.Fatalf("Couldn't generated defs for %s: %s\n", arch, err)
		}

		cmd = exec.Command("gofmt")
		cmd.Env = env
		cmd.Stderr = os.Stderr
		outName := fmt.Sprintf("defs_windows_%s.go", arch)
		out, err := os.Create(outName)
		if err != nil {
			log.Fatalf("Couldn't open file %s: %s", outName, err)
		}
		cmd.Stdout = out
		in, err := cmd.StdinPipe()
		if err != nil {
			log.Fatal("Couldn't create input pipe for gofmt: ", err)
		}
		err = cmd.Start()
		if err != nil {
			log.Fatal("Couldn't start gofmt: ", err)
		}

		_, err = fmt.Fprintf(in, header, strings.Join(append([]string{filepath.Base(os.Args[0])}, os.Args[1:]...), " "))
		if err != nil {
			log.Fatal("Couldn't write header to gofmt: ", err)
		}

		for {
			line, err := generated.ReadBytes('\n')
			if err != nil {
				break
			}
			// remove godefs comments
			if bytes.HasPrefix(line, []byte("//")) {
				continue
			}
			_, err = in.Write(line)
			if err != nil {
				log.Fatal("Couldn't write line to gofmt: ", err)
			}
		}
		in.Close()
		err = cmd.Wait()
		if err != nil {
			log.Fatal("gofmt failed: ", err)
		}
		out.Close()
	}
}
<commit_msg>Fix lineending in generate_defs<commit_after>// Copyright 2019 The GoPacket Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.

// +build ignore

package main

// This file generates the godefs needed for the windows version.
// Rebuild is only necessary if additional libpcap functionality is implemented, or a new arch is implemented in golang.
// Call with go run generate_windows.go [-I includepath]
// Needs npcap sdk, go tool cgo, and gofmt to work. Location of npcap includes can be specified with -I

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

const header = `// Copyright 2019 The GoPacket Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.

// This file contains necessary structs/constants generated from libpcap headers with cgo -godefs
// generated with: %s
// DO NOT MODIFY

`

const source = `
package pcap

//#include <pcap.h>
import "C"

import "syscall" // needed for RawSockaddr

const errorBufferSize = C.PCAP_ERRBUF_SIZE

const (
	pcapErrorNotActivated = C.PCAP_ERROR_NOT_ACTIVATED
	pcapErrorActivated    = C.PCAP_ERROR_ACTIVATED
	pcapWarningPromisc    = C.PCAP_WARNING_PROMISC_NOTSUP
	pcapErrorNoSuchDevice = C.PCAP_ERROR_NO_SUCH_DEVICE
	pcapErrorDenied       = C.PCAP_ERROR_PERM_DENIED
	pcapErrorNotUp        = C.PCAP_ERROR_IFACE_NOT_UP
	pcapError             = C.PCAP_ERROR
	pcapWarning           = C.PCAP_WARNING
	pcapDIN               = C.PCAP_D_IN
	pcapDOUT              = C.PCAP_D_OUT
	pcapDINOUT            = C.PCAP_D_INOUT
	pcapNetmaskUnknown    = C.PCAP_NETMASK_UNKNOWN
)

type timeval C.struct_timeval
type pcapPkthdr C.struct_pcap_pkthdr
type pcapTPtr uintptr
type pcapBpfInstruction C.struct_bpf_insn
type pcapBpfProgram C.struct_bpf_program
type pcapStats C.struct_pcap_stat
type pcapCint C.int
type pcapIf C.struct_pcap_if
// +godefs map struct_sockaddr syscall.RawSockaddr
type pcapAddr C.struct_pcap_addr
`

var includes = flag.String("I", "C:\\npcap-sdk-1.01\\Include", "Include path containing libpcap headers")

func main() {
	flag.Parse()

	infile, err := ioutil.TempFile(".", "defs.*.go")
	if err != nil {
		log.Fatal("Couldn't create temporary source file: ", err)
	}
	defer infile.Close()
	defer os.Remove(infile.Name())

	_, err = infile.WriteString(source)
	if err != nil {
		log.Fatalf("Couldn't write definitions to temporary file %s: %s", infile.Name(), err)
	}
	err = infile.Close()
	if err != nil {
		log.Fatalf("Couldn't close temporary source file %s: %s", infile.Name(), err)
	}

	archs := []string{"386", "amd64"}
	for _, arch := range archs {
		env := append(os.Environ(), "GOARCH="+arch)
		cmd := exec.Command("go", "tool", "cgo", "-godefs", "--", "-I", *includes, infile.Name())
		cmd.Env = env
		cmd.Stderr = os.Stderr
		var generated bytes.Buffer
		cmd.Stdout = &generated
		err := cmd.Run()
		if err != nil {
			log.Fatalf("Couldn't generated defs for %s: %s\n", arch, err)
		}

		cmd = exec.Command("gofmt")
		cmd.Env = env
		cmd.Stderr = os.Stderr
		outName := fmt.Sprintf("defs_windows_%s.go", arch)
		out, err := os.Create(outName)
		if err != nil {
			log.Fatalf("Couldn't open file %s: %s", outName, err)
		}
		cmd.Stdout = out
		in, err := cmd.StdinPipe()
		if err != nil {
			log.Fatal("Couldn't create input pipe for gofmt: ", err)
		}
		err = cmd.Start()
		if err != nil {
			log.Fatal("Couldn't start gofmt: ", err)
		}

		_, err = fmt.Fprintf(in, header, strings.Join(append([]string{filepath.Base(os.Args[0])}, os.Args[1:]...), " "))
		if err != nil {
			log.Fatal("Couldn't write header to gofmt: ", err)
		}

		for {
			line, err := generated.ReadBytes('\n')
			if err != nil {
				break
			}
			// remove godefs comments
			if bytes.HasPrefix(line, []byte("//")) {
				continue
			}
			_, err = in.Write(line)
			if err != nil {
				log.Fatal("Couldn't write line to gofmt: ", err)
			}
		}
		in.Close()
		err = cmd.Wait()
		if err != nil {
			log.Fatal("gofmt failed: ", err)
		}
		out.Close()
	}
}
<|endoftext|>


<commit_before>package routes

//Context Metadata
const (
	META_AJAX     string = "1"    //ajax 1, 0
	META_RESPONSE string = "json" //responseData json, html
	META_REQUEST  string = "json" //requestData json, data
)
<commit_msg>delete unwanted files<commit_after><|endoftext|>


<commit_before>package hamt_test

import (
	"flag"
	"fmt"
	"log"
	"math/rand"
	"os"
	"sort"
	"testing"
	"time"

	//"github.com/lleo/go-hamt/hamt32"
	//"github.com/lleo/go-hamt/hamt64"

	"github.com/lleo/go-hamt"
	"github.com/lleo/go-hamt/hamt32"
	"github.com/lleo/go-hamt/hamt64"
	"github.com/lleo/go-hamt/key"
	"github.com/lleo/go-hamt/stringkey"
	"github.com/lleo/stringutil"

	"github.com/pkg/errors"
)

// Found depth 5 collision between 3m+2k & 3m+4k at depth=5
// Works for hamt32 testing coverage not for hamt64 coverage
var numKvs int = (3 * 1024 * 1024) + (4 * 1024) // between 3m+2k & 3m+4k

//var SVS []StrVal
var KVS []key.KeyVal

var TableOption int

var LookupHamt32 *hamt32.Hamt

var LookupHamt64 *hamt64.Hamt

var Inc = stringutil.Lower.Inc

var StartTime = make(map[string]time.Time)
var RunTime = make(map[string]time.Duration)

func TestMain(m *testing.M) {
	var fullonly, componly, hybrid, all bool
	flag.BoolVar(&fullonly, "F", false, "Use full tables only and exclude C and H Options.")
	flag.BoolVar(&componly, "C", false, "Use compressed tables only and exclude F and H Options.")
	flag.BoolVar(&hybrid, "H", false, "Use compressed tables initially and exclude F and C Options.")
	flag.BoolVar(&all, "A", false, "Run all Tests w/ Options set to hamt32.FullTablesOnly, hamt32.CompTablesOnly, and hamt32.HybridTables; in that order.")

	flag.Parse()

	// If all flag set, ignore fullonly, componly, and hybrid.
	if !all {

		// only one flag may be set between fullonly, componly, and hybrid
		if (fullonly && (componly || hybrid)) ||
			(componly && (fullonly || hybrid)) ||
			(hybrid && (componly || fullonly)) {
			flag.PrintDefaults()
			os.Exit(1)
		}
	}

	// If no flags given, run all tests.
	if !(all || fullonly || componly || hybrid) {
		all = true
	}

	log.SetFlags(log.Lshortfile)

	var logfile, err = os.Create("test.log")
	if err != nil {
		log.Fatal(errors.Wrap(err, "failed to os.Create(\"test.log\")"))
	}
	defer logfile.Close()

	log.SetOutput(logfile)

	log.Println("TestMain: and so it begins...")

	KVS = buildKeyVals("global", numKvs)

	// execute
	var xit int
	if all {
		TableOption = hamt32.FullTablesOnly
		log.Printf("TestMain: TableOption == %s\n", hamt32.TableOptionName[TableOption])
		fmt.Printf("Running TableOption = %s\n", hamt32.TableOptionName[TableOption])

		xit = m.Run()
		if xit != 0 {
			os.Exit(1)
		}

		TableOption = hamt32.CompTablesOnly
		log.Printf("TestMain: TableOption == %s\n", hamt32.TableOptionName[TableOption])
		fmt.Printf("Running TableOption = %s\n", hamt32.TableOptionName[TableOption])

		xit = m.Run()
		if xit != 0 {
			os.Exit(1)
		}

		TableOption = hamt32.HybridTables
		log.Printf("TestMain: TableOption == %s\n", hamt32.TableOptionName[TableOption])
		fmt.Printf("Running TableOption = %s\n", hamt32.TableOptionName[TableOption])

		xit = m.Run()
	} else {
		if hybrid {
			TableOption = hamt32.HybridTables
		} else if fullonly {
			TableOption = hamt32.FullTablesOnly
		} else /* if componly */ {
			TableOption = hamt32.CompTablesOnly
		}

		log.Printf("TestMain: TableOption == %s\n", hamt32.TableOptionName[TableOption])
		fmt.Printf("Running TableOption = %s\n", hamt32.TableOptionName[TableOption])

		xit = m.Run()
	}

	log.Println("\n", RunTimes())

	os.Exit(xit)
}

func buildKeyVals(prefix string, num int) []key.KeyVal {
	var name = fmt.Sprintf("%s-buildKeyVals-%d", prefix, num)
	StartTime[name] = time.Now()

	var kvs = make([]key.KeyVal, num)
	var s = "aaa"

	for i := 0; i < num; i++ {
		var k = stringkey.New(s)

		kvs[i] = key.KeyVal{k, i}
		s = Inc(s)
	}

	RunTime[name] = time.Since(StartTime[name])
	return kvs
}

func buildMap(prefix string, num int) map[string]int {
	var name = fmt.Sprintf("%s-buildMap-%d", prefix, num)
	StartTime[name] = time.Now()

	var m = make(map[string]int, num)
	var s = "aaa"

	for i := 0; i < num; i++ {
		m[s] = i

		s = Inc(s)
	}

	RunTime[name] = time.Since(StartTime[name])
	return m
}

func buildHamt32(prefix string, kvs []key.KeyVal, opt int) (*hamt32.Hamt, error) {
	var name = fmt.Sprintf("%s-buildHamt32-%d", prefix, len(kvs))
	StartTime[name] = time.Now()

	var h = hamt32.New(opt)

	for _, kv := range kvs {
		var k = kv.Key
		var v = kv.Val

		var inserted = h.Put(k, v)
		if !inserted {
			return nil, fmt.Errorf("failed to Put(%s, %v)", k, v)
		}
	}

	RunTime[name] = time.Since(StartTime[name])
	return h, nil
}

func buildHamt64(prefix string, kvs []key.KeyVal, opt int) (*hamt64.Hamt, error) {
	var name = fmt.Sprintf("%s-buildHamt64-%d", prefix, len(kvs))
	StartTime[name] = time.Now()

	var h = hamt64.New(opt)

	for _, kv := range kvs {
		var k = kv.Key
		var v = kv.Val

		var inserted = h.Put(k, v)
		if !inserted {
			return nil, fmt.Errorf("failed to Put(%s, %v)", k, v)
		}
	}

	RunTime[name] = time.Since(StartTime[name])
	return h, nil
}

func genRandomizedKvs(kvs []key.KeyVal) []key.KeyVal {
	randKvs := make([]key.KeyVal, len(kvs))
	copy(randKvs, kvs)

	//From: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
	for i := len(randKvs) - 1; i > 0; i-- {
		j := rand.Intn(i + 1)
		randKvs[i], randKvs[j] = randKvs[j], randKvs[i]
	}

	return randKvs
}

func RunTimes() string {
	// Grab list of keys from RunTime map; MAJOR un-feature of Go!
	var ks = make([]string, len(RunTime))
	var i int = 0
	for k := range RunTime {
		ks[i] = k
		i++
	}
	sort.Strings(ks)

	var s = ""

	s += "Key                                      Val\n"
	s += "========================================+==========\n"

	for _, k := range ks {
		v := RunTime[k]
		s += fmt.Sprintf("%-40s %s\n", k, v)
	}
	return s
}

// This Test is to guarantee that hamt.go and hamt32/hamt.go and hamt64/hamt.go
// definitions of TableOptionName and table options stay in lock step.
func TestTableOptions(t *testing.T) {
	if hamt.HybridTables != hamt32.HybridTables {
		t.Fatal("hamt.HybridTables != hamt32.HybridTables")
	}
	if hamt32.HybridTables != hamt64.HybridTables {
		t.Fatal("hamt32.HybridTables != hamt64.HybridTables")
	}

	if hamt.FullTablesOnly != hamt32.FullTablesOnly {
		t.Fatal("hamt.FullTablesOnly != hamt32.FullTablesOnly")
	}
	if hamt32.FullTablesOnly != hamt64.FullTablesOnly {
		t.Fatal("hamt32.FullTablesOnly != hamt64.FullTablesOnly")
	}

	if hamt.CompTablesOnly != hamt32.CompTablesOnly {
		t.Fatal("hamt.CompTablesOnly != hamt32.CompTablesOnly")
	}
	if hamt32.CompTablesOnly != hamt64.CompTablesOnly {
		t.Fatal("hamt32.CompTablesOnly != hamt64.CompTablesOnly")
	}

	if len(hamt.TableOptionName) != len(hamt32.TableOptionName) {
		t.Fatal("len(hamt.TableOptionName) != len(hamt32.TableOptionName)")
	}
	if len(hamt32.TableOptionName) != len(hamt64.TableOptionName) {
		t.Fatal("len(hamt32.TableOptionName) != len(hamt64.TableOptionName)")
	}
}

//stupid on many levels
func TestNewHamt32(t *testing.T) {
	var h = hamt.NewHamt32()
	if !h.IsEmpty() {
		t.Fatal("!?!? a brand new Hamt !IsEmpty()")
	}
}

//stupid on many levels
func TestNewHamt64(t *testing.T) {
	var h = hamt.NewHamt32()
	if !h.IsEmpty() {
		t.Fatal("!?!? a brand new Hamt !IsEmpty()")
	}
}
<commit_msg>added StrVal struct & genRandomizSvs() function<commit_after>package hamt_test

import (
	"flag"
	"fmt"
	"log"
	"math/rand"
	"os"
	"sort"
	"testing"
	"time"

	"github.com/lleo/go-hamt"
	"github.com/lleo/go-hamt/hamt32"
	"github.com/lleo/go-hamt/hamt64"
	"github.com/lleo/go-hamt/key"
	"github.com/lleo/go-hamt/stringkey"
	"github.com/lleo/stringutil"

	"github.com/pkg/errors"
)

// Found depth 5 collision between 3m+2k & 3m+4k at depth=5
// Works for hamt32 testing coverage not for hamt64 coverage
var numKvs int = (3 * 1024 * 1024) + (4 * 1024) // between 3m+2k & 3m+4k

//var SVS []StrVal
var KVS []key.KeyVal

var TableOption int

var LookupHamt32 *hamt32.Hamt

var LookupHamt64 *hamt64.Hamt

var Inc = stringutil.Lower.Inc

var StartTime = make(map[string]time.Time)
var RunTime = make(map[string]time.Duration)

func TestMain(m *testing.M) {
	var fullonly, componly, hybrid, all bool
	flag.BoolVar(&fullonly, "F", false, "Use full tables only and exclude C and H Options.")
	flag.BoolVar(&componly, "C", false, "Use compressed tables only and exclude F and H Options.")
	flag.BoolVar(&hybrid, "H", false, "Use compressed tables initially and exclude F and C Options.")
	flag.BoolVar(&all, "A", false, "Run all Tests w/ Options set to hamt32.FullTablesOnly, hamt32.CompTablesOnly, and hamt32.HybridTables; in that order.")

	flag.Parse()

	// If all flag set, ignore fullonly, componly, and hybrid.
	if !all {

		// only one flag may be set between fullonly, componly, and hybrid
		if (fullonly && (componly || hybrid)) ||
			(componly && (fullonly || hybrid)) ||
			(hybrid && (componly || fullonly)) {
			flag.PrintDefaults()
			os.Exit(1)
		}
	}

	// If no flags given, run all tests.
	if !(all || fullonly || componly || hybrid) {
		all = true
	}

	log.SetFlags(log.Lshortfile)

	var logfile, err = os.Create("test.log")
	if err != nil {
		log.Fatal(errors.Wrap(err, "failed to os.Create(\"test.log\")"))
	}
	defer logfile.Close()

	log.SetOutput(logfile)

	log.Println("TestMain: and so it begins...")

	KVS = buildKeyVals("global", numKvs)

	// execute
	var xit int
	if all {
		TableOption = hamt32.FullTablesOnly
		log.Printf("TestMain: TableOption == %s\n", hamt32.TableOptionName[TableOption])
		fmt.Printf("Running TableOption = %s\n", hamt32.TableOptionName[TableOption])

		xit = m.Run()
		if xit != 0 {
			os.Exit(1)
		}

		TableOption = hamt32.CompTablesOnly
		log.Printf("TestMain: TableOption == %s\n", hamt32.TableOptionName[TableOption])
		fmt.Printf("Running TableOption = %s\n", hamt32.TableOptionName[TableOption])

		xit = m.Run()
		if xit != 0 {
			os.Exit(1)
		}

		TableOption = hamt32.HybridTables
		log.Printf("TestMain: TableOption == %s\n", hamt32.TableOptionName[TableOption])
		fmt.Printf("Running TableOption = %s\n", hamt32.TableOptionName[TableOption])

		xit = m.Run()
	} else {
		if hybrid {
			TableOption = hamt32.HybridTables
		} else if fullonly {
			TableOption = hamt32.FullTablesOnly
		} else /* if componly */ {
			TableOption = hamt32.CompTablesOnly
		}

		log.Printf("TestMain: TableOption == %s\n", hamt32.TableOptionName[TableOption])
		fmt.Printf("Running TableOption = %s\n", hamt32.TableOptionName[TableOption])

		xit = m.Run()
	}

	log.Println("\n", RunTimes())

	os.Exit(xit)
}

func buildKeyVals(prefix string, num int) []key.KeyVal {
	var name = fmt.Sprintf("%s-buildKeyVals-%d", prefix, num)
	StartTime[name] = time.Now()

	var kvs = make([]key.KeyVal, num)
	var s = "aaa"

	for i := 0; i < num; i++ {
		var k = stringkey.New(s)

		kvs[i] = key.KeyVal{k, i}
		s = Inc(s)
	}

	RunTime[name] = time.Since(StartTime[name])
	return kvs
}

func buildMap(prefix string, num int) map[string]int {
	var name = fmt.Sprintf("%s-buildMap", prefix)
	StartTime[name] = time.Now()

	var m = make(map[string]int, num)
	var s = "aaa"

	for i := 0; i < num; i++ {
		m[s] = i

		s = Inc(s)
	}

	RunTime[name] = time.Since(StartTime[name])
	return m
}

func buildHamt32(prefix string, kvs []key.KeyVal, opt int) (*hamt32.Hamt, error) {
	var name = fmt.Sprintf("%s-buildHamt32-%d", prefix, len(kvs))
	StartTime[name] = time.Now()

	var h = hamt32.New(opt)

	for _, kv := range kvs {
		var k = kv.Key
		var v = kv.Val

		var inserted = h.Put(k, v)
		if !inserted {
			return nil, fmt.Errorf("failed to Put(%s, %v)", k, v)
		}
	}

	RunTime[name] = time.Since(StartTime[name])
	return h, nil
}

func buildHamt64(prefix string, kvs []key.KeyVal, opt int) (*hamt64.Hamt, error) {
	var name = fmt.Sprintf("%s-buildHamt64-%d", prefix, len(kvs))
	StartTime[name] = time.Now()

	var h = hamt64.New(opt)

	for _, kv := range kvs {
		var k = kv.Key
		var v = kv.Val

		var inserted = h.Put(k, v)
		if !inserted {
			return nil, fmt.Errorf("failed to Put(%s, %v)", k, v)
		}
	}

	RunTime[name] = time.Since(StartTime[name])
	return h, nil
}

func genRandomizedKvs(kvs []key.KeyVal) []key.KeyVal {
	randKvs := make([]key.KeyVal, len(kvs))
	copy(randKvs, kvs)

	//From: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
	for i := len(randKvs) - 1; i > 0; i-- {
		j := rand.Intn(i + 1)
		randKvs[i], randKvs[j] = randKvs[j], randKvs[i]
	}

	return randKvs
}

type StrVal struct {
	Str string
	Val int
}

func genRandomizedSvs(svs []StrVal) []StrVal {
	var randSvs = make([]StrVal, len(svs))
	copy(randSvs, svs)

	//From: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
	var limit = len(randSvs) //n-1
	for i := 0; i < limit; /* aka i_max = n-2 */ i++ {
		j := rand.Intn(i+1) - 1 // i <= j < n; j_min=n-(n-2+1)-1=0; j_max=n-0-1=n-1
		randSvs[i], randSvs[j] = randSvs[j], randSvs[i]
	}

	return randSvs
}

func RunTimes() string {
	// Grab list of keys from RunTime map; MAJOR un-feature of Go!
	var ks = make([]string, len(RunTime))
	var i int = 0
	for k := range RunTime {
		ks[i] = k
		i++
	}
	sort.Strings(ks)

	var s = ""

	s += "Key                                      Val\n"
	s += "========================================+==========\n"

	for _, k := range ks {
		v := RunTime[k]
		s += fmt.Sprintf("%-40s %s\n", k, v)
	}
	return s
}

// This Test is to guarantee that hamt.go and hamt32/hamt.go and hamt64/hamt.go
// definitions of TableOptionName and table options stay in lock step.
func TestTableOptions(t *testing.T) {
	if hamt.HybridTables != hamt32.HybridTables {
		t.Fatal("hamt.HybridTables != hamt32.HybridTables")
	}
	if hamt32.HybridTables != hamt64.HybridTables {
		t.Fatal("hamt32.HybridTables != hamt64.HybridTables")
	}

	if hamt.FullTablesOnly != hamt32.FullTablesOnly {
		t.Fatal("hamt.FullTablesOnly != hamt32.FullTablesOnly")
	}
	if hamt32.FullTablesOnly != hamt64.FullTablesOnly {
		t.Fatal("hamt32.FullTablesOnly != hamt64.FullTablesOnly")
	}

	if hamt.CompTablesOnly != hamt32.CompTablesOnly {
		t.Fatal("hamt.CompTablesOnly != hamt32.CompTablesOnly")
	}
	if hamt32.CompTablesOnly != hamt64.CompTablesOnly {
		t.Fatal("hamt32.CompTablesOnly != hamt64.CompTablesOnly")
	}

	if len(hamt.TableOptionName) != len(hamt32.TableOptionName) {
		t.Fatal("len(hamt.TableOptionName) != len(hamt32.TableOptionName)")
	}
	if len(hamt32.TableOptionName) != len(hamt64.TableOptionName) {
		t.Fatal("len(hamt32.TableOptionName) != len(hamt64.TableOptionName)")
	}
}

//stupid on many levels
func TestNewHamt32(t *testing.T) {
	var h = hamt.NewHamt32()
	if !h.IsEmpty() {
		t.Fatal("!?!? a brand new Hamt !IsEmpty()")
	}
}

//stupid on many levels
func TestNewHamt64(t *testing.T) {
	var h = hamt.NewHamt32()
	if !h.IsEmpty() {
		t.Fatal("!?!? a brand new Hamt !IsEmpty()")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"os"
	"path"
)

type harvester struct {
	// executable path
	root string

	// executable dependencies names
	deps map[string]bool

	// all libs
	libs map[string]*dylib

	// current lib stack
	libStack []*dylib
}

func newHarvester(root string) *harvester {
	return &harvester{
		root:     root,
		deps:     make(map[string]bool),
		libs:     make(map[string]*dylib),
		libStack: []*dylib{},
	}
}

func (h *harvester) collect() error {
	return h.collectFile(h.root, true)
}

func (h *harvester) collectFile(path string, isRoot bool) error {
	if flagVerbose {
		fmt.Println("Collecting:", path)
	}

	out, err := oToolExec(path)
	if err != nil {
		fmt.Println("Failed to exec otool:", err, string(out))
		return err
	}

	libs, err := oToolParse(out)
	if err != nil {
		return err
	}

	for _, lib := range libs {
		if curLib := h.curLib(); curLib != nil {
			curLib.addDep(lib)
		}

		if lib.path == path {
			continue
		}

		// root dependencies
		h.deps[lib.name] = true

		if h.libs[lib.name] == nil {
			// all libs
			h.libs[lib.name] = lib

			if err := h.collectLib(lib); err != nil {
				return err
			}
		}
	}

	return nil
}

func (h *harvester) collectLib(lib *dylib) error {
	h.pushLib(lib)

	if err := h.collectFile(lib.path, false); err != nil {
		return err
	}

	// pop
	h.popLib()

	return nil
}

func (h *harvester) pushLib(lib *dylib) {
	h.libStack = append(h.libStack, lib)
}

func (h *harvester) popLib() *dylib {
	var result *dylib

	result, h.libStack = h.libStack[len(h.libStack)-1], h.libStack[:len(h.libStack)-1]

	return result
}

func (h *harvester) curLib() *dylib {
	if len(h.libStack) == 0 {
		return nil
	}

	return h.libStack[len(h.libStack)-1]
}

func (h *harvester) destDir() string {
	if flagDest != "" {
		return flagDest
	}

	return path.Dir(h.root)
}

func (h *harvester) copy() error {
	for _, lib := range h.libs {
		dest := h.destLibPath(lib)

		if _, err := os.Stat(dest); !os.IsNotExist(err) {
			if !flagForce {
				return fmt.Errorf("-force flag not set and destination file already exists: %s", dest)
			}
		}

		if err := copyFile(lib.path, dest); err != nil {
			return err
		}
	}

	return nil
}

func (h *harvester) destLibPath(lib *dylib) string {
	return path.Join(h.destDir(), lib.name)
}

func (h *harvester) fixReferences() error {
	// fixes executable
	for name := range h.deps {
		if err := installNameChange(h.root, h.libs[name]); err != nil {
			return err
		}
	}

	// fixes libs
	for _, lib := range h.libs {
		if err := installNameChange(h.destLibPath(lib), lib); err != nil {
			return err
		}
	}

	return nil
}

func copyFile(from string, to string) error {
	if flagVerbose {
		fmt.Printf("Copying: %s => %s\n", from, to)
	}

	// open source file
	src, err := os.Open(from)
	if err != nil {
		return err
	}
	defer src.Close()

	// open destination file
	dst, err := os.Create(to)
	if err != nil {
		return err
	}
	defer dst.Close()

	// copy
	if _, err := io.Copy(dst, src); err != nil {
		return err
	}

	return nil
}
<commit_msg>fixes lib deps<commit_after>package main

import (
	"fmt"
	"io"
	"os"
	"path"
)

type harvester struct {
	// executable path
	root string

	// executable dependencies names
	deps map[string]bool

	// all libs
	libs map[string]*dylib

	// current lib stack
	libStack []*dylib
}

func newHarvester(root string) *harvester {
	return &harvester{
		root:     root,
		deps:     make(map[string]bool),
		libs:     make(map[string]*dylib),
		libStack: []*dylib{},
	}
}

func (h *harvester) collect() error {
	return h.collectFile(h.root, true)
}

func (h *harvester) collectFile(path string, isRoot bool) error {
	if flagVerbose {
		fmt.Println("Collecting:", path)
	}

	out, err := oToolExec(path)
	if err != nil {
		fmt.Println("Failed to exec otool:", err, string(out))
		return err
	}

	libs, err := oToolParse(out)
	if err != nil {
		return err
	}

	for _, lib := range libs {
		if curLib := h.curLib(); curLib != nil {
			curLib.addDep(lib)
		}

		if lib.path == path {
			continue
		}

		// root dependencies
		h.deps[lib.name] = true

		if h.libs[lib.name] == nil {
			// all libs
			h.libs[lib.name] = lib

			if err := h.collectLib(lib); err != nil {
				return err
			}
		}
	}

	return nil
}

func (h *harvester) collectLib(lib *dylib) error {
	h.pushLib(lib)

	if err := h.collectFile(lib.path, false); err != nil {
		return err
	}

	// pop
	h.popLib()

	return nil
}

func (h *harvester) pushLib(lib *dylib) {
	h.libStack = append(h.libStack, lib)
}

func (h *harvester) popLib() *dylib {
	var result *dylib

	result, h.libStack = h.libStack[len(h.libStack)-1], h.libStack[:len(h.libStack)-1]

	return result
}

func (h *harvester) curLib() *dylib {
	if len(h.libStack) == 0 {
		return nil
	}

	return h.libStack[len(h.libStack)-1]
}

func (h *harvester) destDir() string {
	if flagDest != "" {
		return flagDest
	}

	return path.Dir(h.root)
}

func (h *harvester) copy() error {
	for _, lib := range h.libs {
		dest := h.destLibPath(lib)

		if _, err := os.Stat(dest); !os.IsNotExist(err) {
			if !flagForce {
				return fmt.Errorf("-force flag not set and destination file already exists: %s", dest)
			}
		}

		if err := copyFile(lib.path, dest); err != nil {
			return err
		}
	}

	return nil
}

func (h *harvester) destLibPath(lib *dylib) string {
	return path.Join(h.destDir(), lib.name)
}

func (h *harvester) fixReferences() error {
	// fixes executable
	for name := range h.deps {
		if err := installNameChange(h.root, h.libs[name]); err != nil {
			return err
		}
	}

	// fixes libs
	for _, lib := range h.libs {
		destLib := h.destLibPath(lib)

		for _, dep := range lib.deps {
			if err := installNameChange(destLib, dep); err != nil {
				return err
			}
		}
	}

	return nil
}

func copyFile(from string, to string) error {
	if flagVerbose {
		fmt.Printf("Copying: %s => %s\n", from, to)
	}

	// open source file
	src, err := os.Open(from)
	if err != nil {
		return err
	}
	defer src.Close()

	// open destination file
	dst, err := os.Create(to)
	if err != nil {
		return err
	}
	defer dst.Close()

	// copy
	if _, err := io.Copy(dst, src); err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package havilland

import (
	"sync"
)

type Airline struct {
	flights map[interface{}]*flight
	sync.Mutex
}

type flight struct {
	value interface{}
	err   error
	sync.WaitGroup
}

func (a *Airline) Fly(identifier interface{}, fn func() (interface{}, error)) (interface{}, error) {
	// Lock airspace
	a.Lock()

	// Initialize flights
	if a.flights == nil {
		a.flights = make(map[interface{}]*flight)
	}

	// If an existing flight exists reuse it
	if f, ok := a.flights[identifier]; ok {
		a.Unlock()
		f.Wait()
		return f.value, f.err
	}

	// Create a new flight
	f := new(flight)
	f.Add(1)
	a.flights[identifier] = f
	a.Unlock()

	// Execute
	f.value, f.err = fn()
	f.Done()

	// Remove flight from airspace
	a.Lock()
	delete(a.flights, identifier)
	a.Unlock()

	return f.value, f.err
}
<commit_msg>unexport Mutex<commit_after>// Generic single flight
package havilland

import (
	"sync"
)

type Airline struct {
	flights map[interface{}]*flight
	m sync.Mutex
}

type flight struct {
	value interface{}
	err   error
	sync.WaitGroup
}

func (a *Airline) Fly(identifier interface{}, fn func() (interface{}, error)) (interface{}, error) {
	// Lock airspace
	a.m.Lock()

	// Initialize flights
	if a.flights == nil {
		a.flights = make(map[interface{}]*flight)
	}

	// If an existing flight exists reuse it
	if f, ok := a.flights[identifier]; ok {
		a.m.Unlock()
		f.Wait()
		return f.value, f.err
	}

	// Create a new flight
	f := new(flight)
	f.Add(1)
	a.flights[identifier] = f
	a.m.Unlock()

	// Execute
	f.value, f.err = fn()
	f.Done()

	// Remove flight from airspace
	a.m.Lock()
	delete(a.flights, identifier)
	a.m.Unlock()

	return f.value, f.err
}
<|endoftext|>


<commit_before>package main

import (
	"image"
	"image/color"
	"image/draw"
	"os"
	"time"

	. "github.com/eaburns/quart/geom"
	"github.com/eaburns/quart/phys"

	"github.com/skelterjohn/go.wde"
)

const (
	width  = 640
	height = 480

	speed         = 5
	gravity       = -3
	stopThreshold = 1
)

var (
	black  = color.RGBA{A: 255}
	white  = color.RGBA{R: 255, G: 255, B: 255, A: 255}
	red    = color.RGBA{R: 255, A: 255}
	green  = color.RGBA{G: 255, A: 255}
	blue   = color.RGBA{B: 255, A: 255}
	purple = color.RGBA{R: 255, B: 255, A: 255}
	teal   = color.RGBA{G: 255, B: 255, A: 255}
)

var (
	vel    Vector
	circle = Circle{Center: Point{200, 200}, Radius: 50}

	// Sides is the set of polygon sides.
	sides = []Side{
		{{0, height - 1}, {0, 0}},
		{{0, 0}, {width - 1, 0}},
		{{width - 1, 0}, {width - 1, height - 1}},
		{{width - 1, height - 1}, {0, height - 1}},
	}

	// Click is the position of the latest mouse click.
	click = Point{-1, -1}

	// Cursor is the current cursor position.
	cursor Point

	// Stopped is true if the circle has effectively stopped moving.
	stopped bool
)

func main() {
	go mainLoop()
	wde.Run()
}

func mainLoop() {
	win, err := wde.NewWindow(width, height)
	if err != nil {
		panic(err)
	}
	win.SetTitle("geom test")
	win.Show()

	drawScene(win)

	tick := time.NewTicker(40 * time.Millisecond)
	for {
		select {
		case ev, ok := <-win.EventChan():
			if !ok {
				os.Exit(0)
			}
			switch ev := ev.(type) {
			case wde.CloseEvent:
				os.Exit(0)
			case wde.KeyTypedEvent:
				keyTyped(ev)
			case wde.KeyDownEvent:
				keyDown(wde.KeyEvent(ev))
			case wde.KeyUpEvent:
				keyUp(wde.KeyEvent(ev))
			case wde.MouseDraggedEvent:
				mouseMove(ev.MouseEvent)
			case wde.MouseMovedEvent:
				mouseMove(ev.MouseEvent)
			case wde.MouseDownEvent:
				mouseDown(wde.MouseButtonEvent(ev))
			case wde.MouseUpEvent:
				mouseUp(wde.MouseButtonEvent(ev))
			}

		case <-tick.C:
			if !stopped {
				start := circle.Center
				circle = phys.MoveCircle(circle, vel, sides)
				circle = phys.MoveCircle(circle, Vector{0, gravity}, sides)
				dist := start.Minus(circle.Center).Magnitude()
				stopped = dist < stopThreshold
			}
			drawScene(win)
		}
	}
}

func mouseMove(ev wde.MouseEvent) {
	cursor = Point{float64(ev.Where.X), float64(height - ev.Where.Y - 1)}
}

func mouseDown(ev wde.MouseButtonEvent) {
	switch ev.Which {
	case wde.LeftButton:
		click = Point{float64(ev.Where.X), float64(height - ev.Where.Y - 1)}
	}
}

func mouseUp(ev wde.MouseButtonEvent) {
	switch ev.Which {
	case wde.LeftButton:
		sides = append(sides, Side{click, cursor})
		click = Point{-1, -1}
	}
}

func keyTyped(ev wde.KeyTypedEvent) {
	switch ev.Key {
	case "d":
		if len(sides) > 4 {
			sides = sides[:len(sides)-1]
		}
	}
}

func keyDown(ev wde.KeyEvent) {
	switch ev.Key {
	case "left_arrow":
		vel[0] = -speed
	case "right_arrow":
		vel[0] = speed
	case "up_arrow":
		vel[1] = speed
	case "down_arrow":
		vel[1] = -speed
	}
	stopped = false
}

func keyUp(ev wde.KeyEvent) {
	switch ev.Key {
	case "left_arrow", "right_arrow":
		vel[0] = 0
	case "up_arrow", "down_arrow":
		vel[1] = 0
	}
}

func drawScene(win wde.Window) {
	clear(win)
	cv := ImageCanvas{win.Screen()}

	for _, s := range sides {
		s.Draw(cv, black)
	}
	circle.Draw(cv, black)

	if click[0] >= 0 {
		Side{click, cursor}.Draw(cv, blue)
	}

	win.FlushImage()
}

func clear(win wde.Window) {
	img := win.Screen()
	draw.Draw(img, img.Bounds(), image.NewUniform(white), image.ZP, draw.Src)
}
<commit_msg>Remove color variables.<commit_after>package main

import (
	"image"
	"image/color"
	"image/draw"
	"os"
	"time"

	. "github.com/eaburns/quart/geom"
	"github.com/eaburns/quart/phys"

	"github.com/skelterjohn/go.wde"
)

const (
	width  = 640
	height = 480

	speed         = 5
	gravity       = -3
	stopThreshold = 1
)

var (
	vel    Vector
	circle = Circle{Center: Point{200, 200}, Radius: 50}

	// Sides is the set of polygon sides.
	sides = []Side{
		{{0, height - 1}, {0, 0}},
		{{0, 0}, {width - 1, 0}},
		{{width - 1, 0}, {width - 1, height - 1}},
		{{width - 1, height - 1}, {0, height - 1}},
	}

	// Click is the position of the latest mouse click.
	click = Point{-1, -1}

	// Cursor is the current cursor position.
	cursor Point

	// Stopped is true if the circle has effectively stopped moving.
	stopped bool
)

func main() {
	go mainLoop()
	wde.Run()
}

func mainLoop() {
	win, err := wde.NewWindow(width, height)
	if err != nil {
		panic(err)
	}
	win.SetTitle("geom test")
	win.Show()

	drawScene(win)

	tick := time.NewTicker(40 * time.Millisecond)
	for {
		select {
		case ev, ok := <-win.EventChan():
			if !ok {
				os.Exit(0)
			}
			switch ev := ev.(type) {
			case wde.CloseEvent:
				os.Exit(0)
			case wde.KeyTypedEvent:
				keyTyped(ev)
			case wde.KeyDownEvent:
				keyDown(wde.KeyEvent(ev))
			case wde.KeyUpEvent:
				keyUp(wde.KeyEvent(ev))
			case wde.MouseDraggedEvent:
				mouseMove(ev.MouseEvent)
			case wde.MouseMovedEvent:
				mouseMove(ev.MouseEvent)
			case wde.MouseDownEvent:
				mouseDown(wde.MouseButtonEvent(ev))
			case wde.MouseUpEvent:
				mouseUp(wde.MouseButtonEvent(ev))
			}

		case <-tick.C:
			if !stopped {
				start := circle.Center
				circle = phys.MoveCircle(circle, vel, sides)
				circle = phys.MoveCircle(circle, Vector{0, gravity}, sides)
				dist := start.Minus(circle.Center).Magnitude()
				stopped = dist < stopThreshold
			}
			drawScene(win)
		}
	}
}

func mouseMove(ev wde.MouseEvent) {
	cursor = Point{float64(ev.Where.X), float64(height - ev.Where.Y - 1)}
}

func mouseDown(ev wde.MouseButtonEvent) {
	switch ev.Which {
	case wde.LeftButton:
		click = Point{float64(ev.Where.X), float64(height - ev.Where.Y - 1)}
	}
}

func mouseUp(ev wde.MouseButtonEvent) {
	switch ev.Which {
	case wde.LeftButton:
		sides = append(sides, Side{click, cursor})
		click = Point{-1, -1}
	}
}

func keyTyped(ev wde.KeyTypedEvent) {
	switch ev.Key {
	case "d":
		if len(sides) > 4 {
			sides = sides[:len(sides)-1]
		}
	}
}

func keyDown(ev wde.KeyEvent) {
	switch ev.Key {
	case "left_arrow":
		vel[0] = -speed
	case "right_arrow":
		vel[0] = speed
	case "up_arrow":
		vel[1] = speed
	case "down_arrow":
		vel[1] = -speed
	}
	stopped = false
}

func keyUp(ev wde.KeyEvent) {
	switch ev.Key {
	case "left_arrow", "right_arrow":
		vel[0] = 0
	case "up_arrow", "down_arrow":
		vel[1] = 0
	}
}

func drawScene(win wde.Window) {
	clear(win)
	cv := ImageCanvas{win.Screen()}

	for _, s := range sides {
		s.Draw(cv, color.Black)
	}
	circle.Draw(cv, color.Black)

	if click[0] >= 0 {
		Side{click, cursor}.Draw(cv, color.RGBA{B: 255, A: 255})
	}

	win.FlushImage()
}

func clear(win wde.Window) {
	img := win.Screen()
	draw.Draw(img, img.Bounds(), image.NewUniform(color.White), image.ZP, draw.Src)
}
<|endoftext|>


<commit_before>package apps

import (
	"io"
	"net/url"
	"regexp"
	"time"

	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/logger"
	"github.com/sirupsen/logrus"
)

var slugReg = regexp.MustCompile(`^[a-z0-9\-]+$`)

// Operation is the type of operation the installer is created for.
type Operation int

const (
	// Install operation for installing an application
	Install Operation = iota + 1
	// Update operation for updating an application
	Update
	// Delete operation for deleting an application
	Delete
)

// Installer is used to install or update applications.
type Installer struct {
	fetcher  Fetcher
	op       Operation
	fs       Copier
	db       couchdb.Database
	endState State

	man  Manifest
	src  *url.URL
	slug string

	err  error
	errc chan error
	manc chan Manifest
	log  *logrus.Entry
}

// InstallerOptions provides the slug name of the application along with the
// source URL.
type InstallerOptions struct {
	Type        AppType
	Operation   Operation
	Slug        string
	SourceURL   string
	Deactivated bool
}

// Fetcher interface should be implemented by the underlying transport
// used to fetch the application data.
type Fetcher interface {
	// FetchManifest should returns an io.ReadCloser to read the
	// manifest data
	FetchManifest(src *url.URL) (io.ReadCloser, error)
	// Fetch should download the application and install it in the given
	// directory.
	Fetch(src *url.URL, fs Copier, man Manifest) error
}

// NewInstaller creates a new Installer
func NewInstaller(db couchdb.Database, fs Copier, opts *InstallerOptions) (*Installer, error) {
	if opts.Operation == 0 {
		panic("Missing installer operation")
	}
	if opts.Type != Webapp && opts.Type != Konnector {
		panic("Bad or missing installer type")
	}

	slug := opts.Slug
	if slug == "" || !slugReg.MatchString(slug) {
		return nil, ErrInvalidSlugName
	}

	// For konnectors applications, we actually create a tar archive in which the
	// sources are stored before copying the archive into the application
	// storage.
	if opts.Type == Konnector {
		fs = newTarCopier(fs, KonnectorArchiveName)
	}

	man, err := GetBySlug(db, slug, opts.Type)
	if opts.Operation == Install {
		if err == nil {
			return nil, ErrAlreadyExists
		}
		if err != ErrNotFound {
			return nil, err
		}
		err = nil
		switch opts.Type {
		case Webapp:
			man = &WebappManifest{}
		case Konnector:
			man = &KonnManifest{}
		}
	} else if err != nil {
		return nil, err
	}

	var src *url.URL
	switch opts.Operation {
	case Install:
		if opts.SourceURL == "" {
			return nil, ErrMissingSource
		}
		src, err = url.Parse(opts.SourceURL)
	case Update, Delete:
		var srcString string
		if opts.SourceURL == "" {
			srcString = man.Source()
		} else {
			srcString = opts.SourceURL
		}
		src, err = url.Parse(srcString)
	}
	if err != nil {
		return nil, err
	}

	var endState State
	if opts.Deactivated || man.State() == Installed {
		endState = Installed
	} else {
		endState = Ready
	}

	log := logger.WithDomain(db.Prefix())

	var manFilename string
	switch opts.Type {
	case Webapp:
		manFilename = WebappManifestName
	case Konnector:
		manFilename = KonnectorManifestName
	}

	var fetcher Fetcher
	switch src.Scheme {
	case "git", "git+ssh", "ssh+git":
		fetcher = newGitFetcher(manFilename, log)
	case "http", "https":
		fetcher = newHTTPFetcher(manFilename, log)
	case "registry":
		// TODO:
		// fetcher = newRegistryFetcher(manFilename, log)
	default:
		return nil, ErrNotSupportedSource
	}

	return &Installer{
		fetcher:  fetcher,
		op:       opts.Operation,
		db:       db,
		fs:       fs,
		endState: endState,

		man:  man,
		src:  src,
		slug: slug,

		errc: make(chan error, 1),
		manc: make(chan Manifest, 2),
		log:  log,
	}, nil
}

// Run will install, update or delete the application linked to the installer,
// depending on specified operation. It will report its progress or error (see
// Poll method) and should be run asynchronously.
func (i *Installer) Run() {
	defer i.endOfProc()
	switch i.op {
	case Install:
		i.man, i.err = i.install()
	case Update:
		i.man, i.err = i.update()
	case Delete:
		i.man, i.err = i.delete()
	}
}

// RunSync does the same work as Run but can be used synchronously.
func (i *Installer) RunSync() (Manifest, error) {
	go i.Run()
	for {
		man, done, err := i.Poll()
		if err != nil {
			return nil, err
		}
		if done {
			return man, nil
		}
	}
}

func (i *Installer) endOfProc() {
	man, err := i.man, i.err
	if man == nil || err == ErrBadState {
		i.errc <- err
		return
	}
	if err != nil {
		man.SetState(Errored)
		man.SetError(err)
		man.Update(i.db)
		i.errc <- err
		return
	}
	if i.op != Delete {
		man.SetState(i.endState)
		man.Update(i.db)
	}
	i.manc <- i.man
}

// install will perform the installation of an application. It returns the
// freshly fetched manifest from the source along with a possible error in case
// the installation went wrong.
//
// Note that the fetched manifest is returned even if an error occurred while
// upgrading.
func (i *Installer) install() (Manifest, error) {
	i.log.Infof("[apps] Start install: %s %s", i.slug, i.src.String())
	man := i.man
	if err := i.ReadManifest(Installing, man); err != nil {
		return nil, err
	}
	if err := man.Create(i.db); err != nil {
		return man, err
	}
	i.manc <- man
	return man, i.fetcher.Fetch(i.src, i.fs, man)
}

// update will perform the update of an already installed application. It
// returns the freshly fetched manifest from the source along with a possible
// error in case the update went wrong.
//
// Note that the fetched manifest is returned even if an error occurred while
// upgrading.
func (i *Installer) update() (Manifest, error) {
	i.log.Infof("[apps] Start update: %s %s", i.slug, i.src.String())
	man := i.man
	if err := i.checkState(man); err != nil {
		return nil, err
	}
	if err := i.ReadManifest(Upgrading, man); err != nil {
		return man, err
	}
	if err := man.Update(i.db); err != nil {
		return man, err
	}
	i.manc <- man
	return man, i.fetcher.Fetch(i.src, i.fs, man)
}

func (i *Installer) delete() (Manifest, error) {
	i.log.Infof("[apps] Start delete: %s %s", i.slug, i.src.String())
	man := i.man
	if err := i.checkState(man); err != nil {
		return nil, err
	}
	return man, i.man.Delete(i.db)
}

// checkState returns whether or not the manifest is in the right state to
// perform an update or deletion.
func (i *Installer) checkState(man Manifest) error {
	state := man.State()
	if state == Ready ||
		state == Installed ||
		state == Errored {
		return nil
	}
	if time.Since(man.LastUpdate()) > 15*time.Minute {
		return nil
	}
	return ErrBadState
}

// ReadManifest will fetch the manifest and read its JSON content into the
// passed manifest pointer.
//
// The State field of the manifest will be set to the specified state.
func (i *Installer) ReadManifest(state State, man Manifest) error {
	r, err := i.fetcher.FetchManifest(i.src)
	if err != nil {
		return err
	}
	defer r.Close()
	man.SetState(state)
	return man.ReadManifest(io.LimitReader(r, ManifestMaxSize), i.slug, i.src.String())
}

// Poll should be used to monitor the progress of the Installer.
func (i *Installer) Poll() (Manifest, bool, error) {
	select {
	case man := <-i.manc:
		state := man.State()
		done := (state == Ready || state == Installed)
		return man, done, nil
	case err := <-i.errc:
		return nil, false, err
	}
}
<commit_msg>Comment out registry scheme<commit_after>package apps

import (
	"io"
	"net/url"
	"regexp"
	"time"

	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/logger"
	"github.com/sirupsen/logrus"
)

var slugReg = regexp.MustCompile(`^[a-z0-9\-]+$`)

// Operation is the type of operation the installer is created for.
type Operation int

const (
	// Install operation for installing an application
	Install Operation = iota + 1
	// Update operation for updating an application
	Update
	// Delete operation for deleting an application
	Delete
)

// Installer is used to install or update applications.
type Installer struct {
	fetcher  Fetcher
	op       Operation
	fs       Copier
	db       couchdb.Database
	endState State

	man  Manifest
	src  *url.URL
	slug string

	err  error
	errc chan error
	manc chan Manifest
	log  *logrus.Entry
}

// InstallerOptions provides the slug name of the application along with the
// source URL.
type InstallerOptions struct {
	Type        AppType
	Operation   Operation
	Slug        string
	SourceURL   string
	Deactivated bool
}

// Fetcher interface should be implemented by the underlying transport
// used to fetch the application data.
type Fetcher interface {
	// FetchManifest should returns an io.ReadCloser to read the
	// manifest data
	FetchManifest(src *url.URL) (io.ReadCloser, error)
	// Fetch should download the application and install it in the given
	// directory.
	Fetch(src *url.URL, fs Copier, man Manifest) error
}

// NewInstaller creates a new Installer
func NewInstaller(db couchdb.Database, fs Copier, opts *InstallerOptions) (*Installer, error) {
	if opts.Operation == 0 {
		panic("Missing installer operation")
	}
	if opts.Type != Webapp && opts.Type != Konnector {
		panic("Bad or missing installer type")
	}

	slug := opts.Slug
	if slug == "" || !slugReg.MatchString(slug) {
		return nil, ErrInvalidSlugName
	}

	// For konnectors applications, we actually create a tar archive in which the
	// sources are stored before copying the archive into the application
	// storage.
	if opts.Type == Konnector {
		fs = newTarCopier(fs, KonnectorArchiveName)
	}

	man, err := GetBySlug(db, slug, opts.Type)
	if opts.Operation == Install {
		if err == nil {
			return nil, ErrAlreadyExists
		}
		if err != ErrNotFound {
			return nil, err
		}
		err = nil
		switch opts.Type {
		case Webapp:
			man = &WebappManifest{}
		case Konnector:
			man = &KonnManifest{}
		}
	} else if err != nil {
		return nil, err
	}

	var src *url.URL
	switch opts.Operation {
	case Install:
		if opts.SourceURL == "" {
			return nil, ErrMissingSource
		}
		src, err = url.Parse(opts.SourceURL)
	case Update, Delete:
		var srcString string
		if opts.SourceURL == "" {
			srcString = man.Source()
		} else {
			srcString = opts.SourceURL
		}
		src, err = url.Parse(srcString)
	}
	if err != nil {
		return nil, err
	}

	var endState State
	if opts.Deactivated || man.State() == Installed {
		endState = Installed
	} else {
		endState = Ready
	}

	log := logger.WithDomain(db.Prefix())

	var manFilename string
	switch opts.Type {
	case Webapp:
		manFilename = WebappManifestName
	case Konnector:
		manFilename = KonnectorManifestName
	}

	var fetcher Fetcher
	switch src.Scheme {
	case "git", "git+ssh", "ssh+git":
		fetcher = newGitFetcher(manFilename, log)
	case "http", "https":
		fetcher = newHTTPFetcher(manFilename, log)
	// TODO:
	// case "registry":
	// fetcher = newRegistryFetcher(manFilename, log)
	default:
		return nil, ErrNotSupportedSource
	}

	return &Installer{
		fetcher:  fetcher,
		op:       opts.Operation,
		db:       db,
		fs:       fs,
		endState: endState,

		man:  man,
		src:  src,
		slug: slug,

		errc: make(chan error, 1),
		manc: make(chan Manifest, 2),
		log:  log,
	}, nil
}

// Run will install, update or delete the application linked to the installer,
// depending on specified operation. It will report its progress or error (see
// Poll method) and should be run asynchronously.
func (i *Installer) Run() {
	defer i.endOfProc()
	switch i.op {
	case Install:
		i.man, i.err = i.install()
	case Update:
		i.man, i.err = i.update()
	case Delete:
		i.man, i.err = i.delete()
	}
}

// RunSync does the same work as Run but can be used synchronously.
func (i *Installer) RunSync() (Manifest, error) {
	go i.Run()
	for {
		man, done, err := i.Poll()
		if err != nil {
			return nil, err
		}
		if done {
			return man, nil
		}
	}
}

func (i *Installer) endOfProc() {
	man, err := i.man, i.err
	if man == nil || err == ErrBadState {
		i.errc <- err
		return
	}
	if err != nil {
		man.SetState(Errored)
		man.SetError(err)
		man.Update(i.db)
		i.errc <- err
		return
	}
	if i.op != Delete {
		man.SetState(i.endState)
		man.Update(i.db)
	}
	i.manc <- i.man
}

// install will perform the installation of an application. It returns the
// freshly fetched manifest from the source along with a possible error in case
// the installation went wrong.
//
// Note that the fetched manifest is returned even if an error occurred while
// upgrading.
func (i *Installer) install() (Manifest, error) {
	i.log.Infof("[apps] Start install: %s %s", i.slug, i.src.String())
	man := i.man
	if err := i.ReadManifest(Installing, man); err != nil {
		return nil, err
	}
	if err := man.Create(i.db); err != nil {
		return man, err
	}
	i.manc <- man
	return man, i.fetcher.Fetch(i.src, i.fs, man)
}

// update will perform the update of an already installed application. It
// returns the freshly fetched manifest from the source along with a possible
// error in case the update went wrong.
//
// Note that the fetched manifest is returned even if an error occurred while
// upgrading.
func (i *Installer) update() (Manifest, error) {
	i.log.Infof("[apps] Start update: %s %s", i.slug, i.src.String())
	man := i.man
	if err := i.checkState(man); err != nil {
		return nil, err
	}
	if err := i.ReadManifest(Upgrading, man); err != nil {
		return man, err
	}
	if err := man.Update(i.db); err != nil {
		return man, err
	}
	i.manc <- man
	return man, i.fetcher.Fetch(i.src, i.fs, man)
}

func (i *Installer) delete() (Manifest, error) {
	i.log.Infof("[apps] Start delete: %s %s", i.slug, i.src.String())
	man := i.man
	if err := i.checkState(man); err != nil {
		return nil, err
	}
	return man, i.man.Delete(i.db)
}

// checkState returns whether or not the manifest is in the right state to
// perform an update or deletion.
func (i *Installer) checkState(man Manifest) error {
	state := man.State()
	if state == Ready ||
		state == Installed ||
		state == Errored {
		return nil
	}
	if time.Since(man.LastUpdate()) > 15*time.Minute {
		return nil
	}
	return ErrBadState
}

// ReadManifest will fetch the manifest and read its JSON content into the
// passed manifest pointer.
//
// The State field of the manifest will be set to the specified state.
func (i *Installer) ReadManifest(state State, man Manifest) error {
	r, err := i.fetcher.FetchManifest(i.src)
	if err != nil {
		return err
	}
	defer r.Close()
	man.SetState(state)
	return man.ReadManifest(io.LimitReader(r, ManifestMaxSize), i.slug, i.src.String())
}

// Poll should be used to monitor the progress of the Installer.
func (i *Installer) Poll() (Manifest, bool, error) {
	select {
	case man := <-i.manc:
		state := man.State()
		done := (state == Ready || state == Installed)
		return man, done, nil
	case err := <-i.errc:
		return nil, false, err
	}
}
<|endoftext|>