<commit_before>package volman_test

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"time"

	"github.com/nu7hatch/gouuid"

	"code.cloudfoundry.org/bbs/models"
	"code.cloudfoundry.org/clock"
	"code.cloudfoundry.org/executor"
	executorinit "code.cloudfoundry.org/executor/initializer"
	"code.cloudfoundry.org/lager"
	"code.cloudfoundry.org/lager/lagertest"
	"github.com/cloudfoundry-incubator/cf-test-helpers/generator"
	. "github.com/onsi/ginkgo"
	ginkgoconfig "github.com/onsi/ginkgo/config"
	. "github.com/onsi/gomega"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"
	"github.com/tedsuo/ifrit/grouper"
)

// these tests could eventually be folded into ../executor/executor_garden_test.go
var _ = Describe("Executor/Garden/Volman", func() {
	var (
		executorClient executor.Client
		process        ifrit.Process
		runner         ifrit.Runner
		cachePath      string
		config         executorinit.Configuration
		logger         lager.Logger
		err            error
	)

	getContainer := func(guid string) executor.Container {
		container, err := executorClient.GetContainer(logger, guid)
		Expect(err).NotTo(HaveOccurred())

		return container
	}

	containerStatePoller := func(guid string) func() executor.State {
		return func() executor.State {
			return getContainer(guid).State
		}
	}
	BeforeEach(func() {
		logger = lagertest.NewTestLogger("volman-executor-tests")

		cachePath, err = ioutil.TempDir("", "executor-tmp")
		Expect(err).NotTo(HaveOccurred())

		config = executorinit.DefaultConfiguration
		config.VolmanDriverPaths = []string{path.Join(componentMaker.VolmanDriverConfigDir, fmt.Sprintf("node-%d", ginkgoconfig.GinkgoConfig.ParallelNode))}
		config.GardenNetwork = "tcp"
		config.GardenAddr = componentMaker.Addresses.GardenLinux
		config.HealthyMonitoringInterval = time.Second
		config.UnhealthyMonitoringInterval = 100 * time.Millisecond
		config.ContainerOwnerName = "executor" + generator.RandomName()
		config.GardenHealthcheckProcessPath = "/bin/sh"
		config.GardenHealthcheckProcessArgs = []string{"-c", "echo", "checking health"}
		config.GardenHealthcheckProcessUser = "vcap"

	})

	Context("when volman is not correctly configured", func() {
		BeforeEach(func() {
			var invalidDriverPath = []string{""}
			config.VolmanDriverPaths = invalidDriverPath

			executorClient, runner = initializeExecutor(logger, config)

			_, err = gardenClient.Capacity()
			Expect(err).NotTo(HaveOccurred())
		})

		AfterEach(func() {
			if executorClient != nil {
				executorClient.Cleanup(logger)
			}

			if process != nil {
				ginkgomon.Kill(process)
			}

			os.RemoveAll(cachePath)
		})

		Context("when allocating a container without any volman mounts", func() {
			var (
				guid               string
				allocationRequest  executor.AllocationRequest
				allocationFailures []executor.AllocationFailure
			)

			JustBeforeEach(func() {
				process = ginkgomon.Invoke(runner)
			})

			BeforeEach(func() {
				id, err := uuid.NewV4()
				Expect(err).NotTo(HaveOccurred())
				guid = id.String()

				tags := executor.Tags{"some-tag": "some-value"}

				allocationRequest = executor.NewAllocationRequest(guid, &executor.Resource{}, tags)

				allocationFailures, err = executorClient.AllocateContainers(logger, []executor.AllocationRequest{allocationRequest})

				Expect(err).NotTo(HaveOccurred())
				Expect(allocationFailures).To(BeEmpty())
			})

			Context("when running the container", func() {
				var (
					runReq executor.RunRequest
				)

				BeforeEach(func() {
					runInfo := executor.RunInfo{
						Action: models.WrapAction(&models.RunAction{
							Path: "/bin/touch",
							User: "root",
							Args: []string{"/tmp"},
						}),
					}
					runReq = executor.NewRunRequest(guid, &runInfo, executor.Tags{})
				})

				It("container start should succeed", func() {
					err := executorClient.RunContainer(logger, &runReq)
					Expect(err).NotTo(HaveOccurred())
					Eventually(containerStatePoller(guid)).Should(Equal(executor.StateCompleted))
					Expect(getContainer(guid).RunResult.Failed).Should(BeFalse())
				})
			})
		})
	})

	Context("when volman is correctly configured", func() {
		BeforeEach(func() {
			executorClient, runner = initializeExecutor(logger, config)

			_, err = gardenClient.Capacity()
			Expect(err).NotTo(HaveOccurred())
		})

		AfterEach(func() {
			if executorClient != nil {
				executorClient.Cleanup(logger)
			}

			if process != nil {
				ginkgomon.Kill(process)
			}

			os.RemoveAll(cachePath)
		})

		Context("when running an executor in front of garden and volman", func() {
			BeforeEach(func() {
				process = ginkgomon.Invoke(runner)
			})

			Context("when allocating a container", func() {
				var (
					guid               string
					allocationRequest  executor.AllocationRequest
					allocationFailures []executor.AllocationFailure
				)

				BeforeEach(func() {
					id, err := uuid.NewV4()
					Expect(err).NotTo(HaveOccurred())
					guid = id.String()

					tags := executor.Tags{"some-tag": "some-value"}

					allocationRequest = executor.NewAllocationRequest(guid, &executor.Resource{}, tags)

					allocationFailures, err = executorClient.AllocateContainers(logger, []executor.AllocationRequest{allocationRequest})

					Expect(err).NotTo(HaveOccurred())
					Expect(allocationFailures).To(BeEmpty())
				})

				Context("when running the container", func() {
					var (
						runReq       executor.RunRequest
						volumeId     string
						fileName     string
						volumeMounts []executor.VolumeMount
					)

					BeforeEach(func() {
						fileName = fmt.Sprintf("testfile-%d.txt", time.Now().UnixNano())
						volumeId = fmt.Sprintf("some-volumeID-%d", time.Now().UnixNano())
						someConfig := map[string]interface{}{"volume_id": volumeId}
						volumeMounts = []executor.VolumeMount{executor.VolumeMount{ContainerPath: "/testmount", Driver: "localdriver", VolumeId: volumeId, Config: someConfig, Mode: executor.BindMountModeRW}}
						runInfo := executor.RunInfo{
							VolumeMounts: volumeMounts,
							Privileged:   true,
							Action: models.WrapAction(&models.RunAction{
								Path: "/bin/touch",
								User: "root",
								Args: []string{"/testmount/" + fileName},
							}),
						}
						runReq = executor.NewRunRequest(guid, &runInfo, executor.Tags{})
					})

					Context("when successfully mounting a RW Mode volume", func() {
						BeforeEach(func() {
							err := executorClient.RunContainer(logger, &runReq)
							Expect(err).NotTo(HaveOccurred())
							Eventually(containerStatePoller(guid)).Should(Equal(executor.StateCompleted))
							Expect(getContainer(guid).RunResult.Failed).Should(BeFalse())
						})

						AfterEach(func() {
							err := executorClient.DeleteContainer(logger, guid)
							Expect(err).NotTo(HaveOccurred())

							files, err := filepath.Glob(path.Join(componentMaker.VolmanDriverConfigDir, "_volumes", volumeId, fileName))
							Expect(err).ToNot(HaveOccurred())
							Expect(len(files)).To(Equal(0))
						})

						It("can write files to the mounted volume", func() {
							By("we expect the file it wrote to be available outside of the container")
							volmanPath := path.Join(componentMaker.VolmanDriverConfigDir, "_volumes", volumeId, fileName)
							files, err := filepath.Glob(volmanPath)
							Expect(err).ToNot(HaveOccurred())
							Expect(len(files)).To(Equal(1))
						})

						Context("when a second container using the same volume loads and then unloads", func() {
							var (
								runReq2   executor.RunRequest
								fileName2 string
								guid2     string
							)
							BeforeEach(func() {
								id, err := uuid.NewV4()
								Expect(err).NotTo(HaveOccurred())
								guid2 = id.String()

								tags := executor.Tags{"some-tag": "some-value"}
								allocationRequest2 := executor.NewAllocationRequest(guid2, &executor.Resource{}, tags)
								allocationFailures, err := executorClient.AllocateContainers(logger, []executor.AllocationRequest{allocationRequest2})
								Expect(err).NotTo(HaveOccurred())
								Expect(allocationFailures).To(BeEmpty())

								fileName2 = fmt.Sprintf("testfile2-%d.txt", time.Now().UnixNano())
								runInfo := executor.RunInfo{
									VolumeMounts: volumeMounts,
									Privileged:   true,
									Action: models.WrapAction(&models.RunAction{
										Path: "/bin/touch",
										User: "root",
										Args: []string{"/testmount/" + fileName2},
									}),
								}
								runReq2 = executor.NewRunRequest(guid2, &runInfo, executor.Tags{})
								err = executorClient.RunContainer(logger, &runReq2)
								Expect(err).NotTo(HaveOccurred())
								Eventually(containerStatePoller(guid2)).Should(Equal(executor.StateCompleted))
								Expect(getContainer(guid2).RunResult.Failed).Should(BeFalse())
								err = executorClient.DeleteContainer(logger, guid2)
								Expect(err).NotTo(HaveOccurred())
							})
							It("can still read files on the mounted volume for the first container", func() {
								volmanPath := path.Join(componentMaker.VolmanDriverConfigDir, "_volumes", volumeId, fileName)
								files, err := filepath.Glob(volmanPath)
								Expect(err).ToNot(HaveOccurred())
								Expect(len(files)).To(Equal(1))
							})
						})

					})
				})
			})
		})
	})
})

func initializeExecutor(logger lager.Logger, config executorinit.Configuration) (executor.Client, ifrit.Runner) {
	var executorMembers grouper.Members
	var err error
	var executorClient executor.Client
	executorClient, executorMembers, err = executorinit.Initialize(logger, config, clock.NewClock())
	Expect(err).NotTo(HaveOccurred())

	return executorClient, grouper.NewParallel(os.Kill, executorMembers)
}
<commit_msg>modify inigo tests to clean up mounted test volumes after unmount [#118660173](https://www.pivotaltracker.com/story/show/118660173)<commit_after>package volman_test

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"time"

	"github.com/nu7hatch/gouuid"

	"code.cloudfoundry.org/bbs/models"
	"code.cloudfoundry.org/clock"
	"code.cloudfoundry.org/executor"
	executorinit "code.cloudfoundry.org/executor/initializer"
	"code.cloudfoundry.org/lager"
	"code.cloudfoundry.org/lager/lagertest"
	"github.com/cloudfoundry-incubator/cf-test-helpers/generator"
	. "github.com/onsi/ginkgo"
	ginkgoconfig "github.com/onsi/ginkgo/config"
	. "github.com/onsi/gomega"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"
	"github.com/tedsuo/ifrit/grouper"
)

// these tests could eventually be folded into ../executor/executor_garden_test.go
var _ = Describe("Executor/Garden/Volman", func() {
	var (
		executorClient executor.Client
		process        ifrit.Process
		runner         ifrit.Runner
		cachePath      string
		config         executorinit.Configuration
		logger         lager.Logger
		err            error
	)

	getContainer := func(guid string) executor.Container {
		container, err := executorClient.GetContainer(logger, guid)
		Expect(err).NotTo(HaveOccurred())

		return container
	}

	containerStatePoller := func(guid string) func() executor.State {
		return func() executor.State {
			return getContainer(guid).State
		}
	}
	BeforeEach(func() {
		logger = lagertest.NewTestLogger("volman-executor-tests")

		cachePath, err = ioutil.TempDir("", "executor-tmp")
		Expect(err).NotTo(HaveOccurred())

		config = executorinit.DefaultConfiguration
		config.VolmanDriverPaths = []string{path.Join(componentMaker.VolmanDriverConfigDir, fmt.Sprintf("node-%d", ginkgoconfig.GinkgoConfig.ParallelNode))}
		config.GardenNetwork = "tcp"
		config.GardenAddr = componentMaker.Addresses.GardenLinux
		config.HealthyMonitoringInterval = time.Second
		config.UnhealthyMonitoringInterval = 100 * time.Millisecond
		config.ContainerOwnerName = "executor" + generator.RandomName()
		config.GardenHealthcheckProcessPath = "/bin/sh"
		config.GardenHealthcheckProcessArgs = []string{"-c", "echo", "checking health"}
		config.GardenHealthcheckProcessUser = "vcap"

	})

	Context("when volman is not correctly configured", func() {
		BeforeEach(func() {
			var invalidDriverPath = []string{""}
			config.VolmanDriverPaths = invalidDriverPath

			executorClient, runner = initializeExecutor(logger, config)

			_, err = gardenClient.Capacity()
			Expect(err).NotTo(HaveOccurred())
		})

		AfterEach(func() {
			if executorClient != nil {
				executorClient.Cleanup(logger)
			}

			if process != nil {
				ginkgomon.Kill(process)
			}

			os.RemoveAll(cachePath)
		})

		Context("when allocating a container without any volman mounts", func() {
			var (
				guid               string
				allocationRequest  executor.AllocationRequest
				allocationFailures []executor.AllocationFailure
			)

			JustBeforeEach(func() {
				process = ginkgomon.Invoke(runner)
			})

			BeforeEach(func() {
				id, err := uuid.NewV4()
				Expect(err).NotTo(HaveOccurred())
				guid = id.String()

				tags := executor.Tags{"some-tag": "some-value"}

				allocationRequest = executor.NewAllocationRequest(guid, &executor.Resource{}, tags)

				allocationFailures, err = executorClient.AllocateContainers(logger, []executor.AllocationRequest{allocationRequest})

				Expect(err).NotTo(HaveOccurred())
				Expect(allocationFailures).To(BeEmpty())
			})

			Context("when running the container", func() {
				var (
					runReq executor.RunRequest
				)

				BeforeEach(func() {
					runInfo := executor.RunInfo{
						Action: models.WrapAction(&models.RunAction{
							Path: "/bin/touch",
							User: "root",
							Args: []string{"/tmp"},
						}),
					}
					runReq = executor.NewRunRequest(guid, &runInfo, executor.Tags{})
				})

				It("container start should succeed", func() {
					err := executorClient.RunContainer(logger, &runReq)
					Expect(err).NotTo(HaveOccurred())
					Eventually(containerStatePoller(guid)).Should(Equal(executor.StateCompleted))
					Expect(getContainer(guid).RunResult.Failed).Should(BeFalse())
				})
			})
		})
	})

	Context("when volman is correctly configured", func() {
		BeforeEach(func() {
			executorClient, runner = initializeExecutor(logger, config)

			_, err = gardenClient.Capacity()
			Expect(err).NotTo(HaveOccurred())
		})

		AfterEach(func() {
			if executorClient != nil {
				executorClient.Cleanup(logger)
			}

			if process != nil {
				ginkgomon.Kill(process)
			}

			os.RemoveAll(cachePath)
		})

		Context("when running an executor in front of garden and volman", func() {
			BeforeEach(func() {
				process = ginkgomon.Invoke(runner)
			})

			Context("when allocating a container", func() {
				var (
					guid               string
					allocationRequest  executor.AllocationRequest
					allocationFailures []executor.AllocationFailure
				)

				BeforeEach(func() {
					id, err := uuid.NewV4()
					Expect(err).NotTo(HaveOccurred())
					guid = id.String()

					tags := executor.Tags{"some-tag": "some-value"}

					allocationRequest = executor.NewAllocationRequest(guid, &executor.Resource{}, tags)

					allocationFailures, err = executorClient.AllocateContainers(logger, []executor.AllocationRequest{allocationRequest})

					Expect(err).NotTo(HaveOccurred())
					Expect(allocationFailures).To(BeEmpty())
				})

				Context("when running the container", func() {
					var (
						runReq       executor.RunRequest
						volumeId     string
						fileName     string
						volumeMounts []executor.VolumeMount
					)

					BeforeEach(func() {
						fileName = fmt.Sprintf("testfile-%d.txt", time.Now().UnixNano())
						volumeId = fmt.Sprintf("some-volumeID-%d", time.Now().UnixNano())
						someConfig := map[string]interface{}{"volume_id": volumeId}
						volumeMounts = []executor.VolumeMount{executor.VolumeMount{ContainerPath: "/testmount", Driver: "localdriver", VolumeId: volumeId, Config: someConfig, Mode: executor.BindMountModeRW}}
						runInfo := executor.RunInfo{
							VolumeMounts: volumeMounts,
							Privileged:   true,
							Action: models.WrapAction(&models.RunAction{
								Path: "/bin/touch",
								User: "root",
								Args: []string{"/testmount/" + fileName},
							}),
						}
						runReq = executor.NewRunRequest(guid, &runInfo, executor.Tags{})
					})

					Context("when successfully mounting a RW Mode volume", func() {
						BeforeEach(func() {
							err := executorClient.RunContainer(logger, &runReq)
							Expect(err).NotTo(HaveOccurred())
							Eventually(containerStatePoller(guid)).Should(Equal(executor.StateCompleted))
							Expect(getContainer(guid).RunResult.Failed).Should(BeFalse())
						})

						AfterEach(func() {
							err := executorClient.DeleteContainer(logger, guid)
							Expect(err).NotTo(HaveOccurred())

							err = os.RemoveAll(path.Join(componentMaker.VolmanDriverConfigDir, "_volumes", volumeId))
							Expect(err).ToNot(HaveOccurred())

							files, err := filepath.Glob(path.Join(componentMaker.VolmanDriverConfigDir, "_volumes", volumeId, fileName))
							Expect(err).ToNot(HaveOccurred())
							Expect(len(files)).To(Equal(0))
						})

						It("can write files to the mounted volume", func() {
							By("we expect the file it wrote to be available outside of the container")
							volmanPath := path.Join(componentMaker.VolmanDriverConfigDir, "_volumes", volumeId, fileName)
							files, err := filepath.Glob(volmanPath)
							Expect(err).ToNot(HaveOccurred())
							Expect(len(files)).To(Equal(1))
						})

						Context("when a second container using the same volume loads and then unloads", func() {
							var (
								runReq2   executor.RunRequest
								fileName2 string
								guid2     string
							)
							BeforeEach(func() {
								id, err := uuid.NewV4()
								Expect(err).NotTo(HaveOccurred())
								guid2 = id.String()

								tags := executor.Tags{"some-tag": "some-value"}
								allocationRequest2 := executor.NewAllocationRequest(guid2, &executor.Resource{}, tags)
								allocationFailures, err := executorClient.AllocateContainers(logger, []executor.AllocationRequest{allocationRequest2})
								Expect(err).NotTo(HaveOccurred())
								Expect(allocationFailures).To(BeEmpty())

								fileName2 = fmt.Sprintf("testfile2-%d.txt", time.Now().UnixNano())
								runInfo := executor.RunInfo{
									VolumeMounts: volumeMounts,
									Privileged:   true,
									Action: models.WrapAction(&models.RunAction{
										Path: "/bin/touch",
										User: "root",
										Args: []string{"/testmount/" + fileName2},
									}),
								}
								runReq2 = executor.NewRunRequest(guid2, &runInfo, executor.Tags{})
								err = executorClient.RunContainer(logger, &runReq2)
								Expect(err).NotTo(HaveOccurred())
								Eventually(containerStatePoller(guid2)).Should(Equal(executor.StateCompleted))
								Expect(getContainer(guid2).RunResult.Failed).Should(BeFalse())
								err = executorClient.DeleteContainer(logger, guid2)
								Expect(err).NotTo(HaveOccurred())
							})
							It("can still read files on the mounted volume for the first container", func() {
								volmanPath := path.Join(componentMaker.VolmanDriverConfigDir, "_volumes", volumeId, fileName)
								files, err := filepath.Glob(volmanPath)
								Expect(err).ToNot(HaveOccurred())
								Expect(len(files)).To(Equal(1))
							})
						})

					})
				})
			})
		})
	})
})

func initializeExecutor(logger lager.Logger, config executorinit.Configuration) (executor.Client, ifrit.Runner) {
	var executorMembers grouper.Members
	var err error
	var executorClient executor.Client
	executorClient, executorMembers, err = executorinit.Initialize(logger, config, clock.NewClock())
	Expect(err).NotTo(HaveOccurred())

	return executorClient, grouper.NewParallel(os.Kill, executorMembers)
}
<|endoftext|>


<commit_before>/*

	Autoreader is a simple program, designed to be run from go:generate, that
	helps generate the annoying boilerplate to implement
	boardgame.PropertyReader and boardgame.PropertyReadSetter.

	Autoreader processes a package of go files, searching for structs that
	have a comment immediately above their declaration that begins with
	"+autoreader". For each such struct, it creates a Reader() and
	PropertyReader() method that just use boardgame.DefaultReader and
	boardgame.DefaultReadSetter.

	If you want only a reader or only a readsetter for a given struct, include
	the keyword "reader" or "readsetter", like so: "+autoreader reader"

	You can configure which package to process and where to write output via
	command-line flags. By default it processes the current package and writes
	its output to auto_reader.go, overwriting whatever file was there before.
	See command-line options by passing -h.

	The defaults are set reasonably so that you can use go:generate very
	easily. See examplepkg/ for a very simple example.

*/
package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"github.com/MarcGrol/golangAnnotations/parser"
	"go/format"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strings"
	"text/template"
)

var headerTemplate *template.Template
var structHeaderTemplate *template.Template
var readerTemplate *template.Template
var readSetterTemplate *template.Template

const magicDocLinePrefix = "+autoreader"

type appOptions struct {
	OutputFile       string
	PackageDirectory string
	PrintToConsole   bool
	Help             bool
	UseReflection    bool
	flagSet          *flag.FlagSet
}

type templateConfig struct {
	FirstLetter string
	StructName  string
}

func init() {
	headerTemplate = template.Must(template.New("header").Parse(headerTemplateText))
	structHeaderTemplate = template.Must(template.New("structHeader").Parse(structHeaderTemplateText))
	readerTemplate = template.Must(template.New("reader").Parse(readerTemplateText))
	readSetterTemplate = template.Must(template.New("readsetter").Parse(readSetterTemplateText))
}

func defineFlags(options *appOptions) {
	options.flagSet.StringVar(&options.OutputFile, "out", "auto_reader.go", "Defines which file to render output to. WARNING: it will be overwritten!")
	options.flagSet.StringVar(&options.PackageDirectory, "pkg", ".", "Which package to process")
	options.flagSet.BoolVar(&options.Help, "h", false, "If set, print help message and quit.")
	options.flagSet.BoolVar(&options.PrintToConsole, "print", false, "If true, will print result to console instead of writing to out.")
	options.flagSet.BoolVar(&options.UseReflection, "reflect", true, "If true, will use reflection based output.")
}

func getOptions(flagSet *flag.FlagSet, flagArguments []string) *appOptions {
	options := &appOptions{flagSet: flagSet}
	defineFlags(options)
	flagSet.Parse(flagArguments)
	return options
}

func main() {
	flagSet := flag.CommandLine
	process(getOptions(flagSet, os.Args[1:]), os.Stdout, os.Stderr)
}

func process(options *appOptions, out io.ReadWriter, errOut io.ReadWriter) {

	if options.Help {
		options.flagSet.SetOutput(out)
		options.flagSet.PrintDefaults()
		return
	}

	output, err := processPackage(options.UseReflection, options.PackageDirectory)

	if err != nil {
		fmt.Fprintln(errOut, "ERROR", err)
		return
	}

	if options.PrintToConsole {
		fmt.Fprintln(out, output)
	} else {
		ioutil.WriteFile(options.OutputFile, []byte(output), 0644)
	}

}

func processPackage(useReflection bool, location string) (output string, err error) {
	sources, err := parser.ParseSourceDir(location, ".*")

	if err != nil {
		return "", errors.New("Couldn't parse sources: " + err.Error())
	}

	haveOutputHeader := false

	for _, theStruct := range sources.Structs {

		if !haveOutputHeader {
			output += headerForPackage(theStruct.PackageName)
			haveOutputHeader = true
		}

		outputReader, outputReadSetter := structConfig(theStruct.DocLines)

		if outputReader || outputReadSetter {
			output += headerForStruct(theStruct.Name)
		}

		if outputReader {
			output += readerForStruct(theStruct.Name)
		}
		if outputReadSetter {
			output += readSetterForStruct(theStruct.Name)
		}
	}

	formattedBytes, err := format.Source([]byte(output))

	if err != nil {
		return "", errors.New("Couldn't go fmt code: " + err.Error())
	}

	return string(formattedBytes), nil
}

func structConfig(docLines []string) (outputReader bool, outputReadSetter bool) {

	for _, docLine := range docLines {
		docLine = strings.ToLower(docLine)
		docLine = strings.TrimPrefix(docLine, "//")
		docLine = strings.TrimSpace(docLine)
		if !strings.HasPrefix(docLine, magicDocLinePrefix) {
			continue
		}
		docLine = strings.TrimPrefix(docLine, magicDocLinePrefix)
		docLine = strings.TrimSpace(docLine)

		switch docLine {
		case "":
			return true, true
		case "both":
			return true, true
		case "reader":
			return true, false
		case "readsetter":
			return false, true
		}

	}
	return false, false
}

func templateOutput(template *template.Template, values interface{}) string {
	buf := new(bytes.Buffer)

	err := template.Execute(buf, values)

	if err != nil {
		log.Println(err)
	}

	return buf.String()
}

func headerForPackage(packageName string) string {
	return templateOutput(headerTemplate, map[string]string{
		"packageName": packageName,
	}) + reflectImportText
}

func headerForStruct(structName string) string {
	return templateOutput(structHeaderTemplate, map[string]string{
		"structName": structName,
	})
}

func readerForStruct(structName string) string {

	return templateOutput(readerTemplate, templateConfig{
		FirstLetter: structName[:1],
		StructName:  structName,
	})

}

func readSetterForStruct(structName string) string {
	return templateOutput(readSetterTemplate, templateConfig{
		FirstLetter: structName[:1],
		StructName:  structName,
	})
}

const headerTemplateText = `/************************************
 *
 * This file contains auto-generated methods to help certain structs
 * implement boardgame.SubState and boardgame.MutableSubState. It was
 * generated by autoreader.
 *
 * DO NOT EDIT by hand.
 *
 ************************************/
package {{.packageName}}
`

const reflectImportText = `import (
	"github.com/jkomoros/boardgame"
)

`

const prodImportText = `import (
	"errors"
	"github.com/jkomoros/boardgame"
)

`

const structHeaderTemplateText = `// Implementation for {{.structName}}

 `

const readerTemplateText = `func ({{.FirstLetter}} *{{.StructName}}) Reader() boardgame.PropertyReader {
	return boardgame.DefaultReader({{.FirstLetter}})
}

`

const readSetterTemplateText = `func ({{.FirstLetter}} *{{.StructName}}) ReadSetter() boardgame.PropertyReadSetter {
	return boardgame.DefaultReadSetter({{.FirstLetter}})
}

`
<commit_msg>Pass through useReflection deeper. Part of #310.<commit_after>/*

	Autoreader is a simple program, designed to be run from go:generate, that
	helps generate the annoying boilerplate to implement
	boardgame.PropertyReader and boardgame.PropertyReadSetter.

	Autoreader processes a package of go files, searching for structs that
	have a comment immediately above their declaration that begins with
	"+autoreader". For each such struct, it creates a Reader() and
	PropertyReader() method that just use boardgame.DefaultReader and
	boardgame.DefaultReadSetter.

	If you want only a reader or only a readsetter for a given struct, include
	the keyword "reader" or "readsetter", like so: "+autoreader reader"

	You can configure which package to process and where to write output via
	command-line flags. By default it processes the current package and writes
	its output to auto_reader.go, overwriting whatever file was there before.
	See command-line options by passing -h.

	The defaults are set reasonably so that you can use go:generate very
	easily. See examplepkg/ for a very simple example.

*/
package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"github.com/MarcGrol/golangAnnotations/parser"
	"go/format"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strings"
	"text/template"
)

var headerTemplate *template.Template
var structHeaderTemplate *template.Template
var readerTemplate *template.Template
var readSetterTemplate *template.Template

const magicDocLinePrefix = "+autoreader"

type appOptions struct {
	OutputFile       string
	PackageDirectory string
	PrintToConsole   bool
	Help             bool
	UseReflection    bool
	flagSet          *flag.FlagSet
}

type templateConfig struct {
	FirstLetter string
	StructName  string
}

func init() {
	headerTemplate = template.Must(template.New("header").Parse(headerTemplateText))
	structHeaderTemplate = template.Must(template.New("structHeader").Parse(structHeaderTemplateText))
	readerTemplate = template.Must(template.New("reader").Parse(readerTemplateText))
	readSetterTemplate = template.Must(template.New("readsetter").Parse(readSetterTemplateText))
}

func defineFlags(options *appOptions) {
	options.flagSet.StringVar(&options.OutputFile, "out", "auto_reader.go", "Defines which file to render output to. WARNING: it will be overwritten!")
	options.flagSet.StringVar(&options.PackageDirectory, "pkg", ".", "Which package to process")
	options.flagSet.BoolVar(&options.Help, "h", false, "If set, print help message and quit.")
	options.flagSet.BoolVar(&options.PrintToConsole, "print", false, "If true, will print result to console instead of writing to out.")
	options.flagSet.BoolVar(&options.UseReflection, "reflect", true, "If true, will use reflection based output.")
}

func getOptions(flagSet *flag.FlagSet, flagArguments []string) *appOptions {
	options := &appOptions{flagSet: flagSet}
	defineFlags(options)
	flagSet.Parse(flagArguments)
	return options
}

func main() {
	flagSet := flag.CommandLine
	process(getOptions(flagSet, os.Args[1:]), os.Stdout, os.Stderr)
}

func process(options *appOptions, out io.ReadWriter, errOut io.ReadWriter) {

	if options.Help {
		options.flagSet.SetOutput(out)
		options.flagSet.PrintDefaults()
		return
	}

	output, err := processPackage(options.UseReflection, options.PackageDirectory)

	if err != nil {
		fmt.Fprintln(errOut, "ERROR", err)
		return
	}

	if options.PrintToConsole {
		fmt.Fprintln(out, output)
	} else {
		ioutil.WriteFile(options.OutputFile, []byte(output), 0644)
	}

}

func processPackage(useReflection bool, location string) (output string, err error) {
	sources, err := parser.ParseSourceDir(location, ".*")

	if err != nil {
		return "", errors.New("Couldn't parse sources: " + err.Error())
	}

	haveOutputHeader := false

	for _, theStruct := range sources.Structs {

		if !haveOutputHeader {
			output += headerForPackage(useReflection, theStruct.PackageName)
			haveOutputHeader = true
		}

		outputReader, outputReadSetter := structConfig(theStruct.DocLines)

		if outputReader || outputReadSetter {
			output += headerForStruct(useReflection, theStruct.Name)
		}

		if outputReader {
			output += readerForStruct(useReflection, theStruct.Name)
		}
		if outputReadSetter {
			output += readSetterForStruct(useReflection, theStruct.Name)
		}
	}

	formattedBytes, err := format.Source([]byte(output))

	if err != nil {
		return "", errors.New("Couldn't go fmt code: " + err.Error())
	}

	return string(formattedBytes), nil
}

func structConfig(docLines []string) (outputReader bool, outputReadSetter bool) {

	for _, docLine := range docLines {
		docLine = strings.ToLower(docLine)
		docLine = strings.TrimPrefix(docLine, "//")
		docLine = strings.TrimSpace(docLine)
		if !strings.HasPrefix(docLine, magicDocLinePrefix) {
			continue
		}
		docLine = strings.TrimPrefix(docLine, magicDocLinePrefix)
		docLine = strings.TrimSpace(docLine)

		switch docLine {
		case "":
			return true, true
		case "both":
			return true, true
		case "reader":
			return true, false
		case "readsetter":
			return false, true
		}

	}
	return false, false
}

func templateOutput(template *template.Template, values interface{}) string {
	buf := new(bytes.Buffer)

	err := template.Execute(buf, values)

	if err != nil {
		log.Println(err)
	}

	return buf.String()
}

func headerForPackage(useReflection bool, packageName string) string {
	return templateOutput(headerTemplate, map[string]string{
		"packageName": packageName,
	}) + reflectImportText
}

func headerForStruct(useReflection bool, structName string) string {
	return templateOutput(structHeaderTemplate, map[string]string{
		"structName": structName,
	})
}

func readerForStruct(useReflection bool, structName string) string {

	return templateOutput(readerTemplate, templateConfig{
		FirstLetter: structName[:1],
		StructName:  structName,
	})

}

func readSetterForStruct(useReflection bool, structName string) string {
	return templateOutput(readSetterTemplate, templateConfig{
		FirstLetter: structName[:1],
		StructName:  structName,
	})
}

const headerTemplateText = `/************************************
 *
 * This file contains auto-generated methods to help certain structs
 * implement boardgame.SubState and boardgame.MutableSubState. It was
 * generated by autoreader.
 *
 * DO NOT EDIT by hand.
 *
 ************************************/
package {{.packageName}}
`

const reflectImportText = `import (
	"github.com/jkomoros/boardgame"
)

`

const prodImportText = `import (
	"errors"
	"github.com/jkomoros/boardgame"
)

`

const structHeaderTemplateText = `// Implementation for {{.structName}}

 `

const readerTemplateText = `func ({{.FirstLetter}} *{{.StructName}}) Reader() boardgame.PropertyReader {
	return boardgame.DefaultReader({{.FirstLetter}})
}

`

const readSetterTemplateText = `func ({{.FirstLetter}} *{{.StructName}}) ReadSetter() boardgame.PropertyReadSetter {
	return boardgame.DefaultReadSetter({{.FirstLetter}})
}

`
<|endoftext|>


<commit_before>package main

import (
	"github.com/BytemarkHosting/bytemark-client/util/log"
	"github.com/urfave/cli"
)

func init() {
	adminCommands = append(adminCommands, cli.Command{
		Name:        "revoke",
		Usage:       "revoke privileges on bytemark self-service objects from other users",
		UsageText:   "bytemark revoke <privilege> [on] <object> [from] <user>\r\nbytemark grant cluster_admin [to] <user>",
		Description: "Revoke a privilege from a user for a particular bytemark object\r\n\r\n" + privilegeText,
		Flags: []cli.Flag{
			cli.BoolFlag{
				Name:  "yubikey-required",
				Usage: "Set if the privilege should require a yubikey.",
			},
			cli.GenericFlag{
				Name:  "privilege",
				Usage: "the privilege to revoke",
				Value: new(PrivilegeFlag),
			},
		},
		Action: With(JoinArgs("privilege"), RequiredFlags("privilege"), PrivilegeProvider("privilege"), func(c *Context) (err error) {
			c.Privilege.YubikeyRequired = c.Bool("yubikey-required")

			err = global.Client.RevokePrivilege(c.Privilege)
			if err == nil {
				log.Outputf("Revoked %s\r\n", c.PrivilegeFlag("privilege"))

			}
			return
		}),
	})
}
<commit_msg>revoke - use String() method rather than implicit conversion<commit_after>package main

import (
	"github.com/BytemarkHosting/bytemark-client/util/log"
	"github.com/urfave/cli"
)

func init() {
	adminCommands = append(adminCommands, cli.Command{
		Name:        "revoke",
		Usage:       "revoke privileges on bytemark self-service objects from other users",
		UsageText:   "bytemark revoke <privilege> [on] <object> [from] <user>\r\nbytemark grant cluster_admin [to] <user>",
		Description: "Revoke a privilege from a user for a particular bytemark object\r\n\r\n" + privilegeText,
		Flags: []cli.Flag{
			cli.BoolFlag{
				Name:  "yubikey-required",
				Usage: "Set if the privilege should require a yubikey.",
			},
			cli.GenericFlag{
				Name:  "privilege",
				Usage: "the privilege to revoke",
				Value: new(PrivilegeFlag),
			},
		},
		Action: With(JoinArgs("privilege"), RequiredFlags("privilege"), PrivilegeProvider("privilege"), func(c *Context) (err error) {
			c.Privilege.YubikeyRequired = c.Bool("yubikey-required")

			err = global.Client.RevokePrivilege(c.Privilege)
			if err == nil {
				log.Outputf("Revoked %s\r\n", c.PrivilegeFlag("privilege").String())

			}
			return
		}),
	})
}
<|endoftext|>


<commit_before>//  Copyright (c) 2014 Couchbase, Inc.
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the
//  License. You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//  Unless required by applicable law or agreed to in writing,
//  software distributed under the License is distributed on an "AS
//  IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
//  express or implied. See the License for the specific language
//  governing permissions and limitations under the License.

package main

import (
	"flag"
	"fmt"
	"os"
	"path"
	"sort"
	"strings"
)

type Flags struct {
	BindAddr   string
	CfgConnect string
	Container  string
	DataDir    string
	Help       bool
	Register   string
	Server     string
	StaticDir  string
	StaticETag string
	Tags       string
	Version    bool
	Weight     int
}

var flags Flags
var flagAliases map[string][]string

func init() {
	flagAliases = initFlags(&flags)
}

func initFlags(flags *Flags) map[string][]string {
	flagAliases := map[string][]string{} // main flag name => all aliases.
	flagKinds := map[string]string{}

	s := func(v *string, names []string, kind string,
		defaultVal, usage string) { // String cmd-line param.
		for _, name := range names {
			flag.StringVar(v, name, defaultVal, usage)
		}
		flagAliases[names[0]] = names
		flagKinds[names[0]] = kind
	}

	i := func(v *int, names []string, kind string,
		defaultVal int, usage string) { // Integer cmd-line param.
		for _, name := range names {
			flag.IntVar(v, name, defaultVal, usage)
		}
		flagAliases[names[0]] = names
		flagKinds[names[0]] = kind
	}

	b := func(v *bool, names []string, kind string,
		defaultVal bool, usage string) { // Bool cmd-line param.
		for _, name := range names {
			flag.BoolVar(v, name, defaultVal, usage)
		}
		flagAliases[names[0]] = names
		flagKinds[names[0]] = kind
	}

	s(&flags.BindAddr,
		[]string{"bindAddr"}, "ADDR:PORT", "localhost:8095",
		"optional HTTP/REST listen addr:port;"+
			"\ndefault is 'localhost:8095'.")
	s(&flags.CfgConnect,
		[]string{"cfgConnect", "cfg"}, "CFG_CONNECT", "simple",
		"optional connection string/info to a configuration provider"+
			"\nfor the cluster:"+
			"\n* couchbase:http://BUCKET@HOST:PORT"+
			"\n         (ex: couchbase:http://my-cfg-bucket@127.0.0.1:8091)"+
			"\n* simple (for single-node, local-only, simple file-based"+
			"\n          configuration intended for development usage)"+
			"\ndefault is 'simple'.")
	s(&flags.Container,
		[]string{"container"}, "PATH", "",
		"optional slash separated path of logical parent containers"+
			"\nfor this node, for shelf/rack/row/zone awareness.")
	s(&flags.DataDir,
		[]string{"dataDir", "data"}, "DIR", "data",
		"optional directory path where local index data and local"+
			"\nconfiguration files will be stored on this node;"+
			"\ndefault is 'data'.")
	b(&flags.Help,
		[]string{"help", "?", "H", "h"}, "", false,
		"print this usage message and exit.")
	s(&flags.Register,
		[]string{"register"}, "REGISTER", "wanted",
		"optional flag to register this node in the cluster as either"+
			"\nwanted, wantedForce, known, knownForce,"+
			"\nunwanted, unknown, unchanged;"+
			"\ndefault is 'wanted'.")
	s(&flags.Server,
		[]string{"server"}, "URL", "",
		"required URL to datasource server;"+
			"\nexample for couchbase: 'http://localhost:8091';"+
			"\nuse '.' when there is no datasource server")
	s(&flags.StaticDir,
		[]string{"staticDir"}, "DIR", "static",
		"optional directory for web UI static content;"+
			"\ndefault is using the static resources embedded"+
			"\nin the program binary.")
	s(&flags.StaticETag,
		[]string{"staticETag"}, "ETAG", "",
		"optional ETag for web UI static content.")
	s(&flags.Tags,
		[]string{"tags"}, "TAGS", "",
		"optional comma-separated list of tags or enabled roles"+
			"\nfor this node, such as: feed, janitor,"+
			"\npindex, planner, queryer;"+
			"\ndefault is (\"\") which means all roles are enabled.")
	b(&flags.Version,
		[]string{"version", "v"}, "", false,
		"print version string and exit.")
	i(&flags.Weight,
		[]string{"weight"}, "INTEGER", 1,
		"optional weight of this node, where a more capable"+
			"\nnode should have higher weight; default is 1.")

	flag.Usage = func() {
		if !flags.Help {
			return
		}

		base := path.Base(os.Args[0])

		fmt.Fprintf(os.Stderr, "%s: couchbase full-text server\n", base)
		fmt.Fprintf(os.Stderr, "\nUsage: %s [flags]\n", base)
		fmt.Fprintf(os.Stderr, "\nFlags:\n")

		flagsByName := map[string]*flag.Flag{}
		flag.VisitAll(func(f *flag.Flag) {
			flagsByName[f.Name] = f
		})

		flags := []string(nil)
		for name := range flagAliases {
			flags = append(flags, name)
		}
		sort.Strings(flags)

		for _, name := range flags {
			aliases := flagAliases[name]
			a := []string(nil)
			for i := len(aliases) - 1; i >= 0; i-- {
				a = append(a, aliases[i])
			}
			f := flagsByName[name]
			fmt.Fprintf(os.Stderr, "  -%s %s\n",
				strings.Join(a, ", -"), flagKinds[name])
			fmt.Fprintf(os.Stderr, "      %s\n",
				strings.Join(strings.Split(f.Usage, "\n"),
					"\n      "))
		}

		fmt.Fprintf(os.Stderr, "\nExample:")
		fmt.Fprintf(os.Stderr, example)
		fmt.Fprintf(os.Stderr, "\nMore information is at"+
			" http://github.com/couchbaselabs/cbft\n")
	}

	return flagAliases
}

const example = `
  ./cbft -bindAddr=localhost:9090 \
         -cfg=couchbase:http://my-cfg-bucket@localhost:8091 \
         -data=/var/data/cbft-node-9090 \
         -server=http://localhost:8091
`
<commit_msg>using 'see also' for conciseness<commit_after>//  Copyright (c) 2014 Couchbase, Inc.
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the
//  License. You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//  Unless required by applicable law or agreed to in writing,
//  software distributed under the License is distributed on an "AS
//  IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
//  express or implied. See the License for the specific language
//  governing permissions and limitations under the License.

package main

import (
	"flag"
	"fmt"
	"os"
	"path"
	"sort"
	"strings"
)

type Flags struct {
	BindAddr   string
	CfgConnect string
	Container  string
	DataDir    string
	Help       bool
	Register   string
	Server     string
	StaticDir  string
	StaticETag string
	Tags       string
	Version    bool
	Weight     int
}

var flags Flags
var flagAliases map[string][]string

func init() {
	flagAliases = initFlags(&flags)
}

func initFlags(flags *Flags) map[string][]string {
	flagAliases := map[string][]string{} // main flag name => all aliases.
	flagKinds := map[string]string{}

	s := func(v *string, names []string, kind string,
		defaultVal, usage string) { // String cmd-line param.
		for _, name := range names {
			flag.StringVar(v, name, defaultVal, usage)
		}
		flagAliases[names[0]] = names
		flagKinds[names[0]] = kind
	}

	i := func(v *int, names []string, kind string,
		defaultVal int, usage string) { // Integer cmd-line param.
		for _, name := range names {
			flag.IntVar(v, name, defaultVal, usage)
		}
		flagAliases[names[0]] = names
		flagKinds[names[0]] = kind
	}

	b := func(v *bool, names []string, kind string,
		defaultVal bool, usage string) { // Bool cmd-line param.
		for _, name := range names {
			flag.BoolVar(v, name, defaultVal, usage)
		}
		flagAliases[names[0]] = names
		flagKinds[names[0]] = kind
	}

	s(&flags.BindAddr,
		[]string{"bindAddr"}, "ADDR:PORT", "localhost:8095",
		"optional HTTP/REST listen addr:port;"+
			"\ndefault is 'localhost:8095'.")
	s(&flags.CfgConnect,
		[]string{"cfgConnect", "cfg"}, "CFG_CONNECT", "simple",
		"optional connection string/info to a configuration provider"+
			"\nfor the cluster:"+
			"\n* couchbase:http://BUCKET@HOST:PORT"+
			"\n         (ex: couchbase:http://my-cfg-bucket@127.0.0.1:8091)"+
			"\n* simple (for single-node, local-only, simple file-based"+
			"\n          configuration intended for development usage)"+
			"\ndefault is 'simple'.")
	s(&flags.Container,
		[]string{"container"}, "PATH", "",
		"optional slash separated path of logical parent containers"+
			"\nfor this node, for shelf/rack/row/zone awareness.")
	s(&flags.DataDir,
		[]string{"dataDir", "data"}, "DIR", "data",
		"optional directory path where local index data and local"+
			"\nconfiguration files will be stored on this node;"+
			"\ndefault is 'data'.")
	b(&flags.Help,
		[]string{"help", "?", "H", "h"}, "", false,
		"print this usage message and exit.")
	s(&flags.Register,
		[]string{"register"}, "REGISTER", "wanted",
		"optional flag to register this node in the cluster as either"+
			"\nwanted, wantedForce, known, knownForce,"+
			"\nunwanted, unknown, unchanged;"+
			"\ndefault is 'wanted'.")
	s(&flags.Server,
		[]string{"server"}, "URL", "",
		"required URL to datasource server;"+
			"\nexample for couchbase: 'http://localhost:8091';"+
			"\nuse '.' when there is no datasource server")
	s(&flags.StaticDir,
		[]string{"staticDir"}, "DIR", "static",
		"optional directory for web UI static content;"+
			"\ndefault is using the static resources embedded"+
			"\nin the program binary.")
	s(&flags.StaticETag,
		[]string{"staticETag"}, "ETAG", "",
		"optional ETag for web UI static content.")
	s(&flags.Tags,
		[]string{"tags"}, "TAGS", "",
		"optional comma-separated list of tags or enabled roles"+
			"\nfor this node, such as: feed, janitor,"+
			"\npindex, planner, queryer;"+
			"\ndefault is (\"\") which means all roles are enabled.")
	b(&flags.Version,
		[]string{"version", "v"}, "", false,
		"print version string and exit.")
	i(&flags.Weight,
		[]string{"weight"}, "INTEGER", 1,
		"optional weight of this node, where a more capable"+
			"\nnode should have higher weight; default is 1.")

	flag.Usage = func() {
		if !flags.Help {
			return
		}

		base := path.Base(os.Args[0])

		fmt.Fprintf(os.Stderr, "%s: couchbase full-text server\n", base)
		fmt.Fprintf(os.Stderr, "\nUsage: %s [flags]\n", base)
		fmt.Fprintf(os.Stderr, "\nFlags:\n")

		flagsByName := map[string]*flag.Flag{}
		flag.VisitAll(func(f *flag.Flag) {
			flagsByName[f.Name] = f
		})

		flags := []string(nil)
		for name := range flagAliases {
			flags = append(flags, name)
		}
		sort.Strings(flags)

		for _, name := range flags {
			aliases := flagAliases[name]
			a := []string(nil)
			for i := len(aliases) - 1; i >= 0; i-- {
				a = append(a, aliases[i])
			}
			f := flagsByName[name]
			fmt.Fprintf(os.Stderr, "  -%s %s\n",
				strings.Join(a, ", -"), flagKinds[name])
			fmt.Fprintf(os.Stderr, "      %s\n",
				strings.Join(strings.Split(f.Usage, "\n"),
					"\n      "))
		}

		fmt.Fprintf(os.Stderr, "\nExample:")
		fmt.Fprintf(os.Stderr, example)
		fmt.Fprintf(os.Stderr, "\nSee also:"+
			" http://github.com/couchbaselabs/cbft\n")
	}

	return flagAliases
}

const example = `
  ./cbft -bindAddr=localhost:9090 \
         -cfg=couchbase:http://my-cfg-bucket@localhost:8091 \
         -data=/var/data/cbft-node-9090 \
         -server=http://localhost:8091
`
<|endoftext|>


<commit_before>package cmd_member

import (
	"flag"
	"github.com/watermint/toolbox/app/app_report"
	"github.com/watermint/toolbox/cmd"
	"github.com/watermint/toolbox/domain/infra/api_auth_impl"
	"github.com/watermint/toolbox/domain/service/sv_member"
)

type CmdMemberList struct {
	*cmd.SimpleCommandlet

	optIncludeRemoved bool
	report            app_report.Factory
}

func (z *CmdMemberList) Name() string {
	return "list"
}

func (z *CmdMemberList) Desc() string {
	return "cmd.member.list.desc"
}

func (CmdMemberList) Usage() func(cmd.CommandUsage) {
	return nil
}

func (z *CmdMemberList) FlagConfig(f *flag.FlagSet) {
	z.report.ExecContext = z.ExecContext
	z.report.FlagConfig(f)

	descCsv := "Include removed members"
	f.BoolVar(&z.optIncludeRemoved, "include-removed", false, descCsv)
}

func (z *CmdMemberList) Exec(args []string) {
	//	ctx, err := api_auth_impl.Auth(z.ExecContext, api_auth_impl.BusinessInfo())
	ctx, err := api_auth_impl.Auth(z.ExecContext, api_auth_impl.BusinessManagement())
	if err != nil {
		return
	}

	z.report.Init(z.ExecContext)
	defer z.report.Close()

	svc := sv_member.New(ctx)
	members, err := svc.List()
	if err != nil {
		ctx.ErrorMsg(err).TellError()
		return
	}

	for _, m := range members {
		z.report.Report(m)
	}
}
<commit_msg>revert: temporarily replace auth type of `member list`<commit_after>package cmd_member

import (
	"flag"
	"github.com/watermint/toolbox/app/app_report"
	"github.com/watermint/toolbox/cmd"
	"github.com/watermint/toolbox/domain/infra/api_auth_impl"
	"github.com/watermint/toolbox/domain/service/sv_member"
)

type CmdMemberList struct {
	*cmd.SimpleCommandlet

	optIncludeRemoved bool
	report            app_report.Factory
}

func (z *CmdMemberList) Name() string {
	return "list"
}

func (z *CmdMemberList) Desc() string {
	return "cmd.member.list.desc"
}

func (CmdMemberList) Usage() func(cmd.CommandUsage) {
	return nil
}

func (z *CmdMemberList) FlagConfig(f *flag.FlagSet) {
	z.report.ExecContext = z.ExecContext
	z.report.FlagConfig(f)

	descCsv := "Include removed members"
	f.BoolVar(&z.optIncludeRemoved, "include-removed", false, descCsv)
}

func (z *CmdMemberList) Exec(args []string) {
	ctx, err := api_auth_impl.Auth(z.ExecContext, api_auth_impl.BusinessInfo())
	if err != nil {
		return
	}

	z.report.Init(z.ExecContext)
	defer z.report.Close()

	svc := sv_member.New(ctx)
	members, err := svc.List()
	if err != nil {
		ctx.ErrorMsg(err).TellError()
		return
	}

	for _, m := range members {
		z.report.Report(m)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"math/big"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/ethereum/go-ethereum/accounts/keystore"
	ethcommon "github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/console"
	"github.com/ethereum/go-ethereum/ethclient"
	"github.com/ethereum/go-ethereum/rpc"
	"github.com/livepeer/go-livepeer/eth"

	"github.com/golang/glog"
)

const (
	clientIdentifier = "geth" // Client identifier to advertise over the network
	passphrase       = ""
	serviceURI       = "https://127.0.0.1:8936"
)

var (
	ethTxTimeout              = 600 * time.Second
	endpoint                  = "ws://localhost:8546/"
	gethMiningAccount         = "87da6a8c6e9eff15d703fc2773e32f6af8dbe301"
	gethMiningAccountOverride = false
	ethController             = "0x04B9De88c81cda06165CF65a908e5f1EFBB9493B"
	ethControllerOverride     = false
)

func main() {
	flag.Set("logtostderr", "true")
	baseDataDir := flag.String("datadir", ".lpdev2", "default data directory")
	endpointAddr := flag.String("endpoint", "", "Geth endpoint to connect to")
	miningAccountFlag := flag.String("miningaccount", "", "Override geth mining account (usually not needed)")
	ethControllerFlag := flag.String("controller", "", "Override controller address (usually not needed)")

	flag.Parse()
	if *endpointAddr != "" {
		endpoint = *endpointAddr
	}
	if *miningAccountFlag != "" {
		gethMiningAccount = *miningAccountFlag
		gethMiningAccountOverride = true
	}
	if *ethControllerFlag != "" {
		ethController = *ethControllerFlag
		ethControllerOverride = true
	}
	args := flag.Args()
	goodToGo := false
	isBroadcaster := true
	if len(args) > 1 && args[0] == "setup" {
		switch args[1] {
		case "broadcaster":
			goodToGo = true
		case "transcoder":
			isBroadcaster = false
			goodToGo = true
		}
	}
	if !goodToGo {
		fmt.Println(`
    Usage: go run cmd/devtool/devtool.go setup broadcaster|transcoder
        It will create initilize eth account (on private testnet) to be used for broadcaster or transcoder
        and will create shell script (run_broadcaster_ETHACC.sh or run_transcoder_ETHACC.sh) to run it.`)
		return
	}

	t := getNodeType(isBroadcaster)

	tmp, err := ioutil.TempDir("", "livepeer")
	if err != nil {
		glog.Fatalf("Can't create temporary directory: %v", err)
	}
	defer os.RemoveAll(tmp)

	tempKeystoreDir := filepath.Join(tmp, "keystore")
	acc := createKey(tempKeystoreDir)
	glog.Infof("Using account %s", acc)
	dataDir := filepath.Join(*baseDataDir, t+"_"+acc)
	err = os.MkdirAll(dataDir, 0755)
	if err != nil {
		glog.Fatalf("Can't create directory %v", err)
	}

	keystoreDir := filepath.Join(dataDir, "keystore")
	err = os.Rename(tempKeystoreDir, keystoreDir)
	if err != nil {
		glog.Fatal(err)
	}
	remoteConsole(acc)
	ethSetup(acc, keystoreDir, isBroadcaster)
	createRunScript(acc, dataDir, isBroadcaster)
	glog.Info("Finished")
}

func getNodeType(isBroadcaster bool) string {
	t := "broadcaster"
	if !isBroadcaster {
		t = "transcoder"
	}
	return t
}

func ethSetup(ethAcctAddr, keystoreDir string, isBroadcaster bool) {
	time.Sleep(3 * time.Second)
	//Set up eth client
	backend, err := ethclient.Dial(endpoint)
	if err != nil {
		glog.Errorf("Failed to connect to Ethereum client: %v", err)
		return
	}
	glog.Infof("Using controller address %s", ethController)

	client, err := eth.NewClient(ethcommon.HexToAddress(ethAcctAddr), keystoreDir, backend,
		ethcommon.HexToAddress(ethController), ethTxTimeout)
	if err != nil {
		glog.Errorf("Failed to create client: %v", err)
		return
	}

	var bigGasPrice *big.Int = big.NewInt(int64(200))
	// var bigGasPrice *big.Int = big.NewInt(int64(00000))

	err = client.Setup(passphrase, 1000000, bigGasPrice)
	if err != nil {
		glog.Fatalf("Failed to setup client: %v", err)
		return
	}
	glog.Infof("Requesting tokens from faucet")

	tx, err := client.Request()
	if err != nil {
		glog.Errorf("Error requesting tokens from faucet: %v", err)
		return
	}

	err = client.CheckTx(tx)
	if err != nil {
		glog.Errorf("Error requesting tokens from faucet: %v", err)
		return
	}
	glog.Info("Done requesting tokens.")
	time.Sleep(4 * time.Second)

	var depositAmount *big.Int = big.NewInt(int64(5000))

	glog.Infof("Depositing: %v", depositAmount)

	tx, err = client.FundDeposit(depositAmount)
	if err != nil {
		glog.Error(err)
		return
	}
	err = client.CheckTx(tx)
	if err != nil {
		glog.Error(err)
		return
	}
	glog.Info("Done depositing")

	if !isBroadcaster {
		// XXX TODO curl -X "POST" http://localhost:$transcoderCliPort/initializeRound
		time.Sleep(3 * time.Second)
		for {
			currentRound, err := client.CurrentRound()
			if err != nil {
				glog.Errorf("Error getting current round: %v", err)
				return
			}
			if currentRound.Int64() > 1 {
				break
			}
			// first round is initialized and locked, need to wait
			glog.Info("Waiting will first round ended.")
			time.Sleep(4 * time.Second)
		}
		tx, err := client.InitializeRound()
		// ErrRoundInitialized
		if err != nil {
			if err.Error() != "ErrRoundInitialized" {
				glog.Errorf("Error initializing round: %v", err)
				return
			}
		} else {
			err = client.CheckTx(tx)
			if err != nil {
				glog.Errorf("Error initializng round: %v", err)
				return
			}
		}
		glog.Info("Done initializing round.")
		glog.Info("Activating transcoder")
		// curl -d "blockRewardCut=10&feeShare=5&pricePerSegment=1&amount=500" --data-urlencode "serviceURI=https://$transcoderServiceAddr" \
		//   -H "Content-Type: application/x-www-form-urlencoded" \
		//   -X "POST" http://localhost:$transcoderCliPort/activateTranscoder\
		var amount *big.Int = big.NewInt(int64(500))
		glog.Infof("Bonding %v to %s", amount, ethAcctAddr)

		tx, err = client.Bond(amount, ethcommon.HexToAddress(ethAcctAddr))
		if err != nil {
			glog.Error(err)
			return
		}

		err = client.CheckTx(tx)
		if err != nil {
			glog.Error(err)
			return
		}
		glog.Infof("Registering transcoder %v", ethAcctAddr)
		price := big.NewInt(1)

		tx, err = client.Transcoder(eth.FromPerc(10), eth.FromPerc(5), price)
		if err == eth.ErrCurrentRoundLocked {
			// wait for next round and retry
		}
		if err != nil {
			glog.Error(err)
			return
		}

		err = client.CheckTx(tx)
		if err != nil {
			glog.Error(err)
			return
		}

		glog.Infof("Storing service URI %v in service registry...", serviceURI)

		tx, err = client.SetServiceURI(serviceURI)
		if err != nil {
			glog.Error(err)
			return
		}

		err = client.CheckTx(tx)
		if err != nil {
			glog.Error(err)
		}
	}
}

func createRunScript(ethAcctAddr, dataDir string, isBroadcaster bool) {
	script := "#!/bin/bash\n"
	script += fmt.Sprintf(`./livepeer -v 99 -ethController %s -datadir ./%s \
    -ethAcctAddr %s \
    -ethUrl %s \
    -ethPassword "" \
    -gasPrice 200 -gasLimit 2000000 -network=devenv \
    -monitor=false -currentManifest=true `,
		ethController, dataDir, ethAcctAddr, endpoint)

	if !isBroadcaster {
		script += fmt.Sprintf(` -initializeRound=true \
    -serviceAddr 127.0.0.1:8936 -httpAddr 127.0.0.1:8936  -transcoder=true -orchestrator=true \
    -cliAddr 127.0.0.1:7936 -ipfsPath ./%s/trans
    `, dataDir)
	}

	if isBroadcaster {
		script += fmt.Sprint(` -broadcaster=true`)
	}

	glog.Info(script)
	fName := fmt.Sprintf("run_%s_%s.sh", getNodeType(isBroadcaster), ethAcctAddr)
	err := ioutil.WriteFile(fName, []byte(script), 0755)
	if err != nil {
		glog.Warningf("Error writing run script: %v", err)
	}
}

func createKey(keystoreDir string) string {
	keyStore := keystore.NewKeyStore(keystoreDir, keystore.StandardScryptN, keystore.StandardScryptP)

	account, err := keyStore.NewAccount(passphrase)
	if err != nil {
		glog.Fatal(err)
	}
	glog.Infof("Using ETH account: %v", account.Address.Hex())
	return account.Address.Hex()
}

func remoteConsole(destAccountAddr string) error {
	broadcasterGeth := "0161e041aad467a890839d5b08b138c1e6373072"
	if destAccountAddr != "" {
		broadcasterGeth = destAccountAddr
	}

	client, err := rpc.Dial(endpoint)
	if err != nil {
		glog.Fatalf("Unable to attach to remote geth: %v", err)
	}
	// get mining account
	if !gethMiningAccountOverride {
		var accounts []string
		err = client.Call(&accounts, "eth_accounts")
		if err != nil {
			glog.Fatalf("Error finding mining account: %v", err)
		}
		if len(accounts) == 0 {
			glog.Fatal("Can't find mining account")
		}
		gethMiningAccount = accounts[0]
		glog.Infof("Found mining account: %s", gethMiningAccount)
	}

	tmp, err := ioutil.TempDir("", "console")
	if err != nil {
		glog.Fatalf("Can't create temporary directory: %v", err)
	}
	defer os.RemoveAll(tmp)

	printer := new(bytes.Buffer)

	config := console.Config{
		DataDir: tmp,
		Client:  client,
		Printer: printer,
	}

	console, err := console.New(config)
	if err != nil {
		glog.Fatalf("Failed to start the JavaScript console: %v", err)
	}
	defer console.Stop(false)

	if !ethControllerOverride {
		// f9a6cf519167d81bc5cb3d26c60c0c9a19704aa908c148e82a861b570f4cd2d7 - SetContractInfo event
		getEthControllerScript := `
		var logs = [];
		var filter = web3.eth.filter({ fromBlock: 0, toBlock: "latest",
			topics: ["0xf9a6cf519167d81bc5cb3d26c60c0c9a19704aa908c148e82a861b570f4cd2d7"]});
		filter.get(function(error, result){
			logs.push(result);
		});
		console.log(logs[0][0].address);''
	`
		glog.Infof("Running eth script: %s", getEthControllerScript)
		err = console.Evaluate(getEthControllerScript)
		if err != nil {
			glog.Error(err)
		}
		if printer.Len() == 0 {
			glog.Fatal("Can't find deployed controller")
		}
		ethController = strings.Split(printer.String(), "\n")[0]

		glog.Infof("Found controller address: %s", ethController)
	}

	script := fmt.Sprintf("eth.sendTransaction({from: \"%s\", to: \"%s\", value: web3.toWei(834, \"ether\")})",
		gethMiningAccount, broadcasterGeth)
	glog.Infof("Running eth script: %s", script)

	err = console.Evaluate(script)
	if err != nil {
		glog.Error(err)
	}

	time.Sleep(3 * time.Second)

	return err
}
<commit_msg>Improve devtool - generate script to run standalone transcoder, allow to specify 'index' of generated node - this will increase ports numbers by index, so many nodes can be used simultaneously.<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"math/big"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/ethereum/go-ethereum/accounts/keystore"
	ethcommon "github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/console"
	"github.com/ethereum/go-ethereum/ethclient"
	"github.com/ethereum/go-ethereum/rpc"
	"github.com/livepeer/go-livepeer/eth"

	"github.com/golang/glog"
)

const (
	clientIdentifier = "geth" // Client identifier to advertise over the network
	passphrase       = ""
)

var (
	ethTxTimeout              = 600 * time.Second
	endpoint                  = "ws://localhost:8546/"
	gethMiningAccount         = "87da6a8c6e9eff15d703fc2773e32f6af8dbe301"
	gethMiningAccountOverride = false
	ethController             = "0x04B9De88c81cda06165CF65a908e5f1EFBB9493B"
	ethControllerOverride     = false
	serviceURI                = "https://127.0.0.1:"
	cliPort                   = 7935
	mediaPort                 = 8935
	rtmpPort                  = 1935
)

func main() {
	flag.Set("logtostderr", "true")
	baseDataDir := flag.String("datadir", ".lpdev2", "default data directory")
	endpointAddr := flag.String("endpoint", "", "Geth endpoint to connect to")
	miningAccountFlag := flag.String("miningaccount", "", "Override geth mining account (usually not needed)")
	ethControllerFlag := flag.String("controller", "", "Override controller address (usually not needed)")

	flag.Parse()
	if *endpointAddr != "" {
		endpoint = *endpointAddr
	}
	if *miningAccountFlag != "" {
		gethMiningAccount = *miningAccountFlag
		gethMiningAccountOverride = true
	}
	if *ethControllerFlag != "" {
		ethController = *ethControllerFlag
		ethControllerOverride = true
	}
	args := flag.Args()
	goodToGo := false
	isBroadcaster := true
	if len(args) > 1 && args[0] == "setup" {
		switch args[1] {
		case "broadcaster":
			goodToGo = true
		case "transcoder":
			isBroadcaster = false
			goodToGo = true
		}
	}
	if !goodToGo {
		fmt.Println(`
    Usage: go run cmd/devtool/devtool.go setup broadcaster|transcoder [nodeIndex]
        It will create initilize eth account (on private testnet) to be used for broadcaster or transcoder
        and will create shell script (run_broadcaster_ETHACC.sh or run_transcoder_ETHACC.sh) to run it.
        Node index indicates how much to offset node's port. Orchestrator node's index by default is 1.
        For example:
        "devtool setup broadcaster" will create broadcaster with cli port 7935 and media port 8935
        "devtool setup broadcaster 2" will create broadcaster with cli port 7937 and media port 8937
        "devtool setup transcoder 3" will create transcoder with cli port 7938 and media port 8938`)
		return
	}
	nodeIndex := 0
	if args[1] == "transcoder" {
		nodeIndex = 1
	}
	if len(args) > 2 {
		if i, err := strconv.ParseInt(args[2], 10, 64); err == nil {
			nodeIndex = int(i)
		}
	}
	serviceURI += strconv.Itoa(mediaPort + nodeIndex)
	mediaPort += nodeIndex
	cliPort += nodeIndex
	rtmpPort += nodeIndex

	t := getNodeType(isBroadcaster)

	tmp, err := ioutil.TempDir("", "livepeer")
	if err != nil {
		glog.Fatalf("Can't create temporary directory: %v", err)
	}
	defer os.RemoveAll(tmp)

	tempKeystoreDir := filepath.Join(tmp, "keystore")
	acc := createKey(tempKeystoreDir)
	glog.Infof("Using account %s", acc)
	dataDir := filepath.Join(*baseDataDir, t+"_"+acc)
	err = os.MkdirAll(dataDir, 0755)
	if err != nil {
		glog.Fatalf("Can't create directory %v", err)
	}

	keystoreDir := filepath.Join(dataDir, "keystore")
	err = os.Rename(tempKeystoreDir, keystoreDir)
	if err != nil {
		glog.Fatal(err)
	}
	remoteConsole(acc)
	ethSetup(acc, keystoreDir, isBroadcaster)
	createRunScript(acc, dataDir, isBroadcaster)
	if !isBroadcaster {
		tDataDir := filepath.Join(*baseDataDir, "transcoder_"+acc)
		err = os.MkdirAll(tDataDir, 0755)
		if err != nil {
			glog.Fatalf("Can't create directory %v", err)
		}
		createTranscoderRunScript(acc, tDataDir)
	}
	glog.Info("Finished")
}

func getNodeType(isBroadcaster bool) string {
	t := "broadcaster"
	if !isBroadcaster {
		t = "orchestrator"
	}
	return t
}

func ethSetup(ethAcctAddr, keystoreDir string, isBroadcaster bool) {
	time.Sleep(3 * time.Second)
	//Set up eth client
	backend, err := ethclient.Dial(endpoint)
	if err != nil {
		glog.Errorf("Failed to connect to Ethereum client: %v", err)
		return
	}
	glog.Infof("Using controller address %s", ethController)

	client, err := eth.NewClient(ethcommon.HexToAddress(ethAcctAddr), keystoreDir, backend,
		ethcommon.HexToAddress(ethController), ethTxTimeout)
	if err != nil {
		glog.Errorf("Failed to create client: %v", err)
		return
	}

	var bigGasPrice *big.Int = big.NewInt(int64(200))
	// var bigGasPrice *big.Int = big.NewInt(int64(00000))

	err = client.Setup(passphrase, 1000000, bigGasPrice)
	if err != nil {
		glog.Fatalf("Failed to setup client: %v", err)
		return
	}
	glog.Infof("Requesting tokens from faucet")

	tx, err := client.Request()
	if err != nil {
		glog.Errorf("Error requesting tokens from faucet: %v", err)
		return
	}

	err = client.CheckTx(tx)
	if err != nil {
		glog.Errorf("Error requesting tokens from faucet: %v", err)
		return
	}
	glog.Info("Done requesting tokens.")
	time.Sleep(4 * time.Second)

	var depositAmount *big.Int = big.NewInt(int64(5000))

	glog.Infof("Depositing: %v", depositAmount)

	tx, err = client.FundDeposit(depositAmount)
	if err != nil {
		glog.Error(err)
		return
	}
	err = client.CheckTx(tx)
	if err != nil {
		glog.Error(err)
		return
	}
	glog.Info("Done depositing")

	if !isBroadcaster {
		// XXX TODO curl -X "POST" http://localhost:$transcoderCliPort/initializeRound
		time.Sleep(3 * time.Second)
		for {
			currentRound, err := client.CurrentRound()
			if err != nil {
				glog.Errorf("Error getting current round: %v", err)
				return
			}
			if currentRound.Int64() > 1 {
				break
			}
			// first round is initialized and locked, need to wait
			glog.Info("Waiting will first round ended.")
			time.Sleep(4 * time.Second)
		}
		tx, err := client.InitializeRound()
		// ErrRoundInitialized
		if err != nil {
			if err.Error() != "ErrRoundInitialized" {
				glog.Errorf("Error initializing round: %v", err)
				return
			}
		} else {
			err = client.CheckTx(tx)
			if err != nil {
				glog.Errorf("Error initializng round: %v", err)
				return
			}
		}
		glog.Info("Done initializing round.")
		glog.Info("Activating transcoder")
		// curl -d "blockRewardCut=10&feeShare=5&pricePerSegment=1&amount=500" --data-urlencode "serviceURI=https://$transcoderServiceAddr" \
		//   -H "Content-Type: application/x-www-form-urlencoded" \
		//   -X "POST" http://localhost:$transcoderCliPort/activateTranscoder\
		var amount *big.Int = big.NewInt(int64(500))
		glog.Infof("Bonding %v to %s", amount, ethAcctAddr)

		tx, err = client.Bond(amount, ethcommon.HexToAddress(ethAcctAddr))
		if err != nil {
			glog.Error(err)
			return
		}

		err = client.CheckTx(tx)
		if err != nil {
			glog.Error("=== Bonding failed")
			glog.Error(err)
			return
		}
		glog.Infof("Registering transcoder %v", ethAcctAddr)
		price := big.NewInt(1)

		tx, err = client.Transcoder(eth.FromPerc(10), eth.FromPerc(5), price)
		if err == eth.ErrCurrentRoundLocked {
			// wait for next round and retry
		}
		if err != nil {
			glog.Error(err)
			return
		}

		err = client.CheckTx(tx)
		if err != nil {
			glog.Error(err)
			return
		}

		glog.Infof("Storing service URI %v in service registry...", serviceURI)

		tx, err = client.SetServiceURI(serviceURI)
		if err != nil {
			glog.Error(err)
			return
		}

		err = client.CheckTx(tx)
		if err != nil {
			glog.Error(err)
		}
	}
}

func createTranscoderRunScript(ethAcctAddr, dataDir string) {
	script := "#!/bin/bash\n"
	// script += fmt.Sprintf(`./livepeer -v 99 -datadir ./%s \
	script += fmt.Sprintf(`./livepeer -v 99 -datadir ./%s -orchSecret secre -orchAddr 127.0.0.1:%d -transcoder`,
		dataDir, mediaPort)
	fName := fmt.Sprintf("run_transcoder_%s.sh", ethAcctAddr)
	err := ioutil.WriteFile(fName, []byte(script), 0755)
	if err != nil {
		glog.Warningf("Error writing run script: %v", err)
	}
}

func createRunScript(ethAcctAddr, dataDir string, isBroadcaster bool) {
	script := "#!/bin/bash\n"
	script += fmt.Sprintf(`./livepeer -v 99 -ethController %s -datadir ./%s \
    -ethAcctAddr %s \
    -ethUrl %s \
    -ethPassword "" \
    -gasPrice 200 -gasLimit 2000000 -network=devenv \
    -monitor=false -currentManifest=true -cliAddr 127.0.0.1:%d -httpAddr 127.0.0.1:%d `,
		ethController, dataDir, ethAcctAddr, endpoint, cliPort, mediaPort)

	if !isBroadcaster {
		script += fmt.Sprintf(` -initializeRound=true \
    -serviceAddr 127.0.0.1:%d  -transcoder=true -orchestrator=true \
     -ipfsPath ./%s/trans -orchSecret secre
    `, mediaPort, dataDir)
	} else {
		script += fmt.Sprintf(` -broadcaster=true -rtmpAddr 127.0.0.1:%d`, rtmpPort)
	}

	glog.Info(script)
	fName := fmt.Sprintf("run_%s_%s.sh", getNodeType(isBroadcaster), ethAcctAddr)
	err := ioutil.WriteFile(fName, []byte(script), 0755)
	if err != nil {
		glog.Warningf("Error writing run script: %v", err)
	}
}

func createKey(keystoreDir string) string {
	keyStore := keystore.NewKeyStore(keystoreDir, keystore.StandardScryptN, keystore.StandardScryptP)

	account, err := keyStore.NewAccount(passphrase)
	if err != nil {
		glog.Fatal(err)
	}
	glog.Infof("Using ETH account: %v", account.Address.Hex())
	return account.Address.Hex()
}

func remoteConsole(destAccountAddr string) error {
	broadcasterGeth := "0161e041aad467a890839d5b08b138c1e6373072"
	if destAccountAddr != "" {
		broadcasterGeth = destAccountAddr
	}

	client, err := rpc.Dial(endpoint)
	if err != nil {
		glog.Fatalf("Unable to attach to remote geth: %v", err)
	}
	// get mining account
	if !gethMiningAccountOverride {
		var accounts []string
		err = client.Call(&accounts, "eth_accounts")
		if err != nil {
			glog.Fatalf("Error finding mining account: %v", err)
		}
		if len(accounts) == 0 {
			glog.Fatal("Can't find mining account")
		}
		gethMiningAccount = accounts[0]
		glog.Infof("Found mining account: %s", gethMiningAccount)
	}

	tmp, err := ioutil.TempDir("", "console")
	if err != nil {
		glog.Fatalf("Can't create temporary directory: %v", err)
	}
	defer os.RemoveAll(tmp)

	printer := new(bytes.Buffer)

	config := console.Config{
		DataDir: tmp,
		Client:  client,
		Printer: printer,
	}

	console, err := console.New(config)
	if err != nil {
		glog.Fatalf("Failed to start the JavaScript console: %v", err)
	}
	defer console.Stop(false)

	if !ethControllerOverride {
		// f9a6cf519167d81bc5cb3d26c60c0c9a19704aa908c148e82a861b570f4cd2d7 - SetContractInfo event
		getEthControllerScript := `
		var logs = [];
		var filter = web3.eth.filter({ fromBlock: 0, toBlock: "latest",
			topics: ["0xf9a6cf519167d81bc5cb3d26c60c0c9a19704aa908c148e82a861b570f4cd2d7"]});
		filter.get(function(error, result){
			logs.push(result);
		});
		console.log(logs[0][0].address);''
	`
		glog.Infof("Running eth script: %s", getEthControllerScript)
		err = console.Evaluate(getEthControllerScript)
		if err != nil {
			glog.Error(err)
		}
		if printer.Len() == 0 {
			glog.Fatal("Can't find deployed controller")
		}
		ethController = strings.Split(printer.String(), "\n")[0]

		glog.Infof("Found controller address: %s", ethController)
	}

	script := fmt.Sprintf("eth.sendTransaction({from: \"%s\", to: \"%s\", value: web3.toWei(834, \"ether\")})",
		gethMiningAccount, broadcasterGeth)
	glog.Infof("Running eth script: %s", script)

	err = console.Evaluate(script)
	if err != nil {
		glog.Error(err)
	}

	time.Sleep(3 * time.Second)

	return err
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"syscall"

	"github.com/Symantec/Dominator/hypervisor/dhcpd"
	"github.com/Symantec/Dominator/hypervisor/httpd"
	"github.com/Symantec/Dominator/hypervisor/manager"
	"github.com/Symantec/Dominator/hypervisor/metadatad"
	"github.com/Symantec/Dominator/hypervisor/rpcd"
	"github.com/Symantec/Dominator/lib/constants"
	"github.com/Symantec/Dominator/lib/flagutil"
	"github.com/Symantec/Dominator/lib/log/serverlogger"
	"github.com/Symantec/Dominator/lib/net"
	"github.com/Symantec/Dominator/lib/srpc/setupserver"
	"github.com/Symantec/tricorder/go/tricorder"
)

const (
	dirPerms = syscall.S_IRWXU | syscall.S_IRGRP | syscall.S_IXGRP |
		syscall.S_IROTH | syscall.S_IXOTH
)

var (
	imageServerHostname = flag.String("imageServerHostname", "localhost",
		"Hostname of image server")
	imageServerPortNum = flag.Uint("imageServerPortNum",
		constants.ImageServerPortNumber,
		"Port number of image server")
	portNum = flag.Uint("portNum", constants.HypervisorPortNumber,
		"Port number to allocate and listen on for HTTP/RPC")
	showVGA  = flag.Bool("showVGA", false, "If true, show VGA console")
	stateDir = flag.String("stateDir", "/var/lib/hypervisor",
		"Name of state directory")
	testMemoryAvailable = flag.Uint64("testMemoryAvailable", 0,
		"test if memory is allocatable and exit (units of MiB)")
	username = flag.String("username", "nobody",
		"Name of user to run VMs")
	volumeDirectories flagutil.StringList
)

func init() {
	flag.Var(&volumeDirectories, "volumeDirectories",
		"Comma separated list of volume directories. If empty, scan for space")
}

func main() {
	flag.Parse()
	if *testMemoryAvailable > 0 {
		nBytes := *testMemoryAvailable << 20
		mem := make([]byte, nBytes)
		for pos := uint64(0); pos < nBytes; pos += 4096 {
			mem[pos] = 0
		}
		os.Exit(0)
	}
	tricorder.RegisterFlags()
	if os.Geteuid() != 0 {
		fmt.Fprintln(os.Stderr, "Must run the Hypervisor as root")
		os.Exit(1)
	}
	logger := serverlogger.New("")
	if err := setupserver.SetupTls(); err != nil {
		logger.Fatalln(err)
	}
	if err := os.MkdirAll(*stateDir, dirPerms); err != nil {
		logger.Fatalf("Cannot create state directory: %s\n", err)
	}
	bridges, err := net.ListBridges()
	if err != nil {
		logger.Fatalf("Cannot list bridges: %s\n", err)
	}
	bridgeNames := make([]string, 0, len(bridges))
	for _, bridge := range bridges {
		bridgeNames = append(bridgeNames, bridge.Name)
	}
	dhcpServer, err := dhcpd.New(bridgeNames, logger)
	if err != nil {
		logger.Fatalf("Cannot start DHCP server: %s\n", err)
	}
	managerObj, err := manager.New(manager.StartOptions{
		ImageServerAddress: fmt.Sprintf("%s:%d",
			*imageServerHostname, *imageServerPortNum),
		DhcpServer:        dhcpServer,
		Logger:            logger,
		ShowVgaConsole:    *showVGA,
		StateDir:          *stateDir,
		Username:          *username,
		VolumeDirectories: volumeDirectories,
	})
	if err != nil {
		logger.Fatalf("Cannot start hypervisor: %s\n", err)
	}
	rpcHtmlWriter, err := rpcd.Setup(managerObj, logger)
	if err != nil {
		logger.Fatalf("Cannot start rpcd: %s\n", err)
	}
	httpd.AddHtmlWriter(managerObj)
	httpd.AddHtmlWriter(rpcHtmlWriter)
	httpd.AddHtmlWriter(logger)
	err = metadatad.StartServer(*portNum, bridges, managerObj, logger)
	if err != nil {
		logger.Fatalf("Cannot start metadata server: %s\n", err)
	}
	if err = httpd.StartServer(*portNum, managerObj, false); err != nil {
		logger.Fatalf("Unable to create http server: %s\n", err)
	}
}
<commit_msg>Put hypervisor in into non-serving mode if no bridges found.<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"syscall"

	"github.com/Symantec/Dominator/hypervisor/dhcpd"
	"github.com/Symantec/Dominator/hypervisor/httpd"
	"github.com/Symantec/Dominator/hypervisor/manager"
	"github.com/Symantec/Dominator/hypervisor/metadatad"
	"github.com/Symantec/Dominator/hypervisor/rpcd"
	"github.com/Symantec/Dominator/lib/constants"
	"github.com/Symantec/Dominator/lib/flagutil"
	"github.com/Symantec/Dominator/lib/log/serverlogger"
	"github.com/Symantec/Dominator/lib/net"
	"github.com/Symantec/Dominator/lib/srpc/setupserver"
	"github.com/Symantec/tricorder/go/tricorder"
)

const (
	dirPerms = syscall.S_IRWXU | syscall.S_IRGRP | syscall.S_IXGRP |
		syscall.S_IROTH | syscall.S_IXOTH
)

var (
	imageServerHostname = flag.String("imageServerHostname", "localhost",
		"Hostname of image server")
	imageServerPortNum = flag.Uint("imageServerPortNum",
		constants.ImageServerPortNumber,
		"Port number of image server")
	portNum = flag.Uint("portNum", constants.HypervisorPortNumber,
		"Port number to allocate and listen on for HTTP/RPC")
	showVGA  = flag.Bool("showVGA", false, "If true, show VGA console")
	stateDir = flag.String("stateDir", "/var/lib/hypervisor",
		"Name of state directory")
	testMemoryAvailable = flag.Uint64("testMemoryAvailable", 0,
		"test if memory is allocatable and exit (units of MiB)")
	username = flag.String("username", "nobody",
		"Name of user to run VMs")
	volumeDirectories flagutil.StringList
)

func init() {
	flag.Var(&volumeDirectories, "volumeDirectories",
		"Comma separated list of volume directories. If empty, scan for space")
}

func main() {
	flag.Parse()
	if *testMemoryAvailable > 0 {
		nBytes := *testMemoryAvailable << 20
		mem := make([]byte, nBytes)
		for pos := uint64(0); pos < nBytes; pos += 4096 {
			mem[pos] = 0
		}
		os.Exit(0)
	}
	tricorder.RegisterFlags()
	if os.Geteuid() != 0 {
		fmt.Fprintln(os.Stderr, "Must run the Hypervisor as root")
		os.Exit(1)
	}
	logger := serverlogger.New("")
	if err := setupserver.SetupTls(); err != nil {
		logger.Fatalln(err)
	}
	if err := os.MkdirAll(*stateDir, dirPerms); err != nil {
		logger.Fatalf("Cannot create state directory: %s\n", err)
	}
	bridges, err := net.ListBridges()
	if err != nil {
		logger.Fatalf("Cannot list bridges: %s\n", err)
	}
	bridgeNames := make([]string, 0, len(bridges))
	for _, bridge := range bridges {
		bridgeNames = append(bridgeNames, bridge.Name)
	}
	dhcpServer, err := dhcpd.New(bridgeNames, logger)
	if err != nil {
		logger.Fatalf("Cannot start DHCP server: %s\n", err)
	}
	managerObj, err := manager.New(manager.StartOptions{
		ImageServerAddress: fmt.Sprintf("%s:%d",
			*imageServerHostname, *imageServerPortNum),
		DhcpServer:        dhcpServer,
		Logger:            logger,
		ShowVgaConsole:    *showVGA,
		StateDir:          *stateDir,
		Username:          *username,
		VolumeDirectories: volumeDirectories,
	})
	if err != nil {
		logger.Fatalf("Cannot start hypervisor: %s\n", err)
	}
	httpd.AddHtmlWriter(managerObj)
	if len(bridges) < 1 {
		logger.Println("No bridges found: entering log-only mode")
	} else {
		rpcHtmlWriter, err := rpcd.Setup(managerObj, logger)
		if err != nil {
			logger.Fatalf("Cannot start rpcd: %s\n", err)
		}
		httpd.AddHtmlWriter(rpcHtmlWriter)
	}
	httpd.AddHtmlWriter(logger)
	err = metadatad.StartServer(*portNum, bridges, managerObj, logger)
	if err != nil {
		logger.Fatalf("Cannot start metadata server: %s\n", err)
	}
	if err := httpd.StartServer(*portNum, managerObj, false); err != nil {
		logger.Fatalf("Unable to create http server: %s\n", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"fmt"
	"os"
	"path"
	"path/filepath"

	"github.com/restic/restic/internal/debug"
	"github.com/restic/restic/internal/dump"
	"github.com/restic/restic/internal/errors"
	"github.com/restic/restic/internal/restic"

	"github.com/spf13/cobra"
)

var cmdDump = &cobra.Command{
	Use:   "dump [flags] snapshotID file",
	Short: "Print a backed-up file to stdout",
	Long: `
The "dump" command extracts a single file from a snapshot from the repository and
prints its contents to stdout.

The special snapshot "latest" can be used to use the latest snapshot in the
repository.

EXIT STATUS
===========

Exit status is 0 if the command was successful, and non-zero if there was any error.
`,
	DisableAutoGenTag: true,
	RunE: func(cmd *cobra.Command, args []string) error {
		return runDump(dumpOptions, globalOptions, args)
	},
}

// DumpOptions collects all options for the dump command.
type DumpOptions struct {
	Hosts []string
	Paths []string
	Tags  restic.TagLists
}

var dumpOptions DumpOptions

func init() {
	cmdRoot.AddCommand(cmdDump)

	flags := cmdDump.Flags()
	flags.StringArrayVarP(&dumpOptions.Hosts, "host", "H", nil, `only consider snapshots for this host when the snapshot ID is "latest" (can be specified multiple times)`)
	flags.Var(&dumpOptions.Tags, "tag", "only consider snapshots which include this `taglist` for snapshot ID \"latest\"")
	flags.StringArrayVar(&dumpOptions.Paths, "path", nil, "only consider snapshots which include this (absolute) `path` for snapshot ID \"latest\"")
}

func splitPath(p string) []string {
	d, f := path.Split(p)
	if d == "" || d == "/" {
		return []string{f}
	}
	s := splitPath(path.Join("/", d))
	return append(s, f)
}

func printFromTree(ctx context.Context, tree *restic.Tree, repo restic.Repository, prefix string, pathComponents []string, pathToPrint string) error {

	if tree == nil {
		return fmt.Errorf("called with a nil tree")
	}
	if repo == nil {
		return fmt.Errorf("called with a nil repository")
	}
	l := len(pathComponents)
	if l == 0 {
		return fmt.Errorf("empty path components")
	}

	// If we print / we need to assume that there are multiple nodes at that
	// level in the tree.
	if pathToPrint == "/" {
		if err := checkStdoutTar(); err != nil {
			return err
		}
		return dump.WriteTar(ctx, repo, tree, pathToPrint, os.Stdout)
	}

	item := filepath.Join(prefix, pathComponents[0])
	for _, node := range tree.Nodes {
		// If dumping something in the highest level it will just take the
		// first item it finds and dump that according to the switch case below.
		if node.Name == pathComponents[0] {
			switch {
			case l == 1 && dump.IsFile(node):
				return dump.GetNodeData(ctx, os.Stdout, repo, node)
			case l > 1 && dump.IsDir(node):
				subtree, err := repo.LoadTree(ctx, *node.Subtree)
				if err != nil {
					return errors.Wrapf(err, "cannot load subtree for %q", item)
				}
				return printFromTree(ctx, subtree, repo, item, pathComponents[1:], pathToPrint)
			case dump.IsDir(node):
				if err := checkStdoutTar(); err != nil {
					return err
				}
				subtree, err := repo.LoadTree(ctx, *node.Subtree)
				if err != nil {
					return err
				}
				return dump.WriteTar(ctx, repo, subtree, pathToPrint, os.Stdout)
			case l > 1:
				return fmt.Errorf("%q should be a dir, but is a %q", item, node.Type)
			case !dump.IsFile(node):
				return fmt.Errorf("%q should be a file, but is a %q", item, node.Type)
			}
		}
	}
	return fmt.Errorf("path %q not found in snapshot", item)
}

func runDump(opts DumpOptions, gopts GlobalOptions, args []string) error {
	ctx := gopts.ctx

	if len(args) != 2 {
		return errors.Fatal("no file and no snapshot ID specified")
	}

	snapshotIDString := args[0]
	pathToPrint := args[1]

	debug.Log("dump file %q from %q", pathToPrint, snapshotIDString)

	splittedPath := splitPath(path.Clean(pathToPrint))

	repo, err := OpenRepository(gopts)
	if err != nil {
		return err
	}

	if !gopts.NoLock {
		lock, err := lockRepo(repo)
		defer unlockRepo(lock)
		if err != nil {
			return err
		}
	}

	err = repo.LoadIndex(ctx)
	if err != nil {
		return err
	}

	var id restic.ID

	if snapshotIDString == "latest" {
		id, err = restic.FindLatestSnapshot(ctx, repo, opts.Paths, opts.Tags, opts.Hosts)
		if err != nil {
			Exitf(1, "latest snapshot for criteria not found: %v Paths:%v Hosts:%v", err, opts.Paths, opts.Hosts)
		}
	} else {
		id, err = restic.FindSnapshot(repo, snapshotIDString)
		if err != nil {
			Exitf(1, "invalid id %q: %v", snapshotIDString, err)
		}
	}

	sn, err := restic.LoadSnapshot(gopts.ctx, repo, id)
	if err != nil {
		Exitf(2, "loading snapshot %q failed: %v", snapshotIDString, err)
	}

	tree, err := repo.LoadTree(ctx, *sn.Tree)
	if err != nil {
		Exitf(2, "loading tree for snapshot %q failed: %v", snapshotIDString, err)
	}

	err = printFromTree(ctx, tree, repo, "", splittedPath, pathToPrint)
	if err != nil {
		Exitf(2, "cannot dump file: %v", err)
	}

	return nil
}

func checkStdoutTar() error {
	if stdoutIsTerminal() {
		return fmt.Errorf("stdout is the terminal, please redirect output")
	}
	return nil
}
<commit_msg>dump: Properly handle file paths without / prefix<commit_after>package main

import (
	"context"
	"fmt"
	"os"
	"path"
	"path/filepath"

	"github.com/restic/restic/internal/debug"
	"github.com/restic/restic/internal/dump"
	"github.com/restic/restic/internal/errors"
	"github.com/restic/restic/internal/restic"

	"github.com/spf13/cobra"
)

var cmdDump = &cobra.Command{
	Use:   "dump [flags] snapshotID file",
	Short: "Print a backed-up file to stdout",
	Long: `
The "dump" command extracts a single file from a snapshot from the repository and
prints its contents to stdout.

The special snapshot "latest" can be used to use the latest snapshot in the
repository.

EXIT STATUS
===========

Exit status is 0 if the command was successful, and non-zero if there was any error.
`,
	DisableAutoGenTag: true,
	RunE: func(cmd *cobra.Command, args []string) error {
		return runDump(dumpOptions, globalOptions, args)
	},
}

// DumpOptions collects all options for the dump command.
type DumpOptions struct {
	Hosts []string
	Paths []string
	Tags  restic.TagLists
}

var dumpOptions DumpOptions

func init() {
	cmdRoot.AddCommand(cmdDump)

	flags := cmdDump.Flags()
	flags.StringArrayVarP(&dumpOptions.Hosts, "host", "H", nil, `only consider snapshots for this host when the snapshot ID is "latest" (can be specified multiple times)`)
	flags.Var(&dumpOptions.Tags, "tag", "only consider snapshots which include this `taglist` for snapshot ID \"latest\"")
	flags.StringArrayVar(&dumpOptions.Paths, "path", nil, "only consider snapshots which include this (absolute) `path` for snapshot ID \"latest\"")
}

func splitPath(p string) []string {
	d, f := path.Split(p)
	if d == "" || d == "/" {
		return []string{f}
	}
	s := splitPath(path.Join("/", d))
	return append(s, f)
}

func printFromTree(ctx context.Context, tree *restic.Tree, repo restic.Repository, prefix string, pathComponents []string) error {

	if tree == nil {
		return fmt.Errorf("called with a nil tree")
	}
	if repo == nil {
		return fmt.Errorf("called with a nil repository")
	}
	l := len(pathComponents)
	if l == 0 {
		return fmt.Errorf("empty path components")
	}

	// If we print / we need to assume that there are multiple nodes at that
	// level in the tree.
	if pathComponents[0] == "" {
		if err := checkStdoutTar(); err != nil {
			return err
		}
		return dump.WriteTar(ctx, repo, tree, "/", os.Stdout)
	}

	item := filepath.Join(prefix, pathComponents[0])
	for _, node := range tree.Nodes {
		// If dumping something in the highest level it will just take the
		// first item it finds and dump that according to the switch case below.
		if node.Name == pathComponents[0] {
			switch {
			case l == 1 && dump.IsFile(node):
				return dump.GetNodeData(ctx, os.Stdout, repo, node)
			case l > 1 && dump.IsDir(node):
				subtree, err := repo.LoadTree(ctx, *node.Subtree)
				if err != nil {
					return errors.Wrapf(err, "cannot load subtree for %q", item)
				}
				return printFromTree(ctx, subtree, repo, item, pathComponents[1:])
			case dump.IsDir(node):
				if err := checkStdoutTar(); err != nil {
					return err
				}
				subtree, err := repo.LoadTree(ctx, *node.Subtree)
				if err != nil {
					return err
				}
				return dump.WriteTar(ctx, repo, subtree, item, os.Stdout)
			case l > 1:
				return fmt.Errorf("%q should be a dir, but is a %q", item, node.Type)
			case !dump.IsFile(node):
				return fmt.Errorf("%q should be a file, but is a %q", item, node.Type)
			}
		}
	}
	return fmt.Errorf("path %q not found in snapshot", item)
}

func runDump(opts DumpOptions, gopts GlobalOptions, args []string) error {
	ctx := gopts.ctx

	if len(args) != 2 {
		return errors.Fatal("no file and no snapshot ID specified")
	}

	snapshotIDString := args[0]
	pathToPrint := args[1]

	debug.Log("dump file %q from %q", pathToPrint, snapshotIDString)

	splittedPath := splitPath(path.Clean(pathToPrint))

	repo, err := OpenRepository(gopts)
	if err != nil {
		return err
	}

	if !gopts.NoLock {
		lock, err := lockRepo(repo)
		defer unlockRepo(lock)
		if err != nil {
			return err
		}
	}

	err = repo.LoadIndex(ctx)
	if err != nil {
		return err
	}

	var id restic.ID

	if snapshotIDString == "latest" {
		id, err = restic.FindLatestSnapshot(ctx, repo, opts.Paths, opts.Tags, opts.Hosts)
		if err != nil {
			Exitf(1, "latest snapshot for criteria not found: %v Paths:%v Hosts:%v", err, opts.Paths, opts.Hosts)
		}
	} else {
		id, err = restic.FindSnapshot(repo, snapshotIDString)
		if err != nil {
			Exitf(1, "invalid id %q: %v", snapshotIDString, err)
		}
	}

	sn, err := restic.LoadSnapshot(gopts.ctx, repo, id)
	if err != nil {
		Exitf(2, "loading snapshot %q failed: %v", snapshotIDString, err)
	}

	tree, err := repo.LoadTree(ctx, *sn.Tree)
	if err != nil {
		Exitf(2, "loading tree for snapshot %q failed: %v", snapshotIDString, err)
	}

	err = printFromTree(ctx, tree, repo, "/", splittedPath)
	if err != nil {
		Exitf(2, "cannot dump file: %v", err)
	}

	return nil
}

func checkStdoutTar() error {
	if stdoutIsTerminal() {
		return fmt.Errorf("stdout is the terminal, please redirect output")
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"path/filepath"
	"time"

	"github.com/restic/restic"
	"github.com/restic/restic/backend"
)

type findQuery struct {
	name       string
	minModTime time.Time
	maxModTime time.Time
}

type findResult struct {
	node *restic.Node
	path string
}

type CmdFind struct {
	Oldest time.Time `short:"o" long:"oldest" description:"Oldest modification date/time"`
	Newest time.Time `short:"n" long:"newest" description:"Newest modification date/time"`
}

func init() {
	_, err := parser.AddCommand("find",
		"find a file/directory",
		"The find command searches for files or directories in snapshots",
		&CmdFind{})
	if err != nil {
		panic(err)
	}
}

func findInTree(ch *restic.ContentHandler, id backend.ID, path, pattern string) ([]findResult, error) {
	debug("checking tree %v\n", id)

	tree, err := restic.LoadTree(ch, id)
	if err != nil {
		return nil, err
	}

	results := []findResult{}
	for _, node := range tree {
		m, err := filepath.Match(pattern, node.Name)
		if err != nil {
			return nil, err
		}

		debug("  testing entry %q: %v\n", node.Name, m)

		if m {
			results = append(results, findResult{node: node, path: path})
		}

		if node.Type == "dir" {
			subdirResults, err := findInTree(ch, node.Subtree, filepath.Join(path, node.Name), pattern)
			if err != nil {
				return nil, err
			}

			results = append(results, subdirResults...)
		}
	}

	return results, nil
}

func findInSnapshot(be backend.Server, key *restic.Key, id backend.ID, pattern string) error {
	debug("searching in snapshot %v\n", id)

	ch, err := restic.NewContentHandler(be, key)
	if err != nil {
		return err
	}

	sn, err := ch.LoadSnapshot(id)
	if err != nil {
		return err
	}

	results, err := findInTree(ch, sn.Tree, "", pattern)
	if err != nil {
		return err
	}

	if len(results) == 0 {
		return nil
	}

	fmt.Printf("found %d matching entries in snapshot %s\n", len(results), id)
	for _, res := range results {
		res.node.Name = filepath.Join(res.path, res.node.Name)
		fmt.Printf("  %s\n", res.node)
	}

	return nil
}

func (cmd CmdFind) Usage() string {
	return "[find-OPTIONS] PATTERN [snapshot-ID]"
}

func (cmd CmdFind) Execute(args []string) error {
	if len(args) == 0 {
		return fmt.Errorf("no pattern given, Usage: %s", cmd.Usage())
	}

	be, key, err := OpenRepo()
	if err != nil {
		return err
	}

	pattern := args[0]
	if len(args) == 2 {
		snapshotID, err := backend.FindSnapshot(be, args[1])
		if err != nil {
			return fmt.Errorf("invalid id %q: %v", args[1], err)
		}

		return findInSnapshot(be, key, snapshotID, pattern)
	}

	list, err := be.List(backend.Snapshot)
	if err != nil {
		return err
	}

	for _, snapshotID := range list {
		err := findInSnapshot(be, key, snapshotID, pattern)

		if err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>Add time to command 'find'<commit_after>package main

import (
	"fmt"
	"path/filepath"
	"time"

	"github.com/restic/restic"
	"github.com/restic/restic/backend"
)

type findQuery struct {
	name       string
	minModTime time.Time
	maxModTime time.Time
}

type findResult struct {
	node *restic.Node
	path string
}

type CmdFind struct {
	Oldest   string `short:"o" long:"oldest" description:"Oldest modification date/time"`
	Newest   string `short:"n" long:"newest" description:"Newest modification date/time"`
	Snapshot string `short:"s" long:"snapshot" description:"Snapshot ID to search in"`

	oldest, newest time.Time
	pattern        string
}

var timeFormats = []string{
	"2006-01-02",
	"2006-01-02 15:04",
	"2006-01-02 15:04:05",
	"2006-01-02 15:04:05 -0700",
	"2006-01-02 15:04:05 MST",
	"02.01.2006",
	"02.01.2006 15:04",
	"02.01.2006 15:04:05",
	"02.01.2006 15:04:05 -0700",
	"02.01.2006 15:04:05 MST",
	"Mon Jan 2 15:04:05 -0700 MST 2006",
}

func init() {
	_, err := parser.AddCommand("find",
		"find a file/directory",
		"The find command searches for files or directories in snapshots",
		&CmdFind{})
	if err != nil {
		panic(err)
	}
}

func parseTime(str string) (time.Time, error) {
	for _, fmt := range timeFormats {
		if t, err := time.ParseInLocation(fmt, str, time.Local); err == nil {
			return t, nil
		}
	}

	return time.Time{}, fmt.Errorf("unable to parse time: %q", str)
}

func (c CmdFind) findInTree(ch *restic.ContentHandler, id backend.ID, path string) ([]findResult, error) {
	debug("checking tree %v\n", id)

	tree, err := restic.LoadTree(ch, id)
	if err != nil {
		return nil, err
	}

	results := []findResult{}
	for _, node := range tree {
		debug("  testing entry %q\n", node.Name)

		m, err := filepath.Match(c.pattern, node.Name)
		if err != nil {
			return nil, err
		}

		if m {
			debug("    pattern matches\n")
			if !c.oldest.IsZero() && node.ModTime.Before(c.oldest) {
				debug("    ModTime is older than %s\n", c.oldest)
				continue
			}

			if !c.newest.IsZero() && node.ModTime.After(c.newest) {
				debug("    ModTime is newer than %s\n", c.newest)
				continue
			}

			results = append(results, findResult{node: node, path: path})
		} else {
			debug("    pattern does not match\n")
		}

		if node.Type == "dir" {
			subdirResults, err := c.findInTree(ch, node.Subtree, filepath.Join(path, node.Name))
			if err != nil {
				return nil, err
			}

			results = append(results, subdirResults...)
		}
	}

	return results, nil
}

func (c CmdFind) findInSnapshot(be backend.Server, key *restic.Key, id backend.ID) error {
	debug("searching in snapshot %s\n  for entries within [%s %s]", id, c.oldest, c.newest)

	ch, err := restic.NewContentHandler(be, key)
	if err != nil {
		return err
	}

	sn, err := ch.LoadSnapshot(id)
	if err != nil {
		return err
	}

	results, err := c.findInTree(ch, sn.Tree, "")
	if err != nil {
		return err
	}

	if len(results) == 0 {
		return nil
	}

	fmt.Printf("found %d matching entries in snapshot %s\n", len(results), id)
	for _, res := range results {
		res.node.Name = filepath.Join(res.path, res.node.Name)
		fmt.Printf("  %s\n", res.node)
	}

	return nil
}

func (CmdFind) Usage() string {
	return "[find-OPTIONS] PATTERN"
}

func (c CmdFind) Execute(args []string) error {
	if len(args) != 1 {
		return fmt.Errorf("invalid number of arguments, Usage: %s", c.Usage())
	}

	var err error

	if c.Oldest != "" {
		c.oldest, err = parseTime(c.Oldest)
		if err != nil {
			return err
		}
	}

	if c.Newest != "" {
		c.newest, err = parseTime(c.Newest)
		if err != nil {
			return err
		}
	}

	be, key, err := OpenRepo()
	if err != nil {
		return err
	}

	c.pattern = args[0]

	if c.Snapshot != "" {
		snapshotID, err := backend.FindSnapshot(be, c.Snapshot)
		if err != nil {
			return fmt.Errorf("invalid id %q: %v", args[1], err)
		}

		return c.findInSnapshot(be, key, snapshotID)
	}

	list, err := be.List(backend.Snapshot)
	if err != nil {
		return err
	}

	for _, snapshotID := range list {
		err := c.findInSnapshot(be, key, snapshotID)

		if err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>