<commit_before>package cmd

import (
	"errors"
	"fmt"
	"time"

	"github.com/spf13/cobra"
	"net/http"
)

type stressRequest interface{}

type finishedStress struct{}

type workerDone struct{}

type requestStat struct {
	duration int64 //milliseconds
}
type requestStatSummary struct {
	avgDuration      int64 //milliseconds
	longestDuration  int64 //milliseconds
	shortestDuration int64 //milliseconds
}

//flags
var (
	numTests    int
	timeout     int
	concurrency int
)

func init() {
	RootCmd.AddCommand(stressCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// stressCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// stressCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

	stressCmd.Flags().IntVarP(&numTests, "num", "n", 100, "Number of requests to make")
	stressCmd.Flags().IntVarP(&concurrency, "concurrent", "c", 1, "Number of multiple requests to make")
	stressCmd.Flags().IntVarP(&timeout, "timeout", "t", 0, "Maximum seconds to wait for response. 0 means unlimited")
}

// stressCmd represents the stress command
var stressCmd = &cobra.Command{
	Use:   "stress http[s]://hostname[:port]/path",
	Short: "Run predefined load of requests",
	Long:  `Run predefined load of requests`,
	RunE:  RunStress,
}

func RunStress(cmd *cobra.Command, args []string) error {
	//checks
	if len(args) != 1 {
		return errors.New("needs URL")
	}
	if numTests <= 0 {
		return errors.New("number of requests must be one or more")
	}
	if concurrency <= 0 {
		return errors.New("concurrency must be one or more")
	}
	if timeout < 0 {
		return errors.New("timeout must be zero or more")
	}

	fmt.Println("running stress")

	//setup the queue of requests
	requestChan := make(chan stressRequest, numTests+concurrency)
	for i := 0; i < numTests; i++ {
		//TODO optimize by not creating a new http request each time since it's the same thing
		req, err := http.NewRequest("GET", args[0], nil)
		if err != nil {
			return errors.New("failed to create request: " + err.Error())
		}
		requestChan <- req
	}
	for i := 0; i < concurrency; i++ {
		requestChan <- finishedStress{}
	}

	workerDoneChan := make(chan workerDone)   //workers use this to indicate they are done
	requestStatChan := make(chan requestStat) //workers communicate each requests' info

	//workers
	for i := 0; i < concurrency; i++ {
		go func() {
			client := &http.Client{Timeout: time.Duration(timeout) * time.Second}
			for {
				select {
				case req := <-requestChan:
					switch req.(type) {
					case *http.Request:
						//run the acutal request
						reqStartTime := time.Now()
						_, err := client.Do(req.(*http.Request))
						reqEndTime := time.Now()
						if err != nil {
							fmt.Errorf(err.Error()) //TODO handle this further up
						}
						reqTimeMs := (reqEndTime.UnixNano() - reqStartTime.UnixNano()) / 1000000
						fmt.Printf("request took %dms\n", reqTimeMs)
						requestStatChan <- requestStat{duration: reqTimeMs}
					case finishedStress:
						workerDoneChan <- workerDone{}
						return
					}
				}
			}
		}()
	}

	allRequestStats := make([]requestStat, numTests)
	requestsCompleteCount := 0
	workersDoneCount := 0
	//wait for all workers to finish
	for {
		select {
		case <-workerDoneChan:
			workersDoneCount++
			if workersDoneCount == concurrency {
				//all workers are done
				fmt.Println("%+v", createStats(allRequestStats))
				return nil
			}
		case requestStat := <-requestStatChan:
			allRequestStats[requestsCompleteCount] = requestStat
			requestsCompleteCount++
		}
	}

	return nil
}

func createStats(requestStats []requestStat) requestStatSummary {
	if len(requestStats) == 0 {
		return requestStatSummary{}
	}

	summary := requestStatSummary{longestDuration: requestStats[0].duration, shortestDuration: requestStats[0].duration}
	var totalDurations int64
	totalDurations = 0
	for i := 0; i < len(requestStats); i++ {
		if requestStats[i].duration > summary.longestDuration {
			summary.longestDuration = requestStats[i].duration
		}
		if requestStats[i].duration < summary.shortestDuration {
			summary.shortestDuration = requestStats[i].duration
		}
		totalDurations += requestStats[i].duration
	}
	summary.avgDuration = totalDurations / int64(len(requestStats))
	return summary
}
<commit_msg>Cleaner printing of request summary<commit_after>package cmd

import (
	"errors"
	"fmt"
	"strconv"
	"time"

	"github.com/spf13/cobra"
	"net/http"
)

type stressRequest interface{}

type finishedStress struct{}

type workerDone struct{}

type requestStat struct {
	duration int64 //milliseconds
}
type requestStatSummary struct {
	avgDuration int64 //milliseconds
	maxDuration int64 //milliseconds
	minDuration int64 //milliseconds
}

//flags
var (
	numTests    int
	timeout     int
	concurrency int
)

func init() {
	RootCmd.AddCommand(stressCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// stressCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// stressCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

	stressCmd.Flags().IntVarP(&numTests, "num", "n", 100, "Number of requests to make")
	stressCmd.Flags().IntVarP(&concurrency, "concurrent", "c", 1, "Number of multiple requests to make")
	stressCmd.Flags().IntVarP(&timeout, "timeout", "t", 0, "Maximum seconds to wait for response. 0 means unlimited")
}

// stressCmd represents the stress command
var stressCmd = &cobra.Command{
	Use:   "stress http[s]://hostname[:port]/path",
	Short: "Run predefined load of requests",
	Long:  `Run predefined load of requests`,
	RunE:  RunStress,
}

func RunStress(cmd *cobra.Command, args []string) error {
	//checks
	if len(args) != 1 {
		return errors.New("needs URL")
	}
	if numTests <= 0 {
		return errors.New("number of requests must be one or more")
	}
	if concurrency <= 0 {
		return errors.New("concurrency must be one or more")
	}
	if timeout < 0 {
		return errors.New("timeout must be zero or more")
	}

	url := args[0]

	fmt.Println("Stress testing " + url + "...")

	//setup the queue of requests
	requestChan := make(chan stressRequest, numTests+concurrency)
	for i := 0; i < numTests; i++ {
		//TODO optimize by not creating a new http request each time since it's the same thing
		req, err := http.NewRequest("GET", url, nil)
		if err != nil {
			return errors.New("failed to create request: " + err.Error())
		}
		requestChan <- req
	}
	for i := 0; i < concurrency; i++ {
		requestChan <- finishedStress{}
	}

	workerDoneChan := make(chan workerDone)   //workers use this to indicate they are done
	requestStatChan := make(chan requestStat) //workers communicate each requests' info

	//workers
	for i := 0; i < concurrency; i++ {
		go func() {
			client := &http.Client{Timeout: time.Duration(timeout) * time.Second}
			for {
				select {
				case req := <-requestChan:
					switch req.(type) {
					case *http.Request:
						//run the acutal request
						reqStartTime := time.Now()
						_, err := client.Do(req.(*http.Request))
						reqEndTime := time.Now()
						if err != nil {
							fmt.Errorf(err.Error()) //TODO handle this further up
						}
						reqTimeMs := (reqEndTime.UnixNano() - reqStartTime.UnixNano()) / 1000000
						fmt.Printf("request took %dms\n", reqTimeMs)
						requestStatChan <- requestStat{duration: reqTimeMs}
					case finishedStress:
						workerDoneChan <- workerDone{}
						return
					}
				}
			}
		}()
	}

	allRequestStats := make([]requestStat, numTests)
	requestsCompleteCount := 0
	workersDoneCount := 0
	//wait for all workers to finish
	for {
		select {
		case <-workerDoneChan:
			workersDoneCount++
			if workersDoneCount == concurrency {
				//all workers are done
				fmt.Println(createTextSummary(createStats(allRequestStats)))
				return nil
			}
		case requestStat := <-requestStatChan:
			allRequestStats[requestsCompleteCount] = requestStat
			requestsCompleteCount++
		}
	}
}

func createStats(requestStats []requestStat) requestStatSummary {
	if len(requestStats) == 0 {
		return requestStatSummary{}
	}

	summary := requestStatSummary{maxDuration: requestStats[0].duration, minDuration: requestStats[0].duration}
	var totalDurations int64
	totalDurations = 0
	for i := 0; i < len(requestStats); i++ {
		if requestStats[i].duration > summary.maxDuration {
			summary.maxDuration = requestStats[i].duration
		}
		if requestStats[i].duration < summary.minDuration {
			summary.minDuration = requestStats[i].duration
		}
		totalDurations += requestStats[i].duration
	}
	summary.avgDuration = totalDurations / int64(len(requestStats))
	return summary
}

func createTextSummary(summary requestStatSummary) string {
	return `Average: ` + strconv.Itoa(int(summary.avgDuration)) + "ms\n" +
		`Max:     ` + strconv.Itoa(int(summary.maxDuration)) + "ms\n" +
		`Min:     ` + strconv.Itoa(int(summary.minDuration)) + "ms"
}
<|endoftext|>


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

// Copy files.
//
// Synopsis:
//     cp [-rRfivwP] FROM... TO
//
// Options:
//     -w n: number of worker goroutines
//     -R: copy file hierarchies
//     -r: alias to -R recursive mode
//     -i: prompt about overwriting file
//     -f: force overwrite files
//     -v: verbose copy mode
//     -P: don't follow symlinks
package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

// buffSize is the length of buffer during
// the parallel copy using worker function
const buffSize = 8192

var (
	recursive bool
	ask       bool
	force     bool
	verbose   bool
	symlink   bool
	nwork     int
	input     = bufio.NewReader(os.Stdin)
	// offchan is a channel used for indicate the nextbuffer to read with worker()
	offchan = make(chan int64, 0)
	// zerochan is a channel used for indicate the start of a new read file
	zerochan = make(chan int, 0)
)

func init() {
	defUsage := flag.Usage
	flag.Usage = func() {
		os.Args[0] = "cp [-wRrifvP] file[s] ... dest"
		defUsage()
	}
	flag.IntVar(&nwork, "w", runtime.NumCPU(), "number of worker goroutines")
	flag.BoolVar(&recursive, "R", false, "copy file hierarchies")
	flag.BoolVar(&recursive, "r", false, "alias to -R recursive mode")
	flag.BoolVar(&ask, "i", false, "prompt about overwriting file")
	flag.BoolVar(&force, "f", false, "force overwrite files")
	flag.BoolVar(&verbose, "v", false, "verbose copy mode")
	flag.BoolVar(&symlink, "P", false, "don't follow symlinks")
	flag.Parse()
	go nextOff()
}

// promptOverwrite ask if the user wants overwrite file
func promptOverwrite(dst string) (bool, error) {
	fmt.Printf("cp: overwrite %q? ", dst)
	answer, err := input.ReadString('\n')
	if err != nil {
		return false, err
	}

	if strings.ToLower(answer)[0] != 'y' {
		return false, nil
	}

	return true, nil
}

// copyFile copies file between src (source) and dst (destination)
// todir: if true insert src INTO dir dst
func copyFile(src, dst string, todir bool) error {
	if todir {
		file := filepath.Base(src)
		dst = filepath.Join(dst, file)
	}

	srcb, err := os.Lstat(src)
	if err != nil {
		return fmt.Errorf("can't stat %v: %v", src, err)
	}

	// don't follow symlinks, copy symlink
	if L := os.ModeSymlink; symlink && srcb.Mode()&L == L {
		linkPath, err := filepath.EvalSymlinks(src)
		if err != nil {
			return fmt.Errorf("can't eval symlink %v: %v", src, err)
		}
		return os.Symlink(linkPath, dst)
	}

	if srcb.IsDir() {
		if recursive {
			return copyDir(src, dst)
		}
		return fmt.Errorf("%q is a directory, try use recursive option", src)
	}

	dstb, err := os.Stat(dst)
	if !os.IsNotExist(err) {
		if sameFile(srcb.Sys(), dstb.Sys()) {
			return fmt.Errorf("%q and %q are the same file", src, dst)
		}
		if ask && !force {
			overwrite, err := promptOverwrite(dst)
			if err != nil {
				return err
			}
			if !overwrite {
				return nil
			}
		}
	}

	mode := srcb.Mode() & 0777
	s, err := os.Open(src)
	if err != nil {
		return fmt.Errorf("can't open %q: %v", src, err)
	}
	defer s.Close()

	d, err := os.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode)
	if err != nil {
		return fmt.Errorf("can't create %q: %v", dst, err)
	}
	defer d.Close()

	return copyOneFile(s, d, src, dst)
}

// copyOneFile copy the content between two files
func copyOneFile(s *os.File, d *os.File, src, dst string) error {
	zerochan <- 0
	fail := make(chan error, nwork)
	for i := 0; i < nwork; i++ {
		go worker(s, d, fail)
	}

	// iterate the errors from channel
	for i := 0; i < nwork; i++ {
		err := <-fail
		if err != nil {
			return err
		}
	}

	if verbose {
		fmt.Printf("%q -> %q\n", src, dst)
	}

	return nil
}

// createDir populate dir destination if not exists
// if exists verify is not a dir: return error if is file
// cannot overwrite: dir -> file
func createDir(src, dst string) error {
	dstInfo, err := os.Stat(dst)
	if err != nil && !os.IsNotExist(err) {
		return err
	}

	if err == nil {
		if !dstInfo.IsDir() {
			return fmt.Errorf("can't overwrite non-dir %q with dir %q", dst, src)
		}
		return nil
	}

	srcInfo, err := os.Stat(src)
	if err != nil {
		return err
	}
	if err := os.Mkdir(dst, srcInfo.Mode()); err != nil {
		return err
	}
	if verbose {
		fmt.Printf("%q -> %q\n", src, dst)
	}

	return nil
}

// copyDir copy the file hierarchies
// used at cp when -r or -R flag is true
func copyDir(src, dst string) error {
	if err := createDir(src, dst); err != nil {
		return err
	}

	// list files from destination
	files, err := ioutil.ReadDir(src)
	if err != nil {
		return fmt.Errorf("can't list files from %q: %q", src, err)
	}

	// copy recursively the src -> dst
	for _, file := range files {
		fname := file.Name()
		fpath := filepath.Join(src, fname)
		newDst := filepath.Join(dst, fname)
		copyFile(fpath, newDst, false)
	}

	return err
}

// worker is a concurrent copy, used to copy part of the files
// in parallel
func worker(s *os.File, d *os.File, fail chan error) {
	var buf [buffSize]byte
	var bp []byte

	l := len(buf)
	bp = buf[0:]
	o := <-offchan
	for {
		n, err := s.ReadAt(bp, o)
		if err != nil && err != io.EOF {
			fail <- fmt.Errorf("reading %s at %v: %v", s.Name(), o, err)
			return
		}
		if n == 0 {
			break
		}

		nb := bp[0:n]
		n, err = d.WriteAt(nb, o)
		if err != nil {
			fail <- fmt.Errorf("writing %s: %v", d.Name(), err)
			return
		}
		bp = buf[n:]
		o += int64(n)
		l -= n
		if l == 0 {
			l = len(buf)
			bp = buf[0:]
			o = <-offchan
		}
	}
	fail <- nil
}

// nextOff handler for next buffers and sync goroutines
// zerochan imply the init of file
// offchan is the next buffer part to read
func nextOff() {
	off := int64(0)
	for {
		select {
		case <-zerochan:
			off = 0
		case offchan <- off:
			off += buffSize
		}
	}
}

// cp is a function whose eval the args
// and make decisions for copyfiles
func cp(args []string) (lastErr error) {
	todir := false
	from, to := args[:len(args)-1], args[len(args)-1]
	toStat, err := os.Stat(to)
	if err == nil {
		todir = toStat.IsDir()
	}
	if flag.NArg() > 2 && todir == false {
		log.Fatalf("is not a directory: %s\n", to)
	}

	for _, file := range from {
		if err := copyFile(file, to, todir); err != nil {
			log.Printf("cp: %v\n", err)
			lastErr = err
		}
	}

	return err
}

func main() {
	if flag.NArg() < 2 {
		flag.Usage()
		os.Exit(1)
	}

	if err := cp(flag.Args()); err != nil {
		os.Exit(1)
	}

}
<commit_msg>cp: fix incorrect handling of error on Stat of dst<commit_after>// Copyright 2016-2017 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Copy files.
//
// Synopsis:
//     cp [-rRfivwP] FROM... TO
//
// Options:
//     -w n: number of worker goroutines
//     -R: copy file hierarchies
//     -r: alias to -R recursive mode
//     -i: prompt about overwriting file
//     -f: force overwrite files
//     -v: verbose copy mode
//     -P: don't follow symlinks
package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

// buffSize is the length of buffer during
// the parallel copy using worker function
const buffSize = 8192

var (
	recursive bool
	ask       bool
	force     bool
	verbose   bool
	symlink   bool
	nwork     int
	input     = bufio.NewReader(os.Stdin)
	// offchan is a channel used for indicate the nextbuffer to read with worker()
	offchan = make(chan int64, 0)
	// zerochan is a channel used for indicate the start of a new read file
	zerochan = make(chan int, 0)
)

func init() {
	defUsage := flag.Usage
	flag.Usage = func() {
		os.Args[0] = "cp [-wRrifvP] file[s] ... dest"
		defUsage()
	}
	flag.IntVar(&nwork, "w", runtime.NumCPU(), "number of worker goroutines")
	flag.BoolVar(&recursive, "R", false, "copy file hierarchies")
	flag.BoolVar(&recursive, "r", false, "alias to -R recursive mode")
	flag.BoolVar(&ask, "i", false, "prompt about overwriting file")
	flag.BoolVar(&force, "f", false, "force overwrite files")
	flag.BoolVar(&verbose, "v", false, "verbose copy mode")
	flag.BoolVar(&symlink, "P", false, "don't follow symlinks")
	flag.Parse()
	go nextOff()
}

// promptOverwrite ask if the user wants overwrite file
func promptOverwrite(dst string) (bool, error) {
	fmt.Printf("cp: overwrite %q? ", dst)
	answer, err := input.ReadString('\n')
	if err != nil {
		return false, err
	}

	if strings.ToLower(answer)[0] != 'y' {
		return false, nil
	}

	return true, nil
}

// copyFile copies file between src (source) and dst (destination)
// todir: if true insert src INTO dir dst
func copyFile(src, dst string, todir bool) error {
	if todir {
		file := filepath.Base(src)
		dst = filepath.Join(dst, file)
	}

	srcb, err := os.Lstat(src)
	if err != nil {
		return fmt.Errorf("can't stat %v: %v", src, err)
	}

	// don't follow symlinks, copy symlink
	if L := os.ModeSymlink; symlink && srcb.Mode()&L == L {
		linkPath, err := filepath.EvalSymlinks(src)
		if err != nil {
			return fmt.Errorf("can't eval symlink %v: %v", src, err)
		}
		return os.Symlink(linkPath, dst)
	}

	if srcb.IsDir() {
		if recursive {
			return copyDir(src, dst)
		}
		return fmt.Errorf("%q is a directory, try use recursive option", src)
	}

	dstb, err := os.Stat(dst)
	if err != nil && !os.IsNotExist(err) {
		return fmt.Errorf("%q: can't handle error %v", dst, err)
	}

	if dstb != nil {
		if sameFile(srcb.Sys(), dstb.Sys()) {
			return fmt.Errorf("%q and %q are the same file", src, dst)
		}
		if ask && !force {
			overwrite, err := promptOverwrite(dst)
			if err != nil {
				return err
			}
			if !overwrite {
				return nil
			}
		}
	}

	mode := srcb.Mode() & 0777
	s, err := os.Open(src)
	if err != nil {
		return fmt.Errorf("can't open %q: %v", src, err)
	}
	defer s.Close()

	d, err := os.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode)
	if err != nil {
		return fmt.Errorf("can't create %q: %v", dst, err)
	}
	defer d.Close()

	return copyOneFile(s, d, src, dst)
}

// copyOneFile copy the content between two files
func copyOneFile(s *os.File, d *os.File, src, dst string) error {
	zerochan <- 0
	fail := make(chan error, nwork)
	for i := 0; i < nwork; i++ {
		go worker(s, d, fail)
	}

	// iterate the errors from channel
	for i := 0; i < nwork; i++ {
		err := <-fail
		if err != nil {
			return err
		}
	}

	if verbose {
		fmt.Printf("%q -> %q\n", src, dst)
	}

	return nil
}

// createDir populate dir destination if not exists
// if exists verify is not a dir: return error if is file
// cannot overwrite: dir -> file
func createDir(src, dst string) error {
	dstInfo, err := os.Stat(dst)
	if err != nil && !os.IsNotExist(err) {
		return err
	}

	if err == nil {
		if !dstInfo.IsDir() {
			return fmt.Errorf("can't overwrite non-dir %q with dir %q", dst, src)
		}
		return nil
	}

	srcInfo, err := os.Stat(src)
	if err != nil {
		return err
	}
	if err := os.Mkdir(dst, srcInfo.Mode()); err != nil {
		return err
	}
	if verbose {
		fmt.Printf("%q -> %q\n", src, dst)
	}

	return nil
}

// copyDir copy the file hierarchies
// used at cp when -r or -R flag is true
func copyDir(src, dst string) error {
	if err := createDir(src, dst); err != nil {
		return err
	}

	// list files from destination
	files, err := ioutil.ReadDir(src)
	if err != nil {
		return fmt.Errorf("can't list files from %q: %q", src, err)
	}

	// copy recursively the src -> dst
	for _, file := range files {
		fname := file.Name()
		fpath := filepath.Join(src, fname)
		newDst := filepath.Join(dst, fname)
		copyFile(fpath, newDst, false)
	}

	return err
}

// worker is a concurrent copy, used to copy part of the files
// in parallel
func worker(s *os.File, d *os.File, fail chan error) {
	var buf [buffSize]byte
	var bp []byte

	l := len(buf)
	bp = buf[0:]
	o := <-offchan
	for {
		n, err := s.ReadAt(bp, o)
		if err != nil && err != io.EOF {
			fail <- fmt.Errorf("reading %s at %v: %v", s.Name(), o, err)
			return
		}
		if n == 0 {
			break
		}

		nb := bp[0:n]
		n, err = d.WriteAt(nb, o)
		if err != nil {
			fail <- fmt.Errorf("writing %s: %v", d.Name(), err)
			return
		}
		bp = buf[n:]
		o += int64(n)
		l -= n
		if l == 0 {
			l = len(buf)
			bp = buf[0:]
			o = <-offchan
		}
	}
	fail <- nil
}

// nextOff handler for next buffers and sync goroutines
// zerochan imply the init of file
// offchan is the next buffer part to read
func nextOff() {
	off := int64(0)
	for {
		select {
		case <-zerochan:
			off = 0
		case offchan <- off:
			off += buffSize
		}
	}
}

// cp is a function whose eval the args
// and make decisions for copyfiles
func cp(args []string) (lastErr error) {
	todir := false
	from, to := args[:len(args)-1], args[len(args)-1]
	toStat, err := os.Stat(to)
	if err == nil {
		todir = toStat.IsDir()
	}
	if flag.NArg() > 2 && todir == false {
		log.Fatalf("is not a directory: %s\n", to)
	}

	for _, file := range from {
		if err := copyFile(file, to, todir); err != nil {
			log.Printf("cp: %v\n", err)
			lastErr = err
		}
	}

	return err
}

func main() {
	if flag.NArg() < 2 {
		flag.Usage()
		os.Exit(1)
	}

	if err := cp(flag.Args()); err != nil {
		os.Exit(1)
	}

}
<|endoftext|>


<commit_before>package gkvlite

import (
	"encoding/json"
	"errors"
	"fmt"
	"math/rand"
	"sync"
	"sync/atomic"
	"unsafe"
)

// User-supplied key comparison func should return 0 if a == b,
// -1 if a < b, and +1 if a > b.  For example: bytes.Compare()
type KeyCompare func(a, b []byte) int

// A persistable collection of ordered key-values (Item's).
type Collection struct {
	name    string // May be "" for a private collection.
	store   *Store
	compare KeyCompare

	rootLock *sync.Mutex
	root     *rootNodeLoc // Protected by rootLock.

	stats CollectionStats

	freeLock         sync.Mutex
	freeNodes        *node        // Protected by freeLock.
	freeNodeLocs     *nodeLoc     // Not protected by freeLock.
	freeRootNodeLocs *rootNodeLoc // Protected by freeLock.
}

type CollectionStats struct {
	MkNodeLocs    int64
	FreeNodeLocs  int64
	AllocNodeLocs int64

	MkNodes    int64
	FreeNodes  int64
	AllocNodes int64
}

type rootNodeLoc struct {
	refs int64 // Atomic reference counter.
	root *nodeLoc
	next *rootNodeLoc // For free-list tracking.
}

func (t *Collection) Name() string {
	return t.name
}

// Retrieve an item by its key.  Use withValue of false if you don't
// need the item's value (Item.Val may be nil), which might be able
// to save on I/O and memory resources, especially for large values.
// The returned Item should be treated as immutable.
func (t *Collection) GetItem(key []byte, withValue bool) (i *Item, err error) {
	rnl := t.rootAddRef()
	defer t.rootDecRef(rnl)
	n := rnl.root
	for {
		nNode, err := n.read(t.store)
		if err != nil || n.isEmpty() || nNode == nil {
			return nil, err
		}
		i := &nNode.item
		iItem, err := i.read(t, false)
		if err != nil {
			return nil, err
		}
		if iItem == nil || iItem.Key == nil {
			return nil, errors.New("missing item after item.read() in GetItem()")
		}
		c := t.compare(key, iItem.Key)
		if c < 0 {
			n = &nNode.left
		} else if c > 0 {
			n = &nNode.right
		} else {
			if withValue {
				iItem, err = i.read(t, withValue)
				if err != nil {
					return nil, err
				}
			}
			return iItem, nil
		}
	}
}

// Retrieve a value by its key.  Returns nil if the item is not in the
// collection.  The returned value should be treated as immutable.
func (t *Collection) Get(key []byte) (val []byte, err error) {
	i, err := t.GetItem(key, true)
	if err != nil {
		return nil, err
	}
	if i != nil {
		return i.Val, nil
	}
	return nil, nil
}

// Replace or insert an item of a given key.
// A random item Priority (e.g., rand.Int31()) will usually work well,
// but advanced users may consider using non-random item priorities
// at the risk of unbalancing the lookup tree.  The input Item instance
// should be considered immutable and owned by the Collection.
func (t *Collection) SetItem(item *Item) (err error) {
	if item.Key == nil || len(item.Key) > 0xffff || len(item.Key) == 0 ||
		item.Val == nil {
		return errors.New("Item.Key/Val missing or too long")
	}
	if item.Priority < 0 {
		return errors.New("Item.Priority must be non-negative")
	}
	rnl := t.rootAddRef()
	defer t.rootDecRef(rnl)
	root := rnl.root
	n := t.mkNode(nil, nil, nil, 1, uint64(len(item.Key))+uint64(item.NumValBytes(t)))
	n.item.item = unsafe.Pointer(item) // Avoid garbage via separate init.
	nloc := t.mkNodeLoc(n)
	r, err := t.store.union(t, root, nloc)
	if err != nil {
		return err
	}
	if !t.rootCAS(rnl, t.mkRootNodeLoc(r)) {
		return errors.New("concurrent mutation attempted")
	}
	t.rootDecRef(rnl)
	t.freeNodeLoc(nloc)
	t.reclaimNodes(n)
	return nil
}

// Replace or insert an item of a given key.
func (t *Collection) Set(key []byte, val []byte) error {
	return t.SetItem(&Item{Key: key, Val: val, Priority: rand.Int31()})
}

// Deletes an item of a given key.
func (t *Collection) Delete(key []byte) (wasDeleted bool, err error) {
	rnl := t.rootAddRef()
	defer t.rootDecRef(rnl)
	root := rnl.root
	i, err := t.GetItem(key, false)
	if err != nil || i == nil {
		return false, err
	}
	left, middle, right, err := t.store.split(t, root, key)
	if err != nil {
		return false, err
	}
	if middle.isEmpty() {
		return false, fmt.Errorf("concurrent delete, key: %v", key)
	}
	// TODO: Even though we markReclaimable() the middle node, there
	// might not be a pathway to it during reclaimation.
	t.markReclaimable(middle.Node())
	t.freeNodeLoc(middle)
	r, err := t.store.join(t, left, right)
	if err != nil {
		return false, err
	}
	if !t.rootCAS(rnl, t.mkRootNodeLoc(r)) {
		return false, errors.New("concurrent mutation attempted")
	}
	t.rootDecRef(rnl)
	t.reclaimNodes(left.Node())
	t.reclaimNodes(right.Node())
	t.freeNodeLoc(left)
	t.freeNodeLoc(right)
	return true, nil
}

// Retrieves the item with the "smallest" key.
// The returned item should be treated as immutable.
func (t *Collection) MinItem(withValue bool) (*Item, error) {
	return t.store.walk(t, withValue,
		func(n *node) (*nodeLoc, bool) { return &n.left, true })
}

// Retrieves the item with the "largest" key.
// The returned item should be treated as immutable.
func (t *Collection) MaxItem(withValue bool) (*Item, error) {
	return t.store.walk(t, withValue,
		func(n *node) (*nodeLoc, bool) { return &n.right, true })
}

// Evict some clean items found by randomly walking a tree branch.
func (t *Collection) EvictSomeItems() (numEvicted uint64) {
	t.store.walk(t, false, func(n *node) (*nodeLoc, bool) {
		if !n.item.Loc().isEmpty() {
			atomic.StorePointer(&n.item.item, unsafe.Pointer(nil))
			numEvicted++
		}
		next := &n.left
		if (rand.Int() & 0x01) == 0x01 {
			next = &n.right
		}
		if next.isEmpty() {
			return nil, false
		}
		return next, true
	})
	return numEvicted
}

type ItemVisitor func(i *Item) bool
type ItemVisitorEx func(i *Item, depth uint64) bool

// Visit items greater-than-or-equal to the target key in ascending order.
func (t *Collection) VisitItemsAscend(target []byte, withValue bool, v ItemVisitor) error {
	return t.VisitItemsAscendEx(target, withValue,
		func(i *Item, depth uint64) bool { return v(i) })
}

// Visit items less-than the target key in descending order.
func (t *Collection) VisitItemsDescend(target []byte, withValue bool, v ItemVisitor) error {
	return t.VisitItemsDescendEx(target, withValue,
		func(i *Item, depth uint64) bool { return v(i) })
}

// Visit items greater-than-or-equal to the target key in ascending order; with depth info.
func (t *Collection) VisitItemsAscendEx(target []byte, withValue bool,
	visitor ItemVisitorEx) error {
	rnl := t.rootAddRef()
	defer t.rootDecRef(rnl)
	_, err := t.store.visitNodes(t, rnl.root,
		target, withValue, visitor, 0, ascendChoice)
	return err
}

// Visit items less-than the target key in descending order; with depth info.
func (t *Collection) VisitItemsDescendEx(target []byte, withValue bool,
	visitor ItemVisitorEx) error {
	rnl := t.rootAddRef()
	defer t.rootDecRef(rnl)
	_, err := t.store.visitNodes(t, rnl.root,
		target, withValue, visitor, 0, descendChoice)
	return err
}

func ascendChoice(cmp int, n *node) (bool, *nodeLoc, *nodeLoc) {
	return cmp <= 0, &n.left, &n.right
}

func descendChoice(cmp int, n *node) (bool, *nodeLoc, *nodeLoc) {
	return cmp > 0, &n.right, &n.left
}

// Returns total number of items and total key bytes plus value bytes.
func (t *Collection) GetTotals() (numItems uint64, numBytes uint64, err error) {
	rnl := t.rootAddRef()
	defer t.rootDecRef(rnl)
	n := rnl.root
	nNode, err := n.read(t.store)
	if err != nil || n.isEmpty() || nNode == nil {
		return 0, 0, err
	}
	return nNode.numNodes, nNode.numBytes, nil
}

// Returns JSON representation of root node file location.
func (t *Collection) MarshalJSON() ([]byte, error) {
	rnl := t.rootAddRef()
	defer t.rootDecRef(rnl)
	loc := rnl.root.Loc()
	if loc.isEmpty() {
		return json.Marshal(ploc_empty)
	}
	return json.Marshal(loc)
}

// Unmarshals JSON representation of root node file location.
func (t *Collection) UnmarshalJSON(d []byte) error {
	p := ploc{}
	if err := json.Unmarshal(d, &p); err != nil {
		return err
	}
	if t.rootLock == nil {
		t.rootLock = &sync.Mutex{}
	}
	nloc := t.mkNodeLoc(nil)
	nloc.loc = unsafe.Pointer(&p)
	if !t.rootCAS(nil, t.mkRootNodeLoc(nloc)) {
		return errors.New("concurrent mutation during UnmarshalJSON().")
	}
	return nil
}

// Writes dirty items of a collection BUT (WARNING) does NOT write new
// root records.  Use Store.Flush() to write root records, which would
// make these writes visible to the next file re-opening/re-loading.
func (t *Collection) Write() (err error) {
	rnl := t.rootAddRef()
	defer t.rootDecRef(rnl)
	root := rnl.root
	if err = t.flushItems(root); err != nil {
		return err
	}
	if err = t.store.flushNodes(root); err != nil {
		return err
	}
	return nil
}

// Assumes that the caller serializes invocations w.r.t. mutations.
func (t *Collection) Stats() CollectionStats {
	return t.stats
}

func (t *Collection) flushItems(nloc *nodeLoc) (err error) {
	if nloc == nil || !nloc.Loc().isEmpty() {
		return nil // Flush only unpersisted items of non-empty, unpersisted nodes.
	}
	node := nloc.Node()
	if node == nil {
		return nil
	}
	if err = t.flushItems(&node.left); err != nil {
		return err
	}
	if err = node.item.write(t); err != nil { // Write items in key order.
		return err
	}
	return t.flushItems(&node.right)
}

func (t *Collection) rootCAS(prev, next *rootNodeLoc) bool {
	t.rootLock.Lock()
	defer t.rootLock.Unlock()

	if t.root != prev {
		return false
	}
	t.root = next
	return true
}

func (t *Collection) rootAddRef() *rootNodeLoc {
	t.rootLock.Lock()
	defer t.rootLock.Unlock()

	t.root.refs++
	return t.root
}

func (t *Collection) rootDecRef(r *rootNodeLoc) {
	t.rootLock.Lock()
	defer t.rootLock.Unlock()

	r.refs--
	if r.refs > 0 {
		return
	}
	if r.root.isEmpty() {
		return
	}
	t.reclaimNodes(r.root.Node())
	t.freeNodeLoc(r.root)
	t.freeRootNodeLoc(r)
}
<commit_msg>Smaller rootDecRef() lock area.<commit_after>package gkvlite

import (
	"encoding/json"
	"errors"
	"fmt"
	"math/rand"
	"sync"
	"sync/atomic"
	"unsafe"
)

// User-supplied key comparison func should return 0 if a == b,
// -1 if a < b, and +1 if a > b.  For example: bytes.Compare()
type KeyCompare func(a, b []byte) int

// A persistable collection of ordered key-values (Item's).
type Collection struct {
	name    string // May be "" for a private collection.
	store   *Store
	compare KeyCompare

	rootLock *sync.Mutex
	root     *rootNodeLoc // Protected by rootLock.

	stats CollectionStats

	freeLock         sync.Mutex
	freeNodes        *node        // Protected by freeLock.
	freeNodeLocs     *nodeLoc     // Not protected by freeLock.
	freeRootNodeLocs *rootNodeLoc // Protected by freeLock.
}

type CollectionStats struct {
	MkNodeLocs    int64
	FreeNodeLocs  int64
	AllocNodeLocs int64

	MkNodes    int64
	FreeNodes  int64
	AllocNodes int64
}

type rootNodeLoc struct {
	refs int64 // Atomic reference counter.
	root *nodeLoc
	next *rootNodeLoc // For free-list tracking.
}

func (t *Collection) Name() string {
	return t.name
}

// Retrieve an item by its key.  Use withValue of false if you don't
// need the item's value (Item.Val may be nil), which might be able
// to save on I/O and memory resources, especially for large values.
// The returned Item should be treated as immutable.
func (t *Collection) GetItem(key []byte, withValue bool) (i *Item, err error) {
	rnl := t.rootAddRef()
	defer t.rootDecRef(rnl)
	n := rnl.root
	for {
		nNode, err := n.read(t.store)
		if err != nil || n.isEmpty() || nNode == nil {
			return nil, err
		}
		i := &nNode.item
		iItem, err := i.read(t, false)
		if err != nil {
			return nil, err
		}
		if iItem == nil || iItem.Key == nil {
			return nil, errors.New("missing item after item.read() in GetItem()")
		}
		c := t.compare(key, iItem.Key)
		if c < 0 {
			n = &nNode.left
		} else if c > 0 {
			n = &nNode.right
		} else {
			if withValue {
				iItem, err = i.read(t, withValue)
				if err != nil {
					return nil, err
				}
			}
			return iItem, nil
		}
	}
}

// Retrieve a value by its key.  Returns nil if the item is not in the
// collection.  The returned value should be treated as immutable.
func (t *Collection) Get(key []byte) (val []byte, err error) {
	i, err := t.GetItem(key, true)
	if err != nil {
		return nil, err
	}
	if i != nil {
		return i.Val, nil
	}
	return nil, nil
}

// Replace or insert an item of a given key.
// A random item Priority (e.g., rand.Int31()) will usually work well,
// but advanced users may consider using non-random item priorities
// at the risk of unbalancing the lookup tree.  The input Item instance
// should be considered immutable and owned by the Collection.
func (t *Collection) SetItem(item *Item) (err error) {
	if item.Key == nil || len(item.Key) > 0xffff || len(item.Key) == 0 ||
		item.Val == nil {
		return errors.New("Item.Key/Val missing or too long")
	}
	if item.Priority < 0 {
		return errors.New("Item.Priority must be non-negative")
	}
	rnl := t.rootAddRef()
	defer t.rootDecRef(rnl)
	root := rnl.root
	n := t.mkNode(nil, nil, nil, 1, uint64(len(item.Key))+uint64(item.NumValBytes(t)))
	n.item.item = unsafe.Pointer(item) // Avoid garbage via separate init.
	nloc := t.mkNodeLoc(n)
	r, err := t.store.union(t, root, nloc)
	if err != nil {
		return err
	}
	if !t.rootCAS(rnl, t.mkRootNodeLoc(r)) {
		return errors.New("concurrent mutation attempted")
	}
	t.rootDecRef(rnl)
	t.freeNodeLoc(nloc)
	t.reclaimNodes(n)
	return nil
}

// Replace or insert an item of a given key.
func (t *Collection) Set(key []byte, val []byte) error {
	return t.SetItem(&Item{Key: key, Val: val, Priority: rand.Int31()})
}

// Deletes an item of a given key.
func (t *Collection) Delete(key []byte) (wasDeleted bool, err error) {
	rnl := t.rootAddRef()
	defer t.rootDecRef(rnl)
	root := rnl.root
	i, err := t.GetItem(key, false)
	if err != nil || i == nil {
		return false, err
	}
	left, middle, right, err := t.store.split(t, root, key)
	if err != nil {
		return false, err
	}
	if middle.isEmpty() {
		return false, fmt.Errorf("concurrent delete, key: %v", key)
	}
	// TODO: Even though we markReclaimable() the middle node, there
	// might not be a pathway to it during reclaimation.
	t.markReclaimable(middle.Node())
	t.freeNodeLoc(middle)
	r, err := t.store.join(t, left, right)
	if err != nil {
		return false, err
	}
	if !t.rootCAS(rnl, t.mkRootNodeLoc(r)) {
		return false, errors.New("concurrent mutation attempted")
	}
	t.rootDecRef(rnl)
	t.reclaimNodes(left.Node())
	t.reclaimNodes(right.Node())
	t.freeNodeLoc(left)
	t.freeNodeLoc(right)
	return true, nil
}

// Retrieves the item with the "smallest" key.
// The returned item should be treated as immutable.
func (t *Collection) MinItem(withValue bool) (*Item, error) {
	return t.store.walk(t, withValue,
		func(n *node) (*nodeLoc, bool) { return &n.left, true })
}

// Retrieves the item with the "largest" key.
// The returned item should be treated as immutable.
func (t *Collection) MaxItem(withValue bool) (*Item, error) {
	return t.store.walk(t, withValue,
		func(n *node) (*nodeLoc, bool) { return &n.right, true })
}

// Evict some clean items found by randomly walking a tree branch.
func (t *Collection) EvictSomeItems() (numEvicted uint64) {
	t.store.walk(t, false, func(n *node) (*nodeLoc, bool) {
		if !n.item.Loc().isEmpty() {
			atomic.StorePointer(&n.item.item, unsafe.Pointer(nil))
			numEvicted++
		}
		next := &n.left
		if (rand.Int() & 0x01) == 0x01 {
			next = &n.right
		}
		if next.isEmpty() {
			return nil, false
		}
		return next, true
	})
	return numEvicted
}

type ItemVisitor func(i *Item) bool
type ItemVisitorEx func(i *Item, depth uint64) bool

// Visit items greater-than-or-equal to the target key in ascending order.
func (t *Collection) VisitItemsAscend(target []byte, withValue bool, v ItemVisitor) error {
	return t.VisitItemsAscendEx(target, withValue,
		func(i *Item, depth uint64) bool { return v(i) })
}

// Visit items less-than the target key in descending order.
func (t *Collection) VisitItemsDescend(target []byte, withValue bool, v ItemVisitor) error {
	return t.VisitItemsDescendEx(target, withValue,
		func(i *Item, depth uint64) bool { return v(i) })
}

// Visit items greater-than-or-equal to the target key in ascending order; with depth info.
func (t *Collection) VisitItemsAscendEx(target []byte, withValue bool,
	visitor ItemVisitorEx) error {
	rnl := t.rootAddRef()
	defer t.rootDecRef(rnl)
	_, err := t.store.visitNodes(t, rnl.root,
		target, withValue, visitor, 0, ascendChoice)
	return err
}

// Visit items less-than the target key in descending order; with depth info.
func (t *Collection) VisitItemsDescendEx(target []byte, withValue bool,
	visitor ItemVisitorEx) error {
	rnl := t.rootAddRef()
	defer t.rootDecRef(rnl)
	_, err := t.store.visitNodes(t, rnl.root,
		target, withValue, visitor, 0, descendChoice)
	return err
}

func ascendChoice(cmp int, n *node) (bool, *nodeLoc, *nodeLoc) {
	return cmp <= 0, &n.left, &n.right
}

func descendChoice(cmp int, n *node) (bool, *nodeLoc, *nodeLoc) {
	return cmp > 0, &n.right, &n.left
}

// Returns total number of items and total key bytes plus value bytes.
func (t *Collection) GetTotals() (numItems uint64, numBytes uint64, err error) {
	rnl := t.rootAddRef()
	defer t.rootDecRef(rnl)
	n := rnl.root
	nNode, err := n.read(t.store)
	if err != nil || n.isEmpty() || nNode == nil {
		return 0, 0, err
	}
	return nNode.numNodes, nNode.numBytes, nil
}

// Returns JSON representation of root node file location.
func (t *Collection) MarshalJSON() ([]byte, error) {
	rnl := t.rootAddRef()
	defer t.rootDecRef(rnl)
	loc := rnl.root.Loc()
	if loc.isEmpty() {
		return json.Marshal(ploc_empty)
	}
	return json.Marshal(loc)
}

// Unmarshals JSON representation of root node file location.
func (t *Collection) UnmarshalJSON(d []byte) error {
	p := ploc{}
	if err := json.Unmarshal(d, &p); err != nil {
		return err
	}
	if t.rootLock == nil {
		t.rootLock = &sync.Mutex{}
	}
	nloc := t.mkNodeLoc(nil)
	nloc.loc = unsafe.Pointer(&p)
	if !t.rootCAS(nil, t.mkRootNodeLoc(nloc)) {
		return errors.New("concurrent mutation during UnmarshalJSON().")
	}
	return nil
}

// Writes dirty items of a collection BUT (WARNING) does NOT write new
// root records.  Use Store.Flush() to write root records, which would
// make these writes visible to the next file re-opening/re-loading.
func (t *Collection) Write() (err error) {
	rnl := t.rootAddRef()
	defer t.rootDecRef(rnl)
	root := rnl.root
	if err = t.flushItems(root); err != nil {
		return err
	}
	if err = t.store.flushNodes(root); err != nil {
		return err
	}
	return nil
}

// Assumes that the caller serializes invocations w.r.t. mutations.
func (t *Collection) Stats() CollectionStats {
	return t.stats
}

func (t *Collection) flushItems(nloc *nodeLoc) (err error) {
	if nloc == nil || !nloc.Loc().isEmpty() {
		return nil // Flush only unpersisted items of non-empty, unpersisted nodes.
	}
	node := nloc.Node()
	if node == nil {
		return nil
	}
	if err = t.flushItems(&node.left); err != nil {
		return err
	}
	if err = node.item.write(t); err != nil { // Write items in key order.
		return err
	}
	return t.flushItems(&node.right)
}

func (t *Collection) rootCAS(prev, next *rootNodeLoc) bool {
	t.rootLock.Lock()
	defer t.rootLock.Unlock()

	if t.root != prev {
		return false
	}
	t.root = next
	return true
}

func (t *Collection) rootAddRef() *rootNodeLoc {
	t.rootLock.Lock()
	defer t.rootLock.Unlock()

	t.root.refs++
	return t.root
}

func (t *Collection) rootDecRef(r *rootNodeLoc) {
	t.rootLock.Lock()
	r.refs--
	if r.refs > 0 {
		t.rootLock.Unlock()
		return
	}
	t.rootLock.Unlock()

	if r.root.isEmpty() {
		return
	}
	t.reclaimNodes(r.root.Node())
	t.freeNodeLoc(r.root)
	t.freeRootNodeLoc(r)
}
<|endoftext|>


<commit_before>package tesls

import (
	"go/ast"
	"go/parser"
	"go/token"
	"os"
	"sort"
	"strings"

	"golang.org/x/tools/go/types"
)

// Test describes a single test found in the *_test.go file
type Test struct {
	Name string `json:"name"`
	File string `json:"file"`
	Pkg  string `json:"pkg"`
}

// Format returns Test struct as a string in the given format.
// It can be any string in which %P will turn into package name,
// %T into test name, and %F into file path in which test was found.
// Note that it is not required to use all three placeholders.
func (t *Test) Format(format string) string {
	return strings.NewReplacer("%P", t.Pkg, "%T", t.Name, "%F", t.File).Replace(format)
}

// String returns a string representation of the Test
// in the form of 'package.Test filename'
func (t *Test) String() string {
	return t.Format("%P.%T %F")
}

// TestSlice attaches the methods of sort.Interface to []Test.
// Sorting in increasing order comparing package+testname.
type TestSlice []Test

func (s TestSlice) Len() int           { return len(s) }
func (s TestSlice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s TestSlice) Less(i, j int) bool { return s[i].Pkg+s[i].Name < s[j].Pkg+s[j].Name }

// Sort is a convenience method.
func (s TestSlice) Sort() { sort.Sort(s) }

func filter(fi os.FileInfo) bool {
	return strings.HasSuffix(fi.Name(), "_test.go")
}

func isTest(fdecl *ast.FuncDecl) bool {
	return strings.HasPrefix(fdecl.Name.String(), "Test") &&
		fdecl.Type != nil &&
		fdecl.Type.Params != nil &&
		len(fdecl.Type.Params.List) == 1 &&
		types.ExprString(fdecl.Type.Params.List[0].Type) == "*testing.T"
}

// Tests function searches for test function declarations in the given directory.
func Tests(dir string) (tests TestSlice, err error) {
	fset := token.NewFileSet()
	pkgs, err := parser.ParseDir(fset, dir, filter, parser.Mode(0))
	if err != nil {
		return nil, err
	}
	for _, pkg := range pkgs {
		for filename, file := range pkg.Files {
			for _, decl := range file.Decls {
				fdecl, ok := decl.(*ast.FuncDecl)
				if ok && isTest(fdecl) {
					tests = append(tests, Test{
						Name: fdecl.Name.String(),
						File: filename,
						Pkg:  pkg.Name,
					})
				}
			}
		}
	}
	return tests, nil
}
<commit_msg>tesls: build tags should not be ignored<commit_after>package tesls

import (
	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
	"path/filepath"
	"sort"
	"strings"

	"golang.org/x/tools/go/types"
)

// Test describes a single test found in the *_test.go file
type Test struct {
	Name string `json:"name"`
	File string `json:"file"`
	Pkg  string `json:"pkg"`
}

// Format returns Test struct as a string in the given format.
// It can be any string in which %P will turn into package name,
// %T into test name, and %F into file path in which test was found.
// Note that it is not required to use all three placeholders.
func (t *Test) Format(format string) string {
	return strings.NewReplacer("%P", t.Pkg, "%T", t.Name, "%F", t.File).Replace(format)
}

// String returns a string representation of the Test
// in the form of 'package.Test filename'
func (t *Test) String() string {
	return t.Format("%P.%T %F")
}

// TestSlice attaches the methods of sort.Interface to []Test.
// Sorting in increasing order comparing package+testname.
type TestSlice []Test

func (s TestSlice) Len() int           { return len(s) }
func (s TestSlice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s TestSlice) Less(i, j int) bool { return s[i].Pkg+s[i].Name < s[j].Pkg+s[j].Name }

// Sort is a convenience method.
func (s TestSlice) Sort() { sort.Sort(s) }

func isTest(fdecl *ast.FuncDecl) bool {
	return strings.HasPrefix(fdecl.Name.String(), "Test") &&
		fdecl.Type != nil &&
		fdecl.Type.Params != nil &&
		len(fdecl.Type.Params.List) == 1 &&
		types.ExprString(fdecl.Type.Params.List[0].Type) == "*testing.T"
}

func isNoGoError(err error) bool {
	_, ok := err.(*build.NoGoError)
	return ok
}

// Tests function searches for test function declarations in the given directory.
func Tests(dir string) (tests TestSlice, err error) {
	pkg, err := build.ImportDir(dir, build.ImportMode(0))
	if err != nil && !isNoGoError(err) {
		return nil, err
	}
	fset := token.NewFileSet()
	for _, filename := range pkg.TestGoFiles {
		filename = filepath.Join(dir, filename)
		f, err := parser.ParseFile(fset, filename, nil, parser.Mode(0))
		if err != nil {
			return nil, err
		}
		for _, decl := range f.Decls {
			fdecl, ok := decl.(*ast.FuncDecl)
			if ok && isTest(fdecl) {
				tests = append(tests, Test{
					Name: fdecl.Name.String(),
					File: filename,
					Pkg:  pkg.Name,
				})
			}
		}
	}
	return tests, nil
}
<|endoftext|>


<commit_before><commit_msg>Instrument cloud.google.com/go/storage.Client methods<commit_after><|endoftext|>


<commit_before>// Package trace defines common-use Dapper-style tracing APIs for the Go programming language.
//
// Package trace provides a backend-agnostic APIs and various tracing providers
// can be used with the package by importing various implementations of the Client interface.
package trace

import (
	"context"
	"errors"
	"net/http"
	"time"
)

var client Client

// TODO(jbd): annotate with labels that can propagate, similar to OpenTracing baggage.

// TODO(jbd): should we support a span to have multiple parents?

// TODO(jbd): set error/state on finish.

// TODO(jbd): A big TODO, we probably don't want to set a global client.
func Configure(c Client) {
	client = c
}

// Span represents a work.
type Span struct {
	ID          []byte            // represents the global identifier of the span.
	Annotations map[string][]byte // annotations set on this span.
}

// Annotate allows you to attach data to a span. Key-value pairs are
// arbitary information you want to collect in the lifetime of a span.
func (s *Span) Annotate(key string, val []byte) {
	s.Annotations[key] = val
}

// Child creates a child span from s with the given name.
// Created child span needs to be finished by calling
// the finishing function.
func (s *Span) Child(name string, linked ...*Span) (*Span, FinishFunc) {
	child := &Span{
		ID:          client.NewSpan(s.ID),
		Annotations: make(map[string][]byte),
	}
	start := time.Now()
	fn := func() error {
		return client.Finish(child.ID, name, spanIDs(linked), child.Annotations, start, time.Now())
	}
	return child, fn
}

// ToHTTPReq injects the span information in the given request
// and returns the modified request.
//
// If the current client is not supporting HTTP propagation,
// an error is returned.
func (s *Span) ToHTTPReq(req *http.Request) (*http.Request, error) {
	hc, ok := client.(HTTPCarrier)
	if !ok {
		return req, errors.New("not supported")
	}
	err := hc.ToReq(req, s.ID)
	if err != nil {
		return nil, err
	}
	return req, nil
}

// FromHTTPReq creates a *Span from an incoming request.
//
// An error will be returned if the current tracing client is
// not supporting propagation via HTTP.
func FromHTTPReq(req *http.Request) (*Span, error) {
	hc, ok := client.(HTTPCarrier)
	if !ok {
		return nil, errors.New("not supported")
	}
	id, err := hc.FromReq(req)
	if err != nil {
		return nil, err
	}
	return &Span{ID: id}, nil
}

// HTTPCarrier represents a mechanism that can attach the tracing
// information into an HTTP request or extract it from one.
type HTTPCarrier interface {
	FromReq(req *http.Request) (id []byte, err error)
	ToReq(req *http.Request, id []byte) error
}

// Client represents a client communicates with a tracing backend.
// Tracing backends are supposed to implement the interface in order to
// provide Go support.
//
// A Client is an HTTPCarrier if it can propagate the tracing
// information via an HTTP request.
//
// If you are not a tracing provider, you will never have to interact with
// this interface directly.
type Client interface {
	NewSpan(parent []byte) (id []byte)
	Finish(id []byte, name string, linked [][]byte, annotations map[string][]byte, start, end time.Time) error
}

// NewSpan creates a new root-level span.
//
// The span must be finished when the job it represents it is finished.
func NewSpan(name string, linked ...*Span) (*Span, FinishFunc) {
	span := &Span{
		ID:          client.NewSpan(nil),
		Annotations: make(map[string][]byte),
	}
	start := time.Now()
	fn := func() error {
		return client.Finish(span.ID, name, spanIDs(linked), span.Annotations, start, time.Now())
	}
	return span, fn
}

// NewContext returns a context with the span in.
func NewContext(ctx context.Context, span *Span) context.Context {
	return context.WithValue(ctx, spanKey, span)
}

// FromContext returns a span from the given context.
func FromContext(ctx context.Context) *Span {
	return ctx.Value(spanKey).(*Span)
}

func spanIDs(spans []*Span) [][]byte {
	var links [][]byte
	for _, s := range spans {
		links = append(links, s.ID)
	}
	return links
}

// FinishFunc finalizes its span.
type FinishFunc func() error

type contextKey struct{}

var spanKey = contextKey{}
<commit_msg>noop when span is nil<commit_after>// Package trace defines common-use Dapper-style tracing APIs for the Go programming language.
//
// Package trace provides a backend-agnostic APIs and various tracing providers
// can be used with the package by importing various implementations of the Client interface.
package trace

import (
	"context"
	"errors"
	"net/http"
	"time"
)

var client Client

// TODO(jbd): annotate with labels that can propagate, similar to OpenTracing baggage.

// TODO(jbd): should we support a span to have multiple parents?

// TODO(jbd): set error/state on finish.

// TODO(jbd): Avoid things if client = nil.

// TODO(jbd): A big TODO, we probably don't want to set a global client.
func Configure(c Client) {
	client = c
}

// Span represents a work.
type Span struct {
	ID          []byte            // represents the global identifier of the span.
	Annotations map[string][]byte // annotations set on this span.
}

// Annotate allows you to attach data to a span. Key-value pairs are
// arbitary information you want to collect in the lifetime of a span.
func (s *Span) Annotate(key string, val []byte) {
	if s == nil {
		return
	}
	s.Annotations[key] = val
}

// Child creates a child span from s with the given name.
// Created child span needs to be finished by calling
// the finishing function.
func (s *Span) Child(name string, linked ...*Span) (*Span, FinishFunc) {
	if s == nil {
		return nil, noop
	}
	child := &Span{
		ID:          client.NewSpan(s.ID),
		Annotations: make(map[string][]byte),
	}
	start := time.Now()
	fn := func() error {
		return client.Finish(child.ID, name, spanIDs(linked), child.Annotations, start, time.Now())
	}
	return child, fn
}

// ToHTTPReq injects the span information in the given request
// and returns the modified request.
//
// If the current client is not supporting HTTP propagation,
// an error is returned.
func (s *Span) ToHTTPReq(req *http.Request) (*http.Request, error) {
	if s == nil {
		return req, nil
	}
	hc, ok := client.(HTTPCarrier)
	if !ok {
		return req, errors.New("not supported")
	}
	err := hc.ToReq(req, s.ID)
	if err != nil {
		return nil, err
	}
	return req, nil
}

// FromHTTPReq creates a *Span from an incoming request.
//
// An error will be returned if the current tracing client is
// not supporting propagation via HTTP.
func FromHTTPReq(req *http.Request) (*Span, error) {
	hc, ok := client.(HTTPCarrier)
	if !ok {
		return nil, errors.New("not supported")
	}
	id, err := hc.FromReq(req)
	if err != nil {
		return nil, err
	}
	return &Span{ID: id}, nil
}

// HTTPCarrier represents a mechanism that can attach the tracing
// information into an HTTP request or extract it from one.
type HTTPCarrier interface {
	FromReq(req *http.Request) (id []byte, err error)
	ToReq(req *http.Request, id []byte) error
}

// Client represents a client communicates with a tracing backend.
// Tracing backends are supposed to implement the interface in order to
// provide Go support.
//
// A Client is an HTTPCarrier if it can propagate the tracing
// information via an HTTP request.
//
// If you are not a tracing provider, you will never have to interact with
// this interface directly.
type Client interface {
	NewSpan(parent []byte) (id []byte)
	Finish(id []byte, name string, linked [][]byte, annotations map[string][]byte, start, end time.Time) error
}

// NewSpan creates a new root-level span.
//
// The span must be finished when the job it represents it is finished.
func NewSpan(name string, linked ...*Span) (*Span, FinishFunc) {
	span := &Span{
		ID:          client.NewSpan(nil),
		Annotations: make(map[string][]byte),
	}
	start := time.Now()
	fn := func() error {
		return client.Finish(span.ID, name, spanIDs(linked), span.Annotations, start, time.Now())
	}
	return span, fn
}

// NewContext returns a context with the span in.
func NewContext(ctx context.Context, span *Span) context.Context {
	return context.WithValue(ctx, spanKey, span)
}

// FromContext returns a span from the given context.
func FromContext(ctx context.Context) *Span {
	return ctx.Value(spanKey).(*Span)
}

func spanIDs(spans []*Span) [][]byte {
	var links [][]byte
	for _, s := range spans {
		links = append(links, s.ID)
	}
	return links
}

// FinishFunc finalizes its span.
type FinishFunc func() error

type contextKey struct{}

var spanKey = contextKey{}

func noop() error { return nil }
<|endoftext|>


<commit_before>package ts

import (
	"flag"
	"fmt"
	// "io/ioutil"
	"log"
	"os"
	"regifted/data"
)

const TS_PACKET_SIZE = 188
const PACKET_TYPE_ERROR = 0
const PACKET_TYPE_PAT = 2
const PACKET_TYPE_PCR = 3
const PACKET_TYPE_PES = 4
const PACKET_TYPE_ES = 1
const PACKET_TYPE_PMT = 5
const PACKET_TYPE_PROGRAM = 6
const PACKET_TYPE_TS = 7

type TSState struct {
	globals_initialized bool
	// the keys in these maps are pids
	pesCollector           map[uint]Pes
	pmtConstructors        map[uint]Pmt
	entryConstructors      map[uint]PmtEntry
	elementaryConstructors map[uint]ElementaryStreamPacket
	types                  map[uint]uint
	pat                    Pat

	bytes []byte
	reader *data.Reader
	pcr uint

	// pes.streamtype -> pes[]
	pesMap map[uint][]Pes
}

// this is still global state - it's a temporary step in-between
var state TSState

func Load(bytes []byte) *TSState {
	fmt.Println( "load()" )
	var state2 *TSState
	state2 = &TSState{}
	state2.bytes = bytes
	state2.reader = data.NewReader(bytes)
	state2.main()
	state = *state2
	return state2
}

func (state *TSState) main() {
	reader := state.reader
	bytes := state.bytes

	rc := Init()
	if rc != true {
		log.Printf("could not initialize global state\n")
		os.Exit(71)
	}
	fmt.Println("Size: ", len(bytes))
	s := uint64(len(bytes))

	for reader.Cursor < s {
		var pesData *Pes
		byteChunk := reader.ReadBytes(TS_PACKET_SIZE)
		tsPacket := TsPacket{}
		tsPacket.byteChunk = byteChunk
		packetType, packetReader := tsPacket.Read()

		switch {
		case packetType == PACKET_TYPE_PAT:
			readPat(&tsPacket, packetReader)

		case packetType == PACKET_TYPE_PMT:
			readPMT(&tsPacket, packetReader)

		case packetType == PACKET_TYPE_ES:
			pesData = readES(&tsPacket, packetReader)

			if pesData != nil{
				if state.pesMap[pesData.streamType] != nil{
					state.pesMap[pesData.streamType] = make([]Pes, 1, 1)

				}

				state.pesMap[pesData.streamType] = append(state.pesMap[pesData.streamType], *pesData)

			}
		}

		if tsPacket.hasAdaptation && tsPacket.adaptation.hasPCR {
			state.pcr = tsPacket.adaptation.pcr.pcr
		}
	}

	for key := range state.pesCollector {
		state.CreateAndDispensePes(key, state.types[key])
	}

}

//CreateAndDispensePes
//Dump the remaining PES
func (state *TSState) CreateAndDispensePes(pid uint, streamType uint) {
	pes := state.pesCollector[pid]
	pes.pid = pid
	pes.streamType = streamType
	pes.Read()
	pes.Print()
}

func readPat(tsPacket *TsPacket, reader *data.Reader) {
	state.pat.byteChunk = reader.ReadBytes(reader.Size - reader.Cursor)
	state.pat.unitStart = tsPacket.unitStart
	state.pat.Read()
}

func readPMT(tsPacket *TsPacket, reader *data.Reader) {
	pmt, _ := state.pmtConstructors[tsPacket.pid]
	pmt.unitStart = tsPacket.unitStart
	pmt.byteChunk = reader.ReadBytes(reader.Size - reader.Cursor)
	pmt.Read()
}

func readES(tsPacket *TsPacket, reader *data.Reader) *Pes {
	var pesData *Pes
	elementaryStreamPacket, _ := state.elementaryConstructors[tsPacket.pid]
	elementaryStreamPacket.pid = tsPacket.pid
	elementaryStreamPacket.unitStart = tsPacket.unitStart

	if tsPacket.hasAdaptation {
		elementaryStreamPacket.payload = tsPacket.adaptation.payload
	} else {
		elementaryStreamPacket.payload = reader.ReadBytes(reader.Size - reader.Cursor)
	}

	pesData = elementaryStreamPacket.Dispatch()
	elementaryStreamPacket.Print()
	return pesData
}

// todo( mathew guest ) I think golang wants to use error as return codes but
// it's a little slow so I'm cheating
func getFilepath() (string, int) {
	flag.Parse()
	argc := flag.NArg()
	if argc < 1 {
		log.Printf("Usage: " + os.Args[0] + " [input ts file]\n")
		return "", 66
	}
	if argc > 1 {
		log.Printf("Ignoring all but first argument.\n")
		os.Exit(1)
	}
	fileName := os.Args[1]
	return fileName, 0
}

//Init
//Initialize the constructors
func Init() bool {
	if state.globals_initialized == true {
		log.Printf("EE attempted to initialize globals twice\n")
		return false
	}
	state.pmtConstructors = make(map[uint]Pmt)
	state.entryConstructors = make(map[uint]PmtEntry)
	state.types = make(map[uint]uint)
	state.pesCollector = make(map[uint]Pes)
	state.elementaryConstructors = make(map[uint]ElementaryStreamPacket)
	state.pat = Pat{}
	state.pat.tableId = 0
	state.globals_initialized = true
	return true
}

func DeleteState() {
	if state.globals_initialized == false {
		return
	}
	state.globals_initialized = false
	Init()
	state.globals_initialized = false
}

func ReadHeaderData(bytes []byte) uint {
	reader := data.NewReader(bytes)
	var a uint = (reader.Read(1) >> 1) & 0x07
	var b uint = reader.Read(1)
	var c uint = (reader.Read(1) >> 1) & 0x7f
	var d uint = reader.Read(1)
	var e uint = (reader.Read(1) >> 1) & 0x7f
	var timestamp uint = (a << 30) | (b << 22) | (c << 15) | (d << 7) | e
	return timestamp
}
<commit_msg>added missing constructor for pes buff map<commit_after>package ts

import (
	"flag"
	"fmt"
	// "io/ioutil"
	"log"
	"os"
	"regifted/data"
)

const TS_PACKET_SIZE = 188
const PACKET_TYPE_ERROR = 0
const PACKET_TYPE_PAT = 2
const PACKET_TYPE_PCR = 3
const PACKET_TYPE_PES = 4
const PACKET_TYPE_ES = 1
const PACKET_TYPE_PMT = 5
const PACKET_TYPE_PROGRAM = 6
const PACKET_TYPE_TS = 7

type TSState struct {
	globals_initialized bool
	// the keys in these maps are pids
	pesCollector           map[uint]Pes
	pmtConstructors        map[uint]Pmt
	entryConstructors      map[uint]PmtEntry
	elementaryConstructors map[uint]ElementaryStreamPacket
	types                  map[uint]uint
	pat                    Pat

	bytes []byte
	reader *data.Reader
	pcr uint

	// pes.streamtype -> pes[]
	pesMap map[uint][]Pes
}

// this is still global state - it's a temporary step in-between
var state TSState

func Load(bytes []byte) *TSState {
	fmt.Println( "load()" )

	state = TSState{}
	var state2 *TSState
	state2 = &state
	state2.bytes = bytes
	state2.reader = data.NewReader(bytes)
	state2.main()
	return state2
}

func (state *TSState) main() {
	reader := state.reader
	bytes := state.bytes

	rc := Init()
	if rc != true {
		log.Printf("could not initialize global state\n")
		os.Exit(71)
	}
	fmt.Println("Size: ", len(bytes))
	s := uint64(len(bytes))

	for reader.Cursor < s {
		var pesData *Pes
		byteChunk := reader.ReadBytes(TS_PACKET_SIZE)
		tsPacket := TsPacket{}
		tsPacket.byteChunk = byteChunk
		packetType, packetReader := tsPacket.Read()

		switch {
		case packetType == PACKET_TYPE_PAT:
			readPat(&tsPacket, packetReader)

		case packetType == PACKET_TYPE_PMT:
			readPMT(&tsPacket, packetReader)

		case packetType == PACKET_TYPE_ES:
			pesData = readES(&tsPacket, packetReader)

			if pesData != nil{
				if state.pesMap[pesData.streamType] != nil{
					state.pesMap[pesData.streamType] = make([]Pes, 1, 1)

				}

				state.pesMap[pesData.streamType] = append(state.pesMap[pesData.streamType], *pesData)

			}
		}

		if tsPacket.hasAdaptation && tsPacket.adaptation.hasPCR {
			state.pcr = tsPacket.adaptation.pcr.pcr
		}
	}

	for key := range state.pesCollector {
		state.CreateAndDispensePes(key, state.types[key])
	}

}

//CreateAndDispensePes
//Dump the remaining PES
func (state *TSState) CreateAndDispensePes(pid uint, streamType uint) {
	pes := state.pesCollector[pid]
	pes.pid = pid
	pes.streamType = streamType
	pes.Read()
	pes.Print()
}

func readPat(tsPacket *TsPacket, reader *data.Reader) {
	state.pat.byteChunk = reader.ReadBytes(reader.Size - reader.Cursor)
	state.pat.unitStart = tsPacket.unitStart
	state.pat.Read()
}

func readPMT(tsPacket *TsPacket, reader *data.Reader) {
	pmt, _ := state.pmtConstructors[tsPacket.pid]
	pmt.unitStart = tsPacket.unitStart
	pmt.byteChunk = reader.ReadBytes(reader.Size - reader.Cursor)
	pmt.Read()
}

func readES(tsPacket *TsPacket, reader *data.Reader) *Pes {
	var pesData *Pes
	elementaryStreamPacket, _ := state.elementaryConstructors[tsPacket.pid]
	elementaryStreamPacket.pid = tsPacket.pid
	elementaryStreamPacket.unitStart = tsPacket.unitStart

	if tsPacket.hasAdaptation {
		elementaryStreamPacket.payload = tsPacket.adaptation.payload
	} else {
		elementaryStreamPacket.payload = reader.ReadBytes(reader.Size - reader.Cursor)
	}

	pesData = elementaryStreamPacket.Dispatch()
	elementaryStreamPacket.Print()
	return pesData
}

// todo( mathew guest ) I think golang wants to use error as return codes but
// it's a little slow so I'm cheating
func getFilepath() (string, int) {
	flag.Parse()
	argc := flag.NArg()
	if argc < 1 {
		log.Printf("Usage: " + os.Args[0] + " [input ts file]\n")
		return "", 66
	}
	if argc > 1 {
		log.Printf("Ignoring all but first argument.\n")
		os.Exit(1)
	}
	fileName := os.Args[1]
	return fileName, 0
}

//Init
//Initialize the constructors
func Init() bool {
	if state.globals_initialized == true {
		log.Printf("EE attempted to initialize globals twice\n")
		return false
	}
	state.pmtConstructors = make(map[uint]Pmt)
	state.entryConstructors = make(map[uint]PmtEntry)
	state.types = make(map[uint]uint)
	state.pesCollector = make(map[uint]Pes)
	state.elementaryConstructors = make(map[uint]ElementaryStreamPacket)
	state.pat = Pat{}
	state.pat.tableId = 0
	state.pesMap = make(map[uint][]Pes)
	state.globals_initialized = true
	return true
}

func DeleteState() {
	if state.globals_initialized == false {
		return
	}
	state.globals_initialized = false
	Init()
	state.globals_initialized = false
}

func ReadHeaderData(bytes []byte) uint {
	reader := data.NewReader(bytes)
	var a uint = (reader.Read(1) >> 1) & 0x07
	var b uint = reader.Read(1)
	var c uint = (reader.Read(1) >> 1) & 0x7f
	var d uint = reader.Read(1)
	var e uint = (reader.Read(1) >> 1) & 0x7f
	var timestamp uint = (a << 30) | (b << 22) | (c << 15) | (d << 7) | e
	return timestamp
}
<|endoftext|>


<commit_before>package common

import (
	"github.com/Sirupsen/logrus"
	"golang.org/x/net/context"
)

// WithLogger stores the logger.
func WithLogger(ctx context.Context, l logrus.FieldLogger) context.Context {
	return context.WithValue(ctx, "logger", l)
}

// Logger returns the structured logger.
func Logger(ctx context.Context) logrus.FieldLogger {
	l, ok := ctx.Value("logger").(logrus.FieldLogger)
	if !ok {
		return logrus.StandardLogger()
	}
	return l
}
<commit_msg>Fixed tests, added context to more methods and added some better logger/context handling.<commit_after>package common

import (
	"github.com/Sirupsen/logrus"
	"golang.org/x/net/context"
)

// WithLogger stores the logger.
func WithLogger(ctx context.Context, l logrus.FieldLogger) context.Context {
	return context.WithValue(ctx, "logger", l)
}

// Logger returns the structured logger.
func Logger(ctx context.Context) logrus.FieldLogger {
	l, ok := ctx.Value("logger").(logrus.FieldLogger)
	if !ok {
		return logrus.StandardLogger()
	}
	return l
}

// Attempt at simplifying this whole logger in the context thing
// Could even make this take a generic map, then the logger that gets returned could be used just like the stdlib too, since it's compatible
func LoggerWithFields(ctx context.Context, fields logrus.Fields) (context.Context, logrus.FieldLogger) {
	l := Logger(ctx)
	l = l.WithFields(fields)
	ctx = WithLogger(ctx, l)
	return ctx, l
}
<|endoftext|>


<commit_before>package cachet

import (
	"fmt"
)

const (
	// Docs: https://docs.cachethq.io/docs/component-statuses

	// ComponentStatusOperational means "The component is working."
	ComponentStatusOperational = 1
	// ComponentStatusPerformanceIssues means "The component is experiencing some slowness."
	ComponentStatusPerformanceIssues = 2
	// ComponentStatusPartialOutage means "The component may not be working for everybody."
	// This could be a geographical issue for example.
	ComponentStatusPartialOutage = 3
	// ComponentStatusMajorOutage means "The component is not working for anybody."
	ComponentStatusMajorOutage = 4
)

// ComponentsService contains REST endpoints that belongs to cachet components.
type ComponentsService struct {
	client *Client
}

// Component entity reflects one single component
type Component struct {
	ID          int    `json:"id,omitempty"`
	Name        string `json:"name,omitempty"`
	Description string `json:"description,omitempty"`
	Link        string `json:"link,omitempty"`
	Status      int    `json:"status,omitempty"`
	Order       int    `json:"order,omitempty"`
	GroupID     int    `json:"group_id,omitempty"`
	CreatedAt   string `json:"created_at,omitempty"`
	UpdatedAt   string `json:"updated_at,omitempty"`
	DeletedAt   string `json:"deleted_at,omitempty"`
	StatusName  string `json:"status_name,omitempty"`
}

// ComponentGroup entity reflects one single component group
type ComponentGroup struct {
	ID        int    `json:"id,omitempty"`
	Name      string `json:"name,omitempty"`
	Order     int    `json:"order,omitempty"`
	CreatedAt string `json:"created_at,omitempty"`
	UpdatedAt string `json:"updated_at,omitempty"`
}

// ComponentResponse reflects the response of /components call
type ComponentResponse struct {
	Meta       Meta        `json:"meta,omitempty"`
	Components []Component `json:"data,omitempty"`
}

// ComponentGroupResponse reflects the response of /components/groups call
type ComponentGroupResponse struct {
	Meta            Meta             `json:"meta,omitempty"`
	ComponentGroups []ComponentGroup `json:"data,omitempty"`
}

// componentApiResponse is an internal type to hide
// some the "data" nested level from the API.
// Some calls (e.g. Get or Create) return the component in the "data" key.
type componentAPIResponse struct {
	Data *Component `json:"data"`
}

// componentGroupAPIResponse is an internal type to hide
// some the "data" nested level from the API.
// Some calls (e.g. Get or Create) return the component group in the "data" key.
type componentGroupAPIResponse struct {
	Data *ComponentGroup `json:"data"`
}

// GetAll return all components that have been created.
//
// Docs: https://docs.cachethq.io/docs/get-components
func (s *ComponentsService) GetAll() (*ComponentResponse, *Response, error) {
	u := "api/v1/components"
	v := new(ComponentResponse)

	resp, err := s.client.Call("GET", u, nil, v)
	return v, resp, err
}

// Get return a single component.
//
// Docs: https://docs.cachethq.io/docs/get-a-component
func (s *ComponentsService) Get(id int) (*Component, *Response, error) {
	u := fmt.Sprintf("api/v1/components/%d", id)
	v := new(componentAPIResponse)

	resp, err := s.client.Call("GET", u, nil, v)
	return v.Data, resp, err
}

// Create a new component.
//
// Docs: https://docs.cachethq.io/docs/components
func (s *ComponentsService) Create(c *Component) (*Component, *Response, error) {
	u := "api/v1/components"
	v := new(componentAPIResponse)

	resp, err := s.client.Call("POST", u, c, v)
	return v.Data, resp, err
}

// Update updates a component.
//
// Docs: https://docs.cachethq.io/docs/update-a-component
func (s *ComponentsService) Update(id int, c *Component) (*Component, *Response, error) {
	u := fmt.Sprintf("api/v1/components/%d", id)
	v := new(componentAPIResponse)

	resp, err := s.client.Call("PUT", u, c, v)
	return v.Data, resp, err
}

// Delete deletes a component.
//
// Docs: https://docs.cachethq.io/docs/delete-a-component
func (s *ComponentsService) Delete(id int) (*Response, error) {
	u := fmt.Sprintf("api/v1/components/%d", id)

	resp, err := s.client.Call("DELETE", u, nil, nil)
	return resp, err
}

// GetAllGroups return all component groups that have been created.
//
// Docs: https://docs.cachethq.io/docs/get-componentgroups
func (s *ComponentsService) GetAllGroups() (*ComponentGroupResponse, *Response, error) {
	u := "api/v1/components/groups"
	v := new(ComponentGroupResponse)

	resp, err := s.client.Call("GET", u, nil, v)
	return v, resp, err
}

// GetGroup return a single component group.
//
// Docs: https://docs.cachethq.io/docs/get-a-component-group
func (s *ComponentsService) GetGroup(id int) (*ComponentGroup, *Response, error) {
	u := fmt.Sprintf("api/v1/components/groups/%d", id)
	v := new(componentGroupAPIResponse)

	resp, err := s.client.Call("GET", u, nil, v)
	return v.Data, resp, err
}

// CreateGroup creates a new component group.
//
// Docs: https://docs.cachethq.io/docs/post-componentgroups
func (s *ComponentsService) CreateGroup(c *ComponentGroup) (*ComponentGroup, *Response, error) {
	u := "api/v1/components/groups"
	v := new(componentGroupAPIResponse)

	resp, err := s.client.Call("POST", u, c, v)
	return v.Data, resp, err
}

// UpdateGroup updates a component group.
//
// Docs: https://docs.cachethq.io/docs/put-component-group
func (s *ComponentsService) UpdateGroup(id int, c *ComponentGroup) (*ComponentGroup, *Response, error) {
	u := fmt.Sprintf("api/v1/components/groups/%d", id)
	v := new(componentGroupAPIResponse)

	resp, err := s.client.Call("PUT", u, c, v)
	return v.Data, resp, err
}

// DeleteGroup deletes a component group.
//
// Docs: https://docs.cachethq.io/docs/delete-component-group
func (s *ComponentsService) DeleteGroup(id int) (*Response, error) {
	u := fmt.Sprintf("api/v1/components/groups/%d", id)

	resp, err := s.client.Call("DELETE", u, nil, nil)
	return resp, err
}
<commit_msg>Added Component.Enabled field<commit_after>package cachet

import (
	"fmt"
)

const (
	// Docs: https://docs.cachethq.io/docs/component-statuses

	// ComponentStatusOperational means "The component is working."
	ComponentStatusOperational = 1
	// ComponentStatusPerformanceIssues means "The component is experiencing some slowness."
	ComponentStatusPerformanceIssues = 2
	// ComponentStatusPartialOutage means "The component may not be working for everybody."
	// This could be a geographical issue for example.
	ComponentStatusPartialOutage = 3
	// ComponentStatusMajorOutage means "The component is not working for anybody."
	ComponentStatusMajorOutage = 4
)

// ComponentsService contains REST endpoints that belongs to cachet components.
type ComponentsService struct {
	client *Client
}

// Component entity reflects one single component
type Component struct {
	ID          int    `json:"id,omitempty"`
	Name        string `json:"name,omitempty"`
	Description string `json:"description,omitempty"`
	Link        string `json:"link,omitempty"`
	Status      int    `json:"status,omitempty"`
	Order       int    `json:"order,omitempty"`
	Enabled     bool   `json:"enabled,omitempty"`
	GroupID     int    `json:"group_id,omitempty"`
	CreatedAt   string `json:"created_at,omitempty"`
	UpdatedAt   string `json:"updated_at,omitempty"`
	DeletedAt   string `json:"deleted_at,omitempty"`
	StatusName  string `json:"status_name,omitempty"`
}

// ComponentGroup entity reflects one single component group
type ComponentGroup struct {
	ID        int    `json:"id,omitempty"`
	Name      string `json:"name,omitempty"`
	Order     int    `json:"order,omitempty"`
	CreatedAt string `json:"created_at,omitempty"`
	UpdatedAt string `json:"updated_at,omitempty"`
}

// ComponentResponse reflects the response of /components call
type ComponentResponse struct {
	Meta       Meta        `json:"meta,omitempty"`
	Components []Component `json:"data,omitempty"`
}

// ComponentGroupResponse reflects the response of /components/groups call
type ComponentGroupResponse struct {
	Meta            Meta             `json:"meta,omitempty"`
	ComponentGroups []ComponentGroup `json:"data,omitempty"`
}

// componentApiResponse is an internal type to hide
// some the "data" nested level from the API.
// Some calls (e.g. Get or Create) return the component in the "data" key.
type componentAPIResponse struct {
	Data *Component `json:"data"`
}

// componentGroupAPIResponse is an internal type to hide
// some the "data" nested level from the API.
// Some calls (e.g. Get or Create) return the component group in the "data" key.
type componentGroupAPIResponse struct {
	Data *ComponentGroup `json:"data"`
}

// GetAll return all components that have been created.
//
// Docs: https://docs.cachethq.io/docs/get-components
func (s *ComponentsService) GetAll() (*ComponentResponse, *Response, error) {
	u := "api/v1/components"
	v := new(ComponentResponse)

	resp, err := s.client.Call("GET", u, nil, v)
	return v, resp, err
}

// Get return a single component.
//
// Docs: https://docs.cachethq.io/docs/get-a-component
func (s *ComponentsService) Get(id int) (*Component, *Response, error) {
	u := fmt.Sprintf("api/v1/components/%d", id)
	v := new(componentAPIResponse)

	resp, err := s.client.Call("GET", u, nil, v)
	return v.Data, resp, err
}

// Create a new component.
//
// Docs: https://docs.cachethq.io/docs/components
func (s *ComponentsService) Create(c *Component) (*Component, *Response, error) {
	u := "api/v1/components"
	v := new(componentAPIResponse)

	resp, err := s.client.Call("POST", u, c, v)
	return v.Data, resp, err
}

// Update updates a component.
//
// Docs: https://docs.cachethq.io/docs/update-a-component
func (s *ComponentsService) Update(id int, c *Component) (*Component, *Response, error) {
	u := fmt.Sprintf("api/v1/components/%d", id)
	v := new(componentAPIResponse)

	resp, err := s.client.Call("PUT", u, c, v)
	return v.Data, resp, err
}

// Delete deletes a component.
//
// Docs: https://docs.cachethq.io/docs/delete-a-component
func (s *ComponentsService) Delete(id int) (*Response, error) {
	u := fmt.Sprintf("api/v1/components/%d", id)

	resp, err := s.client.Call("DELETE", u, nil, nil)
	return resp, err
}

// GetAllGroups return all component groups that have been created.
//
// Docs: https://docs.cachethq.io/docs/get-componentgroups
func (s *ComponentsService) GetAllGroups() (*ComponentGroupResponse, *Response, error) {
	u := "api/v1/components/groups"
	v := new(ComponentGroupResponse)

	resp, err := s.client.Call("GET", u, nil, v)
	return v, resp, err
}

// GetGroup return a single component group.
//
// Docs: https://docs.cachethq.io/docs/get-a-component-group
func (s *ComponentsService) GetGroup(id int) (*ComponentGroup, *Response, error) {
	u := fmt.Sprintf("api/v1/components/groups/%d", id)
	v := new(componentGroupAPIResponse)

	resp, err := s.client.Call("GET", u, nil, v)
	return v.Data, resp, err
}

// CreateGroup creates a new component group.
//
// Docs: https://docs.cachethq.io/docs/post-componentgroups
func (s *ComponentsService) CreateGroup(c *ComponentGroup) (*ComponentGroup, *Response, error) {
	u := "api/v1/components/groups"
	v := new(componentGroupAPIResponse)

	resp, err := s.client.Call("POST", u, c, v)
	return v.Data, resp, err
}

// UpdateGroup updates a component group.
//
// Docs: https://docs.cachethq.io/docs/put-component-group
func (s *ComponentsService) UpdateGroup(id int, c *ComponentGroup) (*ComponentGroup, *Response, error) {
	u := fmt.Sprintf("api/v1/components/groups/%d", id)
	v := new(componentGroupAPIResponse)

	resp, err := s.client.Call("PUT", u, c, v)
	return v.Data, resp, err
}

// DeleteGroup deletes a component group.
//
// Docs: https://docs.cachethq.io/docs/delete-component-group
func (s *ComponentsService) DeleteGroup(id int) (*Response, error) {
	u := fmt.Sprintf("api/v1/components/groups/%d", id)

	resp, err := s.client.Call("DELETE", u, nil, nil)
	return resp, err
}
<|endoftext|>


<commit_before>// The googlecompute package contains a packer.Builder implementation that
// builds images for Google Compute Engine.
package googlecompute

import (
	"errors"
	"fmt"
	"log"
	"time"

	"github.com/mitchellh/multistep"
	"github.com/mitchellh/packer/common"
	"github.com/mitchellh/packer/packer"
)

// The unique ID for this builder.
const BuilderId = "kelseyhightower.googlecompute"

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

// config holds the googlecompute builder configuration settings.
type config struct {
	BucketName          string            `mapstructure:"bucket_name"`
	ClientSecretsFile   string            `mapstructure:"client_secrets_file"`
	ImageName           string            `mapstructure:"image_name"`
	ImageDescription    string            `mapstructure:"image_description"`
	MachineType         string            `mapstructure:"machine_type"`
	Metadata            map[string]string `mapstructure:"metadata"`
	Network             string            `mapstructure:"network"`
	Passphrase          string            `mapstructure:"passphrase"`
	PrivateKeyFile      string            `mapstructure:"private_key_file"`
	ProjectId           string            `mapstructure:"project_id"`
	SourceImage         string            `mapstructure:"source_image"`
	SSHUsername         string            `mapstructure:"ssh_username"`
	SSHPort             uint              `mapstructure:"ssh_port"`
	RawSSHTimeout       string            `mapstructure:"ssh_timeout"`
	RawStateTimeout     string            `mapstructure:"state_timeout"`
	Tags                []string          `mapstructure:"tags"`
	Zone                string            `mapstructure:"zone"`
	clientSecrets       *clientSecrets
	common.PackerConfig `mapstructure:",squash"`
	instanceName        string
	privateKeyBytes     []byte
	sshTimeout          time.Duration
	stateTimeout        time.Duration
	tpl                 *packer.ConfigTemplate
}

// Prepare processes the build configuration parameters.
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
	// Load the packer config.
	md, err := common.DecodeConfig(&b.config, raws...)
	if err != nil {
		return nil, err
	}
	b.config.tpl, err = packer.NewConfigTemplate()
	if err != nil {
		return nil, err
	}
	b.config.tpl.UserVars = b.config.PackerUserVars

	errs := common.CheckUnusedConfig(md)
	// Collect errors if any.
	if err := common.CheckUnusedConfig(md); err != nil {
		return nil, err
	}
	// Set defaults.
	if b.config.Network == "" {
		b.config.Network = "default"
	}
	if b.config.ImageDescription == "" {
		b.config.ImageDescription = "Created by Packer"
	}
	if b.config.ImageName == "" {
		// Default to packer-{{ unix timestamp (utc) }}
		b.config.ImageName = "packer-{{timestamp}}"
	}
	if b.config.MachineType == "" {
		b.config.MachineType = "n1-standard-1"
	}
	if b.config.RawSSHTimeout == "" {
		b.config.RawSSHTimeout = "5m"
	}
	if b.config.RawStateTimeout == "" {
		b.config.RawStateTimeout = "5m"
	}
	if b.config.SSHUsername == "" {
		b.config.SSHUsername = "root"
	}
	if b.config.SSHPort == 0 {
		b.config.SSHPort = 22
	}
	// Process Templates
	templates := map[string]*string{
		"bucket_name":         &b.config.BucketName,
		"client_secrets_file": &b.config.ClientSecretsFile,
		"image_name":          &b.config.ImageName,
		"image_description":   &b.config.ImageDescription,
		"machine_type":        &b.config.MachineType,
		"network":             &b.config.Network,
		"passphrase":          &b.config.Passphrase,
		"private_key_file":    &b.config.PrivateKeyFile,
		"project_id":          &b.config.ProjectId,
		"source_image":        &b.config.SourceImage,
		"ssh_username":        &b.config.SSHUsername,
		"ssh_timeout":         &b.config.RawSSHTimeout,
		"state_timeout":       &b.config.RawStateTimeout,
		"zone":                &b.config.Zone,
	}
	for n, ptr := range templates {
		var err error
		*ptr, err = b.config.tpl.Process(*ptr, nil)
		if err != nil {
			errs = packer.MultiErrorAppend(
				errs, fmt.Errorf("Error processing %s: %s", n, err))
		}
	}
	// Process required parameters.
	if b.config.BucketName == "" {
		errs = packer.MultiErrorAppend(
			errs, errors.New("a bucket_name must be specified"))
	}
	if b.config.ClientSecretsFile == "" {
		errs = packer.MultiErrorAppend(
			errs, errors.New("a client_secrets_file must be specified"))
	}
	if b.config.PrivateKeyFile == "" {
		errs = packer.MultiErrorAppend(
			errs, errors.New("a private_key_file must be specified"))
	}
	if b.config.ProjectId == "" {
		errs = packer.MultiErrorAppend(
			errs, errors.New("a project_id must be specified"))
	}
	if b.config.SourceImage == "" {
		errs = packer.MultiErrorAppend(
			errs, errors.New("a source_image must be specified"))
	}
	if b.config.Zone == "" {
		errs = packer.MultiErrorAppend(
			errs, errors.New("a zone must be specified"))
	}
	// Process timeout settings.
	sshTimeout, err := time.ParseDuration(b.config.RawSSHTimeout)
	if err != nil {
		errs = packer.MultiErrorAppend(
			errs, fmt.Errorf("Failed parsing ssh_timeout: %s", err))
	}
	b.config.sshTimeout = sshTimeout
	stateTimeout, err := time.ParseDuration(b.config.RawStateTimeout)
	if err != nil {
		errs = packer.MultiErrorAppend(
			errs, fmt.Errorf("Failed parsing state_timeout: %s", err))
	}
	b.config.stateTimeout = stateTimeout
	// Load the client secrets file.
	cs, err := loadClientSecrets(b.config.ClientSecretsFile)
	if err != nil {
		errs = packer.MultiErrorAppend(
			errs, fmt.Errorf("Failed parsing client secrets file: %s", err))
	}
	b.config.clientSecrets = cs
	// Load the private key.
	b.config.privateKeyBytes, err = processPrivateKeyFile(b.config.PrivateKeyFile, b.config.Passphrase)
	if err != nil {
		errs = packer.MultiErrorAppend(
			errs, fmt.Errorf("Failed loading private key file: %s", err))
	}
	// Check for any errors.
	if errs != nil && len(errs.Errors) > 0 {
		return nil, errs
	}
	return nil, nil
}

// Run executes a googlecompute Packer build and returns a packer.Artifact
// representing a GCE machine image.
func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
	// Initialize the Google Compute Engine API.
	client, err := New(b.config.ProjectId, b.config.Zone, b.config.clientSecrets, b.config.privateKeyBytes)
	if err != nil {
		log.Println("Failed to create the Google Compute Engine client.")
		return nil, err
	}
	// Set up the state.
	state := new(multistep.BasicStateBag)
	state.Put("config", b.config)
	state.Put("client", client)
	state.Put("hook", hook)
	state.Put("ui", ui)
	// Build the steps.
	steps := []multistep.Step{
		new(stepCreateSSHKey),
		new(stepCreateInstance),
		new(stepInstanceInfo),
		&common.StepConnectSSH{
			SSHAddress:     sshAddress,
			SSHConfig:      sshConfig,
			SSHWaitTimeout: 5 * time.Minute,
		},
		new(common.StepProvision),
		new(stepUpdateGsutil),
		new(stepCreateImage),
		new(stepUploadImage),
		new(stepRegisterImage),
	}
	// Run the steps.
	if b.config.PackerDebug {
		b.runner = &multistep.DebugRunner{
			Steps:   steps,
			PauseFn: common.MultistepDebugFn(ui),
		}
	} else {
		b.runner = &multistep.BasicRunner{Steps: steps}
	}
	b.runner.Run(state)
	// Report any errors.
	if rawErr, ok := state.GetOk("error"); ok {
		return nil, rawErr.(error)
	}
	if _, ok := state.GetOk("image_name"); !ok {
		log.Println("Failed to find image_name in state. Bug?")
		return nil, nil
	}
	artifact := &Artifact{
		imageName: state.Get("image_name").(string),
		client:    client,
	}
	return artifact, nil
}

// Cancel.
func (b *Builder) Cancel() {}
<commit_msg>builder/googlecompute: set ID to packer namespace now thats in core<commit_after>// The googlecompute package contains a packer.Builder implementation that
// builds images for Google Compute Engine.
package googlecompute

import (
	"errors"
	"fmt"
	"log"
	"time"

	"github.com/mitchellh/multistep"
	"github.com/mitchellh/packer/common"
	"github.com/mitchellh/packer/packer"
)

// The unique ID for this builder.
const BuilderId = "packer.googlecompute"

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

// config holds the googlecompute builder configuration settings.
type config struct {
	BucketName          string            `mapstructure:"bucket_name"`
	ClientSecretsFile   string            `mapstructure:"client_secrets_file"`
	ImageName           string            `mapstructure:"image_name"`
	ImageDescription    string            `mapstructure:"image_description"`
	MachineType         string            `mapstructure:"machine_type"`
	Metadata            map[string]string `mapstructure:"metadata"`
	Network             string            `mapstructure:"network"`
	Passphrase          string            `mapstructure:"passphrase"`
	PrivateKeyFile      string            `mapstructure:"private_key_file"`
	ProjectId           string            `mapstructure:"project_id"`
	SourceImage         string            `mapstructure:"source_image"`
	SSHUsername         string            `mapstructure:"ssh_username"`
	SSHPort             uint              `mapstructure:"ssh_port"`
	RawSSHTimeout       string            `mapstructure:"ssh_timeout"`
	RawStateTimeout     string            `mapstructure:"state_timeout"`
	Tags                []string          `mapstructure:"tags"`
	Zone                string            `mapstructure:"zone"`
	clientSecrets       *clientSecrets
	common.PackerConfig `mapstructure:",squash"`
	instanceName        string
	privateKeyBytes     []byte
	sshTimeout          time.Duration
	stateTimeout        time.Duration
	tpl                 *packer.ConfigTemplate
}

// Prepare processes the build configuration parameters.
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
	// Load the packer config.
	md, err := common.DecodeConfig(&b.config, raws...)
	if err != nil {
		return nil, err
	}
	b.config.tpl, err = packer.NewConfigTemplate()
	if err != nil {
		return nil, err
	}
	b.config.tpl.UserVars = b.config.PackerUserVars

	errs := common.CheckUnusedConfig(md)
	// Collect errors if any.
	if err := common.CheckUnusedConfig(md); err != nil {
		return nil, err
	}
	// Set defaults.
	if b.config.Network == "" {
		b.config.Network = "default"
	}
	if b.config.ImageDescription == "" {
		b.config.ImageDescription = "Created by Packer"
	}
	if b.config.ImageName == "" {
		// Default to packer-{{ unix timestamp (utc) }}
		b.config.ImageName = "packer-{{timestamp}}"
	}
	if b.config.MachineType == "" {
		b.config.MachineType = "n1-standard-1"
	}
	if b.config.RawSSHTimeout == "" {
		b.config.RawSSHTimeout = "5m"
	}
	if b.config.RawStateTimeout == "" {
		b.config.RawStateTimeout = "5m"
	}
	if b.config.SSHUsername == "" {
		b.config.SSHUsername = "root"
	}
	if b.config.SSHPort == 0 {
		b.config.SSHPort = 22
	}
	// Process Templates
	templates := map[string]*string{
		"bucket_name":         &b.config.BucketName,
		"client_secrets_file": &b.config.ClientSecretsFile,
		"image_name":          &b.config.ImageName,
		"image_description":   &b.config.ImageDescription,
		"machine_type":        &b.config.MachineType,
		"network":             &b.config.Network,
		"passphrase":          &b.config.Passphrase,
		"private_key_file":    &b.config.PrivateKeyFile,
		"project_id":          &b.config.ProjectId,
		"source_image":        &b.config.SourceImage,
		"ssh_username":        &b.config.SSHUsername,
		"ssh_timeout":         &b.config.RawSSHTimeout,
		"state_timeout":       &b.config.RawStateTimeout,
		"zone":                &b.config.Zone,
	}
	for n, ptr := range templates {
		var err error
		*ptr, err = b.config.tpl.Process(*ptr, nil)
		if err != nil {
			errs = packer.MultiErrorAppend(
				errs, fmt.Errorf("Error processing %s: %s", n, err))
		}
	}
	// Process required parameters.
	if b.config.BucketName == "" {
		errs = packer.MultiErrorAppend(
			errs, errors.New("a bucket_name must be specified"))
	}
	if b.config.ClientSecretsFile == "" {
		errs = packer.MultiErrorAppend(
			errs, errors.New("a client_secrets_file must be specified"))
	}
	if b.config.PrivateKeyFile == "" {
		errs = packer.MultiErrorAppend(
			errs, errors.New("a private_key_file must be specified"))
	}
	if b.config.ProjectId == "" {
		errs = packer.MultiErrorAppend(
			errs, errors.New("a project_id must be specified"))
	}
	if b.config.SourceImage == "" {
		errs = packer.MultiErrorAppend(
			errs, errors.New("a source_image must be specified"))
	}
	if b.config.Zone == "" {
		errs = packer.MultiErrorAppend(
			errs, errors.New("a zone must be specified"))
	}
	// Process timeout settings.
	sshTimeout, err := time.ParseDuration(b.config.RawSSHTimeout)
	if err != nil {
		errs = packer.MultiErrorAppend(
			errs, fmt.Errorf("Failed parsing ssh_timeout: %s", err))
	}
	b.config.sshTimeout = sshTimeout
	stateTimeout, err := time.ParseDuration(b.config.RawStateTimeout)
	if err != nil {
		errs = packer.MultiErrorAppend(
			errs, fmt.Errorf("Failed parsing state_timeout: %s", err))
	}
	b.config.stateTimeout = stateTimeout
	// Load the client secrets file.
	cs, err := loadClientSecrets(b.config.ClientSecretsFile)
	if err != nil {
		errs = packer.MultiErrorAppend(
			errs, fmt.Errorf("Failed parsing client secrets file: %s", err))
	}
	b.config.clientSecrets = cs
	// Load the private key.
	b.config.privateKeyBytes, err = processPrivateKeyFile(b.config.PrivateKeyFile, b.config.Passphrase)
	if err != nil {
		errs = packer.MultiErrorAppend(
			errs, fmt.Errorf("Failed loading private key file: %s", err))
	}
	// Check for any errors.
	if errs != nil && len(errs.Errors) > 0 {
		return nil, errs
	}
	return nil, nil
}

// Run executes a googlecompute Packer build and returns a packer.Artifact
// representing a GCE machine image.
func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
	// Initialize the Google Compute Engine API.
	client, err := New(b.config.ProjectId, b.config.Zone, b.config.clientSecrets, b.config.privateKeyBytes)
	if err != nil {
		log.Println("Failed to create the Google Compute Engine client.")
		return nil, err
	}
	// Set up the state.
	state := new(multistep.BasicStateBag)
	state.Put("config", b.config)
	state.Put("client", client)
	state.Put("hook", hook)
	state.Put("ui", ui)
	// Build the steps.
	steps := []multistep.Step{
		new(stepCreateSSHKey),
		new(stepCreateInstance),
		new(stepInstanceInfo),
		&common.StepConnectSSH{
			SSHAddress:     sshAddress,
			SSHConfig:      sshConfig,
			SSHWaitTimeout: 5 * time.Minute,
		},
		new(common.StepProvision),
		new(stepUpdateGsutil),
		new(stepCreateImage),
		new(stepUploadImage),
		new(stepRegisterImage),
	}
	// Run the steps.
	if b.config.PackerDebug {
		b.runner = &multistep.DebugRunner{
			Steps:   steps,
			PauseFn: common.MultistepDebugFn(ui),
		}
	} else {
		b.runner = &multistep.BasicRunner{Steps: steps}
	}
	b.runner.Run(state)
	// Report any errors.
	if rawErr, ok := state.GetOk("error"); ok {
		return nil, rawErr.(error)
	}
	if _, ok := state.GetOk("image_name"); !ok {
		log.Println("Failed to find image_name in state. Bug?")
		return nil, nil
	}
	artifact := &Artifact{
		imageName: state.Get("image_name").(string),
		client:    client,
	}
	return artifact, nil
}

// Cancel.
func (b *Builder) Cancel() {}
<|endoftext|>