<commit_before>package docker

import (
	"bufio"
	"encoding/json"
	"fmt"
	"github.com/dotcloud/docker/utils"
	"io"
	"io/ioutil"
	"os"
	"path"
	"reflect"
	"strings"
)

type BuildFile interface {
	Build(io.Reader) (string, error)
	CmdFrom(string) error
	CmdRun(string) error
}

type buildFile struct {
	runtime *Runtime
	builder *Builder
	srv     *Server

	image      string
	maintainer string
	config     *Config
	context    string

	tmpContainers map[string]struct{}
	tmpImages     map[string]struct{}

	out io.Writer
}

func (b *buildFile) clearTmp(containers, images map[string]struct{}) {
	for c := range containers {
		tmp := b.runtime.Get(c)
		b.runtime.Destroy(tmp)
		utils.Debugf("Removing container %s", c)
	}
	for i := range images {
		b.runtime.graph.Delete(i)
		utils.Debugf("Removing image %s", i)
	}
}

func (b *buildFile) CmdFrom(name string) error {
	image, err := b.runtime.repositories.LookupImage(name)
	if err != nil {
		if b.runtime.graph.IsNotExist(err) {

			var tag, remote string
			if strings.Contains(name, ":") {
				remoteParts := strings.Split(name, ":")
				tag = remoteParts[1]
				remote = remoteParts[0]
			} else {
				remote = name
			}

			if err := b.srv.ImagePull(remote, tag, "", b.out, utils.NewStreamFormatter(false), nil); err != nil {
				return err
			}

			image, err = b.runtime.repositories.LookupImage(name)
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}
	b.image = image.ID
	b.config = &Config{}
	return nil
}

func (b *buildFile) CmdMaintainer(name string) error {
	b.maintainer = name
	return b.commit("", b.config.Cmd, fmt.Sprintf("MAINTAINER %s", name))
}

func (b *buildFile) CmdRun(args string) error {
	if b.image == "" {
		return fmt.Errorf("Please provide a source image with `from` prior to run")
	}
	config, _, err := ParseRun([]string{b.image, "/bin/sh", "-c", args}, nil)
	if err != nil {
		return err
	}

	cmd := b.config.Cmd
	b.config.Cmd = nil
	MergeConfig(b.config, config)

	utils.Debugf("Command to be executed: %v", b.config.Cmd)

	if cache, err := b.srv.ImageGetCached(b.image, b.config); err != nil {
		return err
	} else if cache != nil {
		fmt.Fprintf(b.out, " ---> Using cache\n")
		utils.Debugf("[BUILDER] Use cached version")
		b.image = cache.ID
		return nil
	} else {
		utils.Debugf("[BUILDER] Cache miss")
	}

	cid, err := b.run()
	if err != nil {
		return err
	}
	if err := b.commit(cid, cmd, "run"); err != nil {
		return err
	}
	b.config.Cmd = cmd
	return nil
}

func (b *buildFile) CmdEnv(args string) error {
	tmp := strings.SplitN(args, " ", 2)
	if len(tmp) != 2 {
		return fmt.Errorf("Invalid ENV format")
	}
	key := strings.Trim(tmp[0], " \t")
	value := strings.Trim(tmp[1], " \t")

	for i, elem := range b.config.Env {
		if strings.HasPrefix(elem, key+"=") {
			b.config.Env[i] = key + "=" + value
			return nil
		}
	}
	b.config.Env = append(b.config.Env, key+"="+value)
	return b.commit("", b.config.Cmd, fmt.Sprintf("ENV %s=%s", key, value))
}

func (b *buildFile) CmdCmd(args string) error {
	var cmd []string
	if err := json.Unmarshal([]byte(args), &cmd); err != nil {
		utils.Debugf("Error unmarshalling: %s, using /bin/sh -c", err)
		cmd = []string{"/bin/sh", "-c", args}
	}
	if err := b.commit("", cmd, fmt.Sprintf("CMD %v", cmd)); err != nil {
		return err
	}
	b.config.Cmd = cmd
	return nil
}

func (b *buildFile) CmdExpose(args string) error {
	ports := strings.Split(args, " ")
	b.config.PortSpecs = append(ports, b.config.PortSpecs...)
	return b.commit("", b.config.Cmd, fmt.Sprintf("EXPOSE %v", ports))
}

func (b *buildFile) CmdInsert(args string) error {
	return fmt.Errorf("INSERT has been deprecated. Please use ADD instead")
}

func (b *buildFile) CmdCopy(args string) error {
	return fmt.Errorf("COPY has been deprecated. Please use ADD instead")
}

func (b *buildFile) addRemote(container *Container, orig, dest string) error {
	file, err := utils.Download(orig, ioutil.Discard)
	if err != nil {
		return err
	}
	defer file.Body.Close()

	return container.Inject(file.Body, dest)
}

func (b *buildFile) addContext(container *Container, orig, dest string) error {
	origPath := path.Join(b.context, orig)
	destPath := path.Join(container.RootfsPath(), dest)
	// Preserve the trailing '/'
	if dest[len(dest)-1] == '/' {
		destPath = destPath + "/"
	}
	fi, err := os.Stat(origPath)
	if err != nil {
		return err
	}
	if fi.IsDir() {
		if err := CopyWithTar(origPath, destPath); err != nil {
			return err
		}
		// First try to unpack the source as an archive
	} else if err := UntarPath(origPath, destPath); err != nil {
		utils.Debugf("Couldn't untar %s to %s: %s", origPath, destPath, err)
		// If that fails, just copy it as a regular file
		if err := os.MkdirAll(path.Dir(destPath), 0700); err != nil {
			return err
		}
		if err := CopyWithTar(origPath, destPath); err != nil {
			return err
		}
	}
	return nil
}

func (b *buildFile) CmdAdd(args string) error {
	if b.context == "" {
		return fmt.Errorf("No context given. Impossible to use ADD")
	}
	tmp := strings.SplitN(args, " ", 2)
	if len(tmp) != 2 {
		return fmt.Errorf("Invalid ADD format")
	}
	orig := strings.Trim(tmp[0], " \t")
	dest := strings.Trim(tmp[1], " \t")

	cmd := b.config.Cmd
	b.config.Cmd = []string{"/bin/sh", "-c", fmt.Sprintf("#(nop) ADD %s in %s", orig, dest)}

	b.config.Image = b.image
	// Create the container and start it
	container, err := b.builder.Create(b.config)
	if err != nil {
		return err
	}
	b.tmpContainers[container.ID] = struct{}{}

	if err := container.EnsureMounted(); err != nil {
		return err
	}
	defer container.Unmount()

	if utils.IsURL(orig) {
		if err := b.addRemote(container, orig, dest); err != nil {
			return err
		}
	} else {
		if err := b.addContext(container, orig, dest); err != nil {
			return err
		}
	}

	if err := b.commit(container.ID, cmd, fmt.Sprintf("ADD %s in %s", orig, dest)); err != nil {
		return err
	}
	b.config.Cmd = cmd
	return nil
}

func (b *buildFile) run() (string, error) {
	if b.image == "" {
		return "", fmt.Errorf("Please provide a source image with `from` prior to run")
	}
	b.config.Image = b.image

	// Create the container and start it
	c, err := b.builder.Create(b.config)
	if err != nil {
		return "", err
	}
	b.tmpContainers[c.ID] = struct{}{}
	fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(c.ID))

	//start the container
	if err := c.Start(); err != nil {
		return "", err
	}

	// Wait for it to finish
	if ret := c.Wait(); ret != 0 {
		return "", fmt.Errorf("The command %v returned a non-zero code: %d", b.config.Cmd, ret)
	}

	return c.ID, nil
}

// Commit the container <id> with the autorun command <autoCmd>
func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
	if b.image == "" {
		return fmt.Errorf("Please provide a source image with `from` prior to commit")
	}
	b.config.Image = b.image
	if id == "" {
		cmd := b.config.Cmd
		b.config.Cmd = []string{"/bin/sh", "-c", "#(nop) " + comment}
		defer func(cmd []string) { b.config.Cmd = cmd }(cmd)

		if cache, err := b.srv.ImageGetCached(b.image, b.config); err != nil {
			return err
		} else if cache != nil {
			fmt.Fprintf(b.out, " ---> Using cache\n")
			utils.Debugf("[BUILDER] Use cached version")
			b.image = cache.ID
			return nil
		} else {
			utils.Debugf("[BUILDER] Cache miss")
		}
		container, err := b.builder.Create(b.config)
		if err != nil {
			return err
		}
		b.tmpContainers[container.ID] = struct{}{}
		fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(container.ID))
		id = container.ID
		if err := container.EnsureMounted(); err != nil {
			return err
		}
		defer container.Unmount()
	}

	container := b.runtime.Get(id)
	if container == nil {
		return fmt.Errorf("An error occured while creating the container")
	}

	// Note: Actually copy the struct
	autoConfig := *b.config
	autoConfig.Cmd = autoCmd
	// Commit the container
	image, err := b.builder.Commit(container, "", "", "", b.maintainer, &autoConfig)
	if err != nil {
		return err
	}
	b.tmpImages[image.ID] = struct{}{}
	b.image = image.ID
	return nil
}

func (b *buildFile) Build(context io.Reader) (string, error) {
	// FIXME: @creack any reason for using /tmp instead of ""?
	// FIXME: @creack "name" is a terrible variable name
	name, err := ioutil.TempDir("/tmp", "docker-build")
	if err != nil {
		return "", err
	}
	if err := Untar(context, name); err != nil {
		return "", err
	}
	defer os.RemoveAll(name)
	b.context = name
	dockerfile, err := os.Open(path.Join(name, "Dockerfile"))
	if err != nil {
		return "", fmt.Errorf("Can't build a directory with no Dockerfile")
	}
	// FIXME: "file" is also a terrible variable name ;)
	file := bufio.NewReader(dockerfile)
	stepN := 0
	for {
		line, err := file.ReadString('\n')
		if err != nil {
			if err == io.EOF && line == "" {
				break
			} else if err != io.EOF {
				return "", err
			}
		}
		line = strings.Trim(strings.Replace(line, "\t", " ", -1), " \t\r\n")
		// Skip comments and empty line
		if len(line) == 0 || line[0] == '#' {
			continue
		}
		tmp := strings.SplitN(line, " ", 2)
		if len(tmp) != 2 {
			return "", fmt.Errorf("Invalid Dockerfile format")
		}
		instruction := strings.ToLower(strings.Trim(tmp[0], " "))
		arguments := strings.Trim(tmp[1], " ")
		stepN += 1
		// FIXME: only count known instructions as build steps
		fmt.Fprintf(b.out, "Step %d : %s %s\n", stepN, strings.ToUpper(instruction), arguments)

		method, exists := reflect.TypeOf(b).MethodByName("Cmd" + strings.ToUpper(instruction[:1]) + strings.ToLower(instruction[1:]))
		if !exists {
			fmt.Fprintf(b.out, "# Skipping unknown instruction %s\n", strings.ToUpper(instruction))
			continue
		}
		ret := method.Func.Call([]reflect.Value{reflect.ValueOf(b), reflect.ValueOf(arguments)})[0].Interface()
		if ret != nil {
			return "", ret.(error)
		}

		fmt.Fprintf(b.out, " ---> %v\n", utils.TruncateID(b.image))
	}
	if b.image != "" {
		fmt.Fprintf(b.out, "Successfully built %s\n", utils.TruncateID(b.image))
		return b.image, nil
	}
	return "", fmt.Errorf("An error occured during the build\n")
}

func NewBuildFile(srv *Server, out io.Writer) BuildFile {
	return &buildFile{
		builder:       NewBuilder(srv.runtime),
		runtime:       srv.runtime,
		srv:           srv,
		config:        &Config{},
		out:           out,
		tmpContainers: make(map[string]struct{}),
		tmpImages:     make(map[string]struct{}),
	}
}
<commit_msg>Display containers logs in case of build failure<commit_after>package docker

import (
	"bufio"
	"encoding/json"
	"fmt"
	"github.com/dotcloud/docker/utils"
	"io"
	"io/ioutil"
	"os"
	"path"
	"reflect"
	"strings"
)

type BuildFile interface {
	Build(io.Reader) (string, error)
	CmdFrom(string) error
	CmdRun(string) error
}

type buildFile struct {
	runtime *Runtime
	builder *Builder
	srv     *Server

	image      string
	maintainer string
	config     *Config
	context    string

	lastContainer *Container
	tmpContainers map[string]struct{}
	tmpImages     map[string]struct{}

	out io.Writer
}

func (b *buildFile) clearTmp(containers, images map[string]struct{}) {
	for c := range containers {
		tmp := b.runtime.Get(c)
		b.runtime.Destroy(tmp)
		utils.Debugf("Removing container %s", c)
	}
	for i := range images {
		b.runtime.graph.Delete(i)
		utils.Debugf("Removing image %s", i)
	}
}

func (b *buildFile) CmdFrom(name string) error {
	image, err := b.runtime.repositories.LookupImage(name)
	if err != nil {
		if b.runtime.graph.IsNotExist(err) {

			var tag, remote string
			if strings.Contains(name, ":") {
				remoteParts := strings.Split(name, ":")
				tag = remoteParts[1]
				remote = remoteParts[0]
			} else {
				remote = name
			}

			if err := b.srv.ImagePull(remote, tag, "", b.out, utils.NewStreamFormatter(false), nil); err != nil {
				return err
			}

			image, err = b.runtime.repositories.LookupImage(name)
			if err != nil {
				return err
			}
		} else {
			return err
		}
	}
	b.image = image.ID
	b.config = &Config{}
	return nil
}

func (b *buildFile) CmdMaintainer(name string) error {
	b.maintainer = name
	return b.commit("", b.config.Cmd, fmt.Sprintf("MAINTAINER %s", name))
}

func (b *buildFile) CmdRun(args string) error {
	if b.image == "" {
		return fmt.Errorf("Please provide a source image with `from` prior to run")
	}
	config, _, err := ParseRun([]string{b.image, "/bin/sh", "-c", args}, nil)
	if err != nil {
		return err
	}

	cmd := b.config.Cmd
	b.config.Cmd = nil
	MergeConfig(b.config, config)

	utils.Debugf("Command to be executed: %v", b.config.Cmd)

	if cache, err := b.srv.ImageGetCached(b.image, b.config); err != nil {
		return err
	} else if cache != nil {
		fmt.Fprintf(b.out, " ---> Using cache\n")
		utils.Debugf("[BUILDER] Use cached version")
		b.image = cache.ID
		return nil
	} else {
		utils.Debugf("[BUILDER] Cache miss")
	}

	cid, err := b.run()
	if err != nil {
		return err
	}
	if err := b.commit(cid, cmd, "run"); err != nil {
		return err
	}
	b.config.Cmd = cmd
	return nil
}

func (b *buildFile) CmdEnv(args string) error {
	tmp := strings.SplitN(args, " ", 2)
	if len(tmp) != 2 {
		return fmt.Errorf("Invalid ENV format")
	}
	key := strings.Trim(tmp[0], " \t")
	value := strings.Trim(tmp[1], " \t")

	for i, elem := range b.config.Env {
		if strings.HasPrefix(elem, key+"=") {
			b.config.Env[i] = key + "=" + value
			return nil
		}
	}
	b.config.Env = append(b.config.Env, key+"="+value)
	return b.commit("", b.config.Cmd, fmt.Sprintf("ENV %s=%s", key, value))
}

func (b *buildFile) CmdCmd(args string) error {
	var cmd []string
	if err := json.Unmarshal([]byte(args), &cmd); err != nil {
		utils.Debugf("Error unmarshalling: %s, using /bin/sh -c", err)
		cmd = []string{"/bin/sh", "-c", args}
	}
	if err := b.commit("", cmd, fmt.Sprintf("CMD %v", cmd)); err != nil {
		return err
	}
	b.config.Cmd = cmd
	return nil
}

func (b *buildFile) CmdExpose(args string) error {
	ports := strings.Split(args, " ")
	b.config.PortSpecs = append(ports, b.config.PortSpecs...)
	return b.commit("", b.config.Cmd, fmt.Sprintf("EXPOSE %v", ports))
}

func (b *buildFile) CmdInsert(args string) error {
	return fmt.Errorf("INSERT has been deprecated. Please use ADD instead")
}

func (b *buildFile) CmdCopy(args string) error {
	return fmt.Errorf("COPY has been deprecated. Please use ADD instead")
}

func (b *buildFile) addRemote(container *Container, orig, dest string) error {
	file, err := utils.Download(orig, ioutil.Discard)
	if err != nil {
		return err
	}
	defer file.Body.Close()

	return container.Inject(file.Body, dest)
}

func (b *buildFile) addContext(container *Container, orig, dest string) error {
	origPath := path.Join(b.context, orig)
	destPath := path.Join(container.RootfsPath(), dest)
	// Preserve the trailing '/'
	if dest[len(dest)-1] == '/' {
		destPath = destPath + "/"
	}
	fi, err := os.Stat(origPath)
	if err != nil {
		return err
	}
	if fi.IsDir() {
		if err := CopyWithTar(origPath, destPath); err != nil {
			return err
		}
		// First try to unpack the source as an archive
	} else if err := UntarPath(origPath, destPath); err != nil {
		utils.Debugf("Couldn't untar %s to %s: %s", origPath, destPath, err)
		// If that fails, just copy it as a regular file
		if err := os.MkdirAll(path.Dir(destPath), 0700); err != nil {
			return err
		}
		if err := CopyWithTar(origPath, destPath); err != nil {
			return err
		}
	}
	return nil
}

func (b *buildFile) CmdAdd(args string) error {
	if b.context == "" {
		return fmt.Errorf("No context given. Impossible to use ADD")
	}
	tmp := strings.SplitN(args, " ", 2)
	if len(tmp) != 2 {
		return fmt.Errorf("Invalid ADD format")
	}
	orig := strings.Trim(tmp[0], " \t")
	dest := strings.Trim(tmp[1], " \t")

	cmd := b.config.Cmd
	b.config.Cmd = []string{"/bin/sh", "-c", fmt.Sprintf("#(nop) ADD %s in %s", orig, dest)}

	b.config.Image = b.image
	// Create the container and start it
	container, err := b.builder.Create(b.config)
	if err != nil {
		return err
	}
	b.tmpContainers[container.ID] = struct{}{}
	b.lastContainer = container

	if err := container.EnsureMounted(); err != nil {
		return err
	}
	defer container.Unmount()

	if utils.IsURL(orig) {
		if err := b.addRemote(container, orig, dest); err != nil {
			return err
		}
	} else {
		if err := b.addContext(container, orig, dest); err != nil {
			return err
		}
	}

	if err := b.commit(container.ID, cmd, fmt.Sprintf("ADD %s in %s", orig, dest)); err != nil {
		return err
	}
	b.config.Cmd = cmd
	return nil
}

func (b *buildFile) run() (string, error) {
	if b.image == "" {
		return "", fmt.Errorf("Please provide a source image with `from` prior to run")
	}
	b.config.Image = b.image

	// Create the container and start it
	c, err := b.builder.Create(b.config)
	if err != nil {
		return "", err
	}
	b.tmpContainers[c.ID] = struct{}{}
	b.lastContainer = c
	fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(c.ID))

	//start the container
	if err := c.Start(); err != nil {
		return "", err
	}

	// Wait for it to finish
	if ret := c.Wait(); ret != 0 {
		return "", fmt.Errorf("The command %v returned a non-zero code: %d", b.config.Cmd, ret)
	}

	return c.ID, nil
}

// Commit the container <id> with the autorun command <autoCmd>
func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
	if b.image == "" {
		return fmt.Errorf("Please provide a source image with `from` prior to commit")
	}
	b.config.Image = b.image
	if id == "" {
		cmd := b.config.Cmd
		b.config.Cmd = []string{"/bin/sh", "-c", "#(nop) " + comment}
		defer func(cmd []string) { b.config.Cmd = cmd }(cmd)

		if cache, err := b.srv.ImageGetCached(b.image, b.config); err != nil {
			return err
		} else if cache != nil {
			fmt.Fprintf(b.out, " ---> Using cache\n")
			utils.Debugf("[BUILDER] Use cached version")
			b.image = cache.ID
			return nil
		} else {
			utils.Debugf("[BUILDER] Cache miss")
		}
		container, err := b.builder.Create(b.config)
		if err != nil {
			return err
		}
		b.tmpContainers[container.ID] = struct{}{}
		b.lastContainer = container
		fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(container.ID))
		id = container.ID
		if err := container.EnsureMounted(); err != nil {
			return err
		}
		defer container.Unmount()
	}

	container := b.runtime.Get(id)
	if container == nil {
		return fmt.Errorf("An error occured while creating the container")
	}

	// Note: Actually copy the struct
	autoConfig := *b.config
	autoConfig.Cmd = autoCmd
	// Commit the container
	image, err := b.builder.Commit(container, "", "", "", b.maintainer, &autoConfig)
	if err != nil {
		return err
	}
	b.tmpImages[image.ID] = struct{}{}
	b.image = image.ID
	return nil
}

func (b *buildFile) Build(context io.Reader) (string, error) {
	defer func() {
		// If we have an error and a container, the display the logs
		if b.lastContainer != nil {
			fmt.Fprintf(b.out, "Logs from last container (%s):\n", b.lastContainer.ShortID())

			cLog, err := b.lastContainer.ReadLog("stdout")
			if err != nil {
				utils.Debugf("Error reading logs (stdout): %s", err)
			}
			if _, err := io.Copy(b.out, cLog); err != nil {
				utils.Debugf("Error streaming logs (stdout): %s", err)
			}
			cLog, err = b.lastContainer.ReadLog("stderr")
			if err != nil {
				utils.Debugf("Error reading logs (stderr): %s", err)
			}
			if _, err := io.Copy(b.out, cLog); err != nil {
				utils.Debugf("Error streaming logs (stderr): %s", err)
			}
			fmt.Fprintf(b.out, "End of logs for %s\n", b.lastContainer.ShortID())
		}
	}()

	// FIXME: @creack any reason for using /tmp instead of ""?
	// FIXME: @creack "name" is a terrible variable name
	name, err := ioutil.TempDir("/tmp", "docker-build")
	if err != nil {
		return "", err
	}
	if err := Untar(context, name); err != nil {
		return "", err
	}
	defer os.RemoveAll(name)
	b.context = name
	dockerfile, err := os.Open(path.Join(name, "Dockerfile"))
	if err != nil {
		return "", fmt.Errorf("Can't build a directory with no Dockerfile")
	}
	// FIXME: "file" is also a terrible variable name ;)
	file := bufio.NewReader(dockerfile)
	stepN := 0
	for {
		line, err := file.ReadString('\n')
		if err != nil {
			if err == io.EOF && line == "" {
				break
			} else if err != io.EOF {
				return "", err
			}
		}
		line = strings.Trim(strings.Replace(line, "\t", " ", -1), " \t\r\n")
		// Skip comments and empty line
		if len(line) == 0 || line[0] == '#' {
			continue
		}
		tmp := strings.SplitN(line, " ", 2)
		if len(tmp) != 2 {
			return "", fmt.Errorf("Invalid Dockerfile format")
		}
		instruction := strings.ToLower(strings.Trim(tmp[0], " "))
		arguments := strings.Trim(tmp[1], " ")
		stepN += 1
		// FIXME: only count known instructions as build steps
		fmt.Fprintf(b.out, "Step %d : %s %s\n", stepN, strings.ToUpper(instruction), arguments)

		method, exists := reflect.TypeOf(b).MethodByName("Cmd" + strings.ToUpper(instruction[:1]) + strings.ToLower(instruction[1:]))
		if !exists {
			fmt.Fprintf(b.out, "# Skipping unknown instruction %s\n", strings.ToUpper(instruction))
			continue
		}
		ret := method.Func.Call([]reflect.Value{reflect.ValueOf(b), reflect.ValueOf(arguments)})[0].Interface()
		if ret != nil {
			return "", ret.(error)
		}

		b.lastContainer = nil
		fmt.Fprintf(b.out, " ---> %v\n", utils.TruncateID(b.image))
	}
	if b.image != "" {
		fmt.Fprintf(b.out, "Successfully built %s\n", utils.TruncateID(b.image))
		return b.image, nil
	}
	return "", fmt.Errorf("An error occured during the build\n")
}

func NewBuildFile(srv *Server, out io.Writer) BuildFile {
	return &buildFile{
		builder:       NewBuilder(srv.runtime),
		runtime:       srv.runtime,
		srv:           srv,
		config:        &Config{},
		out:           out,
		tmpContainers: make(map[string]struct{}),
		tmpImages:     make(map[string]struct{}),
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Jacob Taylor jacob@ablox.io
// License: Apache2 - http://www.apache.org/licenses/LICENSE-2.0
package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"
	"sort"
	"testing"
	"time"
)

type filesystemTrackerHelper func(t *testing.T, tracker *FilesystemTracker) bool

func waitFor(t *testing.T, tracker *FilesystemTracker, helper func(t *testing.T, tracker *FilesystemTracker) bool) bool {
	roundTrips := 0
	for {
		if helper(t, tracker) {
			return true
		}

		if roundTrips > 50 {
			return false
		}
		roundTrips++

		time.Sleep(50 * time.Millisecond)
	}
}

func TestEmptyDirectoryMoveIn(t *testing.T) {
	monitoredFolder, _ := ioutil.TempDir("", "monitored")
	outsideFolder, _ := ioutil.TempDir("", "outside")
	defer os.RemoveAll(monitoredFolder)
	defer os.RemoveAll(outsideFolder)

	tracker := new(FilesystemTracker)
	tracker.init(monitoredFolder)
	defer tracker.cleanup()

	logger := &LogOnlyChangeHandler{}
	var loggerInterface ChangeHandler = logger
	tracker.watchDirectory(&loggerInterface)

	folderName := "happy"
	targetMonitoredPath := monitoredFolder + "/" + folderName
	targetOutsidePath := outsideFolder + "/" + folderName

	fmt.Printf("making folder: %s going to rename it to: %s\n", targetOutsidePath, targetMonitoredPath)
	os.Mkdir(targetOutsidePath, os.ModeDir+os.ModePerm)
	os.Rename(targetOutsidePath, targetMonitoredPath)
	stats, _ := os.Stat(targetMonitoredPath)
	fmt.Printf("stats for: %s\n%v\n", targetMonitoredPath, stats)

	helper := func(t *testing.T, tracker *FilesystemTracker) bool {
		_, exists := tracker.contents[folderName]
		fmt.Printf("Checking the value of exists: %v\n", exists)
		return exists
	}

	if !waitFor(t, tracker, helper) {
			t.Fatalf("%s not found in contents\ncontents: %v\n", folderName, tracker.contents)
	}

	os.Rename(targetMonitoredPath, targetOutsidePath)
	helper = func(t *testing.T, tracker *FilesystemTracker) bool {
		_, exists := tracker.contents[folderName]
		fmt.Printf("Checking the value of exists: %v\n", exists)
		return exists
	}

	if !waitFor(t, tracker, helper) {
			t.Fatalf("%s not cleared from contents\ncontents: %v\n", folderName, tracker.contents)
	}

}

func TestDirectoryCreation(t *testing.T) {
	tmpFolder, err := ioutil.TempDir("", "blank")
	defer os.RemoveAll(tmpFolder)

	tracker := new(FilesystemTracker)
	tracker.init(tmpFolder)
	defer tracker.cleanup()

	testDirectory := tmpFolder + "/" + "newbie"
	before, err := os.Stat(testDirectory)

	os.Mkdir(testDirectory, os.ModeDir+os.ModePerm)

	after, err := os.Stat(testDirectory)

	if err != nil {
		fmt.Println("GACK, directory should exist")
	}

	err = os.Remove(testDirectory)

	_, err = os.Stat(testDirectory)

	if !os.IsNotExist(err) {
		t.Fatal("The folder still exists.....oopps")
	}

	fmt.Printf("TestDirectoryCreation\nbefore: %v\nafter: %v\n", before, after)

}

func TestDirectoryStorage(t *testing.T) {
	tmpFolder, err := ioutil.TempDir("", "blank")
	defer os.RemoveAll(tmpFolder)

	tracker := new(FilesystemTracker)
	tracker.init(tmpFolder)
	defer tracker.cleanup()

	empty := make([]string, 0)
	empty = append(empty, ".")

	folderList := tracker.ListFolders()

	if reflect.DeepEqual(empty, folderList) == false {
		t.Fatal(fmt.Sprintf("expected empty folder, found something: %v\n", folderList))
	}

	folderTemplate := []string{"A", "B", "C"}

	for _, folder := range folderTemplate {
		err := tracker.CreatePath(folder, true)
		if err != nil {
			t.Fatal(err)
		}
	}

	folderList = tracker.ListFolders()

	expectedFolderList := append(folderTemplate, ".")
	sort.Strings(expectedFolderList)
	sort.Strings(folderList)

	if reflect.DeepEqual(expectedFolderList, folderList) == false {
		t.Fatal(fmt.Sprintf("Found: %v\nExpected: %v\n", folderList, expectedFolderList))
	}

	err = tracker.DeleteFolder(folderTemplate[0])
	if err != nil {
		t.Fatal(err)
	}

	folderList = tracker.ListFolders()
	sort.Strings(folderList)

	folderTemplate = folderTemplate[1:]

	expectedFolderList = append(folderTemplate, ".")
	sort.Strings(expectedFolderList)

	if reflect.DeepEqual(folderList, expectedFolderList) == false {
		t.Fatal(fmt.Sprintf("Found: %v\nExpected: %v\n", folderList, expectedFolderList))
	}

}

func TestFileChangeTrackerAutoCreateFolderAndCleanup(t *testing.T) {
	tracker := new(FilesystemTracker)

	tmpFolder, err := ioutil.TempDir("", "blank")
	defer os.RemoveAll(tmpFolder)

	tmpFolder = tmpFolder + "R"
	defer os.RemoveAll(tmpFolder)

	logger := &LogOnlyChangeHandler{}
	var loggerInterface ChangeHandler = logger

	tracker.init(tmpFolder)
	tracker.watchDirectory(&loggerInterface)

	// verify the folder was created
	_, err = filepath.EvalSymlinks(tmpFolder)
	if err != nil {
		t.Fatal(err)
	}

	tracker.cleanup()
}

type countingChangeHandler struct {
	FoldersCreated int
	FoldersDeleted int
}

func (handler *countingChangeHandler) FolderCreated(name string) (error) {
	handler.FoldersCreated++

	fmt.Printf("countingChangeHandler:FolderCreated: %s (%d)\n", name, handler.FoldersCreated)
	return nil
}

func (handler *countingChangeHandler) FolderDeleted(name string) (error) {
	handler.FoldersDeleted++

	fmt.Printf("countingChangeHandler:FolderDeleted: %s (%d)\n", name, handler.FoldersDeleted)
	return nil
}

func TestFileChangeTrackerAddFolders(t *testing.T) {
	logHandler := countingChangeHandler{}
	var c ChangeHandler = &logHandler

	tmpFolder, err := ioutil.TempDir("", "blank")
	//tmpFolder := "/tmp/foot"
	defer os.RemoveAll(tmpFolder)

	fmt.Println("TestFileChangeTrackerAddFolders: About to call watchDirectory")
	tracker := new(FilesystemTracker)
	tracker.init(tmpFolder)
	defer tracker.cleanup()

	tracker.watchDirectory(&c)
	fmt.Println("TestFileChangeTrackerAddFolders: Done - About to call watchDirectory")

	numberOfSubFolders := 10

	for i := 0; i < numberOfSubFolders; i++ {
		path := fmt.Sprintf("%s/a%d", tmpFolder, i)

		err = os.Mkdir(path, os.ModeDir+os.ModePerm)
		if err != nil {
			t.Fatal(err)
		}
	}
	fmt.Printf("done with creating %d different subfolders. :)\n", numberOfSubFolders)

	cycleCount := 0
	for {
		cycleCount++
		folderList := tracker.ListFolders()
		if len(folderList) < numberOfSubFolders {
			//fmt.Printf("did not get all folders. Current: %v\n", folderList)
			if cycleCount > 200 {
				t.Fatalf("Did not find enough folders. Got bored of waiting. What was found: %v\n", folderList)
			}
			time.Sleep(time.Millisecond * 50)
		} else {
			fmt.Println("We have all of our ducks in a row")
			break
		}
	}

	folder1 := fmt.Sprintf("%s/a0", tmpFolder)
	folder2 := fmt.Sprintf("%s/a1", tmpFolder)
	fmt.Printf("about to delete two folders \n%s\n%s\n", folder1, folder2)
	// Delete two folders
	fmt.Println(tracker.ListFolders())
	os.Remove(folder1)
	os.Remove(folder2)
	fmt.Printf("deleted two folders \n%s\n%s\n", folder1, folder2)

	expectedCreated := numberOfSubFolders + 1
	expectedDeleted := 2

	// wait for the final tally to come through.
	cycleCount = 0
	for {
		cycleCount++

		if logHandler.FoldersCreated != expectedCreated || logHandler.FoldersDeleted != expectedDeleted {
			if cycleCount > 200 {
				fmt.Printf("Kept finding bad data. Got bored of waiting. What was found: %v\n", tracker.ListFolders())
				break
			}
			time.Sleep(time.Millisecond * 50)
		} else {
			fmt.Println("We have all of our ducks in a row again. Yay!")
			break
		}
	}

	if logHandler.FoldersCreated != expectedCreated || logHandler.FoldersDeleted != expectedDeleted {
		t.Fatalf("Expected/Found created: (%d/%d) deleted: (%d/%d)\n", expectedCreated, logHandler.FoldersCreated, expectedDeleted, logHandler.FoldersDeleted)
	}

	rootDirectory, exists := tracker.contents["."]
	if !exists {
		fmt.Println("root directory fileinfo is nil")
	} else {
		fmt.Printf("Root directory %v\n", rootDirectory)
		fmt.Printf("Root directory named: %s and has size %d\n", rootDirectory.Name(), rootDirectory.Size())
	}
}
<commit_msg>making the tests include rename inside the monitored tree. Making the helper function more reusable<commit_after>// Copyright 2016 Jacob Taylor jacob@ablox.io
// License: Apache2 - http://www.apache.org/licenses/LICENSE-2.0
package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"
	"sort"
	"testing"
	"time"
)

type filesystemTrackerHelper func(t *testing.T, tracker *FilesystemTracker) bool

func waitFor(t *testing.T, tracker *FilesystemTracker, folder string, waitingFor bool, helper func(t *testing.T, tracker *FilesystemTracker, folder string) bool) bool {
	roundTrips := 0
	for {
		if waitingFor == helper(t, tracker, folder) {
			return true
		}

		if roundTrips > 50 {
			return false
		}
		roundTrips++

		time.Sleep(50 * time.Millisecond)
	}
}

func TestEmptyDirectoryMovesInOutAround(t *testing.T) {
	monitoredFolder, _ := ioutil.TempDir("", "monitored")
	outsideFolder, _ := ioutil.TempDir("", "outside")
	defer os.RemoveAll(monitoredFolder)
	defer os.RemoveAll(outsideFolder)

	tracker := new(FilesystemTracker)
	tracker.init(monitoredFolder)
	defer tracker.cleanup()

	logger := &LogOnlyChangeHandler{}
	var loggerInterface ChangeHandler = logger
	tracker.watchDirectory(&loggerInterface)

	folderName := "happy"
	targetMonitoredPath := monitoredFolder + "/" + folderName
	targetOutsidePath := outsideFolder + "/" + folderName

	fmt.Printf("making folder: %s going to rename it to: %s\n", targetOutsidePath, targetMonitoredPath)
	os.Mkdir(targetOutsidePath, os.ModeDir+os.ModePerm)
	os.Rename(targetOutsidePath, targetMonitoredPath)
	stats, _ := os.Stat(targetMonitoredPath)
	fmt.Printf("stats for: %s\n%v\n", targetMonitoredPath, stats)

	helper := func(t *testing.T, tracker *FilesystemTracker, folder string) bool {
		_, exists := tracker.contents[folder]
		fmt.Printf("Checking the value of exists: %v\n", exists)
		return exists
	}

	if !waitFor(t, tracker, folderName, true, helper) {
			t.Fatalf("%s not found in contents\ncontents: %v\n", folderName, tracker.contents)
	}

	folderName = folderName + "b"
	moveSourcePath := targetMonitoredPath
	moveDestinationPath := monitoredFolder + "/" + folderName
	os.Rename(moveSourcePath, moveDestinationPath)

	if !waitFor(t, tracker, folderName, true, helper) {
		t.Fatalf("%s not renamed from contents\ncontents: %v\n", folderName, tracker.contents)
	}

	moveSourcePath = moveDestinationPath
	moveDestinationPath = targetOutsidePath

	os.Rename(moveSourcePath, moveDestinationPath)

	if !waitFor(t, tracker, folderName, false, helper) {
			t.Fatalf("%s not cleared from contents\ncontents: %v\n", folderName, tracker.contents)
	}

}

func TestDirectoryCreation(t *testing.T) {
	tmpFolder, err := ioutil.TempDir("", "blank")
	defer os.RemoveAll(tmpFolder)

	tracker := new(FilesystemTracker)
	tracker.init(tmpFolder)
	defer tracker.cleanup()

	testDirectory := tmpFolder + "/" + "newbie"
	before, err := os.Stat(testDirectory)

	os.Mkdir(testDirectory, os.ModeDir+os.ModePerm)

	after, err := os.Stat(testDirectory)

	if err != nil {
		fmt.Println("GACK, directory should exist")
	}

	err = os.Remove(testDirectory)

	_, err = os.Stat(testDirectory)

	if !os.IsNotExist(err) {
		t.Fatal("The folder still exists.....oopps")
	}

	fmt.Printf("TestDirectoryCreation\nbefore: %v\nafter: %v\n", before, after)

}

func TestDirectoryStorage(t *testing.T) {
	tmpFolder, err := ioutil.TempDir("", "blank")
	defer os.RemoveAll(tmpFolder)

	tracker := new(FilesystemTracker)
	tracker.init(tmpFolder)
	defer tracker.cleanup()

	empty := make([]string, 0)
	empty = append(empty, ".")

	folderList := tracker.ListFolders()

	if reflect.DeepEqual(empty, folderList) == false {
		t.Fatal(fmt.Sprintf("expected empty folder, found something: %v\n", folderList))
	}

	folderTemplate := []string{"A", "B", "C"}

	for _, folder := range folderTemplate {
		err := tracker.CreatePath(folder, true)
		if err != nil {
			t.Fatal(err)
		}
	}

	folderList = tracker.ListFolders()

	expectedFolderList := append(folderTemplate, ".")
	sort.Strings(expectedFolderList)
	sort.Strings(folderList)

	if reflect.DeepEqual(expectedFolderList, folderList) == false {
		t.Fatal(fmt.Sprintf("Found: %v\nExpected: %v\n", folderList, expectedFolderList))
	}

	err = tracker.DeleteFolder(folderTemplate[0])
	if err != nil {
		t.Fatal(err)
	}

	folderList = tracker.ListFolders()
	sort.Strings(folderList)

	folderTemplate = folderTemplate[1:]

	expectedFolderList = append(folderTemplate, ".")
	sort.Strings(expectedFolderList)

	if reflect.DeepEqual(folderList, expectedFolderList) == false {
		t.Fatal(fmt.Sprintf("Found: %v\nExpected: %v\n", folderList, expectedFolderList))
	}

}

func TestFileChangeTrackerAutoCreateFolderAndCleanup(t *testing.T) {
	tracker := new(FilesystemTracker)

	tmpFolder, err := ioutil.TempDir("", "blank")
	defer os.RemoveAll(tmpFolder)

	tmpFolder = tmpFolder + "R"
	defer os.RemoveAll(tmpFolder)

	logger := &LogOnlyChangeHandler{}
	var loggerInterface ChangeHandler = logger

	tracker.init(tmpFolder)
	tracker.watchDirectory(&loggerInterface)

	// verify the folder was created
	_, err = filepath.EvalSymlinks(tmpFolder)
	if err != nil {
		t.Fatal(err)
	}

	tracker.cleanup()
}

type countingChangeHandler struct {
	FoldersCreated int
	FoldersDeleted int
}

func (handler *countingChangeHandler) FolderCreated(name string) (error) {
	handler.FoldersCreated++

	fmt.Printf("countingChangeHandler:FolderCreated: %s (%d)\n", name, handler.FoldersCreated)
	return nil
}

func (handler *countingChangeHandler) FolderDeleted(name string) (error) {
	handler.FoldersDeleted++

	fmt.Printf("countingChangeHandler:FolderDeleted: %s (%d)\n", name, handler.FoldersDeleted)
	return nil
}

func TestFileChangeTrackerAddFolders(t *testing.T) {
	logHandler := countingChangeHandler{}
	var c ChangeHandler = &logHandler

	tmpFolder, err := ioutil.TempDir("", "blank")
	//tmpFolder := "/tmp/foot"
	defer os.RemoveAll(tmpFolder)

	fmt.Println("TestFileChangeTrackerAddFolders: About to call watchDirectory")
	tracker := new(FilesystemTracker)
	tracker.init(tmpFolder)
	defer tracker.cleanup()

	tracker.watchDirectory(&c)
	fmt.Println("TestFileChangeTrackerAddFolders: Done - About to call watchDirectory")

	numberOfSubFolders := 10

	for i := 0; i < numberOfSubFolders; i++ {
		path := fmt.Sprintf("%s/a%d", tmpFolder, i)

		err = os.Mkdir(path, os.ModeDir+os.ModePerm)
		if err != nil {
			t.Fatal(err)
		}
	}
	fmt.Printf("done with creating %d different subfolders. :)\n", numberOfSubFolders)

	cycleCount := 0
	for {
		cycleCount++
		folderList := tracker.ListFolders()
		if len(folderList) < numberOfSubFolders {
			//fmt.Printf("did not get all folders. Current: %v\n", folderList)
			if cycleCount > 200 {
				t.Fatalf("Did not find enough folders. Got bored of waiting. What was found: %v\n", folderList)
			}
			time.Sleep(time.Millisecond * 50)
		} else {
			fmt.Println("We have all of our ducks in a row")
			break
		}
	}

	folder1 := fmt.Sprintf("%s/a0", tmpFolder)
	folder2 := fmt.Sprintf("%s/a1", tmpFolder)
	fmt.Printf("about to delete two folders \n%s\n%s\n", folder1, folder2)
	// Delete two folders
	fmt.Println(tracker.ListFolders())
	os.Remove(folder1)
	os.Remove(folder2)
	fmt.Printf("deleted two folders \n%s\n%s\n", folder1, folder2)

	expectedCreated := numberOfSubFolders + 1
	expectedDeleted := 2

	// wait for the final tally to come through.
	cycleCount = 0
	for {
		cycleCount++

		if logHandler.FoldersCreated != expectedCreated || logHandler.FoldersDeleted != expectedDeleted {
			if cycleCount > 200 {
				fmt.Printf("Kept finding bad data. Got bored of waiting. What was found: %v\n", tracker.ListFolders())
				break
			}
			time.Sleep(time.Millisecond * 50)
		} else {
			fmt.Println("We have all of our ducks in a row again. Yay!")
			break
		}
	}

	if logHandler.FoldersCreated != expectedCreated || logHandler.FoldersDeleted != expectedDeleted {
		t.Fatalf("Expected/Found created: (%d/%d) deleted: (%d/%d)\n", expectedCreated, logHandler.FoldersCreated, expectedDeleted, logHandler.FoldersDeleted)
	}

	rootDirectory, exists := tracker.contents["."]
	if !exists {
		fmt.Println("root directory fileinfo is nil")
	} else {
		fmt.Printf("Root directory %v\n", rootDirectory)
		fmt.Printf("Root directory named: %s and has size %d\n", rootDirectory.Name(), rootDirectory.Size())
	}
}
<|endoftext|>


<commit_before>package sparta

// THIS FILE IS AUTOMATICALLY GENERATED
// DO NOT EDIT
// CREATED: 2020-11-30 03:41:11.304682 +0000 UTC

// SpartaGitHash is the commit hash of this Sparta library
const SpartaGitHash = "cc8c303b381f6e3a29ffa2f1b5f58b7016973ac9"
<commit_msg>"Autogenerated build info"<commit_after>package sparta

// THIS FILE IS AUTOMATICALLY GENERATED
// DO NOT EDIT
// CREATED: 2020-11-30 05:35:27.271707 +0000 UTC

// SpartaGitHash is the commit hash of this Sparta library
const SpartaGitHash = "4fe08214f3721d83a4e7937344cb3aa45f418820"
<|endoftext|>


<commit_before>package sparta

// THIS FILE IS AUTOMATICALLY GENERATED
// DO NOT EDIT
// CREATED: 2021-10-11 03:14:32.370438 +0000 UTC

// SpartaGitHash is the commit hash of this Sparta library
const SpartaGitHash = "33b2aa1faf9d56c1dc3fe103c66cc97ead05c1a1"
const SpartaGitShortHash = "33b2aa1f"
<commit_msg>"Autogenerated build info"<commit_after>package sparta

// THIS FILE IS AUTOMATICALLY GENERATED
// DO NOT EDIT
// CREATED: 2021-10-11 03:30:36.075887 +0000 UTC

// SpartaGitHash is the commit hash of this Sparta library
const SpartaGitHash = "7d7b7f3dfbd2f881edef2c80cd28cf020c7ccbe2"
const SpartaGitShortHash = "7d7b7f3"

<|endoftext|>


<commit_before>package sparta

// THIS FILE IS AUTOMATICALLY GENERATED
// DO NOT EDIT
// CREATED: 2019-08-11 20:07:53.985073 +0000 UTC

// SpartaGitHash is the commit hash of this Sparta library
const SpartaGitHash = "8f4e53643ca5ab3123aa5ea337d6baee623a3de0"
<commit_msg>"Autogenerated build info"<commit_after>package sparta

// THIS FILE IS AUTOMATICALLY GENERATED
// DO NOT EDIT
// CREATED: 2019-08-11 20:53:40.361775 +0000 UTC

// SpartaGitHash is the commit hash of this Sparta library
const SpartaGitHash = "e94156ce02cadc61acaefca47ed9cab88640ba03"
<|endoftext|>


<commit_before>package trousseau

import (
	"fmt"
	"github.com/codegangsta/cli"
	"github.com/oleiade/trousseau/crypto"
	"github.com/oleiade/trousseau/dsn"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strings"
	"time"
)

func CreateAction(c *cli.Context) {
	if !hasExpectedArgs(c.Args(), 1) {
		log.Fatal("Incorrect number of arguments to 'configure' command")
	}

	recipients := strings.Split(c.Args()[0], ",")

	opts := &crypto.Options{
		Algorithm:  crypto.GPG_ENCRYPTION,
		Passphrase: gPasshphrase,
		Recipients: recipients,
	}

	meta := Meta{
		CreatedAt:        time.Now().String(),
		LastModifiedAt:   time.Now().String(),
		Recipients:       recipients,
		TrousseauVersion: TROUSSEAU_VERSION,
	}

	// Create and write empty store file
	err := CreateStoreFile(gStorePath, opts, &meta)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Trousseau data store succesfully created")
}

func PushAction(c *cli.Context) {
	if !hasExpectedArgs(c.Args(), 1) {
		log.Fatal("Incorrect number of arguments to 'push' command")
	}

	endpointDsn, err := dsn.Parse(c.Args()[0])
	if err != nil {
		log.Fatal(err)
	}

	switch endpointDsn.Scheme {
	case "s3":
		err := endpointDsn.SetDefaults(gS3Defaults)
		if err != nil {
			log.Fatal(err)
		}

		err = uploadUsingS3(endpointDsn)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("Trousseau data store succesfully pushed to s3")
	case "scp":
		privateKey := c.String("ssh-private-key")

		err := endpointDsn.SetDefaults(gScpDefaults)
		if err != nil {
			log.Fatal(err)
		}

		if c.Bool("ask-password") == true {
			password := PromptForPassword()
			endpointDsn.Secret = password
		}

		err = uploadUsingScp(endpointDsn, privateKey)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("Trousseau data store succesfully pushed to ssh remote storage")
	case "gist":
		err = uploadUsingGist(endpointDsn)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("Trousseau data store succesfully pushed to gist")
	}
}

func PullAction(c *cli.Context) {
	if !hasExpectedArgs(c.Args(), 1) {
		log.Fatal("Incorrect number of arguments to 'pull' command")
	}

	endpointDsn, err := dsn.Parse(c.Args()[0])
	if err != nil {
		log.Fatal(err)
	}

	switch endpointDsn.Scheme {
	case "s3":
		err := endpointDsn.SetDefaults(gS3Defaults)
		if err != nil {
			log.Fatal(err)
		}

		err = DownloadUsingS3(endpointDsn)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("Trousseau data store succesfully pulled from S3")
	case "scp":
		privateKey := c.String("ssh-private-key")

		err := endpointDsn.SetDefaults(gScpDefaults)
		if err != nil {
			log.Fatal(err)
		}

		if c.Bool("ask-password") == true {
			password := PromptForPassword()
			endpointDsn.Secret = password
		}

		err = DownloadUsingScp(endpointDsn, privateKey)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("Trousseau data store succesfully pulled from ssh remote storage")
	case "gist":
		err = DownloadUsingGist(endpointDsn)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("Trousseau data store succesfully pulled from gist")
	default:
		if endpointDsn.Scheme == "" {
			log.Fatalf("No dsn scheme supplied")
		} else {
			log.Fatalf("Invalid dsn scheme supplied: %s", endpointDsn.Scheme)
		}
	}

	fmt.Printf("Trousseau data store succesfully pulled from remote storage")
}

func ExportAction(c *cli.Context) {
	if !hasExpectedArgs(c.Args(), 1) {
		log.Fatal("Incorrect number of arguments to 'export' command")
	}

	var err error
	var inputFilePath string = gStorePath
	var outputFilePath string = c.Args()[0]

	inputFile, err := os.Open(inputFilePath)
	defer inputFile.Close()
	if err != nil {
		log.Fatal(err)
	}

	outputFile, err := os.Create(outputFilePath)
	defer outputFile.Close()
	if err != nil {
		log.Fatal(err)
	}

	_, err = io.Copy(outputFile, inputFile)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Trousseau data store exported to %s", outputFilePath)
}

func ImportAction(c *cli.Context) {
	if !hasExpectedArgs(c.Args(), 1) {
		log.Fatal("Incorrect number of arguments to 'import' command")
	}

	var err error
	var importedFilePath string = c.Args()[0]
	var localFilePath string = gStorePath
	var strategy *ImportStrategy = new(ImportStrategy)

	// Transform provided merging startegy flags
	// into a proper ImportStrategy byte.
	err = strategy.FromCliContext(c)
	if err != nil {
		log.Fatal(err)
	}

	opts := &crypto.Options{
		Algorithm:  crypto.GPG_ENCRYPTION,
		Passphrase: gPasshphrase,
	}

	localStore, err := LoadStore(localFilePath, opts)
	if err != nil {
		log.Fatal(err)
	}

	importedStore, err := LoadStore(importedFilePath, opts)
	if err != nil {
		log.Fatal(err)
	}

	err = ImportStore(importedStore, localStore, *strategy)
	if err != nil {
		log.Fatal(err)
	}

	err = localStore.Sync()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Trousseau data store imported")
}

func AddRecipientAction(c *cli.Context) {
	if !hasExpectedArgs(c.Args(), 1) {
		log.Fatal("Incorrect number of arguments to 'add-recipient' command")
	}

	recipient := c.Args()[0]

	opts := &crypto.Options{
		Algorithm:  crypto.GPG_ENCRYPTION,
		Passphrase: gPasshphrase,
	}

	store, err := LoadStore(gStorePath, opts)
	if err != nil {
		log.Fatal(err)
	}

	err = store.DataStore.Meta.AddRecipient(recipient)

	err = store.Sync()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%s recipient added to trousseau data store", recipient)
}

func RemoveRecipientAction(c *cli.Context) {
	if !hasExpectedArgs(c.Args(), 1) {
		log.Fatal("Incorrect number of arguments to 'remove-recipient' command")
	}

	recipient := c.Args()[0]

	opts := &crypto.Options{
		Algorithm:  crypto.GPG_ENCRYPTION,
		Passphrase: gPasshphrase,
	}

	store, err := LoadStore(gStorePath, opts)
	if err != nil {
		log.Fatal(err)
	}

	err = store.Meta.RemoveRecipient(recipient)

	err = store.Sync()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%s recipient removed from trousseau data store", recipient)
}

func GetAction(c *cli.Context) {
	if !hasExpectedArgs(c.Args(), 1) {
		log.Fatal("Incorrect number of arguments to 'get' command")
	}

	opts := &crypto.Options{
		Algorithm:  crypto.GPG_ENCRYPTION,
		Passphrase: gPasshphrase,
	}

	store, err := LoadStore(gStorePath, opts)
	if err != nil {
		log.Fatal(err)
	}

	value, err := store.Get(c.Args()[0])
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%s key's value: %s\n", c.Args()[0], value)
}

func SetAction(c *cli.Context) {
	var key string
	var value interface{}
	var err error

	// If the --file flag is provided
	if c.String("file") != "" && hasExpectedArgs(c.Args(), 1) {
		// And the file actually exists on file system
		if pathExists(c.String("file")) {
			// Then load it's content
			value, err = ioutil.ReadFile(c.String("file"))
			if err != nil {
				log.Fatal(err)
			}
		} else {
			log.Fatalf("Cannot open %s because it doesn't exist", c.String("file"))
		}
	} else if c.String("file") == "" && hasExpectedArgs(c.Args(), 2) {
		value = c.Args()[1]
	} else {
		log.Fatal("Incorrect number of arguments to 'set' command")
	}

	opts := &crypto.Options{
		Algorithm:  crypto.GPG_ENCRYPTION,
		Passphrase: gPasshphrase,
	}

	store, err := LoadStore(gStorePath, opts)
	if err != nil {
		log.Fatal(err)
	}

	err = store.Set(key, value)
	if err != nil {
		log.Fatal(err)
	}

	err = store.Sync()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("key-value pair set: %s:%s\n", key, value)
}

func DelAction(c *cli.Context) {
	if !hasExpectedArgs(c.Args(), 1) {
		log.Fatal("Incorrect number of arguments to 'del' command")
	}

	opts := &crypto.Options{
		Algorithm:  crypto.GPG_ENCRYPTION,
		Passphrase: gPasshphrase,
	}

	store, err := LoadStore(gStorePath, opts)
	if err != nil {
		log.Fatal(err)
	}

	err = store.Del(c.Args()[0])
	if err != nil {
		log.Fatal(err)
	}

	err = store.Sync()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%s key deleted\n", c.Args()[0])
}

func KeysAction(c *cli.Context) {
	if !hasExpectedArgs(c.Args(), 0) {
		log.Fatal("Incorrect number of arguments to 'keys' command")
	}

	opts := &crypto.Options{
		Algorithm:  crypto.GPG_ENCRYPTION,
		Passphrase: gPasshphrase,
	}

	store, err := LoadStore(gStorePath, opts)
	if err != nil {
		log.Fatal(err)
	}

	keys, err := store.Keys()
	if err != nil {
		log.Fatal(err)
	} else {
		for _, k := range keys {
			fmt.Println(k)
		}
	}
}

func ShowAction(c *cli.Context) {
	if !hasExpectedArgs(c.Args(), 0) {
		log.Fatal("Incorrect number of arguments to 'show' command")
	}

	opts := &crypto.Options{
		Algorithm:  crypto.GPG_ENCRYPTION,
		Passphrase: gPasshphrase,
	}

	store, err := LoadStore(gStorePath, opts)
	if err != nil {
		log.Fatal(err)
	}

	pairs, err := store.Items()
	if err != nil {
		log.Fatal(err)
	} else {
		for _, pair := range pairs {
			fmt.Printf("%s: %s\n", pair.Key, pair.Value)
		}
	}
}

func MetaAction(c *cli.Context) {
	if !hasExpectedArgs(c.Args(), 0) {
		log.Fatal("Incorrect number of arguments to 'meta' command")
	}

	opts := &crypto.Options{
		Algorithm:  crypto.GPG_ENCRYPTION,
		Passphrase: gPasshphrase,
	}

	store, err := LoadStore(gStorePath, opts)
	if err != nil {
		log.Fatal(err)
	}

	pairs, err := store.Metadata()
	if err != nil {
		log.Fatal(err)
	}

	for _, pair := range pairs {
		fmt.Printf("%s: %s\n", pair.Key, pair.Value)
	}
}

// hasExpectedArgs checks whether the number of args are as expected.
func hasExpectedArgs(args []string, expected int) bool {
	switch expected {
	case -1:
		if len(args) > 0 {
			return true
		} else {
			return false
		}
	default:
		if len(args) == expected {
			return true
		} else {
			return false
		}
	}
}
<commit_msg>Fix a bug where the key is always empty when set a key.<commit_after>package trousseau

import (
	"fmt"
	"github.com/codegangsta/cli"
	"github.com/oleiade/trousseau/crypto"
	"github.com/oleiade/trousseau/dsn"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strings"
	"time"
)

func CreateAction(c *cli.Context) {
	if !hasExpectedArgs(c.Args(), 1) {
		log.Fatal("Incorrect number of arguments to 'configure' command")
	}

	recipients := strings.Split(c.Args()[0], ",")

	opts := &crypto.Options{
		Algorithm:  crypto.GPG_ENCRYPTION,
		Passphrase: gPasshphrase,
		Recipients: recipients,
	}

	meta := Meta{
		CreatedAt:        time.Now().String(),
		LastModifiedAt:   time.Now().String(),
		Recipients:       recipients,
		TrousseauVersion: TROUSSEAU_VERSION,
	}

	// Create and write empty store file
	err := CreateStoreFile(gStorePath, opts, &meta)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Trousseau data store succesfully created")
}

func PushAction(c *cli.Context) {
	if !hasExpectedArgs(c.Args(), 1) {
		log.Fatal("Incorrect number of arguments to 'push' command")
	}

	endpointDsn, err := dsn.Parse(c.Args()[0])
	if err != nil {
		log.Fatal(err)
	}

	switch endpointDsn.Scheme {
	case "s3":
		err := endpointDsn.SetDefaults(gS3Defaults)
		if err != nil {
			log.Fatal(err)
		}

		err = uploadUsingS3(endpointDsn)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("Trousseau data store succesfully pushed to s3")
	case "scp":
		privateKey := c.String("ssh-private-key")

		err := endpointDsn.SetDefaults(gScpDefaults)
		if err != nil {
			log.Fatal(err)
		}

		if c.Bool("ask-password") == true {
			password := PromptForPassword()
			endpointDsn.Secret = password
		}

		err = uploadUsingScp(endpointDsn, privateKey)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("Trousseau data store succesfully pushed to ssh remote storage")
	case "gist":
		err = uploadUsingGist(endpointDsn)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("Trousseau data store succesfully pushed to gist")
	}
}

func PullAction(c *cli.Context) {
	if !hasExpectedArgs(c.Args(), 1) {
		log.Fatal("Incorrect number of arguments to 'pull' command")
	}

	endpointDsn, err := dsn.Parse(c.Args()[0])
	if err != nil {
		log.Fatal(err)
	}

	switch endpointDsn.Scheme {
	case "s3":
		err := endpointDsn.SetDefaults(gS3Defaults)
		if err != nil {
			log.Fatal(err)
		}

		err = DownloadUsingS3(endpointDsn)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("Trousseau data store succesfully pulled from S3")
	case "scp":
		privateKey := c.String("ssh-private-key")

		err := endpointDsn.SetDefaults(gScpDefaults)
		if err != nil {
			log.Fatal(err)
		}

		if c.Bool("ask-password") == true {
			password := PromptForPassword()
			endpointDsn.Secret = password
		}

		err = DownloadUsingScp(endpointDsn, privateKey)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("Trousseau data store succesfully pulled from ssh remote storage")
	case "gist":
		err = DownloadUsingGist(endpointDsn)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("Trousseau data store succesfully pulled from gist")
	default:
		if endpointDsn.Scheme == "" {
			log.Fatalf("No dsn scheme supplied")
		} else {
			log.Fatalf("Invalid dsn scheme supplied: %s", endpointDsn.Scheme)
		}
	}

	fmt.Printf("Trousseau data store succesfully pulled from remote storage")
}

func ExportAction(c *cli.Context) {
	if !hasExpectedArgs(c.Args(), 1) {
		log.Fatal("Incorrect number of arguments to 'export' command")
	}

	var err error
	var inputFilePath string = gStorePath
	var outputFilePath string = c.Args()[0]

	inputFile, err := os.Open(inputFilePath)
	defer inputFile.Close()
	if err != nil {
		log.Fatal(err)
	}

	outputFile, err := os.Create(outputFilePath)
	defer outputFile.Close()
	if err != nil {
		log.Fatal(err)
	}

	_, err = io.Copy(outputFile, inputFile)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Trousseau data store exported to %s", outputFilePath)
}

func ImportAction(c *cli.Context) {
	if !hasExpectedArgs(c.Args(), 1) {
		log.Fatal("Incorrect number of arguments to 'import' command")
	}

	var err error
	var importedFilePath string = c.Args()[0]
	var localFilePath string = gStorePath
	var strategy *ImportStrategy = new(ImportStrategy)

	// Transform provided merging startegy flags
	// into a proper ImportStrategy byte.
	err = strategy.FromCliContext(c)
	if err != nil {
		log.Fatal(err)
	}

	opts := &crypto.Options{
		Algorithm:  crypto.GPG_ENCRYPTION,
		Passphrase: gPasshphrase,
	}

	localStore, err := LoadStore(localFilePath, opts)
	if err != nil {
		log.Fatal(err)
	}

	importedStore, err := LoadStore(importedFilePath, opts)
	if err != nil {
		log.Fatal(err)
	}

	err = ImportStore(importedStore, localStore, *strategy)
	if err != nil {
		log.Fatal(err)
	}

	err = localStore.Sync()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Trousseau data store imported")
}

func AddRecipientAction(c *cli.Context) {
	if !hasExpectedArgs(c.Args(), 1) {
		log.Fatal("Incorrect number of arguments to 'add-recipient' command")
	}

	recipient := c.Args()[0]

	opts := &crypto.Options{
		Algorithm:  crypto.GPG_ENCRYPTION,
		Passphrase: gPasshphrase,
	}

	store, err := LoadStore(gStorePath, opts)
	if err != nil {
		log.Fatal(err)
	}

	err = store.DataStore.Meta.AddRecipient(recipient)

	err = store.Sync()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%s recipient added to trousseau data store", recipient)
}

func RemoveRecipientAction(c *cli.Context) {
	if !hasExpectedArgs(c.Args(), 1) {
		log.Fatal("Incorrect number of arguments to 'remove-recipient' command")
	}

	recipient := c.Args()[0]

	opts := &crypto.Options{
		Algorithm:  crypto.GPG_ENCRYPTION,
		Passphrase: gPasshphrase,
	}

	store, err := LoadStore(gStorePath, opts)
	if err != nil {
		log.Fatal(err)
	}

	err = store.Meta.RemoveRecipient(recipient)

	err = store.Sync()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%s recipient removed from trousseau data store", recipient)
}

func GetAction(c *cli.Context) {
	if !hasExpectedArgs(c.Args(), 1) {
		log.Fatal("Incorrect number of arguments to 'get' command")
	}

	opts := &crypto.Options{
		Algorithm:  crypto.GPG_ENCRYPTION,
		Passphrase: gPasshphrase,
	}

	store, err := LoadStore(gStorePath, opts)
	if err != nil {
		log.Fatal(err)
	}

	value, err := store.Get(c.Args()[0])
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%s key's value: %s\n", c.Args()[0], value)
}

func SetAction(c *cli.Context) {
	var key string
	var value interface{}
	var err error

	// If the --file flag is provided
	if c.String("file") != "" && hasExpectedArgs(c.Args(), 1) {
		// And the file actually exists on file system
		if pathExists(c.String("file")) {
			// Then load it's content
			value, err = ioutil.ReadFile(c.String("file"))
			if err != nil {
				log.Fatal(err)
			}
		} else {
			log.Fatalf("Cannot open %s because it doesn't exist", c.String("file"))
		}
	} else if c.String("file") == "" && hasExpectedArgs(c.Args(), 2) {
		value = c.Args()[1]
	} else {
		log.Fatal("Incorrect number of arguments to 'set' command")
	}

  key = c.Args()[0]

	opts := &crypto.Options{
		Algorithm:  crypto.GPG_ENCRYPTION,
		Passphrase: gPasshphrase,
	}

	store, err := LoadStore(gStorePath, opts)
	if err != nil {
		log.Fatal(err)
	}

	err = store.Set(key, value)
	if err != nil {
		log.Fatal(err)
	}

	err = store.Sync()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("key-value pair set: %s:%s\n", key, value)
}

func DelAction(c *cli.Context) {
	if !hasExpectedArgs(c.Args(), 1) {
		log.Fatal("Incorrect number of arguments to 'del' command")
	}

	opts := &crypto.Options{
		Algorithm:  crypto.GPG_ENCRYPTION,
		Passphrase: gPasshphrase,
	}

	store, err := LoadStore(gStorePath, opts)
	if err != nil {
		log.Fatal(err)
	}

	err = store.Del(c.Args()[0])
	if err != nil {
		log.Fatal(err)
	}

	err = store.Sync()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%s key deleted\n", c.Args()[0])
}

func KeysAction(c *cli.Context) {
	if !hasExpectedArgs(c.Args(), 0) {
		log.Fatal("Incorrect number of arguments to 'keys' command")
	}

	opts := &crypto.Options{
		Algorithm:  crypto.GPG_ENCRYPTION,
		Passphrase: gPasshphrase,
	}

	store, err := LoadStore(gStorePath, opts)
	if err != nil {
		log.Fatal(err)
	}

	keys, err := store.Keys()
	if err != nil {
		log.Fatal(err)
	} else {
		for _, k := range keys {
			fmt.Println(k)
		}
	}
}

func ShowAction(c *cli.Context) {
	if !hasExpectedArgs(c.Args(), 0) {
		log.Fatal("Incorrect number of arguments to 'show' command")
	}

	opts := &crypto.Options{
		Algorithm:  crypto.GPG_ENCRYPTION,
		Passphrase: gPasshphrase,
	}

	store, err := LoadStore(gStorePath, opts)
	if err != nil {
		log.Fatal(err)
	}

	pairs, err := store.Items()
	if err != nil {
		log.Fatal(err)
	} else {
		for _, pair := range pairs {
			fmt.Printf("%s: %s\n", pair.Key, pair.Value)
		}
	}
}

func MetaAction(c *cli.Context) {
	if !hasExpectedArgs(c.Args(), 0) {
		log.Fatal("Incorrect number of arguments to 'meta' command")
	}

	opts := &crypto.Options{
		Algorithm:  crypto.GPG_ENCRYPTION,
		Passphrase: gPasshphrase,
	}

	store, err := LoadStore(gStorePath, opts)
	if err != nil {
		log.Fatal(err)
	}

	pairs, err := store.Metadata()
	if err != nil {
		log.Fatal(err)
	}

	for _, pair := range pairs {
		fmt.Printf("%s: %s\n", pair.Key, pair.Value)
	}
}

// hasExpectedArgs checks whether the number of args are as expected.
func hasExpectedArgs(args []string, expected int) bool {
	switch expected {
	case -1:
		if len(args) > 0 {
			return true
		} else {
			return false
		}
	default:
		if len(args) == expected {
			return true
		} else {
			return false
		}
	}
}
<|endoftext|>


<commit_before>package tui_test

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

	"github.com/starkandwayne/shield/tui"
)

var _ = Describe("Cell Management", func() {
	Context("with the empty string", func() {
		c := tui.ParseCell("")

		It("should calculate the width as 0", func() {
			Ω(c.Width()).Should(Equal(0))
		})
		It("should calculate the height as 1", func() {
			Ω(c.Height()).Should(Equal(1))
		})
		It("should return the empty string for all line indices", func() {
			Ω(c.Line(0)).Should(Equal(""))
			Ω(c.Line(1)).Should(Equal(""))
			Ω(c.Line(9)).Should(Equal(""))
		})
	})

	Context("with single-line strings", func() {
		c := tui.ParseCell("hello")

		It("should calculate the width as the length of the string", func() {
			Ω(c.Width()).Should(Equal(len("hello")))
		})
		It("should calculate the height as 1", func() {
			Ω(c.Height()).Should(Equal(1))
		})
		It("should return the original string for line 0", func() {
			Ω(c.Line(0)).Should(Equal("hello"))
		})
		It("should return the empty string for all line indices > 0", func() {
			Ω(c.Line(1)).Should(Equal(""))
			Ω(c.Line(5)).Should(Equal(""))
			Ω(c.Line(9)).Should(Equal(""))
		})
	})

	Context("with a newline-terminated single-line strings", func() {
		c := tui.ParseCell("hello\n")

		It("should calculate the width as the length of the string", func() {
			Ω(c.Width()).Should(Equal(len("hello")))
		})
		It("should calculate the height as 1", func() {
			Ω(c.Height()).Should(Equal(1))
		})
		It("should return the original string (sans-newline) for line 0", func() {
			Ω(c.Line(0)).Should(Equal("hello"))
		})
		It("should return the empty string for all line indices > 0", func() {
			Ω(c.Line(1)).Should(Equal(""))
			Ω(c.Line(5)).Should(Equal(""))
			Ω(c.Line(9)).Should(Equal(""))
		})
	})

	Context("with a multi-line string", func() {
		c := tui.ParseCell("hi\n" + "hello\n" + "hiya")

		It("should calculate the width as the length of the longest line", func() {
			Ω(c.Width()).Should(Equal(len("hello")))
		})
		It("should calculate the height as the number of lines", func() {
			Ω(c.Height()).Should(Equal(3))
		})
		It("should return the the correct subsstring (sans-newline) for indices 0 - 2", func() {
			Ω(c.Line(0)).Should(Equal("hi"))
			Ω(c.Line(1)).Should(Equal("hello"))
			Ω(c.Line(2)).Should(Equal("hiya"))
		})
		It("should return the empty string for all line indices > 2", func() {
			Ω(c.Line(3)).Should(Equal(""))
			Ω(c.Line(5)).Should(Equal(""))
			Ω(c.Line(9)).Should(Equal(""))
		})
	})

	Context("with a newline-terminated multi-line string", func() {
		c := tui.ParseCell("hi\n" + "hello\n" + "hiya\n")

		It("should calculate the width as the length of the longest line", func() {
			Ω(c.Width()).Should(Equal(len("hello")))
		})
		It("should calculate the height as the number of lines", func() {
			Ω(c.Height()).Should(Equal(3))
		})
		It("should return the the correct subsstring (sans-newline) for indices 0 - 2", func() {
			Ω(c.Line(0)).Should(Equal("hi"))
			Ω(c.Line(1)).Should(Equal("hello"))
			Ω(c.Line(2)).Should(Equal("hiya"))
		})
		It("should return the empty string for all line indices > 2", func() {
			Ω(c.Line(3)).Should(Equal(""))
			Ω(c.Line(5)).Should(Equal(""))
			Ω(c.Line(9)).Should(Equal(""))
		})
	})
})

var _ = Describe("Row Management", func() {
	Context("with no cells", func() {
		r := tui.ParseRow()

		It("should calculate the width as 0", func() {
			Ω(r.Width()).Should(Equal(0))
		})
		It("should calculate the height as 0", func() {
			Ω(r.Height()).Should(Equal(0))
		})
	})

	Context("with a single empty string", func() {
		r := tui.ParseRow("")

		It("should calculate the width as the width of the cell", func() {
			Ω(r.Width()).Should(Equal(0))
		})
		It("should calculate the height as the height of the cell", func() {
			Ω(r.Height()).Should(Equal(1))
		})
	})

	Context("with a solitary, single-line string", func() {
		r := tui.ParseRow("hello")

		It("should calculate the width as the width of the cell", func() {
			Ω(r.Width()).Should(Equal(5))
		})
		It("should calculate the height as the height of the cell", func() {
			Ω(r.Height()).Should(Equal(1))
		})
	})

	Context("with a mix of different line-lengths and line-counts", func() {
		r := tui.ParseRow(
			"To a Mouse", // 10

			"Wee, sleekit, cowrin, tim'rous beastie,\n"+ // 39
				"O, what a panic's in thy breastie!\n",

			"Thou need na start awa sae hasty,\n"+
				"Wi' bickering brattle!\n"+
				"I wad be laith to rin an' chase thee,\n"+ // 37
				"Wi' murdering pattle!\n",
		)

		It("should calculate the width as the sum of the cell widths, plus padding", func() {
			Ω(r.Width()).Should(Equal(10 + 2 + 39 + 2 + 37))
		})
		It("should calculate the height as the height of the tallest cell", func() {
			Ω(r.Height()).Should(Equal(4))
		})
	})
})

var _ = Describe("Table Management", func() {
	Context("with a 1x1 configuration", func() {
		t := tui.NewGrid("header")
		t.Row("hello")

		It("should format data properly", func() {
			Ω(t.Height()).Should(Equal(3))
			Ω(t.Line(0)).Should(Equal("header\n"), `first line`)
			Ω(t.Line(1)).Should(Equal("======\n"), `second line`)
			Ω(t.Line(2)).Should(Equal("hello\n"), `third line`)
		})
	})
	Context("with a 1x3 configuration", func() {
		t := tui.NewGrid("a", "b", "c")
		t.Row("first", "second", "third")

		It("should format data properly", func() {
			Ω(t.Height()).Should(Equal(3))
			Ω(t.Line(0)).Should(Equal("a      b       c\n"), `first line`)
			Ω(t.Line(1)).Should(Equal("=      =       =\n"), `second line`)
			Ω(t.Line(2)).Should(Equal("first  second  third\n"), `third line`)
		})
	})
	Context("with a 4x1 configuration", func() {
		t := tui.NewGrid("Superheroes")
		t.Row("Batman")
		t.Row("Iron Man")
		t.Row("The Green Lantern")
		t.Row("Deadpool(?)")

		It("should format data properly", func() {
			Ω(t.Height()).Should(Equal(6))
			Ω(t.Line(0)).Should(Equal("Superheroes\n"), `first line`)
			Ω(t.Line(1)).Should(Equal("===========\n"), `second line`)
			Ω(t.Line(2)).Should(Equal("Batman\n"), `third line`)
			Ω(t.Line(3)).Should(Equal("Iron Man\n"), `fourth line`)
			Ω(t.Line(4)).Should(Equal("The Green Lantern\n"), `fifth line`)
			Ω(t.Line(5)).Should(Equal("Deadpool(?)\n"), `sixth line`)
		})
	})
	Context("with a 5x2 configuration", func() {
		t := tui.NewGrid("Superhero", "Secret Identity")
		t.Row("Batman", "Bruce Wayne")
		t.Row("Iron Man", "Tony Stark")
		t.Row("The Green Lantern", "Alan / Hal / Guy / Kyle / John")
		t.Row("Deadpool(?)", "Wade Winston Wilson")
		t.Row("The Spectre", "Jim Corrigan")

		It("should format data properly", func() {
			Ω(t.Height()).Should(Equal(7))
			Ω(t.Line(0)).Should(Equal("Superhero          Secret Identity\n"), `first line`)
			Ω(t.Line(1)).Should(Equal("=========          ===============\n"), `second line`)
			Ω(t.Line(2)).Should(Equal("Batman             Bruce Wayne\n"), `third line`)
			Ω(t.Line(3)).Should(Equal("Iron Man           Tony Stark\n"), `fourth line`)
			Ω(t.Line(4)).Should(Equal("The Green Lantern  Alan / Hal / Guy / Kyle / John\n"), `fifth line`)
			Ω(t.Line(5)).Should(Equal("Deadpool(?)        Wade Winston Wilson\n"), `sixth line`)
			Ω(t.Line(6)).Should(Equal("The Spectre        Jim Corrigan\n"), `seventh line`)
		})
	})
	Context("with multi-line cells", func() {
		t := tui.NewGrid("Superhero", "Origin City")
		t.Row("Batman", "Gotham City")
		t.Row("Iron Man", "New York\n(New York, NY)\nunconfirmed")
		t.Row("The Green Lantern\n(Hal Jordan)\n", "Coast City")

		It("should format data properly", func() {
			Ω(t.Height()).Should(Equal(8))
			Ω(t.Line(0)).Should(Equal("Superhero          Origin City\n"), `first line`)
			Ω(t.Line(1)).Should(Equal("=========          ===========\n"), `second line`)
			Ω(t.Line(2)).Should(Equal("Batman             Gotham City\n"), `third line`)
			Ω(t.Line(3)).Should(Equal("Iron Man           New York\n"), `fourth line`)
			Ω(t.Line(4)).Should(Equal("                   (New York, NY)\n"), `fifth line`)
			Ω(t.Line(5)).Should(Equal("                   unconfirmed\n"), `sixth line`)
			Ω(t.Line(6)).Should(Equal("The Green Lantern  Coast City\n"), `seventh line`)
			Ω(t.Line(7)).Should(Equal("(Hal Jordan)\n"), `eighth line`)
		})
	})
	Context("with single-line cells and indexing turned on", func() {
		t := tui.NewIndexedGrid("Superhero", "Origin City")
		t.Row("Batman", "Gotham City")
		t.Row("Iron Man", "New York")
		t.Row("The Green Lantern", "Coast City")

		It("should format data properly", func() {
			Ω(t.Height()).Should(Equal(5))
			Ω(t.Line(0)).Should(Equal("      Superhero          Origin City\n"), `first line`)
			Ω(t.Line(1)).Should(Equal("      =========          ===========\n"), `second line`)
			Ω(t.Line(2)).Should(Equal("   1) Batman             Gotham City\n"), `third line`)
			Ω(t.Line(3)).Should(Equal("   2) Iron Man           New York\n"), `fourth line`)
			Ω(t.Line(4)).Should(Equal("   3) The Green Lantern  Coast City\n"), `fifth line`)
		})
	})
	Context("with multi-line cells and indexing turned on", func() {
		t := tui.NewIndexedGrid("Superhero", "Origin City")
		t.Row("Batman", "Gotham City")
		t.Row("Iron Man", "New York\n(New York, NY)\nunconfirmed")
		t.Row("The Green Lantern\n(Hal Jordan)\n", "Coast City")

		It("should format data properly", func() {
			Ω(t.Height()).Should(Equal(8))
			Ω(t.Line(0)).Should(Equal("      Superhero          Origin City\n"), `first line`)
			Ω(t.Line(1)).Should(Equal("      =========          ===========\n"), `second line`)
			Ω(t.Line(2)).Should(Equal("   1) Batman             Gotham City\n"), `third line`)
			Ω(t.Line(3)).Should(Equal("   2) Iron Man           New York\n"), `fourth line`)
			Ω(t.Line(4)).Should(Equal("                         (New York, NY)\n"), `fifth line`)
			Ω(t.Line(5)).Should(Equal("                         unconfirmed\n"), `sixth line`)
			Ω(t.Line(6)).Should(Equal("   3) The Green Lantern  Coast City\n"), `seventh line`)
			Ω(t.Line(7)).Should(Equal("      (Hal Jordan)\n"), `eighth line`)
		})
	})
})
<commit_msg>Clean up typos in some test verbiage<commit_after>package tui_test

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

	"github.com/starkandwayne/shield/tui"
)

var _ = Describe("Cell Management", func() {
	Context("with the empty string", func() {
		c := tui.ParseCell("")

		It("should calculate the width as 0", func() {
			Ω(c.Width()).Should(Equal(0))
		})
		It("should calculate the height as 1", func() {
			Ω(c.Height()).Should(Equal(1))
		})
		It("should return the empty string for all line indices", func() {
			Ω(c.Line(0)).Should(Equal(""))
			Ω(c.Line(1)).Should(Equal(""))
			Ω(c.Line(9)).Should(Equal(""))
		})
	})

	Context("with a single-line string", func() {
		c := tui.ParseCell("hello")

		It("should calculate the width as the length of the string", func() {
			Ω(c.Width()).Should(Equal(len("hello")))
		})
		It("should calculate the height as 1", func() {
			Ω(c.Height()).Should(Equal(1))
		})
		It("should return the original string for line 0", func() {
			Ω(c.Line(0)).Should(Equal("hello"))
		})
		It("should return the empty string for all line indices > 0", func() {
			Ω(c.Line(1)).Should(Equal(""))
			Ω(c.Line(5)).Should(Equal(""))
			Ω(c.Line(9)).Should(Equal(""))
		})
	})

	Context("with a newline-terminated single-line string", func() {
		c := tui.ParseCell("hello\n")

		It("should calculate the width as the length of the string", func() {
			Ω(c.Width()).Should(Equal(len("hello")))
		})
		It("should calculate the height as 1", func() {
			Ω(c.Height()).Should(Equal(1))
		})
		It("should return the original string (without the newline) for line 0", func() {
			Ω(c.Line(0)).Should(Equal("hello"))
		})
		It("should return the empty string for all line indices > 0", func() {
			Ω(c.Line(1)).Should(Equal(""))
			Ω(c.Line(5)).Should(Equal(""))
			Ω(c.Line(9)).Should(Equal(""))
		})
	})

	Context("with a multi-line string", func() {
		c := tui.ParseCell("hi\n" + "hello\n" + "hiya")

		It("should calculate the width as the length of the longest line", func() {
			Ω(c.Width()).Should(Equal(len("hello")))
		})
		It("should calculate the height as the number of lines", func() {
			Ω(c.Height()).Should(Equal(3))
		})
		It("should return the the correct substring (without the newline) for indices 0 - 2", func() {
			Ω(c.Line(0)).Should(Equal("hi"))
			Ω(c.Line(1)).Should(Equal("hello"))
			Ω(c.Line(2)).Should(Equal("hiya"))
		})
		It("should return the empty string for all line indices > 2", func() {
			Ω(c.Line(3)).Should(Equal(""))
			Ω(c.Line(5)).Should(Equal(""))
			Ω(c.Line(9)).Should(Equal(""))
		})
	})

	Context("with a newline-terminated multi-line string", func() {
		c := tui.ParseCell("hi\n" + "hello\n" + "hiya\n")

		It("should calculate the width as the length of the longest line", func() {
			Ω(c.Width()).Should(Equal(len("hello")))
		})
		It("should calculate the height as the number of lines", func() {
			Ω(c.Height()).Should(Equal(3))
		})
		It("should return the the correct substring (without the newline) for indices 0 - 2", func() {
			Ω(c.Line(0)).Should(Equal("hi"))
			Ω(c.Line(1)).Should(Equal("hello"))
			Ω(c.Line(2)).Should(Equal("hiya"))
		})
		It("should return the empty string for all line indices > 2", func() {
			Ω(c.Line(3)).Should(Equal(""))
			Ω(c.Line(5)).Should(Equal(""))
			Ω(c.Line(9)).Should(Equal(""))
		})
	})
})

var _ = Describe("Row Management", func() {
	Context("with no cells", func() {
		r := tui.ParseRow()

		It("should calculate the width as 0", func() {
			Ω(r.Width()).Should(Equal(0))
		})
		It("should calculate the height as 0", func() {
			Ω(r.Height()).Should(Equal(0))
		})
	})

	Context("with a single empty string", func() {
		r := tui.ParseRow("")

		It("should calculate the width as the width of the cell", func() {
			Ω(r.Width()).Should(Equal(0))
		})
		It("should calculate the height as the height of the cell", func() {
			Ω(r.Height()).Should(Equal(1))
		})
	})

	Context("with a solitary, single-line string", func() {
		r := tui.ParseRow("hello")

		It("should calculate the width as the width of the cell", func() {
			Ω(r.Width()).Should(Equal(5))
		})
		It("should calculate the height as the height of the cell", func() {
			Ω(r.Height()).Should(Equal(1))
		})
	})

	Context("with a mix of different line-lengths and line-counts", func() {
		r := tui.ParseRow(
			"To a Mouse", // 10

			"Wee, sleekit, cowrin, tim'rous beastie,\n"+ // 39
				"O, what a panic's in thy breastie!\n",

			"Thou need na start awa sae hasty,\n"+
				"Wi' bickering brattle!\n"+
				"I wad be laith to rin an' chase thee,\n"+ // 37
				"Wi' murdering pattle!\n",
		)

		It("should calculate the width as the sum of the cell widths, plus padding", func() {
			Ω(r.Width()).Should(Equal(10 + 2 + 39 + 2 + 37))
		})
		It("should calculate the height as the height of the tallest cell", func() {
			Ω(r.Height()).Should(Equal(4))
		})
	})
})

var _ = Describe("Table Management", func() {
	Context("with a 1x1 configuration", func() {
		t := tui.NewGrid("header")
		t.Row("hello")

		It("should format data properly", func() {
			Ω(t.Height()).Should(Equal(3))
			Ω(t.Line(0)).Should(Equal("header\n"), `first line`)
			Ω(t.Line(1)).Should(Equal("======\n"), `second line`)
			Ω(t.Line(2)).Should(Equal("hello\n"), `third line`)
		})
	})
	Context("with a 1x3 configuration", func() {
		t := tui.NewGrid("a", "b", "c")
		t.Row("first", "second", "third")

		It("should format data properly", func() {
			Ω(t.Height()).Should(Equal(3))
			Ω(t.Line(0)).Should(Equal("a      b       c\n"), `first line`)
			Ω(t.Line(1)).Should(Equal("=      =       =\n"), `second line`)
			Ω(t.Line(2)).Should(Equal("first  second  third\n"), `third line`)
		})
	})
	Context("with a 4x1 configuration", func() {
		t := tui.NewGrid("Superheroes")
		t.Row("Batman")
		t.Row("Iron Man")
		t.Row("The Green Lantern")
		t.Row("Deadpool(?)")

		It("should format data properly", func() {
			Ω(t.Height()).Should(Equal(6))
			Ω(t.Line(0)).Should(Equal("Superheroes\n"), `first line`)
			Ω(t.Line(1)).Should(Equal("===========\n"), `second line`)
			Ω(t.Line(2)).Should(Equal("Batman\n"), `third line`)
			Ω(t.Line(3)).Should(Equal("Iron Man\n"), `fourth line`)
			Ω(t.Line(4)).Should(Equal("The Green Lantern\n"), `fifth line`)
			Ω(t.Line(5)).Should(Equal("Deadpool(?)\n"), `sixth line`)
		})
	})
	Context("with a 5x2 configuration", func() {
		t := tui.NewGrid("Superhero", "Secret Identity")
		t.Row("Batman", "Bruce Wayne")
		t.Row("Iron Man", "Tony Stark")
		t.Row("The Green Lantern", "Alan / Hal / Guy / Kyle / John")
		t.Row("Deadpool(?)", "Wade Winston Wilson")
		t.Row("The Spectre", "Jim Corrigan")

		It("should format data properly", func() {
			Ω(t.Height()).Should(Equal(7))
			Ω(t.Line(0)).Should(Equal("Superhero          Secret Identity\n"), `first line`)
			Ω(t.Line(1)).Should(Equal("=========          ===============\n"), `second line`)
			Ω(t.Line(2)).Should(Equal("Batman             Bruce Wayne\n"), `third line`)
			Ω(t.Line(3)).Should(Equal("Iron Man           Tony Stark\n"), `fourth line`)
			Ω(t.Line(4)).Should(Equal("The Green Lantern  Alan / Hal / Guy / Kyle / John\n"), `fifth line`)
			Ω(t.Line(5)).Should(Equal("Deadpool(?)        Wade Winston Wilson\n"), `sixth line`)
			Ω(t.Line(6)).Should(Equal("The Spectre        Jim Corrigan\n"), `seventh line`)
		})
	})
	Context("with multi-line cells", func() {
		t := tui.NewGrid("Superhero", "Origin City")
		t.Row("Batman", "Gotham City")
		t.Row("Iron Man", "New York\n(New York, NY)\nunconfirmed")
		t.Row("The Green Lantern\n(Hal Jordan)\n", "Coast City")

		It("should format data properly", func() {
			Ω(t.Height()).Should(Equal(8))
			Ω(t.Line(0)).Should(Equal("Superhero          Origin City\n"), `first line`)
			Ω(t.Line(1)).Should(Equal("=========          ===========\n"), `second line`)
			Ω(t.Line(2)).Should(Equal("Batman             Gotham City\n"), `third line`)
			Ω(t.Line(3)).Should(Equal("Iron Man           New York\n"), `fourth line`)
			Ω(t.Line(4)).Should(Equal("                   (New York, NY)\n"), `fifth line`)
			Ω(t.Line(5)).Should(Equal("                   unconfirmed\n"), `sixth line`)
			Ω(t.Line(6)).Should(Equal("The Green Lantern  Coast City\n"), `seventh line`)
			Ω(t.Line(7)).Should(Equal("(Hal Jordan)\n"), `eighth line`)
		})
	})
	Context("with single-line cells and indexing turned on", func() {
		t := tui.NewIndexedGrid("Superhero", "Origin City")
		t.Row("Batman", "Gotham City")
		t.Row("Iron Man", "New York")
		t.Row("The Green Lantern", "Coast City")

		It("should format data properly", func() {
			Ω(t.Height()).Should(Equal(5))
			Ω(t.Line(0)).Should(Equal("      Superhero          Origin City\n"), `first line`)
			Ω(t.Line(1)).Should(Equal("      =========          ===========\n"), `second line`)
			Ω(t.Line(2)).Should(Equal("   1) Batman             Gotham City\n"), `third line`)
			Ω(t.Line(3)).Should(Equal("   2) Iron Man           New York\n"), `fourth line`)
			Ω(t.Line(4)).Should(Equal("   3) The Green Lantern  Coast City\n"), `fifth line`)
		})
	})
	Context("with multi-line cells and indexing turned on", func() {
		t := tui.NewIndexedGrid("Superhero", "Origin City")
		t.Row("Batman", "Gotham City")
		t.Row("Iron Man", "New York\n(New York, NY)\nunconfirmed")
		t.Row("The Green Lantern\n(Hal Jordan)\n", "Coast City")

		It("should format data properly", func() {
			Ω(t.Height()).Should(Equal(8))
			Ω(t.Line(0)).Should(Equal("      Superhero          Origin City\n"), `first line`)
			Ω(t.Line(1)).Should(Equal("      =========          ===========\n"), `second line`)
			Ω(t.Line(2)).Should(Equal("   1) Batman             Gotham City\n"), `third line`)
			Ω(t.Line(3)).Should(Equal("   2) Iron Man           New York\n"), `fourth line`)
			Ω(t.Line(4)).Should(Equal("                         (New York, NY)\n"), `fifth line`)
			Ω(t.Line(5)).Should(Equal("                         unconfirmed\n"), `sixth line`)
			Ω(t.Line(6)).Should(Equal("   3) The Green Lantern  Coast City\n"), `seventh line`)
			Ω(t.Line(7)).Should(Equal("      (Hal Jordan)\n"), `eighth line`)
		})
	})
})
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"strconv"

	"github.com/hyperledger/fabric/core/chaincode/shim"
)

type SimpleChaincode struct {
}

var projectName string
var projectRate int
var projectPeriod int
var projectGoal int
var projectTimes int
var projectBenifary string
var projectState string
var currentPrice float64
var projectSummary int

var shareList map[string]int

// var availableList map[string]int

func main() {
	fmt.Println("started logging in main()")
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Println("failed in function main()")
	}
}

//Init comment
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("started logging in Init()")
	shareList = make(map[string]int)

	//started to initialize the projectState
	//step1: check whether args == 5
	if len(args) != 5 {
		return nil, errors.New("failed in args")
	}

	//step 2, intialize the project properties
	projectName = args[0]
	stub.PutState("projectName", []byte(projectName))

	projectRate, _ = strconv.Atoi(args[1])
	if projectRate <= 0 {
		return nil, errors.New("errors in args[1], it cannot be negative")
	}
	stub.PutState("projectRate", []byte(args[1]))

	projectPeriod, _ = strconv.Atoi(args[2])
	if projectPeriod <= 0 {
		return nil, errors.New("errors in args[2], it cannot be negative")
	}
	stub.PutState("projectPeriod", []byte(args[2]))

	projectGoal, _ = strconv.Atoi(args[3])
	if projectGoal <= 0 {
		return nil, errors.New("errors in args[3], it cannot be negative")
	}
	stub.PutState("projectGoal", []byte(args[3]))

	projectTimes = 1
	stub.PutState("projectTimes", []byte(strconv.Itoa(projectTimes)))

	projectBenifary = args[4]
	stub.PutState("projectBenifary", []byte(args[4]))

	projectState = "draft"
	stub.PutState("projectState", []byte(projectState))

	currentPrice = 1.0
	projectSummary = 0

	return nil, nil
} //end of Init()

// Invoke comment
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("started logging in Invoke()")
	switch function {
	case "goPublic":
		fmt.Println("started logging in goPublic")
		if len(args) != 0 {
			return nil, errors.New("failed in args")
		}
		projectState = "public"
		return nil, nil //end of goPublic
	case "pay":
		fmt.Println("started logging in pay()")
		if !isPublic() {
			return []byte("error"), errors.New("current state is not public, function pay() failed")
		}

		if len(args) != 2 {
			return nil, errors.New("failed in args")
		}
		user := args[0]
		amount := args[1]
		fmt.Printf("user is %v and amount is %v\n", user, amount)
		amountInt, _ := strconv.Atoi(amount)
		if amountInt <= 0 {
			return nil, errors.New("amount is negative")
		}

		shareList[user] += amountInt

		projectSummary += amountInt
		return nil, nil
	case "checkGoalReached":
		fmt.Println("started logging in checkGoalReached()")
		// TODO: write code for checkGoalReached
		return nil, nil
	case "checkDaoqi":
		fmt.Println("started logging in checkDaoqi()")
		// TODO: write code for checkDaoqi
		return nil, nil
	case "calculatePrice":
		fmt.Println("started logging in calculatePrice")
		return nil, nil
	case "calculateResult":
		fmt.Println("started logging in calculateResult")
		return nil, nil
	default:
		fmt.Println("no function found")
		return nil, errors.New("no function found")
	}
}

// Query comment
func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("started logging in Query()")
	switch function {
	case "getProjectName":
		result, err := stub.GetState("projectName")
		if err != nil {
			return nil, errors.New("error in getProjectName")
		}
		return result, nil
	case "getProjectGoal":
		result, err := stub.GetState("projectGoal")
		if err != nil {
			return nil, errors.New("error in getProjectGoal")
		}
		return result, nil
	case "getProjectSummary":
		result := strconv.Itoa(projectSummary)
		return []byte(result), nil

	case "getShareList":
		fmt.Println("started logging in getUserList")

		var result string
		for user, amount := range shareList {
			result += "****" + user + "/" + strconv.Itoa(amount)
		}
		return []byte(result), nil
	case "getAvailableList":
		fmt.Println("started logging in getAvailableList")
		return nil, nil
	}
	return nil, nil
}

func isPublic() bool {
	if projectState == "public" {
		return true
	} else {
		return false
	}
}
<commit_msg>demo7.go<commit_after>package main

import (
	"errors"
	"fmt"
	"strconv"

	"github.com/hyperledger/fabric/core/chaincode/shim"
)

type SimpleChaincode struct {
}

var projectName string
var projectRate int
var projectPeriod int
var projectGoal int
var projectTimes int
var projectBenifary string
var projectState string
var currentPrice float64
var projectSummary int

var shareList map[string]int

// var availableList map[string]int

func main() {
	fmt.Println("started logging in main()")
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Println("failed in function main()")
	}
}

//Init comment
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("started logging in Init()")
	shareList = make(map[string]int)

	//started to initialize the projectState
	//step1: check whether args == 5
	if len(args) != 5 {
		return nil, errors.New("failed in args")
	}

	//step 2, intialize the project properties
	projectName = args[0]
	stub.PutState("projectName", []byte(projectName))

	projectRate, _ = strconv.Atoi(args[1])
	if projectRate <= 0 {
		return nil, errors.New("errors in args[1], it cannot be negative")
	}
	stub.PutState("projectRate", []byte(args[1]))

	projectPeriod, _ = strconv.Atoi(args[2])
	if projectPeriod <= 0 {
		return nil, errors.New("errors in args[2], it cannot be negative")
	}
	stub.PutState("projectPeriod", []byte(args[2]))

	projectGoal, _ = strconv.Atoi(args[3])
	if projectGoal <= 0 {
		return nil, errors.New("errors in args[3], it cannot be negative")
	}
	stub.PutState("projectGoal", []byte(args[3]))

	projectTimes = 1
	stub.PutState("projectTimes", []byte(strconv.Itoa(projectTimes)))

	projectBenifary = args[4]
	stub.PutState("projectBenifary", []byte(args[4]))

	projectState = "public"
	stub.PutState("projectState", []byte(projectState))

	currentPrice = 1.0
	projectSummary = 0

	return nil, nil
} //end of Init()

// Invoke comment
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("started logging in Invoke()")
	switch function {
	case "goPublic":
		fmt.Println("started logging in goPublic")
		if len(args) != 0 {
			return nil, errors.New("failed in args")
		}
		projectState = "public"
		return nil, nil //end of goPublic
	case "pay":
		fmt.Println("started logging in pay()")
		if !isPublic() {
			return nil, errors.New("current state is not public, function pay() failed")
		}

		if len(args) != 2 {
			return nil, errors.New("failed in args")
		}
		user := args[0]
		amount := args[1]
		fmt.Printf("user is %v and amount is %v\n", user, amount)
		amountInt, _ := strconv.Atoi(amount)
		if amountInt <= 0 {
			return nil, errors.New("amount is negative")
		}

		shareList[user] += amountInt

		projectSummary += amountInt
		return nil, nil
	case "checkGoalReached":
		fmt.Println("started logging in checkGoalReached()")
		// TODO: write code for checkGoalReached
		return nil, nil
	case "checkDaoqi":
		fmt.Println("started logging in checkDaoqi()")
		// TODO: write code for checkDaoqi
		return nil, nil
	case "calculatePrice":
		fmt.Println("started logging in calculatePrice")
		return nil, nil
	case "calculateResult":
		fmt.Println("started logging in calculateResult")
		return nil, nil
	default:
		fmt.Println("no function found")
		return nil, errors.New("no function found")
	}
}

// Query comment
func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("started logging in Query()")
	switch function {
	case "getProjectName":
		result, err := stub.GetState("projectName")
		if err != nil {
			return nil, errors.New("error in getProjectName")
		}
		return result, nil
	case "getProjectGoal":
		result, err := stub.GetState("projectGoal")
		if err != nil {
			return nil, errors.New("error in getProjectGoal")
		}
		return result, nil
	case "getProjectSummary":
		result := strconv.Itoa(projectSummary)
		return []byte(result), nil

	case "getShareList":
		fmt.Println("started logging in getUserList")

		var result string
		for user, amount := range shareList {
			result += "****" + user + "/" + strconv.Itoa(amount)
		}
		return []byte(result), nil
	case "getAvailableList":
		fmt.Println("started logging in getAvailableList")
		return nil, nil
	}
	return nil, nil
}

func isPublic() bool {
	if projectState == "public" {
		return true
	} else {
		return false
	}
}
<|endoftext|>