<commit_before>package builder

import (
	"github.com/appc/spec/schema"
	"github.com/blablacar/cnt/cnt"
	"github.com/blablacar/cnt/spec"
	"github.com/blablacar/cnt/utils"
	"github.com/ghodss/yaml"
	"github.com/n0rad/go-erlog/data"
	"github.com/n0rad/go-erlog/errs"
	"github.com/n0rad/go-erlog/logs"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
)

const SH_FUNCTIONS = `
execute_files() {
  fdir=$1
  [ -d "$fdir" ] || return 0

  for file in $fdir/*; do
    [ -e "$file" ] && {
     	[ -x "$file" ] || chmod +x "$file"
		isLevelEnabled 4 && echo -e "\e[1m\e[32mRunning script -> $file\e[0m"
     	$file
    }
  done
}

levelFromString() {
	case ` + "`echo ${1} | awk '{print toupper($0)}'`" + ` in
		"FATAL") echo 0; return 0 ;;
		"PANIC") echo 1; return 0 ;;
		"ERROR") echo 2; return 0 ;;
		"WARN"|"WARNING") echo 3; return 0 ;;
		"INFO") echo 4; return 0 ;;
		"DEBUG") echo 5; return 0 ;;
		"TRACE") echo 6; return 0 ;;
		*) echo 4 ;;
	esac
}

isLevelEnabled() {
	l=$(levelFromString $1)

	if [ $l -le $log_level ]; then
		return 0
	fi
	return 1
}

export log_level=$(levelFromString ${LOG_LEVEL:-INFO})
`

const BUILD_SCRIPT = `#!/cnt/bin/busybox sh
set -e
. /cnt/bin/functions.sh
isLevelEnabled "debug" && set -x

export TARGET=$( dirname $0 )
export ROOTFS=%%ROOTFS%%
export TERM=xterm

execute_files "$ROOTFS/cnt/runlevels/inherit-build-early"
execute_files "$TARGET/runlevels/build"
`

const BUILD_SCRIPT_LATE = `#!/cnt/bin/busybox sh
set -e
. /cnt/bin/functions.sh
isLevelEnabled "debug" && set -x

export TARGET=$( dirname $0 )
export ROOTFS=%%ROOTFS%%
export TERM=xterm

execute_files "$TARGET/runlevels/build-late"
execute_files "$ROOTFS/cnt/runlevels/inherit-build-late"
`

const PRESTART = `#!/cnt/bin/busybox sh
set -e
. /cnt/bin/functions.sh
isLevelEnabled "debug" && set -x

BASEDIR=${0%/*}
CNT_PATH=/cnt

execute_files ${CNT_PATH}/runlevels/prestart-early

if [ -z ${LOG_LEVEL} ]; then
	${BASEDIR}/templater -o TEMPLATER_OVERRIDE -t / /cnt
else
	${BASEDIR}/templater -o TEMPLATER_OVERRIDE -L "${LOG_LEVEL}" -t / /cnt
fi

#if [ -d ${CNT_PATH}/attributes ]; then
#	echo "$CONFD_OVERRIDE"
#    ${BASEDIR}/attributes-merger -i ${CNT_PATH}/attributes -e CONFD_OVERRIDE
#    export CONFD_DATA=$(cat attributes.json)
#fi
#${BASEDIR}/confd -onetime -config-file=${CNT_PATH}/prestart/confd.toml

execute_files ${CNT_PATH}/runlevels/prestart-late
`
const BUILD_SETUP = `#!/bin/sh
set -e
. ${TARGET}/rootfs/cnt/bin/functions.sh
isLevelEnabled "debug" && set -x

execute_files ${BASEDIR}/runlevels/build-setup
`

const PATH_BIN = "/bin"
const PATH_TESTS = "/tests"
const PATH_INSTALLED = "/installed"
const PATH_MANIFEST = "/manifest"
const PATH_IMAGE_ACI = "/image.aci"
const PATH_IMAGE_ACI_ZIP = "/image-zip.aci"
const PATH_ROOTFS = "/rootfs"
const PATH_TARGET = "/target"
const PATH_CNT = "/cnt"
const PATH_CNT_MANIFEST = "/cnt-manifest.yml"
const PATH_RUNLEVELS = "/runlevels"
const PATH_PRESTART_EARLY = "/prestart-early"
const PATH_PRESTART_LATE = "/prestart-late"
const PATH_INHERIT_BUILD_LATE = "/inherit-build-late"
const PATH_INHERIT_BUILD_EARLY = "/inherit-build-early"
const PATH_ATTRIBUTES = "/attributes"
const PATH_FILES = "/files"
const PATH_BUILD_LATE = "/build-late"
const PATH_BUILD_SETUP = "/build-setup"
const PATH_BUILD = "/build"
const PATH_TEMPLATES = "/templates"

type Aci struct {
	fields          data.Fields
	path            string
	target          string
	rootfs          string
	podName         *spec.ACFullname
	manifest        spec.AciManifest
	args            BuildArgs
	FullyResolveDep bool
}

func NewAciWithManifest(path string, args BuildArgs, manifest spec.AciManifest) (*Aci, error) {
	if manifest.NameAndVersion == "" {
		logs.WithField("path", path).Fatal("name is mandatory in manifest")
	}

	fields := data.WithField("aci", manifest.NameAndVersion.String())
	logs.WithF(fields).WithFields(data.Fields{"args": args, "path": path, "manifest": manifest}).Debug("New aci")

	fullPath, err := filepath.Abs(path)
	if err != nil {
		return nil, errs.WithEF(err, fields, "Cannot get fullpath of project")
	}

	target := fullPath + PATH_TARGET
	if cnt.Home.Config.TargetWorkDir != "" {
		currentAbsDir, err := filepath.Abs(cnt.Home.Config.TargetWorkDir + "/" + manifest.NameAndVersion.ShortName())
		if err != nil {
			return nil, errs.WithEF(err, fields.WithField("path", path), "Invalid target path")
		}
		target = currentAbsDir
	}

	aci := &Aci{
		fields:          fields,
		args:            args,
		path:            fullPath,
		manifest:        manifest,
		target:          target,
		rootfs:          target + PATH_ROOTFS,
		FullyResolveDep: true,
	}

	aci.checkCompatibilityVersions()
	aci.checkLatestVersions()
	return aci, nil
}

func NewAci(path string, args BuildArgs) (*Aci, error) {
	manifest, err := readAciManifest(path + PATH_CNT_MANIFEST)
	if err != nil {
		return nil, errs.WithEF(err, data.WithField("path", path+PATH_CNT_MANIFEST), "Cannot read manifest")
	}
	return NewAciWithManifest(path, args, *manifest)
}

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

func readAciManifest(manifestPath string) (*spec.AciManifest, error) {
	manifest := spec.AciManifest{Aci: spec.AciDefinition{}}

	source, err := ioutil.ReadFile(manifestPath)
	if err != nil {
		return nil, err
	}
	err = yaml.Unmarshal([]byte(source), &manifest)
	if err != nil {
		return nil, errs.WithE(err, "Cannot unmarshall manifest")
	}

	return &manifest, nil
}

func (aci *Aci) tarAci(zip bool) {
	target := PATH_IMAGE_ACI[1:]
	if zip {
		target = PATH_IMAGE_ACI_ZIP[1:]
	}
	dir, _ := os.Getwd()
	logs.WithField("path", aci.target).Debug("chdir")
	os.Chdir(aci.target)
	utils.Tar(zip, target, PATH_MANIFEST[1:], PATH_ROOTFS[1:])
	logs.WithField("path", dir).Debug("chdir")
	os.Chdir(dir)
}

func (aci *Aci) checkCompatibilityVersions() {
	froms, err := aci.manifest.GetFroms()
	if err != nil {
		logs.WithEF(err, aci.fields).Fatal("Invalid from")
	}
	for _, from := range froms {
		if from == "" {
			continue
		}

		fromFields := aci.fields.WithField("dependency", from.String())

		err := utils.ExecCmd("rkt", "--insecure-options=image", "fetch", from.String())
		if err != nil {
			logs.WithEF(err, fromFields).Fatal("Cannot fetch from")
		}
		out, err := utils.ExecCmdGetOutput("rkt", "image", "cat-manifest", from.String())
		if err != nil {
			logs.WithEF(err, fromFields).Fatal("Cannot find dependency")
		}

		version, ok := loadManifest(out).Annotations.Get("cnt-version")
		var val int
		if ok {
			val, err = strconv.Atoi(version)
			if err != nil {
				logs.WithEF(err, fromFields).WithField("version", version).Fatal("Failed to parse cnt-version from manifest")
			}
		}
		if !ok || val < 51 {
			logs.WithF(aci.fields).
				WithField("from", from).
				WithField("require", ">=51").
				Error("from aci was not build with a compatible version of cnt")
		}
	}

	for _, dep := range aci.manifest.Aci.Dependencies {
		depFields := aci.fields.WithField("dependency", dep.String())
		err := utils.ExecCmd("rkt", "--insecure-options=image", "fetch", dep.String())
		if err != nil {
			logs.WithEF(err, depFields).Fatal("Cannot fetch dependency")
		}
		out, err := utils.ExecCmdGetOutput("rkt", "image", "cat-manifest", dep.String())
		if err != nil {
			logs.WithEF(err, depFields).Fatal("Cannot find dependency")
		}

		version, ok := loadManifest(out).Annotations.Get("cnt-version")
		var val int
		if ok {
			val, err = strconv.Atoi(version)
			if err != nil {
				logs.WithEF(err, depFields).WithField("version", version).Fatal("Failed to parse cnt-version from manifest")
			}
		}
		if !ok || val < 51 {
			logs.WithF(aci.fields).
				WithField("dependency", dep).
				WithField("require", ">=51").
				Error("dependency aci was not build with a compatible version of cnt")
		}
	}
}

func loadManifest(content string) schema.ImageManifest {
	im := schema.ImageManifest{}
	err := im.UnmarshalJSON([]byte(content))
	if err != nil {
		logs.WithE(err).WithField("content", content).Fatal("Failed to read manifest content")
	}
	return im
}

func (aci *Aci) checkLatestVersions() {
	froms, err := aci.manifest.GetFroms()
	if err != nil {
		logs.WithEF(err, aci.fields).Fatal("Invalid from")
	}
	for _, from := range froms {
		if from == "" {
			continue
		}

		version, _ := from.LatestVersion()
		logs.WithField("version", from.Name()+":"+version).Debug("Discovered from latest verion")
		if version != "" && utils.Version(from.Version()).LessThan(utils.Version(version)) {
			logs.WithF(aci.fields.WithField("version", from.Name()+":"+version)).Warn("Newer 'from' version")
		}
	}
	for _, dep := range aci.manifest.Aci.Dependencies {
		if dep.Version() == "" {
			continue
		}
		version, _ := dep.LatestVersion()
		if version != "" && utils.Version(dep.Version()).LessThan(utils.Version(version)) {
			logs.WithF(aci.fields.WithField("version", dep.Name()+":"+version)).Warn("Newer 'dependency' version")
		}
	}
}
<commit_msg>add current version in log when telling there is a newer version<commit_after>package builder

import (
	"github.com/appc/spec/schema"
	"github.com/blablacar/cnt/cnt"
	"github.com/blablacar/cnt/spec"
	"github.com/blablacar/cnt/utils"
	"github.com/ghodss/yaml"
	"github.com/n0rad/go-erlog/data"
	"github.com/n0rad/go-erlog/errs"
	"github.com/n0rad/go-erlog/logs"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
)

const SH_FUNCTIONS = `
execute_files() {
  fdir=$1
  [ -d "$fdir" ] || return 0

  for file in $fdir/*; do
    [ -e "$file" ] && {
     	[ -x "$file" ] || chmod +x "$file"
		isLevelEnabled 4 && echo -e "\e[1m\e[32mRunning script -> $file\e[0m"
     	$file
    }
  done
}

levelFromString() {
	case ` + "`echo ${1} | awk '{print toupper($0)}'`" + ` in
		"FATAL") echo 0; return 0 ;;
		"PANIC") echo 1; return 0 ;;
		"ERROR") echo 2; return 0 ;;
		"WARN"|"WARNING") echo 3; return 0 ;;
		"INFO") echo 4; return 0 ;;
		"DEBUG") echo 5; return 0 ;;
		"TRACE") echo 6; return 0 ;;
		*) echo 4 ;;
	esac
}

isLevelEnabled() {
	l=$(levelFromString $1)

	if [ $l -le $log_level ]; then
		return 0
	fi
	return 1
}

export log_level=$(levelFromString ${LOG_LEVEL:-INFO})
`

const BUILD_SCRIPT = `#!/cnt/bin/busybox sh
set -e
. /cnt/bin/functions.sh
isLevelEnabled "debug" && set -x

export TARGET=$( dirname $0 )
export ROOTFS=%%ROOTFS%%
export TERM=xterm

execute_files "$ROOTFS/cnt/runlevels/inherit-build-early"
execute_files "$TARGET/runlevels/build"
`

const BUILD_SCRIPT_LATE = `#!/cnt/bin/busybox sh
set -e
. /cnt/bin/functions.sh
isLevelEnabled "debug" && set -x

export TARGET=$( dirname $0 )
export ROOTFS=%%ROOTFS%%
export TERM=xterm

execute_files "$TARGET/runlevels/build-late"
execute_files "$ROOTFS/cnt/runlevels/inherit-build-late"
`

const PRESTART = `#!/cnt/bin/busybox sh
set -e
. /cnt/bin/functions.sh
isLevelEnabled "debug" && set -x

BASEDIR=${0%/*}
CNT_PATH=/cnt

execute_files ${CNT_PATH}/runlevels/prestart-early

if [ -z ${LOG_LEVEL} ]; then
	${BASEDIR}/templater -o TEMPLATER_OVERRIDE -t / /cnt
else
	${BASEDIR}/templater -o TEMPLATER_OVERRIDE -L "${LOG_LEVEL}" -t / /cnt
fi

#if [ -d ${CNT_PATH}/attributes ]; then
#	echo "$CONFD_OVERRIDE"
#    ${BASEDIR}/attributes-merger -i ${CNT_PATH}/attributes -e CONFD_OVERRIDE
#    export CONFD_DATA=$(cat attributes.json)
#fi
#${BASEDIR}/confd -onetime -config-file=${CNT_PATH}/prestart/confd.toml

execute_files ${CNT_PATH}/runlevels/prestart-late
`
const BUILD_SETUP = `#!/bin/sh
set -e
. ${TARGET}/rootfs/cnt/bin/functions.sh
isLevelEnabled "debug" && set -x

execute_files ${BASEDIR}/runlevels/build-setup
`

const PATH_BIN = "/bin"
const PATH_TESTS = "/tests"
const PATH_INSTALLED = "/installed"
const PATH_MANIFEST = "/manifest"
const PATH_IMAGE_ACI = "/image.aci"
const PATH_IMAGE_ACI_ZIP = "/image-zip.aci"
const PATH_ROOTFS = "/rootfs"
const PATH_TARGET = "/target"
const PATH_CNT = "/cnt"
const PATH_CNT_MANIFEST = "/cnt-manifest.yml"
const PATH_RUNLEVELS = "/runlevels"
const PATH_PRESTART_EARLY = "/prestart-early"
const PATH_PRESTART_LATE = "/prestart-late"
const PATH_INHERIT_BUILD_LATE = "/inherit-build-late"
const PATH_INHERIT_BUILD_EARLY = "/inherit-build-early"
const PATH_ATTRIBUTES = "/attributes"
const PATH_FILES = "/files"
const PATH_BUILD_LATE = "/build-late"
const PATH_BUILD_SETUP = "/build-setup"
const PATH_BUILD = "/build"
const PATH_TEMPLATES = "/templates"

type Aci struct {
	fields          data.Fields
	path            string
	target          string
	rootfs          string
	podName         *spec.ACFullname
	manifest        spec.AciManifest
	args            BuildArgs
	FullyResolveDep bool
}

func NewAciWithManifest(path string, args BuildArgs, manifest spec.AciManifest) (*Aci, error) {
	if manifest.NameAndVersion == "" {
		logs.WithField("path", path).Fatal("name is mandatory in manifest")
	}

	fields := data.WithField("aci", manifest.NameAndVersion.String())
	logs.WithF(fields).WithFields(data.Fields{"args": args, "path": path, "manifest": manifest}).Debug("New aci")

	fullPath, err := filepath.Abs(path)
	if err != nil {
		return nil, errs.WithEF(err, fields, "Cannot get fullpath of project")
	}

	target := fullPath + PATH_TARGET
	if cnt.Home.Config.TargetWorkDir != "" {
		currentAbsDir, err := filepath.Abs(cnt.Home.Config.TargetWorkDir + "/" + manifest.NameAndVersion.ShortName())
		if err != nil {
			return nil, errs.WithEF(err, fields.WithField("path", path), "Invalid target path")
		}
		target = currentAbsDir
	}

	aci := &Aci{
		fields:          fields,
		args:            args,
		path:            fullPath,
		manifest:        manifest,
		target:          target,
		rootfs:          target + PATH_ROOTFS,
		FullyResolveDep: true,
	}

	aci.checkCompatibilityVersions()
	aci.checkLatestVersions()
	return aci, nil
}

func NewAci(path string, args BuildArgs) (*Aci, error) {
	manifest, err := readAciManifest(path + PATH_CNT_MANIFEST)
	if err != nil {
		return nil, errs.WithEF(err, data.WithField("path", path+PATH_CNT_MANIFEST), "Cannot read manifest")
	}
	return NewAciWithManifest(path, args, *manifest)
}

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

func readAciManifest(manifestPath string) (*spec.AciManifest, error) {
	manifest := spec.AciManifest{Aci: spec.AciDefinition{}}

	source, err := ioutil.ReadFile(manifestPath)
	if err != nil {
		return nil, err
	}
	err = yaml.Unmarshal([]byte(source), &manifest)
	if err != nil {
		return nil, errs.WithE(err, "Cannot unmarshall manifest")
	}

	return &manifest, nil
}

func (aci *Aci) tarAci(zip bool) {
	target := PATH_IMAGE_ACI[1:]
	if zip {
		target = PATH_IMAGE_ACI_ZIP[1:]
	}
	dir, _ := os.Getwd()
	logs.WithField("path", aci.target).Debug("chdir")
	os.Chdir(aci.target)
	utils.Tar(zip, target, PATH_MANIFEST[1:], PATH_ROOTFS[1:])
	logs.WithField("path", dir).Debug("chdir")
	os.Chdir(dir)
}

func (aci *Aci) checkCompatibilityVersions() {
	froms, err := aci.manifest.GetFroms()
	if err != nil {
		logs.WithEF(err, aci.fields).Fatal("Invalid from")
	}
	for _, from := range froms {
		if from == "" {
			continue
		}

		fromFields := aci.fields.WithField("dependency", from.String())

		err := utils.ExecCmd("rkt", "--insecure-options=image", "fetch", from.String())
		if err != nil {
			logs.WithEF(err, fromFields).Fatal("Cannot fetch from")
		}
		out, err := utils.ExecCmdGetOutput("rkt", "image", "cat-manifest", from.String())
		if err != nil {
			logs.WithEF(err, fromFields).Fatal("Cannot find dependency")
		}

		version, ok := loadManifest(out).Annotations.Get("cnt-version")
		var val int
		if ok {
			val, err = strconv.Atoi(version)
			if err != nil {
				logs.WithEF(err, fromFields).WithField("version", version).Fatal("Failed to parse cnt-version from manifest")
			}
		}
		if !ok || val < 51 {
			logs.WithF(aci.fields).
				WithField("from", from).
				WithField("require", ">=51").
				Error("from aci was not build with a compatible version of cnt")
		}
	}

	for _, dep := range aci.manifest.Aci.Dependencies {
		depFields := aci.fields.WithField("dependency", dep.String())
		err := utils.ExecCmd("rkt", "--insecure-options=image", "fetch", dep.String())
		if err != nil {
			logs.WithEF(err, depFields).Fatal("Cannot fetch dependency")
		}
		out, err := utils.ExecCmdGetOutput("rkt", "image", "cat-manifest", dep.String())
		if err != nil {
			logs.WithEF(err, depFields).Fatal("Cannot find dependency")
		}

		version, ok := loadManifest(out).Annotations.Get("cnt-version")
		var val int
		if ok {
			val, err = strconv.Atoi(version)
			if err != nil {
				logs.WithEF(err, depFields).WithField("version", version).Fatal("Failed to parse cnt-version from manifest")
			}
		}
		if !ok || val < 51 {
			logs.WithF(aci.fields).
				WithField("dependency", dep).
				WithField("require", ">=51").
				Error("dependency aci was not build with a compatible version of cnt")
		}
	}
}

func loadManifest(content string) schema.ImageManifest {
	im := schema.ImageManifest{}
	err := im.UnmarshalJSON([]byte(content))
	if err != nil {
		logs.WithE(err).WithField("content", content).Fatal("Failed to read manifest content")
	}
	return im
}

func (aci *Aci) checkLatestVersions() {
	froms, err := aci.manifest.GetFroms()
	if err != nil {
		logs.WithEF(err, aci.fields).Fatal("Invalid from")
	}
	for _, from := range froms {
		if from == "" {
			continue
		}

		version, _ := from.LatestVersion()
		logs.WithField("version", from.Name()+":"+version).Debug("Discovered from latest verion")
		if version != "" && utils.Version(from.Version()).LessThan(utils.Version(version)) {
			logs.WithField("newer", from.Name()+":"+version).
				WithField("current", from.String()).
				Warn("Newer 'from' version")
		}
	}
	for _, dep := range aci.manifest.Aci.Dependencies {
		if dep.Version() == "" {
			continue
		}
		version, _ := dep.LatestVersion()
		if version != "" && utils.Version(dep.Version()).LessThan(utils.Version(version)) {
			logs.WithField("newer", dep.Name()+":"+version).
				WithField("current", dep.String()).
				Warn("Newer 'dependency' version")
		}
	}
}
<|endoftext|>


<commit_before>package builder

import (
	"github.com/modcloth/docker-builder/dclient"
	"github.com/modcloth/docker-builder/log"
	"github.com/modcloth/docker-builder/parser"
)

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/hishboy/gocommons/lang"
	"github.com/modcloth/go-fileutils"
	"github.com/modcloth/queued-command-runner"
	"github.com/onsi/gocleanup"
)

/*
WaitForPush indicates to main() that a `docker push` command has been
started.  Since those are run asynchronously, main() has to wait on the
runner.Done channel.  However, if the build does not require a push, we
don't want to wait or we'll just be stuck forever.
*/
var WaitForPush bool

/*
SkipPush, when set to true, will override any behavior set by a Bobfile and
will cause builders *NOT* to run `docker push` commands.  SkipPush is also set
by the `--skip-push` option when used on the command line.
*/
var SkipPush bool

/*
A Builder is the struct that actually does the work of moving files around and
executing the commands that do the docker build.
*/
type Builder struct {
	dockerClient dclient.DockerClient
	*logrus.Logger
	workdir         string
	isRegular       bool
	nextSubSequence *parser.SubSequence
	Stderr          io.Writer
	Stdout          io.Writer
	Builderfile     string
}

/*
SetNextSubSequence sets the next subsequence within bob to be processed. This
function is exported because it is used explicitly in tests, but in Build(), it
is intended to be used as a helper function.
*/
func (bob *Builder) SetNextSubSequence(subSeq *parser.SubSequence) {
	bob.nextSubSequence = subSeq
}

/*
NewBuilder returns an instance of a Builder struct.  The function exists in
case we want to initialize our Builders with something.
*/
func NewBuilder(logger *logrus.Logger, shouldBeRegular bool) (*Builder, error) {
	if logger == nil {
		logger = logrus.New()
		logger.Level = logrus.Panic
	}

	client, err := dclient.NewDockerClient(logger, shouldBeRegular)

	if err != nil {
		return nil, err
	}

	return &Builder{
		dockerClient: client,
		Logger:       logger,
		isRegular:    shouldBeRegular,
		Stdout:       log.NewOutWriter(logger, "         @{g}%s@{|}"),
		Stderr:       log.NewOutWriter(logger, "         @{r}%s@{|}"),
	}, nil
}

/*
BuilderLogger is an accessor method for bob's internal logger
*/
func (bob *Builder) BuilderLogger() *logrus.Logger {
	return bob.Logger
}

/*
BuildFromFile combines Build() with parser.Parse() to reduce the number of
steps needed to build with bob programatically.
*/
func (bob *Builder) BuildFromFile(file string) error {
	par, err := parser.NewParser(file, bob.BuilderLogger())
	if err != nil {
		return err
	}

	commandSequence, err := par.Parse()
	if err != nil {
		return err
	}

	bob.Builderfile = file

	if err = bob.Build(commandSequence); err != nil {
		return err
	}

	return nil
}

/*
Build does the building!
*/
func (bob *Builder) Build(commandSequence *parser.CommandSequence) error {
	for _, seq := range commandSequence.Commands {
		if err := bob.CleanWorkdir(); err != nil {
			return err
		}
		bob.SetNextSubSequence(seq)
		if err := bob.Setup(); err != nil {
			return err
		}

		workdir := bob.Workdir()

		bob.WithFields(logrus.Fields{
			"container_section": seq.Metadata.Name,
		}).Info("running commands for container section")

		var imageID string
		var err error

		for _, cmd := range seq.SubCommand {
			cmd.Stdout = bob.Stdout
			cmd.Stderr = bob.Stderr
			cmd.Dir = workdir

			if cmd.Path == "docker" {
				path, err := fileutils.Which("docker")
				if err != nil {
					return err
				}

				cmd.Path = path
			}

			switch cmd.Args[1] {
			case "build":
				bob.WithFields(logrus.Fields{
					"command": strings.Join(cmd.Args, ""),
				}).Info("running command")

				if err := cmd.Run(); err != nil {
					return err
				}

				imageID, err = bob.LatestImageTaggedWithUUID(seq.Metadata.UUID)
				if err != nil {
					return err
				}
			case "tag":
				for k, v := range cmd.Args {
					if v == "<IMG>" {
						cmd.Args[k] = imageID
					}
				}
				bob.WithFields(logrus.Fields{
					"command": strings.Join(cmd.Args, ""),
				}).Info("running command")

				if err := cmd.Run(); err != nil {
					return err
				}
			case "push":
				if !SkipPush {
					bob.WithFields(logrus.Fields{
						"command": strings.Join(cmd.Args, ""),
					}).Info("running command")

					WaitForPush = true

					runner.Run(&runner.Command{
						Cmd: &cmd,
					})
				}
			default:
				bob.WithFields(logrus.Fields{
					"command": strings.Join(cmd.Args, ""),
				}).Warn("improperly formatted command")

				return fmt.Errorf("improperly formatted command %q", strings.Join(cmd.Args, ""))
			}
		}
	}

	return nil
}

/*
Setup moves all of the correct files into place in the temporary directory in
order to perform the docker build.
*/
func (bob *Builder) Setup() error {
	if bob.nextSubSequence == nil {
		return errors.New("no command sub sequence set, cannot perform setup")
	}

	meta := bob.nextSubSequence.Metadata
	fileSet := lang.NewHashSet()

	if len(meta.Included) == 0 {
		files, err := ioutil.ReadDir(bob.Repodir())
		if err != nil {
			return err
		}

		for _, v := range files {
			fileSet.Add(v.Name())
		}
	} else {
		for _, v := range meta.Included {
			fileSet.Add(v)
		}
	}

	// subtract any excludes from fileSet
	for _, exclude := range meta.Excluded {
		if fileSet.Contains(exclude) {
			fileSet.Remove(exclude)
		}
	}

	if fileSet.Contains("Dockerfile") {
		fileSet.Remove("Dockerfile")
	}

	// add the Dockerfile
	fileSet.Add(meta.Dockerfile)

	workdir := bob.Workdir()
	repodir := bob.Repodir()

	// copy the actual files over
	for _, file := range fileSet.ToSlice() {
		src := fmt.Sprintf("%s/%s", repodir, file)
		dest := fmt.Sprintf("%s/%s", workdir, file)

		if file == meta.Dockerfile {
			dest = fmt.Sprintf("%s/%s", workdir, "Dockerfile")
		}

		fileInfo, err := os.Stat(src)
		if err != nil {
			return err
		}

		if fileInfo.IsDir() {
			err = fileutils.CpR(src, dest)
		} else {
			err = fileutils.Cp(src, dest)
		}
		if err != nil {
			return err
		}
	}

	return nil
}

/*
Repodir is the dir from which we are using files for our docker builds.
*/
func (bob *Builder) Repodir() string {
	if !bob.isRegular {
		repoDir := "spec/fixtures/repodir"
		return fmt.Sprintf("%s/%s", os.Getenv("PWD"), repoDir)
	}
	return filepath.Dir(bob.Builderfile)
}

/*
Workdir returns bob's working directory.
*/
func (bob *Builder) Workdir() string {
	return bob.workdir
}

func (bob *Builder) generateWorkDir() string {
	tmp, err := ioutil.TempDir("", "bob")
	if err != nil {
		return ""
	}

	gocleanup.Register(func() {
		fileutils.RmRF(tmp)
	})

	return tmp
}

/*
CleanWorkdir effectively does a rm -rf and mkdir -p on bob's workdir.  Intended
to be used before using the workdir (i.e. before new command groups).
*/
func (bob *Builder) CleanWorkdir() error {
	workdir := bob.generateWorkDir()
	bob.workdir = workdir

	if err := fileutils.RmRF(workdir); err != nil {
		return err
	}

	if err := fileutils.MkdirP(workdir, 0755); err != nil {
		return err
	}

	return nil
}

/*
LatestImageTaggedWithUUID accepts a uuid and invokes the underlying utility
DockerClient to determine the id of the most recently created image tagged with
the provided uuid.
*/
func (bob *Builder) LatestImageTaggedWithUUID(uuid string) (string, error) {
	id, err := bob.dockerClient.LatestImageTaggedWithUUID(uuid)
	if err != nil {
		bob.Println(err)
		return "", err
	}

	return id, nil
}
<commit_msg>[OOPS] forgot to included these spaces<commit_after>package builder

import (
	"github.com/modcloth/docker-builder/dclient"
	"github.com/modcloth/docker-builder/log"
	"github.com/modcloth/docker-builder/parser"
)

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/hishboy/gocommons/lang"
	"github.com/modcloth/go-fileutils"
	"github.com/modcloth/queued-command-runner"
	"github.com/onsi/gocleanup"
)

/*
WaitForPush indicates to main() that a `docker push` command has been
started.  Since those are run asynchronously, main() has to wait on the
runner.Done channel.  However, if the build does not require a push, we
don't want to wait or we'll just be stuck forever.
*/
var WaitForPush bool

/*
SkipPush, when set to true, will override any behavior set by a Bobfile and
will cause builders *NOT* to run `docker push` commands.  SkipPush is also set
by the `--skip-push` option when used on the command line.
*/
var SkipPush bool

/*
A Builder is the struct that actually does the work of moving files around and
executing the commands that do the docker build.
*/
type Builder struct {
	dockerClient dclient.DockerClient
	*logrus.Logger
	workdir         string
	isRegular       bool
	nextSubSequence *parser.SubSequence
	Stderr          io.Writer
	Stdout          io.Writer
	Builderfile     string
}

/*
SetNextSubSequence sets the next subsequence within bob to be processed. This
function is exported because it is used explicitly in tests, but in Build(), it
is intended to be used as a helper function.
*/
func (bob *Builder) SetNextSubSequence(subSeq *parser.SubSequence) {
	bob.nextSubSequence = subSeq
}

/*
NewBuilder returns an instance of a Builder struct.  The function exists in
case we want to initialize our Builders with something.
*/
func NewBuilder(logger *logrus.Logger, shouldBeRegular bool) (*Builder, error) {
	if logger == nil {
		logger = logrus.New()
		logger.Level = logrus.Panic
	}

	client, err := dclient.NewDockerClient(logger, shouldBeRegular)

	if err != nil {
		return nil, err
	}

	return &Builder{
		dockerClient: client,
		Logger:       logger,
		isRegular:    shouldBeRegular,
		Stdout:       log.NewOutWriter(logger, "         @{g}%s@{|}"),
		Stderr:       log.NewOutWriter(logger, "         @{r}%s@{|}"),
	}, nil
}

/*
BuilderLogger is an accessor method for bob's internal logger
*/
func (bob *Builder) BuilderLogger() *logrus.Logger {
	return bob.Logger
}

/*
BuildFromFile combines Build() with parser.Parse() to reduce the number of
steps needed to build with bob programatically.
*/
func (bob *Builder) BuildFromFile(file string) error {
	par, err := parser.NewParser(file, bob.BuilderLogger())
	if err != nil {
		return err
	}

	commandSequence, err := par.Parse()
	if err != nil {
		return err
	}

	bob.Builderfile = file

	if err = bob.Build(commandSequence); err != nil {
		return err
	}

	return nil
}

/*
Build does the building!
*/
func (bob *Builder) Build(commandSequence *parser.CommandSequence) error {
	for _, seq := range commandSequence.Commands {
		if err := bob.CleanWorkdir(); err != nil {
			return err
		}
		bob.SetNextSubSequence(seq)
		if err := bob.Setup(); err != nil {
			return err
		}

		workdir := bob.Workdir()

		bob.WithFields(logrus.Fields{
			"container_section": seq.Metadata.Name,
		}).Info("running commands for container section")

		var imageID string
		var err error

		for _, cmd := range seq.SubCommand {
			cmd.Stdout = bob.Stdout
			cmd.Stderr = bob.Stderr
			cmd.Dir = workdir

			if cmd.Path == "docker" {
				path, err := fileutils.Which("docker")
				if err != nil {
					return err
				}

				cmd.Path = path
			}

			switch cmd.Args[1] {
			case "build":
				bob.WithFields(logrus.Fields{
					"command": strings.Join(cmd.Args, " "),
				}).Info("running command")

				if err := cmd.Run(); err != nil {
					return err
				}

				imageID, err = bob.LatestImageTaggedWithUUID(seq.Metadata.UUID)
				if err != nil {
					return err
				}
			case "tag":
				for k, v := range cmd.Args {
					if v == "<IMG>" {
						cmd.Args[k] = imageID
					}
				}
				bob.WithFields(logrus.Fields{
					"command": strings.Join(cmd.Args, " "),
				}).Info("running command")

				if err := cmd.Run(); err != nil {
					return err
				}
			case "push":
				if !SkipPush {
					bob.WithFields(logrus.Fields{
						"command": strings.Join(cmd.Args, " "),
					}).Info("running command")

					WaitForPush = true

					runner.Run(&runner.Command{
						Cmd: &cmd,
					})
				}
			default:
				bob.WithFields(logrus.Fields{
					"command": strings.Join(cmd.Args, " "),
				}).Warn("improperly formatted command")

				return fmt.Errorf("improperly formatted command %q", strings.Join(cmd.Args, " "))
			}
		}
	}

	return nil
}

/*
Setup moves all of the correct files into place in the temporary directory in
order to perform the docker build.
*/
func (bob *Builder) Setup() error {
	if bob.nextSubSequence == nil {
		return errors.New("no command sub sequence set, cannot perform setup")
	}

	meta := bob.nextSubSequence.Metadata
	fileSet := lang.NewHashSet()

	if len(meta.Included) == 0 {
		files, err := ioutil.ReadDir(bob.Repodir())
		if err != nil {
			return err
		}

		for _, v := range files {
			fileSet.Add(v.Name())
		}
	} else {
		for _, v := range meta.Included {
			fileSet.Add(v)
		}
	}

	// subtract any excludes from fileSet
	for _, exclude := range meta.Excluded {
		if fileSet.Contains(exclude) {
			fileSet.Remove(exclude)
		}
	}

	if fileSet.Contains("Dockerfile") {
		fileSet.Remove("Dockerfile")
	}

	// add the Dockerfile
	fileSet.Add(meta.Dockerfile)

	workdir := bob.Workdir()
	repodir := bob.Repodir()

	// copy the actual files over
	for _, file := range fileSet.ToSlice() {
		src := fmt.Sprintf("%s/%s", repodir, file)
		dest := fmt.Sprintf("%s/%s", workdir, file)

		if file == meta.Dockerfile {
			dest = fmt.Sprintf("%s/%s", workdir, "Dockerfile")
		}

		fileInfo, err := os.Stat(src)
		if err != nil {
			return err
		}

		if fileInfo.IsDir() {
			err = fileutils.CpR(src, dest)
		} else {
			err = fileutils.Cp(src, dest)
		}
		if err != nil {
			return err
		}
	}

	return nil
}

/*
Repodir is the dir from which we are using files for our docker builds.
*/
func (bob *Builder) Repodir() string {
	if !bob.isRegular {
		repoDir := "spec/fixtures/repodir"
		return fmt.Sprintf("%s/%s", os.Getenv("PWD"), repoDir)
	}
	return filepath.Dir(bob.Builderfile)
}

/*
Workdir returns bob's working directory.
*/
func (bob *Builder) Workdir() string {
	return bob.workdir
}

func (bob *Builder) generateWorkDir() string {
	tmp, err := ioutil.TempDir("", "bob")
	if err != nil {
		return ""
	}

	gocleanup.Register(func() {
		fileutils.RmRF(tmp)
	})

	return tmp
}

/*
CleanWorkdir effectively does a rm -rf and mkdir -p on bob's workdir.  Intended
to be used before using the workdir (i.e. before new command groups).
*/
func (bob *Builder) CleanWorkdir() error {
	workdir := bob.generateWorkDir()
	bob.workdir = workdir

	if err := fileutils.RmRF(workdir); err != nil {
		return err
	}

	if err := fileutils.MkdirP(workdir, 0755); err != nil {
		return err
	}

	return nil
}

/*
LatestImageTaggedWithUUID accepts a uuid and invokes the underlying utility
DockerClient to determine the id of the most recently created image tagged with
the provided uuid.
*/
func (bob *Builder) LatestImageTaggedWithUUID(uuid string) (string, error) {
	id, err := bob.dockerClient.LatestImageTaggedWithUUID(uuid)
	if err != nil {
		bob.Println(err)
		return "", err
	}

	return id, nil
}
<|endoftext|>


<commit_before>package builder

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
	"sync"

	"github.com/docker/docker/api"
	"github.com/docker/docker/builder/parser"
	"github.com/docker/docker/cliconfig"
	"github.com/docker/docker/daemon"
	"github.com/docker/docker/graph"
	"github.com/docker/docker/pkg/archive"
	"github.com/docker/docker/pkg/httputils"
	"github.com/docker/docker/pkg/parsers"
	"github.com/docker/docker/pkg/streamformatter"
	"github.com/docker/docker/pkg/urlutil"
	"github.com/docker/docker/registry"
	"github.com/docker/docker/runconfig"
)

// whitelist of commands allowed for a commit/import
var validCommitCommands = map[string]bool{
	"entrypoint": true,
	"cmd":        true,
	"user":       true,
	"workdir":    true,
	"env":        true,
	"volume":     true,
	"expose":     true,
	"onbuild":    true,
}

type Config struct {
	DockerfileName string
	RemoteURL      string
	RepoName       string
	SuppressOutput bool
	NoCache        bool
	Remove         bool
	ForceRemove    bool
	Pull           bool
	JSONFormat     bool
	Memory         int64
	MemorySwap     int64
	CpuShares      int64
	CpuSetCpus     string
	CpuSetMems     string
	AuthConfig     *cliconfig.AuthConfig
	ConfigFile     *cliconfig.ConfigFile

	Stdout  io.Writer
	Context io.ReadCloser
	// When closed, the job has been cancelled.
	// Note: not all jobs implement cancellation.
	// See Job.Cancel() and Job.WaitCancelled()
	cancelled  chan struct{}
	cancelOnce sync.Once
}

// When called, causes the Job.WaitCancelled channel to unblock.
func (b *Config) Cancel() {
	b.cancelOnce.Do(func() {
		close(b.cancelled)
	})
}

// Returns a channel which is closed ("never blocks") when the job is cancelled.
func (b *Config) WaitCancelled() <-chan struct{} {
	return b.cancelled
}

func NewBuildConfig() *Config {
	return &Config{
		AuthConfig: &cliconfig.AuthConfig{},
		ConfigFile: &cliconfig.ConfigFile{},
		cancelled:  make(chan struct{}),
	}
}

func Build(d *daemon.Daemon, buildConfig *Config) error {
	var (
		repoName string
		tag      string
		context  io.ReadCloser
	)

	repoName, tag = parsers.ParseRepositoryTag(buildConfig.RepoName)
	if repoName != "" {
		if err := registry.ValidateRepositoryName(repoName); err != nil {
			return err
		}
		if len(tag) > 0 {
			if err := graph.ValidateTagName(tag); err != nil {
				return err
			}
		}
	}

	if buildConfig.RemoteURL == "" {
		context = ioutil.NopCloser(buildConfig.Context)
	} else if urlutil.IsGitURL(buildConfig.RemoteURL) {
		if !urlutil.IsGitTransport(buildConfig.RemoteURL) {
			buildConfig.RemoteURL = "https://" + buildConfig.RemoteURL
		}
		root, err := ioutil.TempDir("", "docker-build-git")
		if err != nil {
			return err
		}
		defer os.RemoveAll(root)

		if output, err := exec.Command("git", "clone", "--recursive", buildConfig.RemoteURL, root).CombinedOutput(); err != nil {
			return fmt.Errorf("Error trying to use git: %s (%s)", err, output)
		}

		c, err := archive.Tar(root, archive.Uncompressed)
		if err != nil {
			return err
		}
		context = c
	} else if urlutil.IsURL(buildConfig.RemoteURL) {
		f, err := httputils.Download(buildConfig.RemoteURL)
		if err != nil {
			return err
		}
		defer f.Body.Close()
		dockerFile, err := ioutil.ReadAll(f.Body)
		if err != nil {
			return err
		}

		// When we're downloading just a Dockerfile put it in
		// the default name - don't allow the client to move/specify it
		buildConfig.DockerfileName = api.DefaultDockerfileName

		c, err := archive.Generate(buildConfig.DockerfileName, string(dockerFile))
		if err != nil {
			return err
		}
		context = c
	}
	defer context.Close()

	sf := streamformatter.NewStreamFormatter(buildConfig.JSONFormat)

	builder := &Builder{
		Daemon: d,
		OutStream: &streamformatter.StdoutFormater{
			Writer:          buildConfig.Stdout,
			StreamFormatter: sf,
		},
		ErrStream: &streamformatter.StderrFormater{
			Writer:          buildConfig.Stdout,
			StreamFormatter: sf,
		},
		Verbose:         !buildConfig.SuppressOutput,
		UtilizeCache:    !buildConfig.NoCache,
		Remove:          buildConfig.Remove,
		ForceRemove:     buildConfig.ForceRemove,
		Pull:            buildConfig.Pull,
		OutOld:          buildConfig.Stdout,
		StreamFormatter: sf,
		AuthConfig:      buildConfig.AuthConfig,
		ConfigFile:      buildConfig.ConfigFile,
		dockerfileName:  buildConfig.DockerfileName,
		cpuShares:       buildConfig.CpuShares,
		cpuSetCpus:      buildConfig.CpuSetCpus,
		cpuSetMems:      buildConfig.CpuSetMems,
		memory:          buildConfig.Memory,
		memorySwap:      buildConfig.MemorySwap,
		cancelled:       buildConfig.WaitCancelled(),
	}

	id, err := builder.Run(context)
	if err != nil {
		return err
	}

	if repoName != "" {
		return d.Repositories().Tag(repoName, tag, id, true)
	}
	return nil
}

func BuildFromConfig(d *daemon.Daemon, c *runconfig.Config, changes []string) (*runconfig.Config, error) {
	ast, err := parser.Parse(bytes.NewBufferString(strings.Join(changes, "\n")))
	if err != nil {
		return nil, err
	}

	// ensure that the commands are valid
	for _, n := range ast.Children {
		if !validCommitCommands[n.Value] {
			return nil, fmt.Errorf("%s is not a valid change command", n.Value)
		}
	}

	builder := &Builder{
		Daemon:        d,
		Config:        c,
		OutStream:     ioutil.Discard,
		ErrStream:     ioutil.Discard,
		disableCommit: true,
	}

	for i, n := range ast.Children {
		if err := builder.dispatch(i, n); err != nil {
			return nil, err
		}
	}

	return builder.Config, nil
}

func Commit(d *daemon.Daemon, name string, c *daemon.ContainerCommitConfig) (string, error) {
	container, err := d.Get(name)
	if err != nil {
		return "", err
	}

	newConfig, err := BuildFromConfig(d, c.Config, c.Changes)
	if err != nil {
		return "", err
	}

	if err := runconfig.Merge(newConfig, container.Config); err != nil {
		return "", err
	}

	img, err := d.Commit(container, c.Repo, c.Tag, c.Comment, c.Author, c.Pause, newConfig)
	if err != nil {
		return "", err
	}

	return img.ID, nil
}
<commit_msg>Shallow clone using git to build images.<commit_after>package builder

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
	"sync"

	"github.com/docker/docker/api"
	"github.com/docker/docker/builder/parser"
	"github.com/docker/docker/cliconfig"
	"github.com/docker/docker/daemon"
	"github.com/docker/docker/graph"
	"github.com/docker/docker/pkg/archive"
	"github.com/docker/docker/pkg/httputils"
	"github.com/docker/docker/pkg/parsers"
	"github.com/docker/docker/pkg/streamformatter"
	"github.com/docker/docker/pkg/urlutil"
	"github.com/docker/docker/registry"
	"github.com/docker/docker/runconfig"
)

// whitelist of commands allowed for a commit/import
var validCommitCommands = map[string]bool{
	"entrypoint": true,
	"cmd":        true,
	"user":       true,
	"workdir":    true,
	"env":        true,
	"volume":     true,
	"expose":     true,
	"onbuild":    true,
}

type Config struct {
	DockerfileName string
	RemoteURL      string
	RepoName       string
	SuppressOutput bool
	NoCache        bool
	Remove         bool
	ForceRemove    bool
	Pull           bool
	JSONFormat     bool
	Memory         int64
	MemorySwap     int64
	CpuShares      int64
	CpuSetCpus     string
	CpuSetMems     string
	AuthConfig     *cliconfig.AuthConfig
	ConfigFile     *cliconfig.ConfigFile

	Stdout  io.Writer
	Context io.ReadCloser
	// When closed, the job has been cancelled.
	// Note: not all jobs implement cancellation.
	// See Job.Cancel() and Job.WaitCancelled()
	cancelled  chan struct{}
	cancelOnce sync.Once
}

// When called, causes the Job.WaitCancelled channel to unblock.
func (b *Config) Cancel() {
	b.cancelOnce.Do(func() {
		close(b.cancelled)
	})
}

// Returns a channel which is closed ("never blocks") when the job is cancelled.
func (b *Config) WaitCancelled() <-chan struct{} {
	return b.cancelled
}

func NewBuildConfig() *Config {
	return &Config{
		AuthConfig: &cliconfig.AuthConfig{},
		ConfigFile: &cliconfig.ConfigFile{},
		cancelled:  make(chan struct{}),
	}
}

func Build(d *daemon.Daemon, buildConfig *Config) error {
	var (
		repoName string
		tag      string
		context  io.ReadCloser
	)

	repoName, tag = parsers.ParseRepositoryTag(buildConfig.RepoName)
	if repoName != "" {
		if err := registry.ValidateRepositoryName(repoName); err != nil {
			return err
		}
		if len(tag) > 0 {
			if err := graph.ValidateTagName(tag); err != nil {
				return err
			}
		}
	}

	if buildConfig.RemoteURL == "" {
		context = ioutil.NopCloser(buildConfig.Context)
	} else if urlutil.IsGitURL(buildConfig.RemoteURL) {
		if !urlutil.IsGitTransport(buildConfig.RemoteURL) {
			buildConfig.RemoteURL = "https://" + buildConfig.RemoteURL
		}
		root, err := ioutil.TempDir("", "docker-build-git")
		if err != nil {
			return err
		}
		defer os.RemoveAll(root)

		if output, err := exec.Command("git", "clone", "--depth", "1", "--recursive", buildConfig.RemoteURL, root).CombinedOutput(); err != nil {
			return fmt.Errorf("Error trying to use git: %s (%s)", err, output)
		}

		c, err := archive.Tar(root, archive.Uncompressed)
		if err != nil {
			return err
		}
		context = c
	} else if urlutil.IsURL(buildConfig.RemoteURL) {
		f, err := httputils.Download(buildConfig.RemoteURL)
		if err != nil {
			return err
		}
		defer f.Body.Close()
		dockerFile, err := ioutil.ReadAll(f.Body)
		if err != nil {
			return err
		}

		// When we're downloading just a Dockerfile put it in
		// the default name - don't allow the client to move/specify it
		buildConfig.DockerfileName = api.DefaultDockerfileName

		c, err := archive.Generate(buildConfig.DockerfileName, string(dockerFile))
		if err != nil {
			return err
		}
		context = c
	}
	defer context.Close()

	sf := streamformatter.NewStreamFormatter(buildConfig.JSONFormat)

	builder := &Builder{
		Daemon: d,
		OutStream: &streamformatter.StdoutFormater{
			Writer:          buildConfig.Stdout,
			StreamFormatter: sf,
		},
		ErrStream: &streamformatter.StderrFormater{
			Writer:          buildConfig.Stdout,
			StreamFormatter: sf,
		},
		Verbose:         !buildConfig.SuppressOutput,
		UtilizeCache:    !buildConfig.NoCache,
		Remove:          buildConfig.Remove,
		ForceRemove:     buildConfig.ForceRemove,
		Pull:            buildConfig.Pull,
		OutOld:          buildConfig.Stdout,
		StreamFormatter: sf,
		AuthConfig:      buildConfig.AuthConfig,
		ConfigFile:      buildConfig.ConfigFile,
		dockerfileName:  buildConfig.DockerfileName,
		cpuShares:       buildConfig.CpuShares,
		cpuSetCpus:      buildConfig.CpuSetCpus,
		cpuSetMems:      buildConfig.CpuSetMems,
		memory:          buildConfig.Memory,
		memorySwap:      buildConfig.MemorySwap,
		cancelled:       buildConfig.WaitCancelled(),
	}

	id, err := builder.Run(context)
	if err != nil {
		return err
	}

	if repoName != "" {
		return d.Repositories().Tag(repoName, tag, id, true)
	}
	return nil
}

func BuildFromConfig(d *daemon.Daemon, c *runconfig.Config, changes []string) (*runconfig.Config, error) {
	ast, err := parser.Parse(bytes.NewBufferString(strings.Join(changes, "\n")))
	if err != nil {
		return nil, err
	}

	// ensure that the commands are valid
	for _, n := range ast.Children {
		if !validCommitCommands[n.Value] {
			return nil, fmt.Errorf("%s is not a valid change command", n.Value)
		}
	}

	builder := &Builder{
		Daemon:        d,
		Config:        c,
		OutStream:     ioutil.Discard,
		ErrStream:     ioutil.Discard,
		disableCommit: true,
	}

	for i, n := range ast.Children {
		if err := builder.dispatch(i, n); err != nil {
			return nil, err
		}
	}

	return builder.Config, nil
}

func Commit(d *daemon.Daemon, name string, c *daemon.ContainerCommitConfig) (string, error) {
	container, err := d.Get(name)
	if err != nil {
		return "", err
	}

	newConfig, err := BuildFromConfig(d, c.Config, c.Changes)
	if err != nil {
		return "", err
	}

	if err := runconfig.Merge(newConfig, container.Config); err != nil {
		return "", err
	}

	img, err := d.Commit(container, c.Repo, c.Tag, c.Comment, c.Author, c.Pause, newConfig)
	if err != nil {
		return "", err
	}

	return img.ID, nil
}
<|endoftext|>


<commit_before>package cache

import (
	log "logging"
	"net/url"
)

type BackendInitializer func(*url.URL) Backend

var (
	defaultCacheUrl string
	backends        = map[string]BackendInitializer{}
	codecs          = map[string]*Codec{}
)

type Backend interface {
	Set(key string, b []byte, timeout int) error
	Get(key string) ([]byte, error)
	GetMulti(keys []string) (map[string][]byte, error)
	Delete(key string) error
	Close() error
}

type Codec struct {
	Encode func(v interface{}) ([]byte, error)
	Decode func(data []byte, v interface{}) error
}

type Cache struct {
	Prefix  string
	Backend Backend
	Codec   *Codec
}

func (c *Cache) manipulatesKeys() bool {
	return c.Prefix != ""
}

func (c *Cache) backendKey(key string) string {
	return c.Prefix + key
}

func (c *Cache) frontendKey(key string) string {
	if c.Prefix != "" {
		return key[len(c.Prefix):]
	}
	return key
}

func (c *Cache) Set(key string, object interface{}, timeout int) {
	b, err := c.Codec.Encode(&object)
	if err != nil {
		log.Errorf("Error encoding object for key %s: %s", key, err)
		return
	}
	c.SetBytes(key, b, timeout)
}

func (c *Cache) Get(key string) interface{} {
	b := c.GetBytes(key)
	if b != nil {
		var object interface{}
		err := c.Codec.Decode(b, &object)
		if err != nil {
			log.Errorf("Error decoding object for key %s: %s", key, err)
		}
		return object
	}
	return nil
}

func (c *Cache) GetMulti(keys []string) map[string]interface{} {
	if c.manipulatesKeys() {
		k := make([]string, len(keys))
		for ii, v := range keys {
			k[ii] = c.backendKey(v)
		}
		keys = k
	}
	data, err := c.Backend.GetMulti(keys)
	if err != nil {
		log.Errorf("Error querying cache for keys %v: %v", keys, err)
		return nil
	}
	objects := make(map[string]interface{}, len(data))
	if c.manipulatesKeys() {
		for k, v := range data {
			var object interface{}
			err := c.Codec.Decode(v, &object)
			if err != nil {
				log.Errorf("Error decoding object for key %s: %s", k, err)
				continue
			}
			objects[c.frontendKey(k)] = object
		}
	} else {
		for k, v := range data {
			var object interface{}
			err := c.Codec.Decode(v, &object)
			if err != nil {
				log.Errorf("Error decoding object for key %s: %s", k, err)
				continue
			}
			objects[k] = object
		}
	}
	return objects
}

func (c *Cache) SetBytes(key string, b []byte, timeout int) {
	log.Debugf("Setting key %s", c.backendKey(key))
	err := c.Backend.Set(c.backendKey(key), b, timeout)
	if err != nil {
		log.Errorf("Error setting cache key %s: %s", key, err)
	}
}

func (c *Cache) GetBytes(key string) []byte {
	b, err := c.Backend.Get(c.backendKey(key))
	if err != nil {
		log.Errorf("Error getting cache key %s: %s", key, err)
		return nil
	}
	return b
}

func (c *Cache) Delete(key string) {
	err := c.Backend.Delete(c.backendKey(key))
	if err != nil {
		log.Errorf("Error deleting cache key %s: %s", key, err)
	}
}

func (c *Cache) Close() {
	c.Backend.Close()
}

func RegisterBackend(scheme string, f BackendInitializer) {
	backends[scheme] = f
}

func RegisterCodec(name string, codec *Codec) {
	codecs[name] = codec
}

func SetDefaultCacheUrl(url string) {
	defaultCacheUrl = url
}

func DefaultCacheUrl() string {
	return defaultCacheUrl
}

func New(cacheUrl string) *Cache {
	cache := &Cache{}
	var query url.Values
	u, err := url.Parse(cacheUrl)
	if err != nil {
		if err != nil {
			log.Errorf("Invalid cache URL '%s': %s\n", cacheUrl, err)
		}
	} else {
		query = u.Query()
	}
	var codec *Codec = nil
	if query != nil {
		codecName := query.Get("codec")
		if codecName != "" {
			if c, ok := codecs[codecName]; ok {
				codec = c
			} else {
				log.Errorf("Unknown cache codec name '%s'\n", codecName)
			}
		}
		cache.Prefix = query.Get("prefix")
	}
	if codec == nil {
		codec = &GobEncoder
	}
	cache.Codec = codec
	var backendInitializer BackendInitializer
	if u != nil {
		backendInitializer = backends[u.Scheme]
		if backendInitializer == nil {
			log.Errorf("Unknown cache backend type '%s'\n", u.Scheme)
		}
	}
	if backendInitializer == nil {
		backendInitializer = InitializeDummyBackend
	}
	cache.Backend = backendInitializer(u)
	return cache
}

func NewDefault() *Cache {
	return New(defaultCacheUrl)
}
<commit_msg>Don't log an error message when the url is empty<commit_after>package cache

import (
	log "logging"
	"net/url"
)

type BackendInitializer func(*url.URL) Backend

var (
	defaultCacheUrl string
	backends        = map[string]BackendInitializer{}
	codecs          = map[string]*Codec{}
)

type Backend interface {
	Set(key string, b []byte, timeout int) error
	Get(key string) ([]byte, error)
	GetMulti(keys []string) (map[string][]byte, error)
	Delete(key string) error
	Close() error
}

type Codec struct {
	Encode func(v interface{}) ([]byte, error)
	Decode func(data []byte, v interface{}) error
}

type Cache struct {
	Prefix  string
	Backend Backend
	Codec   *Codec
}

func (c *Cache) manipulatesKeys() bool {
	return c.Prefix != ""
}

func (c *Cache) backendKey(key string) string {
	return c.Prefix + key
}

func (c *Cache) frontendKey(key string) string {
	if c.Prefix != "" {
		return key[len(c.Prefix):]
	}
	return key
}

func (c *Cache) Set(key string, object interface{}, timeout int) {
	b, err := c.Codec.Encode(&object)
	if err != nil {
		log.Errorf("Error encoding object for key %s: %s", key, err)
		return
	}
	c.SetBytes(key, b, timeout)
}

func (c *Cache) Get(key string) interface{} {
	b := c.GetBytes(key)
	if b != nil {
		var object interface{}
		err := c.Codec.Decode(b, &object)
		if err != nil {
			log.Errorf("Error decoding object for key %s: %s", key, err)
		}
		return object
	}
	return nil
}

func (c *Cache) GetMulti(keys []string) map[string]interface{} {
	if c.manipulatesKeys() {
		k := make([]string, len(keys))
		for ii, v := range keys {
			k[ii] = c.backendKey(v)
		}
		keys = k
	}
	data, err := c.Backend.GetMulti(keys)
	if err != nil {
		log.Errorf("Error querying cache for keys %v: %v", keys, err)
		return nil
	}
	objects := make(map[string]interface{}, len(data))
	if c.manipulatesKeys() {
		for k, v := range data {
			var object interface{}
			err := c.Codec.Decode(v, &object)
			if err != nil {
				log.Errorf("Error decoding object for key %s: %s", k, err)
				continue
			}
			objects[c.frontendKey(k)] = object
		}
	} else {
		for k, v := range data {
			var object interface{}
			err := c.Codec.Decode(v, &object)
			if err != nil {
				log.Errorf("Error decoding object for key %s: %s", k, err)
				continue
			}
			objects[k] = object
		}
	}
	return objects
}

func (c *Cache) SetBytes(key string, b []byte, timeout int) {
	log.Debugf("Setting key %s", c.backendKey(key))
	err := c.Backend.Set(c.backendKey(key), b, timeout)
	if err != nil {
		log.Errorf("Error setting cache key %s: %s", key, err)
	}
}

func (c *Cache) GetBytes(key string) []byte {
	b, err := c.Backend.Get(c.backendKey(key))
	if err != nil {
		log.Errorf("Error getting cache key %s: %s", key, err)
		return nil
	}
	return b
}

func (c *Cache) Delete(key string) {
	err := c.Backend.Delete(c.backendKey(key))
	if err != nil {
		log.Errorf("Error deleting cache key %s: %s", key, err)
	}
}

func (c *Cache) Close() {
	c.Backend.Close()
}

func RegisterBackend(scheme string, f BackendInitializer) {
	backends[scheme] = f
}

func RegisterCodec(name string, codec *Codec) {
	codecs[name] = codec
}

func SetDefaultCacheUrl(url string) {
	defaultCacheUrl = url
}

func DefaultCacheUrl() string {
	return defaultCacheUrl
}

func New(cacheUrl string) *Cache {
	cache := &Cache{}
	var query url.Values
	u, err := url.Parse(cacheUrl)
	if err != nil {
		if err != nil && cacheUrl != "" {
			log.Errorf("Invalid cache URL '%s': %s\n", cacheUrl, err)
		}
	} else {
		query = u.Query()
	}
	var codec *Codec = nil
	if query != nil {
		codecName := query.Get("codec")
		if codecName != "" {
			if c, ok := codecs[codecName]; ok {
				codec = c
			} else {
				log.Errorf("Unknown cache codec name '%s'\n", codecName)
			}
		}
		cache.Prefix = query.Get("prefix")
	}
	if codec == nil {
		codec = &GobEncoder
	}
	cache.Codec = codec
	var backendInitializer BackendInitializer
	if u != nil {
		backendInitializer = backends[u.Scheme]
		if backendInitializer == nil {
			log.Errorf("Unknown cache backend type '%s'\n", u.Scheme)
		}
	}
	if backendInitializer == nil {
		backendInitializer = InitializeDummyBackend
	}
	cache.Backend = backendInitializer(u)
	return cache
}

func NewDefault() *Cache {
	return New(defaultCacheUrl)
}
<|endoftext|>


<commit_before>package cache

import (
	"context"

	"github.com/go-redis/redis/v8"
)

type RedisService struct {
	Ctx context.Context
	Cli *redis.Client
	Opt *redis.Options
}

func NewRedis(opt *redis.Options) (*RedisService, error) {
	rdb := redis.NewClient(opt)
	return &RedisService{Ctx: context.Background(), Cli: rdb, Opt: opt}, nil
}

func (r *RedisService) Get(key string) (string, error) {
	val, err := r.Cli.Get(r.Ctx, key).Result()
	return val, err
}

func (r *RedisService) Set (key, val string) error {
	return r.Cli.Set(r.Ctx, key, val, 0).Err()
}

func (r *RedisService) IsNil (err error) bool {
	if err == redis.Nil {
		return true
	}
	return false
}
<commit_msg>fix api<commit_after>package cache

import (
	"context"

	"github.com/go-redis/redis/v8"
)

type RedisService struct {
	Ctx context.Context
	Cli *redis.Client
	Opt *redis.Options
}

func NewRedis(opt *redis.Options) (*RedisService, error) {
	rdb := redis.NewClient(opt)
	return &RedisService{Ctx: context.Background(), Cli: rdb, Opt: opt}, nil
}

func (r *RedisService) Get(key string) (string, error) {
	val, err := r.Cli.Get(r.Ctx, key).Result()
	return val, err
}

func (r *RedisService) Set (key, val string) error {
	return r.Cli.Set(r.Ctx, key, val, 0).Err()
}

func (r *RedisService) IsNil (e interface{}) bool {
	err, ok := e.(error)
	if !ok {
		return false
	}
	if err == redis.Nil {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>package cache

import (
	"github.com/garyburd/redigo/redis"
	"github.com/revel/revel"
	"time"
)

// Wraps the Redis client to meet the Cache interface.
type RedisCache struct {
	pool              *redis.Pool
	defaultExpiration time.Duration
}

// until redigo supports sharding/clustering, only one host will be in hostList
func NewRedisCache(host string, password string, defaultExpiration time.Duration) RedisCache {
	var pool = &redis.Pool{
		MaxIdle:     revel.Config.IntDefault("cache.redis.maxidle", 5),
		MaxActive:   revel.Config.IntDefault("cache.redis.maxactive", 0),
		IdleTimeout: time.Duration(revel.Config.IntDefault("cache.redis.idletimeout", 240)) * time.Second,
		Dial: func() (redis.Conn, error) {
			protocol := revel.Config.StringDefault("cache.redis.protocol", "tcp")
			c, err := redis.Dial(protocol, host)
			if err != nil {
				return nil, err
			}
			if len(password) > 0 {
				if _, err := c.Do("AUTH", password); err != nil {
					c.Close()
					return nil, err
				}
			} else {
				// check with PING
				if _, err := c.Do("PING"); err != nil {
					c.Close()
					return nil, err
				}
			}
			return c, err
		},
		// custom connection test method
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			if _, err := c.Do("PING"); err != nil {
				return err
			}
			return nil
		},
	}
	return RedisCache{pool, defaultExpiration}
}

func (c RedisCache) Set(key string, value interface{}, expires time.Duration) error {
	conn := c.pool.Get()
	defer conn.Close()
	return c.invoke(conn.Do, key, value, expires)
}

func (c RedisCache) Add(key string, value interface{}, expires time.Duration) error {
	conn := c.pool.Get()
	defer conn.Close()
	if exists(conn, key) {
		return ErrNotStored
	}
	return c.invoke(conn.Do, key, value, expires)
}

func (c RedisCache) Replace(key string, value interface{}, expires time.Duration) error {
	conn := c.pool.Get()
	defer conn.Close()
	if !exists(conn, key) {
		return ErrNotStored
	}
	err := c.invoke(conn.Do, key, value, expires)
	if value == nil {
		return ErrNotStored
	} else {
		return err
	}
}

func (c RedisCache) Get(key string, ptrValue interface{}) error {
	conn := c.pool.Get()
	defer conn.Close()
	raw, err := conn.Do("GET", key)
	if raw == nil {
		return ErrCacheMiss
	}
	item, err := redis.Bytes(raw, err)
	if err != nil {
		return err
	}
	return Deserialize(item, ptrValue)
}

func (c RedisCache) GetMulti(keys ...string) (Getter, error) {
	conn := c.pool.Get()
	defer conn.Close()
	items, err := redis.Values(conn.Do("MGET", keys))
	// now put them in a map of string:[]bytes
	m := make(map[string][]byte)
	for i, key := range keys {
		if items[i] != nil {
			s, ok := items[i].([]byte)
			if !ok {
				// the assertion failed.
				m[key] = nil
			} else {
				m[key] = s
			}
		} else {
			m[key] = nil
		}
	}
	if err != nil {

		return nil, err
	}
	return RedisItemMapGetter(m), nil
}

func exists(conn redis.Conn, key string) bool {
	retval, _ := redis.Bool(conn.Do("EXISTS", key))
	return retval
}

func (c RedisCache) Delete(key string) error {
	conn := c.pool.Get()
	defer conn.Close()
	existed, err := redis.Bool(conn.Do("DEL", key))
	if err == nil && !existed {
		err = ErrCacheMiss
	}
	return err
}

func (c RedisCache) Increment(key string, delta uint64) (uint64, error) {
	conn := c.pool.Get()
	defer conn.Close()
	// Check for existance *before* increment as per the cache contract.
	// redis will auto create the key, and we don't want that. Since we need to do increment
	// ourselves instead of natively via INCRBY (redis doesn't support wrapping), we get the value
	// and do the exists check this way to minimize calls to Redis
	val, err := conn.Do("GET", key)
	if val == nil {
		return 0, ErrCacheMiss
	}
	if err == nil {
		currentVal, err := redis.Int64(val, nil)
		if err != nil {
			return 0, err
		}
		var sum int64 = currentVal + int64(delta)
		_, err = conn.Do("SET", key, sum)
		if err != nil {
			return 0, err
		}
		return uint64(sum), nil
	} else {
		return 0, err
	}
}

func (c RedisCache) Decrement(key string, delta uint64) (newValue uint64, err error) {
	conn := c.pool.Get()
	defer conn.Close()
	// Check for existance *before* increment as per the cache contract.
	// redis will auto create the key, and we don't want that, hence the exists call
	if !exists(conn, key) {
		return 0, ErrCacheMiss
	}
	// Decrement contract says you can only go to 0
	// so we go fetch the value and if the delta is greater than the amount,
	// 0 out the value
	currentVal, err := redis.Int64(conn.Do("GET", key))
	if err == nil && delta > uint64(currentVal) {
		tempint, err := redis.Int64(conn.Do("DECRBY", key, currentVal))
		return uint64(tempint), err
	}
	tempint, err := redis.Int64(conn.Do("DECRBY", key, delta))
	return uint64(tempint), err
}

func (c RedisCache) Flush() error {
	conn := c.pool.Get()
	defer conn.Close()
	_, err := conn.Do("FLUSHALL")
	return err
}

func (c RedisCache) invoke(f func(string, ...interface{}) (interface{}, error),
	key string, value interface{}, expires time.Duration) error {

	switch expires {
	case DEFAULT:
		expires = c.defaultExpiration
	case FOREVER:
		expires = time.Duration(0)
	}

	b, err := Serialize(value)
	if err != nil {
		return err
	}
	conn := c.pool.Get()
	defer conn.Close()
	if expires > 0 {
		_, err := f("SETEX", key, int32(expires/time.Second), b)
		return err
	} else {
		_, err := f("SET", key, b)
		return err
	}
}

// Implement a Getter on top of the returned item map.
type RedisItemMapGetter map[string][]byte

func (g RedisItemMapGetter) Get(key string, ptrValue interface{}) error {
	item, ok := g[key]
	if !ok {
		return ErrCacheMiss
	}
	return Deserialize(item, ptrValue)
}
<commit_msg>RedisCache: fix Get/GetMulti error return<commit_after>package cache

import (
	"github.com/garyburd/redigo/redis"
	"github.com/revel/revel"
	"time"
)

// Wraps the Redis client to meet the Cache interface.
type RedisCache struct {
	pool              *redis.Pool
	defaultExpiration time.Duration
}

// until redigo supports sharding/clustering, only one host will be in hostList
func NewRedisCache(host string, password string, defaultExpiration time.Duration) RedisCache {
	var pool = &redis.Pool{
		MaxIdle:     revel.Config.IntDefault("cache.redis.maxidle", 5),
		MaxActive:   revel.Config.IntDefault("cache.redis.maxactive", 0),
		IdleTimeout: time.Duration(revel.Config.IntDefault("cache.redis.idletimeout", 240)) * time.Second,
		Dial: func() (redis.Conn, error) {
			protocol := revel.Config.StringDefault("cache.redis.protocol", "tcp")
			c, err := redis.Dial(protocol, host)
			if err != nil {
				return nil, err
			}
			if len(password) > 0 {
				if _, err := c.Do("AUTH", password); err != nil {
					c.Close()
					return nil, err
				}
			} else {
				// check with PING
				if _, err := c.Do("PING"); err != nil {
					c.Close()
					return nil, err
				}
			}
			return c, err
		},
		// custom connection test method
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			if _, err := c.Do("PING"); err != nil {
				return err
			}
			return nil
		},
	}
	return RedisCache{pool, defaultExpiration}
}

func (c RedisCache) Set(key string, value interface{}, expires time.Duration) error {
	conn := c.pool.Get()
	defer conn.Close()
	return c.invoke(conn.Do, key, value, expires)
}

func (c RedisCache) Add(key string, value interface{}, expires time.Duration) error {
	conn := c.pool.Get()
	defer conn.Close()
	if exists(conn, key) {
		return ErrNotStored
	}
	return c.invoke(conn.Do, key, value, expires)
}

func (c RedisCache) Replace(key string, value interface{}, expires time.Duration) error {
	conn := c.pool.Get()
	defer conn.Close()
	if !exists(conn, key) {
		return ErrNotStored
	}
	err := c.invoke(conn.Do, key, value, expires)
	if value == nil {
		return ErrNotStored
	} else {
		return err
	}
}

func (c RedisCache) Get(key string, ptrValue interface{}) error {
	conn := c.pool.Get()
	defer conn.Close()
	raw, err := conn.Do("GET", key)
	if err != nil {
		return err
	}
	if raw == nil {
		return ErrCacheMiss
	}
	item, err := redis.Bytes(raw, err)
	if err != nil {
		return err
	}
	return Deserialize(item, ptrValue)
}

func (c RedisCache) GetMulti(keys ...string) (Getter, error) {
	conn := c.pool.Get()
	defer conn.Close()
	items, err := redis.Values(conn.Do("MGET", keys))
	if err != nil {
		return nil, err
	}
	// now put them in a map of string:[]bytes
	m := make(map[string][]byte)
	for i, key := range keys {
		if items[i] != nil {
			s, ok := items[i].([]byte)
			if !ok {
				// the assertion failed.
				m[key] = nil
			} else {
				m[key] = s
			}
		} else {
			m[key] = nil
		}
	}
	return RedisItemMapGetter(m), nil
}

func exists(conn redis.Conn, key string) bool {
	retval, _ := redis.Bool(conn.Do("EXISTS", key))
	return retval
}

func (c RedisCache) Delete(key string) error {
	conn := c.pool.Get()
	defer conn.Close()
	existed, err := redis.Bool(conn.Do("DEL", key))
	if err == nil && !existed {
		err = ErrCacheMiss
	}
	return err
}

func (c RedisCache) Increment(key string, delta uint64) (uint64, error) {
	conn := c.pool.Get()
	defer conn.Close()
	// Check for existance *before* increment as per the cache contract.
	// redis will auto create the key, and we don't want that. Since we need to do increment
	// ourselves instead of natively via INCRBY (redis doesn't support wrapping), we get the value
	// and do the exists check this way to minimize calls to Redis
	val, err := conn.Do("GET", key)
	if val == nil {
		return 0, ErrCacheMiss
	}
	if err == nil {
		currentVal, err := redis.Int64(val, nil)
		if err != nil {
			return 0, err
		}
		var sum int64 = currentVal + int64(delta)
		_, err = conn.Do("SET", key, sum)
		if err != nil {
			return 0, err
		}
		return uint64(sum), nil
	} else {
		return 0, err
	}
}

func (c RedisCache) Decrement(key string, delta uint64) (newValue uint64, err error) {
	conn := c.pool.Get()
	defer conn.Close()
	// Check for existance *before* increment as per the cache contract.
	// redis will auto create the key, and we don't want that, hence the exists call
	if !exists(conn, key) {
		return 0, ErrCacheMiss
	}
	// Decrement contract says you can only go to 0
	// so we go fetch the value and if the delta is greater than the amount,
	// 0 out the value
	currentVal, err := redis.Int64(conn.Do("GET", key))
	if err == nil && delta > uint64(currentVal) {
		tempint, err := redis.Int64(conn.Do("DECRBY", key, currentVal))
		return uint64(tempint), err
	}
	tempint, err := redis.Int64(conn.Do("DECRBY", key, delta))
	return uint64(tempint), err
}

func (c RedisCache) Flush() error {
	conn := c.pool.Get()
	defer conn.Close()
	_, err := conn.Do("FLUSHALL")
	return err
}

func (c RedisCache) invoke(f func(string, ...interface{}) (interface{}, error),
	key string, value interface{}, expires time.Duration) error {

	switch expires {
	case DEFAULT:
		expires = c.defaultExpiration
	case FOREVER:
		expires = time.Duration(0)
	}

	b, err := Serialize(value)
	if err != nil {
		return err
	}
	conn := c.pool.Get()
	defer conn.Close()
	if expires > 0 {
		_, err := f("SETEX", key, int32(expires/time.Second), b)
		return err
	} else {
		_, err := f("SET", key, b)
		return err
	}
}

// Implement a Getter on top of the returned item map.
type RedisItemMapGetter map[string][]byte

func (g RedisItemMapGetter) Get(key string, ptrValue interface{}) error {
	item, ok := g[key]
	if !ok {
		return ErrCacheMiss
	}
	return Deserialize(item, ptrValue)
}
<|endoftext|>


<commit_before>package captain // import "github.com/harbur/captain/captain"

import (
	"fmt"
	"os"
	"strings"

	"github.com/spf13/cobra"
)

type Options struct {
	debug  bool
	config string
	images []string
}

var options Options

func handleCmd() {

	var cmdBuild = &cobra.Command{
		Use:   "build [image]",
		Short: "Builds the docker image(s) of your repository",
		Long:  `It will build the docker image(s) described on captain.yml in order they appear on file.`,
		Run: func(cmd *cobra.Command, args []string) {
			config := NewConfig(options, true)

			var images = config.GetImageNames()

			if len(args) == 1 {
				images = filterImages(images, args[0])
			}

			for _, value := range images {
				s := strings.Split(value, "=")
				dockerfile, image := s[0], s[1]

				info("Building image %s", image)
				execute("docker", "build", "-f", dockerfile, "-t", image, ".")

				if isDirty() {
					debug("Skipping tag of %s", image)
				} else {
					var rev = getRevision()
					var imagename = image + ":" + rev
					imagename = imagename + "x"
					info("Tagging image as %s", imagename)
					execute("docker", "tag", "-f", image, imagename)

					var branch = getBranch()
					var branchname = image + ":" + branch
					info("Tagging image as %s", branchname)
					execute("docker", "tag", "-f", image, branchname)
				}
			}
		},
	}

	var cmdTest = &cobra.Command{
		Use:   "test",
		Short: "Runs the unit tests",
		Long:  `It will execute the commands described on unit testing in order they appear on file.`,
		Run: func(cmd *cobra.Command, args []string) {
			config := NewConfig(options, true)

			for _, value := range config.GetUnitTestCommands() {
				info("Running unit test command: %s", value)
				execute("bash", "-c", value)
			}
		},
	}

	var cmdVersion = &cobra.Command{
		Use:   "version",
		Short: "Display version",
		Long:  `Displays the version of Crane.`,
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("v0.0.1")
		},
	}

	var captainCmd = &cobra.Command{
		Use:   "captain",
		Short: "captain - build tool for Docker focused on CI/CD",
		Long: `
Captain, the CLI build tool for Docker made for Continuous Integration / Continuous Delivery.

It works by reading captain.yaml file which describes how to build, test, push and release the docker image(s) of your repository.`,
	}

	captainCmd.PersistentFlags().BoolVarP(&options.debug, "debug", "D", false, "Enable debug mode")
	captainCmd.AddCommand(cmdBuild, cmdTest, cmdVersion)
	captainCmd.Execute()
}

func filterImages(images []string, arg string) []string {
	for _, value := range images {
		s := strings.Split(value, "=")
		_, image := s[0], s[1]
		if image == arg {
			return []string{value}
		}
	}
	err("Build image %s is not defined", arg)
	os.Exit(-1)
	return []string{}
}
<commit_msg>Removed x suffix from imagename<commit_after>package captain // import "github.com/harbur/captain/captain"

import (
	"fmt"
	"os"
	"strings"

	"github.com/spf13/cobra"
)

type Options struct {
	debug  bool
	config string
	images []string
}

var options Options

func handleCmd() {

	var cmdBuild = &cobra.Command{
		Use:   "build [image]",
		Short: "Builds the docker image(s) of your repository",
		Long:  `It will build the docker image(s) described on captain.yml in order they appear on file.`,
		Run: func(cmd *cobra.Command, args []string) {
			config := NewConfig(options, true)

			var images = config.GetImageNames()

			if len(args) == 1 {
				images = filterImages(images, args[0])
			}

			for _, value := range images {
				s := strings.Split(value, "=")
				dockerfile, image := s[0], s[1]

				info("Building image %s", image)
				execute("docker", "build", "-f", dockerfile, "-t", image, ".")

				if isDirty() {
					debug("Skipping tag of %s", image)
				} else {
					var rev = getRevision()
					var imagename = image + ":" + rev
					info("Tagging image as %s", imagename)
					execute("docker", "tag", "-f", image, imagename)

					var branch = getBranch()
					var branchname = image + ":" + branch
					info("Tagging image as %s", branchname)
					execute("docker", "tag", "-f", image, branchname)
				}
			}
		},
	}

	var cmdTest = &cobra.Command{
		Use:   "test",
		Short: "Runs the unit tests",
		Long:  `It will execute the commands described on unit testing in order they appear on file.`,
		Run: func(cmd *cobra.Command, args []string) {
			config := NewConfig(options, true)

			for _, value := range config.GetUnitTestCommands() {
				info("Running unit test command: %s", value)
				execute("bash", "-c", value)
			}
		},
	}

	var cmdVersion = &cobra.Command{
		Use:   "version",
		Short: "Display version",
		Long:  `Displays the version of Crane.`,
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("v0.0.1")
		},
	}

	var captainCmd = &cobra.Command{
		Use:   "captain",
		Short: "captain - build tool for Docker focused on CI/CD",
		Long: `
Captain, the CLI build tool for Docker made for Continuous Integration / Continuous Delivery.

It works by reading captain.yaml file which describes how to build, test, push and release the docker image(s) of your repository.`,
	}

	captainCmd.PersistentFlags().BoolVarP(&options.debug, "debug", "D", false, "Enable debug mode")
	captainCmd.AddCommand(cmdBuild, cmdTest, cmdVersion)
	captainCmd.Execute()
}

func filterImages(images []string, arg string) []string {
	for _, value := range images {
		s := strings.Split(value, "=")
		_, image := s[0], s[1]
		if image == arg {
			return []string{value}
		}
	}
	err("Build image %s is not defined", arg)
	os.Exit(-1)
	return []string{}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	. "github.com/dohodges/fifty2"
	. "github.com/dohodges/fifty2/poker"
	"os"
	"reflect"
	"strings"
)

var (
	game Game
	board []Card
	hands [][]Card
	choose []int
	fullBoard []Card
	fullHands [][]Card
)

type Tally struct {
	Wins int64
	Ties int64
	Losses int64
}

func (t Tally) WinOdds() float64 {
	return 100. * float64(t.Wins) / float64(t.Total())
}

func (t Tally) TieOdds() float64 {
	return 100. * float64(t.Ties) / float64(t.Total())
}

func (t Tally) LossOdds() float64 {
	return 100. * float64(t.Losses) / float64(t.Total())
}

func (t Tally) Total() int64 {
	return t.Wins + t.Ties + t.Losses
}

func (t Tally) Add(t2 Tally) Tally {
	t.Wins += t2.Wins
	t.Ties += t2.Ties
	t.Losses += t2.Losses
	return t
}

func main() {

	var (
		gameFlag  string
		boardFlag string
	)

	flag.StringVar(&gameFlag, "game", string(Holdem), "game")
	flag.StringVar(&boardFlag, "board", "", "community cards")
	flag.Parse()

	game = GetGame(GameType(gameFlag))
	if game.Name == "" {
		fmt.Printf("potodds: unknown game - %s\n", gameFlag)
		os.Exit(1)
	}

	var err error
	board, err = NewCardReader(strings.NewReader(boardFlag)).ReadAll()
	if err != nil {
		fmt.Printf("potodds: invalid board - %v\n", err)
		os.Exit(1)
	} else if len(board) > game.BoardSize {
		fmt.Printf("potodds: %s has a maximum of %d community cards\n", game.Name, game.BoardSize)
		os.Exit(1)
	}

	hands = make([][]Card, flag.NArg())
	for i, arg := range flag.Args() {
		hand, err := NewCardReader(strings.NewReader(arg)).ReadAll()
		if err != nil {
			fmt.Printf("potodds: invalid hand - %v\n", err)
			os.Exit(1)
		} else if len(hand) > game.HandSize {
			fmt.Printf("potodds: %s has a maximum hand size of %d\n", game.Name, game.HandSize)
			os.Exit(1)
		}
		hands[i] = hand
	}

	if len(hands) < 2 {
		fmt.Printf("potodds: specify at least 2 hands\n")
		os.Exit(1)
	}

	deck := NewDeck()
	deck = Remove(deck, board...)
	for _, hand := range hands {
		deck = Remove(deck, hand...)
	}

	// copy known cards to full board and hands
	fullBoard = make([]Card, game.BoardSize)
	copy(fullBoard, board)
	fullHands = make([][]Card, len(hands))
	for i, hand := range hands {
		fullHands[i] = make([]Card, game.HandSize)
		copy(fullHands[i], hand)
	}

	// determine # cards to deal to board and each hand
	deckChoose := game.BoardSize - len(board)
	choose = make([]int, len(hands)+1)
	choose[0] = game.BoardSize - len(board)
	for i, hand := range hands {
		deckChoose += game.HandSize - len(hand)
		choose[i+1] = game.HandSize - len(hand)
	}

	// tally each possible outcome
	tallys := make([]Tally, len(hands))
	for deal := range Combinations(deck, deckChoose) {
		dealTallys := TallyDeal(deal)
		for i := 0; i < len(tallys); i++ {
			tallys[i] = tallys[i].Add(dealTallys[i])
		}
	}

	// results
	fmt.Printf("Game - %s\n", game.Name)
	if game.BoardSize > 0 {
		fmt.Printf("Board %s\n", board)
	}
	for i, tally := range tallys {
		fmt.Printf("Player %d %s - win: %6.2f%%  tie: %6.2f%%  lose: %6.2f%%\n", i+1, hands[i],
			tally.WinOdds(), tally.TieOdds(), tally.LossOdds())
	}

}

func TallyDeal(deal []Card) []Tally {
	tallys := make([]Tally, len(hands))

	// each possible deal
	for dealCombo := range MultipleCombinations(deal, choose) {
		hiStrengths := make([]HandStrength, len(fullHands))
		copy(fullBoard[len(board):], dealCombo[0])
		for i, fullHand := range fullHands {
			copy(fullHand[len(hands[i]):], dealCombo[i+1])
			strength, err := game.HiStrength(fullBoard, fullHand)
			if err != nil {
				strength = HandStrength{} // invalid hand
			}
			hiStrengths[i] = strength
		}

		// tally wins/losses/ties
		max := MaxHandStrength(hiStrengths)
		best := make([]int, 0, len(hiStrengths))
		for i, strength := range hiStrengths {
			if reflect.DeepEqual(strength, max) {
				best = append(best, i)
			} else {
				tallys[i].Losses++
			}
		}
		if len(best) > 1 {
			for i := range best {
				tallys[best[i]].Ties++
			}
		} else {
			tallys[best[0]].Wins++
		}
	}

	return tallys
}
<commit_msg>add progress bar<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/cheggaaa/pb"
	. "github.com/dohodges/fifty2"
	. "github.com/dohodges/fifty2/poker"
	"os"
	"reflect"
	"strings"
)

var (
	game Game
	board []Card
	hands [][]Card
	choose []int
	fullBoard []Card
	fullHands [][]Card
)

type Tally struct {
	Wins int64
	Ties int64
	Losses int64
}

func (t Tally) WinOdds() float64 {
	return 100. * float64(t.Wins) / float64(t.Total())
}

func (t Tally) TieOdds() float64 {
	return 100. * float64(t.Ties) / float64(t.Total())
}

func (t Tally) LossOdds() float64 {
	return 100. * float64(t.Losses) / float64(t.Total())
}

func (t Tally) Total() int64 {
	return t.Wins + t.Ties + t.Losses
}

func (t Tally) Add(t2 Tally) Tally {
	t.Wins += t2.Wins
	t.Ties += t2.Ties
	t.Losses += t2.Losses
	return t
}

func main() {

	var (
		gameFlag  string
		boardFlag string
	)

	flag.StringVar(&gameFlag, "game", string(Holdem), "game")
	flag.StringVar(&boardFlag, "board", "", "community cards")
	flag.Parse()

	game = GetGame(GameType(gameFlag))
	if game.Name == "" {
		fmt.Printf("potodds: unknown game - %s\n", gameFlag)
		os.Exit(1)
	}

	var err error
	board, err = NewCardReader(strings.NewReader(boardFlag)).ReadAll()
	if err != nil {
		fmt.Printf("potodds: invalid board - %v\n", err)
		os.Exit(1)
	} else if len(board) > game.BoardSize {
		fmt.Printf("potodds: %s has a maximum of %d community cards\n", game.Name, game.BoardSize)
		os.Exit(1)
	}

	hands = make([][]Card, flag.NArg())
	for i, arg := range flag.Args() {
		hand, err := NewCardReader(strings.NewReader(arg)).ReadAll()
		if err != nil {
			fmt.Printf("potodds: invalid hand - %v\n", err)
			os.Exit(1)
		} else if len(hand) > game.HandSize {
			fmt.Printf("potodds: %s has a maximum hand size of %d\n", game.Name, game.HandSize)
			os.Exit(1)
		}
		hands[i] = hand
	}

	if len(hands) < 2 {
		fmt.Printf("potodds: specify at least 2 hands\n")
		os.Exit(1)
	}

	deck := NewDeck()
	deck = Remove(deck, board...)
	for _, hand := range hands {
		deck = Remove(deck, hand...)
	}

	// copy known cards to full board and hands
	fullBoard = make([]Card, game.BoardSize)
	copy(fullBoard, board)
	fullHands = make([][]Card, len(hands))
	for i, hand := range hands {
		fullHands[i] = make([]Card, game.HandSize)
		copy(fullHands[i], hand)
	}

	// determine # cards to deal to board and each hand
	deckChoose := game.BoardSize - len(board)
	choose = make([]int, len(hands)+1)
	choose[0] = game.BoardSize - len(board)
	for i, hand := range hands {
		deckChoose += game.HandSize - len(hand)
		choose[i+1] = game.HandSize - len(hand)
	}

	progress := pb.New64(combination(len(deck), deckChoose))
	progress.Start()

	// tally each possible outcome
	tallys := make([]Tally, len(hands))
	for deal := range Combinations(deck, deckChoose) {
		dealTallys := TallyDeal(deal)
		for i := 0; i < len(tallys); i++ {
			tallys[i] = tallys[i].Add(dealTallys[i])
		}
		progress.Increment()
	}
	progress.Finish()

	// results
	fmt.Printf("Game - %s\n", game.Name)
	if game.BoardSize > 0 {
		fmt.Printf("Board %s\n", board)
	}
	for i, tally := range tallys {
		fmt.Printf("Player %2d - win: %6.2f%%  tie: %6.2f%%  lose: %6.2f%%  %s\n", i+1,
			tally.WinOdds(), tally.TieOdds(), tally.LossOdds(), hands[i])
	}

}

func TallyDeal(deal []Card) []Tally {
	tallys := make([]Tally, len(hands))

	// each possible deal
	for dealCombo := range MultipleCombinations(deal, choose) {
		hiStrengths := make([]HandStrength, len(fullHands))
		copy(fullBoard[len(board):], dealCombo[0])
		for i, fullHand := range fullHands {
			copy(fullHand[len(hands[i]):], dealCombo[i+1])
			strength, err := game.HiStrength(fullBoard, fullHand)
			if err != nil {
				strength = HandStrength{} // invalid hand
			}
			hiStrengths[i] = strength
		}

		// tally wins/losses/ties
		max := MaxHandStrength(hiStrengths)
		best := make([]int, 0, len(hiStrengths))
		for i, strength := range hiStrengths {
			if reflect.DeepEqual(strength, max) {
				best = append(best, i)
			} else {
				tallys[i].Losses++
			}
		}
		if len(best) > 1 {
			for i := range best {
				tallys[best[i]].Ties++
			}
		} else {
			tallys[best[0]].Wins++
		}
	}

	return tallys
}

func combination(n, k int) int64 {
	c := int64(n)
	for i := int64(1); i < int64(k); i++ {
		c *= (int64(n)-i)
		c /= i+1
	}
	return c
}
<|endoftext|>


<commit_before>package containeranalysis

import (
	"context"
	"errors"

	containeranalysisapi "cloud.google.com/go/containeranalysis/apiv1"
	grafeasv1 "cloud.google.com/go/grafeas/apiv1"

	"github.com/docker/distribution/reference"
	"google.golang.org/api/iterator"
	grafeas "google.golang.org/genproto/googleapis/grafeas/v1"

	voucher "github.com/grafeas/voucher/v2"
	"github.com/grafeas/voucher/v2/attestation"
	"github.com/grafeas/voucher/v2/docker/uri"
	"github.com/grafeas/voucher/v2/repository"
	"github.com/grafeas/voucher/v2/signer"
)

var errCannotAttest = errors.New("cannot create attestations, keyring is empty")

// Client implements voucher.MetadataClient, connecting to containeranalysis Grafeas.
type Client struct {
	containeranalysis *grafeasv1.Client        // The client reference.
	keyring           signer.AttestationSigner // The keyring used for signing metadata.
	binauthProject    string                   // The project that Binauth Notes and Occurrences are written to.
}

// CanAttest returns true if the client can create and sign attestations.
func (g *Client) CanAttest() bool {
	return nil != g.keyring
}

// NewPayloadBody returns a payload body appropriate for this MetadataClient.
func (g *Client) NewPayloadBody(ref reference.Canonical) (string, error) {
	payload, err := attestation.NewPayload(ref).ToString()
	if err != nil {
		return "", err
	}

	return payload, err
}

// AddAttestationToImage adds a new attestation with the passed Attestation
// to the image described by ImageData.
func (g *Client) AddAttestationToImage(ctx context.Context, ref reference.Canonical, attestation voucher.Attestation) (voucher.SignedAttestation, error) {
	if !g.CanAttest() {
		return voucher.SignedAttestation{}, errCannotAttest
	}

	signedAttestation, err := voucher.SignAttestation(g.keyring, attestation)
	if nil != err {
		return voucher.SignedAttestation{}, err
	}

	_, err = g.containeranalysis.CreateOccurrence(
		ctx,
		newOccurrenceAttestation(
			ref,
			signedAttestation,
			g.binauthProject,
		),
	)

	if isAttestionExistsErr(err) {
		err = nil

		signedAttestation.Signature = ""
	}

	return signedAttestation, err
}

// GetAttestations returns all of the attestations associated with an image.
func (g *Client) GetAttestations(ctx context.Context, ref reference.Canonical) ([]voucher.SignedAttestation, error) {
	filterStr := kindFilterStr(ref, grafeas.NoteKind_ATTESTATION)

	var attestations []voucher.SignedAttestation

	project := projectPath(g.binauthProject)
	req := &grafeas.ListOccurrencesRequest{Parent: project, Filter: filterStr}
	occIterator := g.containeranalysis.ListOccurrences(ctx, req)

	for {
		occ, err := occIterator.Next()
		if nil != err {
			if iterator.Done == err {
				return attestations, nil
			}
			return nil, err
		}

		note, err := g.containeranalysis.GetOccurrenceNote(
			ctx,
			&grafeas.GetOccurrenceNoteRequest{
				Name: occ.GetName(),
			},
		)
		if nil != err {
			return nil, err
		}

		name := getCheckNameFromNoteName(g.binauthProject, note.GetName())

		attestations = append(
			attestations,
			OccurrenceToAttestation(name, occ),
		)
	}
}

// GetVulnerabilities returns the detected vulnerabilities for the Image described by voucher.ImageData.
func (g *Client) GetVulnerabilities(ctx context.Context, ref reference.Canonical) (vulnerabilities []voucher.Vulnerability, err error) {
	filterStr := kindFilterStr(ref, grafeas.NoteKind_VULNERABILITY)

	err = pollForDiscoveries(ctx, g, ref)
	if nil != err {
		return []voucher.Vulnerability{}, err
	}

	project, err := uri.ReferenceToProjectName(ref)
	if nil != err {
		return []voucher.Vulnerability{}, err
	}

	req := &grafeas.ListOccurrencesRequest{Parent: projectPath(project), Filter: filterStr}
	occIterator := g.containeranalysis.ListOccurrences(ctx, req)

	for {
		var occ *grafeas.Occurrence

		occ, err = occIterator.Next()
		if nil != err {
			if iterator.Done == err {
				err = nil
			}

			break
		}

		vuln := OccurrenceToVulnerability(occ)
		vulnerabilities = append(vulnerabilities, vuln)
	}

	return
}

// Close closes the containeranalysis Grafeas client.
func (g *Client) Close() {
	if nil != g.keyring {
		_ = g.keyring.Close()
	}
	g.containeranalysis.Close()
}

// GetBuildDetail gets the BuildDetail for the passed image.
func (g *Client) GetBuildDetail(ctx context.Context, ref reference.Canonical) (repository.BuildDetail, error) {
	var err error

	filterStr := kindFilterStr(ref, grafeas.NoteKind_BUILD)

	project, err := uri.ReferenceToProjectName(ref)
	if nil != err {
		return repository.BuildDetail{}, err
	}

	req := &grafeas.ListOccurrencesRequest{Parent: projectPath(project), Filter: filterStr}
	occIterator := g.containeranalysis.ListOccurrences(ctx, req)

	occ, err := occIterator.Next()
	if err != nil {
		if err == iterator.Done {
			err = &voucher.NoMetadataError{
				Type: voucher.VulnerabilityType,
				Err:  errNoOccurrences,
			}
		}
		return repository.BuildDetail{}, err
	}

	if _, err := occIterator.Next(); err != iterator.Done {
		return repository.BuildDetail{}, errors.New("Found multiple Grafeas occurrences for " + ref.String())
	}

	return OccurrenceToBuildDetail(occ), nil
}

// NewClient creates a new containeranalysis Grafeas Client.
func NewClient(ctx context.Context, binauthProject string, keyring signer.AttestationSigner) (*Client, error) {
	var err error

	caClient, err := containeranalysisapi.NewClient(ctx)
	if err != nil {
		return nil, err
	}

	client := &Client{
		containeranalysis: caClient.GetGrafeasClient(),
		keyring:           keyring,
		binauthProject:    binauthProject,
	}

	return client, nil
}
<commit_msg>containeranalysis: close grpcClient<commit_after>package containeranalysis

import (
	"context"
	"errors"

	containeranalysisapi "cloud.google.com/go/containeranalysis/apiv1"
	grafeasv1 "cloud.google.com/go/grafeas/apiv1"

	"github.com/docker/distribution/reference"
	"google.golang.org/api/iterator"
	grafeas "google.golang.org/genproto/googleapis/grafeas/v1"

	voucher "github.com/grafeas/voucher/v2"
	"github.com/grafeas/voucher/v2/attestation"
	"github.com/grafeas/voucher/v2/docker/uri"
	"github.com/grafeas/voucher/v2/repository"
	"github.com/grafeas/voucher/v2/signer"
)

var errCannotAttest = errors.New("cannot create attestations, keyring is empty")

// Client implements voucher.MetadataClient, connecting to containeranalysis Grafeas.
type Client struct {
	containeranalysis *grafeasv1.Client        // The client reference.
	keyring           signer.AttestationSigner // The keyring used for signing metadata.
	binauthProject    string                   // The project that Binauth Notes and Occurrences are written to.
}

// CanAttest returns true if the client can create and sign attestations.
func (g *Client) CanAttest() bool {
	return nil != g.keyring
}

// NewPayloadBody returns a payload body appropriate for this MetadataClient.
func (g *Client) NewPayloadBody(ref reference.Canonical) (string, error) {
	payload, err := attestation.NewPayload(ref).ToString()
	if err != nil {
		return "", err
	}

	return payload, err
}

// AddAttestationToImage adds a new attestation with the passed Attestation
// to the image described by ImageData.
func (g *Client) AddAttestationToImage(ctx context.Context, ref reference.Canonical, attestation voucher.Attestation) (voucher.SignedAttestation, error) {
	if !g.CanAttest() {
		return voucher.SignedAttestation{}, errCannotAttest
	}

	signedAttestation, err := voucher.SignAttestation(g.keyring, attestation)
	if nil != err {
		return voucher.SignedAttestation{}, err
	}

	_, err = g.containeranalysis.CreateOccurrence(
		ctx,
		newOccurrenceAttestation(
			ref,
			signedAttestation,
			g.binauthProject,
		),
	)

	if isAttestionExistsErr(err) {
		err = nil

		signedAttestation.Signature = ""
	}

	return signedAttestation, err
}

// GetAttestations returns all of the attestations associated with an image.
func (g *Client) GetAttestations(ctx context.Context, ref reference.Canonical) ([]voucher.SignedAttestation, error) {
	filterStr := kindFilterStr(ref, grafeas.NoteKind_ATTESTATION)

	var attestations []voucher.SignedAttestation

	project := projectPath(g.binauthProject)
	req := &grafeas.ListOccurrencesRequest{Parent: project, Filter: filterStr}
	occIterator := g.containeranalysis.ListOccurrences(ctx, req)

	for {
		occ, err := occIterator.Next()
		if nil != err {
			if iterator.Done == err {
				return attestations, nil
			}
			return nil, err
		}

		note, err := g.containeranalysis.GetOccurrenceNote(
			ctx,
			&grafeas.GetOccurrenceNoteRequest{
				Name: occ.GetName(),
			},
		)
		if nil != err {
			return nil, err
		}

		name := getCheckNameFromNoteName(g.binauthProject, note.GetName())

		attestations = append(
			attestations,
			OccurrenceToAttestation(name, occ),
		)
	}
}

// GetVulnerabilities returns the detected vulnerabilities for the Image described by voucher.ImageData.
func (g *Client) GetVulnerabilities(ctx context.Context, ref reference.Canonical) (vulnerabilities []voucher.Vulnerability, err error) {
	filterStr := kindFilterStr(ref, grafeas.NoteKind_VULNERABILITY)

	err = pollForDiscoveries(ctx, g, ref)
	if nil != err {
		return []voucher.Vulnerability{}, err
	}

	project, err := uri.ReferenceToProjectName(ref)
	if nil != err {
		return []voucher.Vulnerability{}, err
	}

	req := &grafeas.ListOccurrencesRequest{Parent: projectPath(project), Filter: filterStr}
	occIterator := g.containeranalysis.ListOccurrences(ctx, req)

	for {
		var occ *grafeas.Occurrence

		occ, err = occIterator.Next()
		if nil != err {
			if iterator.Done == err {
				err = nil
			}

			break
		}

		vuln := OccurrenceToVulnerability(occ)
		vulnerabilities = append(vulnerabilities, vuln)
	}

	return
}

// Close closes the containeranalysis Grafeas client.
func (g *Client) Close() {
	if nil != g.keyring {
		_ = g.keyring.Close()
	}
	g.containeranalysis.Close()
}

// GetBuildDetail gets the BuildDetail for the passed image.
func (g *Client) GetBuildDetail(ctx context.Context, ref reference.Canonical) (repository.BuildDetail, error) {
	var err error

	filterStr := kindFilterStr(ref, grafeas.NoteKind_BUILD)

	project, err := uri.ReferenceToProjectName(ref)
	if nil != err {
		return repository.BuildDetail{}, err
	}

	req := &grafeas.ListOccurrencesRequest{Parent: projectPath(project), Filter: filterStr}
	occIterator := g.containeranalysis.ListOccurrences(ctx, req)

	occ, err := occIterator.Next()
	if err != nil {
		if err == iterator.Done {
			err = &voucher.NoMetadataError{
				Type: voucher.VulnerabilityType,
				Err:  errNoOccurrences,
			}
		}
		return repository.BuildDetail{}, err
	}

	if _, err := occIterator.Next(); err != iterator.Done {
		return repository.BuildDetail{}, errors.New("Found multiple Grafeas occurrences for " + ref.String())
	}

	return OccurrenceToBuildDetail(occ), nil
}

// NewClient creates a new containeranalysis Grafeas Client.
func NewClient(ctx context.Context, binauthProject string, keyring signer.AttestationSigner) (*Client, error) {
	var err error

	caClient, err := containeranalysisapi.NewClient(ctx)
	if err != nil {
		return nil, err
	}
	if err := caClient.Close(); err != nil {
		return nil, err
	}

	client := &Client{
		containeranalysis: caClient.GetGrafeasClient(),
		keyring:           keyring,
		binauthProject:    binauthProject,
	}

	return client, nil
}
<|endoftext|>