<commit_before>package data

type Map interface {
	Put(key Value, value Value) Value
	Get(key Value) (Value, error)
}
<commit_msg>Hashable interface<commit_after>package data

type Map interface {
	Put(key Value, value Value) Value
	Get(key Value) (Value, error)
}

type Hashable interface {
	HashCode() int
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"os/user"
	"path"
	"strconv"
	"strings"
)

const DIR_COLOR = "blue"
const PROMPT_COLOR = "cyan"
const COMMAND_COLOR = "yellow"
const CLEAN_TREE_COLOR = "green"
const DIRTY_TREE_COLOR = "red"
const ROOT_WARNING_COLOR = "red"

func main() {
	initColorCodes()

	statusParts := make([]string, 0, 10)

	// Add root warning.
	if os.Geteuid() == 0 {
		statusParts = append(statusParts,
			colorize(ROOT_WARNING_COLOR, "(root)"))
	}

	// Add working dir.
	statusParts = append(statusParts, colorize(DIR_COLOR, getwd()))

	// Add git branch.
	branch := gitBranch()
	if branch != "" {
		statusParts = append(statusParts, branch)
	}

	fmt.Print("\n[", strings.Join(statusParts, " "), "]\n")
}

func isTreeClean() (out bool) {
	cmd := exec.Command("git", "status", "-s")
	var outbuf, errbuf bytes.Buffer
	cmd.Stdout = &outbuf
	cmd.Stderr = &errbuf
	err := cmd.Run()
	check(err)
	return strings.TrimSpace(outbuf.String() + errbuf.String()) == ""
}

func gitBranch() (out string) {
	repoDir := gitRepoDir()
	if repoDir == "" {
		return ""
	}

	head, err := ioutil.ReadFile(path.Join(repoDir, ".git/HEAD"))
	check(err)
	branch := strings.TrimSpace(string(head))
	if strings.HasPrefix(branch, "ref: refs/heads/") {
		branch = strings.TrimPrefix(branch, "ref: refs/heads/")
	}
	var color string
	if isTreeClean() {
		color = CLEAN_TREE_COLOR
	} else {
		color = DIRTY_TREE_COLOR
	}
	return colorize(color, branch)
}

func gitRepoDir() (out string) {
	oldRepoDir := ""
	repoDir := getwd()

	for repoDir != oldRepoDir {
		if isGitRepo(repoDir) {
			return repoDir
		}
		oldRepoDir = repoDir
		repoDir, _ = path.Split(repoDir)
		repoDir = strings.TrimRight(repoDir, "/")
	}

	return ""
}

func isGitRepo(dir string) (out bool) {
	file, err := os.Stat(path.Join(dir + "/.git"))
	if err != nil {
		return false
	}
	return file.IsDir()
}

func getwd() (out string) {
	wd, err := os.Getwd()
	check(err)
	return wd
}

func replaceHome(dir string) (out string) {
	usr, err := user.Current()
	check(err)
	fmt.Println(usr.HomeDir)
	if strings.HasPrefix(dir, usr.HomeDir) {
		return "~" + strings.TrimPrefix(dir, usr.HomeDir)
	} else {
		return dir
	}
}

func colorize(colorSpec, s string) (out string) {
	return colorSequence(colorSpec) + s + colorSequence("off")
}

func colorSequence(colorSpec string) (out string) {
	colors := strings.Split(colorSpec, ",")
	codeStrs := make([]string, len(colors))
	for i := 0; i < len(colors); i++ {
		codeStrs[i] = strconv.Itoa(colorCodes[colors[i]])
	}
	return fmt.Sprintf("\x1b[%vm", strings.Join(codeStrs, ";"))
}

var colorCodes map[string]int

func initColorCodes() {
	colorCodes = map[string]int{
		"off":       0,
		"bold":      1,
		"dim":       2,
		"underline": 4,
		"reverse":   7,
		"concealed": 8,

		"black":   30,
		"red":     31,
		"green":   32,
		"yellow":  33,
		"blue":    34,
		"magenta": 35,
		"cyan":    36,
		"white":   37,
		"gray":    90,

		"bk_black":   40,
		"bk_red":     41,
		"bk_green":   42,
		"bk_yellow":  43,
		"bk_blue":    44,
		"bk_magenta": 45,
		"bk_cyan":    46,
		"bk_white":   47,
		"bk_gray":    100,

		// These don't work in emacs.
		"light_red":     91,
		"light_green":   92,
		"light_yellow":  93,
		"light_blue":    94,
		"light_magenta": 95,
		"light_cyan":    96,
		"light_white":   97,

		"bk_light_red":     101,
		"bk_light_green":   102,
		"bk_light_yellow":  103,
		"bk_light_blue":    104,
		"bk_light_magenta": 105,
		"bk_light_cyan":    106,
		"bk_light_white":   107,
	}
}

func check(e error) {
	if e != nil {
		panic(e)
	}
}
<commit_msg>fix prompter for when cwd is inside .git<commit_after>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"os/user"
	"path"
	"strconv"
	"strings"
)

const DIR_COLOR = "blue"
const PROMPT_COLOR = "cyan"
const COMMAND_COLOR = "yellow"
const CLEAN_TREE_COLOR = "green"
const DIRTY_TREE_COLOR = "red"
const ROOT_WARNING_COLOR = "red"

func main() {
	initColorCodes()

	statusParts := make([]string, 0, 10)

	// Add root warning.
	if os.Geteuid() == 0 {
		statusParts = append(statusParts,
			colorize(ROOT_WARNING_COLOR, "(root)"))
	}

	// Add working dir.
	statusParts = append(statusParts, colorize(DIR_COLOR, getwd()))

	// Add git branch.
	branch := gitBranch()
	if branch != "" {
		statusParts = append(statusParts, branch)
	}

	fmt.Print("\n[", strings.Join(statusParts, " "), "]\n")
}

func isTreeClean(repoDir string) (out bool) {
	cmd := exec.Command("git", "status", "-s")
	var outbuf, errbuf bytes.Buffer
	cmd.Stdout = &outbuf
	cmd.Stderr = &errbuf
	cmd.Dir = repoDir
	err := cmd.Run()
	check(err)
	return strings.TrimSpace(outbuf.String() + errbuf.String()) == ""
}

func gitBranch() (out string) {
	repoDir := gitRepoDir()
	if repoDir == "" {
		return ""
	}

	head, err := ioutil.ReadFile(path.Join(repoDir, ".git/HEAD"))
	check(err)
	branch := strings.TrimSpace(string(head))
	if strings.HasPrefix(branch, "ref: refs/heads/") {
		branch = strings.TrimPrefix(branch, "ref: refs/heads/")
	}
	var color string
	if isTreeClean(repoDir) {
		color = CLEAN_TREE_COLOR
	} else {
		color = DIRTY_TREE_COLOR
	}
	return colorize(color, branch)
}

func gitRepoDir() (out string) {
	oldRepoDir := ""
	repoDir := getwd()

	for repoDir != oldRepoDir {
		if isGitRepo(repoDir) {
			return repoDir
		}
		oldRepoDir = repoDir
		repoDir, _ = path.Split(repoDir)
		repoDir = strings.TrimRight(repoDir, "/")
	}

	return ""
}

func isGitRepo(dir string) (out bool) {
	file, err := os.Stat(path.Join(dir + "/.git"))
	if err != nil {
		return false
	}
	return file.IsDir()
}

func getwd() (out string) {
	wd, err := os.Getwd()
	check(err)
	return wd
}

func replaceHome(dir string) (out string) {
	usr, err := user.Current()
	check(err)
	fmt.Println(usr.HomeDir)
	if strings.HasPrefix(dir, usr.HomeDir) {
		return "~" + strings.TrimPrefix(dir, usr.HomeDir)
	} else {
		return dir
	}
}

func colorize(colorSpec, s string) (out string) {
	return colorSequence(colorSpec) + s + colorSequence("off")
}

func colorSequence(colorSpec string) (out string) {
	colors := strings.Split(colorSpec, ",")
	codeStrs := make([]string, len(colors))
	for i := 0; i < len(colors); i++ {
		codeStrs[i] = strconv.Itoa(colorCodes[colors[i]])
	}
	return fmt.Sprintf("\x1b[%vm", strings.Join(codeStrs, ";"))
}

var colorCodes map[string]int

func initColorCodes() {
	colorCodes = map[string]int{
		"off":       0,
		"bold":      1,
		"dim":       2,
		"underline": 4,
		"reverse":   7,
		"concealed": 8,

		"black":   30,
		"red":     31,
		"green":   32,
		"yellow":  33,
		"blue":    34,
		"magenta": 35,
		"cyan":    36,
		"white":   37,
		"gray":    90,

		"bk_black":   40,
		"bk_red":     41,
		"bk_green":   42,
		"bk_yellow":  43,
		"bk_blue":    44,
		"bk_magenta": 45,
		"bk_cyan":    46,
		"bk_white":   47,
		"bk_gray":    100,

		// These don't work in emacs.
		"light_red":     91,
		"light_green":   92,
		"light_yellow":  93,
		"light_blue":    94,
		"light_magenta": 95,
		"light_cyan":    96,
		"light_white":   97,

		"bk_light_red":     101,
		"bk_light_green":   102,
		"bk_light_yellow":  103,
		"bk_light_blue":    104,
		"bk_light_magenta": 105,
		"bk_light_cyan":    106,
		"bk_light_white":   107,
	}
}

func check(e error) {
	if e != nil {
		panic(e)
	}
}
<|endoftext|>


<commit_before>package src

import (
	"fmt"
	"log"
	"os/exec"
	"strconv"
	"testing"
)

func TestNoop(t *testing.T) {

}

func BenchmarkHead(b *testing.B) {
	benchmarkFmt(0, b)
}
func BenchmarkHeadMinus1(b *testing.B) {
	benchmarkFmt(1, b)
}
func BenchmarkHeadMinus2(b *testing.B) {
	benchmarkFmt(2, b)
}
func BenchmarkHeadMinus3(b *testing.B) {
	benchmarkFmt(3, b)
}
func BenchmarkHeadMinus4(b *testing.B) {
	benchmarkFmt(4, b)
}
func BenchmarkHeadMinus5(b *testing.B) {
	benchmarkFmt(5, b)
}

func benchmarkFmt(commits int, b *testing.B) {
	b.StopTimer()
	exec.Command("git", "checkout", "master").Output()
	exec.Command("git", "branch", "-D", "performance").Output()
	exec.Command("git", "checkout", "-b", "performance").Output()
	exec.Command("git", "reset", "--hard", "HEAD~"+strconv.Itoa(commits)).Output()
	out, err := exec.Command("git", "show", "--pretty=oneline").Output()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(out)

	b.StartTimer()
	for n := 0; n < b.N; n++ {
		exec.Command("php", "test.php", "-v").Output()
	}
	b.StopTimer()
	exec.Command("git", "checkout", "master").Output()
	exec.Command("git", "branch", "-D", "performance").Output()
	b.StartTimer()
}
<commit_msg>Showing commit content before running benchmark - take 2<commit_after>package src

import (
	"fmt"
	"log"
	"os/exec"
	"strconv"
	"testing"
)

func TestNoop(t *testing.T) {

}

func BenchmarkHead(b *testing.B) {
	benchmarkFmt(0, b)
}
func BenchmarkHeadMinus1(b *testing.B) {
	benchmarkFmt(1, b)
}
func BenchmarkHeadMinus2(b *testing.B) {
	benchmarkFmt(2, b)
}
func BenchmarkHeadMinus3(b *testing.B) {
	benchmarkFmt(3, b)
}
func BenchmarkHeadMinus4(b *testing.B) {
	benchmarkFmt(4, b)
}
func BenchmarkHeadMinus5(b *testing.B) {
	benchmarkFmt(5, b)
}

func benchmarkFmt(commits int, b *testing.B) {
	b.StopTimer()
	exec.Command("git", "checkout", "master").Output()
	exec.Command("git", "branch", "-D", "performance").Output()
	exec.Command("git", "checkout", "-b", "performance").Output()
	exec.Command("git", "reset", "--hard", "HEAD~"+strconv.Itoa(commits)).Output()
	out, err := exec.Command("git", "show", "--pretty=oneline").Output()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s", out)

	b.StartTimer()
	for n := 0; n < b.N; n++ {
		exec.Command("php", "test.php", "-v").Output()
	}
	b.StopTimer()
	exec.Command("git", "checkout", "master").Output()
	exec.Command("git", "branch", "-D", "performance").Output()
	b.StartTimer()
}
<|endoftext|>


<commit_before>// Copyright 2014 go-beacon authors.  All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package main

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

const base64GifPixel = "R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs="

func (s *httpServer) route() {
	http.HandleFunc(s.config.BeaconURI, s.beaconHandler)
	http.HandleFunc("/echo", s.echoBeaconHandler)
	http.Handle("/", http.FileServer(http.Dir(s.config.DocumentRoot)))
}

func (s *httpServer) indexHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "hello, world\r\n")
}

func (s *httpServer) beaconHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
	w.Header().Set("Pragma", "no-cache")
	w.Header().Set("Expires", "0")
	w.Header().Set("X-TRACKER-ID", "0")
	w.Header().Set("Content-Type", "image/gif")
	output, _ := base64.StdEncoding.DecodeString(base64GifPixel)
	w.Write(output)
	if len(r.URL.Query()) > 0 {
		go func() {
			err := producer.Send(r.URL.Query())
			if err != nil {
				log.Println(err)
			}
		}()
	}
}

func (s *httpServer) echoBeaconHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
	w.Header().Set("Pragma", "no-cache")
	w.Header().Set("Expires", "0")
	w.Header().Set("X-TRACKER-ID", "0")
	t, err := json.Marshal(r.URL.Query())
	if err != nil {
		log.Println(err)
		return
	}
	w.Write(t)
}
<commit_msg>Use Form instead of URL.Query()<commit_after>// Copyright 2014 go-beacon authors.  All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package main

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

const base64GifPixel = "R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs="

func (s *httpServer) route() {
	http.HandleFunc(s.config.BeaconURI, s.beaconHandler)
	http.HandleFunc("/echo", s.echoBeaconHandler)
	http.Handle("/", http.FileServer(http.Dir(s.config.DocumentRoot)))
}

func (s *httpServer) indexHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "hello, world\r\n")
}

func (s *httpServer) beaconHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
	w.Header().Set("Pragma", "no-cache")
	w.Header().Set("Expires", "0")
	w.Header().Set("X-TRACKER-ID", "0")
	w.Header().Set("Content-Type", "image/gif")
	output, _ := base64.StdEncoding.DecodeString(base64GifPixel)
	w.Write(output)
	err := r.ParseForm()
	if err != nil {
		log.Println(err)
		return
	}
	if len(r.Form) > 0 {
		go func() {
			err := producer.Send(r.Form)
			if err != nil {
				log.Println(err)
			}
		}()
	}
}

func (s *httpServer) echoBeaconHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
	w.Header().Set("Pragma", "no-cache")
	w.Header().Set("Expires", "0")
	w.Header().Set("X-TRACKER-ID", "0")
	t, err := json.Marshal(r.URL.Query())
	if err != nil {
		log.Println(err)
		return
	}
	w.Write(t)
}
<|endoftext|>


<commit_before>package unit_test

import (
	"path/filepath"
	"time"

	"github.com/cloudfoundry/libbuildpack"
	"github.com/cloudfoundry/libbuildpack/cutlass"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Options.JSON", func() {
	var versions []string
	var defaults map[string]interface{}
	BeforeEach(func() {
		bpDir, err := cutlass.FindRoot()
		Expect(err).NotTo(HaveOccurred())

		Expect(libbuildpack.NewJSON().Load(filepath.Join(bpDir, "defaults", "options.json"), &defaults)).To(Succeed())

		manifest, err := libbuildpack.NewManifest(bpDir, nil, time.Now())
		Expect(err).NotTo(HaveOccurred())
		versions = manifest.AllDependencyVersions("php")
	})

	It("PHP_71_LATEST has the latest 7.1 version", func() {
		latest, err := libbuildpack.FindMatchingVersion("7.1.x", versions)
		Expect(err).NotTo(HaveOccurred())

		Expect(defaults["PHP_71_LATEST"]).To(Equal(latest))
	})

	It("PHP_72_LATEST has the latest 7.2 version", func() {
		latest, err := libbuildpack.FindMatchingVersion("7.2.x", versions)
		Expect(err).NotTo(HaveOccurred())

		Expect(defaults["PHP_72_LATEST"]).To(Equal(latest))
	})
})
<commit_msg>No-op to trigger pipelines<commit_after>package unit_test

import (
	"path/filepath"
	"time"

	"github.com/cloudfoundry/libbuildpack"
	"github.com/cloudfoundry/libbuildpack/cutlass"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Options.JSON", func() {
	var versions []string
	var defaults map[string]interface{}
	BeforeEach(func() {
		bpDir, err := cutlass.FindRoot()
		Expect(err).NotTo(HaveOccurred())

		Expect(libbuildpack.NewJSON().Load(filepath.Join(bpDir, "defaults", "options.json"), &defaults)).To(Succeed())

		manifest, err := libbuildpack.NewManifest(bpDir, nil, time.Now())
		Expect(err).NotTo(HaveOccurred())
		versions = manifest.AllDependencyVersions("php")
	})

	It("PHP_71_LATEST will have the latest 7.1 version", func() {
		latest, err := libbuildpack.FindMatchingVersion("7.1.x", versions)
		Expect(err).NotTo(HaveOccurred())

		Expect(defaults["PHP_71_LATEST"]).To(Equal(latest))
	})

	It("PHP_72_LATEST will have the latest 7.2 version", func() {
		latest, err := libbuildpack.FindMatchingVersion("7.2.x", versions)
		Expect(err).NotTo(HaveOccurred())

		Expect(defaults["PHP_72_LATEST"]).To(Equal(latest))
	})
})
<|endoftext|>


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

package main

import "time"

type Mob interface {
	Bored(time.Duration) bool
}

type Mobile struct {
	DetectionRadius float32
	BoredThreshold  time.Duration
}

func (m *Mobile) Bored(d time.Duration) bool {
	return d >= m.BoredThreshold
}

// MobState is implemented by various states responsible for controlling mobile
// entities.
// ExamineWorld examines the current state of the game and determines which
// state
type MobState interface {
	// ExamineWorld examines the current state of the game and determines
	// which state the mobile should transition to. It's legal to return
	// either the current MobState or nil, indicating that the mobile
	// should transition to a previous state.
	ExamineWorld(Mob, *Level) (newState MobState)
	// Update should be called each frame and may update values in the
	// current state or call functions on the mob.
	Update(Mob, time.Duration)
	// Enter should be called when entering this MobState.
	Enter(Mob)
	// Enter should be called when exiting this MobState.
	Exit(Mob)
}

// SearchState is the state during which a mobile is aimlessly wandering,
// hoping to chance across the player.
type SearchState struct{}

// ExamineWorld returns HuntState if the player is seen, otherwise the mob
// continues wandering.
func (s *SearchState) ExamineWorld(m Mob, l *Level) MobState {
	if playerSeen(m, l) {
		return &HuntState{}
	}
	return s
}

func (s *SearchState) Update(m Mob, d time.Duration) {
}

func (s *SearchState) Enter(m Mob) {
	// TODO: set some hunting animation.
}

func (s *SearchState) Exit(m Mob) {
	// TODO: maybe something should happen when we start hunting?
}

// HuntState is the state during which a mobile is actively hunting the player.
type HuntState struct {
	durSinceLastContact time.Duration
}

// ExamineWorld returns the current state if the player is currently seen or
// the mob is not yet tired of chasing. Otherwise, it returns nil.
func (h *HuntState) ExamineWorld(m Mob, l *Level) MobState {
	if playerSeen(m, l) {
		h.durSinceLastContact = time.Duration(0)
		return h
	}
	if !m.Bored(h.durSinceLastContact) {
		return h
	}
	return nil
}

// Update resets the player's hiding timer if the player is seen, otherwise it
// increments.
func (h *HuntState) Update(m Mob, d time.Duration) {
	h.durSinceLastContact += d
}

func (h *HuntState) Enter(m Mob) {
}

func (h *HuntState) Exit(m Mob) {
}

// playerSeen returns true if the player is currently visible to the mob and
// within its detection radius.
func playerSeen(m Mob, l *Level) bool {
	// TODO: do something with visibility and detection radius.
	return true
}
<commit_msg>Mobs can now detect the player.<commit_after>// Copyright 2015 Pikkpoiss
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"time"

	"../lib/twodee"
	"github.com/go-gl/mathgl/mgl32"
)

type Mob interface {
	Bored(time.Duration) bool
	SetFrames(f []int)
	Detect(dist float32) bool
	Pos() twodee.Point
}

type Mobile struct {
	DetectionRadius float32
	BoredThreshold  time.Duration
}

func (m *Mobile) Bored(d time.Duration) bool {
	return d >= m.BoredThreshold
}

func (m *Mobile) Detect(d float32) bool {
	return d <= m.DetectionRadius
}

// MobState is implemented by various states responsible for controlling mobile
// entities.
// ExamineWorld examines the current state of the game and determines which
// state
type MobState interface {
	// ExamineWorld examines the current state of the game and determines
	// which state the mobile should transition to. It's legal to return
	// either the current MobState or nil, indicating that the mobile
	// should transition to a previous state.
	ExamineWorld(Mob, *Level) (newState MobState)
	// Update should be called each frame and may update values in the
	// current state or call functions on the mob.
	Update(Mob, time.Duration)
	// Enter should be called when entering this MobState.
	Enter(Mob)
	// Enter should be called when exiting this MobState.
	Exit(Mob)
}

// SearchState is the state during which a mobile is aimlessly wandering,
// hoping to chance across the player.
type SearchState struct{}

// ExamineWorld returns HuntState if the player is seen, otherwise the mob
// continues wandering.
func (s *SearchState) ExamineWorld(m Mob, l *Level) MobState {
	if playerSeen(m, l) {
		return &HuntState{}
	}
	return s
}

func (s *SearchState) Update(m Mob, d time.Duration) {
}

func (s *SearchState) Enter(m Mob) {
	// TODO: set some hunting animation.
}

func (s *SearchState) Exit(m Mob) {
	// TODO: maybe something should happen when we start hunting?
}

// HuntState is the state during which a mobile is actively hunting the player.
type HuntState struct {
	durSinceLastContact time.Duration
}

// ExamineWorld returns the current state if the player is currently seen or
// the mob is not yet tired of chasing. Otherwise, it returns nil.
func (h *HuntState) ExamineWorld(m Mob, l *Level) MobState {
	if playerSeen(m, l) {
		h.durSinceLastContact = time.Duration(0)
		return h
	}
	if !m.Bored(h.durSinceLastContact) {
		return h
	}
	return nil
}

// Update resets the player's hiding timer if the player is seen, otherwise it
// increments.
func (h *HuntState) Update(m Mob, d time.Duration) {
	h.durSinceLastContact += d
}

func (h *HuntState) Enter(m Mob) {
}

func (h *HuntState) Exit(m Mob) {
}

// playerSeen returns true if the player is currently visible to the mob and
// within its detection radius.
func playerSeen(m Mob, l *Level) bool {
	c := l.Collisions
	mpv := mgl32.Vec2{m.Pos().X, m.Pos().Y}
	ppv := mgl32.Vec2{l.Player.Pos().X, l.Player.Pos().Y}
	if c.CanSee(mpv, ppv, 0.5, 0.5) && m.Detect(mpv.Sub(ppv).Len()) {
		return true
	}
	return false
}
<|endoftext|>


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

package storagetransfer

import (
	"bytes"
	"context"
	"io/ioutil"
	"log"
	"os"
	"strings"
	"testing"

	"cloud.google.com/go/iam"
	"cloud.google.com/go/storage"
	storagetransfer "cloud.google.com/go/storagetransfer/apiv1"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"
	storagetransferpb "google.golang.org/genproto/googleapis/storagetransfer/v1"

	"github.com/GoogleCloudPlatform/golang-samples/internal/testutil"
	"github.com/aws/aws-sdk-go/service/s3"
)

var sc *storage.Client
var sts *storagetransfer.Client
var s3Bucket string
var gcsSourceBucket string
var gcsSinkBucket string

func TestMain(m *testing.M) {
	// Initialize global vars
	tc, _ := testutil.ContextMain(m)

	ctx := context.Background()
	c, err := storage.NewClient(ctx)
	if err != nil {
		log.Fatalf("storage.NewClient: %v", err)
	}
	sc = c
	defer sc.Close()

	gcsSourceBucket = testutil.UniqueBucketName("gcssourcebucket")
	source := sc.Bucket(gcsSourceBucket)
	err = source.Create(ctx, tc.ProjectID, nil)
	if err != nil {
		log.Fatalf("couldn't create GCS Source bucket: %v", err)
	}

	gcsSinkBucket = testutil.UniqueBucketName("gcssinkbucket")
	sink := sc.Bucket(gcsSinkBucket)
	err = sink.Create(ctx, tc.ProjectID, nil)
	if err != nil {
		log.Fatalf("couldn't create GCS Sink bucket: %v", err)
	}

	sts, err = storagetransfer.NewClient(ctx)
	if err != nil {
		log.Fatalf("storagetransfer.NewClient: %v", err)
	}
	defer sts.Close()

	grantSTSPermissions(gcsSourceBucket, tc.ProjectID, sts, sc)
	grantSTSPermissions(gcsSinkBucket, tc.ProjectID, sts, sc)

	s3Bucket = testutil.UniqueBucketName("stss3bucket")
	sess, err := session.NewSession(&aws.Config{
		Region: aws.String("us-west-2")},
	)
	s3c := s3.New(sess)
	_, err = s3c.CreateBucket(&s3.CreateBucketInput{
		Bucket: aws.String(s3Bucket),
	})
	if err != nil {
		log.Fatalf("couldn't create S3 bucket: %v", err)
	}

	// Run tests
	exit := m.Run()

	err = sink.Delete(ctx)
	if err != nil {
		log.Printf("couldn't delete GCS Sink bucket: %v", err)
	}

	err = source.Delete(ctx)
	if err != nil {
		log.Printf("couldn't delete GCS Source bucket: %v", err)
	}
	s3manager.NewDeleteListIterator(s3c, &s3.ListObjectsInput{
		Bucket: aws.String(s3Bucket),
	})
	_, err = s3c.DeleteBucket(&s3.DeleteBucketInput{
		Bucket: aws.String(s3Bucket),
	})
	if err != nil {
		log.Printf("couldn't delete S3 bucket: %v", err)
	}

	os.Exit(exit)
}

func TestQuickstart(t *testing.T) {
	tc := testutil.SystemTest(t)

	buf := new(bytes.Buffer)
	resp, err := quickstart(buf, tc.ProjectID, gcsSourceBucket, gcsSinkBucket)
	defer cleanupSTSJob(resp, tc.ProjectID)

	if err != nil {
		t.Errorf("quickstart: %#v", err)
	}

	got := buf.String()
	if want := "transferJobs/"; !strings.Contains(got, want) {
		t.Errorf("quickstart: got %q, want %q", got, want)
	}
}

func TestTransferFromAws(t *testing.T) {
	tc := testutil.SystemTest(t)

	buf := new(bytes.Buffer)

	resp, err := transferFromAws(buf, tc.ProjectID, s3Bucket, gcsSinkBucket)
	defer cleanupSTSJob(resp, tc.ProjectID)

	if err != nil {
		t.Errorf("transfer_from_aws: %#v", err)
	}

	got := buf.String()
	if want := "transferJobs/"; !strings.Contains(got, want) {
		t.Errorf("transfer_from_aws: got %q, want %q", got, want)
	}
}

func TestTransferToNearline(t *testing.T) {
	tc := testutil.SystemTest(t)

	buf := new(bytes.Buffer)

	resp, err := transferToNearline(buf, tc.ProjectID, gcsSourceBucket, gcsSinkBucket)
	defer cleanupSTSJob(resp, tc.ProjectID)

	if err != nil {
		t.Errorf("transfer_from_aws: %#v", err)
	}

	got := buf.String()
	if want := "transferJobs/"; !strings.Contains(got, want) {
		t.Errorf("transfer_to_nearline: got %q, want %q", got, want)
	}
}

func TestGetLatestTransferOperation(t *testing.T) {
	tc := testutil.SystemTest(t)

	buf := new(bytes.Buffer)

	job, err := transferToNearline(buf, tc.ProjectID, gcsSourceBucket, gcsSinkBucket)
	defer cleanupSTSJob(job, tc.ProjectID)

	op, err := checkLatestTransferOperation(buf, tc.ProjectID, job.Name)

	if err != nil {
		t.Errorf("check_latest_transfer_operation: %#v", err)
	}
	if !strings.Contains(op.Name, "transferOperations/") {
		t.Errorf("check_latest_transfer_operation: Operation returned didn't have a valid operation name: %q", op.Name)
	}

	got := buf.String()
	if want := op.Name; !strings.Contains(got, want) {
		t.Errorf("check_latest_transfer_operation: got %q, want %q", got, want)
	}
}

func TestDownloadToPosix(t *testing.T) {
	tc := testutil.SystemTest(t)

	buf := new(bytes.Buffer)

	rootDirectory, err := ioutil.TempDir("", "download-to-posix-test")
	if err != nil {
		t.Fatalf("download_to_posix: %#v", err)
	}
	defer os.RemoveAll(rootDirectory)

	sinkAgentPoolName := "" //use default agent pool
	gcsSourcePath := rootDirectory + "/"

	resp, err := downloadToPosix(buf, tc.ProjectID, sinkAgentPoolName, gcsSinkBucket, gcsSourcePath, rootDirectory)
	defer cleanupSTSJob(resp, tc.ProjectID)

	if err != nil {
		t.Errorf("download_to_posix: %#v", err)
	}

	got := buf.String()
	if want := "transferJobs/"; !strings.Contains(got, want) {
		t.Errorf("download_to_posix: got %q, want %q", got, want)
	}
}

func TestTransferFromPosix(t *testing.T) {
	tc := testutil.SystemTest(t)

	buf := new(bytes.Buffer)

	rootDirectory, err := ioutil.TempDir("", "transfer-from-posix-test")
	if err != nil {
		t.Fatalf("transfer_from_posix: %#v", err)
	}
	defer os.RemoveAll(rootDirectory)

	sourceAgentPoolName := "" //use default agent pool

	resp, err := transferFromPosix(buf, tc.ProjectID, sourceAgentPoolName, rootDirectory, gcsSinkBucket)
	defer cleanupSTSJob(resp, tc.ProjectID)

	if err != nil {
		t.Errorf("transfer_from_posix: %#v", err)
	}

	got := buf.String()
	if want := "transferJobs/"; !strings.Contains(got, want) {
		t.Errorf("transfer_from_posix: got %q, want %q", got, want)
	}
}

func TestTransferBetweenPosix(t *testing.T) {
	tc := testutil.SystemTest(t)

	buf := new(bytes.Buffer)

	rootDirectory, err := ioutil.TempDir("", "transfer-between-posix-test-source")
	if err != nil {
		t.Fatalf("transfer_between_posix: %#v", err)
	}
	defer os.RemoveAll(rootDirectory)

	destinationDirectory, err := ioutil.TempDir("", "transfer-between-posix-test-sink")
	if err != nil {
		t.Fatalf("transfer_between_posix: %#v", err)
	}
	defer os.RemoveAll(destinationDirectory)

	sourceAgentPoolName := "" //use default agent pool
	sinkAgentPoolName := ""   //use default agent pool

	resp, err := transferBetweenPosix(buf, tc.ProjectID, sourceAgentPoolName, sinkAgentPoolName, rootDirectory, destinationDirectory, gcsSinkBucket)
	if err != nil {
		t.Errorf("transfer_between_posix: %#v", err)
	}
	defer cleanupSTSJob(resp, tc.ProjectID)

	got := buf.String()
	if want := "transferJobs/"; !strings.Contains(got, want) {
		t.Errorf("transfer_between_posix: got %q, want %q", got, want)
	}
}

func TestTransferUsingManifest(t *testing.T) {
	tc := testutil.SystemTest(t)

	buf := new(bytes.Buffer)

	rootDirectory, err := ioutil.TempDir("", "transfer-using-manifest-test")
	if err != nil {
		t.Fatalf("transfer_using_manifest: %#v", err)
	}
	defer os.RemoveAll(rootDirectory)

	sourceAgentPoolName := "" //use default agent pool
	object := sc.Bucket(gcsSourceBucket).Object("manifest.csv")
	defer object.Delete(context.Background())

	resp, err := transferUsingManifest(buf, tc.ProjectID, sourceAgentPoolName, rootDirectory, gcsSinkBucket, gcsSourceBucket, "manifest.csv")
	defer cleanupSTSJob(resp, tc.ProjectID)

	if err != nil {
		t.Errorf("transfer_using_manifest: %#v", err)
	}

	got := buf.String()
	if want := "transferJobs/"; !strings.Contains(got, want) {
		t.Errorf("transfer_using_manifest: got %q, want %q", got, want)
	}
}

func grantSTSPermissions(bucketName string, projectID string, sts *storagetransfer.Client, str *storage.Client) {
	ctx := context.Background()

	req := &storagetransferpb.GetGoogleServiceAccountRequest{
		ProjectId: projectID,
	}

	resp, err := sts.GetGoogleServiceAccount(ctx, req)
	if err != nil {
		log.Fatalf("error getting service account")
	}
	email := resp.AccountEmail

	identity := "serviceAccount:" + email

	bucket := str.Bucket(bucketName)
	policy, err := bucket.IAM().Policy(ctx)
	if err != nil {
		log.Fatalf("Bucket(%q).IAM().Policy: %v", bucketName, err)
	}

	var objectViewer iam.RoleName = "roles/storage.objectViewer"
	var bucketReader iam.RoleName = "roles/storage.legacyBucketReader"
	var bucketWriter iam.RoleName = "roles/storage.legacyBucketWriter"

	policy.Add(identity, objectViewer)
	policy.Add(identity, bucketReader)
	policy.Add(identity, bucketWriter)

	if err := bucket.IAM().SetPolicy(ctx, policy); err != nil {
		log.Fatalf("bucket(%q).IAM().SetPolicy: %v", bucketName, err)
	}
}

func cleanupSTSJob(job *storagetransferpb.TransferJob, projectID string) {
	if job == nil {
		return
	}

	ctx := context.Background()

	tj := &storagetransferpb.TransferJob{
		Name:   job.Name,
		Status: storagetransferpb.TransferJob_DELETED,
	}
	sts.UpdateTransferJob(ctx, &storagetransferpb.UpdateTransferJobRequest{
		JobName:     job.Name,
		ProjectId:   projectID,
		TransferJob: tj,
	})
}
<commit_msg>test(storage): add test retry (#2684)<commit_after>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package storagetransfer

import (
	"bytes"
	"context"
	"io/ioutil"
	"log"
	"os"
	"strings"
	"testing"
	"time"

	"cloud.google.com/go/iam"
	"cloud.google.com/go/storage"
	storagetransfer "cloud.google.com/go/storagetransfer/apiv1"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"
	storagetransferpb "google.golang.org/genproto/googleapis/storagetransfer/v1"

	"github.com/GoogleCloudPlatform/golang-samples/internal/testutil"
	"github.com/aws/aws-sdk-go/service/s3"
)

var sc *storage.Client
var sts *storagetransfer.Client
var s3Bucket string
var gcsSourceBucket string
var gcsSinkBucket string

func TestMain(m *testing.M) {
	// Initialize global vars
	tc, _ := testutil.ContextMain(m)

	ctx := context.Background()
	c, err := storage.NewClient(ctx)
	if err != nil {
		log.Fatalf("storage.NewClient: %v", err)
	}
	sc = c
	defer sc.Close()

	gcsSourceBucket = testutil.UniqueBucketName("gcssourcebucket")
	source := sc.Bucket(gcsSourceBucket)
	err = source.Create(ctx, tc.ProjectID, nil)
	if err != nil {
		log.Fatalf("couldn't create GCS Source bucket: %v", err)
	}

	gcsSinkBucket = testutil.UniqueBucketName("gcssinkbucket")
	sink := sc.Bucket(gcsSinkBucket)
	err = sink.Create(ctx, tc.ProjectID, nil)
	if err != nil {
		log.Fatalf("couldn't create GCS Sink bucket: %v", err)
	}

	sts, err = storagetransfer.NewClient(ctx)
	if err != nil {
		log.Fatalf("storagetransfer.NewClient: %v", err)
	}
	defer sts.Close()

	grantSTSPermissions(gcsSourceBucket, tc.ProjectID, sts, sc)
	grantSTSPermissions(gcsSinkBucket, tc.ProjectID, sts, sc)

	s3Bucket = testutil.UniqueBucketName("stss3bucket")
	sess, err := session.NewSession(&aws.Config{
		Region: aws.String("us-west-2")},
	)
	s3c := s3.New(sess)
	_, err = s3c.CreateBucket(&s3.CreateBucketInput{
		Bucket: aws.String(s3Bucket),
	})
	if err != nil {
		log.Fatalf("couldn't create S3 bucket: %v", err)
	}

	// Run tests
	exit := m.Run()

	err = sink.Delete(ctx)
	if err != nil {
		log.Printf("couldn't delete GCS Sink bucket: %v", err)
	}

	err = source.Delete(ctx)
	if err != nil {
		log.Printf("couldn't delete GCS Source bucket: %v", err)
	}
	s3manager.NewDeleteListIterator(s3c, &s3.ListObjectsInput{
		Bucket: aws.String(s3Bucket),
	})
	_, err = s3c.DeleteBucket(&s3.DeleteBucketInput{
		Bucket: aws.String(s3Bucket),
	})
	if err != nil {
		log.Printf("couldn't delete S3 bucket: %v", err)
	}

	os.Exit(exit)
}

func TestQuickstart(t *testing.T) {
	tc := testutil.SystemTest(t)

	buf := new(bytes.Buffer)
	resp, err := quickstart(buf, tc.ProjectID, gcsSourceBucket, gcsSinkBucket)
	defer cleanupSTSJob(resp, tc.ProjectID)

	if err != nil {
		t.Errorf("quickstart: %#v", err)
	}

	got := buf.String()
	if want := "transferJobs/"; !strings.Contains(got, want) {
		t.Errorf("quickstart: got %q, want %q", got, want)
	}
}

func TestTransferFromAws(t *testing.T) {
	tc := testutil.SystemTest(t)

	buf := new(bytes.Buffer)

	resp, err := transferFromAws(buf, tc.ProjectID, s3Bucket, gcsSinkBucket)
	defer cleanupSTSJob(resp, tc.ProjectID)

	if err != nil {
		t.Errorf("transfer_from_aws: %#v", err)
	}

	got := buf.String()
	if want := "transferJobs/"; !strings.Contains(got, want) {
		t.Errorf("transfer_from_aws: got %q, want %q", got, want)
	}
}

func TestTransferToNearline(t *testing.T) {
	tc := testutil.SystemTest(t)

	buf := new(bytes.Buffer)

	resp, err := transferToNearline(buf, tc.ProjectID, gcsSourceBucket, gcsSinkBucket)
	defer cleanupSTSJob(resp, tc.ProjectID)

	if err != nil {
		t.Errorf("transfer_from_aws: %#v", err)
	}

	got := buf.String()
	if want := "transferJobs/"; !strings.Contains(got, want) {
		t.Errorf("transfer_to_nearline: got %q, want %q", got, want)
	}
}

func TestGetLatestTransferOperation(t *testing.T) {
	tc := testutil.SystemTest(t)

	buf := new(bytes.Buffer)

	job, err := transferToNearline(buf, tc.ProjectID, gcsSourceBucket, gcsSinkBucket)
	defer cleanupSTSJob(job, tc.ProjectID)

	op, err := checkLatestTransferOperation(buf, tc.ProjectID, job.Name)

	if err != nil {
		t.Errorf("check_latest_transfer_operation: %#v", err)
	}
	if !strings.Contains(op.Name, "transferOperations/") {
		t.Errorf("check_latest_transfer_operation: Operation returned didn't have a valid operation name: %q", op.Name)
	}

	got := buf.String()
	if want := op.Name; !strings.Contains(got, want) {
		t.Errorf("check_latest_transfer_operation: got %q, want %q", got, want)
	}
}

func TestDownloadToPosix(t *testing.T) {
	tc := testutil.SystemTest(t)

	buf := new(bytes.Buffer)

	rootDirectory, err := ioutil.TempDir("", "download-to-posix-test")
	if err != nil {
		t.Fatalf("download_to_posix: %#v", err)
	}
	defer os.RemoveAll(rootDirectory)

	sinkAgentPoolName := "" //use default agent pool
	gcsSourcePath := rootDirectory + "/"

	resp, err := downloadToPosix(buf, tc.ProjectID, sinkAgentPoolName, gcsSinkBucket, gcsSourcePath, rootDirectory)
	defer cleanupSTSJob(resp, tc.ProjectID)

	if err != nil {
		t.Errorf("download_to_posix: %#v", err)
	}

	got := buf.String()
	if want := "transferJobs/"; !strings.Contains(got, want) {
		t.Errorf("download_to_posix: got %q, want %q", got, want)
	}
}

func TestTransferFromPosix(t *testing.T) {
	tc := testutil.SystemTest(t)

	buf := new(bytes.Buffer)

	rootDirectory, err := ioutil.TempDir("", "transfer-from-posix-test")
	if err != nil {
		t.Fatalf("transfer_from_posix: %#v", err)
	}
	defer os.RemoveAll(rootDirectory)

	sourceAgentPoolName := "" //use default agent pool

	resp, err := transferFromPosix(buf, tc.ProjectID, sourceAgentPoolName, rootDirectory, gcsSinkBucket)
	defer cleanupSTSJob(resp, tc.ProjectID)

	if err != nil {
		t.Errorf("transfer_from_posix: %#v", err)
	}

	got := buf.String()
	if want := "transferJobs/"; !strings.Contains(got, want) {
		t.Errorf("transfer_from_posix: got %q, want %q", got, want)
	}
}

func TestTransferBetweenPosix(t *testing.T) {
	tc := testutil.SystemTest(t)

	buf := new(bytes.Buffer)

	rootDirectory, err := ioutil.TempDir("", "transfer-between-posix-test-source")
	if err != nil {
		t.Fatalf("transfer_between_posix: %#v", err)
	}
	defer os.RemoveAll(rootDirectory)

	destinationDirectory, err := ioutil.TempDir("", "transfer-between-posix-test-sink")
	if err != nil {
		t.Fatalf("transfer_between_posix: %#v", err)
	}
	defer os.RemoveAll(destinationDirectory)

	sourceAgentPoolName := "" //use default agent pool
	sinkAgentPoolName := ""   //use default agent pool

	resp, err := transferBetweenPosix(buf, tc.ProjectID, sourceAgentPoolName, sinkAgentPoolName, rootDirectory, destinationDirectory, gcsSinkBucket)
	if err != nil {
		t.Errorf("transfer_between_posix: %#v", err)
	}
	defer cleanupSTSJob(resp, tc.ProjectID)

	got := buf.String()
	if want := "transferJobs/"; !strings.Contains(got, want) {
		t.Errorf("transfer_between_posix: got %q, want %q", got, want)
	}
}

func TestTransferUsingManifest(t *testing.T) {
	tc := testutil.SystemTest(t)

	buf := new(bytes.Buffer)

	rootDirectory, err := ioutil.TempDir("", "transfer-using-manifest-test")
	if err != nil {
		t.Fatalf("transfer_using_manifest: %#v", err)
	}
	defer os.RemoveAll(rootDirectory)

	sourceAgentPoolName := "" //use default agent pool
	object := sc.Bucket(gcsSourceBucket).Object("manifest.csv")
	defer object.Delete(context.Background())

	testutil.Retry(t, 5, time.Second, func(r *testutil.R) {
		resp, err := transferUsingManifest(buf, tc.ProjectID, sourceAgentPoolName, rootDirectory, gcsSinkBucket, gcsSourceBucket, "manifest.csv")
		defer cleanupSTSJob(resp, tc.ProjectID)

		if err != nil {
			r.Errorf("transfer_using_manifest: %#v", err)
		}
	})

	got := buf.String()
	if want := "transferJobs/"; !strings.Contains(got, want) {
		t.Errorf("transfer_using_manifest: got %q, want %q", got, want)
	}
}

func grantSTSPermissions(bucketName string, projectID string, sts *storagetransfer.Client, str *storage.Client) {
	ctx := context.Background()

	req := &storagetransferpb.GetGoogleServiceAccountRequest{
		ProjectId: projectID,
	}

	resp, err := sts.GetGoogleServiceAccount(ctx, req)
	if err != nil {
		log.Fatalf("error getting service account")
	}
	email := resp.AccountEmail

	identity := "serviceAccount:" + email

	bucket := str.Bucket(bucketName)
	policy, err := bucket.IAM().Policy(ctx)
	if err != nil {
		log.Fatalf("Bucket(%q).IAM().Policy: %v", bucketName, err)
	}

	var objectViewer iam.RoleName = "roles/storage.objectViewer"
	var bucketReader iam.RoleName = "roles/storage.legacyBucketReader"
	var bucketWriter iam.RoleName = "roles/storage.legacyBucketWriter"

	policy.Add(identity, objectViewer)
	policy.Add(identity, bucketReader)
	policy.Add(identity, bucketWriter)

	if err := bucket.IAM().SetPolicy(ctx, policy); err != nil {
		log.Fatalf("bucket(%q).IAM().SetPolicy: %v", bucketName, err)
	}
}

func cleanupSTSJob(job *storagetransferpb.TransferJob, projectID string) {
	if job == nil {
		return
	}

	ctx := context.Background()

	tj := &storagetransferpb.TransferJob{
		Name:   job.Name,
		Status: storagetransferpb.TransferJob_DELETED,
	}
	sts.UpdateTransferJob(ctx, &storagetransferpb.UpdateTransferJobRequest{
		JobName:     job.Name,
		ProjectId:   projectID,
		TransferJob: tj,
	})
}
<|endoftext|>


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

package subcommandstest

import (
	"testing"

	"github.com/maruel/subcommands"
	"github.com/maruel/ut"
)

// Testing subcommands would require importing subcommandstest. To not create
// an import cycle between subcommands and subcommandstest, the public part of
// module subcommands is tested here.

func init() {
	DisableLogOutput()
}

func TestHelp(t *testing.T) {
	t.Parallel()
	app := &subcommands.DefaultApplication{
		Name:  "name",
		Title: "doc",
		Commands: []*subcommands.Command{
			subcommands.CmdHelp,
		},
	}
	a := MakeAppMock(t, app)
	args := []string{"help"}
	r := subcommands.Run(a, args)
	ut.AssertEqual(t, r, 0)
	a.CheckBuffer(true, false)
}

func TestHelpBadFlag(t *testing.T) {
	t.Parallel()
	app := &subcommands.DefaultApplication{
		Name:  "name",
		Title: "doc",
		Commands: []*subcommands.Command{
			subcommands.CmdHelp,
		},
	}
	a := MakeAppMock(t, app)
	args := []string{"help", "-foo"}
	r := subcommands.Run(a, args)
	ut.AssertEqual(t, r, 2)
	a.CheckBuffer(false, true)
}

func TestHelpBadCommand(t *testing.T) {
	t.Parallel()
	app := &subcommands.DefaultApplication{
		Name:  "name",
		Title: "doc",
		Commands: []*subcommands.Command{
			subcommands.CmdHelp,
		},
	}
	a := MakeAppMock(t, app)
	args := []string{"help", "non_existing_command"}
	r := subcommands.Run(a, args)
	ut.AssertEqual(t, r, 2)
	a.CheckBuffer(false, true)
}

func TestBadCommand(t *testing.T) {
	t.Parallel()
	app := &subcommands.DefaultApplication{
		Name:  "name",
		Title: "doc",
		Commands: []*subcommands.Command{
			subcommands.CmdHelp,
		},
	}
	a := MakeAppMock(t, app)
	args := []string{"non_existing_command"}
	r := subcommands.Run(a, args)
	ut.AssertEqual(t, r, 2)
	a.CheckBuffer(false, true)
}
<commit_msg>Don't run tests in parallel anymore.<commit_after>/* Copyright 2012 Marc-Antoine Ruel. Licensed under the Apache License, Version
2.0 (the "License"); you may not use this file except in compliance with the
License.  You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0. Unless required by applicable law or
agreed to in writing, software distributed under the License is distributed on
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the License for the specific language governing permissions and
limitations under the License. */

package subcommandstest

import (
	"testing"

	"github.com/maruel/subcommands"
	"github.com/maruel/ut"
)

// Testing subcommands would require importing subcommandstest. To not create
// an import cycle between subcommands and subcommandstest, the public part of
// module subcommands is tested here.

func init() {
	DisableLogOutput()
}

func TestHelp(t *testing.T) {
	app := &subcommands.DefaultApplication{
		Name:  "name",
		Title: "doc",
		Commands: []*subcommands.Command{
			subcommands.CmdHelp,
		},
	}
	a := MakeAppMock(t, app)
	args := []string{"help"}
	r := subcommands.Run(a, args)
	ut.AssertEqual(t, r, 0)
	a.CheckBuffer(true, false)
}

func TestHelpBadFlag(t *testing.T) {
	app := &subcommands.DefaultApplication{
		Name:  "name",
		Title: "doc",
		Commands: []*subcommands.Command{
			subcommands.CmdHelp,
		},
	}
	a := MakeAppMock(t, app)
	args := []string{"help", "-foo"}
	r := subcommands.Run(a, args)
	ut.AssertEqual(t, r, 2)
	a.CheckBuffer(false, true)
}

func TestHelpBadCommand(t *testing.T) {
	app := &subcommands.DefaultApplication{
		Name:  "name",
		Title: "doc",
		Commands: []*subcommands.Command{
			subcommands.CmdHelp,
		},
	}
	a := MakeAppMock(t, app)
	args := []string{"help", "non_existing_command"}
	r := subcommands.Run(a, args)
	ut.AssertEqual(t, r, 2)
	a.CheckBuffer(false, true)
}

func TestBadCommand(t *testing.T) {
	app := &subcommands.DefaultApplication{
		Name:  "name",
		Title: "doc",
		Commands: []*subcommands.Command{
			subcommands.CmdHelp,
		},
	}
	a := MakeAppMock(t, app)
	args := []string{"non_existing_command"}
	r := subcommands.Run(a, args)
	ut.AssertEqual(t, r, 2)
	a.CheckBuffer(false, true)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/mrlauer/gosockjs"
	"io"
	"log"
	"net/http"
)

func echo(c *gosockjs.Conn) {
	io.Copy(c, c)
}

func closeSock(c *gosockjs.Conn) {
	c.Close()
}

func main() {
	gosockjs.Install("/echo", echo)
	dwe, err := gosockjs.Install("/disabled_websocket_echo", echo)
	if err != nil {
		log.Println(err)
	}
	dwe.WebsocketEnabled = false
	gosockjs.Install("/close", closeSock)
	fmt.Println("Listening on port 8081")
	http.ListenAndServe(":8081", nil)
}
<commit_msg>add delay to fix test<commit_after>package main

import (
	"fmt"
	"github.com/mrlauer/gosockjs"
	"io"
	"log"
	"net/http"
	"time"
)

func echo(c *gosockjs.Conn) {
	io.Copy(c, c)
}

func closeSock(c *gosockjs.Conn) {
	// Wait a bit to give tests time to catch up!
	time.Sleep(time.Millisecond * 10)
	c.Close()
}

func main() {
	gosockjs.Install("/echo", echo)
	dwe, err := gosockjs.Install("/disabled_websocket_echo", echo)
	if err != nil {
		log.Println(err)
	}
	dwe.WebsocketEnabled = false
	gosockjs.Install("/close", closeSock)
	fmt.Println("Listening on port 8081")
	http.ListenAndServe(":8081", nil)
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package mapper

import (
	"strings"

	"github.com/ernestio/aws-definition-mapper/definition"
	"github.com/ernestio/aws-definition-mapper/output"
)

// MapS3Buckets : Maps the s3 buckets from a given input payload.
func MapS3Buckets(d definition.Definition) []output.S3 {
	var s3buckets []output.S3

	for _, s3 := range d.S3Buckets {

		s := output.S3{
			Name:             s3.Name,
			ACL:              strings.ToUpper(s3.ACL),
			BucketLocation:   s3.BucketLocation,
			ProviderType:     "$(datacenters.items.0.type)",
			DatacenterName:   "$(datacenters.items.0.name)",
			DatacenterSecret: "$(datacenters.items.0.secret)",
			DatacenterToken:  "$(datacenters.items.0.token)",
			DatacenterRegion: "$(datacenters.items.0.region)",
		}

		for _, grantee := range s3.Grantees {
			s.Grantees = append(s.Grantees, output.S3Grantee{
				ID:          grantee.ID,
				Type:        grantee.Type,
				Permissions: strings.ToUpper(grantee.Permissions),
			})
		}

		s3buckets = append(s3buckets, s)
	}

	return s3buckets
}
<commit_msg>removed to upper on s3 acl permission<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package mapper

import (
	"strings"

	"github.com/ernestio/aws-definition-mapper/definition"
	"github.com/ernestio/aws-definition-mapper/output"
)

// MapS3Buckets : Maps the s3 buckets from a given input payload.
func MapS3Buckets(d definition.Definition) []output.S3 {
	var s3buckets []output.S3

	for _, s3 := range d.S3Buckets {

		s := output.S3{
			Name:             s3.Name,
			ACL:              strings.ToUpper(s3.ACL),
			BucketLocation:   s3.BucketLocation,
			ProviderType:     "$(datacenters.items.0.type)",
			DatacenterName:   "$(datacenters.items.0.name)",
			DatacenterSecret: "$(datacenters.items.0.secret)",
			DatacenterToken:  "$(datacenters.items.0.token)",
			DatacenterRegion: "$(datacenters.items.0.region)",
		}

		for _, grantee := range s3.Grantees {
			s.Grantees = append(s.Grantees, output.S3Grantee{
				ID:          grantee.ID,
				Type:        grantee.Type,
				Permissions: grantee.Permissions,
			})
		}

		s3buckets = append(s3buckets, s)
	}

	return s3buckets
}
<|endoftext|>


<commit_before>package api

import (
	"github.com/go-macaron/binding"
	"github.com/grafana/grafana/pkg/api/avatar"
	"github.com/grafana/grafana/pkg/api/dtos"
	"github.com/grafana/grafana/pkg/api/live"
	"github.com/grafana/grafana/pkg/middleware"
	m "github.com/grafana/grafana/pkg/models"
	"gopkg.in/macaron.v1"
)

// Register adds http routes
func Register(r *macaron.Macaron) {
	reqSignedIn := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true})
	reqGrafanaAdmin := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true, ReqGrafanaAdmin: true})
	reqEditorRole := middleware.RoleAuth(m.ROLE_EDITOR, m.ROLE_ADMIN)
	reqOrgAdmin := middleware.RoleAuth(m.ROLE_ADMIN)
	quota := middleware.Quota
	bind := binding.Bind

	// not logged in views
	r.Get("/", reqSignedIn, Index)
	r.Get("/logout", Logout)
	r.Post("/login", quota("session"), bind(dtos.LoginCommand{}), wrap(LoginPost))
	r.Get("/login/:name", quota("session"), OAuthLogin)
	r.Get("/login", LoginView)
	r.Get("/invite/:code", Index)

	// authed views
	r.Get("/profile/", reqSignedIn, Index)
	r.Get("/profile/password", reqSignedIn, Index)
	r.Get("/profile/switch-org/:id", reqSignedIn, ChangeActiveOrgAndRedirectToHome)
	r.Get("/org/", reqSignedIn, Index)
	r.Get("/org/new", reqSignedIn, Index)
	r.Get("/datasources/", reqSignedIn, Index)
	r.Get("/datasources/new", reqSignedIn, Index)
	r.Get("/datasources/edit/*", reqSignedIn, Index)
	r.Get("/org/users/", reqSignedIn, Index)
	r.Get("/org/apikeys/", reqSignedIn, Index)
	r.Get("/dashboard/import/", reqSignedIn, Index)
	r.Get("/admin", reqGrafanaAdmin, Index)
	r.Get("/admin/settings", reqGrafanaAdmin, Index)
	r.Get("/admin/users", reqGrafanaAdmin, Index)
	r.Get("/admin/users/create", reqGrafanaAdmin, Index)
	r.Get("/admin/users/edit/:id", reqGrafanaAdmin, Index)
	r.Get("/admin/orgs", reqGrafanaAdmin, Index)
	r.Get("/admin/orgs/edit/:id", reqGrafanaAdmin, Index)
	r.Get("/admin/stats", reqGrafanaAdmin, Index)

	r.Get("/styleguide", reqSignedIn, Index)

	r.Get("/plugins", reqSignedIn, Index)
	r.Get("/plugins/:id/edit", reqSignedIn, Index)
	r.Get("/plugins/:id/page/:page", reqSignedIn, Index)

	r.Get("/dashboard/*", reqSignedIn, Index)
	r.Get("/dashboard-solo/*", reqSignedIn, Index)
	r.Get("/import/dashboard", reqSignedIn, Index)
	r.Get("/dashboards/*", reqSignedIn, Index)

	r.Get("/playlists/", reqSignedIn, Index)
	r.Get("/playlists/*", reqSignedIn, Index)
	r.Get("/alerting/", reqSignedIn, Index)
	r.Get("/alerting/*", reqSignedIn, Index)

	// sign up
	r.Get("/signup", Index)
	r.Get("/api/user/signup/options", wrap(GetSignUpOptions))
	r.Post("/api/user/signup", quota("user"), bind(dtos.SignUpForm{}), wrap(SignUp))
	r.Post("/api/user/signup/step2", bind(dtos.SignUpStep2Form{}), wrap(SignUpStep2))

	// invited
	r.Get("/api/user/invite/:code", wrap(GetInviteInfoByCode))
	r.Post("/api/user/invite/complete", bind(dtos.CompleteInviteForm{}), wrap(CompleteInvite))

	// reset password
	r.Get("/user/password/send-reset-email", Index)
	r.Get("/user/password/reset", Index)

	r.Post("/api/user/password/send-reset-email", bind(dtos.SendResetPasswordEmailForm{}), wrap(SendResetPasswordEmail))
	r.Post("/api/user/password/reset", bind(dtos.ResetUserPasswordForm{}), wrap(ResetPassword))

	// dashboard snapshots
	r.Get("/dashboard/snapshot/*", Index)
	r.Get("/dashboard/snapshots/", reqSignedIn, Index)

	// api for dashboard snapshots
	r.Post("/api/snapshots/", bind(m.CreateDashboardSnapshotCommand{}), CreateDashboardSnapshot)
	r.Get("/api/snapshot/shared-options/", GetSharingOptions)
	r.Get("/api/snapshots/:key", GetDashboardSnapshot)
	r.Get("/api/snapshots-delete/:key", reqEditorRole, DeleteDashboardSnapshot)

	// api renew session based on remember cookie
	r.Get("/api/login/ping", quota("session"), LoginApiPing)

	// authed api
	r.Group("/api", func() {

		// user (signed in)
		r.Group("/user", func() {
			r.Get("/", wrap(GetSignedInUser))
			r.Put("/", bind(m.UpdateUserCommand{}), wrap(UpdateSignedInUser))
			r.Post("/using/:id", wrap(UserSetUsingOrg))
			r.Get("/orgs", wrap(GetSignedInUserOrgList))

			r.Post("/stars/dashboard/:id", wrap(StarDashboard))
			r.Delete("/stars/dashboard/:id", wrap(UnstarDashboard))

			r.Put("/password", bind(m.ChangeUserPasswordCommand{}), wrap(ChangeUserPassword))
			r.Get("/quotas", wrap(GetUserQuotas))

			r.Get("/preferences", wrap(GetUserPreferences))
			r.Put("/preferences", bind(dtos.UpdatePrefsCmd{}), wrap(UpdateUserPreferences))
		})

		// users (admin permission required)
		r.Group("/users", func() {
			r.Get("/", wrap(SearchUsers))
			r.Get("/:id", wrap(GetUserById))
			r.Get("/:id/orgs", wrap(GetUserOrgList))
			r.Put("/:id", bind(m.UpdateUserCommand{}), wrap(UpdateUser))
			r.Post("/:id/using/:orgId", wrap(UpdateUserActiveOrg))
		}, reqGrafanaAdmin)

		// org information available to all users.
		r.Group("/org", func() {
			r.Get("/", wrap(GetOrgCurrent))
			r.Get("/quotas", wrap(GetOrgQuotas))
		})

		// current org
		r.Group("/org", func() {
			r.Put("/", bind(dtos.UpdateOrgForm{}), wrap(UpdateOrgCurrent))
			r.Put("/address", bind(dtos.UpdateOrgAddressForm{}), wrap(UpdateOrgAddressCurrent))
			r.Post("/users", quota("user"), bind(m.AddOrgUserCommand{}), wrap(AddOrgUserToCurrentOrg))
			r.Get("/users", wrap(GetOrgUsersForCurrentOrg))
			r.Patch("/users/:userId", bind(m.UpdateOrgUserCommand{}), wrap(UpdateOrgUserForCurrentOrg))
			r.Delete("/users/:userId", wrap(RemoveOrgUserForCurrentOrg))

			// invites
			r.Get("/invites", wrap(GetPendingOrgInvites))
			r.Post("/invites", quota("user"), bind(dtos.AddInviteForm{}), wrap(AddOrgInvite))
			r.Patch("/invites/:code/revoke", wrap(RevokeInvite))

			// prefs
			r.Get("/preferences", wrap(GetOrgPreferences))
			r.Put("/preferences", bind(dtos.UpdatePrefsCmd{}), wrap(UpdateOrgPreferences))
		}, reqOrgAdmin)

		// create new org
		r.Post("/orgs", quota("org"), bind(m.CreateOrgCommand{}), wrap(CreateOrg))

		// search all orgs
		r.Get("/orgs", reqGrafanaAdmin, wrap(SearchOrgs))

		// orgs (admin routes)
		r.Group("/orgs/:orgId", func() {
			r.Get("/", wrap(GetOrgById))
			r.Put("/", bind(dtos.UpdateOrgForm{}), wrap(UpdateOrg))
			r.Put("/address", bind(dtos.UpdateOrgAddressForm{}), wrap(UpdateOrgAddress))
			r.Delete("/", wrap(DeleteOrgById))
			r.Get("/users", wrap(GetOrgUsers))
			r.Post("/users", bind(m.AddOrgUserCommand{}), wrap(AddOrgUser))
			r.Patch("/users/:userId", bind(m.UpdateOrgUserCommand{}), wrap(UpdateOrgUser))
			r.Delete("/users/:userId", wrap(RemoveOrgUser))
			r.Get("/quotas", wrap(GetOrgQuotas))
			r.Put("/quotas/:target", bind(m.UpdateOrgQuotaCmd{}), wrap(UpdateOrgQuota))
		}, reqGrafanaAdmin)

		// orgs (admin routes)
		r.Group("/orgs/name/:name", func() {
			r.Get("/", wrap(GetOrgByName))
		}, reqGrafanaAdmin)

		// auth api keys
		r.Group("/auth/keys", func() {
			r.Get("/", wrap(GetApiKeys))
			r.Post("/", quota("api_key"), bind(m.AddApiKeyCommand{}), wrap(AddApiKey))
			r.Delete("/:id", wrap(DeleteApiKey))
		}, reqOrgAdmin)

		// Preferences
		r.Group("/preferences", func() {
			r.Post("/set-home-dash", bind(m.SavePreferencesCommand{}), wrap(SetHomeDashboard))
		})

		// Data sources
		r.Group("/datasources", func() {
			r.Get("/", GetDataSources)
			r.Post("/", quota("data_source"), bind(m.AddDataSourceCommand{}), AddDataSource)
			r.Put("/:id", bind(m.UpdateDataSourceCommand{}), UpdateDataSource)
			r.Delete("/:id", DeleteDataSource)
			r.Get("/:id", wrap(GetDataSourceById))
			r.Get("/name/:name", wrap(GetDataSourceByName))
		}, reqOrgAdmin)

		r.Get("/datasources/id/:name", wrap(GetDataSourceIdByName), reqSignedIn)

		r.Get("/plugins", wrap(GetPluginList))
		r.Get("/plugins/:pluginId/settings", wrap(GetPluginSettingById))

		r.Group("/plugins", func() {
			r.Get("/:pluginId/readme", wrap(GetPluginReadme))
			r.Get("/:pluginId/dashboards/", wrap(GetPluginDashboards))
			r.Post("/:pluginId/settings", bind(m.UpdatePluginSettingCmd{}), wrap(UpdatePluginSetting))
		}, reqOrgAdmin)

		r.Get("/frontend/settings/", GetFrontendSettings)
		r.Any("/datasources/proxy/:id/*", reqSignedIn, ProxyDataSourceRequest)
		r.Any("/datasources/proxy/:id", reqSignedIn, ProxyDataSourceRequest)

		// Dashboard
		r.Group("/dashboards", func() {
			r.Combo("/db/:slug").Get(GetDashboard).Delete(DeleteDashboard)
			r.Post("/db", reqEditorRole, bind(m.SaveDashboardCommand{}), wrap(PostDashboard))
			r.Get("/file/:file", GetDashboardFromJsonFile)
			r.Get("/home", wrap(GetHomeDashboard))
			r.Get("/tags", GetDashboardTags)
			r.Post("/import", bind(dtos.ImportDashboardCommand{}), wrap(ImportDashboard))
		})

		// Dashboard snapshots
		r.Group("/dashboard/snapshots", func() {
			r.Get("/", wrap(SearchDashboardSnapshots))
		})

		// Playlist
		r.Group("/playlists", func() {
			r.Get("/", wrap(SearchPlaylists))
			r.Get("/:id", ValidateOrgPlaylist, wrap(GetPlaylist))
			r.Get("/:id/items", ValidateOrgPlaylist, wrap(GetPlaylistItems))
			r.Get("/:id/dashboards", ValidateOrgPlaylist, wrap(GetPlaylistDashboards))
			r.Delete("/:id", reqEditorRole, ValidateOrgPlaylist, wrap(DeletePlaylist))
			r.Put("/:id", reqEditorRole, bind(m.UpdatePlaylistCommand{}), ValidateOrgPlaylist, wrap(UpdatePlaylist))
			r.Post("/", reqEditorRole, bind(m.CreatePlaylistCommand{}), wrap(CreatePlaylist))
		})

		// Search
		r.Get("/search/", Search)

		// metrics
		r.Get("/metrics/test", wrap(GetTestMetrics))

		// metrics
		r.Get("/metrics", wrap(GetInternalMetrics))

		r.Group("/alerts", func() {
			r.Post("/test", bind(dtos.AlertTestCommand{}), wrap(AlertTest))
			//r.Get("/:alertId/states", wrap(GetAlertStates))
			//r.Put("/:alertId/state", bind(m.UpdateAlertStateCommand{}), wrap(PutAlertState))
			r.Get("/:alertId", ValidateOrgAlert, wrap(GetAlert))
			//r.Delete("/:alertId", ValidateOrgAlert, wrap(DelAlert)) disabled until we know how to handle it dashboard updates
			r.Get("/", wrap(GetAlerts))
		})

		r.Get("/alert-notifications", wrap(GetAlertNotifications))

		r.Group("/alert-notifications", func() {
			r.Post("/", bind(m.CreateAlertNotificationCommand{}), wrap(CreateAlertNotification))
			r.Put("/:notificationId", bind(m.UpdateAlertNotificationCommand{}), wrap(UpdateAlertNotification))
			r.Get("/:notificationId", wrap(GetAlertNotificationById))
			r.Delete("/:notificationId", wrap(DeleteAlertNotification))
		}, reqOrgAdmin)

		// error test
		r.Get("/metrics/error", wrap(GenerateError))

	}, reqSignedIn)

	// admin api
	r.Group("/api/admin", func() {
		r.Get("/settings", AdminGetSettings)
		r.Post("/users", bind(dtos.AdminCreateUserForm{}), AdminCreateUser)
		r.Put("/users/:id/password", bind(dtos.AdminUpdateUserPasswordForm{}), AdminUpdateUserPassword)
		r.Put("/users/:id/permissions", bind(dtos.AdminUpdateUserPermissionsForm{}), AdminUpdateUserPermissions)
		r.Delete("/users/:id", AdminDeleteUser)
		r.Get("/users/:id/quotas", wrap(GetUserQuotas))
		r.Put("/users/:id/quotas/:target", bind(m.UpdateUserQuotaCmd{}), wrap(UpdateUserQuota))
		r.Get("/stats", AdminGetStats)
	}, reqGrafanaAdmin)

	// rendering
	r.Get("/render/*", reqSignedIn, RenderToPng)

	// grafana.net proxy
	r.Any("/api/gnet/*", reqSignedIn, ProxyGnetRequest)

	// Gravatar service.
	avt := avatar.CacheServer()
	r.Get("/avatar/:hash", avt.ServeHTTP)

	// Websocket
	liveConn := live.New()
	r.Any("/ws", liveConn.Serve)

	// streams
	r.Post("/api/streams/push", reqSignedIn, bind(dtos.StreamMessage{}), liveConn.PushToStream)

	InitAppPluginRoutes(r)

}
<commit_msg>chore(api): remove commented endpoints<commit_after>package api

import (
	"github.com/go-macaron/binding"
	"github.com/grafana/grafana/pkg/api/avatar"
	"github.com/grafana/grafana/pkg/api/dtos"
	"github.com/grafana/grafana/pkg/api/live"
	"github.com/grafana/grafana/pkg/middleware"
	m "github.com/grafana/grafana/pkg/models"
	"gopkg.in/macaron.v1"
)

// Register adds http routes
func Register(r *macaron.Macaron) {
	reqSignedIn := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true})
	reqGrafanaAdmin := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true, ReqGrafanaAdmin: true})
	reqEditorRole := middleware.RoleAuth(m.ROLE_EDITOR, m.ROLE_ADMIN)
	reqOrgAdmin := middleware.RoleAuth(m.ROLE_ADMIN)
	quota := middleware.Quota
	bind := binding.Bind

	// not logged in views
	r.Get("/", reqSignedIn, Index)
	r.Get("/logout", Logout)
	r.Post("/login", quota("session"), bind(dtos.LoginCommand{}), wrap(LoginPost))
	r.Get("/login/:name", quota("session"), OAuthLogin)
	r.Get("/login", LoginView)
	r.Get("/invite/:code", Index)

	// authed views
	r.Get("/profile/", reqSignedIn, Index)
	r.Get("/profile/password", reqSignedIn, Index)
	r.Get("/profile/switch-org/:id", reqSignedIn, ChangeActiveOrgAndRedirectToHome)
	r.Get("/org/", reqSignedIn, Index)
	r.Get("/org/new", reqSignedIn, Index)
	r.Get("/datasources/", reqSignedIn, Index)
	r.Get("/datasources/new", reqSignedIn, Index)
	r.Get("/datasources/edit/*", reqSignedIn, Index)
	r.Get("/org/users/", reqSignedIn, Index)
	r.Get("/org/apikeys/", reqSignedIn, Index)
	r.Get("/dashboard/import/", reqSignedIn, Index)
	r.Get("/admin", reqGrafanaAdmin, Index)
	r.Get("/admin/settings", reqGrafanaAdmin, Index)
	r.Get("/admin/users", reqGrafanaAdmin, Index)
	r.Get("/admin/users/create", reqGrafanaAdmin, Index)
	r.Get("/admin/users/edit/:id", reqGrafanaAdmin, Index)
	r.Get("/admin/orgs", reqGrafanaAdmin, Index)
	r.Get("/admin/orgs/edit/:id", reqGrafanaAdmin, Index)
	r.Get("/admin/stats", reqGrafanaAdmin, Index)

	r.Get("/styleguide", reqSignedIn, Index)

	r.Get("/plugins", reqSignedIn, Index)
	r.Get("/plugins/:id/edit", reqSignedIn, Index)
	r.Get("/plugins/:id/page/:page", reqSignedIn, Index)

	r.Get("/dashboard/*", reqSignedIn, Index)
	r.Get("/dashboard-solo/*", reqSignedIn, Index)
	r.Get("/import/dashboard", reqSignedIn, Index)
	r.Get("/dashboards/*", reqSignedIn, Index)

	r.Get("/playlists/", reqSignedIn, Index)
	r.Get("/playlists/*", reqSignedIn, Index)
	r.Get("/alerting/", reqSignedIn, Index)
	r.Get("/alerting/*", reqSignedIn, Index)

	// sign up
	r.Get("/signup", Index)
	r.Get("/api/user/signup/options", wrap(GetSignUpOptions))
	r.Post("/api/user/signup", quota("user"), bind(dtos.SignUpForm{}), wrap(SignUp))
	r.Post("/api/user/signup/step2", bind(dtos.SignUpStep2Form{}), wrap(SignUpStep2))

	// invited
	r.Get("/api/user/invite/:code", wrap(GetInviteInfoByCode))
	r.Post("/api/user/invite/complete", bind(dtos.CompleteInviteForm{}), wrap(CompleteInvite))

	// reset password
	r.Get("/user/password/send-reset-email", Index)
	r.Get("/user/password/reset", Index)

	r.Post("/api/user/password/send-reset-email", bind(dtos.SendResetPasswordEmailForm{}), wrap(SendResetPasswordEmail))
	r.Post("/api/user/password/reset", bind(dtos.ResetUserPasswordForm{}), wrap(ResetPassword))

	// dashboard snapshots
	r.Get("/dashboard/snapshot/*", Index)
	r.Get("/dashboard/snapshots/", reqSignedIn, Index)

	// api for dashboard snapshots
	r.Post("/api/snapshots/", bind(m.CreateDashboardSnapshotCommand{}), CreateDashboardSnapshot)
	r.Get("/api/snapshot/shared-options/", GetSharingOptions)
	r.Get("/api/snapshots/:key", GetDashboardSnapshot)
	r.Get("/api/snapshots-delete/:key", reqEditorRole, DeleteDashboardSnapshot)

	// api renew session based on remember cookie
	r.Get("/api/login/ping", quota("session"), LoginApiPing)

	// authed api
	r.Group("/api", func() {

		// user (signed in)
		r.Group("/user", func() {
			r.Get("/", wrap(GetSignedInUser))
			r.Put("/", bind(m.UpdateUserCommand{}), wrap(UpdateSignedInUser))
			r.Post("/using/:id", wrap(UserSetUsingOrg))
			r.Get("/orgs", wrap(GetSignedInUserOrgList))

			r.Post("/stars/dashboard/:id", wrap(StarDashboard))
			r.Delete("/stars/dashboard/:id", wrap(UnstarDashboard))

			r.Put("/password", bind(m.ChangeUserPasswordCommand{}), wrap(ChangeUserPassword))
			r.Get("/quotas", wrap(GetUserQuotas))

			r.Get("/preferences", wrap(GetUserPreferences))
			r.Put("/preferences", bind(dtos.UpdatePrefsCmd{}), wrap(UpdateUserPreferences))
		})

		// users (admin permission required)
		r.Group("/users", func() {
			r.Get("/", wrap(SearchUsers))
			r.Get("/:id", wrap(GetUserById))
			r.Get("/:id/orgs", wrap(GetUserOrgList))
			r.Put("/:id", bind(m.UpdateUserCommand{}), wrap(UpdateUser))
			r.Post("/:id/using/:orgId", wrap(UpdateUserActiveOrg))
		}, reqGrafanaAdmin)

		// org information available to all users.
		r.Group("/org", func() {
			r.Get("/", wrap(GetOrgCurrent))
			r.Get("/quotas", wrap(GetOrgQuotas))
		})

		// current org
		r.Group("/org", func() {
			r.Put("/", bind(dtos.UpdateOrgForm{}), wrap(UpdateOrgCurrent))
			r.Put("/address", bind(dtos.UpdateOrgAddressForm{}), wrap(UpdateOrgAddressCurrent))
			r.Post("/users", quota("user"), bind(m.AddOrgUserCommand{}), wrap(AddOrgUserToCurrentOrg))
			r.Get("/users", wrap(GetOrgUsersForCurrentOrg))
			r.Patch("/users/:userId", bind(m.UpdateOrgUserCommand{}), wrap(UpdateOrgUserForCurrentOrg))
			r.Delete("/users/:userId", wrap(RemoveOrgUserForCurrentOrg))

			// invites
			r.Get("/invites", wrap(GetPendingOrgInvites))
			r.Post("/invites", quota("user"), bind(dtos.AddInviteForm{}), wrap(AddOrgInvite))
			r.Patch("/invites/:code/revoke", wrap(RevokeInvite))

			// prefs
			r.Get("/preferences", wrap(GetOrgPreferences))
			r.Put("/preferences", bind(dtos.UpdatePrefsCmd{}), wrap(UpdateOrgPreferences))
		}, reqOrgAdmin)

		// create new org
		r.Post("/orgs", quota("org"), bind(m.CreateOrgCommand{}), wrap(CreateOrg))

		// search all orgs
		r.Get("/orgs", reqGrafanaAdmin, wrap(SearchOrgs))

		// orgs (admin routes)
		r.Group("/orgs/:orgId", func() {
			r.Get("/", wrap(GetOrgById))
			r.Put("/", bind(dtos.UpdateOrgForm{}), wrap(UpdateOrg))
			r.Put("/address", bind(dtos.UpdateOrgAddressForm{}), wrap(UpdateOrgAddress))
			r.Delete("/", wrap(DeleteOrgById))
			r.Get("/users", wrap(GetOrgUsers))
			r.Post("/users", bind(m.AddOrgUserCommand{}), wrap(AddOrgUser))
			r.Patch("/users/:userId", bind(m.UpdateOrgUserCommand{}), wrap(UpdateOrgUser))
			r.Delete("/users/:userId", wrap(RemoveOrgUser))
			r.Get("/quotas", wrap(GetOrgQuotas))
			r.Put("/quotas/:target", bind(m.UpdateOrgQuotaCmd{}), wrap(UpdateOrgQuota))
		}, reqGrafanaAdmin)

		// orgs (admin routes)
		r.Group("/orgs/name/:name", func() {
			r.Get("/", wrap(GetOrgByName))
		}, reqGrafanaAdmin)

		// auth api keys
		r.Group("/auth/keys", func() {
			r.Get("/", wrap(GetApiKeys))
			r.Post("/", quota("api_key"), bind(m.AddApiKeyCommand{}), wrap(AddApiKey))
			r.Delete("/:id", wrap(DeleteApiKey))
		}, reqOrgAdmin)

		// Preferences
		r.Group("/preferences", func() {
			r.Post("/set-home-dash", bind(m.SavePreferencesCommand{}), wrap(SetHomeDashboard))
		})

		// Data sources
		r.Group("/datasources", func() {
			r.Get("/", GetDataSources)
			r.Post("/", quota("data_source"), bind(m.AddDataSourceCommand{}), AddDataSource)
			r.Put("/:id", bind(m.UpdateDataSourceCommand{}), UpdateDataSource)
			r.Delete("/:id", DeleteDataSource)
			r.Get("/:id", wrap(GetDataSourceById))
			r.Get("/name/:name", wrap(GetDataSourceByName))
		}, reqOrgAdmin)

		r.Get("/datasources/id/:name", wrap(GetDataSourceIdByName), reqSignedIn)

		r.Get("/plugins", wrap(GetPluginList))
		r.Get("/plugins/:pluginId/settings", wrap(GetPluginSettingById))

		r.Group("/plugins", func() {
			r.Get("/:pluginId/readme", wrap(GetPluginReadme))
			r.Get("/:pluginId/dashboards/", wrap(GetPluginDashboards))
			r.Post("/:pluginId/settings", bind(m.UpdatePluginSettingCmd{}), wrap(UpdatePluginSetting))
		}, reqOrgAdmin)

		r.Get("/frontend/settings/", GetFrontendSettings)
		r.Any("/datasources/proxy/:id/*", reqSignedIn, ProxyDataSourceRequest)
		r.Any("/datasources/proxy/:id", reqSignedIn, ProxyDataSourceRequest)

		// Dashboard
		r.Group("/dashboards", func() {
			r.Combo("/db/:slug").Get(GetDashboard).Delete(DeleteDashboard)
			r.Post("/db", reqEditorRole, bind(m.SaveDashboardCommand{}), wrap(PostDashboard))
			r.Get("/file/:file", GetDashboardFromJsonFile)
			r.Get("/home", wrap(GetHomeDashboard))
			r.Get("/tags", GetDashboardTags)
			r.Post("/import", bind(dtos.ImportDashboardCommand{}), wrap(ImportDashboard))
		})

		// Dashboard snapshots
		r.Group("/dashboard/snapshots", func() {
			r.Get("/", wrap(SearchDashboardSnapshots))
		})

		// Playlist
		r.Group("/playlists", func() {
			r.Get("/", wrap(SearchPlaylists))
			r.Get("/:id", ValidateOrgPlaylist, wrap(GetPlaylist))
			r.Get("/:id/items", ValidateOrgPlaylist, wrap(GetPlaylistItems))
			r.Get("/:id/dashboards", ValidateOrgPlaylist, wrap(GetPlaylistDashboards))
			r.Delete("/:id", reqEditorRole, ValidateOrgPlaylist, wrap(DeletePlaylist))
			r.Put("/:id", reqEditorRole, bind(m.UpdatePlaylistCommand{}), ValidateOrgPlaylist, wrap(UpdatePlaylist))
			r.Post("/", reqEditorRole, bind(m.CreatePlaylistCommand{}), wrap(CreatePlaylist))
		})

		// Search
		r.Get("/search/", Search)

		// metrics
		r.Get("/metrics/test", wrap(GetTestMetrics))

		// metrics
		r.Get("/metrics", wrap(GetInternalMetrics))

		r.Group("/alerts", func() {
			r.Post("/test", bind(dtos.AlertTestCommand{}), wrap(AlertTest))
			//r.Get("/:alertId/states", wrap(GetAlertStates))
			r.Get("/:alertId", ValidateOrgAlert, wrap(GetAlert))
			r.Get("/", wrap(GetAlerts))
		})

		r.Get("/alert-notifications", wrap(GetAlertNotifications))

		r.Group("/alert-notifications", func() {
			r.Post("/", bind(m.CreateAlertNotificationCommand{}), wrap(CreateAlertNotification))
			r.Put("/:notificationId", bind(m.UpdateAlertNotificationCommand{}), wrap(UpdateAlertNotification))
			r.Get("/:notificationId", wrap(GetAlertNotificationById))
			r.Delete("/:notificationId", wrap(DeleteAlertNotification))
		}, reqOrgAdmin)

		// error test
		r.Get("/metrics/error", wrap(GenerateError))

	}, reqSignedIn)

	// admin api
	r.Group("/api/admin", func() {
		r.Get("/settings", AdminGetSettings)
		r.Post("/users", bind(dtos.AdminCreateUserForm{}), AdminCreateUser)
		r.Put("/users/:id/password", bind(dtos.AdminUpdateUserPasswordForm{}), AdminUpdateUserPassword)
		r.Put("/users/:id/permissions", bind(dtos.AdminUpdateUserPermissionsForm{}), AdminUpdateUserPermissions)
		r.Delete("/users/:id", AdminDeleteUser)
		r.Get("/users/:id/quotas", wrap(GetUserQuotas))
		r.Put("/users/:id/quotas/:target", bind(m.UpdateUserQuotaCmd{}), wrap(UpdateUserQuota))
		r.Get("/stats", AdminGetStats)
	}, reqGrafanaAdmin)

	// rendering
	r.Get("/render/*", reqSignedIn, RenderToPng)

	// grafana.net proxy
	r.Any("/api/gnet/*", reqSignedIn, ProxyGnetRequest)

	// Gravatar service.
	avt := avatar.CacheServer()
	r.Get("/avatar/:hash", avt.ServeHTTP)

	// Websocket
	liveConn := live.New()
	r.Any("/ws", liveConn.Serve)

	// streams
	r.Post("/api/streams/push", reqSignedIn, bind(dtos.StreamMessage{}), liveConn.PushToStream)

	InitAppPluginRoutes(r)

}
<|endoftext|>


<commit_before>// Copyright (c) 2020, the Drone Plugins project authors.
// Please see the AUTHORS file for details. All rights reserved.
// Use of this source code is governed by an Apache 2.0 license that can be
// found in the LICENSE file.

package plugin

import (
	"context"
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/drone/drone-go/drone"
	"github.com/joho/godotenv"
	"github.com/urfave/cli/v2"
	"golang.org/x/oauth2"
)

// Settings for the plugin.
type Settings struct {
	Repos          cli.StringSlice
	Server         string
	Token          string
	Wait           bool
	Timeout        time.Duration
	LastSuccessful bool
	Params         cli.StringSlice
	ParamsEnv      cli.StringSlice
	Deploy         string

	server string
	params map[string]string
}

var (
	errBuildNotFound = fmt.Errorf("build not found")
)

// Validate handles the settings validation of the plugin.
func (p *Plugin) Validate() error {
	if len(p.settings.Token) == 0 {
		return fmt.Errorf("you must provide your drone access token")
	}

	p.settings.server = getServerWithDefaults(p.settings.Server, p.pipeline.System.Host, p.pipeline.System.Proto)
	if len(p.settings.server) == 0 {
		return fmt.Errorf("you must provide your drone server")
	}

	if p.settings.Wait && p.settings.LastSuccessful {
		return fmt.Errorf("only one of wait and last_successful can be true; choose one")
	}

	var err error
	p.settings.params, err = parseParams(p.settings.Params.Value())
	if err != nil {
		return fmt.Errorf("unable to parse params: %s", err)
	}

	for _, k := range p.settings.ParamsEnv.Value() {
		v, exists := os.LookupEnv(k)
		if !exists {
			return fmt.Errorf("param_from_env %s is not set", k)
		}

		p.settings.params[k] = v
	}

	return nil
}

func findFirstBuild(client drone.Client, owner, name string, cond func(*drone.Build) bool) (*drone.Build, error) {
	const pageSize = 50

	for page := 0; ; page++ {

		builds, err := client.BuildList(owner, name, drone.ListOptions{
			Page: page,
			Size: pageSize,
		})

		if err != nil {
			return nil, fmt.Errorf("unable to get build list: %w", err)
		}

		for _, b := range builds {
			if cond(b) {
				return b, nil
			}
		}

		if len(builds) < pageSize {
			// we received less items than asked, it means there are no more builds
			break
		}
	}
	return nil, errBuildNotFound
}

// Execute provides the implementation of the plugin.
func (p *Plugin) Execute() error {
	config := new(oauth2.Config)

	auther := config.Client(
		context.WithValue(context.Background(), oauth2.HTTPClient, p.network.Client),
		&oauth2.Token{
			AccessToken: p.settings.Token,
		},
	)

	client := drone.NewClient(p.settings.server, auther)

	for _, entry := range p.settings.Repos.Value() {

		// parses the repository name in owner/name@branch format
		owner, name, branch := parseRepoBranch(entry)
		if len(owner) == 0 || len(name) == 0 {
			return fmt.Errorf("unable to parse repository name %s", entry)
		}

		// check for mandatory build no during deploy trigger
		if len(p.settings.Deploy) != 0 {
			if branch == "" {
				return fmt.Errorf("build no or branch must be mentioned for deploy, format repository@build/branch")
			}
			if _, err := strconv.Atoi(branch); err != nil && !p.settings.LastSuccessful {
				return fmt.Errorf("for deploy build no must be numeric only " +
					" or for branch deploy last_successful should be true," +
					" format repository@build/branch")
			}
		}

		waiting := false

		timeout := time.After(p.settings.Timeout)
		//lint:ignore SA1015 refactor later
		tick := time.Tick(1 * time.Second)

		var err error

		// Keep trying until we're timed out, successful or got an error
		// Tagged with "I" due to break nested in select
	I:
		for {
			select {
			// Got a timeout! fail with a timeout error
			case <-timeout:
				return fmt.Errorf("timed out waiting on a build for %s", entry)
			// Got a tick, we should check on the build status
			case <-tick:
				// first handle the deploy trigger
				if len(p.settings.Deploy) != 0 {
					var build *drone.Build
					if p.settings.LastSuccessful {
						// Get the last successful build of branch
						build, err = findFirstBuild(client, owner, name, func(b *drone.Build) bool {
							return b.Source == branch && b.Status == drone.StatusPassing
						})

						if err != nil {
							return fmt.Errorf("unable to get last successful build for %s: %w", entry, err)
						}
					} else {
						// Get build by number
						buildNumber, _ := strconv.Atoi(branch)
						build, err = client.Build(owner, name, buildNumber)
						if err != nil {
							return fmt.Errorf("unable to get requested build %v for deploy for %s", buildNumber, entry)
						}
					}
					if p.settings.Wait && !waiting && (build.Status == drone.StatusRunning || build.Status == drone.StatusPending) {
						fmt.Printf("BuildLast for repository: %s, returned build number: %v with a status of %s. Will retry for %v.\n", entry, build.Number, build.Status, p.settings.Timeout)
						waiting = true
						continue
					}
					if (build.Status != drone.StatusRunning && build.Status != drone.StatusPending) || !p.settings.Wait {
						// start a new deploy
						_, err = client.Promote(owner, name, int(build.Number), p.settings.Deploy, p.settings.params)
						if err != nil {
							if waiting {
								continue
							}
							return fmt.Errorf("unable to trigger deploy for %s - err %v", entry, err)
						}
						fmt.Printf("starting deploy for %s/%s env - %s build - %d", owner, name, p.settings.Deploy, build.Number)
						logParams(p.settings.params, p.settings.ParamsEnv.Value())
						break I
					}
				}

				// get the latest build for the specified repository
				build, err := client.BuildLast(owner, name, branch)
				if err != nil {
					if waiting {
						continue
					}
					return fmt.Errorf("unable to get latest build for %s: %s", entry, err)
				}
				if p.settings.Wait && !waiting && (build.Status == drone.StatusRunning || build.Status == drone.StatusPending) {
					fmt.Printf("BuildLast for repository: %s, returned build number: %v with a status of %s. Will retry for %v.\n", entry, build.Number, build.Status, p.settings.Timeout)
					waiting = true
					continue
				} else if p.settings.LastSuccessful && build.Status != drone.StatusPassing {

					build, err = findFirstBuild(client, owner, name, func(b *drone.Build) bool {
						return b.Source == branch && b.Status == drone.StatusPassing
					})

					if err != nil {
						return fmt.Errorf("unable to get last successful build for %s: %w", entry, err)
					}
				}

				if (build.Status != drone.StatusRunning && build.Status != drone.StatusPending) || !p.settings.Wait {
					// rebuild the latest build
					_, err = client.BuildRestart(owner, name, int(build.Number), p.settings.params)
					if err != nil {
						if waiting {
							continue
						}
						return fmt.Errorf("unable to trigger build for %s", entry)
					}
					fmt.Printf("Restarting build %d for %s\n", build.Number, entry)
					logParams(p.settings.params, p.settings.ParamsEnv.Value())

					break I
				}
			}
		}
	}

	return nil
}

func parseRepoBranch(repo string) (string, string, string) {
	var (
		owner  string
		name   string
		branch string
	)

	parts := strings.Split(repo, "@")
	if len(parts) == 2 {
		branch = parts[1]
		repo = parts[0]
	}

	parts = strings.Split(repo, "/")
	if len(parts) == 2 {
		owner = parts[0]
		name = parts[1]
	}
	return owner, name, branch
}

func parseParams(paramList []string) (map[string]string, error) {
	params := make(map[string]string)
	for _, p := range paramList {
		parts := strings.SplitN(p, "=", 2)
		if len(parts) == 2 {
			params[parts[0]] = parts[1]
		} else if _, err := os.Stat(parts[0]); os.IsNotExist(err) {
			return nil, fmt.Errorf(
				"invalid param '%s'; must be KEY=VALUE or file path",
				parts[0],
			)
		} else {
			fileParams, err := godotenv.Read(parts[0])
			if err != nil {
				return nil, err
			}

			for k, v := range fileParams {
				params[k] = v
			}
		}
	}

	return params, nil
}

func logParams(params map[string]string, paramsEnv []string) {
	if len(params) > 0 {
		fmt.Println("  with params:")
		for k, v := range params {
			fromEnv := false
			for _, e := range paramsEnv {
				if k == e {
					fromEnv = true
					break
				}
			}
			if fromEnv {
				v = "[from-environment]"
			}
			fmt.Printf("  - %s: %s\n", k, v)
		}
	}
}

func getServerWithDefaults(server string, host string, protocol string) string {
	if len(server) != 0 {
		return server
	}

	if len(host) == 0 || len(protocol) == 0 {
		return ""
	}

	return fmt.Sprintf("%s://%s", protocol, host)
}
<commit_msg>fix: filtering condition (#80)<commit_after>// Copyright (c) 2020, the Drone Plugins project authors.
// Please see the AUTHORS file for details. All rights reserved.
// Use of this source code is governed by an Apache 2.0 license that can be
// found in the LICENSE file.

package plugin

import (
	"context"
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/drone/drone-go/drone"
	"github.com/joho/godotenv"
	"github.com/urfave/cli/v2"
	"golang.org/x/oauth2"
)

// Settings for the plugin.
type Settings struct {
	Repos          cli.StringSlice
	Server         string
	Token          string
	Wait           bool
	Timeout        time.Duration
	LastSuccessful bool
	Params         cli.StringSlice
	ParamsEnv      cli.StringSlice
	Deploy         string

	server string
	params map[string]string
}

var (
	errBuildNotFound = fmt.Errorf("build not found")
)

// Validate handles the settings validation of the plugin.
func (p *Plugin) Validate() error {
	if len(p.settings.Token) == 0 {
		return fmt.Errorf("you must provide your drone access token")
	}

	p.settings.server = getServerWithDefaults(p.settings.Server, p.pipeline.System.Host, p.pipeline.System.Proto)
	if len(p.settings.server) == 0 {
		return fmt.Errorf("you must provide your drone server")
	}

	if p.settings.Wait && p.settings.LastSuccessful {
		return fmt.Errorf("only one of wait and last_successful can be true; choose one")
	}

	var err error
	p.settings.params, err = parseParams(p.settings.Params.Value())
	if err != nil {
		return fmt.Errorf("unable to parse params: %s", err)
	}

	for _, k := range p.settings.ParamsEnv.Value() {
		v, exists := os.LookupEnv(k)
		if !exists {
			return fmt.Errorf("param_from_env %s is not set", k)
		}

		p.settings.params[k] = v
	}

	return nil
}

func findFirstBuild(client drone.Client, owner, name string, cond func(*drone.Build) bool) (*drone.Build, error) {
	const pageSize = 50

	for page := 0; ; page++ {

		builds, err := client.BuildList(owner, name, drone.ListOptions{
			Page: page,
			Size: pageSize,
		})

		if err != nil {
			return nil, fmt.Errorf("unable to get build list: %w", err)
		}

		for _, b := range builds {
			if cond(b) {
				return b, nil
			}
		}

		if len(builds) < pageSize {
			// we received less items than asked, it means there are no more builds
			break
		}
	}
	return nil, errBuildNotFound
}

// Execute provides the implementation of the plugin.
func (p *Plugin) Execute() error {
	config := new(oauth2.Config)

	auther := config.Client(
		context.WithValue(context.Background(), oauth2.HTTPClient, p.network.Client),
		&oauth2.Token{
			AccessToken: p.settings.Token,
		},
	)

	client := drone.NewClient(p.settings.server, auther)

	for _, entry := range p.settings.Repos.Value() {

		// parses the repository name in owner/name@branch format
		owner, name, branch := parseRepoBranch(entry)
		if len(owner) == 0 || len(name) == 0 {
			return fmt.Errorf("unable to parse repository name %s", entry)
		}

		// check for mandatory build no during deploy trigger
		if len(p.settings.Deploy) != 0 {
			if branch == "" {
				return fmt.Errorf("build no or branch must be mentioned for deploy, format repository@build/branch")
			}
			if _, err := strconv.Atoi(branch); err != nil && !p.settings.LastSuccessful {
				return fmt.Errorf("for deploy build no must be numeric only " +
					" or for branch deploy last_successful should be true," +
					" format repository@build/branch")
			}
		}

		waiting := false

		timeout := time.After(p.settings.Timeout)
		//lint:ignore SA1015 refactor later
		tick := time.Tick(1 * time.Second)

		var err error

		// Keep trying until we're timed out, successful or got an error
		// Tagged with "I" due to break nested in select
	I:
		for {
			select {
			// Got a timeout! fail with a timeout error
			case <-timeout:
				return fmt.Errorf("timed out waiting on a build for %s", entry)
			// Got a tick, we should check on the build status
			case <-tick:
				// first handle the deploy trigger
				if len(p.settings.Deploy) != 0 {
					var build *drone.Build
					if p.settings.LastSuccessful {
						// Get the last successful build of branch
						build, err = findFirstBuild(client, owner, name, func(b *drone.Build) bool {
							return b.Source == branch && b.Status == drone.StatusPassing && b.Event == "push"
						})

						if err != nil {
							return fmt.Errorf("unable to get last successful build for %s: %w", entry, err)
						}
					} else {
						// Get build by number
						buildNumber, _ := strconv.Atoi(branch)
						build, err = client.Build(owner, name, buildNumber)
						if err != nil {
							return fmt.Errorf("unable to get requested build %v for deploy for %s", buildNumber, entry)
						}
					}
					if p.settings.Wait && !waiting && (build.Status == drone.StatusRunning || build.Status == drone.StatusPending) {
						fmt.Printf("BuildLast for repository: %s, returned build number: %v with a status of %s. Will retry for %v.\n", entry, build.Number, build.Status, p.settings.Timeout)
						waiting = true
						continue
					}
					if (build.Status != drone.StatusRunning && build.Status != drone.StatusPending) || !p.settings.Wait {
						// start a new deploy
						_, err = client.Promote(owner, name, int(build.Number), p.settings.Deploy, p.settings.params)
						if err != nil {
							if waiting {
								continue
							}
							return fmt.Errorf("unable to trigger deploy for %s - err %v", entry, err)
						}
						fmt.Printf("starting deploy for %s/%s env - %s build - %d", owner, name, p.settings.Deploy, build.Number)
						logParams(p.settings.params, p.settings.ParamsEnv.Value())
						break I
					}
				}

				// get the latest build for the specified repository
				build, err := client.BuildLast(owner, name, branch)
				if err != nil {
					if waiting {
						continue
					}
					return fmt.Errorf("unable to get latest build for %s: %s", entry, err)
				}
				if p.settings.Wait && !waiting && (build.Status == drone.StatusRunning || build.Status == drone.StatusPending) {
					fmt.Printf("BuildLast for repository: %s, returned build number: %v with a status of %s. Will retry for %v.\n", entry, build.Number, build.Status, p.settings.Timeout)
					waiting = true
					continue
				} else if p.settings.LastSuccessful && build.Status != drone.StatusPassing {

					build, err = findFirstBuild(client, owner, name, func(b *drone.Build) bool {
						return b.Source == branch && b.Status == drone.StatusPassing && b.Event == "push"
					})

					if err != nil {
						return fmt.Errorf("unable to get last successful build for %s: %w", entry, err)
					}
				}

				if (build.Status != drone.StatusRunning && build.Status != drone.StatusPending) || !p.settings.Wait {
					// rebuild the latest build
					_, err = client.BuildRestart(owner, name, int(build.Number), p.settings.params)
					if err != nil {
						if waiting {
							continue
						}
						return fmt.Errorf("unable to trigger build for %s", entry)
					}
					fmt.Printf("Restarting build %d for %s\n", build.Number, entry)
					logParams(p.settings.params, p.settings.ParamsEnv.Value())

					break I
				}
			}
		}
	}

	return nil
}

func parseRepoBranch(repo string) (string, string, string) {
	var (
		owner  string
		name   string
		branch string
	)

	parts := strings.Split(repo, "@")
	if len(parts) == 2 {
		branch = parts[1]
		repo = parts[0]
	}

	parts = strings.Split(repo, "/")
	if len(parts) == 2 {
		owner = parts[0]
		name = parts[1]
	}
	return owner, name, branch
}

func parseParams(paramList []string) (map[string]string, error) {
	params := make(map[string]string)
	for _, p := range paramList {
		parts := strings.SplitN(p, "=", 2)
		if len(parts) == 2 {
			params[parts[0]] = parts[1]
		} else if _, err := os.Stat(parts[0]); os.IsNotExist(err) {
			return nil, fmt.Errorf(
				"invalid param '%s'; must be KEY=VALUE or file path",
				parts[0],
			)
		} else {
			fileParams, err := godotenv.Read(parts[0])
			if err != nil {
				return nil, err
			}

			for k, v := range fileParams {
				params[k] = v
			}
		}
	}

	return params, nil
}

func logParams(params map[string]string, paramsEnv []string) {
	if len(params) > 0 {
		fmt.Println("  with params:")
		for k, v := range params {
			fromEnv := false
			for _, e := range paramsEnv {
				if k == e {
					fromEnv = true
					break
				}
			}
			if fromEnv {
				v = "[from-environment]"
			}
			fmt.Printf("  - %s: %s\n", k, v)
		}
	}
}

func getServerWithDefaults(server string, host string, protocol string) string {
	if len(server) != 0 {
		return server
	}

	if len(host) == 0 || len(protocol) == 0 {
		return ""
	}

	return fmt.Sprintf("%s://%s", protocol, host)
}
<|endoftext|>


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

package plugin

import (
	"bytes"
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/appc/cni/pkg/ip"
	"github.com/vishvananda/netlink"
)

// Find returns the full path of the plugin by searching in CNI_PATH
func Find(plugin string) string {
	paths := strings.Split(os.Getenv("CNI_PATH"), ":")

	for _, p := range paths {
		fullname := filepath.Join(p, plugin)
		if fi, err := os.Stat(fullname); err == nil && fi.Mode().IsRegular() {
			return fullname
		}
	}

	return ""
}

func pluginErr(err error, output []byte) error {
	if _, ok := err.(*exec.ExitError); ok {
		emsg := Error{}
		if perr := json.Unmarshal(output, &emsg); perr != nil {
			return fmt.Errorf("netplugin failed but error parsing its diagnostic message %q: %v", string(output), perr)
		}
		details := ""
		if emsg.Details != "" {
			details = fmt.Sprintf("; %v", emsg.Details)
		}
		return fmt.Errorf("%v%v", emsg.Msg, details)
	}

	return err
}

// ExecAdd executes IPAM plugin, assuming CNI_COMMAND == ADD.
// Parses and returns resulting IPConfig
func ExecAdd(plugin string, netconf []byte) (*Result, error) {
	if os.Getenv("CNI_COMMAND") != "ADD" {
		return nil, fmt.Errorf("CNI_COMMAND is not ADD")
	}

	pluginPath := Find(plugin)
	if pluginPath == "" {
		return nil, fmt.Errorf("could not find %q plugin", plugin)
	}

	stdout := &bytes.Buffer{}

	c := exec.Cmd{
		Path:   pluginPath,
		Args:   []string{pluginPath},
		Stdin:  bytes.NewBuffer(netconf),
		Stdout: stdout,
		Stderr: os.Stderr,
	}
	if err := c.Run(); err != nil {
		return nil, pluginErr(err, stdout.Bytes())
	}

	res := &Result{}
	err := json.Unmarshal(stdout.Bytes(), res)
	return res, err
}

// ExecDel executes IPAM plugin, assuming CNI_COMMAND == DEL.
func ExecDel(plugin string, netconf []byte) error {
	if os.Getenv("CNI_COMMAND") != "DEL" {
		return fmt.Errorf("CNI_COMMAND is not DEL")
	}

	pluginPath := Find(plugin)
	if pluginPath == "" {
		return fmt.Errorf("could not find %q plugin", plugin)
	}

	stdout := &bytes.Buffer{}

	c := exec.Cmd{
		Path:   pluginPath,
		Args:   []string{pluginPath},
		Stdin:  bytes.NewBuffer(netconf),
		Stdout: stdout,
		Stderr: os.Stderr,
	}
	if err := c.Run(); err != nil {
		return pluginErr(err, stdout.Bytes())
	}
	return nil
}

// ConfigureIface takes the result of IPAM plugin and
// applies to the ifName interface
func ConfigureIface(ifName string, res *Result) error {
	link, err := netlink.LinkByName(ifName)
	if err != nil {
		return fmt.Errorf("failed to lookup %q: %v", ifName, err)
	}

	if err := netlink.LinkSetUp(link); err != nil {
		return fmt.Errorf("failed too set %q UP: %v", ifName, err)
	}

	// TODO(eyakubovich): IPv6
	addr := &netlink.Addr{IPNet: &res.IP4.IP, Label: ""}
	if err = netlink.AddrAdd(link, addr); err != nil {
		return fmt.Errorf("failed to add IP addr to %q: %v", ifName, err)
	}

	for _, r := range res.IP4.Routes {
		gw := r.GW
		if gw == nil {
			gw = res.IP4.Gateway
		}
		if err = ip.AddRoute(&r.Dst, gw, link); err != nil {
			// we skip over duplicate routes as we assume the first one wins
			if !os.IsExist(err) {
				return fmt.Errorf("failed to add route '%v via %v dev %v': %v", r.Dst, gw, ifName, err)
			}
		}
	}

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

package plugin

import (
	"bytes"
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/appc/cni/pkg/ip"
	"github.com/vishvananda/netlink"
)

// Find returns the full path of the plugin by searching in CNI_PATH
func Find(plugin string) string {
	paths := strings.Split(os.Getenv("CNI_PATH"), ":")

	for _, p := range paths {
		fullname := filepath.Join(p, plugin)
		if fi, err := os.Stat(fullname); err == nil && fi.Mode().IsRegular() {
			return fullname
		}
	}

	return ""
}

func pluginErr(err error, output []byte) error {
	if _, ok := err.(*exec.ExitError); ok {
		emsg := Error{}
		if perr := json.Unmarshal(output, &emsg); perr != nil {
			return fmt.Errorf("netplugin failed but error parsing its diagnostic message %q: %v", string(output), perr)
		}
		details := ""
		if emsg.Details != "" {
			details = fmt.Sprintf("; %v", emsg.Details)
		}
		return fmt.Errorf("%v%v", emsg.Msg, details)
	}

	return err
}

// ExecAdd executes IPAM plugin, assuming CNI_COMMAND == ADD.
// Parses and returns resulting IPConfig
func ExecAdd(plugin string, netconf []byte) (*Result, error) {
	if os.Getenv("CNI_COMMAND") != "ADD" {
		return nil, fmt.Errorf("CNI_COMMAND is not ADD")
	}

	pluginPath := Find(plugin)
	if pluginPath == "" {
		return nil, fmt.Errorf("could not find %q plugin", plugin)
	}

	stdout := &bytes.Buffer{}

	c := exec.Cmd{
		Path:   pluginPath,
		Args:   []string{pluginPath},
		Stdin:  bytes.NewBuffer(netconf),
		Stdout: stdout,
		Stderr: os.Stderr,
	}
	if err := c.Run(); err != nil {
		return nil, pluginErr(err, stdout.Bytes())
	}

	res := &Result{}
	err := json.Unmarshal(stdout.Bytes(), res)
	return res, err
}

// ExecDel executes IPAM plugin, assuming CNI_COMMAND == DEL.
func ExecDel(plugin string, netconf []byte) error {
	if os.Getenv("CNI_COMMAND") != "DEL" {
		return fmt.Errorf("CNI_COMMAND is not DEL")
	}

	pluginPath := Find(plugin)
	if pluginPath == "" {
		return fmt.Errorf("could not find %q plugin", plugin)
	}

	stdout := &bytes.Buffer{}

	c := exec.Cmd{
		Path:   pluginPath,
		Args:   []string{pluginPath},
		Stdin:  bytes.NewBuffer(netconf),
		Stdout: stdout,
		Stderr: os.Stderr,
	}
	if err := c.Run(); err != nil {
		return pluginErr(err, stdout.Bytes())
	}
	return nil
}

// ConfigureIface takes the result of IPAM plugin and
// applies to the ifName interface
func ConfigureIface(ifName string, res *Result) error {
	link, err := netlink.LinkByName(ifName)
	if err != nil {
		return fmt.Errorf("failed to lookup %q: %v", ifName, err)
	}

	if err := netlink.LinkSetUp(link); err != nil {
		return fmt.Errorf("failed to set %q UP: %v", ifName, err)
	}

	// TODO(eyakubovich): IPv6
	addr := &netlink.Addr{IPNet: &res.IP4.IP, Label: ""}
	if err = netlink.AddrAdd(link, addr); err != nil {
		return fmt.Errorf("failed to add IP addr to %q: %v", ifName, err)
	}

	for _, r := range res.IP4.Routes {
		gw := r.GW
		if gw == nil {
			gw = res.IP4.Gateway
		}
		if err = ip.AddRoute(&r.Dst, gw, link); err != nil {
			// we skip over duplicate routes as we assume the first one wins
			if !os.IsExist(err) {
				return fmt.Errorf("failed to add route '%v via %v dev %v': %v", r.Dst, gw, ifName, err)
			}
		}
	}

	return nil
}
<|endoftext|>