<commit_before>package dockerclient

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"sync/atomic"
)

type DockerClient struct {
	URL           *url.URL
	HTTPClient    *http.Client
	monitorEvents int32
}

type Callback func(*Event, ...interface{})

func NewDockerClient(daemonUrl string) (*DockerClient, error) {
	u, err := url.Parse(daemonUrl)
	if err != nil {
		return nil, err
	}
	httpClient := newHTTPClient(u)
	return &DockerClient{u, httpClient, 0}, nil
}

func (client *DockerClient) doRequest(method string, path string, body []byte) ([]byte, error) {
	b := bytes.NewBuffer(body)
	req, err := http.NewRequest(method, client.URL.String()+path, b)
	if err != nil {
		return nil, err
	}
	resp, err := client.HTTPClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode >= 400 {
		return nil, fmt.Errorf("%s: %s", resp.Status, data)
	}
	return data, nil
}

func (client *DockerClient) ListContainers(all bool) ([]Container, error) {
	argAll := 0
	if all == true {
		argAll = 1
	}
	args := fmt.Sprintf("?all=%d", argAll)
	data, err := client.doRequest("GET", "/v1.10/containers/json"+args, nil)
	if err != nil {
		return nil, err
	}
	ret := []Container{}
	err = json.Unmarshal(data, &ret)
	if err != nil {
		return nil, err
	}
	return ret, nil
}

func (client *DockerClient) InspectContainer(id string) (*ContainerInfo, error) {
	uri := fmt.Sprintf("/v1.10/containers/%s/json", id)
	data, err := client.doRequest("GET", uri, nil)
	if err != nil {
		return nil, err
	}
	info := &ContainerInfo{}
	err = json.Unmarshal(data, info)
	if err != nil {
		return nil, err
	}
	return info, nil
}

func (client *DockerClient) CreateContainer(config *ContainerConfig) (string, error) {
	data, err := json.Marshal(config)
	if err != nil {
		return "", err
	}
	uri := "/v1.10/containers/create"
	data, err = client.doRequest("POST", uri, data)
	if err != nil {
		return "", err
	}
	result := &RespContainersCreate{}
	err = json.Unmarshal(data, result)
	if err != nil {
		return "", err
	}
	return result.Id, nil
}

func (client *DockerClient) StartContainer(id string, config *HostConfig) error {
	data, err := json.Marshal(config)
	if err != nil {
		return err
	}
	uri := fmt.Sprintf("/v1.10/containers/%s/start", id)
	_, err = client.doRequest("POST", uri, data)
	if err != nil {
		return err
	}
	return nil
}

func (client *DockerClient) StopContainer(id string, timeout int) error {
	uri := fmt.Sprintf("/v1.10/containers/%s/stop?t=%d", id, timeout)
	_, err := client.doRequest("POST", uri, nil)
	if err != nil {
		return err
	}
	return nil
}

func (client *DockerClient) RestartContainer(id string, timeout int) error {
	uri := fmt.Sprintf("/v1.10/containers/%s/restart?t=%d", id, timeout)
	_, err := client.doRequest("POST", uri, nil)
	if err != nil {
		return err
	}
	return nil
}

func (client *DockerClient) KillContainer(id string) error {
	uri := fmt.Sprintf("/v1.10/containers/%s/kill", id)
	_, err := client.doRequest("POST", uri, nil)
	if err != nil {
		return err
	}
	return nil
}

func (client *DockerClient) StartMonitorEvents(cb Callback, args ...interface{}) {
	atomic.StoreInt32(&client.monitorEvents, 1)
	go client.getEvents(cb, args...)
}

func (client *DockerClient) getEvents(cb Callback, args ...interface{}) {
	uri := client.URL.String() + "/v1.10/events"
	resp, err := client.HTTPClient.Get(uri)
	if err != nil {
		log.Println(err)
		return
	}
	defer resp.Body.Close()

	dec := json.NewDecoder(resp.Body)
	for atomic.LoadInt32(&client.monitorEvents) > 0 {
		var event *Event
		if err := dec.Decode(&event); err != nil {
			log.Println(err)
			return
		}
		cb(event, args...)
	}
}

func (client *DockerClient) StopAllMonitorEvents() {
	atomic.StoreInt32(&client.monitorEvents, 0)
}

func (client *DockerClient) Version() (*Version, error) {
	data, err := client.doRequest("GET", "/v1.10/version", nil)
	if err != nil {
		return nil, err
	}
	version := &Version{}
	err = json.Unmarshal(data, version)
	if err != nil {
		return nil, err
	}
	return version, nil
}

func (client *DockerClient) PullImage(name, tag string) error {
	v := url.Values{}
	v.Set("fromImage", name)
	if tag != "" {
		v.Set("tag", tag)
	}
	_, err := client.doRequest("POST", "/v1.10/images/create?="+v.Encode(), nil)
	return err
}

func (client *DockerClient) RemoveContainer(id string) error {
	_, err := client.doRequest("DELETE", fmt.Sprintf("/v1.10/containers/%s", id), nil)
	return err
}
<commit_msg>Add ErrNotFound to indicate 404s<commit_after>package dockerclient

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"sync/atomic"
)

var (
	ErrNotFound = errors.New("Not found")
)

type DockerClient struct {
	URL           *url.URL
	HTTPClient    *http.Client
	monitorEvents int32
}

type Callback func(*Event, ...interface{})

func NewDockerClient(daemonUrl string) (*DockerClient, error) {
	u, err := url.Parse(daemonUrl)
	if err != nil {
		return nil, err
	}
	httpClient := newHTTPClient(u)
	return &DockerClient{u, httpClient, 0}, nil
}

func (client *DockerClient) doRequest(method string, path string, body []byte) ([]byte, error) {
	b := bytes.NewBuffer(body)
	req, err := http.NewRequest(method, client.URL.String()+path, b)
	if err != nil {
		return nil, err
	}
	resp, err := client.HTTPClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode == 404 {
		return nil, ErrNotFound
	}
	if resp.StatusCode >= 400 {
		return nil, fmt.Errorf("%s: %s", resp.Status, data)
	}
	return data, nil
}

func (client *DockerClient) ListContainers(all bool) ([]Container, error) {
	argAll := 0
	if all == true {
		argAll = 1
	}
	args := fmt.Sprintf("?all=%d", argAll)
	data, err := client.doRequest("GET", "/v1.10/containers/json"+args, nil)
	if err != nil {
		return nil, err
	}
	ret := []Container{}
	err = json.Unmarshal(data, &ret)
	if err != nil {
		return nil, err
	}
	return ret, nil
}

func (client *DockerClient) InspectContainer(id string) (*ContainerInfo, error) {
	uri := fmt.Sprintf("/v1.10/containers/%s/json", id)
	data, err := client.doRequest("GET", uri, nil)
	if err != nil {
		return nil, err
	}
	info := &ContainerInfo{}
	err = json.Unmarshal(data, info)
	if err != nil {
		return nil, err
	}
	return info, nil
}

func (client *DockerClient) CreateContainer(config *ContainerConfig) (string, error) {
	data, err := json.Marshal(config)
	if err != nil {
		return "", err
	}
	uri := "/v1.10/containers/create"
	data, err = client.doRequest("POST", uri, data)
	if err != nil {
		return "", err
	}
	result := &RespContainersCreate{}
	err = json.Unmarshal(data, result)
	if err != nil {
		return "", err
	}
	return result.Id, nil
}

func (client *DockerClient) StartContainer(id string, config *HostConfig) error {
	data, err := json.Marshal(config)
	if err != nil {
		return err
	}
	uri := fmt.Sprintf("/v1.10/containers/%s/start", id)
	_, err = client.doRequest("POST", uri, data)
	if err != nil {
		return err
	}
	return nil
}

func (client *DockerClient) StopContainer(id string, timeout int) error {
	uri := fmt.Sprintf("/v1.10/containers/%s/stop?t=%d", id, timeout)
	_, err := client.doRequest("POST", uri, nil)
	if err != nil {
		return err
	}
	return nil
}

func (client *DockerClient) RestartContainer(id string, timeout int) error {
	uri := fmt.Sprintf("/v1.10/containers/%s/restart?t=%d", id, timeout)
	_, err := client.doRequest("POST", uri, nil)
	if err != nil {
		return err
	}
	return nil
}

func (client *DockerClient) KillContainer(id string) error {
	uri := fmt.Sprintf("/v1.10/containers/%s/kill", id)
	_, err := client.doRequest("POST", uri, nil)
	if err != nil {
		return err
	}
	return nil
}

func (client *DockerClient) StartMonitorEvents(cb Callback, args ...interface{}) {
	atomic.StoreInt32(&client.monitorEvents, 1)
	go client.getEvents(cb, args...)
}

func (client *DockerClient) getEvents(cb Callback, args ...interface{}) {
	uri := client.URL.String() + "/v1.10/events"
	resp, err := client.HTTPClient.Get(uri)
	if err != nil {
		log.Println(err)
		return
	}
	defer resp.Body.Close()

	dec := json.NewDecoder(resp.Body)
	for atomic.LoadInt32(&client.monitorEvents) > 0 {
		var event *Event
		if err := dec.Decode(&event); err != nil {
			log.Println(err)
			return
		}
		cb(event, args...)
	}
}

func (client *DockerClient) StopAllMonitorEvents() {
	atomic.StoreInt32(&client.monitorEvents, 0)
}

func (client *DockerClient) Version() (*Version, error) {
	data, err := client.doRequest("GET", "/v1.10/version", nil)
	if err != nil {
		return nil, err
	}
	version := &Version{}
	err = json.Unmarshal(data, version)
	if err != nil {
		return nil, err
	}
	return version, nil
}

func (client *DockerClient) PullImage(name, tag string) error {
	v := url.Values{}
	v.Set("fromImage", name)
	if tag != "" {
		v.Set("tag", tag)
	}
	_, err := client.doRequest("POST", "/v1.10/images/create?="+v.Encode(), nil)
	return err
}

func (client *DockerClient) RemoveContainer(id string) error {
	_, err := client.doRequest("DELETE", fmt.Sprintf("/v1.10/containers/%s", id), nil)
	return err
}
<|endoftext|>


<commit_before>// +build !windows

/*
   Copyright The containerd Authors.

   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 sys

import (
	"errors"
	"os"
	"os/exec"
	"testing"
	"time"

	"gotest.tools/assert"
	is "gotest.tools/assert/cmp"
)

func TestSetPositiveOomScoreAdjustment(t *testing.T) {
	adjustment, err := adjustOom(123)
	if err != nil {
		t.Error(err)
		return
	}
	assert.Check(t, is.Equal(adjustment, 123))
}

func TestSetNegativeOomScoreAdjustmentWhenPrivileged(t *testing.T) {
	if RunningUnprivileged() {
		t.Skip("Needs to be run as root")
		return
	}

	adjustment, err := adjustOom(-123)
	if err != nil {
		t.Error(err)
		return
	}
	assert.Check(t, is.Equal(adjustment, -123))
}

func TestSetNegativeOomScoreAdjustmentWhenUnprivilegedHasNoEffect(t *testing.T) {
	if RunningPrivileged() {
		t.Skip("Needs to be run as non-root")
		return
	}

	adjustment, err := adjustOom(-123)
	if err != nil {
		t.Error(err)
		return
	}
	assert.Check(t, is.Equal(adjustment, 0))
}

func adjustOom(adjustment int) (int, error) {
	cmd := exec.Command("sleep", "100")
	if err := cmd.Start(); err != nil {
		return 0, err
	}

	pid, err := waitForPid(cmd.Process)
	if err != nil {
		return 0, err
	}

	if err := SetOOMScore(pid, adjustment); err != nil {
		return 0, err
	}

	return GetOOMScoreAdj(pid)
}

func waitForPid(process *os.Process) (int, error) {
	c := make(chan int)
	go func() {
		for {
			pid := process.Pid
			if pid != 0 {
				c <- pid
			}
		}
	}()

	select {
	case pid := <-c:
		return pid, nil
	case <-time.After(10 * time.Second):
		return 0, errors.New("process did not start in 10 seconds")
	}
}
<commit_msg>sys: clean up process after test<commit_after>// +build !windows

/*
   Copyright The containerd Authors.

   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 sys

import (
	"errors"
	"os"
	"os/exec"
	"testing"
	"time"

	"gotest.tools/assert"
	is "gotest.tools/assert/cmp"
)

func TestSetPositiveOomScoreAdjustment(t *testing.T) {
	adjustment, err := adjustOom(123)
	if err != nil {
		t.Error(err)
		return
	}
	assert.Check(t, is.Equal(adjustment, 123))
}

func TestSetNegativeOomScoreAdjustmentWhenPrivileged(t *testing.T) {
	if RunningUnprivileged() {
		t.Skip("Needs to be run as root")
		return
	}

	adjustment, err := adjustOom(-123)
	if err != nil {
		t.Error(err)
		return
	}
	assert.Check(t, is.Equal(adjustment, -123))
}

func TestSetNegativeOomScoreAdjustmentWhenUnprivilegedHasNoEffect(t *testing.T) {
	if RunningPrivileged() {
		t.Skip("Needs to be run as non-root")
		return
	}

	adjustment, err := adjustOom(-123)
	if err != nil {
		t.Error(err)
		return
	}
	assert.Check(t, is.Equal(adjustment, 0))
}

func adjustOom(adjustment int) (int, error) {
	cmd := exec.Command("sleep", "100")
	if err := cmd.Start(); err != nil {
		return 0, err
	}

	defer cmd.Process.Kill()

	pid, err := waitForPid(cmd.Process)
	if err != nil {
		return 0, err
	}

	if err := SetOOMScore(pid, adjustment); err != nil {
		return 0, err
	}

	return GetOOMScoreAdj(pid)
}

func waitForPid(process *os.Process) (int, error) {
	c := make(chan int)
	go func() {
		for {
			pid := process.Pid
			if pid != 0 {
				c <- pid
			}
		}
	}()

	select {
	case pid := <-c:
		return pid, nil
	case <-time.After(10 * time.Second):
		return 0, errors.New("process did not start in 10 seconds")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"code.cloudfoundry.org/cli/plugin/models"
	"fmt"
	"github.com/bluemixgaragelondon/cf-blue-green-deploy/from-cf-codebase/manifest"
)

type ManifestReader func(manifest.Repository, string) *plugin_models.GetAppModel

type ManifestAppFinder struct {
	Repo         manifest.Repository
	ManifestPath string
	AppName      string
}

// func (f *ManifestAppFinder) oldRoutesFromManifest(defaultDomain string) []plugin_models.GetApp_RouteSummary {
// 	if appParams := f.AppParams(defaultDomain); appParams != nil {

// 		manifestRoutes := make([]plugin_models.GetApp_RouteSummary, 0)

// 		for _, host := range appParams.Hosts {
// 			if appParams.Domains == nil {
// 				manifestRoutes = append(manifestRoutes, plugin_models.GetApp_RouteSummary{Host: host, Domain: plugin_models.GetApp_DomainFields{Name: defaultDomain}})
// 				continue
// 			}

// 			for _, domain := range appParams.Domains {
// 				manifestRoutes = append(manifestRoutes, plugin_models.GetApp_RouteSummary{Host: host, Domain: plugin_models.GetApp_DomainFields{Name: domain}})
// 			}
// 		}

// 		return manifestRoutes
// 	}
// 	return nil
// }

// TODO This function was interesting, and now is boring and should be eliminated?
func (f *ManifestAppFinder) RoutesFromManifest(defaultDomain string) []plugin_models.GetApp_RouteSummary {
	if appParams := f.AppParams(defaultDomain); appParams != nil {
		return appParams.Routes
	}
	return nil
}

func IsHostEmpty(app plugin_models.GetAppModel) bool {
	for _, route := range app.Routes {
		if route.Host != "" {
			return false
		}
	}
	return true
}

func (f *ManifestAppFinder) AppParams(defaultDomain string) *plugin_models.GetAppModel {
	var manifest *manifest.Manifest
	var err error
	if f.ManifestPath == "" {
		manifest, err = f.Repo.ReadManifest("./")
	} else {
		manifest, err = f.Repo.ReadManifest(f.ManifestPath)
	}

	if err != nil {
		fmt.Println(err)
		return nil
	}

	apps, err := manifest.Applications(defaultDomain)

	if err != nil {
		fmt.Println(err)
		return nil
	}

	for index, app := range apps {
		if IsHostEmpty(app) {
			continue
		}

		if app.Name != "" && app.Name != f.AppName {
			continue
		}

		return &apps[index]
	}
	return nil
}
<commit_msg>Remove obsolete code<commit_after>package main

import (
	"code.cloudfoundry.org/cli/plugin/models"
	"fmt"
	"github.com/bluemixgaragelondon/cf-blue-green-deploy/from-cf-codebase/manifest"
)

type ManifestReader func(manifest.Repository, string) *plugin_models.GetAppModel

type ManifestAppFinder struct {
	Repo         manifest.Repository
	ManifestPath string
	AppName      string
}

// TODO This function was interesting, and now is boring and should be eliminated?
func (f *ManifestAppFinder) RoutesFromManifest(defaultDomain string) []plugin_models.GetApp_RouteSummary {
	if appParams := f.AppParams(defaultDomain); appParams != nil {
		return appParams.Routes
	}
	return nil
}

func IsHostEmpty(app plugin_models.GetAppModel) bool {
	for _, route := range app.Routes {
		if route.Host != "" {
			return false
		}
	}
	return true
}

func (f *ManifestAppFinder) AppParams(defaultDomain string) *plugin_models.GetAppModel {
	var manifest *manifest.Manifest
	var err error
	if f.ManifestPath == "" {
		manifest, err = f.Repo.ReadManifest("./")
	} else {
		manifest, err = f.Repo.ReadManifest(f.ManifestPath)
	}

	if err != nil {
		fmt.Println(err)
		return nil
	}

	apps, err := manifest.Applications(defaultDomain)

	if err != nil {
		fmt.Println(err)
		return nil
	}

	for index, app := range apps {
		if IsHostEmpty(app) {
			continue
		}

		if app.Name != "" && app.Name != f.AppName {
			continue
		}

		return &apps[index]
	}
	return nil
}
<|endoftext|>


<commit_before>package oauth_fb

import (
	"code.google.com/p/goauth2/oauth"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
)

type FBAuth struct {
	oauth.Config
	Token *oauth.Token
}

type Graph struct {
	AccessToken string
}

type Item struct {
	Id   string `json:"id"`
	Name string `json:"name"`
}

type Profile struct {
	Id                  string  `json:"id"`
	Username            string  `json:"username"`
	Name                string  `json:"name"`
	FirstName           string  `json:"first_name"`
	LastName            string  `json:"last_name"`
	Link                string  `json:"link"`
	Gender              string  `json:"gender"`
	Timezone            float32 `json:"timezone"`
	Locale              string  `json:"locale"`
	Verified            bool    `json:"verified"`
	UpdatedTime         string  `json:"updated_time"`
	Hometown            Item    `json:"hometown"`
	Location            Item    `json:"location"`
	Sports              []Item  `json:"sports"`
	FavoriteTeams       []Item  `json:"favourite_teams"`
	Languages           []Item  `json:"languages"`
	InspirationalPeople []Item  `json:"inspirational_people"`
}

func Init(client_id, client_secret, redirect_url string, options map[string]string) *FBAuth {
	fba := new(FBAuth)
	fba.ClientId = client_id
	fba.ClientSecret = client_secret
	fba.RedirectURL = redirect_url
	fba.AuthURL = "https://graph.facebook.com/oauth/authorize"
	fba.TokenURL = "https://graph.facebook.com/oauth/access_token"

	return fba
}

func (fba *FBAuth) LoginURL() string {
	// demo is a random string to prevent cross site requests
	return fba.AuthCodeURL("demo")
}

func (fba *FBAuth) Authorize(code string) (string, error) {
	t := &oauth.Transport{Config: &fba.Config}
	tok, err := t.Exchange(code)
	fba.Token = tok
	if err != nil {
		fmt.Println("Error in getting token")
	}

	return fba.AccessToken(), err
}

func (fba *FBAuth) AccessToken() string {
	var token string
	if fba.Token != nil {
		token = fba.Token.AccessToken
	}
	return token
}

func (g *Graph) GetObject(object string) (*Profile, error) {
	var request_uri url.URL
	var profile Profile

	q := url.Values{"access_token": {g.AccessToken}}.Encode()

	request_uri.Host = "graph.facebook.com"
	request_uri.Scheme = "https"
	request_uri.Path = object
	request_uri.RawQuery = q

	resp, err := http.Get(request_uri.String())

	if err != nil {
		panic("Error in opening connection to server")
	}

	data, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()

	if err != nil {
		fmt.Println("Error in opening the response Body")
		return nil, err
	}

	err = json.Unmarshal(data, &profile)
	if err != nil {
		fmt.Println("Error in decoding json data")
		return nil, err
	}

	fmt.Println(profile)
	return &profile, err
}
<commit_msg>cleanups<commit_after>package oauth_fb

import (
	"code.google.com/p/goauth2/oauth"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
)

type FBAuth struct {
	oauth.Config
	Token *oauth.Token
}

type Graph struct {
	AccessToken string
}

type Item struct {
	Id   string `json:"id"`
	Name string `json:"name"`
}

type Profile struct {
	Id                  string  `json:"id"`
	Username            string  `json:"username"`
	Name                string  `json:"name"`
	FirstName           string  `json:"first_name"`
	LastName            string  `json:"last_name"`
	Link                string  `json:"link"`
	Gender              string  `json:"gender"`
	Timezone            float32 `json:"timezone"`
	Locale              string  `json:"locale"`
	Verified            bool    `json:"verified"`
	UpdatedTime         string  `json:"updated_time"`
	Hometown            Item    `json:"hometown"`
	Location            Item    `json:"location"`
	Sports              []Item  `json:"sports"`
	FavoriteTeams       []Item  `json:"favourite_teams"`
	Languages           []Item  `json:"languages"`
	InspirationalPeople []Item  `json:"inspirational_people"`
}

const GraphHost = "graph.facebook.com"

func Init(client_id, client_secret, redirect_url string, options map[string]string) *FBAuth {
	fba := new(FBAuth)
	fba.ClientId = client_id
	fba.ClientSecret = client_secret
	fba.RedirectURL = redirect_url
	fba.AuthURL = "https://graph.facebook.com/oauth/authorize"
	fba.TokenURL = "https://graph.facebook.com/oauth/access_token"

	return fba
}

func (fba *FBAuth) LoginURL() string {
	// demo is a random string to prevent cross site requests
	return fba.AuthCodeURL("demo")
}

func (fba *FBAuth) Authorize(code string) (string, error) {
	t := &oauth.Transport{Config: &fba.Config}
	tok, err := t.Exchange(code)
	fba.Token = tok
	if err != nil {
		fmt.Println("Error in getting token")
	}

	return fba.AccessToken(), err
}

func (fba *FBAuth) AccessToken() string {
	var token string
	if fba.Token != nil {
		token = fba.Token.AccessToken
	}
	return token
}

func (g *Graph) getRequestUri(path string) string {
	var uri url.URL
	query := url.Values{"access_token": {g.AccessToken}}.Encode()

	uri.Host = GraphHost
	uri.Path = path
	uri.Scheme = "https"
	uri.RawQuery = query

	return uri.String()
}

func (g *Graph) GetObject(object string) (*Profile, error) {
	var profile Profile
	resp, err := http.Get(g.getRequestUri(object))

	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()
	err = json.NewDecoder(resp.Body).Decode(&profile)
	return &profile, nil
}
<|endoftext|>


<commit_before>package presdo

import (
  "strings"
  "html/template"
  "github.com/russross/blackfriday"
  "io/ioutil"
  "log"
  "os"
  "time"
)

type MarkdownStruct struct { }

var markdown MarkdownStruct = MarkdownStruct{}

func (md *MarkdownStruct) Parse(requestFilePath string, markdownPath string) template.HTML {
    markdownContent, _ := ioutil.ReadFile(markdownPath)

    var pageContent Page

    // Get all header fields
    extractHeader(markdownContent, &pageContent)

    pageHtml := view.HTML(&pageContent)

    save(requestFilePath, markdownPath, pageHtml)

    return pageHtml
}

// configure markdown render options
// See blackfriday markdown source for details
func render(content []byte) template.HTML {
  htmlFlags := 0
  //htmlFlags |= blackfriday.HTML_SKIP_SCRIPT
  htmlFlags |= blackfriday.HTML_USE_XHTML
  htmlFlags |= blackfriday.HTML_USE_SMARTYPANTS
  htmlFlags |= blackfriday.HTML_SMARTYPANTS_FRACTIONS
  htmlFlags |= blackfriday.HTML_SMARTYPANTS_LATEX_DASHES
  renderer := blackfriday.HtmlRenderer(htmlFlags, "", "")

  extensions := 0
  extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS
  extensions |= blackfriday.EXTENSION_TABLES
  extensions |= blackfriday.EXTENSION_FENCED_CODE
  extensions |= blackfriday.EXTENSION_AUTOLINK
  extensions |= blackfriday.EXTENSION_STRIKETHROUGH
  extensions |= blackfriday.EXTENSION_SPACE_HEADERS

  return template.HTML(blackfriday.Markdown([]byte(content), renderer, extensions))
}

func save(requestFilePath string, markdownPath string, parsedMarkdown template.HTML) {
    cachedPath := paths.Cache(requestFilePath)

    if err := ioutil.WriteFile(cachedPath, []byte(parsedMarkdown), 0644); err != nil {
        log.Println("Error on create markdown cache file: ", err)
    } else {
        if markdownStat, err := os.Stat(markdownPath); err == nil {
            os.Chtimes(cachedPath, markdownStat.ModTime(), markdownStat.ModTime())
        }
    }
}

func extractHeader(markdownContent []byte, page *Page) {
    page.Params = make(map[string]string)

    var lines = strings.Split(string(markdownContent), "\n")
    var found = 0

    for i, line := range lines {
        line = strings.TrimSpace(line)

        if found == 1 {
            // parse line for param
            colonIndex := strings.Index(line, ":")
            if colonIndex > 0 {
                key := strings.TrimSpace(line[:colonIndex])
                value := strings.TrimSpace(line[colonIndex+1:])
                value = strings.Trim(value, "\"") //remove quotes
                switch key {
                    case "title":
                    page.Title = value
                    case "layout":
                    page.Layout = value
                    case "date":
                    page.Date, _ = time.Parse(websiteConfig.DateFormat, value)
                    default:
                    page.Params[key] = value
                }
            }
        } else if found >= 2 {
            // params over
            lines = lines[i:]
            break
        }

        if line == "---" {
            found += 1
        }
    }

    // convert markdown content
    content := strings.Join(lines, "\n")
    page.Content = render([]byte(content))
}
<commit_msg>Create full path to cached file<commit_after>package presdo

import (
  "strings"
  "html/template"
  "github.com/russross/blackfriday"
  "io/ioutil"
  "log"
  "path/filepath"
  "os"
  "time"
)

type MarkdownStruct struct { }

var markdown MarkdownStruct = MarkdownStruct{}

func (md *MarkdownStruct) Parse(requestFilePath string, markdownPath string) template.HTML {
    markdownContent, _ := ioutil.ReadFile(markdownPath)

    var pageContent Page

    // Get all header fields
    extractHeader(markdownContent, &pageContent)

    pageHtml := view.HTML(&pageContent)

    save(requestFilePath, markdownPath, pageHtml)

    return pageHtml
}

// configure markdown render options
// See blackfriday markdown source for details
func render(content []byte) template.HTML {
    htmlFlags := 0
    //htmlFlags |= blackfriday.HTML_SKIP_SCRIPT
    htmlFlags |= blackfriday.HTML_USE_XHTML
    htmlFlags |= blackfriday.HTML_USE_SMARTYPANTS
    htmlFlags |= blackfriday.HTML_SMARTYPANTS_FRACTIONS
    htmlFlags |= blackfriday.HTML_SMARTYPANTS_LATEX_DASHES
    renderer := blackfriday.HtmlRenderer(htmlFlags, "", "")

    extensions := 0
    extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS
    extensions |= blackfriday.EXTENSION_TABLES
    extensions |= blackfriday.EXTENSION_FENCED_CODE
    extensions |= blackfriday.EXTENSION_AUTOLINK
    extensions |= blackfriday.EXTENSION_STRIKETHROUGH
    extensions |= blackfriday.EXTENSION_SPACE_HEADERS

    return template.HTML(blackfriday.Markdown([]byte(content), renderer, extensions))
}

func save(requestFilePath string, markdownPath string, parsedMarkdown template.HTML) {
    cachedPath := paths.Cache(requestFilePath)
    cachedFolder := filepath.Dir(cachedPath)

    // check if full path file exists
    if _, err := os.Stat(cachedFolder); os.IsNotExist(err) {
        // create full path
        os.MkdirAll(cachedFolder, 0755)
    }

    if err := ioutil.WriteFile(cachedPath, []byte(parsedMarkdown), 0664); err != nil {
        log.Println("Error on create markdown cache file: ", err)
    } else {
        if markdownStat, err := os.Stat(markdownPath); err == nil {
            os.Chtimes(cachedPath, markdownStat.ModTime(), markdownStat.ModTime())
        }
    }
}

func extractHeader(markdownContent []byte, page *Page) {
    page.Params = make(map[string]string)

    var lines = strings.Split(string(markdownContent), "\n")
    var found = 0

    for i, line := range lines {
        line = strings.TrimSpace(line)

        if found == 1 {
            // parse line for param
            colonIndex := strings.Index(line, ":")
            if colonIndex > 0 {
                key := strings.TrimSpace(line[:colonIndex])
                value := strings.TrimSpace(line[colonIndex+1:])
                value = strings.Trim(value, "\"") //remove quotes
                switch key {
                    case "title":
                    page.Title = value
                    case "layout":
                    page.Layout = value
                    case "date":
                    page.Date, _ = time.Parse(websiteConfig.DateFormat, value)
                    default:
                    page.Params[key] = value
                }
            }
        } else if found >= 2 {
            // params over
            lines = lines[i:]
            break
        }

        if line == "---" {
            found += 1
        }
    }

    // convert markdown content
    content := strings.Join(lines, "\n")
    page.Content = render([]byte(content))
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2016 Jon Carlson.  All rights reserved.
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//

package main

import (
	"database/sql"
	"fmt"
	"sort"

	"github.com/joncrlsn/misc"
	"github.com/joncrlsn/pgutil"
)

// ==================================
// MatViewRows definition
// ==================================

// MatViewRows is a sortable slice of string maps
type MatViewRows []map[string]string

func (slice MatViewRows) Len() int {
	return len(slice)
}

func (slice MatViewRows) Less(i, j int) bool {
	return slice[i]["matviewname"] < slice[j]["matviewname"]
}

func (slice MatViewRows) Swap(i, j int) {
	slice[i], slice[j] = slice[j], slice[i]
}

// MatViewSchema holds a channel streaming matview information from one of the databases as well as
// a reference to the current row of data we're matviewing.
//
// MatViewSchema implements the Schema interface defined in pgdiff.go
type MatViewSchema struct {
	rows   MatViewRows
	rowNum int
	done   bool
}

// get returns the value from the current row for the given key
func (c *MatViewSchema) get(key string) string {
	if c.rowNum >= len(c.rows) {
		return ""
	}
	return c.rows[c.rowNum][key]
}

// NextRow increments the rowNum and tells you whether or not there are more
func (c *MatViewSchema) NextRow() bool {
	if c.rowNum >= len(c.rows)-1 {
		c.done = true
	}
	c.rowNum = c.rowNum + 1
	return !c.done
}

// Compare tells you, in one pass, whether or not the first row matches, is less than, or greater than the second row
func (c *MatViewSchema) Compare(obj interface{}) int {
	c2, ok := obj.(*MatViewSchema)
	if !ok {
		fmt.Println("Error!!!, Compare(obj) needs a MatViewSchema instance", c2)
		return +999
	}

	val := misc.CompareStrings(c.get("matviewname"), c2.get("matviewname"))
	//fmt.Printf("-- Compared %v: %s with %s \n", val, c.get("matviewname"), c2.get("matviewname"))
	return val
}

// Add returns SQL to create the matview
func (c MatViewSchema) Add() {
	fmt.Printf("CREATE MATERIALIZED VIEW %s AS %s \n\n", c.get("matviewname"), c.get("definition"))
}

// Drop returns SQL to drop the matview
func (c MatViewSchema) Drop() {
	fmt.Printf("DROP MATERIALIZED VIEW %s;\n\n", c.get("matviewname"))
}

// Change handles the case where the names match, but the definition does not
func (c MatViewSchema) Change(obj interface{}) {
	c2, ok := obj.(*MatViewSchema)
	if !ok {
		fmt.Println("Error!!!, Change needs a MatViewSchema instance", c2)
	}
	if c.get("definition") != c2.get("definition") {
		fmt.Printf("DROP MATERIALIZED VIEW %s;\n", c.get("matviewname"))
		fmt.Printf("CREATE MATERIALIZED VIEW %s AS %s \n\n", c.get("matviewname"), c.get("definition"))
	}
}

// compareMatViews outputs SQL to make the matviews match between DBs
func compareMatViews(conn1 *sql.DB, conn2 *sql.DB) {
	sql := `
	SELECT schemaname || '.' || matviewname AS matviewname
	, definition
	FROM pg_matviews
	WHERE schemaname NOT LIKE 'pg_%'
	ORDER BY matviewname;
	`

	rowChan1, _ := pgutil.QueryStrings(conn1, sql)
	rowChan2, _ := pgutil.QueryStrings(conn2, sql)

	rows1 := make(MatViewRows, 0)
	for row := range rowChan1 {
		rows1 = append(rows1, row)
	}
	sort.Sort(rows1)

	rows2 := make(MatViewRows, 0)
	for row := range rowChan2 {
		rows2 = append(rows2, row)
	}
	sort.Sort(rows2)

	// We have to explicitly type this as Schema here
	var schema1 Schema = &MatViewSchema{rows: rows1, rowNum: -1}
	var schema2 Schema = &MatViewSchema{rows: rows2, rowNum: -1}

	// Compare the matviews
	doDiff(schema1, schema2)
}
<commit_msg>automatically recreates indexes after matview recreation<commit_after>//
// Copyright (c) 2016 Jon Carlson.  All rights reserved.
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//

package main

import (
	"database/sql"
	"fmt"
	"sort"

	"github.com/joncrlsn/misc"
	"github.com/joncrlsn/pgutil"
)

// ==================================
// MatViewRows definition
// ==================================

// MatViewRows is a sortable slice of string maps
type MatViewRows []map[string]string

func (slice MatViewRows) Len() int {
	return len(slice)
}

func (slice MatViewRows) Less(i, j int) bool {
	return slice[i]["matviewname"] < slice[j]["matviewname"]
}

func (slice MatViewRows) Swap(i, j int) {
	slice[i], slice[j] = slice[j], slice[i]
}

// MatViewSchema holds a channel streaming matview information from one of the databases as well as
// a reference to the current row of data we're matviewing.
//
// MatViewSchema implements the Schema interface defined in pgdiff.go
type MatViewSchema struct {
	rows   MatViewRows
	rowNum int
	done   bool
}

// get returns the value from the current row for the given key
func (c *MatViewSchema) get(key string) string {
	if c.rowNum >= len(c.rows) {
		return ""
	}
	return c.rows[c.rowNum][key]
}

// NextRow increments the rowNum and tells you whether or not there are more
func (c *MatViewSchema) NextRow() bool {
	if c.rowNum >= len(c.rows)-1 {
		c.done = true
	}
	c.rowNum = c.rowNum + 1
	return !c.done
}

// Compare tells you, in one pass, whether or not the first row matches, is less than, or greater than the second row
func (c *MatViewSchema) Compare(obj interface{}) int {
	c2, ok := obj.(*MatViewSchema)
	if !ok {
		fmt.Println("Error!!!, Compare(obj) needs a MatViewSchema instance", c2)
		return +999
	}

	val := misc.CompareStrings(c.get("matviewname"), c2.get("matviewname"))
	//fmt.Printf("-- Compared %v: %s with %s \n", val, c.get("matviewname"), c2.get("matviewname"))
	return val
}

// Add returns SQL to create the matview
func (c MatViewSchema) Add() {
	fmt.Printf("CREATE OR REPLACE MATERIALIZED VIEW %s AS %s \n\n%s \n\n", c.get("matviewname"), c.get("definition"), c.get("indexdef"))
}

// Drop returns SQL to drop the matview
func (c MatViewSchema) Drop() {
	fmt.Printf("DROP MATERIALIZED VIEW %s;\n\n", c.get("matviewname"))
}

// Change handles the case where the names match, but the definition does not
func (c MatViewSchema) Change(obj interface{}) {
	c2, ok := obj.(*MatViewSchema)
	if !ok {
		fmt.Println("Error!!!, Change needs a MatViewSchema instance", c2)
	}
	if c.get("definition") != c2.get("definition") {
		fmt.Printf("DROP MATERIALIZED VIEW %s;\n\n", c.get("matviewname"))
		fmt.Printf("CREATE OR REPLACE MATERIALIZED VIEW %s AS %s \n\n%s \n\n", c.get("matviewname"), c.get("definition"), c.get("indexdef"))
	}
}

// compareMatViews outputs SQL to make the matviews match between DBs
func compareMatViews(conn1 *sql.DB, conn2 *sql.DB) {
	sql := `
	WITH matviews as ( SELECT schemaname || '.' || matviewname AS matviewname,
	definition
	FROM pg_catalog.pg_matviews
	WHERE schemaname NOT LIKE 'pg_%'
	)
	SELECT
	matviewname,
	definition,
	string_agg(indexdef, ';' || E'\n\n') || ';' as indexdef
	FROM matviews
	LEFT JOIN  pg_catalog.pg_indexes on matviewname = schemaname || '.' || tablename
	group by matviewname, definition
	ORDER BY
	matviewname;
	`

	rowChan1, _ := pgutil.QueryStrings(conn1, sql)
	rowChan2, _ := pgutil.QueryStrings(conn2, sql)

	rows1 := make(MatViewRows, 0)
	for row := range rowChan1 {
		rows1 = append(rows1, row)
	}
	sort.Sort(rows1)

	rows2 := make(MatViewRows, 0)
	for row := range rowChan2 {
		rows2 = append(rows2, row)
	}
	sort.Sort(rows2)

	// We have to explicitly type this as Schema here
	var schema1 Schema = &MatViewSchema{rows: rows1, rowNum: -1}
	var schema2 Schema = &MatViewSchema{rows: rows2, rowNum: -1}

	// Compare the matviews
	doDiff(schema1, schema2)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/boivie/lovebeat-go/alert"
	"github.com/boivie/lovebeat-go/backend"
	"github.com/boivie/lovebeat-go/config"
	"github.com/boivie/lovebeat-go/dashboard"
	"github.com/boivie/lovebeat-go/httpapi"
	"github.com/boivie/lovebeat-go/service"
	"github.com/boivie/lovebeat-go/tcpapi"
	"github.com/boivie/lovebeat-go/udpapi"
	"github.com/gorilla/mux"
	"github.com/op/go-logging"
	"net/http"
	"os"
	"os/signal"
	"runtime"
	"strings"
	"syscall"
)

var log = logging.MustGetLogger("lovebeat")

const (
	VERSION = "0.8.0"
)

var (
	udpAddr     = flag.String("udp", ":8127", "UDP service address")
	tcpAddr     = flag.String("tcp", ":8127", "TCP service address")
	debug       = flag.Bool("debug", false, "Enable debug printouts")
	showVersion = flag.Bool("version", false, "Print version string")
	workDir     = flag.String("workdir", "work", "Working directory")
	cfgFile     = flag.String("config", "/etc/lovebeat.cfg", "Configuration file")
)

var (
	signalchan = make(chan os.Signal, 1)
)

func signalHandler(be backend.Backend) {
	for {
		select {
		case sig := <-signalchan:
			fmt.Printf("!! Caught signal %d... shutting down\n", sig)
			be.Sync()
			return
		}
	}
}

func httpServer(port int16, svcs *service.Services) {
	rtr := mux.NewRouter()
	httpapi.Register(rtr, svcs.GetClient())
	dashboard.Register(rtr, svcs.GetClient())
	http.Handle("/", rtr)
	log.Info("HTTP server running on port %d\n", port)
	http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
}

func getHostname() string {
	var hostname, err = os.Hostname()
	if err != nil {
		return fmt.Sprintf("unknown_%d", os.Getpid())
	}
	return strings.Split(hostname, ".")[0]
}

func main() {
	flag.Parse()

	var format = logging.MustStringFormatter("%{level} %{message}")
	logging.SetFormatter(format)
	if *debug {
		logging.SetLevel(logging.DEBUG, "lovebeat")
	} else {
		logging.SetLevel(logging.INFO, "lovebeat")
	}
	log.Debug("Debug logs enabled")

	if *showVersion {
		fmt.Printf("lovebeats v%s (built w/%s)\n", VERSION, runtime.Version())
		return
	}

	var cfg = config.ReadConfig(*cfgFile)

	var hostname = getHostname()
	log.Info("Lovebeat v%s started as host %s, PID %d", VERSION, hostname, os.Getpid())

	var be = backend.NewFileBackend(*workDir)
	var alerters = []alert.Alerter{alert.NewMailAlerter(&cfg.Mail),
		alert.NewWebhooksAlerter()}
	var svcs = service.NewServices(be, alerters)

	signal.Notify(signalchan, syscall.SIGTERM)
	signal.Notify(signalchan, os.Interrupt)

	go svcs.Monitor()
	go httpServer(8080, svcs)
	go udpapi.Listener(*udpAddr, svcs.GetClient())
	go tcpapi.Listener(*tcpAddr, svcs.GetClient())

	// Ensure that the 'all' view exists
	svcs.GetClient().CreateOrUpdateView("all", "", "", "")

	signalHandler(be)
}
<commit_msg>Can specify HTTP bind address and port<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/boivie/lovebeat-go/alert"
	"github.com/boivie/lovebeat-go/backend"
	"github.com/boivie/lovebeat-go/config"
	"github.com/boivie/lovebeat-go/dashboard"
	"github.com/boivie/lovebeat-go/httpapi"
	"github.com/boivie/lovebeat-go/service"
	"github.com/boivie/lovebeat-go/tcpapi"
	"github.com/boivie/lovebeat-go/udpapi"
	"github.com/gorilla/mux"
	"github.com/op/go-logging"
	"net/http"
	"os"
	"os/signal"
	"runtime"
	"strings"
	"syscall"
)

var log = logging.MustGetLogger("lovebeat")

const (
	VERSION = "0.8.0"
)

var (
	udpAddr     = flag.String("udp", ":8127", "UDP service address")
	tcpAddr     = flag.String("tcp", ":8127", "TCP service address")
	httpAddr    = flag.String("http", ":8080", "HTTP service address")
	debug       = flag.Bool("debug", false, "Enable debug printouts")
	showVersion = flag.Bool("version", false, "Print version string")
	workDir     = flag.String("workdir", "work", "Working directory")
	cfgFile     = flag.String("config", "/etc/lovebeat.cfg", "Configuration file")
)

var (
	signalchan = make(chan os.Signal, 1)
)

func signalHandler(be backend.Backend) {
	for {
		select {
		case sig := <-signalchan:
			fmt.Printf("!! Caught signal %d... shutting down\n", sig)
			be.Sync()
			return
		}
	}
}

func httpServer(bindAddr string, svcs *service.Services) {
	rtr := mux.NewRouter()
	httpapi.Register(rtr, svcs.GetClient())
	dashboard.Register(rtr, svcs.GetClient())
	http.Handle("/", rtr)
	log.Info("HTTP listening on %s\n", bindAddr)
	http.ListenAndServe(bindAddr, nil)
}

func getHostname() string {
	var hostname, err = os.Hostname()
	if err != nil {
		return fmt.Sprintf("unknown_%d", os.Getpid())
	}
	return strings.Split(hostname, ".")[0]
}

func main() {
	flag.Parse()

	var format = logging.MustStringFormatter("%{level} %{message}")
	logging.SetFormatter(format)
	if *debug {
		logging.SetLevel(logging.DEBUG, "lovebeat")
	} else {
		logging.SetLevel(logging.INFO, "lovebeat")
	}
	log.Debug("Debug logs enabled")

	if *showVersion {
		fmt.Printf("lovebeats v%s (built w/%s)\n", VERSION, runtime.Version())
		return
	}

	var cfg = config.ReadConfig(*cfgFile)

	var hostname = getHostname()
	log.Info("Lovebeat v%s started as host %s, PID %d", VERSION, hostname, os.Getpid())

	var be = backend.NewFileBackend(*workDir)
	var alerters = []alert.Alerter{alert.NewMailAlerter(&cfg.Mail),
		alert.NewWebhooksAlerter()}
	var svcs = service.NewServices(be, alerters)

	signal.Notify(signalchan, syscall.SIGTERM)
	signal.Notify(signalchan, os.Interrupt)

	go svcs.Monitor()
	go httpServer(*httpAddr, svcs)
	go udpapi.Listener(*udpAddr, svcs.GetClient())
	go tcpapi.Listener(*tcpAddr, svcs.GetClient())

	// Ensure that the 'all' view exists
	svcs.GetClient().CreateOrUpdateView("all", "", "", "")

	signalHandler(be)
}
<|endoftext|>


<commit_before>package router

import (
	"net/url"

	"github.com/sqs/mux"
	"sourcegraph.com/sourcegraph/srclib/graph"
)

const (
	Build            = "build"
	BuildUpdate      = "build.update"
	BuildLog         = "build.log"
	Builds           = "builds"
	BuildTasks       = "build.tasks"
	BuildTaskUpdate  = "build.task"
	BuildTasksCreate = "build.tasks.create"
	BuildTaskLog     = "build.task.log"

	Org               = "org"
	OrgMembers        = "org.members"
	OrgSettings       = "org.settings"
	OrgSettingsUpdate = "org.settings.update"

	People                        = "people"
	Person                        = "person"
	PersonOrgs                    = "person.orgs"
	PersonAuthors                 = "person.authors"
	PersonClients                 = "person.clients"
	PersonEmails                  = "person.emails"
	PersonFromGitHub              = "person.from-github"
	PersonRepositoryContributions = "person.repo-contributions"
	PersonRepositoryDependencies  = "person.repo-dependencies"
	PersonRepositoryDependents    = "person.repo-dependents"
	PersonRefreshProfile          = "person.refresh-profile"
	PersonSettings                = "person.settings"
	PersonSettingsUpdate          = "person.settings.update"
	PersonComputeStats            = "person.compute-stats"

	RepoPullRequests        = "repo.pull-requests"
	RepoPullRequest         = "repo.pull-request"
	RepoPullRequestComments = "repo.pull-request.comments"

	RepoIssues        = "repo.issues"
	RepoIssue         = "repo.issue"
	RepoIssueComments = "repo.issue.comments"

	Repositories             = "repos"
	RepositoriesCreate       = "repos.create"
	RepositoriesGetOrCreate  = "repos.get-or-create"
	Repository               = "repo"
	RepositoryAuthors        = "repo.authors"
	RepositoryClients        = "repo.clients"
	RepositoryDependents     = "repo.dependents"
	RepositoryDependencies   = "repo.dependencies"
	RepositoryBadge          = "repo.badge"
	RepositoryBadges         = "repo.badges"
	RepositoryCounter        = "repo.counter"
	RepositoryCounters       = "repo.counters"
	RepositoryReadme         = "repo.readme"
	RepositoryBuilds         = "repo.builds"
	RepositoryBuildsCreate   = "repo.builds.create"
	RepositoryBuildDataEntry = "repo.build-data.entry"
	RepositoryDocPage        = "repo.doc-page"
	RepositoryTreeEntry      = "repo.tree.entry"
	RepositoryRefreshProfile = "repo.refresh-profile"
	RepositoryRefreshVCSData = "repo.refresh-vcs-data"
	RepositoryComputeStats   = "repo.compute-stats"

	RepositorySettings       = "repo.settings"
	RepositorySettingsUpdate = "repo.settings.update"

	RepositoryStats = "repo.stats"

	RepoBuild = "repo.build"

	RepoCommits        = "repo.commits"
	RepoCommit         = "repo.commit"
	RepoCompareCommits = "repo.compare-commits"
	RepoTags           = "repo.tags"
	RepoBranches       = "repo.branches"

	Unit  = "unit"
	Units = "units"

	Search = "search"

	Snippet = "snippet"

	Defs          = "defs"
	Def           = "def"
	DefBySID      = "def-by-sid"
	DefExamples   = "def.examples"
	DefAuthors    = "def.authors"
	DefClients    = "def.clients"
	DefDependents = "def.dependents"
	DefVersions   = "def.versions"

	Delta                   = "delta"
	DeltaDefs               = "delta.defs"
	DeltaDependencies       = "delta.dependencies"
	DeltaFiles              = "delta.files"
	DeltaAffectedAuthors    = "delta.affected-authors"
	DeltaAffectedClients    = "delta.affected-clients"
	DeltaAffectedDependents = "delta.affected-dependents"
	DeltaReviewers          = "delta.reviewers"
	DeltasIncoming          = "deltas.incoming"

	ExtGitHubReceiveWebhook = "ext.github.receive-webhook"

	// Redirects for old routes.
	RedirectOldRepositoryBadgesAndCounters = "repo.redirect-old-badges-and-counters"
)

var APIRouter = NewAPIRouter(mux.NewRouter().PathPrefix("/api").Subrouter())

// NewAPIRouter creates a new API router with route URL pattern definitions but
// no handlers attached to the routes.
//
// It is in a separate package from app so that other packages may use it to
// generate URLs without resulting in Go import cycles (and so we can release
// the router as open-source to support our client library).
func NewAPIRouter(base *mux.Router) *mux.Router {
	if base == nil {
		base = mux.NewRouter()
	}

	base.StrictSlash(true)

	base.Path("/builds").Methods("GET").Name(Builds)
	builds := base.PathPrefix("/builds").Subrouter()
	buildPath := "/{BID}"
	builds.Path(buildPath).Methods("GET").Name(Build)
	builds.Path(buildPath).Methods("PUT").Name(BuildUpdate)
	build := builds.PathPrefix(buildPath).Subrouter()
	build.Path("/log").Methods("GET").Name(BuildLog)
	build.Path("/tasks").Methods("GET").Name(BuildTasks)
	build.Path("/tasks").Methods("POST").Name(BuildTasksCreate)
	build.Path("/tasks/{TaskID}").Methods("PUT").Name(BuildTaskUpdate)
	build.Path("/tasks/{TaskID}/log").Methods("GET").Name(BuildTaskLog)

	base.Path("/repos").Methods("GET").Name(Repositories)
	base.Path("/repos").Methods("POST").Name(RepositoriesCreate)

	base.Path("/repos/github.com/{owner:[^/]+}/{repo:[^/]+}/{what:(?:badges|counters)}/{which}.png").Methods("GET").Name(RedirectOldRepositoryBadgesAndCounters)

	repoRev := base.PathPrefix(`/repos/` + RepoRevSpecPattern).PostMatchFunc(FixRepoRevSpecVars).BuildVarsFunc(PrepareRepoRevSpecRouteVars).Subrouter()
	repoRev.Path("/.stats").Methods("PUT").Name(RepositoryComputeStats)
	repoRev.Path("/.stats").Methods("GET").Name(RepositoryStats)
	repoRev.Path("/.authors").Methods("GET").Name(RepositoryAuthors)
	repoRev.Path("/.readme").Methods("GET").Name(RepositoryReadme)
	repoRev.Path("/.build").Methods("GET").Name(RepoBuild)
	repoRev.Path("/.dependencies").Methods("GET").Name(RepositoryDependencies)
	repoRev.PathPrefix("/.build-data"+TreeEntryPathPattern).PostMatchFunc(FixTreeEntryVars).BuildVarsFunc(PrepareTreeEntryRouteVars).Methods("GET", "PUT").Name(RepositoryBuildDataEntry)
	repoRev.Path("/.docs/{Path:.*}").Methods("GET").Name(RepositoryDocPage)
	repoRev.Path("/.badges/{Badge}.png").Methods("GET").Name(RepositoryBadge)

	// repo contains routes that are NOT specific to a revision. In these routes, the URL may not contain a revspec after the repo (that is, no "github.com/foo/bar@myrevspec").
	repoPath := `/repos/` + RepoSpecPathPattern
	base.Path(repoPath).Methods("GET").Name(Repository)
	base.Path(repoPath).Methods("PUT").Name(RepositoriesGetOrCreate)
	repo := base.PathPrefix(repoPath).Subrouter()
	repo.Path("/.clients").Methods("GET").Name(RepositoryClients)
	repo.Path("/.dependents").Methods("GET").Name(RepositoryDependents)
	repo.Path("/.external-profile").Methods("PUT").Name(RepositoryRefreshProfile)
	repo.Path("/.vcs-data").Methods("PUT").Name(RepositoryRefreshVCSData)
	repo.Path("/.settings").Methods("GET").Name(RepositorySettings)
	repo.Path("/.settings").Methods("PUT").Name(RepositorySettingsUpdate)
	repo.Path("/.commits").Methods("GET").Name(RepoCommits)
	repo.Path("/.commits/{Rev:.+}/compare").Methods("GET").Name(RepoCompareCommits)
	repo.Path("/.commits/{Rev:.+}").Methods("GET").Name(RepoCommit)
	repo.Path("/.branches").Methods("GET").Name(RepoBranches)
	repo.Path("/.tags").Methods("GET").Name(RepoTags)
	repo.Path("/.badges").Methods("GET").Name(RepositoryBadges)
	repo.Path("/.counters").Methods("GET").Name(RepositoryCounters)
	repo.Path("/.counters/{Counter}.png").Methods("GET").Name(RepositoryCounter)
	repo.Path("/.builds").Methods("GET").Name(RepositoryBuilds)
	repo.Path("/.builds").Methods("POST").Name(RepositoryBuildsCreate)

	repo.Path("/.pulls").Methods("GET").Name(RepoPullRequests)
	pullPath := "/.pulls/{Pull}"
	repo.Path(pullPath).Methods("GET").Name(RepoPullRequest)
	pull := repo.PathPrefix(pullPath).Subrouter()
	pull.Path("/comments").Methods("GET").Name(RepoPullRequestComments)

	repo.Path("/.issues").Methods("GET").Name(RepoIssues)
	issuePath := "/.issues/{Issue}"
	repo.Path(issuePath).Methods("GET").Name(RepoIssue)
	issue := repo.PathPrefix(issuePath).Subrouter()
	issue.Path("/comments").Methods("GET").Name(RepoIssueComments)

	deltaPath := "/.deltas/{Rev:.+}..{DeltaHeadRev:" + PathComponentNoLeadingDot + "}"
	repo.Path(deltaPath).Methods("GET").Name(Delta)
	deltas := repo.PathPrefix(deltaPath).Subrouter()
	deltas.Path("/.defs").Methods("GET").Name(DeltaDefs)
	deltas.Path("/.dependencies").Methods("GET").Name(DeltaDependencies)
	deltas.Path("/.files").Methods("GET").Name(DeltaFiles)
	deltas.Path("/.affected-authors").Methods("GET").Name(DeltaAffectedAuthors)
	deltas.Path("/.affected-clients").Methods("GET").Name(DeltaAffectedClients)
	deltas.Path("/.affected-dependents").Methods("GET").Name(DeltaAffectedDependents)
	deltas.Path("/.reviewers").Methods("GET").Name(DeltaReviewers)

	repo.Path("/.deltas-incoming").Methods("GET").Name(DeltasIncoming)

	// See router_util/tree_route.go for an explanation of how we match tree
	// entry routes.
	repoRev.Path("/.tree" + TreeEntryPathPattern).PostMatchFunc(FixTreeEntryVars).BuildVarsFunc(PrepareTreeEntryRouteVars).Methods("GET").Name(RepositoryTreeEntry)

	base.Path("/people").Methods("GET").Name(People)
	personPath := `/people/` + PersonSpecPattern
	base.Path(personPath).Methods("GET").Name(Person)
	person := base.PathPrefix(personPath).Subrouter()
	person.Path("/orgs").Methods("GET").Name(PersonOrgs)
	person.Path("/clients").Methods("GET").Name(PersonClients)
	person.Path("/authors").Methods("GET").Name(PersonAuthors)
	person.Path("/emails").Methods("GET").Name(PersonEmails)
	person.Path("/repo-contributions").Methods("GET").Name(PersonRepositoryContributions)
	person.Path("/repo-dependencies").Methods("GET").Name(PersonRepositoryDependencies)
	person.Path("/repo-dependents").Methods("GET").Name(PersonRepositoryDependents)
	person.Path("/external-profile").Methods("PUT").Name(PersonRefreshProfile)
	person.Path("/stats").Methods("PUT").Name(PersonComputeStats)
	person.Path("/settings").Methods("GET").Name(PersonSettings)
	person.Path("/settings").Methods("PUT").Name(PersonSettingsUpdate)
	base.Path("/external-users/github/{GitHubUserSpec}").Methods("GET").Name(PersonFromGitHub)

	orgPath := "/orgs/{OrgSpec}"
	base.Path(orgPath).Methods("GET").Name(Org)
	org := base.PathPrefix(orgPath).Subrouter()
	org.Path("/settings").Methods("GET").Name(OrgSettings)
	org.Path("/settings").Methods("PUT").Name(OrgSettingsUpdate)
	org.Path("/members").Methods("GET").Name(OrgMembers)

	base.Path("/search").Methods("GET").Name(Search)

	base.Path("/snippet").Methods("GET", "POST", "ORIGIN").Name(Snippet)

	base.Path("/.defs").Methods("GET").Name(Defs)
	base.Path(`/.defs/{SID:\d+}`).Methods("GET").Name(DefBySID)

	// See router_util/def_route.go for an explanation of how we match def
	// routes.
	defPath := `/.defs/` + DefPathPattern
	repoRev.Path(defPath).Methods("GET").PostMatchFunc(FixDefUnitVars).BuildVarsFunc(PrepareDefRouteVars).Name(Def)
	def := repoRev.PathPrefix(defPath).PostMatchFunc(FixDefUnitVars).BuildVarsFunc(PrepareDefRouteVars).Subrouter()
	def.Path("/.examples").Methods("GET").Name(DefExamples)
	def.Path("/.authors").Methods("GET").Name(DefAuthors)
	def.Path("/.clients").Methods("GET").Name(DefClients)
	def.Path("/.dependents").Methods("GET").Name(DefDependents)
	def.Path("/.versions").Methods("GET").Name(DefVersions)

	base.Path("/.units").Methods("GET").Name(Units)
	unitPath := `/.units/.{UnitType}/{Unit:.*}`
	repoRev.Path(unitPath).Methods("GET").Name(Unit)

	base.Path("/ext/github/webhook").Methods("POST").Name(ExtGitHubReceiveWebhook)

	return base
}

func URIToDef(key graph.DefKey) *url.URL {
	return URITo(Def, "RepoSpec", string(key.Repo), "UnitType", key.UnitType, "Unit", key.Unit, "Path", string(key.Path))
}

func URITo(routeName string, params ...string) *url.URL {
	return URLTo(APIRouter, routeName, params...)
}
<commit_msg>/.commit/Rev/compare -> /.commit/Rev/.compare<commit_after>package router

import (
	"net/url"

	"github.com/sqs/mux"
	"sourcegraph.com/sourcegraph/srclib/graph"
)

const (
	Build            = "build"
	BuildUpdate      = "build.update"
	BuildLog         = "build.log"
	Builds           = "builds"
	BuildTasks       = "build.tasks"
	BuildTaskUpdate  = "build.task"
	BuildTasksCreate = "build.tasks.create"
	BuildTaskLog     = "build.task.log"

	Org               = "org"
	OrgMembers        = "org.members"
	OrgSettings       = "org.settings"
	OrgSettingsUpdate = "org.settings.update"

	People                        = "people"
	Person                        = "person"
	PersonOrgs                    = "person.orgs"
	PersonAuthors                 = "person.authors"
	PersonClients                 = "person.clients"
	PersonEmails                  = "person.emails"
	PersonFromGitHub              = "person.from-github"
	PersonRepositoryContributions = "person.repo-contributions"
	PersonRepositoryDependencies  = "person.repo-dependencies"
	PersonRepositoryDependents    = "person.repo-dependents"
	PersonRefreshProfile          = "person.refresh-profile"
	PersonSettings                = "person.settings"
	PersonSettingsUpdate          = "person.settings.update"
	PersonComputeStats            = "person.compute-stats"

	RepoPullRequests        = "repo.pull-requests"
	RepoPullRequest         = "repo.pull-request"
	RepoPullRequestComments = "repo.pull-request.comments"

	RepoIssues        = "repo.issues"
	RepoIssue         = "repo.issue"
	RepoIssueComments = "repo.issue.comments"

	Repositories             = "repos"
	RepositoriesCreate       = "repos.create"
	RepositoriesGetOrCreate  = "repos.get-or-create"
	Repository               = "repo"
	RepositoryAuthors        = "repo.authors"
	RepositoryClients        = "repo.clients"
	RepositoryDependents     = "repo.dependents"
	RepositoryDependencies   = "repo.dependencies"
	RepositoryBadge          = "repo.badge"
	RepositoryBadges         = "repo.badges"
	RepositoryCounter        = "repo.counter"
	RepositoryCounters       = "repo.counters"
	RepositoryReadme         = "repo.readme"
	RepositoryBuilds         = "repo.builds"
	RepositoryBuildsCreate   = "repo.builds.create"
	RepositoryBuildDataEntry = "repo.build-data.entry"
	RepositoryDocPage        = "repo.doc-page"
	RepositoryTreeEntry      = "repo.tree.entry"
	RepositoryRefreshProfile = "repo.refresh-profile"
	RepositoryRefreshVCSData = "repo.refresh-vcs-data"
	RepositoryComputeStats   = "repo.compute-stats"

	RepositorySettings       = "repo.settings"
	RepositorySettingsUpdate = "repo.settings.update"

	RepositoryStats = "repo.stats"

	RepoBuild = "repo.build"

	RepoCommits        = "repo.commits"
	RepoCommit         = "repo.commit"
	RepoCompareCommits = "repo.compare-commits"
	RepoTags           = "repo.tags"
	RepoBranches       = "repo.branches"

	Unit  = "unit"
	Units = "units"

	Search = "search"

	Snippet = "snippet"

	Defs          = "defs"
	Def           = "def"
	DefBySID      = "def-by-sid"
	DefExamples   = "def.examples"
	DefAuthors    = "def.authors"
	DefClients    = "def.clients"
	DefDependents = "def.dependents"
	DefVersions   = "def.versions"

	Delta                   = "delta"
	DeltaDefs               = "delta.defs"
	DeltaDependencies       = "delta.dependencies"
	DeltaFiles              = "delta.files"
	DeltaAffectedAuthors    = "delta.affected-authors"
	DeltaAffectedClients    = "delta.affected-clients"
	DeltaAffectedDependents = "delta.affected-dependents"
	DeltaReviewers          = "delta.reviewers"
	DeltasIncoming          = "deltas.incoming"

	ExtGitHubReceiveWebhook = "ext.github.receive-webhook"

	// Redirects for old routes.
	RedirectOldRepositoryBadgesAndCounters = "repo.redirect-old-badges-and-counters"
)

var APIRouter = NewAPIRouter(mux.NewRouter().PathPrefix("/api").Subrouter())

// NewAPIRouter creates a new API router with route URL pattern definitions but
// no handlers attached to the routes.
//
// It is in a separate package from app so that other packages may use it to
// generate URLs without resulting in Go import cycles (and so we can release
// the router as open-source to support our client library).
func NewAPIRouter(base *mux.Router) *mux.Router {
	if base == nil {
		base = mux.NewRouter()
	}

	base.StrictSlash(true)

	base.Path("/builds").Methods("GET").Name(Builds)
	builds := base.PathPrefix("/builds").Subrouter()
	buildPath := "/{BID}"
	builds.Path(buildPath).Methods("GET").Name(Build)
	builds.Path(buildPath).Methods("PUT").Name(BuildUpdate)
	build := builds.PathPrefix(buildPath).Subrouter()
	build.Path("/log").Methods("GET").Name(BuildLog)
	build.Path("/tasks").Methods("GET").Name(BuildTasks)
	build.Path("/tasks").Methods("POST").Name(BuildTasksCreate)
	build.Path("/tasks/{TaskID}").Methods("PUT").Name(BuildTaskUpdate)
	build.Path("/tasks/{TaskID}/log").Methods("GET").Name(BuildTaskLog)

	base.Path("/repos").Methods("GET").Name(Repositories)
	base.Path("/repos").Methods("POST").Name(RepositoriesCreate)

	base.Path("/repos/github.com/{owner:[^/]+}/{repo:[^/]+}/{what:(?:badges|counters)}/{which}.png").Methods("GET").Name(RedirectOldRepositoryBadgesAndCounters)

	repoRev := base.PathPrefix(`/repos/` + RepoRevSpecPattern).PostMatchFunc(FixRepoRevSpecVars).BuildVarsFunc(PrepareRepoRevSpecRouteVars).Subrouter()
	repoRev.Path("/.stats").Methods("PUT").Name(RepositoryComputeStats)
	repoRev.Path("/.stats").Methods("GET").Name(RepositoryStats)
	repoRev.Path("/.authors").Methods("GET").Name(RepositoryAuthors)
	repoRev.Path("/.readme").Methods("GET").Name(RepositoryReadme)
	repoRev.Path("/.build").Methods("GET").Name(RepoBuild)
	repoRev.Path("/.dependencies").Methods("GET").Name(RepositoryDependencies)
	repoRev.PathPrefix("/.build-data"+TreeEntryPathPattern).PostMatchFunc(FixTreeEntryVars).BuildVarsFunc(PrepareTreeEntryRouteVars).Methods("GET", "PUT").Name(RepositoryBuildDataEntry)
	repoRev.Path("/.docs/{Path:.*}").Methods("GET").Name(RepositoryDocPage)
	repoRev.Path("/.badges/{Badge}.png").Methods("GET").Name(RepositoryBadge)

	// repo contains routes that are NOT specific to a revision. In these routes, the URL may not contain a revspec after the repo (that is, no "github.com/foo/bar@myrevspec").
	repoPath := `/repos/` + RepoSpecPathPattern
	base.Path(repoPath).Methods("GET").Name(Repository)
	base.Path(repoPath).Methods("PUT").Name(RepositoriesGetOrCreate)
	repo := base.PathPrefix(repoPath).Subrouter()
	repo.Path("/.clients").Methods("GET").Name(RepositoryClients)
	repo.Path("/.dependents").Methods("GET").Name(RepositoryDependents)
	repo.Path("/.external-profile").Methods("PUT").Name(RepositoryRefreshProfile)
	repo.Path("/.vcs-data").Methods("PUT").Name(RepositoryRefreshVCSData)
	repo.Path("/.settings").Methods("GET").Name(RepositorySettings)
	repo.Path("/.settings").Methods("PUT").Name(RepositorySettingsUpdate)
	repo.Path("/.commits").Methods("GET").Name(RepoCommits)
	repo.Path("/.commits/{Rev:" + PathComponentNoLeadingDot + "}/.compare").Methods("GET").Name(RepoCompareCommits)
	repo.Path("/.commits/{Rev:" + PathComponentNoLeadingDot + "}").Methods("GET").Name(RepoCommit)
	repo.Path("/.branches").Methods("GET").Name(RepoBranches)
	repo.Path("/.tags").Methods("GET").Name(RepoTags)
	repo.Path("/.badges").Methods("GET").Name(RepositoryBadges)
	repo.Path("/.counters").Methods("GET").Name(RepositoryCounters)
	repo.Path("/.counters/{Counter}.png").Methods("GET").Name(RepositoryCounter)
	repo.Path("/.builds").Methods("GET").Name(RepositoryBuilds)
	repo.Path("/.builds").Methods("POST").Name(RepositoryBuildsCreate)

	repo.Path("/.pulls").Methods("GET").Name(RepoPullRequests)
	pullPath := "/.pulls/{Pull}"
	repo.Path(pullPath).Methods("GET").Name(RepoPullRequest)
	pull := repo.PathPrefix(pullPath).Subrouter()
	pull.Path("/comments").Methods("GET").Name(RepoPullRequestComments)

	repo.Path("/.issues").Methods("GET").Name(RepoIssues)
	issuePath := "/.issues/{Issue}"
	repo.Path(issuePath).Methods("GET").Name(RepoIssue)
	issue := repo.PathPrefix(issuePath).Subrouter()
	issue.Path("/comments").Methods("GET").Name(RepoIssueComments)

	deltaPath := "/.deltas/{Rev:.+}..{DeltaHeadRev:" + PathComponentNoLeadingDot + "}"
	repo.Path(deltaPath).Methods("GET").Name(Delta)
	deltas := repo.PathPrefix(deltaPath).Subrouter()
	deltas.Path("/.defs").Methods("GET").Name(DeltaDefs)
	deltas.Path("/.dependencies").Methods("GET").Name(DeltaDependencies)
	deltas.Path("/.files").Methods("GET").Name(DeltaFiles)
	deltas.Path("/.affected-authors").Methods("GET").Name(DeltaAffectedAuthors)
	deltas.Path("/.affected-clients").Methods("GET").Name(DeltaAffectedClients)
	deltas.Path("/.affected-dependents").Methods("GET").Name(DeltaAffectedDependents)
	deltas.Path("/.reviewers").Methods("GET").Name(DeltaReviewers)

	repo.Path("/.deltas-incoming").Methods("GET").Name(DeltasIncoming)

	// See router_util/tree_route.go for an explanation of how we match tree
	// entry routes.
	repoRev.Path("/.tree" + TreeEntryPathPattern).PostMatchFunc(FixTreeEntryVars).BuildVarsFunc(PrepareTreeEntryRouteVars).Methods("GET").Name(RepositoryTreeEntry)

	base.Path("/people").Methods("GET").Name(People)
	personPath := `/people/` + PersonSpecPattern
	base.Path(personPath).Methods("GET").Name(Person)
	person := base.PathPrefix(personPath).Subrouter()
	person.Path("/orgs").Methods("GET").Name(PersonOrgs)
	person.Path("/clients").Methods("GET").Name(PersonClients)
	person.Path("/authors").Methods("GET").Name(PersonAuthors)
	person.Path("/emails").Methods("GET").Name(PersonEmails)
	person.Path("/repo-contributions").Methods("GET").Name(PersonRepositoryContributions)
	person.Path("/repo-dependencies").Methods("GET").Name(PersonRepositoryDependencies)
	person.Path("/repo-dependents").Methods("GET").Name(PersonRepositoryDependents)
	person.Path("/external-profile").Methods("PUT").Name(PersonRefreshProfile)
	person.Path("/stats").Methods("PUT").Name(PersonComputeStats)
	person.Path("/settings").Methods("GET").Name(PersonSettings)
	person.Path("/settings").Methods("PUT").Name(PersonSettingsUpdate)
	base.Path("/external-users/github/{GitHubUserSpec}").Methods("GET").Name(PersonFromGitHub)

	orgPath := "/orgs/{OrgSpec}"
	base.Path(orgPath).Methods("GET").Name(Org)
	org := base.PathPrefix(orgPath).Subrouter()
	org.Path("/settings").Methods("GET").Name(OrgSettings)
	org.Path("/settings").Methods("PUT").Name(OrgSettingsUpdate)
	org.Path("/members").Methods("GET").Name(OrgMembers)

	base.Path("/search").Methods("GET").Name(Search)

	base.Path("/snippet").Methods("GET", "POST", "ORIGIN").Name(Snippet)

	base.Path("/.defs").Methods("GET").Name(Defs)
	base.Path(`/.defs/{SID:\d+}`).Methods("GET").Name(DefBySID)

	// See router_util/def_route.go for an explanation of how we match def
	// routes.
	defPath := `/.defs/` + DefPathPattern
	repoRev.Path(defPath).Methods("GET").PostMatchFunc(FixDefUnitVars).BuildVarsFunc(PrepareDefRouteVars).Name(Def)
	def := repoRev.PathPrefix(defPath).PostMatchFunc(FixDefUnitVars).BuildVarsFunc(PrepareDefRouteVars).Subrouter()
	def.Path("/.examples").Methods("GET").Name(DefExamples)
	def.Path("/.authors").Methods("GET").Name(DefAuthors)
	def.Path("/.clients").Methods("GET").Name(DefClients)
	def.Path("/.dependents").Methods("GET").Name(DefDependents)
	def.Path("/.versions").Methods("GET").Name(DefVersions)

	base.Path("/.units").Methods("GET").Name(Units)
	unitPath := `/.units/.{UnitType}/{Unit:.*}`
	repoRev.Path(unitPath).Methods("GET").Name(Unit)

	base.Path("/ext/github/webhook").Methods("POST").Name(ExtGitHubReceiveWebhook)

	return base
}

func URIToDef(key graph.DefKey) *url.URL {
	return URITo(Def, "RepoSpec", string(key.Repo), "UnitType", key.UnitType, "Unit", key.Unit, "Path", string(key.Path))
}

func URITo(routeName string, params ...string) *url.URL {
	return URLTo(APIRouter, routeName, params...)
}
<|endoftext|>


<commit_before>// Copyright 2015-2017 trivago GmbH
//
// 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 router

import (
	"github.com/trivago/gollum/core"
)

// Distribute stream plugin
// Messages will be routed to all routers configured. Each target stream can
// hold another stream configuration, too, so this is not directly sending to
// the producers attached to the target routers.
// Configuration example
//
// "myrouter":
//    Type: "router.Distribute"
//    Stream: "mystream"
//    TargetStreams:
//    	- "foo"
//      - "bar"
//
// Routes defines a 1:n stream remapping.
// Messages are reassigned to all of stream(s) in this list.
// If no route is set messages are forwarded on the incoming router.
// When routing to multiple routers, the incoming stream has to be listed explicitly to be used.
type Distribute struct {
	Broadcast `gollumdoc:"DISABLED_embed_type"`
	routers        []core.Router
	boundStreamIDs []core.MessageStreamID
}

func init() {
	core.TypeRegistry.Register(Distribute{})
}

// Configure initializes this distributor with values from a plugin config.
func (router *Distribute) Configure(conf core.PluginConfigReader) error {
	router.Broadcast.Configure(conf)
	router.boundStreamIDs = conf.GetStreamArray("TargetStreams", []core.MessageStreamID{})

	return conf.Errors.OrNil()
}

// Start the router
func (router *Distribute) Start() error {
	for _, streamID := range router.boundStreamIDs {
		targetRouter := core.StreamRegistry.GetRouterOrFallback(streamID)
		router.routers = append(router.routers, targetRouter)
	}

	return nil
}

func (router *Distribute) route(msg *core.Message, targetRouter core.Router) {
	if router.StreamID() == targetRouter.StreamID() {
		router.Broadcast.Enqueue(msg)
	} else {
		msg.SetStreamID(targetRouter.StreamID())
		core.Route(msg, targetRouter)
	}
}

// Enqueue enques a message to the router
func (router *Distribute) Enqueue(msg *core.Message) error {
	numStreams := len(router.routers)

	switch numStreams {
	case 0:
		return core.NewModulateResultError("No producers configured for stream %s", router.GetID())

	case 1:
		router.route(msg, router.routers[0])

	default:
		lastStreamIdx := numStreams - 1
		for streamIdx := 0; streamIdx < lastStreamIdx; streamIdx++ {
			router.route(msg.Clone(), router.routers[streamIdx])
			router.Log.Debug.Printf("routed to StreamID '%v'", router.routers[streamIdx].StreamID())
		}
		router.route(msg, router.routers[lastStreamIdx])
		router.Log.Debug.Printf("routed to StreamID '%v'", router.routers[lastStreamIdx].StreamID())
	}

	return nil
}
<commit_msg>Restore gollumdoc:"embed_type" tag<commit_after>// Copyright 2015-2017 trivago GmbH
//
// 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 router

import (
	"github.com/trivago/gollum/core"
)

// Distribute stream plugin
// Messages will be routed to all routers configured. Each target stream can
// hold another stream configuration, too, so this is not directly sending to
// the producers attached to the target routers.
// Configuration example
//
// "myrouter":
//    Type: "router.Distribute"
//    Stream: "mystream"
//    TargetStreams:
//    	- "foo"
//      - "bar"
//
// Routes defines a 1:n stream remapping.
// Messages are reassigned to all of stream(s) in this list.
// If no route is set messages are forwarded on the incoming router.
// When routing to multiple routers, the incoming stream has to be listed explicitly to be used.
type Distribute struct {
	Broadcast `gollumdoc:"embed_type"`
	routers        []core.Router
	boundStreamIDs []core.MessageStreamID
}

func init() {
	core.TypeRegistry.Register(Distribute{})
}

// Configure initializes this distributor with values from a plugin config.
func (router *Distribute) Configure(conf core.PluginConfigReader) error {
	router.Broadcast.Configure(conf)
	router.boundStreamIDs = conf.GetStreamArray("TargetStreams", []core.MessageStreamID{})

	return conf.Errors.OrNil()
}

// Start the router
func (router *Distribute) Start() error {
	for _, streamID := range router.boundStreamIDs {
		targetRouter := core.StreamRegistry.GetRouterOrFallback(streamID)
		router.routers = append(router.routers, targetRouter)
	}

	return nil
}

func (router *Distribute) route(msg *core.Message, targetRouter core.Router) {
	if router.StreamID() == targetRouter.StreamID() {
		router.Broadcast.Enqueue(msg)
	} else {
		msg.SetStreamID(targetRouter.StreamID())
		core.Route(msg, targetRouter)
	}
}

// Enqueue enques a message to the router
func (router *Distribute) Enqueue(msg *core.Message) error {
	numStreams := len(router.routers)

	switch numStreams {
	case 0:
		return core.NewModulateResultError("No producers configured for stream %s", router.GetID())

	case 1:
		router.route(msg, router.routers[0])

	default:
		lastStreamIdx := numStreams - 1
		for streamIdx := 0; streamIdx < lastStreamIdx; streamIdx++ {
			router.route(msg.Clone(), router.routers[streamIdx])
			router.Log.Debug.Printf("routed to StreamID '%v'", router.routers[streamIdx].StreamID())
		}
		router.route(msg, router.routers[lastStreamIdx])
		router.Log.Debug.Printf("routed to StreamID '%v'", router.routers[lastStreamIdx].StreamID())
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"compress/gzip"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"strings"
	"time"
)

type Page struct {
	Title string
	SourceCommentHeader template.HTML
}

type gzipResponseWriter struct {
	io.Writer
	http.ResponseWriter
}

func (w gzipResponseWriter) Write(b []byte) (int, error) {
	if "" == w.Header().Get("Content-Type") {
        // If no content type, apply sniffing algorithm to un-gzipped body.
        w.Header().Set("Content-Type", http.DetectContentType(b))
    }
	return w.Writer.Write(b)
}

func makeGzipHandler(fn http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
			fn(w, r)
			return
		}
		w.Header().Set("Content-Encoding", "gzip")
		gz := gzip.NewWriter(w)
		defer gz.Close()
		gzr := gzipResponseWriter{Writer: gz, ResponseWriter: w}
		fn(gzr, r)
	}
}

func serveSingle(pattern string, filename string) {
	http.HandleFunc(pattern, makeGzipHandler(func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, filename)
	}))
}

func IndexHandler(w http.ResponseWriter, r *http.Request) {
	page := new(Page)
	page.Title = "BoardGameGeek Inventory"
	page.SourceCommentHeader = template.HTML("<!-- https://github.com/zaknelson/bgg-prices/ -->")

	t := template.New("index")
	t, _ = t.ParseFiles("templates/index.html")
	t.ExecuteTemplate(w, "index.html", page)
}

func UpdateHandler(w http.ResponseWriter, r *http.Request) {
	startedInfo, lastStartedErr := os.Stat("model/started.txt")
	startedTimeAgo := time.Now().Sub(startedInfo.ModTime())

	finishedInfo, finishedErr := os.Stat("model/games.json")
	finishedTimeAgo := time.Now().Sub(finishedInfo.ModTime())

	if  lastStartedErr == nil && finishedErr == nil &&
		startedTimeAgo.Minutes() > 20 && finishedTimeAgo.Hours() > 24 {
		go func() {
			ioutil.WriteFile("model/started.txt", nil, 0644)
			command := exec.Command("ruby", "bgg-inventory-scraper.rb")
			err := command.Run()
			if err != nil {
				fmt.Printf("Error occurred with first fetch attempt, try again")
				time.Sleep(5 * time.Second)
				command := exec.Command("ruby", "bgg-inventory-scraper.rb")
				command.Run()
				// If we fail again, oh well will just have to try again later
			}
		}()
	}

	fmt.Fprintf(w, "%s", finishedInfo.ModTime().Format(time.ANSIC))
}

func init() {
	http.HandleFunc("/", makeGzipHandler(IndexHandler))
	http.HandleFunc("/update", UpdateHandler)
	serveSingle("/api/v1/games", "model/games.json")
	http.Handle("/css/", http.StripPrefix("/css/", http.FileServer(http.Dir("./css/"))))
	http.Handle("/js/", http.StripPrefix("/js/", http.FileServer(http.Dir("./js/"))))
	http.Handle("/fonts/", http.StripPrefix("/fonts/", http.FileServer(http.Dir("./fonts/"))))
	http.Handle("/images/", http.StripPrefix("/images/", http.FileServer(http.Dir("./images/"))))
	http.ListenAndServe(":" + os.Getenv("PORT"), nil)
}

func main() {}<commit_msg>Switch to 8 hour scraping intervals.<commit_after>package main

import (
	"compress/gzip"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"strings"
	"time"
)

type Page struct {
	Title string
	SourceCommentHeader template.HTML
}

type gzipResponseWriter struct {
	io.Writer
	http.ResponseWriter
}

func (w gzipResponseWriter) Write(b []byte) (int, error) {
	if "" == w.Header().Get("Content-Type") {
        // If no content type, apply sniffing algorithm to un-gzipped body.
        w.Header().Set("Content-Type", http.DetectContentType(b))
    }
	return w.Writer.Write(b)
}

func makeGzipHandler(fn http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
			fn(w, r)
			return
		}
		w.Header().Set("Content-Encoding", "gzip")
		gz := gzip.NewWriter(w)
		defer gz.Close()
		gzr := gzipResponseWriter{Writer: gz, ResponseWriter: w}
		fn(gzr, r)
	}
}

func serveSingle(pattern string, filename string) {
	http.HandleFunc(pattern, makeGzipHandler(func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, filename)
	}))
}

func IndexHandler(w http.ResponseWriter, r *http.Request) {
	page := new(Page)
	page.Title = "BoardGameGeek Inventory"
	page.SourceCommentHeader = template.HTML("<!-- https://github.com/zaknelson/bgg-prices/ -->")

	t := template.New("index")
	t, _ = t.ParseFiles("templates/index.html")
	t.ExecuteTemplate(w, "index.html", page)
}

func UpdateHandler(w http.ResponseWriter, r *http.Request) {
	startedInfo, lastStartedErr := os.Stat("model/started.txt")
	startedTimeAgo := time.Now().Sub(startedInfo.ModTime())

	finishedInfo, finishedErr := os.Stat("model/games.json")
	finishedTimeAgo := time.Now().Sub(finishedInfo.ModTime())

	if  lastStartedErr == nil && finishedErr == nil &&
		startedTimeAgo.Minutes() > 20 && finishedTimeAgo.Hours() > 8 {
		go func() {
			ioutil.WriteFile("model/started.txt", nil, 0644)
			command := exec.Command("ruby", "bgg-inventory-scraper.rb")
			err := command.Run()
			if err != nil {
				fmt.Printf("Error occurred with first fetch attempt, try again")
				time.Sleep(5 * time.Second)
				command := exec.Command("ruby", "bgg-inventory-scraper.rb")
				command.Run()
				// If we fail again, oh well will just have to try again later
			}
		}()
	}

	fmt.Fprintf(w, "%s", finishedInfo.ModTime().Format(time.ANSIC))
}

func init() {
	http.HandleFunc("/", makeGzipHandler(IndexHandler))
	http.HandleFunc("/update", UpdateHandler)
	serveSingle("/api/v1/games", "model/games.json")
	http.Handle("/css/", http.StripPrefix("/css/", http.FileServer(http.Dir("./css/"))))
	http.Handle("/js/", http.StripPrefix("/js/", http.FileServer(http.Dir("./js/"))))
	http.Handle("/fonts/", http.StripPrefix("/fonts/", http.FileServer(http.Dir("./fonts/"))))
	http.Handle("/images/", http.StripPrefix("/images/", http.FileServer(http.Dir("./images/"))))
	http.ListenAndServe(":" + os.Getenv("PORT"), nil)
}

func main() {}<|endoftext|>


<commit_before>package github

import (
	"errors"
	"fmt"
	"strconv"
	"strings"

	"github.com/gistia/slackbot/db"
	"github.com/gistia/slackbot/robots"
	"github.com/gistia/slackbot/utils"
	"github.com/google/go-github/github"
	"golang.org/x/oauth2"
)

type bot struct {
	handler utils.SlackHandler
}

func init() {
	handler := utils.NewSlackHandler("GitHub", "https://assets-cdn.github.com/images/modules/logos_page/Octocat.png")
	s := &bot{handler: handler}
	robots.RegisterRobot("github", s)
	robots.RegisterRobot("gh", s)
}

func (r bot) Run(p *robots.Payload) string {
	go r.DeferredAction(p)
	return ""
}

func (r bot) DeferredAction(p *robots.Payload) {
	ch := utils.NewCmdHandler(p, r.handler, "gh")
	ch.Handle("pullrequests", r.pullRequests)
	ch.Handle("prs", r.pullRequests)
	ch.Handle("teams", r.teams)
	ch.Handle("teaminfo", r.teamInfo)
	ch.Handle("addtoteam", r.addToTeam)
	ch.Process(p.Text)
}

func (r bot) teamInfo(p *robots.Payload, cmd utils.Command) error {
	teamID := cmd.Arg(0)
	if teamID == "" {
		return errors.New("Missing team name. Use `!github teaminfo <team>`")
	}

	client, err := r.getClient(p.UserName)
	if err != nil {
		return err
	}

	id, err := strconv.Atoi(teamID)
	if err != nil {
		return err
	}

	team, _, err := client.Organizations.GetTeam(id)
	if err != nil {
		return err
	}

	s := "Members for *" + *team.Name + "*:\n"
	// opts := &OrganizationListTeamMembersOptions{}
	users, _, err := client.Organizations.ListTeamMembers(id, nil)
	if err != nil {
		return err
	}

	for _, u := range users {
		s += fmt.Sprintf("- %s\n", *u.Login)
	}

	r.handler.Send(p, s)
	return nil
}

func (r bot) teams(p *robots.Payload, cmd utils.Command) error {
	org := cmd.Arg(0)
	opt := &github.ListOptions{}

	client, err := r.getClient(p.UserName)
	if err != nil {
		return err
	}

	teams, _, err := client.Organizations.ListTeams(org, opt)
	if err != nil {
		return err
	}

	s := "Current teams:\n"
	for _, t := range teams {
		s += fmt.Sprintf("%d - %s\n", *t.ID, *t.Name)
	}

	r.handler.Send(p, s)
	return nil
}

func (r bot) addToTeam(p *robots.Payload, cmd utils.Command) error {
	user := cmd.Arg(0)
	if user == "" {
		return errors.New("Missing user name. Use `!github addtoteam <user> <team>`")
	}
	team := cmd.Arg(1)
	if team == "" {
		return errors.New("Missing team name. Use `!github addtoteam <user> <team>`")
	}
	// role := "member"
	client, err := r.getClient(p.UserName)
	if err != nil {
		return err
	}
	id, err := strconv.Atoi(team)
	if err != nil {
		return err
	}

	_, _, err = client.Organizations.AddTeamMembership(id, user)
	if err != nil {
		return err
	}

	r.handler.Send(p, "User *"+user+"* added to team.")
	return nil
}

func (r bot) pullRequests(p *robots.Payload, cmd utils.Command) error {
	repo := cmd.Arg(0)
	if repo == "" {
		return errors.New("Missing repo name. Use `!github prs <repo-name>`")
	}

	parts := strings.Split(repo, "/")
	owner := parts[0]
	name := parts[1]
	client, err := r.getClient(p.UserName)
	if err != nil {
		return err
	}

	prs, _, err := client.PullRequests.List(owner, name, nil)
	if err != nil {
		return err
	}

	if len(prs) < 1 {
		r.handler.Send(p, "No open pull requests for *"+repo+"*")
		return nil
	}

	s := "Open pull requests for *" + repo + "*:\n"
	atts := []robots.Attachment{}

	for _, pr := range prs {
		atts = append(atts, utils.FmtAttachment(
			fmt.Sprintf("%d - %s", *pr.Number, *pr.Title),
			*pr.Title,
			*pr.HTMLURL,
			fmt.Sprintf("#%d %s on %s by %s",
				*pr.Number, *pr.State,
				(*pr.CreatedAt).Format("Jan 2, 2006"), *pr.User.Login)))
	}

	r.handler.SendWithAttachments(p, s, atts)
	return nil
}

func (r bot) getClient(user string) (*github.Client, error) {
	token, err := db.GetSetting(user, "GITHUB_TOKEN")
	if err != nil {
		return nil, err
	}
	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: token.Value},
	)
	tc := oauth2.NewClient(oauth2.NoContext, ts)

	return github.NewClient(tc), nil
}

func (r bot) Description() (description string) {
	return "GitHub bot\n\tUsage: !github <command>\n"
}
<commit_msg>Added github auth command<commit_after>package github

import (
	"errors"
	"fmt"
	"strconv"
	"strings"

	"github.com/gistia/slackbot/db"
	"github.com/gistia/slackbot/robots"
	"github.com/gistia/slackbot/utils"
	"github.com/google/go-github/github"
	"golang.org/x/oauth2"
)

type bot struct {
	handler utils.SlackHandler
}

func init() {
	handler := utils.NewSlackHandler("GitHub", "https://assets-cdn.github.com/images/modules/logos_page/Octocat.png")
	s := &bot{handler: handler}
	robots.RegisterRobot("github", s)
	robots.RegisterRobot("gh", s)
}

func (r bot) Run(p *robots.Payload) string {
	go r.DeferredAction(p)
	return ""
}

func (r bot) DeferredAction(p *robots.Payload) {
	ch := utils.NewCmdHandler(p, r.handler, "gh")
	ch.Handle("auth", r.auth)
	ch.Handle("pullrequests", r.pullRequests)
	ch.Handle("prs", r.pullRequests)
	ch.Handle("teams", r.teams)
	ch.Handle("teaminfo", r.teamInfo)
	ch.Handle("addtoteam", r.addToTeam)
	ch.Process(p.Text)
}

func (r bot) auth(p *robots.Payload, cmd utils.Command) error {
	s, err := db.GetSetting(p.UserName, "GITHUB_TOKEN")
	if err != nil {
		return err
	}

	if s != nil {
		r.handler.Send(p, "You are already connected with GitHub.")
		return nil
	}

	r.handler.Send(p, `*Authenticating with GitHub*
1. Follow the instructions here https://github.com/blog/1509-personal-api-tokens
2. Copy your API token
3. Run the command:
   `+"`/store set GITHUB_TOKEN=<token>`")
	return nil
}

func (r bot) teamInfo(p *robots.Payload, cmd utils.Command) error {
	teamID := cmd.Arg(0)
	if teamID == "" {
		return errors.New("Missing team name. Use `!github teaminfo <team>`")
	}

	client, err := r.getClient(p.UserName)
	if err != nil {
		return err
	}

	id, err := strconv.Atoi(teamID)
	if err != nil {
		return err
	}

	team, _, err := client.Organizations.GetTeam(id)
	if err != nil {
		return err
	}

	s := "Members for *" + *team.Name + "*:\n"
	// opts := &OrganizationListTeamMembersOptions{}
	users, _, err := client.Organizations.ListTeamMembers(id, nil)
	if err != nil {
		return err
	}

	for _, u := range users {
		s += fmt.Sprintf("- %s\n", *u.Login)
	}

	r.handler.Send(p, s)
	return nil
}

func (r bot) teams(p *robots.Payload, cmd utils.Command) error {
	org := cmd.Arg(0)
	opt := &github.ListOptions{}

	client, err := r.getClient(p.UserName)
	if err != nil {
		return err
	}

	teams, _, err := client.Organizations.ListTeams(org, opt)
	if err != nil {
		return err
	}

	s := "Current teams:\n"
	for _, t := range teams {
		s += fmt.Sprintf("%d - %s\n", *t.ID, *t.Name)
	}

	r.handler.Send(p, s)
	return nil
}

func (r bot) addToTeam(p *robots.Payload, cmd utils.Command) error {
	user := cmd.Arg(0)
	if user == "" {
		return errors.New("Missing user name. Use `!github addtoteam <user> <team>`")
	}
	team := cmd.Arg(1)
	if team == "" {
		return errors.New("Missing team name. Use `!github addtoteam <user> <team>`")
	}
	// role := "member"
	client, err := r.getClient(p.UserName)
	if err != nil {
		return err
	}
	id, err := strconv.Atoi(team)
	if err != nil {
		return err
	}

	_, _, err = client.Organizations.AddTeamMembership(id, user)
	if err != nil {
		return err
	}

	r.handler.Send(p, "User *"+user+"* added to team.")
	return nil
}

func (r bot) pullRequests(p *robots.Payload, cmd utils.Command) error {
	repo := cmd.Arg(0)
	if repo == "" {
		return errors.New("Missing repo name. Use `!github prs <repo-name>`")
	}

	parts := strings.Split(repo, "/")
	owner := parts[0]
	name := parts[1]
	client, err := r.getClient(p.UserName)
	if err != nil {
		return err
	}

	prs, _, err := client.PullRequests.List(owner, name, nil)
	if err != nil {
		return err
	}

	if len(prs) < 1 {
		r.handler.Send(p, "No open pull requests for *"+repo+"*")
		return nil
	}

	s := "Open pull requests for *" + repo + "*:\n"
	atts := []robots.Attachment{}

	for _, pr := range prs {
		atts = append(atts, utils.FmtAttachment(
			fmt.Sprintf("%d - %s", *pr.Number, *pr.Title),
			*pr.Title,
			*pr.HTMLURL,
			fmt.Sprintf("#%d %s on %s by %s",
				*pr.Number, *pr.State,
				(*pr.CreatedAt).Format("Jan 2, 2006"), *pr.User.Login)))
	}

	r.handler.SendWithAttachments(p, s, atts)
	return nil
}

func (r bot) getClient(user string) (*github.Client, error) {
	token, err := db.GetSetting(user, "GITHUB_TOKEN")
	if err != nil {
		return nil, err
	}
	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: token.Value},
	)
	tc := oauth2.NewClient(oauth2.NoContext, ts)

	return github.NewClient(tc), nil
}

func (r bot) Description() (description string) {
	return "GitHub bot\n\tUsage: !github <command>\n"
}
<|endoftext|>


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

package main

import (
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"runtime/pprof"
	"syscall"
	"time"

	"github.com/square/metrics/function/registry"
	"github.com/square/metrics/log"
	"github.com/square/metrics/main/common"
	"github.com/square/metrics/metric_metadata"
	"github.com/square/metrics/metric_metadata/cached"
	"github.com/square/metrics/metric_metadata/cassandra"
	"github.com/square/metrics/query/command"
	"github.com/square/metrics/timeseries"
	"github.com/square/metrics/timeseries/blueflood"
	"github.com/square/metrics/util"
	"github.com/square/metrics/web"
)

func startServer(config web.Config, context command.ExecutionContext) error {
	httpMux, err := web.NewMux(config, context, web.Hook{})
	if err != nil {
		return err
	}

	server := &http.Server{
		Addr:           fmt.Sprintf(":%d", config.Port),
		Handler:        httpMux,
		ReadTimeout:    time.Duration(config.Timeout) * time.Second,
		WriteTimeout:   time.Duration(config.Timeout) * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	return server.ListenAndServe()
}

func main() {
	//Adding a signal handler to dump goroutines
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, syscall.SIGUSR2)

	go func() {
		for range sigs {
			pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
		}
	}()

	config := struct {
		ConversionRulesPath string           `yaml:"conversion_rules_path"`
		Cassandra           cassandra.Config `yaml:"cassandra"`
		Blueflood           blueflood.Config `yaml"blueflood"`
		Web                 web.Config       `yaml:"web"`
	}{}

	common.LoadConfigs(&config)

	metadataAPI, err := cassandra.NewMetricMetadataAPI(config.Cassandra)
	if err != nil {
		common.ExitWithErrorMessage("Error loading Cassandra API: %s", err.Error())
		return
	}

	ruleset, err := util.LoadRules(config.ConversionRulesPath)
	if err != nil {
		common.ExitWithErrorMessage("Error loading conversion rules: %s", err.Error())
		return
	}

	config.Blueflood.GraphiteMetricConverter = &util.RuleBasedGraphiteConverter{Ruleset: ruleset}

	blueflood := blueflood.NewBlueflood(config.Blueflood)

	optimizedMetadataAPI := cached.NewMetricMetadataAPI(metadataAPI, cached.Config{
		TimeToLive:   time.Minute * 5, // Cache items invalidated after 5 minutes.
		RequestLimit: 500,
	})
	for i := 0; i < 10; i++ {
		// Start goroutines to update the metadata cache in the background.
		go func() {
			for {
				err := optimizedMetadataAPI.GetBackgroundAction()(metadata.Context{})
				if err != nil {
					log.Errorf("Error performing background cache-update: %s", err.Error())
				}
			}
		}()
	}

	//Defaults
	userConfig := timeseries.UserSpecifiableConfig{
		IncludeRawData: false,
	}

	err = startServer(config.Web, command.ExecutionContext{
		MetricMetadataAPI:     optimizedMetadataAPI,
		TimeseriesStorageAPI:  blueflood,
		FetchLimit:            1500,
		SlotLimit:             5000,
		Registry:              registry.Default(),
		UserSpecifiableConfig: userConfig,
	})
	if err != nil {
		log.Infof(err.Error())
	}
}
<commit_msg>fix yaml field (#282)<commit_after>// Copyright 2015 - 2016 Square Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"runtime/pprof"
	"syscall"
	"time"

	"github.com/square/metrics/function/registry"
	"github.com/square/metrics/log"
	"github.com/square/metrics/main/common"
	"github.com/square/metrics/metric_metadata"
	"github.com/square/metrics/metric_metadata/cached"
	"github.com/square/metrics/metric_metadata/cassandra"
	"github.com/square/metrics/query/command"
	"github.com/square/metrics/timeseries"
	"github.com/square/metrics/timeseries/blueflood"
	"github.com/square/metrics/util"
	"github.com/square/metrics/web"
)

func startServer(config web.Config, context command.ExecutionContext) error {
	httpMux, err := web.NewMux(config, context, web.Hook{})
	if err != nil {
		return err
	}

	server := &http.Server{
		Addr:           fmt.Sprintf(":%d", config.Port),
		Handler:        httpMux,
		ReadTimeout:    time.Duration(config.Timeout) * time.Second,
		WriteTimeout:   time.Duration(config.Timeout) * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	return server.ListenAndServe()
}

func main() {
	//Adding a signal handler to dump goroutines
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, syscall.SIGUSR2)

	go func() {
		for range sigs {
			pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
		}
	}()

	config := struct {
		ConversionRulesPath string           `yaml:"conversion_rules_path"`
		Cassandra           cassandra.Config `yaml:"cassandra"`
		Blueflood           blueflood.Config `yaml:"blueflood"`
		Web                 web.Config       `yaml:"web"`
	}{}

	common.LoadConfigs(&config)

	metadataAPI, err := cassandra.NewMetricMetadataAPI(config.Cassandra)
	if err != nil {
		common.ExitWithErrorMessage("Error loading Cassandra API: %s", err.Error())
		return
	}

	ruleset, err := util.LoadRules(config.ConversionRulesPath)
	if err != nil {
		common.ExitWithErrorMessage("Error loading conversion rules: %s", err.Error())
		return
	}

	config.Blueflood.GraphiteMetricConverter = &util.RuleBasedGraphiteConverter{Ruleset: ruleset}

	blueflood := blueflood.NewBlueflood(config.Blueflood)

	optimizedMetadataAPI := cached.NewMetricMetadataAPI(metadataAPI, cached.Config{
		TimeToLive:   time.Minute * 5, // Cache items invalidated after 5 minutes.
		RequestLimit: 500,
	})
	for i := 0; i < 10; i++ {
		// Start goroutines to update the metadata cache in the background.
		go func() {
			for {
				err := optimizedMetadataAPI.GetBackgroundAction()(metadata.Context{})
				if err != nil {
					log.Errorf("Error performing background cache-update: %s", err.Error())
				}
			}
		}()
	}

	//Defaults
	userConfig := timeseries.UserSpecifiableConfig{
		IncludeRawData: false,
	}

	err = startServer(config.Web, command.ExecutionContext{
		MetricMetadataAPI:     optimizedMetadataAPI,
		TimeseriesStorageAPI:  blueflood,
		FetchLimit:            1500,
		SlotLimit:             5000,
		Registry:              registry.Default(),
		UserSpecifiableConfig: userConfig,
	})
	if err != nil {
		log.Infof(err.Error())
	}
}
<|endoftext|>