<commit_before>package storage

import "github.com/slok/khronos/job"

// Client implements the client of an storage
type Client interface {
	Close() error

	// Job actions
	// GetJobs returns an slice of job instances; the low parmeter will be the
	// first job and the high will be the next one to the last job that will be
	// returned; this acts like an slice operator. 0 on high parameter means all.
	// this would be translated as jobs[low:] and 0 on low would be jobs[:high]
	GetJobs(low, high int) ([]*job.Job, error)

	// GetJob returns a job by ID
	GetJob(id int) (*job.Job, error)

	// SaveJob stores the job; this method works as an insert or update, the
	// method will know if the job needs to be updated or inserted by identifying
	// the presence of the ID. This wil save as a batch so on an update the
	// instance should have all the fields set
	SaveJob(j *job.Job) error

	// DeleteJob deletes a job
	DeleteJob(j *job.Job) error
}
<commit_msg>Add result methods to the storage interface<commit_after>package storage

import "github.com/slok/khronos/job"

// Client implements the client of an storage
type Client interface {
	Close() error

	// Job actions
	// GetJobs returns an slice of job instances; the low parmeter will be the
	// first job and the high will be the next one to the last job that will be
	// returned; this acts like an slice operator. 0 on high parameter means all.
	// this would be translated as jobs[low:] and 0 on low would be jobs[:high]
	GetJobs(low, high int) ([]*job.Job, error)

	// GetJob returns a job by ID
	GetJob(id int) (*job.Job, error)

	// SaveJob stores the job; this method works as an insert or update, the
	// method will know if the job needs to be updated or inserted by identifying
	// the presence of the ID. This wil save as a batch so on an update the
	// instance should have all the fields set
	SaveJob(j *job.Job) error

	// DeleteJob deletes a job
	DeleteJob(j *job.Job) error

	// Result actions
	// GetResults returns an slice of results from a job; jobID parameter is the
	// id of the job from the results will be obtained. The low parmeter will be the
	// first result and the high will be the next one to the last result that will be
	// returned; this acts like an slice operator. 0 on high parameter means all.
	// this would be translated as results[low:] and 0 on low would be results[:high]
	GetResults(jobID, low, high int) ([]*job.Result, error)

	// GetResult returns a result based on the id
	GetResult(id int) (*job.Result, error)

	// SaveResult stores the result.  Results cannot be updated
	SaveResult(r *job.Result) error

	// DeleteResult deletes a result
	DeleteResult(r *job.Result) error
}
<|endoftext|>


<commit_before>package storage

import (
	"bytes"
	"context"
	"io"
	"io/ioutil"
	"os"

	GCP "cloud.google.com/go/storage"
	"google.golang.org/api/option"
	SDK "google.golang.org/api/storage/v1"

	"github.com/evalphobia/google-api-go-wrapper/config"
	"github.com/evalphobia/google-api-go-wrapper/log"
)

const (
	serviceName = "storage"
)

// Storage repesents Cloud Storage API client.
type Storage struct {
	*GCP.Client
	logger log.Logger
}

// New returns initialized *Storage.
func New(ctx context.Context, conf config.Config) (*Storage, error) {
	if len(conf.Scopes) == 0 {
		conf.Scopes = []string{SDK.CloudPlatformScope}
	}

	httpClient, err := conf.Client()
	if err != nil {
		return nil, err
	}

	svc, err := GCP.NewClient(ctx, option.WithHTTPClient(httpClient))
	if err != nil {
		return nil, err
	}

	return &Storage{
		Client: svc,
		logger: log.DefaultLogger,
	}, nil
}

// SetLogger sets internal API logger.
func (s *Storage) SetLogger(logger log.Logger) {
	s.logger = logger
}

// UploadByBytes uploads an object from bytes.
func (s *Storage) UploadByBytes(byt []byte, opt ObjectOption) error {
	r := bytes.NewReader(byt)
	return s.Upload(r, opt)
}

// UploadByFile uploads an object from bytes.
func (s *Storage) UploadByFile(filepath string, opt ObjectOption) error {
	f, err := os.Open(filepath)
	if err != nil {
		return err
	}
	defer f.Close()
	return s.Upload(f, opt)
}

// Upload uploads an object from io.Reader.
func (s *Storage) Upload(r io.Reader, opt ObjectOption) error {
	w := s.getObjectHandle(opt).NewWriter(opt.getOrCreateContext())
	_, err := io.Copy(w, r)
	if err != nil {
		s.Errorf("error on `object.write` operation by Upload; bucket=%s, path=%s, error=%s;", opt.BucketName, opt.Path, err.Error())
		return err
	}
	return w.Close()
}

// Delete deletes an object.
func (s *Storage) Delete(opt ObjectOption) error {
	handler := s.getObjectHandle(opt)
	err := handler.Delete(opt.getOrCreateContext())
	if hasDeleteError(err) {
		s.Errorf("error on `object.delete` operation by Delete; bucket=%s, path=%s, error=%s;", opt.BucketName, opt.Path, err.Error())
		return err
	}
	return nil
}

// Download downloads object data.
func (s *Storage) Download(opt ObjectOption) (data []byte, err error) {
	r, err := s.getObjectHandle(opt).NewReader(opt.getOrCreateContext())
	if err != nil {
		s.Errorf("error on creating reader; bucket=%s, path=%s, error=%s;", opt.BucketName, opt.Path, err.Error())
		return nil, err
	}
	defer r.Close()

	data, err = ioutil.ReadAll(r)
	if err != nil {
		s.Errorf("error on `object.get` operation by Download; bucket=%s, path=%s, error=%s;", opt.BucketName, opt.Path, err.Error())
	}
	return data, err
}

// Rename moves an object from opt.Path to destPath..
func (s *Storage) Rename(destPath string, opt ObjectOption) error {
	destOpt := opt
	destOpt.Path = destPath
	src := s.getObjectHandle(opt)
	dest := s.getObjectHandle(destOpt)

	ctx := opt.getOrCreateContext()
	_, err := dest.CopierFrom(src).Run(ctx)
	if err != nil {
		s.Errorf("error on `object.write` operation by Rename; bucket=%s, src=%s, dest=%s, error=%s;", opt.BucketName, opt.Path, destPath, err.Error())
		return err
	}

	err = src.Delete(ctx)
	if err != nil {
		s.Errorf("error on `object.delete` operation by Delete; bucket=%s, path=%s, error=%s;", opt.BucketName, opt.Path, err.Error())
	}
	return err
}

// IsExists checks if an object exists.
func (s *Storage) IsExists(opt ObjectOption) (isExist bool, err error) {
	_, err = s.Attrs(opt)
	switch {
	case isErrObjectNotExist(err):
		return false, nil
	case err != nil:
		return false, err
	default:
		return true, nil
	}
}

// Attrs gets attributes of the object.
func (s *Storage) Attrs(opt ObjectOption) (*GCP.ObjectAttrs, error) {
	handler := s.getObjectHandle(opt)
	a, err := handler.Attrs(opt.getOrCreateContext())
	if err != nil {
		s.Errorf("error on `object.get` operation by Attrs; bucket=%s, path=%s, error=%s;", opt.BucketName, opt.Path, err.Error())
	}
	return a, err
}

func (s *Storage) getObjectHandle(opt ObjectOption) *GCP.ObjectHandle {
	return s.Client.Bucket(opt.BucketName).Object(opt.Path)
}

// Errorf logging error information.
func (s *Storage) Errorf(format string, vv ...interface{}) {
	s.logger.Errorf(serviceName, format, vv...)
}

func hasDeleteError(err error) bool {
	switch {
	case err == nil,
		isErrObjectNotExist(err):
		return false
	default:
		return true
	}
}

func isErrObjectNotExist(err error) bool {
	return err != nil && err == GCP.ErrObjectNotExist
}
<commit_msg>[storage] Add Copy (#27)<commit_after>package storage

import (
	"bytes"
	"context"
	"io"
	"io/ioutil"
	"os"

	GCP "cloud.google.com/go/storage"
	"google.golang.org/api/option"
	SDK "google.golang.org/api/storage/v1"

	"github.com/evalphobia/google-api-go-wrapper/config"
	"github.com/evalphobia/google-api-go-wrapper/log"
)

const (
	serviceName = "storage"
)

// Storage repesents Cloud Storage API client.
type Storage struct {
	*GCP.Client
	logger log.Logger
}

// New returns initialized *Storage.
func New(ctx context.Context, conf config.Config) (*Storage, error) {
	if len(conf.Scopes) == 0 {
		conf.Scopes = []string{SDK.CloudPlatformScope}
	}

	httpClient, err := conf.Client()
	if err != nil {
		return nil, err
	}

	svc, err := GCP.NewClient(ctx, option.WithHTTPClient(httpClient))
	if err != nil {
		return nil, err
	}

	return &Storage{
		Client: svc,
		logger: log.DefaultLogger,
	}, nil
}

// SetLogger sets internal API logger.
func (s *Storage) SetLogger(logger log.Logger) {
	s.logger = logger
}

// UploadByBytes uploads an object from bytes.
func (s *Storage) UploadByBytes(byt []byte, opt ObjectOption) error {
	r := bytes.NewReader(byt)
	return s.Upload(r, opt)
}

// UploadByFile uploads an object from bytes.
func (s *Storage) UploadByFile(filepath string, opt ObjectOption) error {
	f, err := os.Open(filepath)
	if err != nil {
		return err
	}
	defer f.Close()
	return s.Upload(f, opt)
}

// Upload uploads an object from io.Reader.
func (s *Storage) Upload(r io.Reader, opt ObjectOption) error {
	w := s.getObjectHandle(opt).NewWriter(opt.getOrCreateContext())
	_, err := io.Copy(w, r)
	if err != nil {
		s.Errorf("error on `object.write` operation by Upload; bucket=%s, path=%s, error=%s;", opt.BucketName, opt.Path, err.Error())
		return err
	}
	return w.Close()
}

// Delete deletes an object.
func (s *Storage) Delete(opt ObjectOption) error {
	handler := s.getObjectHandle(opt)
	err := handler.Delete(opt.getOrCreateContext())
	if hasDeleteError(err) {
		s.Errorf("error on `object.delete` operation by Delete; bucket=%s, path=%s, error=%s;", opt.BucketName, opt.Path, err.Error())
		return err
	}
	return nil
}

// Download downloads object data.
func (s *Storage) Download(opt ObjectOption) (data []byte, err error) {
	r, err := s.getObjectHandle(opt).NewReader(opt.getOrCreateContext())
	if err != nil {
		s.Errorf("error on creating reader; bucket=%s, path=%s, error=%s;", opt.BucketName, opt.Path, err.Error())
		return nil, err
	}
	defer r.Close()

	data, err = ioutil.ReadAll(r)
	if err != nil {
		s.Errorf("error on `object.get` operation by Download; bucket=%s, path=%s, error=%s;", opt.BucketName, opt.Path, err.Error())
	}
	return data, err
}

// Rename moves an object from opt.Path to destPath..
func (s *Storage) Rename(destPath string, opt ObjectOption) error {
	destOpt := opt
	destOpt.Path = destPath
	src := s.getObjectHandle(opt)
	dest := s.getObjectHandle(destOpt)

	ctx := opt.getOrCreateContext()
	_, err := dest.CopierFrom(src).Run(ctx)
	if err != nil {
		s.Errorf("error on `object.write` operation by Rename; bucket=%s, src=%s, dest=%s, error=%s;", opt.BucketName, opt.Path, destPath, err.Error())
		return err
	}

	err = src.Delete(ctx)
	if err != nil {
		s.Errorf("error on `object.delete` operation by Delete; bucket=%s, path=%s, error=%s;", opt.BucketName, opt.Path, err.Error())
	}
	return err
}

// Copy copies an object from opt.Path to destPath..
func (s *Storage) Copy(destPath string, opt ObjectOption) error {
	destOpt := opt
	destOpt.Path = destPath
	src := s.getObjectHandle(opt)
	dest := s.getObjectHandle(destOpt)

	ctx := opt.getOrCreateContext()
	_, err := dest.CopierFrom(src).Run(ctx)
	if err != nil {
		s.Errorf("error on `object.write` operation by Copy; bucket=%s, src=%s, dest=%s, error=%s;", opt.BucketName, opt.Path, destPath, err.Error())
	}
	return err
}

// CopyToBucket copies an object from opt.Path to another bucket.
func (s *Storage) CopyToBucket(destBucket, destPath string, opt ObjectOption) error {
	destOpt := opt
	destOpt.BucketName = destBucket
	destOpt.Path = destPath
	src := s.getObjectHandle(opt)
	dest := s.getObjectHandle(destOpt)

	ctx := opt.getOrCreateContext()
	_, err := dest.CopierFrom(src).Run(ctx)
	if err != nil {
		s.Errorf("error on `object.write` operation by Copy; bucket=%s, src=%s, dest=%s, error=%s;", opt.BucketName, opt.Path, destPath, err.Error())
	}
	return err
}

// IsExists checks if an object exists.
func (s *Storage) IsExists(opt ObjectOption) (isExist bool, err error) {
	_, err = s.Attrs(opt)
	switch {
	case isErrObjectNotExist(err):
		return false, nil
	case err != nil:
		return false, err
	default:
		return true, nil
	}
}

// Attrs gets attributes of the object.
func (s *Storage) Attrs(opt ObjectOption) (*GCP.ObjectAttrs, error) {
	handler := s.getObjectHandle(opt)
	a, err := handler.Attrs(opt.getOrCreateContext())
	if err != nil {
		s.Errorf("error on `object.get` operation by Attrs; bucket=%s, path=%s, error=%s;", opt.BucketName, opt.Path, err.Error())
	}
	return a, err
}

func (s *Storage) getObjectHandle(opt ObjectOption) *GCP.ObjectHandle {
	return s.Client.Bucket(opt.BucketName).Object(opt.Path)
}

// Errorf logging error information.
func (s *Storage) Errorf(format string, vv ...interface{}) {
	s.logger.Errorf(serviceName, format, vv...)
}

func hasDeleteError(err error) bool {
	switch {
	case err == nil,
		isErrObjectNotExist(err):
		return false
	default:
		return true
	}
}

func isErrObjectNotExist(err error) bool {
	return err != nil && err == GCP.ErrObjectNotExist
}
<|endoftext|>


<commit_before>package riak

import (
	"reflect"
	"testing"

	"github.com/basho/riak-go-client/rpb/riak_ts"
)

func TestBuildTsGetReqCorrectlyViaBuilder(t *testing.T) {
	key := make([]TsCell, 3)

	key[0] = NewStringTsCell("Test Key Value")
	key[1] = NewSint64TsCell(1)
	key[2] = NewDoubleTsCell(0.1)

	builder := NewTsFetchRowCommandBuilder().
		WithTable("table_name").
		WithKey(key)

	cmd, err := builder.Build()
	if err != nil {
		t.Fatal(err.Error())
	}

	if _, ok := cmd.(retryableCommand); !ok {
		t.Errorf("got %v, want cmd %s to implement retryableCommand", ok, reflect.TypeOf(cmd))
	}

	protobuf, err := cmd.constructPbRequest()
	if err != nil {
		t.Fatal(err.Error())
	}
	if protobuf == nil {
		t.FailNow()
	}

	if req, ok := protobuf.(*riak_ts.TsGetReq); ok {
		if expected, actual := "table_name", string(req.GetTable()); expected != actual {
			t.Errorf("expected %v, got %v", expected, actual)
		}

		if expected, actual := 3, len(req.GetKey()); expected != actual {
			t.Errorf("expected %v, got %v", expected, actual)
		}
	} else {
		t.Errorf("ok: %v - could not convert %v to *riak_ts.TsGetReq", ok, reflect.TypeOf(protobuf))
	}
}

func TestBuildTsDelReqCorrectlyViaBuilder(t *testing.T) {
	key := make([]TsCell, 3)

	key[0] = NewStringTsCell("Test Key Value")
	key[1] = NewSint64TsCell(1)
	key[2] = NewDoubleTsCell(0.1)

	builder := NewTsFetchRowCommandBuilder().
		WithTable("table_name").
		WithKey(key)

	cmd, err := builder.Build()
	if err != nil {
		t.Fatal(err.Error())
	}

	if _, ok := cmd.(retryableCommand); !ok {
		t.Errorf("got %v, want cmd %s to implement retryableCommand", ok, reflect.TypeOf(cmd))
	}

	protobuf, err := cmd.constructPbRequest()
	if err != nil {
		t.Fatal(err.Error())
	}
	if protobuf == nil {
		t.FailNow()
	}

	if req, ok := protobuf.(*riak_ts.TsDelReq); ok {
		if expected, actual := "table_name", string(req.GetTable()); expected != actual {
			t.Errorf("expected %v, got %v", expected, actual)
		}

		if expected, actual := 3, len(req.GetKey()); expected != actual {
			t.Errorf("expected %v, got %v", expected, actual)
		}
	} else {
		t.Errorf("ok: %v - could not convert %v to *riak_ts.TsDelReq", ok, reflect.TypeOf(protobuf))
	}
}

func TestBuildTsPutReqCorrectlyViaBuilder(t *testing.T) {
	row := make([]TsCell, 5)

	row[0] = NewStringTsCell("Test Key Value")
	row[1] = NewSint64TsCell(1)
	row[2] = NewDoubleTsCell(0.1)
	row[3] = NewBooleanTsCell(true)
	row[4] = NewTimestampTsCell(1234567890)

	rows := make([][]TsCell, 1)
	rows[0] = row

	builder := NewTsStoreRowsCommandBuilder().
		WithTable("table_name").
		WithRows(rows)

	cmd, err := builder.Build()
	if err != nil {
		t.Fatal(err.Error())
	}

	if _, ok := cmd.(retryableCommand); !ok {
		t.Errorf("got %v, want cmd %s to implement retryableCommand", ok, reflect.TypeOf(cmd))
	}

	protobuf, err := cmd.constructPbRequest()
	if err != nil {
		t.Fatal(err.Error())
	}

	if protobuf == nil {
		t.FailNow()
	}

	if req, ok := protobuf.(*riak_ts.TsPutReq); ok {
		if expected, actual := "table_name", string(req.GetTable()); expected != actual {
			t.Errorf("expected %v, got %v", expected, actual)
		}

		if expected, actual := 1, len(req.GetRows()); expected != actual {
			t.Errorf("expected %v, got %v", expected, actual)
		}
	} else {
		t.Errorf("ok: %v - could not convert %v to *riak_ts.TsPutReq", ok, reflect.TypeOf(protobuf))
	}
}

func TestBuildTsQueryReqCorrectlyViaBuilder(t *testing.T) {

	builder := NewTsQueryCommandBuilder().
		WithQuery("DESCRIBE table_name")

	if builder.protobuf.GetStream() != false {
		t.Errorf("expected %v, got %v", nil, builder.protobuf.GetStream())
	}

	cmd, err := builder.Build()
	if err != nil {
		t.Fatal(err.Error())
	}

	builder.WithStreaming(true)
	if expected, actual := true, builder.protobuf.GetStream(); expected != actual {
		t.Errorf("expected %v, got %v", expected, actual)
	}

	cmd, err = builder.Build()
	if err == nil {
		t.Fatal("Expected an error, you cannot build the command with streaming true and callback = nil")
	}

	cb := func(rows [][]TsCell) error {
		// do stuff
		return nil
	}

	builder.WithCallback(cb)

	cmd, err = builder.Build()
	if err != nil {
		t.Fatal(err.Error())
	}

	protobuf, err := cmd.constructPbRequest()
	if err != nil {
		t.Fatal(err.Error())
	}

	if protobuf == nil {
		t.FailNow()
	}

	if req, ok := protobuf.(*riak_ts.TsQueryReq); ok {
		if expected, actual := "DESCRIBE table_name", string(req.GetQuery().GetBase()); expected != actual {
			t.Errorf("expected %v, got %v", expected, actual)
		}
		if expected, actual := true, req.GetStream(); expected != actual {
			t.Errorf("expected %v, got %v", expected, actual)
		}
	} else {
		t.Errorf("ok: %v - could not convert %v to *riak_ts.TsQueryReq", ok, reflect.TypeOf(protobuf))
	}
}

func TestBuildTsListKeysReqCorrectlyViaBuilder(t *testing.T) {
	builder := NewTsListKeysCommandBuilder().
		WithTable("table_name")

	if expected, actual := false, builder.streaming; expected != actual {
		t.Errorf("expected %v, got %v", expected, actual)
	}

	cmd, err := builder.Build()
	if err != nil {
		t.Fatal(err.Error())
	}

	builder.WithStreaming(true)
	if expected, actual := true, builder.streaming; expected != actual {
		t.Errorf("expected %v, got %v", expected, actual)
	}

	cmd, err = builder.Build()
	if err == nil {
		t.Fatal("Expected an error, you cannot build the command with streaming true and callback = nil")
	}

	cb := func(keys []string) error {
		// do stuff
		return nil
	}

	builder.WithCallback(cb)
	cmd, err = builder.Build()
	if err != nil {
		t.Fatal(err.Error())
	}

	protobuf, err := cmd.constructPbRequest()
	if err != nil {
		t.Fatal(err.Error())
	}

	if protobuf == nil {
		t.FailNow()
	}

	if req, ok := protobuf.(*riak_ts.TsListKeysReq); ok {
		if expected, actual := "table_name", string(req.GetTable()); expected != actual {
			t.Errorf("expected %v, got %v", expected, actual)
		}
	} else {
		t.Errorf("ok: %v - could not convert %v to *riak_ts.TsListKeysReq", ok, reflect.TypeOf(protobuf))
	}
}
<commit_msg>Fix unit test<commit_after>package riak

import (
	"reflect"
	"testing"

	"github.com/basho/riak-go-client/rpb/riak_ts"
)

func TestBuildTsGetReqCorrectlyViaBuilder(t *testing.T) {
	key := make([]TsCell, 3)

	key[0] = NewStringTsCell("Test Key Value")
	key[1] = NewSint64TsCell(1)
	key[2] = NewDoubleTsCell(0.1)

	builder := NewTsFetchRowCommandBuilder().
		WithTable("table_name").
		WithKey(key)

	cmd, err := builder.Build()
	if err != nil {
		t.Fatal(err.Error())
	}

	if _, ok := cmd.(retryableCommand); !ok {
		t.Errorf("got %v, want cmd %s to implement retryableCommand", ok, reflect.TypeOf(cmd))
	}

	protobuf, err := cmd.constructPbRequest()
	if err != nil {
		t.Fatal(err.Error())
	}
	if protobuf == nil {
		t.FailNow()
	}

	if req, ok := protobuf.(*riak_ts.TsGetReq); ok {
		if expected, actual := "table_name", string(req.GetTable()); expected != actual {
			t.Errorf("expected %v, got %v", expected, actual)
		}

		if expected, actual := 3, len(req.GetKey()); expected != actual {
			t.Errorf("expected %v, got %v", expected, actual)
		}
	} else {
		t.Errorf("ok: %v - could not convert %v to *riak_ts.TsGetReq", ok, reflect.TypeOf(protobuf))
	}
}

func TestBuildTsDelReqCorrectlyViaBuilder(t *testing.T) {
	key := make([]TsCell, 3)

	key[0] = NewStringTsCell("Test Key Value")
	key[1] = NewSint64TsCell(1)
	key[2] = NewDoubleTsCell(0.1)

	builder := NewTsDeleteRowCommandBuilder().
		WithTable("table_name").
		WithKey(key)

	cmd, err := builder.Build()
	if err != nil {
		t.Fatal(err.Error())
	}

	if _, ok := cmd.(retryableCommand); !ok {
		t.Errorf("got %v, want cmd %s to implement retryableCommand", ok, reflect.TypeOf(cmd))
	}

	protobuf, err := cmd.constructPbRequest()
	if err != nil {
		t.Fatal(err.Error())
	}
	if protobuf == nil {
		t.FailNow()
	}

	if req, ok := protobuf.(*riak_ts.TsDelReq); ok {
		if expected, actual := "table_name", string(req.GetTable()); expected != actual {
			t.Errorf("expected %v, got %v", expected, actual)
		}

		if expected, actual := 3, len(req.GetKey()); expected != actual {
			t.Errorf("expected %v, got %v", expected, actual)
		}
	} else {
		t.Errorf("ok: %v - could not convert %v to *riak_ts.TsDelReq", ok, reflect.TypeOf(protobuf))
	}
}

func TestBuildTsPutReqCorrectlyViaBuilder(t *testing.T) {
	row := make([]TsCell, 5)

	row[0] = NewStringTsCell("Test Key Value")
	row[1] = NewSint64TsCell(1)
	row[2] = NewDoubleTsCell(0.1)
	row[3] = NewBooleanTsCell(true)
	row[4] = NewTimestampTsCell(1234567890)

	rows := make([][]TsCell, 1)
	rows[0] = row

	builder := NewTsStoreRowsCommandBuilder().
		WithTable("table_name").
		WithRows(rows)

	cmd, err := builder.Build()
	if err != nil {
		t.Fatal(err.Error())
	}

	if _, ok := cmd.(retryableCommand); !ok {
		t.Errorf("got %v, want cmd %s to implement retryableCommand", ok, reflect.TypeOf(cmd))
	}

	protobuf, err := cmd.constructPbRequest()
	if err != nil {
		t.Fatal(err.Error())
	}

	if protobuf == nil {
		t.FailNow()
	}

	if req, ok := protobuf.(*riak_ts.TsPutReq); ok {
		if expected, actual := "table_name", string(req.GetTable()); expected != actual {
			t.Errorf("expected %v, got %v", expected, actual)
		}

		if expected, actual := 1, len(req.GetRows()); expected != actual {
			t.Errorf("expected %v, got %v", expected, actual)
		}
	} else {
		t.Errorf("ok: %v - could not convert %v to *riak_ts.TsPutReq", ok, reflect.TypeOf(protobuf))
	}
}

func TestBuildTsQueryReqCorrectlyViaBuilder(t *testing.T) {

	builder := NewTsQueryCommandBuilder().
		WithQuery("DESCRIBE table_name")

	if builder.protobuf.GetStream() != false {
		t.Errorf("expected %v, got %v", nil, builder.protobuf.GetStream())
	}

	cmd, err := builder.Build()
	if err != nil {
		t.Fatal(err.Error())
	}

	builder.WithStreaming(true)
	if expected, actual := true, builder.protobuf.GetStream(); expected != actual {
		t.Errorf("expected %v, got %v", expected, actual)
	}

	cmd, err = builder.Build()
	if err == nil {
		t.Fatal("Expected an error, you cannot build the command with streaming true and callback = nil")
	}

	cb := func(rows [][]TsCell) error {
		// do stuff
		return nil
	}

	builder.WithCallback(cb)

	cmd, err = builder.Build()
	if err != nil {
		t.Fatal(err.Error())
	}

	protobuf, err := cmd.constructPbRequest()
	if err != nil {
		t.Fatal(err.Error())
	}

	if protobuf == nil {
		t.FailNow()
	}

	if req, ok := protobuf.(*riak_ts.TsQueryReq); ok {
		if expected, actual := "DESCRIBE table_name", string(req.GetQuery().GetBase()); expected != actual {
			t.Errorf("expected %v, got %v", expected, actual)
		}
		if expected, actual := true, req.GetStream(); expected != actual {
			t.Errorf("expected %v, got %v", expected, actual)
		}
	} else {
		t.Errorf("ok: %v - could not convert %v to *riak_ts.TsQueryReq", ok, reflect.TypeOf(protobuf))
	}
}

func TestBuildTsListKeysReqCorrectlyViaBuilder(t *testing.T) {
	builder := NewTsListKeysCommandBuilder().
		WithTable("table_name")

	if expected, actual := false, builder.streaming; expected != actual {
		t.Errorf("expected %v, got %v", expected, actual)
	}

	cmd, err := builder.Build()
	if err != nil {
		t.Fatal(err.Error())
	}

	builder.WithStreaming(true)
	if expected, actual := true, builder.streaming; expected != actual {
		t.Errorf("expected %v, got %v", expected, actual)
	}

	cmd, err = builder.Build()
	if err == nil {
		t.Fatal("Expected an error, you cannot build the command with streaming true and callback = nil")
	}

	cb := func(keys []string) error {
		// do stuff
		return nil
	}

	builder.WithCallback(cb)
	cmd, err = builder.Build()
	if err != nil {
		t.Fatal(err.Error())
	}

	protobuf, err := cmd.constructPbRequest()
	if err != nil {
		t.Fatal(err.Error())
	}

	if protobuf == nil {
		t.FailNow()
	}

	if req, ok := protobuf.(*riak_ts.TsListKeysReq); ok {
		if expected, actual := "table_name", string(req.GetTable()); expected != actual {
			t.Errorf("expected %v, got %v", expected, actual)
		}
	} else {
		t.Errorf("ok: %v - could not convert %v to *riak_ts.TsListKeysReq", ok, reflect.TypeOf(protobuf))
	}
}
<|endoftext|>


<commit_before>package common

import (
	"fmt"

	"github.com/hashicorp/packer/helper/multistep"
	"github.com/hashicorp/packer/packer"
	"github.com/hashicorp/packer/template/interpolate"
	"github.com/outscale/osc-go/oapi"
)

type TagMap map[string]string
type OAPITags []oapi.ResourceTag

func (t OAPITags) Report(ui packer.Ui) {
	for _, tag := range t {
		ui.Message(fmt.Sprintf("Adding tag: \"%s\": \"%s\"",
			tag.Key, tag.Value))
	}
}

func (t TagMap) IsSet() bool {
	return len(t) > 0
}

func (t TagMap) OAPITags(ctx interpolate.Context, region string, state multistep.StateBag) (OAPITags, error) {
	var oapiTags []oapi.ResourceTag
	ctx.Data = extractBuildInfo(region, state)

	for key, value := range t {
		interpolatedKey, err := interpolate.Render(key, &ctx)
		if err != nil {
			return nil, fmt.Errorf("Error processing tag: %s:%s - %s", key, value, err)
		}
		interpolatedValue, err := interpolate.Render(value, &ctx)
		if err != nil {
			return nil, fmt.Errorf("Error processing tag: %s:%s - %s", key, value, err)
		}
		oapiTags = append(oapiTags, oapi.ResourceTag{
			Key:   interpolatedKey,
			Value: interpolatedValue,
		})
	}
	return oapiTags, nil
}
<commit_msg>feature: add create tags function<commit_after>package common

import (
	"fmt"

	"github.com/hashicorp/packer/helper/multistep"
	"github.com/hashicorp/packer/packer"
	"github.com/hashicorp/packer/template/interpolate"
	"github.com/outscale/osc-go/oapi"
)

type TagMap map[string]string
type OAPITags []oapi.ResourceTag

func (t OAPITags) Report(ui packer.Ui) {
	for _, tag := range t {
		ui.Message(fmt.Sprintf("Adding tag: \"%s\": \"%s\"",
			tag.Key, tag.Value))
	}
}

func (t TagMap) IsSet() bool {
	return len(t) > 0
}

func (t TagMap) OAPITags(ctx interpolate.Context, region string, state multistep.StateBag) (OAPITags, error) {
	var oapiTags []oapi.ResourceTag
	ctx.Data = extractBuildInfo(region, state)

	for key, value := range t {
		interpolatedKey, err := interpolate.Render(key, &ctx)
		if err != nil {
			return nil, fmt.Errorf("Error processing tag: %s:%s - %s", key, value, err)
		}
		interpolatedValue, err := interpolate.Render(value, &ctx)
		if err != nil {
			return nil, fmt.Errorf("Error processing tag: %s:%s - %s", key, value, err)
		}
		oapiTags = append(oapiTags, oapi.ResourceTag{
			Key:   interpolatedKey,
			Value: interpolatedValue,
		})
	}
	return oapiTags, nil
}

func CreateTags(conn *oapi.Client, resourceID string, ui packer.Ui, tags OAPITags) error {
	tags.Report(ui)

	_, err := conn.POST_CreateTags(oapi.CreateTagsRequest{
		ResourceIds: []string{resourceID},
		Tags:        tags,
	})

	return err
}
<|endoftext|>


<commit_before>//go:generate struct-markdown
//go:generate mapstructure-to-hcl2 -type Config

package scaleway

import (
	"errors"
	"fmt"
	"log"
	"os"

	"github.com/hashicorp/packer/common"
	"github.com/hashicorp/packer/common/uuid"
	"github.com/hashicorp/packer/helper/communicator"
	"github.com/hashicorp/packer/helper/config"
	"github.com/hashicorp/packer/helper/useragent"
	"github.com/hashicorp/packer/packer"
	"github.com/hashicorp/packer/template/interpolate"
	"github.com/mitchellh/mapstructure"
)

type Config struct {
	common.PackerConfig `mapstructure:",squash"`
	Comm                communicator.Config `mapstructure:",squash"`
	// The token to use to authenticate with your account.
	// It can also be specified via environment variable SCALEWAY_API_TOKEN. You
	// can see and generate tokens in the "Credentials"
	// section of the control panel.
	Token string `mapstructure:"api_token" required:"true"`
	// The organization id to use to identify your
	// organization. It can also be specified via environment variable
	// SCALEWAY_ORGANIZATION. Your organization id is available in the
	// "Account" section of the
	// control panel.
	// Previously named: api_access_key with environment variable: SCALEWAY_API_ACCESS_KEY
	Organization string `mapstructure:"organization_id" required:"true"`
	// The name of the region to launch the server in (par1
	// or ams1). Consequently, this is the region where the snapshot will be
	// available.
	Region string `mapstructure:"region" required:"true"`
	// The UUID of the base image to use. This is the image
	// that will be used to launch a new server and provision it. See
	// the images list
	// get the complete list of the accepted image UUID.
	Image string `mapstructure:"image" required:"true"`
	// The name of the server commercial type:
	// ARM64-128GB, ARM64-16GB, ARM64-2GB, ARM64-32GB, ARM64-4GB,
	// ARM64-64GB, ARM64-8GB, C1, C2L, C2M, C2S, START1-L,
	// START1-M, START1-S, START1-XS, X64-120GB, X64-15GB, X64-30GB,
	// X64-60GB
	CommercialType string `mapstructure:"commercial_type" required:"true"`
	// The name of the resulting snapshot that will
	// appear in your account. Default packer-TIMESTAMP
	SnapshotName string `mapstructure:"snapshot_name" required:"false"`
	// The name of the resulting image that will appear in
	// your account. Default packer-TIMESTAMP
	ImageName string `mapstructure:"image_name" required:"false"`
	// The name assigned to the server. Default
	// packer-UUID
	ServerName string `mapstructure:"server_name" required:"false"`
	// The id of an existing bootscript to use when
	// booting the server.
	Bootscript string `mapstructure:"bootscript" required:"false"`
	// The type of boot, can be either local or
	// bootscript, Default bootscript
	BootType string `mapstructure:"boottype" required:"false"`

	RemoveVolume bool `mapstructure:"remove_volume"`

	UserAgent string `mapstructure-to-hcl2:",skip"`
	ctx       interpolate.Context
}

func (c *Config) Prepare(raws ...interface{}) ([]string, error) {

	var md mapstructure.Metadata
	err := config.Decode(c, &config.DecodeOpts{
		Metadata:           &md,
		Interpolate:        true,
		InterpolateContext: &c.ctx,
		InterpolateFilter: &interpolate.RenderFilter{
			Exclude: []string{
				"run_command",
			},
		},
	}, raws...)
	if err != nil {
		return nil, err
	}

	c.UserAgent = useragent.String()

	if c.Organization == "" {
		if os.Getenv("SCALEWAY_ORGANIZATION") != "" {
			c.Organization = os.Getenv("SCALEWAY_ORGANIZATION")
		} else {
			log.Printf("Deprecation warning: Use SCALEWAY_ORGANIZATION environment variable and organization_id argument instead of api_access_key argument and SCALEWAY_API_ACCESS_KEY environment variable.")
			c.Organization = os.Getenv("SCALEWAY_API_ACCESS_KEY")
		}
	}

	if c.Token == "" {
		c.Token = os.Getenv("SCALEWAY_API_TOKEN")
	}

	if c.SnapshotName == "" {
		def, err := interpolate.Render("snapshot-packer-{{timestamp}}", nil)
		if err != nil {
			panic(err)
		}

		c.SnapshotName = def
	}

	if c.ImageName == "" {
		def, err := interpolate.Render("image-packer-{{timestamp}}", nil)
		if err != nil {
			panic(err)
		}

		c.ImageName = def
	}

	if c.ServerName == "" {
		// Default to packer-[time-ordered-uuid]
		c.ServerName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID())
	}

	if c.BootType == "" {
		c.BootType = "bootscript"
	}

	var errs *packer.MultiError
	if es := c.Comm.Prepare(&c.ctx); len(es) > 0 {
		errs = packer.MultiErrorAppend(errs, es...)
	}
	if c.Organization == "" {
		errs = packer.MultiErrorAppend(
			errs, errors.New("Scaleway Organization ID must be specified"))
	}

	if c.Token == "" {
		errs = packer.MultiErrorAppend(
			errs, errors.New("Scaleway Token must be specified"))
	}

	if c.Region == "" {
		errs = packer.MultiErrorAppend(
			errs, errors.New("region is required"))
	}

	if c.CommercialType == "" {
		errs = packer.MultiErrorAppend(
			errs, errors.New("commercial type is required"))
	}

	if c.Image == "" {
		errs = packer.MultiErrorAppend(
			errs, errors.New("image is required"))
	}

	if errs != nil && len(errs.Errors) > 0 {
		return nil, errs
	}

	packer.LogSecretFilter.Set(c.Token)
	return nil, nil
}
<commit_msg>change default scaleway boottype to local<commit_after>//go:generate struct-markdown
//go:generate mapstructure-to-hcl2 -type Config

package scaleway

import (
	"errors"
	"fmt"
	"log"
	"os"

	"github.com/hashicorp/packer/common"
	"github.com/hashicorp/packer/common/uuid"
	"github.com/hashicorp/packer/helper/communicator"
	"github.com/hashicorp/packer/helper/config"
	"github.com/hashicorp/packer/helper/useragent"
	"github.com/hashicorp/packer/packer"
	"github.com/hashicorp/packer/template/interpolate"
	"github.com/mitchellh/mapstructure"
)

type Config struct {
	common.PackerConfig `mapstructure:",squash"`
	Comm                communicator.Config `mapstructure:",squash"`
	// The token to use to authenticate with your account.
	// It can also be specified via environment variable SCALEWAY_API_TOKEN. You
	// can see and generate tokens in the "Credentials"
	// section of the control panel.
	Token string `mapstructure:"api_token" required:"true"`
	// The organization id to use to identify your
	// organization. It can also be specified via environment variable
	// SCALEWAY_ORGANIZATION. Your organization id is available in the
	// "Account" section of the
	// control panel.
	// Previously named: api_access_key with environment variable: SCALEWAY_API_ACCESS_KEY
	Organization string `mapstructure:"organization_id" required:"true"`
	// The name of the region to launch the server in (par1
	// or ams1). Consequently, this is the region where the snapshot will be
	// available.
	Region string `mapstructure:"region" required:"true"`
	// The UUID of the base image to use. This is the image
	// that will be used to launch a new server and provision it. See
	// the images list
	// get the complete list of the accepted image UUID.
	Image string `mapstructure:"image" required:"true"`
	// The name of the server commercial type:
	// ARM64-128GB, ARM64-16GB, ARM64-2GB, ARM64-32GB, ARM64-4GB,
	// ARM64-64GB, ARM64-8GB, C1, C2L, C2M, C2S, START1-L,
	// START1-M, START1-S, START1-XS, X64-120GB, X64-15GB, X64-30GB,
	// X64-60GB
	CommercialType string `mapstructure:"commercial_type" required:"true"`
	// The name of the resulting snapshot that will
	// appear in your account. Default packer-TIMESTAMP
	SnapshotName string `mapstructure:"snapshot_name" required:"false"`
	// The name of the resulting image that will appear in
	// your account. Default packer-TIMESTAMP
	ImageName string `mapstructure:"image_name" required:"false"`
	// The name assigned to the server. Default
	// packer-UUID
	ServerName string `mapstructure:"server_name" required:"false"`
	// The id of an existing bootscript to use when
	// booting the server.
	Bootscript string `mapstructure:"bootscript" required:"false"`
	// The type of boot, can be either local or
	// bootscript, Default bootscript
	BootType string `mapstructure:"boottype" required:"false"`

	RemoveVolume bool `mapstructure:"remove_volume"`

	UserAgent string `mapstructure-to-hcl2:",skip"`
	ctx       interpolate.Context
}

func (c *Config) Prepare(raws ...interface{}) ([]string, error) {

	var md mapstructure.Metadata
	err := config.Decode(c, &config.DecodeOpts{
		Metadata:           &md,
		Interpolate:        true,
		InterpolateContext: &c.ctx,
		InterpolateFilter: &interpolate.RenderFilter{
			Exclude: []string{
				"run_command",
			},
		},
	}, raws...)
	if err != nil {
		return nil, err
	}

	c.UserAgent = useragent.String()

	if c.Organization == "" {
		if os.Getenv("SCALEWAY_ORGANIZATION") != "" {
			c.Organization = os.Getenv("SCALEWAY_ORGANIZATION")
		} else {
			log.Printf("Deprecation warning: Use SCALEWAY_ORGANIZATION environment variable and organization_id argument instead of api_access_key argument and SCALEWAY_API_ACCESS_KEY environment variable.")
			c.Organization = os.Getenv("SCALEWAY_API_ACCESS_KEY")
		}
	}

	if c.Token == "" {
		c.Token = os.Getenv("SCALEWAY_API_TOKEN")
	}

	if c.SnapshotName == "" {
		def, err := interpolate.Render("snapshot-packer-{{timestamp}}", nil)
		if err != nil {
			panic(err)
		}

		c.SnapshotName = def
	}

	if c.ImageName == "" {
		def, err := interpolate.Render("image-packer-{{timestamp}}", nil)
		if err != nil {
			panic(err)
		}

		c.ImageName = def
	}

	if c.ServerName == "" {
		// Default to packer-[time-ordered-uuid]
		c.ServerName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID())
	}

	if c.BootType == "" {
		c.BootType = "local"
	}

	var errs *packer.MultiError
	if es := c.Comm.Prepare(&c.ctx); len(es) > 0 {
		errs = packer.MultiErrorAppend(errs, es...)
	}
	if c.Organization == "" {
		errs = packer.MultiErrorAppend(
			errs, errors.New("Scaleway Organization ID must be specified"))
	}

	if c.Token == "" {
		errs = packer.MultiErrorAppend(
			errs, errors.New("Scaleway Token must be specified"))
	}

	if c.Region == "" {
		errs = packer.MultiErrorAppend(
			errs, errors.New("region is required"))
	}

	if c.CommercialType == "" {
		errs = packer.MultiErrorAppend(
			errs, errors.New("commercial type is required"))
	}

	if c.Image == "" {
		errs = packer.MultiErrorAppend(
			errs, errors.New("image is required"))
	}

	if errs != nil && len(errs.Errors) > 0 {
		return nil, errs
	}

	packer.LogSecretFilter.Set(c.Token)
	return nil, nil
}
<|endoftext|>


<commit_before>package upcloud

import (
	"context"
	"fmt"
	"github.com/UpCloudLtd/upcloud-go-api/upcloud"
	"github.com/UpCloudLtd/upcloud-go-api/upcloud/request"
	"github.com/hashicorp/hcl/v2/hcldec"
	"github.com/hashicorp/packer/common"
	"github.com/hashicorp/packer/helper/communicator"
	"github.com/hashicorp/packer/helper/multistep"
	"github.com/hashicorp/packer/packer"
	"log"
)

// The unique ID for this builder.
const BuilderId = "upcloudltd.upcloud"

// Builder represents a Packer Builder.
type Builder struct {
	config *Config
	runner multistep.Runner
}

func (b *Builder) ConfigSpec() hcldec.ObjectSpec {
	return b.config.FlatMapstructure().HCL2Spec()
}

// Prepare processes the build configuration parameters and validates the configuration
func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
	var err error
	// Parse and create the configuration
	b.config, err = NewConfig(raws...)

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

	// Check that the client/service is usable
	service := b.config.GetService()

	if _, err := service.GetAccount(); err != nil {
		return nil, nil, err
	}

	// Check that the specified storage device is a template
	storageDetails, err := service.GetStorageDetails(&request.GetStorageDetailsRequest{
		UUID: b.config.StorageUUID,
	})
	if err != nil {
		return nil, nil, err
	}

	if storageDetails.Type != upcloud.StorageTypeTemplate {
		return nil, nil, fmt.Errorf("The specified storage UUID is of invalid type \"%s\"", storageDetails.Type)
	}

	return nil, nil, nil
}

// Run executes the actual build steps
func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) {
	// Create the service
	service := b.config.GetService()

	// Set up the state which is used to share state between the steps
	state := new(multistep.BasicStateBag)
	state.Put("config", *b.config)
	state.Put("service", *service)
	state.Put("hook", hook)
	state.Put("ui", ui)

	// Build the steps
	steps := []multistep.Step{
		&StepCreateSSHKey{
			Debug:        b.config.PackerDebug,
			DebugKeyPath: fmt.Sprintf("packer-builder-upcloud-%s.pem", b.config.PackerBuildName),
		},
		new(StepCreateServer),
		&communicator.StepConnect{
			Config:    &b.config.Comm,
			Host:      sshHostCallback,
			SSHConfig: sshConfigCallback,
		},
		new(common.StepProvision),
		new(StepTemplatizeStorage),
	}

	// Create the runner which will run the steps we just build
	b.runner = &multistep.BasicRunner{Steps: steps}
	b.runner.Run(ctx, state)

	if rawErr, ok := state.GetOk("error"); ok {
		return nil, rawErr.(error)
	}

	// Extract the final storage details from the state
	rawDetails, ok := state.GetOk("storage_details")

	if !ok {
		log.Println("No storage details found in state, the build was probably cancelled")
		return nil, nil
	}

	storageDetails := rawDetails.(*upcloud.StorageDetails)

	// Create an artifact and return it
	artifact := &Artifact{
		UUID:    storageDetails.UUID,
		Zone:    storageDetails.Zone,
		Title:   storageDetails.Title,
		service: service,
	}

	return artifact, nil
}
<commit_msg>Refactored<commit_after>package upcloud

import (
	"context"
	"fmt"
	"github.com/UpCloudLtd/upcloud-go-api/upcloud"
	"github.com/UpCloudLtd/upcloud-go-api/upcloud/request"
	"github.com/hashicorp/hcl/v2/hcldec"
	"github.com/hashicorp/packer/common"
	"github.com/hashicorp/packer/helper/communicator"
	"github.com/hashicorp/packer/helper/multistep"
	"github.com/hashicorp/packer/packer"
	"log"
)

// The unique ID for this builder.
const BuilderId = "upcloudltd.upcloud"

// Builder represents a Packer Builder.
type Builder struct {
	config *Config
}

func (b *Builder) ConfigSpec() hcldec.ObjectSpec {
	return b.config.FlatMapstructure().HCL2Spec()
}

// Prepare processes the build configuration parameters and validates the configuration
func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) {
	var err error
	// Parse and create the configuration
	b.config, err = NewConfig(raws...)

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

	// Check that the client/service is usable
	service := b.config.GetService()

	if _, err := service.GetAccount(); err != nil {
		return nil, nil, err
	}

	// Check that the specified storage device is a template
	storageDetails, err := service.GetStorageDetails(&request.GetStorageDetailsRequest{
		UUID: b.config.StorageUUID,
	})
	if err != nil {
		return nil, nil, err
	}

	if storageDetails.Type != upcloud.StorageTypeTemplate {
		return nil, nil, fmt.Errorf("The specified storage UUID is of invalid type \"%s\"", storageDetails.Type)
	}

	return nil, nil, nil
}

// Run executes the actual build steps
func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) {
	// Create the service
	service := b.config.GetService()

	// Set up the state which is used to share state between the steps
	state := new(multistep.BasicStateBag)
	state.Put("config", *b.config)
	state.Put("service", *service)
	state.Put("hook", hook)
	state.Put("ui", ui)

	// Build the steps
	steps := []multistep.Step{
		&StepCreateSSHKey{
			Debug:        b.config.PackerDebug,
			DebugKeyPath: fmt.Sprintf("packer-builder-upcloud-%s.pem", b.config.PackerBuildName),
		},
		new(StepCreateServer),
		&communicator.StepConnect{
			Config:    &b.config.Comm,
			Host:      sshHostCallback,
			SSHConfig: sshConfigCallback,
		},
		new(common.StepProvision),
		new(StepTemplatizeStorage),
	}

	// Create the runner which will run the steps we just build
	runner := &multistep.BasicRunner{Steps: steps}
	runner.Run(ctx, state)

	if rawErr, ok := state.GetOk("error"); ok {
		return nil, rawErr.(error)
	}

	// Extract the final storage details from the state
	rawDetails, ok := state.GetOk("storage_details")

	if !ok {
		log.Println("No storage details found in state, the build was probably cancelled")
		return nil, nil
	}

	storageDetails := rawDetails.(*upcloud.StorageDetails)

	// Create an artifact and return it
	artifact := &Artifact{
		UUID:    storageDetails.UUID,
		Zone:    storageDetails.Zone,
		Title:   storageDetails.Title,
		service: service,
	}

	return artifact, nil
}
<|endoftext|>


<commit_before>package backend

import "imperial-splendour-bundler/backend/customErrors"

const (
	deactivatorUrl = "https://github.com/SophieAu/imperial-splendour-launcher/raw/master/artifacts/deactivator.exe"
	launcherUrl    = "https://github.com/SophieAu/imperial-splendour-launcher/raw/master/artifacts/ImperialSplendour.exe"
	setupUrl       = "https://github.com/SophieAu/imperial-splendour-launcher/raw/master/setup/setupBundled.iss"
	appiconUrl     = "https://github.com/SophieAu/imperial-splendour-launcher/raw/master/setup/appicon.ico"
)

func (a *API) downloadFiles() error {
	appiconTarget := a.setupBaseFolder + appicon
	setupTarget := a.setupBaseFolder + setupFile
	launcherTarget := a.setupBaseFolder + tempPath + launcherFile
	deactivatorTarget := a.setupBaseFolder + tempPath + uninstallPath + deactivatorFile

	if err := a.Sh.DownloadFile(appiconUrl, appiconTarget); err != nil {
		return a.error("Cannot download Appicon", customErrors.Download)
	}
	a.logToFrontend("App icon was downloaded")
	if err := a.Sh.DownloadFile(setupUrl, setupTarget); err != nil {
		return a.error("Cannot download setup script", customErrors.Download)
	}
	a.logToFrontend("Setup script was downloaded")
	if err := a.Sh.DownloadFile(launcherUrl, launcherTarget); err != nil {
		return a.error("Cannot download launcher", customErrors.Download)
	}
	a.logToFrontend("Launcher was downloaded")
	if err := a.Sh.DownloadFile(deactivatorUrl, deactivatorTarget); err != nil {
		return a.error("Cannot download deactivator", customErrors.Download)
	}
	a.logToFrontend("Deactivator was downloaded")
	return nil
}
<commit_msg>Fix file download paths<commit_after>package backend

import "imperial-splendour-bundler/backend/customErrors"

const (
	deactivatorUrl = "https://raw.githubusercontent.com/SophieAu/imperial-splendour-launcher/raw/master/artifacts/deactivator.exe"
	launcherUrl    = "https://raw.githubusercontent.com/SophieAu/imperial-splendour-launcher/raw/master/artifacts/ImperialSplendour.exe"
	setupUrl       = "https://raw.githubusercontent.com/SophieAu/imperial-splendour-launcher/raw/master/setup/setupBundled.iss"
	appiconUrl     = "https://raw.githubusercontent.com/SophieAu/imperial-splendour-launcher/raw/master/setup/appicon.ico"
)

func (a *API) downloadFiles() error {
	appiconTarget := a.setupBaseFolder + appicon
	setupTarget := a.setupBaseFolder + setupFile
	launcherTarget := a.setupBaseFolder + tempPath + launcherFile
	deactivatorTarget := a.setupBaseFolder + tempPath + uninstallPath + deactivatorFile

	if err := a.Sh.DownloadFile(appiconUrl, appiconTarget); err != nil {
		return a.error("Cannot download Appicon", customErrors.Download)
	}
	a.logToFrontend("App icon was downloaded")
	if err := a.Sh.DownloadFile(setupUrl, setupTarget); err != nil {
		return a.error("Cannot download setup script", customErrors.Download)
	}
	a.logToFrontend("Setup script was downloaded")
	if err := a.Sh.DownloadFile(launcherUrl, launcherTarget); err != nil {
		return a.error("Cannot download launcher", customErrors.Download)
	}
	a.logToFrontend("Launcher was downloaded")
	if err := a.Sh.DownloadFile(deactivatorUrl, deactivatorTarget); err != nil {
		return a.error("Cannot download deactivator", customErrors.Download)
	}
	a.logToFrontend("Deactivator was downloaded")
	return nil
}
<|endoftext|>


<commit_before>package model

import (
	"fmt"

	"strings"

	"github.com/evandroflores/claimr/database"
	"github.com/jinzhu/gorm"
)

func init() {
	database.DB.AutoMigrate(&Container{})
}

// Container defines the Container information on database.
type Container struct {
	gorm.Model
	TeamID         string `gorm:"not null"`
	ChannelID      string `gorm:"not null"`
	Name           string `gorm:"not null"`
	InUseBy        string
	InUseForReason string
	CreatedByUser  string
}

// MaxNameSize is the max number of characters for a container name.
const MaxNameSize = 22

func isValidContainerInput(teamID string, channelID string, containerName string) (bool, error) {
	fields := map[string]string{"teamID": teamID, "channelID": channelID, "container name": containerName}

	for fieldName, fieldValue := range fields {
		err := checkRequired(fieldName, fieldValue)
		if err != nil {
			return false, err
		}
	}

	if len(containerName) > MaxNameSize {
		return false, fmt.Errorf("try a smaller container name up to %d characters", MaxNameSize)
	}

	return true, nil
}

func checkRequired(fieldName string, fieldValue string) error {
	if fieldValue == "" {
		return fmt.Errorf("can not continue without a %s 🙄", fieldName)
	}
	return nil
}

// GetContainer returns a container for teamID, channelID, and name provided
func GetContainer(teamID string, channelID string, name string) (Container, error) {
	result := Container{}
	valid, err := isValidContainerInput(teamID, channelID, name)

	if !valid {
		return result, err
	}

	database.DB.Where(&Container{TeamID: teamID, ChannelID: channelID, Name: strings.ToLower(name)}).
		First(&result)

	return result, nil
}

// GetContainers returns a list of containers for the given TeamID and ChannelID
func GetContainers(teamID string, channelID string) ([]Container, error) {
	results := []Container{}
	valid, err := isValidContainerInput(teamID, channelID, ".")

	if !valid {
		return results, err
	}

	database.DB.Where(&Container{TeamID: teamID, ChannelID: channelID}).
		Find(&results)

	return results, nil
}

// Add a given Container to database
func (container Container) Add() error {
	existingContainer, err := GetContainer(container.TeamID, container.ChannelID, container.Name)

	if err != nil {
		return err
	}

	if existingContainer != (Container{}) {
		return fmt.Errorf("there is a container with the same name on this channel. Try a different one 😕")
	}
	container.Name = strings.ToLower(container.Name)
	database.DB.Create(&container)

	return nil
}

// Update a given Container
func (container Container) Update() error {
	existingContainer, err := GetContainer(container.TeamID, container.ChannelID, strings.ToLower(container.Name))

	if err != nil {
		return err
	}

	if existingContainer == (Container{}) {
		return fmt.Errorf("could not find this container on this channel. Can not update 😕")
	}

	existingContainer.InUseBy = container.InUseBy
	existingContainer.InUseForReason = container.InUseForReason

	database.DB.Save(&existingContainer)

	return nil
}

// Delete removes a Container from the database
func (container Container) Delete() error {
	existingContainer, err := GetContainer(container.TeamID, container.ChannelID, strings.ToLower(container.Name))

	if err != nil {
		return err
	}
	if existingContainer == (Container{}) {
		return fmt.Errorf("could not find this container on this channel. Can not delete 😕")
	}

	database.DB.Delete(&existingContainer)

	return nil
}
<commit_msg>Changing map for a different approach to preserve the order<commit_after>package model

import (
	"fmt"

	"strings"

	"github.com/evandroflores/claimr/database"
	"github.com/jinzhu/gorm"
)

func init() {
	database.DB.AutoMigrate(&Container{})
}

// Container defines the Container information on database.
type Container struct {
	gorm.Model
	TeamID         string `gorm:"not null"`
	ChannelID      string `gorm:"not null"`
	Name           string `gorm:"not null"`
	InUseBy        string
	InUseForReason string
	CreatedByUser  string
}

// MaxNameSize is the max number of characters for a container name.
const MaxNameSize = 22

func isValidContainerInput(teamID string, channelID string, containerName string) (bool, error) {
	fields := []struct {
		name  string
		value string
	}{
		{"teamID", teamID},
		{"channelID", channelID},
		{"container name", containerName},
	}

	for _, field := range fields {
		err := checkRequired(field.name, field.value)
		if err != nil {
			return false, err
		}
	}

	if len(containerName) > MaxNameSize {
		return false, fmt.Errorf("try a smaller container name up to %d characters", MaxNameSize)
	}

	return true, nil
}

func checkRequired(fieldName string, fieldValue string) error {
	if fieldValue == "" {
		return fmt.Errorf("can not continue without a %s 🙄", fieldName)
	}
	return nil
}

// GetContainer returns a container for teamID, channelID, and name provided
func GetContainer(teamID string, channelID string, name string) (Container, error) {
	result := Container{}
	valid, err := isValidContainerInput(teamID, channelID, name)

	if !valid {
		return result, err
	}

	database.DB.Where(&Container{TeamID: teamID, ChannelID: channelID, Name: strings.ToLower(name)}).
		First(&result)

	return result, nil
}

// GetContainers returns a list of containers for the given TeamID and ChannelID
func GetContainers(teamID string, channelID string) ([]Container, error) {
	results := []Container{}
	valid, err := isValidContainerInput(teamID, channelID, ".")

	if !valid {
		return results, err
	}

	database.DB.Where(&Container{TeamID: teamID, ChannelID: channelID}).
		Find(&results)

	return results, nil
}

// Add a given Container to database
func (container Container) Add() error {
	existingContainer, err := GetContainer(container.TeamID, container.ChannelID, container.Name)

	if err != nil {
		return err
	}

	if existingContainer != (Container{}) {
		return fmt.Errorf("there is a container with the same name on this channel. Try a different one 😕")
	}
	container.Name = strings.ToLower(container.Name)
	database.DB.Create(&container)

	return nil
}

// Update a given Container
func (container Container) Update() error {
	existingContainer, err := GetContainer(container.TeamID, container.ChannelID, strings.ToLower(container.Name))

	if err != nil {
		return err
	}

	if existingContainer == (Container{}) {
		return fmt.Errorf("could not find this container on this channel. Can not update 😕")
	}

	existingContainer.InUseBy = container.InUseBy
	existingContainer.InUseForReason = container.InUseForReason

	database.DB.Save(&existingContainer)

	return nil
}

// Delete removes a Container from the database
func (container Container) Delete() error {
	existingContainer, err := GetContainer(container.TeamID, container.ChannelID, strings.ToLower(container.Name))

	if err != nil {
		return err
	}
	if existingContainer == (Container{}) {
		return fmt.Errorf("could not find this container on this channel. Can not delete 😕")
	}

	database.DB.Delete(&existingContainer)

	return nil
}
<|endoftext|>


<commit_before>package model

import (
	"encoding/json"
	"fmt"
	"net/http"
)

//go:generate counterfeiter -o ../fakes/fake_storage_client.go . StorageClient
type StorageClient interface {
	Activate() error
	CreateVolume(name string, opts map[string]interface{}) error
	RemoveVolume(name string, forceDelete bool) error
	ListVolumes() ([]VolumeMetadata, error)
	GetVolume(name string) (volumeMetadata VolumeMetadata, volumeConfigDetails SpectrumConfig, err error)
	Attach(name string) (string, error)
	Detach(name string) error
	GetPluginName() string
}

type CreateRequest struct {
	Name string
	Opts map[string]interface{}
}

type RemoveRequest struct {
	Name        string
	ForceDelete bool
}

type AttachRequest struct {
	Name string
}

type DetachRequest struct {
	Name string
}

type ActivateResponse struct {
	Implements []string
}

func (r *ActivateResponse) WriteResponse(w http.ResponseWriter) {
	data, err := json.Marshal(r)
	if err != nil {
		fmt.Errorf("Error marshalling response: %s", err.Error())
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, string(data))
}

type GenericResponse struct {
	Err string
}

func (r *GenericResponse) WriteResponse(w http.ResponseWriter) {
	if r.Err != "" {
		w.WriteHeader(http.StatusBadRequest)
	}
	data, err := json.Marshal(r)
	if err != nil {
		fmt.Errorf("Error marshalling response: %s", err.Error())
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, string(data))
}

type GenericRequest struct {
	Name string
}

type MountResponse struct {
	Mountpoint string
	Err        string
}

func (r *MountResponse) WriteResponse(w http.ResponseWriter) {
	if r.Err != "" {
		w.WriteHeader(http.StatusBadRequest)
	}
	data, err := json.Marshal(r)
	if err != nil {
		fmt.Errorf("Error marshalling Get response: %s", err.Error())
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, string(data))
}

type VolumeMetadata struct {
	Name       string
	Mountpoint string
}

type SpectrumConfig struct {
	FilesetId  string `json:"fileset"`
	Filesystem string `json:"filesystem"`
}
type GetResponse struct {
	Volume VolumeMetadata
	Err    string
	Config SpectrumConfig
}

func (r *GetResponse) WriteResponse(w http.ResponseWriter) {
	if r.Err != "" {
		w.WriteHeader(http.StatusBadRequest)
	}
	data, err := json.Marshal(r)
	if err != nil {
		fmt.Errorf("Error marshalling Get response: %s", err.Error())
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, string(data))
}

type ListResponse struct {
	Volumes []VolumeMetadata
	Err     string
}

func (r *ListResponse) WriteResponse(w http.ResponseWriter) {
	if r.Err != "" {
		w.WriteHeader(http.StatusBadRequest)
	}
	data, err := json.Marshal(r)
	if err != nil {
		fmt.Errorf("Error marshalling Get response: %s", err.Error())
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, string(data))
}

type FlexVolumeResponse struct {
	Status  string `json:"status"`
	Message string `json:"message"`
	Device  string `json:"device"`
}

type FlexVolumeMountRequest struct {
	MountPath   string                 `json:"mountPath"`
	MountDevice string                 `json:"name"`
	Opts        map[string]interface{} `json:"opts"`
}

type FlexVolumeAttachRequest struct {
	VolumeId   string `json:"volumeID"`
	Filesystem string `json:"filesystem"`
	Size       string `json:"size"`
	Path       string `json:"path"`
	Fileset    string `json:"fileset"`
}

type FlexVolumeUnmountRequest struct {
	MountPath string `json:"mountPath"`
}

type FlexVolumeDetachRequest struct {
	MountPath string `json:"mountPath"`
}
<commit_msg>modified flex detach request<commit_after>package model

import (
	"encoding/json"
	"fmt"
	"net/http"
)

//go:generate counterfeiter -o ../fakes/fake_storage_client.go . StorageClient
type StorageClient interface {
	Activate() error
	CreateVolume(name string, opts map[string]interface{}) error
	RemoveVolume(name string, forceDelete bool) error
	ListVolumes() ([]VolumeMetadata, error)
	GetVolume(name string) (volumeMetadata VolumeMetadata, volumeConfigDetails SpectrumConfig, err error)
	Attach(name string) (string, error)
	Detach(name string) error
	GetPluginName() string
}

type CreateRequest struct {
	Name string
	Opts map[string]interface{}
}

type RemoveRequest struct {
	Name        string
	ForceDelete bool
}

type AttachRequest struct {
	Name string
}

type DetachRequest struct {
	Name string
}

type ActivateResponse struct {
	Implements []string
}

func (r *ActivateResponse) WriteResponse(w http.ResponseWriter) {
	data, err := json.Marshal(r)
	if err != nil {
		fmt.Errorf("Error marshalling response: %s", err.Error())
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, string(data))
}

type GenericResponse struct {
	Err string
}

func (r *GenericResponse) WriteResponse(w http.ResponseWriter) {
	if r.Err != "" {
		w.WriteHeader(http.StatusBadRequest)
	}
	data, err := json.Marshal(r)
	if err != nil {
		fmt.Errorf("Error marshalling response: %s", err.Error())
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, string(data))
}

type GenericRequest struct {
	Name string
}

type MountResponse struct {
	Mountpoint string
	Err        string
}

func (r *MountResponse) WriteResponse(w http.ResponseWriter) {
	if r.Err != "" {
		w.WriteHeader(http.StatusBadRequest)
	}
	data, err := json.Marshal(r)
	if err != nil {
		fmt.Errorf("Error marshalling Get response: %s", err.Error())
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, string(data))
}

type VolumeMetadata struct {
	Name       string
	Mountpoint string
}

type SpectrumConfig struct {
	FilesetId  string `json:"fileset"`
	Filesystem string `json:"filesystem"`
}
type GetResponse struct {
	Volume VolumeMetadata
	Err    string
	Config SpectrumConfig
}

func (r *GetResponse) WriteResponse(w http.ResponseWriter) {
	if r.Err != "" {
		w.WriteHeader(http.StatusBadRequest)
	}
	data, err := json.Marshal(r)
	if err != nil {
		fmt.Errorf("Error marshalling Get response: %s", err.Error())
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, string(data))
}

type ListResponse struct {
	Volumes []VolumeMetadata
	Err     string
}

func (r *ListResponse) WriteResponse(w http.ResponseWriter) {
	if r.Err != "" {
		w.WriteHeader(http.StatusBadRequest)
	}
	data, err := json.Marshal(r)
	if err != nil {
		fmt.Errorf("Error marshalling Get response: %s", err.Error())
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, string(data))
}

type FlexVolumeResponse struct {
	Status  string `json:"status"`
	Message string `json:"message"`
	Device  string `json:"device"`
}

type FlexVolumeMountRequest struct {
	MountPath   string                 `json:"mountPath"`
	MountDevice string                 `json:"name"`
	Opts        map[string]interface{} `json:"opts"`
}

type FlexVolumeAttachRequest struct {
	VolumeId   string `json:"volumeID"`
	Filesystem string `json:"filesystem"`
	Size       string `json:"size"`
	Path       string `json:"path"`
	Fileset    string `json:"fileset"`
}

type FlexVolumeUnmountRequest struct {
	MountPath string `json:"mountPath"`
}

type FlexVolumeDetachRequest struct {
Name string `json:"name"`
}
<|endoftext|>


<commit_before>package models

import (
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
	"github.com/mcuadros/go-version"
	"gonder/bindata"
	"strings"
)

func ConnectDb() error {
	var err error
	Db, err = sqlx.Open("mysql", Config.dbString)
	if err != nil {
		return fmt.Errorf("open database error: %s", err)
	}
	err = Db.Ping()
	if err != nil {
		return fmt.Errorf("ping database error: %s", err)
	}
	Db.SetMaxIdleConns(Config.dbConnections)
	Db.SetMaxOpenConns(Config.dbConnections)
	return nil
}

func CheckDb() error {
	if _, err := Db.Exec("SELECT 1 FROM `auth_user`"); err != nil {
		return fmt.Errorf("database is empty, use -i key for create from a template")
	}
	// with version 0.16.0 there was a table of versions
	_, err := Db.Exec("SELECT 1 FROM `version`")
	if err != nil {
		err = dbQueryFrom("sql/update/0.16.0.sql")
		if err != nil {
			return err
		}
	}
	row := Db.QueryRow("SELECT `number` FROM `version` ORDER BY `at` DESC LIMIT 1 ")
	var dbVersion string
	err = row.Scan(&dbVersion)
	if err != nil {
		return fmt.Errorf("get database version: %s", err)
	}

	// in the future, here, if necessary, will check the version of the application and the database
	if version.Compare(Version, dbVersion, ">") {
		if err = dbQueryFrom("sql/update/0.16.3.sql"); err != nil {
			return fmt.Errorf("update database to version %s: %s", Version, err)
		}
	}

	// update the version in the database when it changes
	if version.Compare(Version, dbVersion, ">") {
		if _, err := Db.Exec("INSERT INTO `version` (`number`) VALUES (?)", Version); err != nil {
			return fmt.Errorf("insert new version to database: %s", err)
		}
	}

	return nil
}

// InitDb initialize database
func InitDb(withoutConfirm bool) error {
	if !withoutConfirm {
		var confirm string
		fmt.Print("Initial database (y/N)? ")
		if _, err := fmt.Scanln(&confirm); err != nil {
			return err
		}
		if strings.ToLower(confirm) != "y" {
			return nil
		}
	}

	return dbQueryFrom("sql/dump.sql")
}

func dbQueryFrom(filename string) error {
	sqlDump, err := bindata.ReadFileOrAsset(filename)
	if err != nil {
		return err
	}
	query := strings.Split(string(sqlDump), ";")
	tx, err := Db.Begin()
	if err != nil {
		return err
	}
	defer func() {
		_ = tx.Rollback()
	}()
	for i := range query {
		if strings.TrimSpace(query[i]) == "" {
			continue
		}
		_, err = tx.Exec(query[i])
		if err != nil {
			return err
		}
	}
	if err = tx.Commit(); err != nil {
		return err
	}
	return nil
}
<commit_msg>right check version<commit_after>package models

import (
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
	"github.com/mcuadros/go-version"
	"gonder/bindata"
	"strings"
)

func ConnectDb() error {
	var err error
	Db, err = sqlx.Open("mysql", Config.dbString)
	if err != nil {
		return fmt.Errorf("open database error: %s", err)
	}
	err = Db.Ping()
	if err != nil {
		return fmt.Errorf("ping database error: %s", err)
	}
	Db.SetMaxIdleConns(Config.dbConnections)
	Db.SetMaxOpenConns(Config.dbConnections)
	return nil
}

func CheckDb() error {
	if _, err := Db.Exec("SELECT 1 FROM `auth_user`"); err != nil {
		return fmt.Errorf("database is empty, use -i key for create from a template")
	}
	// with version 0.16.0 there was a table of versions
	_, err := Db.Exec("SELECT 1 FROM `version`")
	if err != nil {
		err = dbQueryFrom("sql/update/0.16.0.sql")
		if err != nil {
			return err
		}
	}
	row := Db.QueryRow("SELECT `number` FROM `version` ORDER BY `at` DESC LIMIT 1 ")
	var dbVersion string
	err = row.Scan(&dbVersion)
	if err != nil {
		return fmt.Errorf("get database version: %s", err)
	}

	// in the future, here, if necessary, will check the version of the application and the database
	if version.Compare(Version, dbVersion, "<") {
		if err = dbQueryFrom("sql/update/0.16.3.sql"); err != nil {
			return fmt.Errorf("update database to version %s: %s", Version, err)
		}
	}

	// update the version in the database when it changes
	if version.Compare(Version, dbVersion, ">") {
		if _, err := Db.Exec("INSERT INTO `version` (`number`) VALUES (?)", Version); err != nil {
			return fmt.Errorf("insert new version to database: %s", err)
		}
	}

	return nil
}

// InitDb initialize database
func InitDb(withoutConfirm bool) error {
	if !withoutConfirm {
		var confirm string
		fmt.Print("Initial database (y/N)? ")
		if _, err := fmt.Scanln(&confirm); err != nil {
			return err
		}
		if strings.ToLower(confirm) != "y" {
			return nil
		}
	}

	return dbQueryFrom("sql/dump.sql")
}

func dbQueryFrom(filename string) error {
	sqlDump, err := bindata.ReadFileOrAsset(filename)
	if err != nil {
		return err
	}
	query := strings.Split(string(sqlDump), ";")
	tx, err := Db.Begin()
	if err != nil {
		return err
	}
	defer func() {
		_ = tx.Rollback()
	}()
	for i := range query {
		if strings.TrimSpace(query[i]) == "" {
			continue
		}
		_, err = tx.Exec(query[i])
		if err != nil {
			return err
		}
	}
	if err = tx.Commit(); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package util

import (
	"errors"
	"fmt"
	"os"
	"path"
	"runtime"
)

// Name is the name of the CLI
var Name = "rack"

// UserAgent is the user-agent used for each HTTP request
var UserAgent = fmt.Sprintf("%s-%s/%s", "rackcli", runtime.GOOS, Version)

// Usage return a string that specifies how to call a particular command.
func Usage(commandPrefix, action, mandatoryFlags string) string {
	return fmt.Sprintf("%s %s %s %s [OPTIONS]", Name, commandPrefix, action, mandatoryFlags)
}

// RemoveFromList removes an element from a slice and returns the slice.
func RemoveFromList(list []string, item string) []string {
	for i, element := range list {
		if element == item {
			list = append(list[:i], list[i+1:]...)
			break
		}
	}
	return list
}

// Contains checks whether a given string is in a provided slice of strings.
func Contains(s []string, e string) bool {
	for _, a := range s {
		if a == e {
			return true
		}
	}
	return false
}

// RackDir returns the location of the `rack` directory. This directory is for
// storing `rack`-specific information such as the cache or a config file.
func RackDir() (string, error) {
	homeDir, err := HomeDir()
	if err != nil {
		return "", err
	}
	dirpath := path.Join(homeDir, ".rack")
	err = os.MkdirAll(dirpath, 0744)
	return dirpath, err
}

// HomeDir returns the user's home directory, which is platform-dependent.
func HomeDir() (string, error) {
	var homeDir string
	if runtime.GOOS == "windows" {
		homeDir = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH") // Windows
		if homeDir == "" {
			homeDir = os.Getenv("USERPROFILE") // Windows
		}
	} else {
		homeDir = os.Getenv("HOME") // *nix
	}
	if homeDir == "" {
		return "", errors.New("User home directory not found.")
	}
	return homeDir, nil
}

// Pluralize will plurarize a given noun according to its number. For example,
// 0 servers were deleted; 1 account updated.
func Pluralize(noun string, count int64) string {
	if count != 1 {
		noun += "s"
	}
	return noun
}

// Version is the current CLI version
var Version = "0.0.0-dev"
<commit_msg>Removing -dev from version in master<commit_after>package util

import (
	"errors"
	"fmt"
	"os"
	"path"
	"runtime"
)

// Name is the name of the CLI
var Name = "rack"

// UserAgent is the user-agent used for each HTTP request
var UserAgent = fmt.Sprintf("%s-%s/%s", "rackcli", runtime.GOOS, Version)

// Usage return a string that specifies how to call a particular command.
func Usage(commandPrefix, action, mandatoryFlags string) string {
	return fmt.Sprintf("%s %s %s %s [OPTIONS]", Name, commandPrefix, action, mandatoryFlags)
}

// RemoveFromList removes an element from a slice and returns the slice.
func RemoveFromList(list []string, item string) []string {
	for i, element := range list {
		if element == item {
			list = append(list[:i], list[i+1:]...)
			break
		}
	}
	return list
}

// Contains checks whether a given string is in a provided slice of strings.
func Contains(s []string, e string) bool {
	for _, a := range s {
		if a == e {
			return true
		}
	}
	return false
}

// RackDir returns the location of the `rack` directory. This directory is for
// storing `rack`-specific information such as the cache or a config file.
func RackDir() (string, error) {
	homeDir, err := HomeDir()
	if err != nil {
		return "", err
	}
	dirpath := path.Join(homeDir, ".rack")
	err = os.MkdirAll(dirpath, 0744)
	return dirpath, err
}

// HomeDir returns the user's home directory, which is platform-dependent.
func HomeDir() (string, error) {
	var homeDir string
	if runtime.GOOS == "windows" {
		homeDir = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH") // Windows
		if homeDir == "" {
			homeDir = os.Getenv("USERPROFILE") // Windows
		}
	} else {
		homeDir = os.Getenv("HOME") // *nix
	}
	if homeDir == "" {
		return "", errors.New("User home directory not found.")
	}
	return homeDir, nil
}

// Pluralize will plurarize a given noun according to its number. For example,
// 0 servers were deleted; 1 account updated.
func Pluralize(noun string, count int64) string {
	if count != 1 {
		noun += "s"
	}
	return noun
}

// Version is the current CLI version
var Version = "0.0.0"
<|endoftext|>


<commit_before>package util

import (
	"fmt"
	"os"
	"io"
	"reflect"
	"testing"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"net/http"
)

// Contents reads a file into a string
func Contents(filepath string) (string, error) {
	f, err := os.Open(filepath)
	if err != nil {
		return "", err
	}
	defer f.Close()  // f.Close will run when we're finished.

	var result []byte
	buf := make([]byte, 100)
	for {
		n, err := f.Read(buf[0:])
		result = Append(result, buf[0:n])
		if err != nil {
			if err == io.EOF {
				break
			}
			return "", err  // f will be closed if we return here.
		}
	}
	return string(result), nil // f will be closed if we return here.
}

// Append bytes to a slice
func Append(slice, data[]byte) []byte {
	l := len(slice)
	if l + len(data) > cap(slice) {  // reallocate
		// Allocate double what's needed, for future growth.
		newSlice := make([]byte, (l+len(data))*2)
		// The copy function is predeclared and works for any slice type.
		copy(newSlice, slice)
		slice = newSlice
	}
	slice = slice[0:l+len(data)]
	for i, c := range data {
		slice[l+i] = c
	}
	return slice
}

// Generates an HMAC using SHA256
func GenerateMAC(message, key []byte) []byte {
	mac := hmac.New(sha256.New, key)
	mac.Write(message)
	ret := make([]byte, 64)
	hex.Encode(ret, mac.Sum(nil))
	return ret
}

// CheckMAC returns true if messageMAC is a valid HMAC tag for message. Uses SHA256.
func CheckMAC(message, messageMAC, key []byte) bool {
	expectedMAC := GenerateMAC(message, key)

	// careful! use hmac.Equal to be safe against timing side channel attacks
	return hmac.Equal(messageMAC, expectedMAC)
}

// given an http reponse object and a sql result, returns in json the id of
// the new object inside the result
func WriteIdJson(w http.ResponseWriter, id int) (err error) {
	json_id, err := json.Marshal(map[string]interface{}{"id": id})
	if err != nil {
		return
	}
	w.WriteHeader(http.StatusAccepted)
	w.Header().Set("Content-Type", "application/json")
	if l, err := w.Write(json_id); err != nil {
		panic(err)
	}
	return
}

/* Test Helpers */
func Expect(t *testing.T, a interface{}, b interface{}) {
	if a != b {
		t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
	}
}

func Refute(t *testing.T, a interface{}, b interface{}) {
	if a == b {
		t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
	}
}

type Marhsaller interface {
	Marshal() ([]byte, error)
}

func JsonMarshalOne(w http.ResponseWriter, m Marhsaller) {
	var (
		data []byte
		err error
	)

	w.Header().Set("Content-Type", "content/json")
	if data, err = m.Marshal(); err != nil {
		panic(err)
	}
	w.WriteHeader(http.StatusOK)
	w.Write(data)
}
<commit_msg>remove unneeded error checking<commit_after>package util

import (
	"os"
	"io"
	"reflect"
	"testing"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"net/http"
)

// Contents reads a file into a string
func Contents(filepath string) (string, error) {
	f, err := os.Open(filepath)
	if err != nil {
		return "", err
	}
	defer f.Close()  // f.Close will run when we're finished.

	var result []byte
	buf := make([]byte, 100)
	for {
		n, err := f.Read(buf[0:])
		result = Append(result, buf[0:n])
		if err != nil {
			if err == io.EOF {
				break
			}
			return "", err  // f will be closed if we return here.
		}
	}
	return string(result), nil // f will be closed if we return here.
}

// Append bytes to a slice
func Append(slice, data[]byte) []byte {
	l := len(slice)
	if l + len(data) > cap(slice) {  // reallocate
		// Allocate double what's needed, for future growth.
		newSlice := make([]byte, (l+len(data))*2)
		// The copy function is predeclared and works for any slice type.
		copy(newSlice, slice)
		slice = newSlice
	}
	slice = slice[0:l+len(data)]
	for i, c := range data {
		slice[l+i] = c
	}
	return slice
}

// Generates an HMAC using SHA256
func GenerateMAC(message, key []byte) []byte {
	mac := hmac.New(sha256.New, key)
	mac.Write(message)
	ret := make([]byte, 64)
	hex.Encode(ret, mac.Sum(nil))
	return ret
}

// CheckMAC returns true if messageMAC is a valid HMAC tag for message. Uses SHA256.
func CheckMAC(message, messageMAC, key []byte) bool {
	expectedMAC := GenerateMAC(message, key)

	// careful! use hmac.Equal to be safe against timing side channel attacks
	return hmac.Equal(messageMAC, expectedMAC)
}

// given an http reponse object and a sql result, returns in json the id of
// the new object inside the result
func WriteIdJson(w http.ResponseWriter, id int) (err error) {
	json_id, err := json.Marshal(map[string]interface{}{"id": id})
	if err != nil {
		return
	}
	w.WriteHeader(http.StatusAccepted)
	w.Header().Set("Content-Type", "application/json")
	w.Write(json_id)
	return
}

/* Test Helpers */
func Expect(t *testing.T, a interface{}, b interface{}) {
	if a != b {
		t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
	}
}

func Refute(t *testing.T, a interface{}, b interface{}) {
	if a == b {
		t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
	}
}

type Marhsaller interface {
	Marshal() ([]byte, error)
}

func JsonMarshalOne(w http.ResponseWriter, m Marhsaller) {
	var (
		data []byte
		err error
	)

	w.Header().Set("Content-Type", "content/json")
	if data, err = m.Marshal(); err != nil {
		panic(err)
	}
	w.WriteHeader(http.StatusOK)
	w.Write(data)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"time"
)

//!+main
type Track struct {
	Title  string
	Artist string
	Album  string
	Year   int
	Length time.Duration
}

var tracks = []*Track{
	{"Go", "Delilah", "From the Roots Up", 2012, length("3m38s")},
	{"Go", "Moby", "Moby", 1992, length("3m37s")},
	{"Go Ahead", "Alicia Keys", "As I Am", 2007, length("4m36s")},
	{"Ready 2 Go", "Martin Solveig", "Smash", 2011, length("4m24s")},
}

var headings = []string{
	"Title",
	"Artist",
	"Album",
	"Year",
	"Length",
}

func length(s string) time.Duration {
	d, err := time.ParseDuration(s)
	if err != nil {
		panic(s)
	}
	return d
}

func main() {

	scanner := bufio.NewScanner(os.Stdin)

	fmt.Printf("Table Headings\n")

	list(headings)

	fmt.Println()

	fmt.Print("Select a Heading:")
	scanner.Scan()

	if i, err := strconv.Atoi(scanner.Text()); err == nil {

		i -= 1
		if i < len(headings) {

			fmt.Printf("You selected: %v\n", headings[i])

			if contains(headings, headings[i]) {
				fmt.Println("You made a valid choice.")
				headings = sortHeadings(headings, headings[i])
			}
		}
		fmt.Println("Invalid choice")
	}

}

func contains(strSlice []string, search string) bool {
	for _, value := range strSlice {
		if value == search {
			return true
		}
	}
	return false
}

// sortHeading takes a slice of strings and one element from that slice
// It re-orders the slice, placing the selection in the first position
func sortHeadings(headings []string, selection string) []string {

	fmt.Println("Selection:", selection)

	if selection == headings[0] {
		fmt.Println("Order is correct")
		return headings
	}
	// Reorder slice

	return headings
}

func list(headings []string) {
	for index := 0; index < len(headings); index++ {
		fmt.Printf("%d. %s\n", index+1, headings[index])
	}
}
<commit_msg>Added by block<commit_after>// Original Work
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/

// gopl.io Exercise 7.8
// Modifications Copyright © 2017 Douglas Will
// License: https://creativecommons.org/licenses/by-sa/4.0/

// ******  This exercise is not complete  *******//

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"time"
)

//!+main
type Track struct {
	Title  string
	Artist string
	Album  string
	Year   int
	Length time.Duration
}

var tracks = []*Track{
	{"Go", "Delilah", "From the Roots Up", 2012, length("3m38s")},
	{"Go", "Moby", "Moby", 1992, length("3m37s")},
	{"Go Ahead", "Alicia Keys", "As I Am", 2007, length("4m36s")},
	{"Ready 2 Go", "Martin Solveig", "Smash", 2011, length("4m24s")},
}

var headings = []string{
	"Title",
	"Artist",
	"Album",
	"Year",
	"Length",
}

func length(s string) time.Duration {
	d, err := time.ParseDuration(s)
	if err != nil {
		panic(s)
	}
	return d
}

func main() {

	scanner := bufio.NewScanner(os.Stdin)

	fmt.Printf("Table Headings\n")

	list(headings)

	fmt.Println()

	fmt.Print("Select a Heading:")
	scanner.Scan()

	if i, err := strconv.Atoi(scanner.Text()); err == nil {

		i -= 1
		if i < len(headings) {

			fmt.Printf("You selected: %v\n", headings[i])

			if contains(headings, headings[i]) {
				fmt.Println("You made a valid choice.")
				headings = sortHeadings(headings, headings[i])
			}
		}
		fmt.Println("Invalid choice")
	}

}

func contains(strSlice []string, search string) bool {
	for _, value := range strSlice {
		if value == search {
			return true
		}
	}
	return false
}

// sortHeading takes a slice of strings and one element from that slice
// It re-orders the slice, placing the selection in the first position
func sortHeadings(headings []string, selection string) []string {

	fmt.Println("Selection:", selection)

	if selection == headings[0] {
		fmt.Println("Order is correct")
		return headings
	}
	// Reorder slice

	return headings
}

func list(headings []string) {
	for index := 0; index < len(headings); index++ {
		fmt.Printf("%d. %s\n", index+1, headings[index])
	}
}
<|endoftext|>


<commit_before>package main

import (
	"testing"
)

func buildTestChans(n int) []chan int {
	s := make([]chan int, 0, n)
	for i := 0; i < n; i++ {
		s = append(s, make(chan int))
	}
	return s
}

func runBenchmarkCloseRange(b *testing.B, n int) {
	b.StopTimer()
	for i := 0; i < b.N; i++ {
		s := buildTestChans(n)

		b.StartTimer()
		for i := range s {
			close(s[i])
		}
		b.StopTimer()
	}
}

func runBenchmarkCloseAll(b *testing.B, n int) {
	b.StopTimer()
	for i := 0; i < b.N; i++ {
		s := buildTestChans(n)

		b.StartTimer()
		closeAll(s)
		b.StopTimer()
	}
}

func BenchmarkCloseRange1(b *testing.B) {
	runBenchmarkCloseRange(b, 1)
}

func BenchmarkCloseRange3(b *testing.B) {
	runBenchmarkCloseRange(b, 3)
}

func BenchmarkCloseRange1000(b *testing.B) {
	runBenchmarkCloseRange(b, 1000)
}

func BenchmarkCloseAll1(b *testing.B) {
	runBenchmarkCloseAll(b, 1)
}

func BenchmarkCloseAll3(b *testing.B) {
	runBenchmarkCloseAll(b, 3)
}

func BenchmarkCloseAll1000(b *testing.B) {
	runBenchmarkCloseAll(b, 1000)
}
<commit_msg>Added tests for closeAll<commit_after>package main

import (
	"testing"
)

func TestCloseAllEmpty(t *testing.T) {
	closeAll([]chan int{})
}

func TestCloseAllTwo(t *testing.T) {
	ichan := make(chan int)
	i2chan := make(chan int)
	closeAll([]chan int{ichan, i2chan})
	_, ok := <-ichan
	if ok {
		t.Errorf("ichan wasn't closed")
	}
	_, ok = <-i2chan
	if ok {
		t.Errorf("bchan wasn't closed")
	}
}

func buildTestChans(n int) []chan int {
	s := make([]chan int, 0, n)
	for i := 0; i < n; i++ {
		s = append(s, make(chan int))
	}
	return s
}

func runBenchmarkCloseRange(b *testing.B, n int) {
	b.StopTimer()
	for i := 0; i < b.N; i++ {
		s := buildTestChans(n)

		b.StartTimer()
		for i := range s {
			close(s[i])
		}
		b.StopTimer()
	}
}

func runBenchmarkCloseAll(b *testing.B, n int) {
	b.StopTimer()
	for i := 0; i < b.N; i++ {
		s := buildTestChans(n)

		b.StartTimer()
		closeAll(s)
		b.StopTimer()
	}
}

func BenchmarkCloseRange1(b *testing.B) {
	runBenchmarkCloseRange(b, 1)
}

func BenchmarkCloseRange3(b *testing.B) {
	runBenchmarkCloseRange(b, 3)
}

func BenchmarkCloseRange1000(b *testing.B) {
	runBenchmarkCloseRange(b, 1000)
}

func BenchmarkCloseAll1(b *testing.B) {
	runBenchmarkCloseAll(b, 1)
}

func BenchmarkCloseAll3(b *testing.B) {
	runBenchmarkCloseAll(b, 3)
}

func BenchmarkCloseAll1000(b *testing.B) {
	runBenchmarkCloseAll(b, 1000)
}
<|endoftext|>