<commit_before>package tpl_test

import (
	"bytes"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/joefitzgerald/inductor/tpl"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Tpl", func() {
	var (
		err       error
		osName    string
		tmpDir    string
		templates tpl.TemplateContainer
	)
	BeforeEach(func() {
		tmpDir, err = ioutil.TempDir("", "inductor")
		Expect(err).NotTo(HaveOccurred())
		createTemplateFile(tmpDir, "nano/Autounattend.xml.disks.ptpl")
		createTemplateFile(tmpDir, "nano/packer.json.provisioners.ptpl")
		createTemplateFile(tmpDir, "windowsxp/Autounattend.xml.tpl")
		createTemplateFile(tmpDir, "scripts/win-updates.ps1")
		createTemplateFile(tmpDir, "scripts/nano/SetupComplete.cmd")
		createTemplateFile(tmpDir, "inductor.json")
		createTemplateFile(tmpDir, "README.md")
		createTemplateFile(tmpDir, "Autounattend.xml.tpl")
		createTemplateFile(tmpDir, "Autounattend.xml.oobe.ptpl")
		createTemplateFile(tmpDir, "Autounattend.xml.disks.ptpl")
		createTemplateFile(tmpDir, "packer.json.tpl")
		createTemplateFile(tmpDir, "packer.json.builders.ptpl")
		createTemplateFile(tmpDir, "packer.json.provisioners.ptpl")
		createTemplateFile(tmpDir, "Vagrantfile.tpl")
	})
	JustBeforeEach(func() {
		templates = tpl.New(tmpDir, osName)
	})
	AfterEach(func() {
		os.RemoveAll(tmpDir)
	})

	Context("Windows2012r2", func() {
		BeforeEach(func() {
			osName = "windows2012r2"
		})
		Describe("Autounattend.xml.tpl root template", func() {
			var rootTemplate tpl.Templater
			JustBeforeEach(func() {
				rootTemplate = templates.FindTemplate(filepath.Join(tmpDir, "Autounattend.xml.tpl"))
			})
			It("should be found", func() {
				Expect(rootTemplate).ToNot(BeNil())
			})
			It("should have 2 partial templates", func() {
				Expect(rootTemplate.ListTemplates()).To(HaveLen(2))
			})
			It("should include Autounattend.xml.oobe.ptpl", func() {
				path := filepath.Join(tmpDir, "Autounattend.xml.oobe.ptpl")
				Expect(rootTemplate.FindTemplate(path)).ToNot(BeNil())
			})
			It("should include Autounattend.xml.disks.ptpl", func() {
				path := filepath.Join(tmpDir, "Autounattend.xml.disks.ptpl")
				Expect(rootTemplate.FindTemplate(path)).ToNot(BeNil())
			})
			It("should have template content", func() {
				expected := `Autounattend.xml.tpl
{{define "disks"}}
Autounattend.xml.disks.ptpl
{{end}}
{{define "oobe"}}
Autounattend.xml.oobe.ptpl
{{end}}`
				var buffer bytes.Buffer
				Expect(rootTemplate.Content(&buffer)).NotTo(HaveOccurred())
				Expect(buffer.String()).To(Equal(expected))
			})
		})
	})

	Context("Nano", func() {
		BeforeEach(func() {
			osName = "nano"
		})
		Describe("Autounattend.xml.tpl root template", func() {
			var rootTemplate tpl.Templater
			JustBeforeEach(func() {
				rootTemplate = templates.FindTemplate(filepath.Join(tmpDir, "Autounattend.xml.tpl"))
			})
			It("should be found", func() {
				Expect(rootTemplate).ToNot(BeNil())
			})
			It("should have 2 partial templates", func() {
				Expect(rootTemplate.ListTemplates()).To(HaveLen(2))
			})
			It("should include Autounattend.xml.oobe.ptpl", func() {
				path := filepath.Join(tmpDir, "Autounattend.xml.oobe.ptpl")
				Expect(rootTemplate.FindTemplate(path)).ToNot(BeNil())
			})
			It("should include nano/Autounattend.xml.disks.ptpl", func() {
				path := filepath.Join(tmpDir, "nano/Autounattend.xml.disks.ptpl")
				Expect(rootTemplate.FindTemplate(path)).ToNot(BeNil())
			})
		})

		Describe("packer.json.tpl root template", func() {
			var rootTemplate tpl.Templater
			JustBeforeEach(func() {
				rootTemplate = templates.FindTemplate(filepath.Join(tmpDir, "packer.json.tpl"))
			})
			It("should be found", func() {
				Expect(rootTemplate).ToNot(BeNil())
			})
			It("should have 2 partial templates", func() {
				Expect(rootTemplate.ListTemplates()).To(HaveLen(2))
			})
			It("should include packer.json.builders.ptpl", func() {
				path := filepath.Join(tmpDir, "packer.json.builders.ptpl")
				Expect(rootTemplate.FindTemplate(path)).ToNot(BeNil())
			})
			It("should include nano/packer.json.provisioners.ptpl", func() {
				path := filepath.Join(tmpDir, "nano/packer.json.provisioners.ptpl")
				Expect(rootTemplate.FindTemplate(path)).ToNot(BeNil())
			})
		})

		Describe("Vagrantfile.tpl root template", func() {
			var rootTemplate tpl.Templater
			JustBeforeEach(func() {
				rootTemplate = templates.FindTemplate(filepath.Join(tmpDir, "Vagrantfile.tpl"))
			})
			It("should be found", func() {
				Expect(rootTemplate).ToNot(BeNil())
			})
			It("should have zero partial templates", func() {
				Expect(rootTemplate.ListTemplates()).To(BeEmpty())
			})
		})
	})
})

func createTemplateFile(baseDir, path string) {
	fullPath := filepath.Join(baseDir, path)
	fileName := filepath.Base(fullPath)
	fullDir := strings.TrimSuffix(fullPath, fileName)
	os.MkdirAll(fullDir, 0744)
	ioutil.WriteFile(fullPath, []byte(fileName), 0644)
}
<commit_msg>Add BaseFilename test<commit_after>package tpl_test

import (
	"bytes"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/joefitzgerald/inductor/tpl"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Tpl", func() {
	var (
		err       error
		osName    string
		tmpDir    string
		templates tpl.TemplateContainer
	)
	BeforeEach(func() {
		tmpDir, err = ioutil.TempDir("", "inductor")
		Expect(err).NotTo(HaveOccurred())
		createTemplateFile(tmpDir, "nano/Autounattend.xml.disks.ptpl")
		createTemplateFile(tmpDir, "nano/packer.json.provisioners.ptpl")
		createTemplateFile(tmpDir, "windowsxp/Autounattend.xml.tpl")
		createTemplateFile(tmpDir, "scripts/win-updates.ps1")
		createTemplateFile(tmpDir, "scripts/nano/SetupComplete.cmd")
		createTemplateFile(tmpDir, "inductor.json")
		createTemplateFile(tmpDir, "README.md")
		createTemplateFile(tmpDir, "Autounattend.xml.tpl")
		createTemplateFile(tmpDir, "Autounattend.xml.oobe.ptpl")
		createTemplateFile(tmpDir, "Autounattend.xml.disks.ptpl")
		createTemplateFile(tmpDir, "packer.json.tpl")
		createTemplateFile(tmpDir, "packer.json.builders.ptpl")
		createTemplateFile(tmpDir, "packer.json.provisioners.ptpl")
		createTemplateFile(tmpDir, "Vagrantfile.tpl")
	})
	JustBeforeEach(func() {
		templates = tpl.New(tmpDir, osName)
	})
	AfterEach(func() {
		os.RemoveAll(tmpDir)
	})

	Context("Windows2012r2", func() {
		BeforeEach(func() {
			osName = "windows2012r2"
		})
		Describe("Autounattend.xml.tpl root template", func() {
			var rootTemplate tpl.Templater
			JustBeforeEach(func() {
				rootTemplate = templates.FindTemplate(filepath.Join(tmpDir, "Autounattend.xml.tpl"))
			})
			It("should be found", func() {
				Expect(rootTemplate).ToNot(BeNil())
			})
			It("should have 2 partial templates", func() {
				Expect(rootTemplate.ListTemplates()).To(HaveLen(2))
			})
			It("should include Autounattend.xml.oobe.ptpl", func() {
				path := filepath.Join(tmpDir, "Autounattend.xml.oobe.ptpl")
				Expect(rootTemplate.FindTemplate(path)).ToNot(BeNil())
			})
			It("should include Autounattend.xml.disks.ptpl", func() {
				path := filepath.Join(tmpDir, "Autounattend.xml.disks.ptpl")
				Expect(rootTemplate.FindTemplate(path)).ToNot(BeNil())
			})
			It("should have template content", func() {
				expected := `Autounattend.xml.tpl
{{define "disks"}}
Autounattend.xml.disks.ptpl
{{end}}
{{define "oobe"}}
Autounattend.xml.oobe.ptpl
{{end}}`
				var buffer bytes.Buffer
				Expect(rootTemplate.Content(&buffer)).NotTo(HaveOccurred())
				Expect(buffer.String()).To(Equal(expected))
			})
		})
	})

	Context("Nano", func() {
		BeforeEach(func() {
			osName = "nano"
		})
		Describe("Autounattend.xml.tpl root template", func() {
			var rootTemplate tpl.Templater
			JustBeforeEach(func() {
				rootTemplate = templates.FindTemplate(filepath.Join(tmpDir, "Autounattend.xml.tpl"))
			})
			It("should be found", func() {
				Expect(rootTemplate).ToNot(BeNil())
			})
			It("should have 2 partial templates", func() {
				Expect(rootTemplate.ListTemplates()).To(HaveLen(2))
			})
			It("should include Autounattend.xml.oobe.ptpl", func() {
				path := filepath.Join(tmpDir, "Autounattend.xml.oobe.ptpl")
				Expect(rootTemplate.FindTemplate(path)).ToNot(BeNil())
			})
			It("should include nano/Autounattend.xml.disks.ptpl", func() {
				path := filepath.Join(tmpDir, "nano/Autounattend.xml.disks.ptpl")
				Expect(rootTemplate.FindTemplate(path)).ToNot(BeNil())
			})
		})

		Describe("packer.json.tpl root template", func() {
			var rootTemplate tpl.Templater
			JustBeforeEach(func() {
				rootTemplate = templates.FindTemplate(filepath.Join(tmpDir, "packer.json.tpl"))
			})
			It("should be found", func() {
				Expect(rootTemplate).ToNot(BeNil())
			})
			It("should have 2 partial templates", func() {
				Expect(rootTemplate.ListTemplates()).To(HaveLen(2))
			})
			It("should include packer.json.builders.ptpl", func() {
				path := filepath.Join(tmpDir, "packer.json.builders.ptpl")
				Expect(rootTemplate.FindTemplate(path)).ToNot(BeNil())
			})
			It("should include nano/packer.json.provisioners.ptpl", func() {
				path := filepath.Join(tmpDir, "nano/packer.json.provisioners.ptpl")
				Expect(rootTemplate.FindTemplate(path)).ToNot(BeNil())
			})
		})

		Describe("Vagrantfile.tpl root template", func() {
			var rootTemplate tpl.Templater
			JustBeforeEach(func() {
				rootTemplate = templates.FindTemplate(filepath.Join(tmpDir, "Vagrantfile.tpl"))
			})
			It("should be found", func() {
				Expect(rootTemplate).ToNot(BeNil())
			})
			It("should have zero partial templates", func() {
				Expect(rootTemplate.ListTemplates()).To(BeEmpty())
			})
			It("should have basefilename", func() {
				Expect(rootTemplate.BaseFilename()).To(Equal("Vagrantfile"))
			})
		})
	})
})

func createTemplateFile(baseDir, path string) {
	fullPath := filepath.Join(baseDir, path)
	fileName := filepath.Base(fullPath)
	fullDir := strings.TrimSuffix(fullPath, fileName)
	os.MkdirAll(fullDir, 0744)
	ioutil.WriteFile(fullPath, []byte(fileName), 0644)
}
<|endoftext|>


<commit_before>package controllers

import (
	"encoding/json"
	"github.com/alex1sz/shotcharter-go-api/models"
	"github.com/alex1sz/shotcharter-go-api/utilities"
	"github.com/gorilla/mux"
	// "log"
	"net/http"
)

// team specific decoder needed to avoid performance hit of using reflect
func decodeReqIntoTeam(w http.ResponseWriter, req *http.Request) (team models.Team) {
	if err := json.NewDecoder(req.Body).Decode(&team); err != nil {
		utils.RespondWithAppError(w, err, "Invalid team data", 500)
		return
	}
	return
}

// POST /teams
func CreateTeam(w http.ResponseWriter, req *http.Request) {
	team := decodeReqIntoTeam(w, req)

	if err := team.Create(); err != nil {
		utils.RespondWithAppError(w, err, "Unexpected error", 500)
		return
	}
	utils.RespondWithJSON(w, team, 201)
}

// GET /teams/:id
func GetTeamByID(w http.ResponseWriter, req *http.Request) {
	params := mux.Vars(req)
	team, err := models.FindTeamByID(params["id"])

	if err != nil {
		utils.HandleFindError(w, err)
		return
	}
	utils.RespondWithJSON(w, team, 200)
}

// PATCH /teams/:id
func UpdateTeam(w http.ResponseWriter, req *http.Request) {
	team := decodeReqIntoTeam(w, req)

	if err := team.Update(); err != nil {
		utils.HandleFindError(w, err)
		return
	}
	utils.RespondWithJSON(w, team, 200)
}
<commit_msg>Tidy up GetTeamByID<commit_after>package controllers

import (
	"encoding/json"
	"github.com/alex1sz/shotcharter-go-api/models"
	"github.com/alex1sz/shotcharter-go-api/utilities"
	"github.com/gorilla/mux"
	"net/http"
)

// team specific decoder needed to avoid performance hit of using reflect
func decodeReqIntoTeam(w http.ResponseWriter, req *http.Request) (team models.Team) {
	if err := json.NewDecoder(req.Body).Decode(&team); err != nil {
		utils.RespondWithAppError(w, err, "Invalid team data", 500)
		return
	}
	return
}

// POST /teams
func CreateTeam(w http.ResponseWriter, req *http.Request) {
	team := decodeReqIntoTeam(w, req)

	if err := team.Create(); err != nil {
		utils.RespondWithAppError(w, err, "Unexpected error", 500)
		return
	}
	utils.RespondWithJSON(w, team, 201)
}

// GET /teams/:id
func GetTeamByID(w http.ResponseWriter, req *http.Request) {
	team, err := models.FindTeamByID(mux.Vars(req)["id"])

	if err != nil {
		utils.HandleFindError(w, err)
		return
	}
	utils.RespondWithJSON(w, team, 200)
}

// PATCH /teams/:id
func UpdateTeam(w http.ResponseWriter, req *http.Request) {
	team := decodeReqIntoTeam(w, req)

	if err := team.Update(); err != nil {
		utils.HandleFindError(w, err)
		return
	}
	utils.RespondWithJSON(w, team, 200)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"log"
	"strings"

	"github.com/google/go-github/github"

	"github.com/wsxiaoys/terminal"
	"github.com/wsxiaoys/terminal/color"
)

func NewPullRequestor(config *Config, client *github.Client) *PullRequestor {
	return &PullRequestor{config, client}
}

type PullRequestor struct {
	config *Config
	client *github.Client
}

func (self *PullRequestor) writePullRequest(organization string, project string, pr github.PullRequest, out chan<- string) {
	if self.config.Debug {
		log.Println("Listing comments for", project)
	}
	comments, _, err := self.client.PullRequests.ListComments(organization, project, *pr.Number, nil)

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

	var buffer bytes.Buffer

	buffer.WriteString(color.Sprintf("@w[%d] %s\n", *pr.Number, *pr.Title))

	buffer.WriteString(color.Sprintf("@{/}(Created on %s :: %d comments)\n", *pr.CreatedAt, len(comments)))

	if pr.Body == nil || len(*pr.Body) == 0 {
		buffer.WriteString(color.Sprint("@r<no body>\n"))
	} else {
		bodyLen := len(*pr.Body)
		if bodyLen > 120 {
			bodyLen = 120
		}

		buffer.WriteString(color.Sprintf("@b%s\n", (*pr.Body)[:bodyLen]))
	}

	buffer.WriteString(color.Sprintf("@g%s\n\n", (*pr.HTMLURL)))

	if self.config.Debug {
		log.Println("Done printing pull requests for", project)
	}

	out <- buffer.String()
}

func (self *PullRequestor) PrintPullRequests(repo Repository, done chan<- struct{}) {
	for _, project := range repo.Projects {
		var buffer bytes.Buffer
		if self.config.Debug {
			log.Println("Getting pull requests for", project)
		}
		prs, _, err := self.client.PullRequests.List(repo.Organization, project, nil)

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

		if len(prs) == 0 {
			continue
		}

		// use a channel to collect all of the writes to a buffer then write it all at once
		printer := make(chan string)
		defer close(printer)

		for _, pr := range prs {
			go self.writePullRequest(repo.Organization, project, pr, printer)
		}

		// write out the printer to the terminal after everything has been collected
		terminal.Stdout.Color("y")

		// Get color codes here: https://github.com/wsxiaoys/terminal/blob/master/color/color.go
		title := fmt.Sprintf(" [ %s (%d) ] ", strings.ToUpper(project), len(prs))
		paddingWidth := (80 - len(title)) / 2

		buffer.WriteString(color.Sprintf("%s\n", strings.Repeat("=", 80)))
		buffer.WriteString(color.Sprintf("@{!m}%s%s%s\n", strings.Repeat("-", paddingWidth), title, strings.Repeat("-", paddingWidth)))

		for i := 0; i < len(prs); i++ {
			buffer.WriteString(<-printer)
		}

		color.Print(buffer.String())
	}

	done <- struct{}{}
}

func (self *PullRequestor) ListRepos() {
	// list all repositories for the authenticated user
	done := make(chan struct{})
	defer close(done)

	for _, repo := range self.config.Repositories {
		go self.PrintPullRequests(repo, done)
	}

	for i := 0; i < len(self.config.Repositories); i++ {
		<-done
	}
}
<commit_msg>Define buffer where it is needed<commit_after>package main

import (
	"bytes"
	"fmt"
	"log"
	"strings"

	"github.com/google/go-github/github"

	"github.com/wsxiaoys/terminal"
	"github.com/wsxiaoys/terminal/color"
)

func NewPullRequestor(config *Config, client *github.Client) *PullRequestor {
	return &PullRequestor{config, client}
}

type PullRequestor struct {
	config *Config
	client *github.Client
}

func (self *PullRequestor) writePullRequest(organization string, project string, pr github.PullRequest, out chan<- string) {
	if self.config.Debug {
		log.Println("Listing comments for", project)
	}
	comments, _, err := self.client.PullRequests.ListComments(organization, project, *pr.Number, nil)

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

	var buffer bytes.Buffer

	buffer.WriteString(color.Sprintf("@w[%d] %s\n", *pr.Number, *pr.Title))

	buffer.WriteString(color.Sprintf("@{/}(Created on %s :: %d comments)\n", *pr.CreatedAt, len(comments)))

	if pr.Body == nil || len(*pr.Body) == 0 {
		buffer.WriteString(color.Sprint("@r<no body>\n"))
	} else {
		bodyLen := len(*pr.Body)
		if bodyLen > 120 {
			bodyLen = 120
		}

		buffer.WriteString(color.Sprintf("@b%s\n", (*pr.Body)[:bodyLen]))
	}

	buffer.WriteString(color.Sprintf("@g%s\n\n", (*pr.HTMLURL)))

	if self.config.Debug {
		log.Println("Done printing pull requests for", project)
	}

	out <- buffer.String()
}

func (self *PullRequestor) PrintPullRequests(repo Repository, done chan<- struct{}) {
	for _, project := range repo.Projects {
		if self.config.Debug {
			log.Println("Getting pull requests for", project)
		}
		prs, _, err := self.client.PullRequests.List(repo.Organization, project, nil)

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

		if len(prs) == 0 {
			continue
		}

		// use a channel to collect all of the writes to a buffer then write it all at once
		printer := make(chan string)
		defer close(printer)

		for _, pr := range prs {
			go self.writePullRequest(repo.Organization, project, pr, printer)
		}

		// write out the printer to the terminal after everything has been collected
		terminal.Stdout.Color("y")

		// Get color codes here: https://github.com/wsxiaoys/terminal/blob/master/color/color.go
		title := fmt.Sprintf(" [ %s (%d) ] ", strings.ToUpper(project), len(prs))
		paddingWidth := (80 - len(title)) / 2

		var buffer bytes.Buffer
		buffer.WriteString(color.Sprintf("%s\n", strings.Repeat("=", 80)))
		buffer.WriteString(color.Sprintf("@{!m}%s%s%s\n", strings.Repeat("-", paddingWidth), title, strings.Repeat("-", paddingWidth)))

		for i := 0; i < len(prs); i++ {
			buffer.WriteString(<-printer)
		}

		color.Print(buffer.String())
	}

	done <- struct{}{}
}

func (self *PullRequestor) ListRepos() {
	// list all repositories for the authenticated user
	done := make(chan struct{})
	defer close(done)

	for _, repo := range self.config.Repositories {
		go self.PrintPullRequests(repo, done)
	}

	for i := 0; i < len(self.config.Repositories); i++ {
		<-done
	}
}
<|endoftext|>


<commit_before>/*
http://www.apache.org/licenses/LICENSE-2.0.txt

Copyright 2015 Intel Corporation

Licensed under the Apache License, Version 2.0 (the "License");

    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 client

import (
	"errors"
	"fmt"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/intelsdi-x/pulse/core"
	"github.com/intelsdi-x/pulse/pkg/chrono"
)

// the time limit for which a cache entry is valid.
var GlobalCacheExpiration time.Duration

var (
	metricCache = cache{
		table: make(map[string]*cachecell),
	}
	cacheLog = log.WithField("_module", "client-cache")

	ErrCacheEntryDoesNotExist = errors.New("cache entry does not exist")
)

type cachecell struct {
	time    time.Time
	metric  core.Metric
	metrics []core.Metric
	hits    uint64
	misses  uint64
}

type cache struct {
	table map[string]*cachecell
}

func (c *cache) get(ns string, version int) interface{} {
	var (
		cell *cachecell
		ok   bool
	)

	key := fmt.Sprintf("%v:%v", ns, version)
	if cell, ok = c.table[key]; ok && chrono.Chrono.Now().Sub(cell.time) < GlobalCacheExpiration {
		cell.hits++
		cacheLog.WithFields(log.Fields{
			"namespace": key,
			"hits":      cell.hits,
			"misses":    cell.misses,
		}).Debug(fmt.Sprintf("cache hit [%s]", key))
		if cell.metric != nil {
			return cell.metric
		}
		return cell.metrics
	} else {
		if !ok {
			c.table[key] = &cachecell{
				time:    time.Time{},
				metrics: nil,
			}
		}
		c.table[key].misses++
		cacheLog.WithFields(log.Fields{
			"namespace": key,
			"hits":      c.table[key].hits,
			"misses":    c.table[key].misses,
		}).Debug(fmt.Sprintf("cache miss [%s]", key))
	}
	return nil
}

func (c *cache) put(ns string, version int, m interface{}) {
	key := fmt.Sprintf("%v:%v", ns, version)
	switch metric := m.(type) {
	case core.Metric:
		if _, ok := c.table[key]; ok {
			c.table[key].time = chrono.Chrono.Now()
			c.table[key].metric = metric
		} else {
			c.table[key] = &cachecell{
				time:   chrono.Chrono.Now(),
				metric: metric,
			}
		}
	case []core.Metric:
		if _, ok := c.table[key]; ok {
			c.table[key].time = time.Now()
			c.table[key].metrics = metric
		} else {
			c.table[key] = &cachecell{
				time:    chrono.Chrono.Now(),
				metrics: metric,
			}
		}
	default:
		cacheLog.WithFields(log.Fields{
			"namespace": key,
			"_block":    "put",
		}).Error("unsupported type")
	}
}
<commit_msg>Reintroduce deleted license lines<commit_after>/*
http://www.apache.org/licenses/LICENSE-2.0.txt

Copyright 2015 Intel Corporation

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 client

import (
	"errors"
	"fmt"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/intelsdi-x/pulse/core"
	"github.com/intelsdi-x/pulse/pkg/chrono"
)

// the time limit for which a cache entry is valid.
var GlobalCacheExpiration time.Duration

var (
	metricCache = cache{
		table: make(map[string]*cachecell),
	}
	cacheLog = log.WithField("_module", "client-cache")

	ErrCacheEntryDoesNotExist = errors.New("cache entry does not exist")
)

type cachecell struct {
	time    time.Time
	metric  core.Metric
	metrics []core.Metric
	hits    uint64
	misses  uint64
}

type cache struct {
	table map[string]*cachecell
}

func (c *cache) get(ns string, version int) interface{} {
	var (
		cell *cachecell
		ok   bool
	)

	key := fmt.Sprintf("%v:%v", ns, version)
	if cell, ok = c.table[key]; ok && chrono.Chrono.Now().Sub(cell.time) < GlobalCacheExpiration {
		cell.hits++
		cacheLog.WithFields(log.Fields{
			"namespace": key,
			"hits":      cell.hits,
			"misses":    cell.misses,
		}).Debug(fmt.Sprintf("cache hit [%s]", key))
		if cell.metric != nil {
			return cell.metric
		}
		return cell.metrics
	} else {
		if !ok {
			c.table[key] = &cachecell{
				time:    time.Time{},
				metrics: nil,
			}
		}
		c.table[key].misses++
		cacheLog.WithFields(log.Fields{
			"namespace": key,
			"hits":      c.table[key].hits,
			"misses":    c.table[key].misses,
		}).Debug(fmt.Sprintf("cache miss [%s]", key))
	}
	return nil
}

func (c *cache) put(ns string, version int, m interface{}) {
	key := fmt.Sprintf("%v:%v", ns, version)
	switch metric := m.(type) {
	case core.Metric:
		if _, ok := c.table[key]; ok {
			c.table[key].time = chrono.Chrono.Now()
			c.table[key].metric = metric
		} else {
			c.table[key] = &cachecell{
				time:   chrono.Chrono.Now(),
				metric: metric,
			}
		}
	case []core.Metric:
		if _, ok := c.table[key]; ok {
			c.table[key].time = time.Now()
			c.table[key].metrics = metric
		} else {
			c.table[key] = &cachecell{
				time:    chrono.Chrono.Now(),
				metrics: metric,
			}
		}
	default:
		cacheLog.WithFields(log.Fields{
			"namespace": key,
			"_block":    "put",
		}).Error("unsupported type")
	}
}
<|endoftext|>


<commit_before>package data

import (
	ct "github.com/flynn/flynn/controller/types"
	"github.com/flynn/flynn/pkg/postgres"
	. "github.com/flynn/go-check"
	"github.com/jackc/pgx"
)

const bufSize = 1024 * 1024

type S struct {
	db *postgres.DB
}

var _ = Suite(&S{})

func (s *S) SetUpSuite(c *C) {
	dbname := "controllerschematest"
	db := setupTestDB(c, dbname)
	if err := MigrateDB(db); err != nil {
		c.Fatal(err)
	}

	// reconnect with que statements prepared now that schema is migrated
	pgxpool, err := pgx.NewConnPool(pgx.ConnPoolConfig{
		ConnConfig: pgx.ConnConfig{
			Host:     "/var/run/postgresql",
			Database: dbname,
		},
		AfterConnect: PrepareStatements,
	})
	if err != nil {
		c.Fatal(err)
	}
	db = postgres.New(pgxpool, nil)
	s.db = db
}

func (s *S) TearDownSuite(c *C) {
}

func (s *S) SetUpTest(c *C) {
}

func (s *S) matchLabelFilters(c *C, labelFilters []ct.LabelFilter, labels map[string]string) bool {
	var ret bool
	c.Assert(s.db.QueryRow("SELECT match_label_filters($1, $2)", labelFilters, labels).Scan(&ret), IsNil)
	return ret
}

func (s *S) TestMatchLabelFilters(c *C) {
	labels := map[string]string{
		"one":   "ONE",
		"two":   "TWO",
		"three": "THREE",
		"four":  "FOUR",
	}

	// OP_IN
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:     ct.LabelFilterExpressionOpIn,
				Key:    "one",
				Values: []string{"1", "ONE"},
			},
		},
	}, labels), Equals, true)
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:     ct.LabelFilterExpressionOpIn,
				Key:    "one",
				Values: []string{"1"},
			},
		},
	}, labels), Equals, false)

	// OP_NOT_IN
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:     ct.LabelFilterExpressionOpNotIn,
				Key:    "one",
				Values: []string{"1", "foo", "bar"},
			},
		},
	}, labels), Equals, true)
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:     ct.LabelFilterExpressionOpNotIn,
				Key:    "one",
				Values: []string{"1", "ONE"},
			},
		},
	}, labels), Equals, false)

	// OP_EXISTS
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "one",
			},
		},
	}, labels), Equals, true)
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "foo",
			},
		},
	}, labels), Equals, false)

	// OP_NOT_EXISTS
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpNotExists,
				Key: "foo",
			},
		},
	}, labels), Equals, true)
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpNotExists,
				Key: "one",
			},
		},
	}, labels), Equals, false)

	// Multiple Expressions
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:     ct.LabelFilterExpressionOpIn,
				Key:    "one",
				Values: []string{"1", "ONE", "one"},
			},
			&ct.LabelFilterExpression{
				Op:     ct.LabelFilterExpressionOpNotIn,
				Key:    "one",
				Values: []string{"foo", "bar", "baz"},
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "two",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "three",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpNotExists,
				Key: "foo",
			},
		},
	}, labels), Equals, true) // expressions are ANDed
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:     ct.LabelFilterExpressionOpIn,
				Key:    "one",
				Values: []string{"1", "ONE", "one"},
			},
			&ct.LabelFilterExpression{
				Op:     ct.LabelFilterExpressionOpNotIn,
				Key:    "one",
				Values: []string{"foo", "bar", "baz"},
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "two",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "three",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpNotExists,
				Key: "foo",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpNotExists,
				Key: "four", // it exists
			},
		},
	}, labels), Equals, false) // expressions are ANDed

	// Multiple Filters
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:     ct.LabelFilterExpressionOpIn,
				Key:    "three",
				Values: []string{"foo", "bar"},
			},
		}, // false
		{
			&ct.LabelFilterExpression{
				Op:     ct.LabelFilterExpressionOpIn,
				Key:    "one",
				Values: []string{"1", "ONE"},
			},
		}, // true
		{
			&ct.LabelFilterExpression{
				Op:     ct.LabelFilterExpressionOpIn,
				Key:    "two",
				Values: []string{"2", "TWO"},
			},
		}, // true
	}, labels), Equals, true) // filtered are ORed

	// Multiple Filters with Multiple Expressions
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "one",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "two",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "three",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "foo",
			},
		}, // false
		{
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "one",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "two",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "three",
			},
		}, // true
	}, labels), Equals, true) // filtered are ORed
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "one",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "two",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "three",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "foo",
			},
		}, // false
		{
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "one",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "two",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "three",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpNotExists,
				Key: "four",
			},
		}, // false
	}, labels), Equals, false) // filtered are ORed

	// Empty List of Filters should always match
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{}, labels), Equals, true)
}
<commit_msg>controller: Remove empty methods<commit_after>package data

import (
	ct "github.com/flynn/flynn/controller/types"
	"github.com/flynn/flynn/pkg/postgres"
	. "github.com/flynn/go-check"
	"github.com/jackc/pgx"
)

const bufSize = 1024 * 1024

type S struct {
	db *postgres.DB
}

var _ = Suite(&S{})

func (s *S) SetUpSuite(c *C) {
	dbname := "controllerschematest"
	db := setupTestDB(c, dbname)
	if err := MigrateDB(db); err != nil {
		c.Fatal(err)
	}

	// reconnect with que statements prepared now that schema is migrated
	pgxpool, err := pgx.NewConnPool(pgx.ConnPoolConfig{
		ConnConfig: pgx.ConnConfig{
			Host:     "/var/run/postgresql",
			Database: dbname,
		},
		AfterConnect: PrepareStatements,
	})
	if err != nil {
		c.Fatal(err)
	}
	db = postgres.New(pgxpool, nil)
	s.db = db
}

func (s *S) matchLabelFilters(c *C, labelFilters []ct.LabelFilter, labels map[string]string) bool {
	var ret bool
	c.Assert(s.db.QueryRow("SELECT match_label_filters($1, $2)", labelFilters, labels).Scan(&ret), IsNil)
	return ret
}

func (s *S) TestMatchLabelFilters(c *C) {
	labels := map[string]string{
		"one":   "ONE",
		"two":   "TWO",
		"three": "THREE",
		"four":  "FOUR",
	}

	// OP_IN
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:     ct.LabelFilterExpressionOpIn,
				Key:    "one",
				Values: []string{"1", "ONE"},
			},
		},
	}, labels), Equals, true)
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:     ct.LabelFilterExpressionOpIn,
				Key:    "one",
				Values: []string{"1"},
			},
		},
	}, labels), Equals, false)

	// OP_NOT_IN
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:     ct.LabelFilterExpressionOpNotIn,
				Key:    "one",
				Values: []string{"1", "foo", "bar"},
			},
		},
	}, labels), Equals, true)
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:     ct.LabelFilterExpressionOpNotIn,
				Key:    "one",
				Values: []string{"1", "ONE"},
			},
		},
	}, labels), Equals, false)

	// OP_EXISTS
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "one",
			},
		},
	}, labels), Equals, true)
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "foo",
			},
		},
	}, labels), Equals, false)

	// OP_NOT_EXISTS
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpNotExists,
				Key: "foo",
			},
		},
	}, labels), Equals, true)
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpNotExists,
				Key: "one",
			},
		},
	}, labels), Equals, false)

	// Multiple Expressions
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:     ct.LabelFilterExpressionOpIn,
				Key:    "one",
				Values: []string{"1", "ONE", "one"},
			},
			&ct.LabelFilterExpression{
				Op:     ct.LabelFilterExpressionOpNotIn,
				Key:    "one",
				Values: []string{"foo", "bar", "baz"},
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "two",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "three",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpNotExists,
				Key: "foo",
			},
		},
	}, labels), Equals, true) // expressions are ANDed
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:     ct.LabelFilterExpressionOpIn,
				Key:    "one",
				Values: []string{"1", "ONE", "one"},
			},
			&ct.LabelFilterExpression{
				Op:     ct.LabelFilterExpressionOpNotIn,
				Key:    "one",
				Values: []string{"foo", "bar", "baz"},
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "two",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "three",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpNotExists,
				Key: "foo",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpNotExists,
				Key: "four", // it exists
			},
		},
	}, labels), Equals, false) // expressions are ANDed

	// Multiple Filters
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:     ct.LabelFilterExpressionOpIn,
				Key:    "three",
				Values: []string{"foo", "bar"},
			},
		}, // false
		{
			&ct.LabelFilterExpression{
				Op:     ct.LabelFilterExpressionOpIn,
				Key:    "one",
				Values: []string{"1", "ONE"},
			},
		}, // true
		{
			&ct.LabelFilterExpression{
				Op:     ct.LabelFilterExpressionOpIn,
				Key:    "two",
				Values: []string{"2", "TWO"},
			},
		}, // true
	}, labels), Equals, true) // filtered are ORed

	// Multiple Filters with Multiple Expressions
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "one",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "two",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "three",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "foo",
			},
		}, // false
		{
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "one",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "two",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "three",
			},
		}, // true
	}, labels), Equals, true) // filtered are ORed
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{
		{
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "one",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "two",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "three",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "foo",
			},
		}, // false
		{
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "one",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "two",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpExists,
				Key: "three",
			},
			&ct.LabelFilterExpression{
				Op:  ct.LabelFilterExpressionOpNotExists,
				Key: "four",
			},
		}, // false
	}, labels), Equals, false) // filtered are ORed

	// Empty List of Filters should always match
	c.Assert(s.matchLabelFilters(c, []ct.LabelFilter{}, labels), Equals, true)
}
<|endoftext|>


<commit_before>package controllers

import (
	"fmt"
	"github.com/astaxie/beego"
	"github.com/royburns/goTestLinkReport/models"
	"strconv"
	// "strings"
)

type IndexController struct {
	beego.Controller
}

func (this *IndexController) Get() {

	ExecutionsTableHeader := models.GetExectutionTableHeader()

	// Calculate pages.
	pagenum := 20
	pn, err := strconv.Atoi(this.Input().Get("p"))
	maxPageNum := int(models.GetExecutionCount()/int64(pagenum)) + 1
	if err != nil || pn > maxPageNum {
		pn = 1
	}

	if pn < 10 {
		this.Data["Prev"] = 1
	} else {
		this.Data["Prev"] = pn - 10
	}

	if pn > maxPageNum-10 {
		this.Data["Next"] = maxPageNum
	} else {
		this.Data["Next"] = pn + 10
	}

	// Get TestPlans
	testplans := make(map[int]string)
	res := models.GetAllTestPlans("v_testlink_testexecution_tree")
	for key, item := range res {
		testplans[key] = string(item["TestPlan"])
	}
	this.Data["TestPlans"] = testplans

	// Calculate page list.
	this.Data["PageList"] = calPageList(pn, maxPageNum)

	// 100, (page-1)*100
	testexecution_tree, err := models.GetAllExecutions(pagenum, (pn-1)*pagenum)

	if err != nil {
		beego.Debug(fmt.Sprintf("Failed to get reports from db: %v\n", err))
	} else {
		beego.Debug("Success!!!")
	}

	this.Data["TableHeader"] = ExecutionsTableHeader
	this.Data["TestExecutionTree"] = testexecution_tree
	this.Data["IsIndex"] = true
	this.Data["Website"] = "goTestLinkReport.org"
	this.Data["Email"] = "roy.burns@163.com"

	this.TplNames = "index.tpl"
}

type page struct {
	IsActive  bool
	TestPlans string
	PageNum   int
}

// calPageList returns page lists.
func calPageList(p, maxPageNum int) []*page {
	listSize := 15
	hls := listSize / 2
	pl := make([]*page, 0, listSize)

	start, end := p-hls, p+hls
	if p < hls+1 {
		start, end = 1, listSize
	}

	if end > maxPageNum {
		end = maxPageNum
	}

	for i := start; i <= end; i++ {
		pl = append(pl, &page{
			IsActive: i == p,
			PageNum:  i,
		})
	}
	return pl
}
<commit_msg>forbid some code.<commit_after>package controllers

import (
	"fmt"
	"github.com/astaxie/beego"
	"github.com/royburns/goTestLinkReport/models"
	"strconv"
	// "strings"
)

type IndexController struct {
	beego.Controller
}

func (this *IndexController) Get() {

	ExecutionsTableHeader := models.GetExectutionTableHeader()

	// Calculate pages.
	pagenum := 20
	pn, err := strconv.Atoi(this.Input().Get("p"))
	maxPageNum := int(models.GetExecutionCount()/int64(pagenum)) + 1
	if err != nil || pn > maxPageNum {
		pn = 1
	}

	if pn < 10 {
		this.Data["Prev"] = 1
	} else {
		this.Data["Prev"] = pn - 10
	}

	if pn > maxPageNum-10 {
		this.Data["Next"] = maxPageNum
	} else {
		this.Data["Next"] = pn + 10
	}

	// Get TestPlans
	testplans := make(map[int]string)
	res := models.GetAllTestPlans("v_testlink_testexecution_tree")
	for key, item := range res {
		testplans[key] = string(item["TestPlan"])
	}
	this.Data["TestPlans"] = testplans

	// Calculate page list.
	this.Data["PageList"] = calPageList(pn, maxPageNum)

	// 100, (page-1)*100
	// testexecution_tree, err := models.GetAllExecutions(pagenum, (pn-1)*pagenum)

	if err != nil {
		beego.Debug(fmt.Sprintf("Failed to get reports from db: %v\n", err))
	} else {
		beego.Debug("Success!!!")
	}

	this.Data["TableHeader"] = ExecutionsTableHeader
	// this.Data["TestExecutionTree"] = testexecution_tree
	this.Data["Website"] = "goTestLinkReport.org"
	this.Data["Email"] = "roy.burns@163.com"

	this.TplNames = "index.tpl"
}

type page struct {
	IsActive  bool
	TestPlans string
	PageNum   int
}

// calPageList returns page lists.
func calPageList(p, maxPageNum int) []*page {
	listSize := 15
	hls := listSize / 2
	pl := make([]*page, 0, listSize)

	start, end := p-hls, p+hls
	if p < hls+1 {
		start, end = 1, listSize
	}

	if end > maxPageNum {
		end = maxPageNum
	}

	for i := start; i <= end; i++ {
		pl = append(pl, &page{
			IsActive: i == p,
			PageNum:  i,
		})
	}
	return pl
}
<|endoftext|>


<commit_before>package commands

import (
	cmds "github.com/ipfs/go-ipfs/commands"
	"strings"
	"testing"
)

func checkHelptextRecursive(t *testing.T, name []string, c *cmds.Command) {
	if c.Helptext.Tagline == "" {
		t.Errorf("%s has no tagline!", strings.Join(name, " "))
	}

	if c.Helptext.LongDescription == "" {
		t.Errorf("%s has no long description!", strings.Join(name, " "))
	}

	if c.Helptext.ShortDescription == "" {
		t.Errorf("%s has no short description!", strings.Join(name, " "))
	}

	if c.Helptext.Synopsis == "" {
		t.Errorf("%s has no synopsis!", strings.Join(name, " "))
	}

	for subname, sub := range c.Subcommands {
		checkHelptextRecursive(t, append(name, subname), sub)
	}
}

func TestHelptexts(t *testing.T) {
	Root.ProcessHelp()
	checkHelptextRecursive(t, []string{"ipfs"}, Root)
}
<commit_msg>test: skip the require all helptext test<commit_after>package commands

import (
	"strings"
	"testing"

	cmds "github.com/ipfs/go-ipfs/commands"
)

func checkHelptextRecursive(t *testing.T, name []string, c *cmds.Command) {
	if c.Helptext.Tagline == "" {
		t.Errorf("%s has no tagline!", strings.Join(name, " "))
	}

	if c.Helptext.LongDescription == "" {
		t.Errorf("%s has no long description!", strings.Join(name, " "))
	}

	if c.Helptext.ShortDescription == "" {
		t.Errorf("%s has no short description!", strings.Join(name, " "))
	}

	if c.Helptext.Synopsis == "" {
		t.Errorf("%s has no synopsis!", strings.Join(name, " "))
	}

	for subname, sub := range c.Subcommands {
		checkHelptextRecursive(t, append(name, subname), sub)
	}
}

func TestHelptexts(t *testing.T) {
	t.Skip("sill isn't 100%")
	Root.ProcessHelp()
	checkHelptextRecursive(t, []string{"ipfs"}, Root)
}
<|endoftext|>


<commit_before><commit_msg>add tls flags validation<commit_after><|endoftext|>


<commit_before><commit_msg>Group (code,data,log) return values into types.Result<commit_after><|endoftext|>


<commit_before><commit_msg>Add some important TODO comments<commit_after><|endoftext|>


<commit_before>// Copyright (C) 2019 The Syncthing Authors.
//
// 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/.

// +build go1.14,!noquic,!go1.17

package connections

import (
	"context"
	"crypto/tls"
	"net"
	"net/url"
	"strings"
	"sync"
	"sync/atomic"
	"syscall"
	"time"

	"github.com/lucas-clemente/quic-go"

	"github.com/syncthing/syncthing/lib/config"
	"github.com/syncthing/syncthing/lib/connections/registry"
	"github.com/syncthing/syncthing/lib/nat"
	"github.com/syncthing/syncthing/lib/stun"
	"github.com/syncthing/syncthing/lib/svcutil"
)

func init() {
	factory := &quicListenerFactory{}
	for _, scheme := range []string{"quic", "quic4", "quic6"} {
		listeners[scheme] = factory
	}
}

type quicListener struct {
	svcutil.ServiceWithError
	nat atomic.Value

	onAddressesChangedNotifier

	uri     *url.URL
	cfg     config.Wrapper
	tlsCfg  *tls.Config
	conns   chan internalConn
	factory listenerFactory

	address *url.URL
	mut     sync.Mutex
}

func (t *quicListener) OnNATTypeChanged(natType stun.NATType) {
	if natType != stun.NATUnknown {
		l.Infof("%s detected NAT type: %s", t.uri, natType)
	}
	t.nat.Store(natType)
}

func (t *quicListener) OnExternalAddressChanged(address *stun.Host, via string) {
	var uri *url.URL
	if address != nil {
		copy := *t.uri
		uri = &copy
		uri.Host = address.TransportAddr()
	}

	t.mut.Lock()
	existingAddress := t.address
	t.address = uri
	t.mut.Unlock()

	if uri != nil && (existingAddress == nil || existingAddress.String() != uri.String()) {
		l.Infof("%s resolved external address %s (via %s)", t.uri, uri.String(), via)
		t.notifyAddressesChanged(t)
	} else if uri == nil && existingAddress != nil {
		t.notifyAddressesChanged(t)
	}
}

func (t *quicListener) serve(ctx context.Context) error {
	network := strings.ReplaceAll(t.uri.Scheme, "quic", "udp")

	packetConn, err := net.ListenPacket(network, t.uri.Host)
	if err != nil {
		l.Infoln("Listen (BEP/quic):", err)
		return err
	}
	defer func() { _ = packetConn.Close() }()

	svc, conn := stun.New(t.cfg, t, packetConn)
	defer func() { _ = conn.Close() }()
	wrapped := &stunConnQUICWrapper{
		PacketConn: conn,
		underlying: packetConn.(*net.UDPConn),
	}

	go svc.Serve(ctx)

	registry.Register(t.uri.Scheme, wrapped)
	defer registry.Unregister(t.uri.Scheme, wrapped)

	listener, err := quic.Listen(wrapped, t.tlsCfg, quicConfig)
	if err != nil {
		l.Infoln("Listen (BEP/quic):", err)
		return err
	}
	t.notifyAddressesChanged(t)
	defer listener.Close()
	defer t.clearAddresses(t)

	l.Infof("QUIC listener (%v) starting", packetConn.LocalAddr())
	defer l.Infof("QUIC listener (%v) shutting down", packetConn.LocalAddr())

	acceptFailures := 0
	const maxAcceptFailures = 10

	for {
		select {
		case <-ctx.Done():
			return ctx.Err()
		default:
		}

		session, err := listener.Accept(ctx)
		if err == context.Canceled {
			return nil
		} else if err != nil {
			l.Infoln("Listen (BEP/quic): Accepting connection:", err)

			acceptFailures++
			if acceptFailures > maxAcceptFailures {
				// Return to restart the listener, because something
				// seems permanently damaged.
				return err
			}

			// Slightly increased delay for each failure.
			time.Sleep(time.Duration(acceptFailures) * time.Second)

			continue
		}

		acceptFailures = 0

		l.Debugln("connect from", session.RemoteAddr())

		streamCtx, cancel := context.WithTimeout(ctx, quicOperationTimeout)
		stream, err := session.AcceptStream(streamCtx)
		cancel()
		if err != nil {
			l.Debugf("failed to accept stream from %s: %v", session.RemoteAddr(), err)
			_ = session.CloseWithError(1, err.Error())
			continue
		}

		t.conns <- newInternalConn(&quicTlsConn{session, stream, nil}, connTypeQUICServer, quicPriority)
	}
}

func (t *quicListener) URI() *url.URL {
	return t.uri
}

func (t *quicListener) WANAddresses() []*url.URL {
	uris := []*url.URL{t.uri}
	t.mut.Lock()
	if t.address != nil {
		uris = append(uris, t.address)
	}
	t.mut.Unlock()
	return uris
}

func (t *quicListener) LANAddresses() []*url.URL {
	addrs := []*url.URL{t.uri}
	network := strings.ReplaceAll(t.uri.Scheme, "quic", "udp")
	addrs = append(addrs, getURLsForAllAdaptersIfUnspecified(network, t.uri)...)
	return addrs
}

func (t *quicListener) String() string {
	return t.uri.String()
}

func (t *quicListener) Factory() listenerFactory {
	return t.factory
}

func (t *quicListener) NATType() string {
	v := t.nat.Load().(stun.NATType)
	if v == stun.NATUnknown || v == stun.NATError {
		return "unknown"
	}
	return v.String()
}

type quicListenerFactory struct{}

func (f *quicListenerFactory) Valid(config.Configuration) error {
	return nil
}

func (f *quicListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, natService *nat.Service) genericListener {
	l := &quicListener{
		uri:     fixupPort(uri, config.DefaultQUICPort),
		cfg:     cfg,
		tlsCfg:  tlsCfg,
		conns:   conns,
		factory: f,
	}
	l.ServiceWithError = svcutil.AsService(l.serve, l.String())
	l.nat.Store(stun.NATUnknown)
	return l
}

func (quicListenerFactory) Enabled(cfg config.Configuration) bool {
	return true
}

type stunConnQUICWrapper struct {
	net.PacketConn
	underlying *net.UDPConn
}

// SetReadBuffer is required by QUIC < v0.20.0
func (s *stunConnQUICWrapper) SetReadBuffer(size int) error {
	return s.underlying.SetReadBuffer(size)
}

// SyscallConn is required by QUIC
func (s *stunConnQUICWrapper) SyscallConn() (syscall.RawConn, error) {
	return s.underlying.SyscallConn()
}
<commit_msg>lib/connections: Correct comments on quic wrapper type (#7652)<commit_after>// Copyright (C) 2019 The Syncthing Authors.
//
// 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/.

// +build go1.14,!noquic,!go1.17

package connections

import (
	"context"
	"crypto/tls"
	"net"
	"net/url"
	"strings"
	"sync"
	"sync/atomic"
	"syscall"
	"time"

	"github.com/lucas-clemente/quic-go"

	"github.com/syncthing/syncthing/lib/config"
	"github.com/syncthing/syncthing/lib/connections/registry"
	"github.com/syncthing/syncthing/lib/nat"
	"github.com/syncthing/syncthing/lib/stun"
	"github.com/syncthing/syncthing/lib/svcutil"
)

func init() {
	factory := &quicListenerFactory{}
	for _, scheme := range []string{"quic", "quic4", "quic6"} {
		listeners[scheme] = factory
	}
}

type quicListener struct {
	svcutil.ServiceWithError
	nat atomic.Value

	onAddressesChangedNotifier

	uri     *url.URL
	cfg     config.Wrapper
	tlsCfg  *tls.Config
	conns   chan internalConn
	factory listenerFactory

	address *url.URL
	mut     sync.Mutex
}

func (t *quicListener) OnNATTypeChanged(natType stun.NATType) {
	if natType != stun.NATUnknown {
		l.Infof("%s detected NAT type: %s", t.uri, natType)
	}
	t.nat.Store(natType)
}

func (t *quicListener) OnExternalAddressChanged(address *stun.Host, via string) {
	var uri *url.URL
	if address != nil {
		copy := *t.uri
		uri = &copy
		uri.Host = address.TransportAddr()
	}

	t.mut.Lock()
	existingAddress := t.address
	t.address = uri
	t.mut.Unlock()

	if uri != nil && (existingAddress == nil || existingAddress.String() != uri.String()) {
		l.Infof("%s resolved external address %s (via %s)", t.uri, uri.String(), via)
		t.notifyAddressesChanged(t)
	} else if uri == nil && existingAddress != nil {
		t.notifyAddressesChanged(t)
	}
}

func (t *quicListener) serve(ctx context.Context) error {
	network := strings.ReplaceAll(t.uri.Scheme, "quic", "udp")

	packetConn, err := net.ListenPacket(network, t.uri.Host)
	if err != nil {
		l.Infoln("Listen (BEP/quic):", err)
		return err
	}
	defer func() { _ = packetConn.Close() }()

	svc, conn := stun.New(t.cfg, t, packetConn)
	defer func() { _ = conn.Close() }()
	wrapped := &stunConnQUICWrapper{
		PacketConn: conn,
		underlying: packetConn.(*net.UDPConn),
	}

	go svc.Serve(ctx)

	registry.Register(t.uri.Scheme, wrapped)
	defer registry.Unregister(t.uri.Scheme, wrapped)

	listener, err := quic.Listen(wrapped, t.tlsCfg, quicConfig)
	if err != nil {
		l.Infoln("Listen (BEP/quic):", err)
		return err
	}
	t.notifyAddressesChanged(t)
	defer listener.Close()
	defer t.clearAddresses(t)

	l.Infof("QUIC listener (%v) starting", packetConn.LocalAddr())
	defer l.Infof("QUIC listener (%v) shutting down", packetConn.LocalAddr())

	acceptFailures := 0
	const maxAcceptFailures = 10

	for {
		select {
		case <-ctx.Done():
			return ctx.Err()
		default:
		}

		session, err := listener.Accept(ctx)
		if err == context.Canceled {
			return nil
		} else if err != nil {
			l.Infoln("Listen (BEP/quic): Accepting connection:", err)

			acceptFailures++
			if acceptFailures > maxAcceptFailures {
				// Return to restart the listener, because something
				// seems permanently damaged.
				return err
			}

			// Slightly increased delay for each failure.
			time.Sleep(time.Duration(acceptFailures) * time.Second)

			continue
		}

		acceptFailures = 0

		l.Debugln("connect from", session.RemoteAddr())

		streamCtx, cancel := context.WithTimeout(ctx, quicOperationTimeout)
		stream, err := session.AcceptStream(streamCtx)
		cancel()
		if err != nil {
			l.Debugf("failed to accept stream from %s: %v", session.RemoteAddr(), err)
			_ = session.CloseWithError(1, err.Error())
			continue
		}

		t.conns <- newInternalConn(&quicTlsConn{session, stream, nil}, connTypeQUICServer, quicPriority)
	}
}

func (t *quicListener) URI() *url.URL {
	return t.uri
}

func (t *quicListener) WANAddresses() []*url.URL {
	uris := []*url.URL{t.uri}
	t.mut.Lock()
	if t.address != nil {
		uris = append(uris, t.address)
	}
	t.mut.Unlock()
	return uris
}

func (t *quicListener) LANAddresses() []*url.URL {
	addrs := []*url.URL{t.uri}
	network := strings.ReplaceAll(t.uri.Scheme, "quic", "udp")
	addrs = append(addrs, getURLsForAllAdaptersIfUnspecified(network, t.uri)...)
	return addrs
}

func (t *quicListener) String() string {
	return t.uri.String()
}

func (t *quicListener) Factory() listenerFactory {
	return t.factory
}

func (t *quicListener) NATType() string {
	v := t.nat.Load().(stun.NATType)
	if v == stun.NATUnknown || v == stun.NATError {
		return "unknown"
	}
	return v.String()
}

type quicListenerFactory struct{}

func (f *quicListenerFactory) Valid(config.Configuration) error {
	return nil
}

func (f *quicListenerFactory) New(uri *url.URL, cfg config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, natService *nat.Service) genericListener {
	l := &quicListener{
		uri:     fixupPort(uri, config.DefaultQUICPort),
		cfg:     cfg,
		tlsCfg:  tlsCfg,
		conns:   conns,
		factory: f,
	}
	l.ServiceWithError = svcutil.AsService(l.serve, l.String())
	l.nat.Store(stun.NATUnknown)
	return l
}

func (quicListenerFactory) Enabled(cfg config.Configuration) bool {
	return true
}

// stunConnQUICWrapper provides methods used by quic.
type stunConnQUICWrapper struct {
	net.PacketConn
	underlying *net.UDPConn
}

func (s *stunConnQUICWrapper) SetReadBuffer(size int) error {
	// https://github.com/lucas-clemente/quic-go/blob/master/packet_handler_map.go#L85
	return s.underlying.SetReadBuffer(size)
}

func (s *stunConnQUICWrapper) SyscallConn() (syscall.RawConn, error) {
	// https://github.com/lucas-clemente/quic-go/blob/84e03e59760ceee37359688871bb0688fcc4e98f/conn_windows.go#L18
	return s.underlying.SyscallConn()
}
<|endoftext|>


<commit_before><commit_msg>Remove unnecessary log in test<commit_after><|endoftext|>


<commit_before>package server

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"net/url"

	"github.com/Sirupsen/logrus"
	"github.com/braintree/manners"
	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
	"github.com/meatballhat/negroni-logrus"
	"github.com/phyber/negroni-gzip/gzip"
	"github.com/travis-ci/jupiter-brain"
	"github.com/travis-ci/jupiter-brain/server/jsonapi"
	"golang.org/x/net/context"
)

type server struct {
	addr, authToken, sentryDSN string

	log *logrus.Logger

	i jupiterbrain.InstanceManager

	n *negroni.Negroni
	r *mux.Router
	s *manners.GracefulServer
}

func newServer(cfg *Config) (*server, error) {
	log := logrus.New()
	if cfg.Debug {
		log.Level = logrus.DebugLevel
	}

	logrus.SetFormatter(&logrus.TextFormatter{DisableColors: true})

	u, err := url.Parse(cfg.VSphereURL)
	if err != nil {
		return nil, err
	}

	if !u.IsAbs() {
		return nil, fmt.Errorf("vSphere API URL must be absolute")
	}

	paths := jupiterbrain.VSpherePaths{
		BasePath:    cfg.VSphereBasePath,
		VMPath:      cfg.VSphereVMPath,
		ClusterPath: cfg.VSphereClusterPath,
	}

	srv := &server{
		addr:      cfg.Addr,
		authToken: cfg.AuthToken,
		sentryDSN: cfg.SentryDSN,

		log: log,

		i: jupiterbrain.NewVSphereInstanceManager(log, u, paths),

		n: negroni.New(),
		r: mux.NewRouter(),
		s: manners.NewServer(),
	}

	return srv, nil
}

func (srv *server) Setup() {
	srv.setupRoutes()
	srv.setupMiddleware()
}

func (srv *server) Run() {
	srv.log.WithField("addr", srv.addr).Info("Listening")
	_ = srv.s.ListenAndServe(srv.addr, srv.n)
}

func (srv *server) setupRoutes() {
	srv.r.HandleFunc(`/instances`, srv.handleInstancesList).Methods("GET").Name("instances-list")
	srv.r.HandleFunc(`/instances`, srv.handleInstancesCreate).Methods("POST").Name("instances-create")
	srv.r.HandleFunc(`/instances/{id}`, srv.handleInstanceByIDFetch).Methods("GET").Name("instance-by-id")
	srv.r.HandleFunc(`/instances/{id}`, srv.handleInstanceByIDTerminate).Methods("DELETE").Name("instance-by-id-terminate")
}

func (srv *server) setupMiddleware() {
	srv.n.Use(negroni.NewRecovery())
	srv.n.Use(negronilogrus.NewMiddleware())
	srv.n.Use(gzip.Gzip(gzip.DefaultCompression))
	srv.n.Use(negroni.HandlerFunc(srv.authMiddleware))
	srv.n.UseHandler(srv.r)
}

func (srv *server) authMiddleware(w http.ResponseWriter, req *http.Request, f http.HandlerFunc) {
	authHeader := req.Header.Get("Authorization")
	srv.log.WithField("authorization", authHeader).Debug("raw authorization header")

	if authHeader == "" {
		w.Header().Set("WWW-Authenticate", "token")
		srv.log.WithField("request_id", req.Header.Get("X-Request-ID")).Debug("responding 401 due to empty Authorization header")

		jsonapi.Error(w, errors.New("token is required"), http.StatusUnauthorized)
		return
	}

	if authHeader != ("token "+srv.authToken) && authHeader != ("token="+srv.authToken) {
		jsonapi.Error(w, errors.New("incorrect token"), http.StatusUnauthorized)
		return
	}

	f(w, req)
}

func (srv *server) handleInstancesList(w http.ResponseWriter, req *http.Request) {
	instances, err := srv.i.List(context.TODO())
	if err != nil {
		jsonapi.Error(w, err, http.StatusInternalServerError)
		return
	}

	response := map[string][]interface{}{
		"data": make([]interface{}, 0),
	}

	for _, instance := range instances {
		response["data"] = append(response["data"], MarshalInstance(instance))
	}

	b, err := json.MarshalIndent(response, "", "  ")
	if err != nil {
		jsonapi.Error(w, err, http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/vnd.api+json")
	w.WriteHeader(http.StatusOK)
	fmt.Fprintf(w, string(b)+"\n")
}

func (srv *server) handleInstancesCreate(w http.ResponseWriter, req *http.Request) {
	var requestBody map[string]map[string]string
	err := json.NewDecoder(req.Body).Decode(&requestBody)
	if err != nil {
		jsonapi.Error(w, err, http.StatusBadRequest)
		return
	}

	if requestBody["data"] == nil {
		jsonapi.Error(w, &jsonapi.JSONError{Status: "422", Code: "missing-field", Title: "root object must have data field"}, 422)
		return
	}

	if requestBody["data"]["type"] != "instances" {
		jsonapi.Error(w, &jsonapi.JSONError{Status: "409", Code: "incorrect-type", Title: "data must be of type instances"}, http.StatusConflict)
		return
	}

	if requestBody["data"]["base-image"] == "" {
		jsonapi.Error(w, &jsonapi.JSONError{Status: "422", Code: "missing-field", Title: "instance must have base-image field"}, 422)
		return
	}

	instance, err := srv.i.Start(context.TODO(), requestBody["data"]["base-image"])
	if err != nil {
		jsonapi.Error(w, err, http.StatusInternalServerError)
		return
	}

	response := map[string][]interface{}{
		"data": {MarshalInstance(instance)},
	}

	b, err := json.MarshalIndent(response, "", "  ")
	if err != nil {
		jsonapi.Error(w, err, http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/vnd.api+json")
	w.Header().Set("Location", fmt.Sprintf("/instances/%s", instance.ID))
	w.WriteHeader(http.StatusCreated)
	fmt.Fprintf(w, string(b)+"\n")
}

func (srv *server) handleInstanceByIDFetch(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	instance, err := srv.i.Fetch(context.TODO(), vars["id"])
	if err != nil {
		switch err.(type) {
		case jupiterbrain.VirtualMachineNotFoundError:
			jsonapi.Error(w, err, http.StatusNotFound)
			return
		default:
			srv.log.WithFields(logrus.Fields{
				"err": err,
				"id":  vars["id"],
			}).Error("failed to fetch instance")
			jsonapi.Error(w, err, http.StatusInternalServerError)
			return
		}
	}

	response := map[string][]interface{}{
		"data": {MarshalInstance(instance)},
	}

	b, err := json.MarshalIndent(response, "", "  ")
	if err != nil {
		jsonapi.Error(w, err, http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/vnd.api+json")
	w.WriteHeader(http.StatusOK)
	fmt.Fprintf(w, string(b)+"\n")
}

func (srv *server) handleInstanceByIDTerminate(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	err := srv.i.Terminate(context.TODO(), vars["id"])
	if err != nil {
		switch err.(type) {
		case jupiterbrain.VirtualMachineNotFoundError:
			jsonapi.Error(w, err, http.StatusNotFound)
			return
		default:
			srv.log.WithFields(logrus.Fields{
				"err": err,
				"id":  vars["id"],
			}).Error("failed to terminate instance")
			jsonapi.Error(w, err, http.StatusInternalServerError)
			return
		}
	}

	w.WriteHeader(http.StatusNoContent)
	return
}
<commit_msg>server: disable gzip compression<commit_after>package server

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"net/url"

	"github.com/Sirupsen/logrus"
	"github.com/braintree/manners"
	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
	"github.com/meatballhat/negroni-logrus"
	"github.com/travis-ci/jupiter-brain"
	"github.com/travis-ci/jupiter-brain/server/jsonapi"
	"golang.org/x/net/context"
)

type server struct {
	addr, authToken, sentryDSN string

	log *logrus.Logger

	i jupiterbrain.InstanceManager

	n *negroni.Negroni
	r *mux.Router
	s *manners.GracefulServer
}

func newServer(cfg *Config) (*server, error) {
	log := logrus.New()
	if cfg.Debug {
		log.Level = logrus.DebugLevel
	}

	logrus.SetFormatter(&logrus.TextFormatter{DisableColors: true})

	u, err := url.Parse(cfg.VSphereURL)
	if err != nil {
		return nil, err
	}

	if !u.IsAbs() {
		return nil, fmt.Errorf("vSphere API URL must be absolute")
	}

	paths := jupiterbrain.VSpherePaths{
		BasePath:    cfg.VSphereBasePath,
		VMPath:      cfg.VSphereVMPath,
		ClusterPath: cfg.VSphereClusterPath,
	}

	srv := &server{
		addr:      cfg.Addr,
		authToken: cfg.AuthToken,
		sentryDSN: cfg.SentryDSN,

		log: log,

		i: jupiterbrain.NewVSphereInstanceManager(log, u, paths),

		n: negroni.New(),
		r: mux.NewRouter(),
		s: manners.NewServer(),
	}

	return srv, nil
}

func (srv *server) Setup() {
	srv.setupRoutes()
	srv.setupMiddleware()
}

func (srv *server) Run() {
	srv.log.WithField("addr", srv.addr).Info("Listening")
	_ = srv.s.ListenAndServe(srv.addr, srv.n)
}

func (srv *server) setupRoutes() {
	srv.r.HandleFunc(`/instances`, srv.handleInstancesList).Methods("GET").Name("instances-list")
	srv.r.HandleFunc(`/instances`, srv.handleInstancesCreate).Methods("POST").Name("instances-create")
	srv.r.HandleFunc(`/instances/{id}`, srv.handleInstanceByIDFetch).Methods("GET").Name("instance-by-id")
	srv.r.HandleFunc(`/instances/{id}`, srv.handleInstanceByIDTerminate).Methods("DELETE").Name("instance-by-id-terminate")
}

func (srv *server) setupMiddleware() {
	srv.n.Use(negroni.NewRecovery())
	srv.n.Use(negronilogrus.NewMiddleware())
	srv.n.Use(negroni.HandlerFunc(srv.authMiddleware))
	srv.n.UseHandler(srv.r)
}

func (srv *server) authMiddleware(w http.ResponseWriter, req *http.Request, f http.HandlerFunc) {
	authHeader := req.Header.Get("Authorization")
	srv.log.WithField("authorization", authHeader).Debug("raw authorization header")

	if authHeader == "" {
		w.Header().Set("WWW-Authenticate", "token")
		srv.log.WithField("request_id", req.Header.Get("X-Request-ID")).Debug("responding 401 due to empty Authorization header")

		jsonapi.Error(w, errors.New("token is required"), http.StatusUnauthorized)
		return
	}

	if authHeader != ("token "+srv.authToken) && authHeader != ("token="+srv.authToken) {
		jsonapi.Error(w, errors.New("incorrect token"), http.StatusUnauthorized)
		return
	}

	f(w, req)
}

func (srv *server) handleInstancesList(w http.ResponseWriter, req *http.Request) {
	instances, err := srv.i.List(context.TODO())
	if err != nil {
		jsonapi.Error(w, err, http.StatusInternalServerError)
		return
	}

	response := map[string][]interface{}{
		"data": make([]interface{}, 0),
	}

	for _, instance := range instances {
		response["data"] = append(response["data"], MarshalInstance(instance))
	}

	b, err := json.MarshalIndent(response, "", "  ")
	if err != nil {
		jsonapi.Error(w, err, http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/vnd.api+json")
	w.WriteHeader(http.StatusOK)
	fmt.Fprintf(w, string(b)+"\n")
}

func (srv *server) handleInstancesCreate(w http.ResponseWriter, req *http.Request) {
	var requestBody map[string]map[string]string
	err := json.NewDecoder(req.Body).Decode(&requestBody)
	if err != nil {
		jsonapi.Error(w, err, http.StatusBadRequest)
		return
	}

	if requestBody["data"] == nil {
		jsonapi.Error(w, &jsonapi.JSONError{Status: "422", Code: "missing-field", Title: "root object must have data field"}, 422)
		return
	}

	if requestBody["data"]["type"] != "instances" {
		jsonapi.Error(w, &jsonapi.JSONError{Status: "409", Code: "incorrect-type", Title: "data must be of type instances"}, http.StatusConflict)
		return
	}

	if requestBody["data"]["base-image"] == "" {
		jsonapi.Error(w, &jsonapi.JSONError{Status: "422", Code: "missing-field", Title: "instance must have base-image field"}, 422)
		return
	}

	instance, err := srv.i.Start(context.TODO(), requestBody["data"]["base-image"])
	if err != nil {
		jsonapi.Error(w, err, http.StatusInternalServerError)
		return
	}

	response := map[string][]interface{}{
		"data": {MarshalInstance(instance)},
	}

	b, err := json.MarshalIndent(response, "", "  ")
	if err != nil {
		jsonapi.Error(w, err, http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/vnd.api+json")
	w.Header().Set("Location", fmt.Sprintf("/instances/%s", instance.ID))
	w.WriteHeader(http.StatusCreated)
	fmt.Fprintf(w, string(b)+"\n")
}

func (srv *server) handleInstanceByIDFetch(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	instance, err := srv.i.Fetch(context.TODO(), vars["id"])
	if err != nil {
		switch err.(type) {
		case jupiterbrain.VirtualMachineNotFoundError:
			jsonapi.Error(w, err, http.StatusNotFound)
			return
		default:
			srv.log.WithFields(logrus.Fields{
				"err": err,
				"id":  vars["id"],
			}).Error("failed to fetch instance")
			jsonapi.Error(w, err, http.StatusInternalServerError)
			return
		}
	}

	response := map[string][]interface{}{
		"data": {MarshalInstance(instance)},
	}

	b, err := json.MarshalIndent(response, "", "  ")
	if err != nil {
		jsonapi.Error(w, err, http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/vnd.api+json")
	w.WriteHeader(http.StatusOK)
	fmt.Fprintf(w, string(b)+"\n")
}

func (srv *server) handleInstanceByIDTerminate(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	err := srv.i.Terminate(context.TODO(), vars["id"])
	if err != nil {
		switch err.(type) {
		case jupiterbrain.VirtualMachineNotFoundError:
			jsonapi.Error(w, err, http.StatusNotFound)
			return
		default:
			srv.log.WithFields(logrus.Fields{
				"err": err,
				"id":  vars["id"],
			}).Error("failed to terminate instance")
			jsonapi.Error(w, err, http.StatusInternalServerError)
			return
		}
	}

	w.WriteHeader(http.StatusNoContent)
	return
}
<|endoftext|>


<commit_before>package main

import (
	"compress/gzip"
	"crypto/tls"
	"fmt"
	"log"
	"net/http"
	"regexp"
	"strconv"
	"strings"
	"time"

	"code.google.com/p/goncurses"
	"github.com/PuerkitoBio/goquery"
)

const YC_ROOT = "https://news.ycombinator.com/"
const ROWS_PER_ARTICLE = 3

var agoRegexp = regexp.MustCompile(`((?:\w*\W){2})(?:ago)`)

var trans *http.Transport = &http.Transport{
	TLSClientConfig:    &tls.Config{InsecureSkipVerify: true},
	DisableCompression: false,
}

var cfduid string

var client *http.Client = &http.Client{Transport: trans}

func doReq(req *http.Request) (doc *goquery.Document) {
	req.Header.Set("cookie", cfduid)
	req.Header.Set("referrer", "https://news.ycombinator.com/news")
	req.Header.Set("user-agent", "CLI Scraper (github.com/andrewstuart/hn)")
	req.Header.Set("accept-encoding", "gzip")

	if resp, err := client.Do(req); err != nil {
		log.Println(err)
	} else {
		if unzipper, zerr := gzip.NewReader(resp.Body); zerr != nil {
			log.Println(zerr)
		} else {
			var qerr error
			if doc, qerr = goquery.NewDocumentFromReader(unzipper); qerr != nil {
				log.Fatal(qerr)
			}
		}
	}
	return
}

//Comments structure for HN articles
type Comment struct {
	Text     string     `json:"text"`
	User     string     `json:"user"`
	Id       int        `json:"id"`
	Created  time.Time  `json:"created,omitempty"`
	Comments []*Comment `json:"comments,omitempty"`
}

func (c *Comment) String() string {
	return strings.Replace(fmt.Sprintf("%s: %s", c.User, c.Text), "\n", " ", -1)
}

//Article structure
type Article struct {
	Rank        int        `json:"rank"`
	Title       string     `json:"title"xml:"`
	Karma       int        `json:"karma"`
	Id          int        `json:"id"`
	Url         string     `json:"url"`
	NumComments int        `json:"numComments"`
	Comments    []*Comment `json:"comments",omitempty`
	User        string     `json:"user"`
	CreatedAgo  string     `json:"createdAgo,omitempty"`
	Created     time.Time  `json:"created",omitempty`
}

var arsCache = make(map[int]*Article)

var timeName = map[string]time.Duration{
	"second": time.Second,
	"minute": time.Minute,
	"hour":   time.Hour,
	"day":    24 * time.Hour,
}

func parseCreated(s string) time.Time {
	agoStr := agoRegexp.FindStringSubmatch(s)

	if len(agoStr) == 0 {
		return time.Now()
	}

	words := strings.Split(agoStr[1], " ")

	if count, err := strconv.Atoi(words[0]); err == nil {
		durText := words[1]

		if durText[len(durText)-1] == 's' {
			durText = durText[:len(durText)-1]
		}

		dur := timeName[durText]
		diff := -int64(count) * int64(dur)
		return time.Now().Add(time.Duration(diff)).Round(dur)
	} else {
		return time.Time{}
	}
}

//Retreives comments for a given article
func (a *Article) GetComments() {
	if _, exists := arsCache[a.Id]; exists {
		return
	}

	a.Comments = make([]*Comment, 0)

	articleUrl := YC_ROOT + "/item?id=" + strconv.Itoa(a.Id)

	req, e := http.NewRequest("GET", articleUrl, nil)

	if e != nil {
		log.Fatal(e)
	}

	doc := doReq(req)

	commentStack := make([]*Comment, 1, 10)

	doc.Find("span.comment").Each(func(i int, comment *goquery.Selection) {
		text := ""
		user := comment.Parent().Find("a").First().Text()

		text += comment.Text()

		//Get around HN's little weird "reply" nesting randomness
		//Is it part of the comment, or isn't it?
		if last5 := len(text) - 5; len(text) > 0 && last5 > 0 && text[last5:] == "reply" {
			text = text[:last5]
		}

		c := &Comment{
			User:     user,
			Text:     text,
			Comments: make([]*Comment, 0),
		}

		//Get comment create time
		// t := comment.Prev().Text()

		// c.Created = parseCreated(t)

		//Get id
		if idAttr, exists := comment.Prev().Find("a").Last().Attr("href"); exists {
			idSt := strings.Split(idAttr, "=")[1]

			if id, err := strconv.Atoi(idSt); err == nil {
				c.Id = id
			}
		}

		//Track the comment offset for nesting.
		if width, exists := comment.Parent().Prev().Prev().Find("img").Attr("width"); exists {
			offset, _ := strconv.Atoi(width)
			offset = offset / 40

			lastEle := len(commentStack) - 1 //Index of the last element in the stack

			if offset > lastEle {
				commentStack = append(commentStack, c)
				commentStack[lastEle].Comments = append(commentStack[lastEle].Comments, c)
			} else {

				if offset < lastEle {
					commentStack = commentStack[:offset+1] //Trim the stack
				}

				commentStack[offset] = c

				//Add the comment to its parents
				if offset == 0 {
					a.Comments = append(a.Comments, c)
				} else {
					commentStack[offset-1].Comments = append(commentStack[offset-1].Comments, c)
				}
			}
		}
	})

	arsCache[a.Id] = a

	//Cache the article for 5 minutes
	go func() {
		<-time.After(5 * time.Minute)
		delete(arsCache, a.Id)
	}()
}

func (a *Article) String() string {
	return fmt.Sprintf("(%d) %s: %s\n\n", a.Karma, a.User, a.Title)
}

//The character used to pad comments for printing
const COMMENT_PAD = "   "

//Recursively get comments
func commentString(cs []*Comment, off string) string {
	s := ""

	for _, c := range cs {
		s += off + fmt.Sprintf(off+"%s\n", c)

		if len(c.Comments) > 0 {
			s += commentString(c.Comments, off+"  ")
		}
	}

	return s
}

func (a *Article) PrintComments() string {
	a.GetComments()

	return a.String() + commentString(a.Comments, "")
}

type Page struct {
	NextUrl  string     `json:"next"`
	Url      string     `json:"url"`
	Articles []*Article `json:"articles"`
}

//Get a new page by passing a url
func NewPage(url string) *Page {
	p := Page{
		Url:      url,
		Articles: make([]*Article, 0),
	}

	url = YC_ROOT + url

	head, _ := http.NewRequest("HEAD", url, nil)

	if resp, err := client.Do(head); err == nil {
		c := resp.Cookies()
		cfduid = c[0].Raw
	} else {
		goncurses.End()
		log.Println(resp)
		log.Println(err)
	}

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		log.Fatal(err)
	}

	doc := doReq(req)

	//Get all the trs with subtext for children then go back one (for the first row)
	rows := doc.Find(".subtext").ParentsFilteredUntil("tr", "tbody").Prev()

	var a bool

	p.NextUrl, a = doc.Find("td.title").Last().Find("a").Attr("href")

	if !a {
		goncurses.End()
		log.Println("Could not retreive next hackernews page. Time to go outside?")
	}

	for len(p.NextUrl) > 0 && p.NextUrl[0] == '/' {
		p.NextUrl = p.NextUrl[1:]
	}

	rows.Each(func(i int, row *goquery.Selection) {
		ar := Article{
			Rank: len(p.Articles) + i,
		}

		title := row.Find(".title").Eq(1)
		link := title.Find("a").First()

		ar.Title = link.Text()

		if url, exists := link.Attr("href"); exists {
			ar.Url = url
		}

		row = row.Next()

		row.Find("span").Each(func(i int, s *goquery.Selection) {
			if karma, err := strconv.Atoi(strings.Split(s.Text(), " ")[0]); err == nil {
				ar.Karma = karma
			} else {
				log.Println(err)
			}

			if idSt, exists := s.Attr("id"); exists {
				if id, err := strconv.Atoi(strings.Split(idSt, "_")[1]); err == nil {
					ar.Id = id
				} else {
					log.Println(err)
				}
			}
		})

		sub := row.Find("td.subtext")
		t := sub.Text()

		ar.Created = parseCreated(t)

		ar.User = sub.Find("a").First().Text()

		comStr := strings.Split(sub.Find("a").Last().Text(), " ")[0]

		if comNum, err := strconv.Atoi(comStr); err == nil {
			ar.NumComments = comNum
		}

		p.Articles = append(p.Articles, &ar)

	})

	return &p
}
<commit_msg>Double spacing between comments<commit_after>package main

import (
	"compress/gzip"
	"crypto/tls"
	"fmt"
	"log"
	"net/http"
	"regexp"
	"strconv"
	"strings"
	"time"

	"code.google.com/p/goncurses"
	"github.com/PuerkitoBio/goquery"
)

const YC_ROOT = "https://news.ycombinator.com/"
const ROWS_PER_ARTICLE = 3

var agoRegexp = regexp.MustCompile(`((?:\w*\W){2})(?:ago)`)

var trans *http.Transport = &http.Transport{
	TLSClientConfig:    &tls.Config{InsecureSkipVerify: true},
	DisableCompression: false,
}

var cfduid string

var client *http.Client = &http.Client{Transport: trans}

func doReq(req *http.Request) (doc *goquery.Document) {
	req.Header.Set("cookie", cfduid)
	req.Header.Set("referrer", "https://news.ycombinator.com/news")
	req.Header.Set("user-agent", "CLI Scraper (github.com/andrewstuart/hn)")
	req.Header.Set("accept-encoding", "gzip")

	if resp, err := client.Do(req); err != nil {
		log.Println(err)
	} else {
		if unzipper, zerr := gzip.NewReader(resp.Body); zerr != nil {
			log.Println(zerr)
		} else {
			var qerr error
			if doc, qerr = goquery.NewDocumentFromReader(unzipper); qerr != nil {
				log.Fatal(qerr)
			}
		}
	}
	return
}

//Comments structure for HN articles
type Comment struct {
	Text     string     `json:"text"`
	User     string     `json:"user"`
	Id       int        `json:"id"`
	Created  time.Time  `json:"created,omitempty"`
	Comments []*Comment `json:"comments,omitempty"`
}

func (c *Comment) String() string {
	return strings.Replace(fmt.Sprintf("%s: %s", c.User, c.Text), "\n", " ", -1)
}

//Article structure
type Article struct {
	Rank        int        `json:"rank"`
	Title       string     `json:"title"xml:"`
	Karma       int        `json:"karma"`
	Id          int        `json:"id"`
	Url         string     `json:"url"`
	NumComments int        `json:"numComments"`
	Comments    []*Comment `json:"comments",omitempty`
	User        string     `json:"user"`
	CreatedAgo  string     `json:"createdAgo,omitempty"`
	Created     time.Time  `json:"created",omitempty`
}

var arsCache = make(map[int]*Article)

var timeName = map[string]time.Duration{
	"second": time.Second,
	"minute": time.Minute,
	"hour":   time.Hour,
	"day":    24 * time.Hour,
}

func parseCreated(s string) time.Time {
	agoStr := agoRegexp.FindStringSubmatch(s)

	if len(agoStr) == 0 {
		return time.Now()
	}

	words := strings.Split(agoStr[1], " ")

	if count, err := strconv.Atoi(words[0]); err == nil {
		durText := words[1]

		if durText[len(durText)-1] == 's' {
			durText = durText[:len(durText)-1]
		}

		dur := timeName[durText]
		diff := -int64(count) * int64(dur)
		return time.Now().Add(time.Duration(diff)).Round(dur)
	} else {
		return time.Time{}
	}
}

//Retreives comments for a given article
func (a *Article) GetComments() {
	if _, exists := arsCache[a.Id]; exists {
		return
	}

	a.Comments = make([]*Comment, 0)

	articleUrl := YC_ROOT + "/item?id=" + strconv.Itoa(a.Id)

	req, e := http.NewRequest("GET", articleUrl, nil)

	if e != nil {
		log.Fatal(e)
	}

	doc := doReq(req)

	commentStack := make([]*Comment, 1, 10)

	doc.Find("span.comment").Each(func(i int, comment *goquery.Selection) {
		text := ""
		user := comment.Parent().Find("a").First().Text()

		text += comment.Text()

		//Get around HN's little weird "reply" nesting randomness
		//Is it part of the comment, or isn't it?
		if last5 := len(text) - 5; len(text) > 0 && last5 > 0 && text[last5:] == "reply" {
			text = text[:last5]
		}

		c := &Comment{
			User:     user,
			Text:     text,
			Comments: make([]*Comment, 0),
		}

		//Get comment create time
		// t := comment.Prev().Text()

		// c.Created = parseCreated(t)

		//Get id
		if idAttr, exists := comment.Prev().Find("a").Last().Attr("href"); exists {
			idSt := strings.Split(idAttr, "=")[1]

			if id, err := strconv.Atoi(idSt); err == nil {
				c.Id = id
			}
		}

		//Track the comment offset for nesting.
		if width, exists := comment.Parent().Prev().Prev().Find("img").Attr("width"); exists {
			offset, _ := strconv.Atoi(width)
			offset = offset / 40

			lastEle := len(commentStack) - 1 //Index of the last element in the stack

			if offset > lastEle {
				commentStack = append(commentStack, c)
				commentStack[lastEle].Comments = append(commentStack[lastEle].Comments, c)
			} else {

				if offset < lastEle {
					commentStack = commentStack[:offset+1] //Trim the stack
				}

				commentStack[offset] = c

				//Add the comment to its parents
				if offset == 0 {
					a.Comments = append(a.Comments, c)
				} else {
					commentStack[offset-1].Comments = append(commentStack[offset-1].Comments, c)
				}
			}
		}
	})

	arsCache[a.Id] = a

	//Cache the article for 5 minutes
	go func() {
		<-time.After(5 * time.Minute)
		delete(arsCache, a.Id)
	}()
}

func (a *Article) String() string {
	return fmt.Sprintf("(%d) %s: %s\n\n", a.Karma, a.User, a.Title)
}

//The character used to pad comments for printing
const COMMENT_PAD = "   "

//Recursively get comments
func commentString(cs []*Comment, off string) string {
	s := ""

	for _, c := range cs {
		s += off + fmt.Sprintf(off+"%s\n\n", c)

		if len(c.Comments) > 0 {
			s += commentString(c.Comments, off+"  ")
		}
	}

	return s
}

func (a *Article) PrintComments() string {
	a.GetComments()

	return a.String() + commentString(a.Comments, "")
}

type Page struct {
	NextUrl  string     `json:"next"`
	Url      string     `json:"url"`
	Articles []*Article `json:"articles"`
}

//Get a new page by passing a url
func NewPage(url string) *Page {
	p := Page{
		Url:      url,
		Articles: make([]*Article, 0),
	}

	url = YC_ROOT + url

	head, _ := http.NewRequest("HEAD", url, nil)

	if resp, err := client.Do(head); err == nil {
		c := resp.Cookies()
		cfduid = c[0].Raw
	} else {
		goncurses.End()
		log.Println(resp)
		log.Println(err)
	}

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		log.Fatal(err)
	}

	doc := doReq(req)

	//Get all the trs with subtext for children then go back one (for the first row)
	rows := doc.Find(".subtext").ParentsFilteredUntil("tr", "tbody").Prev()

	var a bool

	p.NextUrl, a = doc.Find("td.title").Last().Find("a").Attr("href")

	if !a {
		goncurses.End()
		log.Println("Could not retreive next hackernews page. Time to go outside?")
	}

	for len(p.NextUrl) > 0 && p.NextUrl[0] == '/' {
		p.NextUrl = p.NextUrl[1:]
	}

	rows.Each(func(i int, row *goquery.Selection) {
		ar := Article{
			Rank: len(p.Articles) + i,
		}

		title := row.Find(".title").Eq(1)
		link := title.Find("a").First()

		ar.Title = link.Text()

		if url, exists := link.Attr("href"); exists {
			ar.Url = url
		}

		row = row.Next()

		row.Find("span").Each(func(i int, s *goquery.Selection) {
			if karma, err := strconv.Atoi(strings.Split(s.Text(), " ")[0]); err == nil {
				ar.Karma = karma
			} else {
				log.Println(err)
			}

			if idSt, exists := s.Attr("id"); exists {
				if id, err := strconv.Atoi(strings.Split(idSt, "_")[1]); err == nil {
					ar.Id = id
				} else {
					log.Println(err)
				}
			}
		})

		sub := row.Find("td.subtext")
		t := sub.Text()

		ar.Created = parseCreated(t)

		ar.User = sub.Find("a").First().Text()

		comStr := strings.Split(sub.Find("a").Last().Text(), " ")[0]

		if comNum, err := strconv.Atoi(comStr); err == nil {
			ar.NumComments = comNum
		}

		p.Articles = append(p.Articles, &ar)

	})

	return &p
}
<|endoftext|>