<commit_before>package gerrit

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"strings"

	"github.com/google/go-querystring/query"
)

// TODO Try to reduce the code duplications of a std API req
// Maybe with http://play.golang.org/p/j-667shCCB
// and https://groups.google.com/forum/#!topic/golang-nuts/D-gIr24k5uY

// A Client manages communication with the Gerrit API.
type Client struct {
	// HTTP client used to communicate with the API.
	client *http.Client

	// Base URL for API requests.
	// BaseURL should always be specified with a trailing slash.
	baseURL *url.URL

	// Gerrit service for authentication
	Authentication *AuthenticationService

	// Services used for talking to different parts of the standard
	// Gerrit API.
	Access   *AccessService
	Accounts *AccountsService
	Changes  *ChangesService
	Config   *ConfigService
	Groups   *GroupsService
	Plugins  *PluginsService
	Projects *ProjectsService

	// Additional services used for talking to non-standard Gerrit
	// APIs.
	EventsLog *EventsLogService
}

// Response is a Gerrit API response.
// This wraps the standard http.Response returned from Gerrit.
type Response struct {
	*http.Response
}

// NewClient returns a new Gerrit API client.
// gerritInstance has to be the HTTP endpoint of the Gerrit instance.
// If a nil httpClient is provided, http.DefaultClient will be used.
func NewClient(gerritURL string, httpClient *http.Client) (*Client, error) {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}

	if len(gerritURL) == 0 {
		return nil, fmt.Errorf("No Gerrit instance given.")
	}
	baseURL, err := url.Parse(gerritURL)
	if err != nil {
		return nil, err
	}

	c := &Client{
		client:  httpClient,
		baseURL: baseURL,
	}
	c.Authentication = &AuthenticationService{client: c}
	c.Access = &AccessService{client: c}
	c.Accounts = &AccountsService{client: c}
	c.Changes = &ChangesService{client: c}
	c.Config = &ConfigService{client: c}
	c.Groups = &GroupsService{client: c}
	c.Plugins = &PluginsService{client: c}
	c.Projects = &ProjectsService{client: c}
	c.EventsLog = &EventsLogService{client: c}

	return c, nil
}

// NewRequest creates an API request.
// A relative URL can be provided in urlStr, in which case it is resolved relative to the baseURL of the Client.
// Relative URLs should always be specified without a preceding slash.
// If specified, the value pointed to by body is JSON encoded and included as the request body.
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) {
	// Build URL for request
	u, err := c.buildURLForRequest(urlStr)
	if err != nil {
		return nil, err
	}

	var buf io.ReadWriter
	if body != nil {
		buf = new(bytes.Buffer)
		err := json.NewEncoder(buf).Encode(body)
		if err != nil {
			return nil, err
		}
	}

	req, err := http.NewRequest(method, u, buf)
	if err != nil {
		return nil, err
	}

	// Apply Authentication
	if err := c.addAuthentication(req); err != nil {
		return nil, err
	}

	// Request compact JSON
	// See https://gerrit-review.googlesource.com/Documentation/rest-api.html#output
	req.Header.Add("Accept", "application/json")
	req.Header.Add("Content-Type", "application/json")

	// TODO: Add gzip encoding
	// Accept-Encoding request header is set to gzip
	// See https://gerrit-review.googlesource.com/Documentation/rest-api.html#output

	return req, nil
}

// Call is a combine function for Client.NewRequest and Client.Do.
//
// Most API methods are quite the same.
// Get the URL, apply options, make a request, and get the response.
// Without adding special headers or something.
// To avoid a big amount of code duplication you can Client.Call.
//
// method is the HTTP method you want to call.
// u is the URL you want to call.
// body is the HTTP body.
// v is the HTTP response.
//
// For more information read https://github.com/google/go-github/issues/234
func (c *Client) Call(method, u string, body interface{}, v interface{}) (*Response, error) {
	req, err := c.NewRequest(method, u, body)
	if err != nil {
		return nil, err
	}

	resp, err := c.Do(req, v)
	if err != nil {
		return resp, err
	}

	return resp, err
}

// buildURLForRequest will build the URL (as string) that will be called.
// We need such a utility method, because the URL.Path needs to be escaped (partly).
//
// E.g. if a project is called via "projects/%s" and the project is named "plugin/delete-project"
// there has to be "projects/plugin%25Fdelete-project" instead of "projects/plugin/delete-project".
// The second url will return nothing.
func (c *Client) buildURLForRequest(urlStr string) (string, error) {
	u := c.baseURL.String()

	// If there is no / at the end, add one
	if strings.HasSuffix(u, "/") == false {
		u += "/"
	}

	// If there is a "/" at the start, remove it
	if strings.HasPrefix(urlStr, "/") == true {
		urlStr = urlStr[1:]
	}

	// If we are authenticated, lets apply the a/ prefix
	if c.Authentication.HasAuth() == true {
		urlStr = "a/" + urlStr
	}

	rel, err := url.Parse(urlStr)
	if err != nil {
		return "", err
	}
	u += rel.String()

	return u, nil
}

// Do sends an API request and returns the API response.
// The API response is JSON decoded and stored in the value pointed to by v,
// or returned as an error if an API error has occurred.
// If v implements the io.Writer interface, the raw response body will be written to v,
// without attempting to first decode it.
func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}

	// Wrap response
	response := &Response{Response: resp}

	err = CheckResponse(resp)
	if err != nil {
		// even though there was an error, we still return the response
		// in case the caller wants to inspect it further
		return response, err
	}

	if v != nil {
		defer resp.Body.Close()
		if w, ok := v.(io.Writer); ok {
			io.Copy(w, resp.Body)
		} else {
			var body []byte
			body, err = ioutil.ReadAll(resp.Body)
			if err != nil {
				// even though there was an error, we still return the response
				// in case the caller wants to inspect it further
				return response, err
			}

			body = RemoveMagicPrefixLine(body)
			err = json.Unmarshal(body, v)
		}
	}
	return response, err
}

func (c *Client) addAuthentication(req *http.Request) error {
	// Apply HTTP Basic Authentication
	if c.Authentication.HasBasicAuth() {
		req.SetBasicAuth(c.Authentication.name, c.Authentication.secret)
		return nil
	}

	// Apply HTTP Cookie
	if c.Authentication.HasCookieAuth() {
		req.AddCookie(&http.Cookie{
			Name:  c.Authentication.name,
			Value: c.Authentication.secret,
		})
		return nil
	}

	// Apply Digest Authentication.  If we're using digest based
	// authentication we need to make a request, process the
	// WWW-Authenticate header, then set the Authorization header on the
	// incoming request.  We do not need to send a body along because
	// the request itself should fail first.
	if c.Authentication.HasDigestAuth() {
		uri, err := c.buildURLForRequest(req.URL.RequestURI())
		if err != nil {
			return err
		}

		// WARNING: Don't use c.NewRequest here unless you like
		// infinite recursion.
		digestRequest, err := http.NewRequest(req.Method, uri, nil)
		digestRequest.Header.Set("Accept", "*/*")
		digestRequest.Header.Set("Content-Type", "application/json")
		if err != nil {
			return err
		}

		response, err := c.client.Do(digestRequest)
		if err != nil {
			return err

		}

		// When the function exits discard the rest of the
		// body and close it.  This should cause go to
		// reuse the connection.
		defer io.Copy(ioutil.Discard, response.Body)
		defer response.Body.Close()

		if response.StatusCode == http.StatusUnauthorized {
			authorization, err := c.Authentication.digestAuthHeader(response)

			if err != nil {
				return err
			}
			req.Header.Set("Authorization", authorization)
		}
	}

	return nil
}

// DeleteRequest sends an DELETE API Request to urlStr with optional body.
// It is a shorthand combination for Client.NewRequest with Client.Do.
//
// Relative URLs should always be specified without a preceding slash.
// If specified, the value pointed to by body is JSON encoded and included as the request body.
func (c *Client) DeleteRequest(urlStr string, body interface{}) (*Response, error) {
	req, err := c.NewRequest("DELETE", urlStr, body)
	if err != nil {
		return nil, err
	}

	return c.Do(req, nil)
}

// RemoveMagicPrefixLine removes the "magic prefix line" of Gerris JSON
// response if present. The JSON response body starts with a magic prefix line
// that must be stripped before feeding the rest of the response body to a JSON
// parser. The reason for this is to prevent against Cross Site Script
// Inclusion (XSSI) attacks.  By default all standard Gerrit APIs include this
// prefix line though some plugins may not.
//
// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api.html#output
func RemoveMagicPrefixLine(body []byte) []byte {
	if bytes.HasPrefix(body, []byte(")]}'\n")) {
		index := bytes.IndexByte(body, '\n')
		if index > -1 {
			// +1 to catch the \n as well
			body = body[(index + 1):]
		}
	}
	return body
}

// CheckResponse checks the API response for errors, and returns them if present.
// A response is considered an error if it has a status code outside the 200 range.
// API error responses are expected to have no response body.
//
// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api.html#response-codes
func CheckResponse(r *http.Response) error {
	if c := r.StatusCode; 200 <= c && c <= 299 {
		return nil
	}

	// Some calls require an authentification
	// In such cases errors like:
	// 		API call to https://review.typo3.org/accounts/self failed: 403 Forbidden
	// will be thrown.

	err := fmt.Errorf("API call to %s failed: %s", r.Request.URL.String(), r.Status)
	return err
}

// addOptions adds the parameters in opt as URL query parameters to s.
// opt must be a struct whose fields may contain "url" tags.
func addOptions(s string, opt interface{}) (string, error) {
	v := reflect.ValueOf(opt)
	if v.Kind() == reflect.Ptr && v.IsNil() {
		return s, nil
	}

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

	qs, err := query.Values(opt)
	if err != nil {
		return s, err
	}

	u.RawQuery = qs.Encode()
	return u.String(), nil
}

// getStringResponseWithoutOptions retrieved a single string Response for a GET request
func getStringResponseWithoutOptions(client *Client, u string) (string, *Response, error) {
	v := new(string)
	resp, err := client.Call("GET", u, nil, v)
	return *v, resp, err
}
<commit_msg>don't prepend a/ if it's not necessary<commit_after>package gerrit

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"strings"

	"github.com/google/go-querystring/query"
)

// TODO Try to reduce the code duplications of a std API req
// Maybe with http://play.golang.org/p/j-667shCCB
// and https://groups.google.com/forum/#!topic/golang-nuts/D-gIr24k5uY

// A Client manages communication with the Gerrit API.
type Client struct {
	// HTTP client used to communicate with the API.
	client *http.Client

	// Base URL for API requests.
	// BaseURL should always be specified with a trailing slash.
	baseURL *url.URL

	// Gerrit service for authentication
	Authentication *AuthenticationService

	// Services used for talking to different parts of the standard
	// Gerrit API.
	Access   *AccessService
	Accounts *AccountsService
	Changes  *ChangesService
	Config   *ConfigService
	Groups   *GroupsService
	Plugins  *PluginsService
	Projects *ProjectsService

	// Additional services used for talking to non-standard Gerrit
	// APIs.
	EventsLog *EventsLogService
}

// Response is a Gerrit API response.
// This wraps the standard http.Response returned from Gerrit.
type Response struct {
	*http.Response
}

// NewClient returns a new Gerrit API client.
// gerritInstance has to be the HTTP endpoint of the Gerrit instance.
// If a nil httpClient is provided, http.DefaultClient will be used.
func NewClient(gerritURL string, httpClient *http.Client) (*Client, error) {
	if httpClient == nil {
		httpClient = http.DefaultClient
	}

	if len(gerritURL) == 0 {
		return nil, fmt.Errorf("No Gerrit instance given.")
	}
	baseURL, err := url.Parse(gerritURL)
	if err != nil {
		return nil, err
	}

	c := &Client{
		client:  httpClient,
		baseURL: baseURL,
	}
	c.Authentication = &AuthenticationService{client: c}
	c.Access = &AccessService{client: c}
	c.Accounts = &AccountsService{client: c}
	c.Changes = &ChangesService{client: c}
	c.Config = &ConfigService{client: c}
	c.Groups = &GroupsService{client: c}
	c.Plugins = &PluginsService{client: c}
	c.Projects = &ProjectsService{client: c}
	c.EventsLog = &EventsLogService{client: c}

	return c, nil
}

// NewRequest creates an API request.
// A relative URL can be provided in urlStr, in which case it is resolved relative to the baseURL of the Client.
// Relative URLs should always be specified without a preceding slash.
// If specified, the value pointed to by body is JSON encoded and included as the request body.
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) {
	// Build URL for request
	u, err := c.buildURLForRequest(urlStr)
	if err != nil {
		return nil, err
	}

	var buf io.ReadWriter
	if body != nil {
		buf = new(bytes.Buffer)
		err := json.NewEncoder(buf).Encode(body)
		if err != nil {
			return nil, err
		}
	}

	req, err := http.NewRequest(method, u, buf)
	if err != nil {
		return nil, err
	}

	// Apply Authentication
	if err := c.addAuthentication(req); err != nil {
		return nil, err
	}

	// Request compact JSON
	// See https://gerrit-review.googlesource.com/Documentation/rest-api.html#output
	req.Header.Add("Accept", "application/json")
	req.Header.Add("Content-Type", "application/json")

	// TODO: Add gzip encoding
	// Accept-Encoding request header is set to gzip
	// See https://gerrit-review.googlesource.com/Documentation/rest-api.html#output

	return req, nil
}

// Call is a combine function for Client.NewRequest and Client.Do.
//
// Most API methods are quite the same.
// Get the URL, apply options, make a request, and get the response.
// Without adding special headers or something.
// To avoid a big amount of code duplication you can Client.Call.
//
// method is the HTTP method you want to call.
// u is the URL you want to call.
// body is the HTTP body.
// v is the HTTP response.
//
// For more information read https://github.com/google/go-github/issues/234
func (c *Client) Call(method, u string, body interface{}, v interface{}) (*Response, error) {
	req, err := c.NewRequest(method, u, body)
	if err != nil {
		return nil, err
	}

	resp, err := c.Do(req, v)
	if err != nil {
		return resp, err
	}

	return resp, err
}

// buildURLForRequest will build the URL (as string) that will be called.
// We need such a utility method, because the URL.Path needs to be escaped (partly).
//
// E.g. if a project is called via "projects/%s" and the project is named "plugin/delete-project"
// there has to be "projects/plugin%25Fdelete-project" instead of "projects/plugin/delete-project".
// The second url will return nothing.
func (c *Client) buildURLForRequest(urlStr string) (string, error) {
	u := c.baseURL.String()

	// If there is no / at the end, add one
	if strings.HasSuffix(u, "/") == false {
		u += "/"
	}

	// If there is a "/" at the start, remove it
	if strings.HasPrefix(urlStr, "/") == true {
		urlStr = urlStr[1:]
	}

	// If we are authenticated, lets apply the a/ prefix but only if it has
	// not already been applied.
	if c.Authentication.HasAuth() == true && !strings.HasPrefix(urlStr, "a/") {
		urlStr = "a/" + urlStr
	}

	rel, err := url.Parse(urlStr)
	if err != nil {
		return "", err
	}
	u += rel.String()

	return u, nil
}

// Do sends an API request and returns the API response.
// The API response is JSON decoded and stored in the value pointed to by v,
// or returned as an error if an API error has occurred.
// If v implements the io.Writer interface, the raw response body will be written to v,
// without attempting to first decode it.
func (c *Client) Do(req *http.Request, v interface{}) (*Response, error) {
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}

	// Wrap response
	response := &Response{Response: resp}

	err = CheckResponse(resp)
	if err != nil {
		// even though there was an error, we still return the response
		// in case the caller wants to inspect it further
		return response, err
	}

	if v != nil {
		defer resp.Body.Close()
		if w, ok := v.(io.Writer); ok {
			io.Copy(w, resp.Body)
		} else {
			var body []byte
			body, err = ioutil.ReadAll(resp.Body)
			if err != nil {
				// even though there was an error, we still return the response
				// in case the caller wants to inspect it further
				return response, err
			}

			body = RemoveMagicPrefixLine(body)
			err = json.Unmarshal(body, v)
		}
	}
	return response, err
}

func (c *Client) addAuthentication(req *http.Request) error {
	// Apply HTTP Basic Authentication
	if c.Authentication.HasBasicAuth() {
		req.SetBasicAuth(c.Authentication.name, c.Authentication.secret)
		return nil
	}

	// Apply HTTP Cookie
	if c.Authentication.HasCookieAuth() {
		req.AddCookie(&http.Cookie{
			Name:  c.Authentication.name,
			Value: c.Authentication.secret,
		})
		return nil
	}

	// Apply Digest Authentication.  If we're using digest based
	// authentication we need to make a request, process the
	// WWW-Authenticate header, then set the Authorization header on the
	// incoming request.  We do not need to send a body along because
	// the request itself should fail first.
	if c.Authentication.HasDigestAuth() {
		uri, err := c.buildURLForRequest(req.URL.RequestURI())
		if err != nil {
			return err
		}

		// WARNING: Don't use c.NewRequest here unless you like
		// infinite recursion.
		digestRequest, err := http.NewRequest(req.Method, uri, nil)
		digestRequest.Header.Set("Accept", "*/*")
		digestRequest.Header.Set("Content-Type", "application/json")
		if err != nil {
			return err
		}

		response, err := c.client.Do(digestRequest)
		if err != nil {
			return err

		}

		// When the function exits discard the rest of the
		// body and close it.  This should cause go to
		// reuse the connection.
		defer io.Copy(ioutil.Discard, response.Body)
		defer response.Body.Close()

		if response.StatusCode == http.StatusUnauthorized {
			authorization, err := c.Authentication.digestAuthHeader(response)

			if err != nil {
				return err
			}
			req.Header.Set("Authorization", authorization)
		}
	}

	return nil
}

// DeleteRequest sends an DELETE API Request to urlStr with optional body.
// It is a shorthand combination for Client.NewRequest with Client.Do.
//
// Relative URLs should always be specified without a preceding slash.
// If specified, the value pointed to by body is JSON encoded and included as the request body.
func (c *Client) DeleteRequest(urlStr string, body interface{}) (*Response, error) {
	req, err := c.NewRequest("DELETE", urlStr, body)
	if err != nil {
		return nil, err
	}

	return c.Do(req, nil)
}

// RemoveMagicPrefixLine removes the "magic prefix line" of Gerris JSON
// response if present. The JSON response body starts with a magic prefix line
// that must be stripped before feeding the rest of the response body to a JSON
// parser. The reason for this is to prevent against Cross Site Script
// Inclusion (XSSI) attacks.  By default all standard Gerrit APIs include this
// prefix line though some plugins may not.
//
// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api.html#output
func RemoveMagicPrefixLine(body []byte) []byte {
	if bytes.HasPrefix(body, []byte(")]}'\n")) {
		index := bytes.IndexByte(body, '\n')
		if index > -1 {
			// +1 to catch the \n as well
			body = body[(index + 1):]
		}
	}
	return body
}

// CheckResponse checks the API response for errors, and returns them if present.
// A response is considered an error if it has a status code outside the 200 range.
// API error responses are expected to have no response body.
//
// Gerrit API docs: https://gerrit-review.googlesource.com/Documentation/rest-api.html#response-codes
func CheckResponse(r *http.Response) error {
	if c := r.StatusCode; 200 <= c && c <= 299 {
		return nil
	}

	// Some calls require an authentification
	// In such cases errors like:
	// 		API call to https://review.typo3.org/accounts/self failed: 403 Forbidden
	// will be thrown.

	err := fmt.Errorf("API call to %s failed: %s", r.Request.URL.String(), r.Status)
	return err
}

// addOptions adds the parameters in opt as URL query parameters to s.
// opt must be a struct whose fields may contain "url" tags.
func addOptions(s string, opt interface{}) (string, error) {
	v := reflect.ValueOf(opt)
	if v.Kind() == reflect.Ptr && v.IsNil() {
		return s, nil
	}

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

	qs, err := query.Values(opt)
	if err != nil {
		return s, err
	}

	u.RawQuery = qs.Encode()
	return u.String(), nil
}

// getStringResponseWithoutOptions retrieved a single string Response for a GET request
func getStringResponseWithoutOptions(client *Client, u string) (string, *Response, error) {
	v := new(string)
	resp, err := client.Call("GET", u, nil, v)
	return *v, resp, err
}
<|endoftext|>


<commit_before>package ghooks

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"strings"
)

const (
	VERSION = 0.1
)

type Server struct {
	Port int
}

type Hook struct {
	Event string
	Func  func(payload interface{})
}

type Hooks struct {
	Hooks []Hook
}

var hooks Hooks

func (s *Server) On(name string, handler func(payload interface{})) {
	hooks.Hooks = append(hooks.Hooks, Hook{Event: name, Func: handler})
}

func Emmit(name string, payload interface{}) {
	for _, v := range hooks.Hooks {
		if strings.EqualFold(v.Event, name) {
			v.Func(payload)
		}
	}
}

func NewServer(port int) *Server {
	return &Server{port}
}

func (s *Server) Run() error {
	fmt.Printf("ghooks server start 0.0.0.0:%d \n", s.Port)
	http.HandleFunc("/", Reciver)
	return http.ListenAndServe(":"+strconv.Itoa(s.Port), nil)
}

func Reciver(w http.ResponseWriter, req *http.Request) {
	if req.Method == "GET" {
		http.Error(w, "Method Not Allowd", http.StatusMethodNotAllowed)
		return
	}

	event := req.Header.Get("X-GitHub-Event")

	if event == "" {
		http.Error(w, "Bad Request", http.StatusBadRequest)
		return
	}

	if req.Body == nil {
		http.Error(w, "Bad Request", http.StatusBadRequest)
		return
	}
	defer req.Body.Close()

	var payload interface{}
	var decoder *json.Decoder

	if strings.Contains(req.Header.Get("Content-Type"), "application/json") {
		decoder = json.NewDecoder(req.Body)
		err := decoder.Decode(&payload)
		if err != nil {
			http.Error(w, "Bad Request", http.StatusBadRequest)
			return
		}
	} else if strings.Contains(req.Header.Get("Content-Type"), "application/x-www-form-urlencoded") {
		err := req.ParseForm()
		if err != nil {
			http.Error(w, "Bad Request", http.StatusBadRequest)
			return
		}
		p := req.FormValue("payload")
		decoder = json.NewDecoder(strings.NewReader(p))
		err = decoder.Decode(&payload)
		if err != nil {
			http.Error(w, "Bad Request", http.StatusBadRequest)
			fmt.Printf("error: %s", err.Error())
			return
		}
	}

	Emmit(event, payload)
	w.WriteHeader(http.StatusOK)
}
<commit_msg>共通部分をまとめた #3<commit_after>package ghooks

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"strings"
)

const (
	VERSION = 0.1
)

type Server struct {
	Port int
}

type Hook struct {
	Event string
	Func  func(payload interface{})
}

type Hooks struct {
	Hooks []Hook
}

var hooks Hooks

func (s *Server) On(name string, handler func(payload interface{})) {
	hooks.Hooks = append(hooks.Hooks, Hook{Event: name, Func: handler})
}

func Emmit(name string, payload interface{}) {
	for _, v := range hooks.Hooks {
		if strings.EqualFold(v.Event, name) {
			v.Func(payload)
		}
	}
}

func NewServer(port int) *Server {
	return &Server{port}
}

func (s *Server) Run() error {
	fmt.Printf("ghooks server start 0.0.0.0:%d \n", s.Port)
	http.HandleFunc("/", Reciver)
	return http.ListenAndServe(":"+strconv.Itoa(s.Port), nil)
}

func Reciver(w http.ResponseWriter, req *http.Request) {
	if req.Method == "GET" {
		http.Error(w, "Method Not Allowd", http.StatusMethodNotAllowed)
		return
	}

	event := req.Header.Get("X-GitHub-Event")

	if event == "" {
		http.Error(w, "Bad Request", http.StatusBadRequest)
		return
	}

	if req.Body == nil {
		http.Error(w, "Bad Request", http.StatusBadRequest)
		return
	}
	defer req.Body.Close()

	var payload interface{}
	var decoder *json.Decoder

	if strings.Contains(req.Header.Get("Content-Type"), "application/json") {

		decoder = json.NewDecoder(req.Body)

	} else if strings.Contains(req.Header.Get("Content-Type"), "application/x-www-form-urlencoded") {
		err := req.ParseForm()
		if err != nil {
			http.Error(w, "Bad Request", http.StatusBadRequest)
			return
		}
		p := req.FormValue("payload")
		decoder = json.NewDecoder(strings.NewReader(p))
	}

	err := decoder.Decode(&payload)
	if err != nil {
		http.Error(w, "Bad Request", http.StatusBadRequest)
		return
	}
	Emmit(event, payload)
	w.WriteHeader(http.StatusOK)
}
<|endoftext|>


<commit_before>// Package github implements a simple client to consume gitlab API.
package gogitlab

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

const (
	dasboard_feed_path = "/dashboard.atom"
)

type Gitlab struct {
	BaseUrl      string
	ApiPath      string
	RepoFeedPath string
	Token        string
	Client       *http.Client
}

const (
	dateLayout = "2006-01-02T15:04:05-07:00"
)

func NewGitlab(baseUrl, apiPath, token string) *Gitlab {

	client := &http.Client{}

	return &Gitlab{
		BaseUrl: baseUrl,
		ApiPath: apiPath,
		Token:   token,
		Client:  client,
	}
}

func (g *Gitlab) ResourceUrl(url string, params map[string]string) string {

	if params != nil {
		for key, val := range params {
			url = strings.Replace(url, key, val, -1)
		}
	}

	url = g.BaseUrl + g.ApiPath + url + "?private_token=" + g.Token
	return url
}

func (g *Gitlab) buildAndExecRequest(method, url string, body []byte) ([]byte, error) {

	var req *http.Request
	var err error

	if body != nil {
		reader := bytes.NewReader(body)
		req, err = http.NewRequest(method, url, reader)
	} else {
		req, err = http.NewRequest(method, url, nil)
	}
	if err != nil {
		panic("Error while building gitlab request")
	}

	resp, err := g.Client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("Client.Do error: %q", err)
	}
	defer resp.Body.Close()
	contents, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("%s", err)
	}

	if resp.StatusCode >= 400 {
		err = fmt.Errorf("*Gitlab.buildAndExecRequest failed: <%d> %s", resp.StatusCode, req.URL)
	}

	return contents, err
}

func (g *Gitlab) ResourceUrlRaw(u string, params map[string]string) (string, string) {

	if params != nil {
		for key, val := range params {
			u = strings.Replace(u, key, val, -1)
		}
	}

	path := u
	u = g.BaseUrl + g.ApiPath + path + "?private_token=" + g.Token
	p, err := url.Parse(u)
	if err != nil {
		return u, ""
	}
	opaque := "//" + p.Host + g.ApiPath + path
	return u, opaque
}

func (g *Gitlab) buildAndExecRequestRaw(method, url, opaque string, body []byte) ([]byte, error) {

	var req *http.Request
	var err error

	if body != nil {
		reader := bytes.NewReader(body)
		req, err = http.NewRequest(method, url, reader)
	} else {
		req, err = http.NewRequest(method, url, nil)
	}
	if err != nil {
		panic("Error while building gitlab request")
	}

	if len(opaque) > 0 {
		req.URL.Opaque = opaque
	}

	resp, err := g.Client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("Client.Do error: %q", err)
	}
	defer resp.Body.Close()
	contents, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("%s", err)
	}

	if resp.StatusCode >= 400 {
		err = fmt.Errorf("*Gitlab.buildAndExecRequestRaw failed: <%d> %s", resp.StatusCode, req.URL)
	}

	return contents, err
}
<commit_msg>Add support self-signed certificates<commit_after>// Package github implements a simple client to consume gitlab API.
package gogitlab

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"crypto/tls"
)

const (
	dasboard_feed_path = "/dashboard.atom"
)

type Gitlab struct {
	BaseUrl      string
	ApiPath      string
	RepoFeedPath string
	Token        string
	Client       *http.Client
}

const (
	dateLayout = "2006-01-02T15:04:05-07:00"
)

func NewGitlab(baseUrl, apiPath, token string) *Gitlab {

	config := &tls.Config{InsecureSkipVerify: true}
	tr := &http.Transport{ TLSClientConfig: config }
	client := &http.Client{Transport: tr}

	return &Gitlab{
		BaseUrl: baseUrl,
		ApiPath: apiPath,
		Token:   token,
		Client:  client,
	}
}

func (g *Gitlab) ResourceUrl(url string, params map[string]string) string {

	if params != nil {
		for key, val := range params {
			url = strings.Replace(url, key, val, -1)
		}
	}

	url = g.BaseUrl + g.ApiPath + url + "?private_token=" + g.Token
	return url
}

func (g *Gitlab) buildAndExecRequest(method, url string, body []byte) ([]byte, error) {

	var req *http.Request
	var err error

	if body != nil {
		reader := bytes.NewReader(body)
		req, err = http.NewRequest(method, url, reader)
	} else {
		req, err = http.NewRequest(method, url, nil)
	}
	if err != nil {
		panic("Error while building gitlab request")
	}

	resp, err := g.Client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("Client.Do error: %q", err)
	}
	defer resp.Body.Close()
	contents, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("%s", err)
	}

	if resp.StatusCode >= 400 {
		err = fmt.Errorf("*Gitlab.buildAndExecRequest failed: <%d> %s", resp.StatusCode, req.URL)
	}

	return contents, err
}

func (g *Gitlab) ResourceUrlRaw(u string, params map[string]string) (string, string) {

	if params != nil {
		for key, val := range params {
			u = strings.Replace(u, key, val, -1)
		}
	}

	path := u
	u = g.BaseUrl + g.ApiPath + path + "?private_token=" + g.Token
	p, err := url.Parse(u)
	if err != nil {
		return u, ""
	}
	opaque := "//" + p.Host + g.ApiPath + path
	return u, opaque
}

func (g *Gitlab) buildAndExecRequestRaw(method, url, opaque string, body []byte) ([]byte, error) {

	var req *http.Request
	var err error

	if body != nil {
		reader := bytes.NewReader(body)
		req, err = http.NewRequest(method, url, reader)
	} else {
		req, err = http.NewRequest(method, url, nil)
	}
	if err != nil {
		panic("Error while building gitlab request")
	}

	if len(opaque) > 0 {
		req.URL.Opaque = opaque
	}

	resp, err := g.Client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("Client.Do error: %q", err)
	}
	defer resp.Body.Close()
	contents, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("%s", err)
	}

	if resp.StatusCode >= 400 {
		err = fmt.Errorf("*Gitlab.buildAndExecRequestRaw failed: <%d> %s", resp.StatusCode, req.URL)
	}

	return contents, err
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	_ "net/http/pprof"
	"os"
	"path/filepath"
)

var (
	g_is_server = flag.Bool("s", false, "run a server instead of a client")
	g_format    = flag.String("f", "nice", "output format (vim | emacs | nice | csv | json)")
	g_input     = flag.String("in", "", "use this file instead of stdin input")
	g_sock      = create_sock_flag("sock", "socket type (unix | tcp)")
	g_addr      = flag.String("addr", "localhost:37373", "address for tcp socket")
	g_debug     = flag.Bool("debug", false, "enable server-side debug mode")
	g_profile   = flag.Int("profile", 0, "port on which to expose profiling information for pprof; 0 to disable profiling")
)

func get_socket_filename() string {
	user := os.Getenv("USER")
	if user == "" {
		user = "all"
	}
	return filepath.Join(os.TempDir(), fmt.Sprintf("gocode-daemon.%s", user))
}

func show_usage() {
	fmt.Fprintf(os.Stderr,
		"Usage: %s [-s] [-f=<format>] [-in=<path>] [-sock=<type>] [-addr=<addr>]\n"+
			"       <command> [<args>]\n\n",
		os.Args[0])
	fmt.Fprintf(os.Stderr,
		"Flags:\n")
	flag.PrintDefaults()
	fmt.Fprintf(os.Stderr,
		"\nCommands:\n"+
			"  autocomplete [<path>] <offset>     main autocompletion command\n"+
			"  close                              close the gocode daemon\n"+
			"  status                             gocode daemon status report\n"+
			"  drop-cache                         drop gocode daemon's cache\n"+
			"  set [<name> [<value>]]             list or set config options\n")
}

func main() {
	flag.Usage = show_usage
	flag.Parse()

	var retval int
	if *g_is_server {
		go func() {
			if *g_profile <= 0 {
				return
			}
			addr := fmt.Sprintf("localhost:%d", *g_profile)
			// Use the following commands to profile the binary:
			// go tool pprof http://localhost:6060/debug/pprof/profile   # 30-second CPU profile
			// go tool pprof http://localhost:6060/debug/pprof/heap      # heap profile
			// go tool pprof http://localhost:6060/debug/pprof/block     # goroutine blocking profile
			// See http://blog.golang.org/profiling-go-programs for more info.
			log.Printf("enabling  profiler on %s", addr)
			log.Print(http.ListenAndServe(addr, nil))
		}()
		retval = do_server()
	} else {
		retval = do_client()
	}
	os.Exit(retval)
}
<commit_msg>Use 127.0.0.1 instead of localhost to avoid DNS lookups.<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	_ "net/http/pprof"
	"os"
	"path/filepath"
)

var (
	g_is_server = flag.Bool("s", false, "run a server instead of a client")
	g_format    = flag.String("f", "nice", "output format (vim | emacs | nice | csv | json)")
	g_input     = flag.String("in", "", "use this file instead of stdin input")
	g_sock      = create_sock_flag("sock", "socket type (unix | tcp)")
	g_addr      = flag.String("addr", "127.0.0.1:37373", "address for tcp socket")
	g_debug     = flag.Bool("debug", false, "enable server-side debug mode")
	g_profile   = flag.Int("profile", 0, "port on which to expose profiling information for pprof; 0 to disable profiling")
)

func get_socket_filename() string {
	user := os.Getenv("USER")
	if user == "" {
		user = "all"
	}
	return filepath.Join(os.TempDir(), fmt.Sprintf("gocode-daemon.%s", user))
}

func show_usage() {
	fmt.Fprintf(os.Stderr,
		"Usage: %s [-s] [-f=<format>] [-in=<path>] [-sock=<type>] [-addr=<addr>]\n"+
			"       <command> [<args>]\n\n",
		os.Args[0])
	fmt.Fprintf(os.Stderr,
		"Flags:\n")
	flag.PrintDefaults()
	fmt.Fprintf(os.Stderr,
		"\nCommands:\n"+
			"  autocomplete [<path>] <offset>     main autocompletion command\n"+
			"  close                              close the gocode daemon\n"+
			"  status                             gocode daemon status report\n"+
			"  drop-cache                         drop gocode daemon's cache\n"+
			"  set [<name> [<value>]]             list or set config options\n")
}

func main() {
	flag.Usage = show_usage
	flag.Parse()

	var retval int
	if *g_is_server {
		go func() {
			if *g_profile <= 0 {
				return
			}
			addr := fmt.Sprintf("localhost:%d", *g_profile)
			// Use the following commands to profile the binary:
			// go tool pprof http://localhost:6060/debug/pprof/profile   # 30-second CPU profile
			// go tool pprof http://localhost:6060/debug/pprof/heap      # heap profile
			// go tool pprof http://localhost:6060/debug/pprof/block     # goroutine blocking profile
			// See http://blog.golang.org/profiling-go-programs for more info.
			log.Printf("enabling  profiler on %s", addr)
			log.Print(http.ListenAndServe(addr, nil))
		}()
		retval = do_server()
	} else {
		retval = do_client()
	}
	os.Exit(retval)
}
<|endoftext|>


<commit_before>// Package goldie provides test assertions based on golden files. It's typically
// used for testing responses with larger data bodies.
//
// The concept is straight forward. Valid response data is stored in a "golden
// file". The actual response data will be byte compared with the golden file
// and the test will fail if there is a difference.
//
// Updating the golden file can be done by running `go test -update ./...`.
package goldie

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
)

var (
	// FixtureDir is the folder name for where the fixtures are stored. It's
	// relative to the "go test" path.
	FixtureDir = "fixtures"

	// FileNameSuffix is the suffix appended to the fixtures. Set to empty
	// string to disable file name suffixes.
	FileNameSuffix = ".golden"

	// FlagName is the name of the command line flag for go test.
	FlagName = "update"

	// FilePerms is used to set the permissions on the golden fixture files.
	FilePerms os.FileMode = 0644

	// DirPerms is used to set the permissions on the golden fixture folder.
	DirPerms os.FileMode = 0755

	// update determines if the actual received data should be written to the
	// golden files or not. This should be true when you need to update the
	// data, but false when actually running the tests.
	update = flag.Bool(FlagName, false, "Update golden test file fixture")
)

// Assert compares the actual data received with the expected data in the
// golden files. If the update flag is set, it will also update the golden
// file.
//
// `name` refers to the name of the test and it should typically be unique
// withing the package. Also it should be a valid file name (so keeping to
// `a-z0-9\-\_` is a good idea).
func Assert(t *testing.T, name string, actualData []byte) {
	if *update {
		err := Update(name, actualData)
		if err != nil {
			t.Error(err)
			t.FailNow()
		}
	}

	expectedData, err := ioutil.ReadFile(goldenFileName(name))
	if err != nil {
		if os.IsNotExist(err) {
			t.Error("Golden fixture not found. Try running with -update flag.")
			t.FailNow()
		} else {
			t.Errorf("Expected %s to be nil", err.Error())
		}
	}

	if !bytes.Equal(actualData, expectedData) {
		t.Errorf("Result did not match the golden file")
	}
}

// Update will update the golden fixtures with the received actual data.
//
// This method does not need to be called from code, but it's exposed so that it
// can be explicitly called if needed. The more common approach would be to
// update using `go test -update ./...`.
func Update(name string, actualData []byte) error {
	err := ensureBasePath()
	if err != nil {
		return err
	}

	err := ioutil.WriteFile(goldenFileName(name), actualData, FilePerms)
	if err != nil {
		return err
	}

	return nil
}

// ensureBasePath will create the fixture folder if it does not already exist.
func ensureBasePath() error {
	_, err := os.Stat(FixtureDir)
	if err == nil {
		return nil
	}

	if os.IsNotExist(err) {
		err = os.Mkdir(FixtureDir, DirPerms)
		if err != nil {
			return err
		}
	}

	return err
}

// goldenFileName simply returns the file name of the golden file fixture.
func goldenFileName(name string) string {
	return filepath.Join(FixtureDir, fmt.Sprintf("%s%s", name, FileNameSuffix))
}
<commit_msg>Fix issue with no new variables on the left<commit_after>// Package goldie provides test assertions based on golden files. It's typically
// used for testing responses with larger data bodies.
//
// The concept is straight forward. Valid response data is stored in a "golden
// file". The actual response data will be byte compared with the golden file
// and the test will fail if there is a difference.
//
// Updating the golden file can be done by running `go test -update ./...`.
package goldie

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
)

var (
	// FixtureDir is the folder name for where the fixtures are stored. It's
	// relative to the "go test" path.
	FixtureDir = "fixtures"

	// FileNameSuffix is the suffix appended to the fixtures. Set to empty
	// string to disable file name suffixes.
	FileNameSuffix = ".golden"

	// FlagName is the name of the command line flag for go test.
	FlagName = "update"

	// FilePerms is used to set the permissions on the golden fixture files.
	FilePerms os.FileMode = 0644

	// DirPerms is used to set the permissions on the golden fixture folder.
	DirPerms os.FileMode = 0755

	// update determines if the actual received data should be written to the
	// golden files or not. This should be true when you need to update the
	// data, but false when actually running the tests.
	update = flag.Bool(FlagName, false, "Update golden test file fixture")
)

// Assert compares the actual data received with the expected data in the
// golden files. If the update flag is set, it will also update the golden
// file.
//
// `name` refers to the name of the test and it should typically be unique
// withing the package. Also it should be a valid file name (so keeping to
// `a-z0-9\-\_` is a good idea).
func Assert(t *testing.T, name string, actualData []byte) {
	if *update {
		err := Update(name, actualData)
		if err != nil {
			t.Error(err)
			t.FailNow()
		}
	}

	expectedData, err := ioutil.ReadFile(goldenFileName(name))
	if err != nil {
		if os.IsNotExist(err) {
			t.Error("Golden fixture not found. Try running with -update flag.")
			t.FailNow()
		} else {
			t.Errorf("Expected %s to be nil", err.Error())
		}
	}

	if !bytes.Equal(actualData, expectedData) {
		t.Errorf("Result did not match the golden file")
	}
}

// Update will update the golden fixtures with the received actual data.
//
// This method does not need to be called from code, but it's exposed so that it
// can be explicitly called if needed. The more common approach would be to
// update using `go test -update ./...`.
func Update(name string, actualData []byte) error {
	err := ensureBasePath()
	if err != nil {
		return err
	}

	err = ioutil.WriteFile(goldenFileName(name), actualData, FilePerms)
	if err != nil {
		return err
	}

	return nil
}

// ensureBasePath will create the fixture folder if it does not already exist.
func ensureBasePath() error {
	_, err := os.Stat(FixtureDir)
	if err == nil {
		return nil
	}

	if os.IsNotExist(err) {
		err = os.Mkdir(FixtureDir, DirPerms)
		if err != nil {
			return err
		}
	}

	return err
}

// goldenFileName simply returns the file name of the golden file fixture.
func goldenFileName(name string) string {
	return filepath.Join(FixtureDir, fmt.Sprintf("%s%s", name, FileNameSuffix))
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"encoding/json"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

func main() {
	// set logging
	f, err := os.OpenFile("debug.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	checkError(err)
	defer f.Close()
	log.SetOutput(f)

	// listen for stdin
	for {
		// get message length, 4 bytes
		var data map[string]string
		var length uint32
		err := binary.Read(os.Stdin, binary.LittleEndian, &length)
		if err != nil {
			break
		}

		input := make([]byte, length)
		_, err = os.Stdin.Read(input)
		if err != nil {
			break
		}

		err = json.Unmarshal(input, &data)
		checkError(err)

		usernames := getUsernames(data["domain"])
		results := make([]map[string]string, 0)

		for _, username := range usernames {
			password, _ := getPassword(data["domain"], username)
			results = append(results, map[string]string{
				"u": username,
				"p": password,
			})
		}

		jsonResponse, err := json.Marshal(results)
		checkError(err)
		binary.Write(os.Stdout, binary.LittleEndian, uint32(len(jsonResponse)))
		_, err = os.Stdout.Write(jsonResponse)
		checkError(err)
	}
}

// get list of usernames for the domain
func getUsernames(domain string) []string {
	matches, _ := filepath.Glob(os.Getenv("HOME") + "/.password-store/" + domain + "*/*.gpg")
	usernames := make([]string, 0)

	for _, file := range matches {
		_, filename := filepath.Split(file)
		username := strings.TrimSuffix(filename, filepath.Ext(filename))
		usernames = append(usernames, username)
	}

	return usernames
}

// runs pass to get decrypted file content
func getPassword(domain string, username string) (string, error) {
	var out bytes.Buffer
	cmd := exec.Command("pass", domain+"/"+username)
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		return "", err
	}

	// read first line (the password)
	scanner := bufio.NewScanner(&out)
	scanner.Scan()
	password := scanner.Text()
	return password, nil
}

func checkError(err error) {
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Add support for PASSWORD_STORE_DIR env variable. Closes #1<commit_after>package main

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"encoding/json"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

var PwStoreDir string

func main() {
	// Find dir to password store
	PwStoreDir = os.Getenv("PASSWORD_STORE_DIR")
	if PwStoreDir == "" {
		PwStoreDir = os.Getenv("HOME") + "/.password-store/"
	}

	// set logging
	f, err := os.OpenFile("debug.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	checkError(err)
	defer f.Close()
	log.SetOutput(f)

	// listen for stdin
	for {
		// get message length, 4 bytes
		var data map[string]string
		var length uint32
		err := binary.Read(os.Stdin, binary.LittleEndian, &length)
		if err != nil {
			break
		}

		input := make([]byte, length)
		_, err = os.Stdin.Read(input)
		if err != nil {
			break
		}

		err = json.Unmarshal(input, &data)
		checkError(err)

		usernames := getUsernames(data["domain"])
		results := make([]map[string]string, 0)

		for _, username := range usernames {
			password, _ := getPassword(data["domain"], username)
			results = append(results, map[string]string{
				"u": username,
				"p": password,
			})
		}

		jsonResponse, err := json.Marshal(results)
		checkError(err)
		binary.Write(os.Stdout, binary.LittleEndian, uint32(len(jsonResponse)))
		_, err = os.Stdout.Write(jsonResponse)
		checkError(err)
	}
}

// get list of usernames for the domain
func getUsernames(domain string) []string {
	matches, _ := filepath.Glob(PwStoreDir + domain + "*/*.gpg")
	usernames := make([]string, 0)

	for _, file := range matches {
		_, filename := filepath.Split(file)
		username := strings.TrimSuffix(filename, filepath.Ext(filename))
		usernames = append(usernames, username)
	}

	return usernames
}

// runs pass to get decrypted file content
func getPassword(domain string, username string) (string, error) {
	var out bytes.Buffer
	cmd := exec.Command("pass", domain+"/"+username)
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		return "", err
	}

	// read first line (the password)
	scanner := bufio.NewScanner(&out)
	scanner.Scan()
	password := scanner.Text()
	return password, nil
}

func checkError(err error) {
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package gopher

import (
	"net/http"

	f "github.com/gopherlabs/gopher-framework"
	"github.com/gopherlabs/gopher-services"
)

var (
	c          *f.Container
	App        *app
	Log        f.Loggable
	Route      f.Routable
	RouteGroup routeGroup
	Context    f.Mappable
	Render     f.Renderable
)

type app struct {
	ctnr *f.Container
}

func init() {
	initApp()
	App.Config()
}

func initApp() {
	app := new(app)
	App = app
}

type Config map[string]interface{}
type ConfigLogger f.ConfigLogger
type ConfigRouter f.ConfigRouter
type ConfigRenderer f.ConfigRenderer

type GroupMatcher struct {
	Host       string
	PathPrefix string
	Methods    []string
	Queries    []string
	Schemes    []string
}

type routeGroup struct{}

func (g *routeGroup) New(matcher GroupMatcher) f.Routable {
	return App.ctnr.RouteGroup.New(f.GroupMatcher(matcher))
}

func (m *app) Config(config ...map[string]interface{}) {
	if len(config) > 0 {
		c = f.NewContainer(convertConfig(config[0]))
	} else {
		c = f.NewContainer()
	}
	App.ctnr = c
	c.Use(f.LoggerMiddleware)
	registerProviders()
}

func (m *app) Use(mw f.MiddlewareHandler, args ...interface{}) {
	m.ctnr.Use(mw, args...)
}

func convertConfig(in Config) f.Config {
	conf := f.Config{}
	if in[KEY_LOGGER] != nil {
		conf[KEY_LOGGER] = f.ConfigLogger(in[KEY_LOGGER].(ConfigLogger))
	}
	if in[KEY_ROUTER] != nil {
		conf[KEY_ROUTER] = f.ConfigRouter(in[KEY_ROUTER].(ConfigRouter))
	}
	if in[KEY_RENDERER] != nil {
		conf[KEY_RENDERER] = f.ConfigRenderer(in[KEY_RENDERER].(ConfigRenderer))
	}
	return conf
}

func registerProviders() {
	c.RegisterProvider(new(services.LogProvider))
	Log = c.Log
	c.RegisterProvider(new(services.MapProvider))
	Context = c.Context
	c.RegisterProvider(new(services.RouteProvider))
	Route = c.Route
	RouteGroup = routeGroup{}
	c.RegisterProvider(new(services.RenderProvider))
	Render = c.Render
	f.Initialized = true
}

func ListenAndServe() {
	Route.(f.Servable).ListenAndServe()
}

func GetHttpHandler() http.Handler {
	return Route.(f.Servable).GetHttpHandler()
}

const (
	KEY_LOGGER   = f.LOGGER
	KEY_ROUTER   = f.ROUTER
	KEY_RENDERER = f.RENDERER
	KEY_MAPPER   = f.MAPPER
)

// Log Levels
const (
	// PanicLevel level, highest level of severity. Logs and then calls panic with the
	// message passed to Debug, Info, ...
	LEVEL_PANIC uint8 = iota
	// FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the
	// logging level is set to Panic.
	LEVEL_FATAL
	// ErrorLevel level. Logs. Used for errors that should definitely be noted.
	// Commonly used for hooks to send errors to an error tracking service.
	LEVEL_ERROR
	// WarnLevel level. Non-critical entries that deserve eyes.
	LEVEL_WARN
	// InfoLevel level. General operational entries about what's going on inside the
	// application.
	LEVEL_INFO
	// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
	LEVEL_DEBUG
)
<commit_msg>Replaced mapper with context<commit_after>package gopher

import (
	"net/http"

	f "github.com/gopherlabs/gopher-framework"
	"github.com/gopherlabs/gopher-services"
)

var (
	c          *f.Container
	App        *app
	Log        f.Loggable
	Route      f.Routable
	RouteGroup routeGroup
	Context    f.Contextable
	Render     f.Renderable
)

type app struct {
	ctnr *f.Container
}

func init() {
	initApp()
	App.Config()
}

func initApp() {
	app := new(app)
	App = app
}

type Config map[string]interface{}
type ConfigLogger f.ConfigLogger
type ConfigRouter f.ConfigRouter
type ConfigRenderer f.ConfigRenderer

type GroupMatcher struct {
	Host       string
	PathPrefix string
	Methods    []string
	Queries    []string
	Schemes    []string
}

type routeGroup struct{}

func (g *routeGroup) New(matcher GroupMatcher) f.Routable {
	return App.ctnr.RouteGroup.New(f.GroupMatcher(matcher))
}

func (m *app) Config(config ...map[string]interface{}) {
	if len(config) > 0 {
		c = f.NewContainer(convertConfig(config[0]))
	} else {
		c = f.NewContainer()
	}
	App.ctnr = c
	c.Use(f.LoggerMiddleware)
	registerProviders()
}

func (m *app) Use(mw f.MiddlewareHandler, args ...interface{}) {
	m.ctnr.Use(mw, args...)
}

func convertConfig(in Config) f.Config {
	conf := f.Config{}
	if in[KEY_LOGGER] != nil {
		conf[KEY_LOGGER] = f.ConfigLogger(in[KEY_LOGGER].(ConfigLogger))
	}
	if in[KEY_ROUTER] != nil {
		conf[KEY_ROUTER] = f.ConfigRouter(in[KEY_ROUTER].(ConfigRouter))
	}
	if in[KEY_RENDERER] != nil {
		conf[KEY_RENDERER] = f.ConfigRenderer(in[KEY_RENDERER].(ConfigRenderer))
	}
	return conf
}

func registerProviders() {
	c.RegisterProvider(new(services.LogProvider))
	Log = c.Log
	c.RegisterProvider(new(services.ContextProvider))
	Context = c.Context
	c.RegisterProvider(new(services.RouteProvider))
	Route = c.Route
	RouteGroup = routeGroup{}
	c.RegisterProvider(new(services.RenderProvider))
	Render = c.Render
	f.Initialized = true
}

func ListenAndServe() {
	Route.(f.Servable).ListenAndServe()
}

func GetHttpHandler() http.Handler {
	return Route.(f.Servable).GetHttpHandler()
}

const (
	KEY_LOGGER   = f.LOGGER
	KEY_ROUTER   = f.ROUTER
	KEY_RENDERER = f.RENDERER
	KEY_CONTEXT  = f.CONTEXT
)

// Log Levels
const (
	// PanicLevel level, highest level of severity. Logs and then calls panic with the
	// message passed to Debug, Info, ...
	LEVEL_PANIC uint8 = iota
	// FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the
	// logging level is set to Panic.
	LEVEL_FATAL
	// ErrorLevel level. Logs. Used for errors that should definitely be noted.
	// Commonly used for hooks to send errors to an error tracking service.
	LEVEL_ERROR
	// WarnLevel level. Non-critical entries that deserve eyes.
	LEVEL_WARN
	// InfoLevel level. General operational entries about what's going on inside the
	// application.
	LEVEL_INFO
	// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
	LEVEL_DEBUG
)
<|endoftext|>


<commit_before>package main

import  (
        "fmt"
        "os"
        "../go-todotxt"
        "github.com/spf13/cobra"
        "os/user"
        "strings"
        "strconv"
        "github.com/rakyll/globalconf"
        "flag"
        "regexp"
        "os/exec"
        "io/ioutil"
)

func extendedLoader(filename string) (todotxt.TaskList, error) {
        usr, err := user.Current()
        if err != nil {
                return nil, err
        }

        filename = strings.Replace(filename, "~", usr.HomeDir, -1)
        tasks := todotxt.LoadTaskList(filename)

        return tasks, nil
}

type flagValue struct {
        str string
}

func (f *flagValue) String() string {
        return f.str
}

func (f *flagValue) Set(value string) error {
        f.str = value
        return nil
}

func newFlagValue(val string) *flagValue {
        return &flagValue{str: val}
}

func main() {

        conf, _ := globalconf.New("gotodo")

        var numtasks bool
        var sortby string
        var finished bool
        var prettyformat string
        var filename string
        var no_color bool

        var flagFilename = flag.String("file", "", "Location of the todo.txt file.")

        var flags = make(map[string]string)

        var cmdConfig = &cobra.Command{
            Use:   "config [key] [value]",
            Short: "Show and sets config values",
            Long:  `Config can be used to see and also set configuration variables.`,
            Run: func(cmd *cobra.Command, args []string) {
                    if len(args) == 0{
                            fmt.Printf("Available config variables:\n\n")
                            for k := range flags {
                                    fmt.Printf("%s\n", k)
                            }
                    }
                    if len(args) == 1 {
                            val, exists := flags[args[0]]
                            if exists {
                                    fmt.Printf("%s\n", val)
                            } else {
                                    // otherwise exit with non-zero status
                                    os.Exit(1)
                            }
                    }
                    if len(args) == 2 {
                            _, exists := flags[args[0]]
                            if exists {
                                    f := &flag.Flag{Name: args[0], Value: newFlagValue(args[1])}
                                    conf.Set("", f)
                            } else {
                                    os.Exit(1)
                            }
                    }
            },
        }

        var cmdList = &cobra.Command{
            Use:   "list [keyword]",
            Short: "Lists tasks that contain keyword, if any",
            Long:  `List is the most basic command that is used for listing tasks.
                    You can specify a keyword as well as other options.`,
            Run: func(cmd *cobra.Command, args []string) {
                tasks, err := extendedLoader(filename)
                if err != nil {
                        fmt.Println(err)
                        return
                }

                if numtasks {
                    fmt.Println(tasks.Len())
                } else {
                    tasks.Sort(sortby)

                    if no_color {
                        prettyformat = "%i %p %t%r"
                    }

                    var filteredTasks todotxt.TaskList
                    for _, task := range tasks {
                        if (!task.Finished() && !finished) ||
                           (task.Finished() && finished) {
                           if (len(args) > 0) {
                                   match, _ := regexp.MatchString(args[0], task.Text())
                                   if match {
                                           filteredTasks = append(filteredTasks, task)
                                   }
                           } else {
                                   filteredTasks = append(filteredTasks, task)
                           }
                        }
                    }

                    for _, task := range filteredTasks {
                            task.SetIdPaddingBy(tasks)
                            fmt.Println(task.PrettyPrint(prettyformat))
                    }
                }
            },
        }
        cmdList.Flags().BoolVarP(&numtasks, "num-tasks", "n", false,
                                 "Show the number of tasks")
        cmdList.Flags().BoolVarP(&finished, "finished", "f", false,
                                 "Show finished tasks")
        cmdList.Flags().StringVarP(&sortby, "sort", "s", "prio",
                                   "Sort tasks by parameter (prio|date|len|prio-rev|date-rev|len-rev|id|rand)")
        cmdList.Flags().StringVarP(&prettyformat, "pretty", "", "%i%c %p %t%r",
                                   "Pretty print tasks")
        cmdList.Flags().BoolVarP(&no_color, "no-color", "c", false,
                                 "Do not use colored output when pretty-printing")

        var cmdAdd = &cobra.Command{
            Use:   "add [task]",
            Short: "Adds a task to the todo list.",
            Long:  `Adds a task to the todo list.`,
            Run: func(cmd *cobra.Command, args []string) {
                tasks, err := extendedLoader(filename)
                if err != nil {
                        fmt.Println(err)
                        return
                }

                if len(args) == 0 {
                        fmt.Println("No task to be added.")
                        return
                }

                task := strings.Join(args, " ")
                tasks.Add(task)

                tasks.Save(filename)
            },
        }

        var nofinishdate bool
        var cmdDone = &cobra.Command{
            Use:   "done [taskid]",
            Short: "Marks task as done.",
            Long:  `Marks task as done.`,
            Run: func(cmd *cobra.Command, args []string) {
                tasks, err := extendedLoader(filename)
                if err != nil {
                        fmt.Println(err)
                        return
                }

                if len(args) < 1 {
                        fmt.Println("So what needs to be done?")
                        return
                }

                taskid, err := strconv.Atoi(args[0])
                if err != nil {
                        fmt.Printf("Do you really consider that a number? %v\n", err)
                        return
                }

                err = tasks.Done(taskid, !nofinishdate)
                if err != nil {
                        fmt.Printf("There was an error %v\n", err)
                }

                tasks.Save(filename)
            },
        }
        cmdDone.Flags().BoolVarP(&nofinishdate, "no-finish-date", "D", false,
                                        "Do not mark finished tasks with date.")

        var cmdArchive = &cobra.Command{
            Use:   "archive [taskid]",
            Short: "Archives task.",
            Long:  `Archives task.`,
            Run: func(cmd *cobra.Command, args []string) {
                tasks, err := extendedLoader(filename)
                if err != nil {
                        fmt.Println(err)
                        return
                }

                if len(args) < 1 {
                        fmt.Println("So what needs to be done?")
                        return
                }

                taskid, err := strconv.Atoi(args[0])
                if err != nil {
                        fmt.Printf("Do you really consider that a number? %v\n", err)
                        return
                }

                fmt.Printf("Archiving task %v\n", taskid)

                tasks.Save(filename)
            },
        }

        var setprio string
        var settodo string
        var cmdSet = &cobra.Command{
            Use:   "set [taskid]",
            Short: "Sets given task's parameters.",
            Long:  `Sets given task's parameters.`,
            Run: func(cmd *cobra.Command, args []string) {
                tasks, err := extendedLoader(filename)
                if err != nil {
                        fmt.Println(err)
                        return
                }

                if len(args) < 1 {
                        fmt.Println("So what do you want to edit?")
                        return
                }

                taskid, err := strconv.Atoi(args[0])
                if err != nil {
                        fmt.Printf("Do you really consider that a number? %v\n", err)
                        return
                }

                if len(setprio) > 0 {
                        tasks[taskid].SetPriority(setprio[0])
                        tasks[taskid].RebuildRawTodo()
                }

                if len(settodo) > 0 {
                        tasks[taskid].SetTodo(settodo)
                        tasks[taskid].RebuildRawTodo()
                }

                tasks.Save(filename)
            },
        }

        var cmdEdit = &cobra.Command{
            Use:   "edit [taskid]",
            Short: "Edit given task",
            Long:  `Edit given task with your prefered editor.`,
            Run: func(cmd *cobra.Command, args []string) {
                tasks, err := extendedLoader(filename)
                if err != nil {
                        fmt.Println(err)
                        return
                }

                if len(args) < 1 {
                        fmt.Println("So what do you want to edit?")
                        return
                }

                taskid, err := strconv.Atoi(args[0])
                if err != nil {
                        fmt.Printf("Do you really consider that a number? %v\n", err)
                        return
                }

                text := tasks[taskid].RawText()

                file, err := ioutil.TempFile(os.TempDir(), "gotodo")
                defer os.Remove(file.Name())

                if err != nil {
                        panic(err)
                }

                e := ioutil.WriteFile(file.Name(), []byte(text), 0644)
                if e != nil {
                        panic(e)
                }

                editor := os.Getenv("EDITOR")
                if len(editor) == 0 {
                        editor = "nano" //FIXME: saner default?
                }

                c := exec.Command(editor, file.Name())

                // nasty hack, see http://stackoverflow.com/a/12089980
                c.Stdin = os.Stdin
                c.Stdout = os.Stdout
                c.Stderr = os.Stderr

                er := c.Run()

                if er != nil {
                        fmt.Println(er.Error())
                        panic(er)
                }

                dat, err := ioutil.ReadFile(file.Name())
                if err != nil {
                        panic(err)
                }

                lines := strings.Split(string(dat), "\n")
                if len (lines) > 0 {
                        if tasks[taskid].RawText() != lines[0] {
                                tasks[taskid] = todotxt.ParseTask(lines[0], taskid)
                                fmt.Printf("Task %d updated to:\n%s\n", taskid, lines[0])
                        }
                }

                tasks.Save(filename)
            },
        }

        cmdSet.PersistentFlags().StringVarP(&setprio, "priority", "p", "",
                                     "Sets task's priority.")
        cmdSet.PersistentFlags().StringVarP(&settodo, "todo", "t", "",
                                     "Sets task's todo.")

        var GotodoCmd = &cobra.Command{
            Use:   "gotodo",
            Short: "Gotodo is a go implementation of todo.txt.",
            Long: `A small, fast and fun implementation of todo.txt`,
            Run: func(cmd *cobra.Command, args []string) {
                cmdList.Run(cmd, nil)
            },
        }

        GotodoCmd.PersistentFlags().StringVarP(&filename, "filename", "", "",
                                     "Load tasks from this file.")

        conf.ParseAll()

        // values here
        flags["file"] = *flagFilename

        // sadly, this is the best we can do right now
        if filename == "" {
                if *flagFilename == "" {
                        filename = "todo.txt"
                } else {
                        filename = *flagFilename
                }
        }

        GotodoCmd.AddCommand(cmdList)
        GotodoCmd.AddCommand(cmdAdd)
        GotodoCmd.AddCommand(cmdDone)
        GotodoCmd.AddCommand(cmdArchive)
        GotodoCmd.AddCommand(cmdSet)
        GotodoCmd.AddCommand(cmdEdit)
        GotodoCmd.AddCommand(cmdConfig)
        GotodoCmd.Execute()
}
<commit_msg>update: Using new task.Matches<commit_after>package main

import  (
        "fmt"
        "os"
        "../go-todotxt"
        "github.com/spf13/cobra"
        "os/user"
        "strings"
        "strconv"
        "github.com/rakyll/globalconf"
        "flag"
        "os/exec"
        "io/ioutil"
)

func extendedLoader(filename string) (todotxt.TaskList, error) {
        usr, err := user.Current()
        if err != nil {
                return nil, err
        }

        filename = strings.Replace(filename, "~", usr.HomeDir, -1)
        tasks := todotxt.LoadTaskList(filename)

        return tasks, nil
}

type flagValue struct {
        str string
}

func (f *flagValue) String() string {
        return f.str
}

func (f *flagValue) Set(value string) error {
        f.str = value
        return nil
}

func newFlagValue(val string) *flagValue {
        return &flagValue{str: val}
}

func main() {

        conf, _ := globalconf.New("gotodo")

        var numtasks bool
        var sortby string
        var finished bool
        var prettyformat string
        var filename string
        var no_color bool

        var flagFilename = flag.String("file", "", "Location of the todo.txt file.")

        var flags = make(map[string]string)

        var cmdConfig = &cobra.Command{
            Use:   "config [key] [value]",
            Short: "Show and sets config values",
            Long:  `Config can be used to see and also set configuration variables.`,
            Run: func(cmd *cobra.Command, args []string) {
                    if len(args) == 0{
                            fmt.Printf("Available config variables:\n\n")
                            for k := range flags {
                                    fmt.Printf("%s\n", k)
                            }
                    }
                    if len(args) == 1 {
                            val, exists := flags[args[0]]
                            if exists {
                                    fmt.Printf("%s\n", val)
                            } else {
                                    // otherwise exit with non-zero status
                                    os.Exit(1)
                            }
                    }
                    if len(args) == 2 {
                            _, exists := flags[args[0]]
                            if exists {
                                    f := &flag.Flag{Name: args[0], Value: newFlagValue(args[1])}
                                    conf.Set("", f)
                            } else {
                                    os.Exit(1)
                            }
                    }
            },
        }

        var cmdList = &cobra.Command{
            Use:   "list [keyword]",
            Short: "Lists tasks that contain keyword, if any",
            Long:  `List is the most basic command that is used for listing tasks.
                    You can specify a keyword as well as other options.`,
            Run: func(cmd *cobra.Command, args []string) {
                tasks, err := extendedLoader(filename)
                if err != nil {
                        fmt.Println(err)
                        return
                }

                if numtasks {
                    fmt.Println(tasks.Len())
                } else {
                    tasks.Sort(sortby)

                    if no_color {
                        prettyformat = "%i %p %t%r"
                    }

                    var filteredTasks todotxt.TaskList
                    for _, task := range tasks {
                        if (!task.Finished() && !finished) ||
                           (task.Finished() && finished) {
                           if (len(args) > 0) {
                                   if task.Matches(strings.Join(args, " ")) {
                                           filteredTasks = append(filteredTasks, task)
                                   }
                           } else {
                                   filteredTasks = append(filteredTasks, task)
                           }
                        }
                    }

                    for _, task := range filteredTasks {
                            task.SetIdPaddingBy(tasks)
                            fmt.Println(task.PrettyPrint(prettyformat))
                    }
                }
            },
        }
        cmdList.Flags().BoolVarP(&numtasks, "num-tasks", "n", false,
                                 "Show the number of tasks")
        cmdList.Flags().BoolVarP(&finished, "finished", "f", false,
                                 "Show finished tasks")
        cmdList.Flags().StringVarP(&sortby, "sort", "s", "prio",
                                   "Sort tasks by parameter (prio|date|len|prio-rev|date-rev|len-rev|id|rand)")
        cmdList.Flags().StringVarP(&prettyformat, "pretty", "", "%i%c %p %t%r",
                                   "Pretty print tasks")
        cmdList.Flags().BoolVarP(&no_color, "no-color", "c", false,
                                 "Do not use colored output when pretty-printing")

        var cmdAdd = &cobra.Command{
            Use:   "add [task]",
            Short: "Adds a task to the todo list.",
            Long:  `Adds a task to the todo list.`,
            Run: func(cmd *cobra.Command, args []string) {
                tasks, err := extendedLoader(filename)
                if err != nil {
                        fmt.Println(err)
                        return
                }

                if len(args) == 0 {
                        fmt.Println("No task to be added.")
                        return
                }

                task := strings.Join(args, " ")
                tasks.Add(task)

                tasks.Save(filename)
            },
        }

        var nofinishdate bool
        var cmdDone = &cobra.Command{
            Use:   "done [taskid]",
            Short: "Marks task as done.",
            Long:  `Marks task as done.`,
            Run: func(cmd *cobra.Command, args []string) {
                tasks, err := extendedLoader(filename)
                if err != nil {
                        fmt.Println(err)
                        return
                }

                if len(args) < 1 {
                        fmt.Println("So what needs to be done?")
                        return
                }

                taskid, err := strconv.Atoi(args[0])
                if err != nil {
                        fmt.Printf("Do you really consider that a number? %v\n", err)
                        return
                }

                err = tasks.Done(taskid, !nofinishdate)
                if err != nil {
                        fmt.Printf("There was an error %v\n", err)
                }

                tasks.Save(filename)
            },
        }
        cmdDone.Flags().BoolVarP(&nofinishdate, "no-finish-date", "D", false,
                                        "Do not mark finished tasks with date.")

        var cmdArchive = &cobra.Command{
            Use:   "archive [taskid]",
            Short: "Archives task.",
            Long:  `Archives task.`,
            Run: func(cmd *cobra.Command, args []string) {
                tasks, err := extendedLoader(filename)
                if err != nil {
                        fmt.Println(err)
                        return
                }

                if len(args) < 1 {
                        fmt.Println("So what needs to be done?")
                        return
                }

                taskid, err := strconv.Atoi(args[0])
                if err != nil {
                        fmt.Printf("Do you really consider that a number? %v\n", err)
                        return
                }

                fmt.Printf("Archiving task %v\n", taskid)

                tasks.Save(filename)
            },
        }

        var setprio string
        var settodo string
        var cmdSet = &cobra.Command{
            Use:   "set [taskid]",
            Short: "Sets given task's parameters.",
            Long:  `Sets given task's parameters.`,
            Run: func(cmd *cobra.Command, args []string) {
                tasks, err := extendedLoader(filename)
                if err != nil {
                        fmt.Println(err)
                        return
                }

                if len(args) < 1 {
                        fmt.Println("So what do you want to edit?")
                        return
                }

                taskid, err := strconv.Atoi(args[0])
                if err != nil {
                        fmt.Printf("Do you really consider that a number? %v\n", err)
                        return
                }

                if len(setprio) > 0 {
                        tasks[taskid].SetPriority(setprio[0])
                        tasks[taskid].RebuildRawTodo()
                }

                if len(settodo) > 0 {
                        tasks[taskid].SetTodo(settodo)
                        tasks[taskid].RebuildRawTodo()
                }

                tasks.Save(filename)
            },
        }

        var cmdEdit = &cobra.Command{
            Use:   "edit [taskid]",
            Short: "Edit given task",
            Long:  `Edit given task with your prefered editor.`,
            Run: func(cmd *cobra.Command, args []string) {
                tasks, err := extendedLoader(filename)
                if err != nil {
                        fmt.Println(err)
                        return
                }

                if len(args) < 1 {
                        fmt.Println("So what do you want to edit?")
                        return
                }

                taskid, err := strconv.Atoi(args[0])
                if err != nil {
                        fmt.Printf("Do you really consider that a number? %v\n", err)
                        return
                }

                text := tasks[taskid].RawText()

                file, err := ioutil.TempFile(os.TempDir(), "gotodo")
                defer os.Remove(file.Name())

                if err != nil {
                        panic(err)
                }

                e := ioutil.WriteFile(file.Name(), []byte(text), 0644)
                if e != nil {
                        panic(e)
                }

                editor := os.Getenv("EDITOR")
                if len(editor) == 0 {
                        editor = "nano" //FIXME: saner default?
                }

                c := exec.Command(editor, file.Name())

                // nasty hack, see http://stackoverflow.com/a/12089980
                c.Stdin = os.Stdin
                c.Stdout = os.Stdout
                c.Stderr = os.Stderr

                er := c.Run()

                if er != nil {
                        fmt.Println(er.Error())
                        panic(er)
                }

                dat, err := ioutil.ReadFile(file.Name())
                if err != nil {
                        panic(err)
                }

                lines := strings.Split(string(dat), "\n")
                if len (lines) > 0 {
                        if tasks[taskid].RawText() != lines[0] {
                                tasks[taskid] = todotxt.ParseTask(lines[0], taskid)
                                fmt.Printf("Task %d updated to:\n%s\n", taskid, lines[0])
                        }
                }

                tasks.Save(filename)
            },
        }

        cmdSet.PersistentFlags().StringVarP(&setprio, "priority", "p", "",
                                     "Sets task's priority.")
        cmdSet.PersistentFlags().StringVarP(&settodo, "todo", "t", "",
                                     "Sets task's todo.")

        var GotodoCmd = &cobra.Command{
            Use:   "gotodo",
            Short: "Gotodo is a go implementation of todo.txt.",
            Long: `A small, fast and fun implementation of todo.txt`,
            Run: func(cmd *cobra.Command, args []string) {
                cmdList.Run(cmd, nil)
            },
        }

        GotodoCmd.PersistentFlags().StringVarP(&filename, "filename", "", "",
                                     "Load tasks from this file.")

        conf.ParseAll()

        // values here
        flags["file"] = *flagFilename

        // sadly, this is the best we can do right now
        if filename == "" {
                if *flagFilename == "" {
                        filename = "todo.txt"
                } else {
                        filename = *flagFilename
                }
        }

        GotodoCmd.AddCommand(cmdList)
        GotodoCmd.AddCommand(cmdAdd)
        GotodoCmd.AddCommand(cmdDone)
        GotodoCmd.AddCommand(cmdArchive)
        GotodoCmd.AddCommand(cmdSet)
        GotodoCmd.AddCommand(cmdEdit)
        GotodoCmd.AddCommand(cmdConfig)
        GotodoCmd.Execute()
}
<|endoftext|>


<commit_before>/* grcron
 *
 * Copyright (c) 2017 Motoaki Nishikawa
 * Distributed under MIT license, see LICENSE file.
 */

package main

import (
	"bufio"
	"flag"
	"fmt"
	"os"
	"os/exec"
	"runtime"
	"syscall"
)

const version string = "0.0.3"

type grcron struct {
	StateFile    string
	DefaultState string
	CurrentState string
}

func (gr grcron) Validate() error {
	_, err := os.Stat(gr.StateFile)
	if err != nil {
		return err
	}
	if !(gr.DefaultState == "active" || gr.DefaultState == "passive") {
		return fmt.Errorf("The Value of DefaultState:%s is incorrect", gr.DefaultState)
	}
	return nil
}

func (gr *grcron) ParseState() error {
	if gr == nil {
		return fmt.Errorf("Don't run nil Pointer Receiver")
	}
	f, err := os.Open(gr.StateFile)
	if err != nil {
		return err
	}
	defer f.Close()

	sc := bufio.NewScanner(f)
	if !sc.Scan() {
		return sc.Err()
	}
	st := sc.Text()
	switch st {
	case "active", "passive":
		gr.CurrentState = st
	default:
		fmt.Fprintf(os.Stderr, "corrupted state file('%s') (content='%s'), staying at gr.DefaultState('%s')\n", gr.StateFile, st, gr.DefaultState)
		gr.CurrentState = gr.DefaultState
	}
	return nil
}
func (gr grcron) IsActive() (bool, error) {
	cmd := exec.Command("sh", "-c", "ps cax | grep -q keepalived")
	err := cmd.Run()

	// 異常終了はkeepalivedプロセスがいないとみなす
	if _, ok := err.(*exec.ExitError); ok {
		return false, fmt.Errorf("keepalived is probably down")
	}

	return gr.CurrentState == "active", nil
}

func main() {
	var (
		showVersion bool
		dryRun      bool
	)

	gr := &grcron{}
	flag.StringVar(&gr.StateFile, "f", "/var/lib/grcron/state", "grcron state file.")
	flag.StringVar(&gr.DefaultState, "s", "passive", "grcron default state.")
	flag.BoolVar(&showVersion, "version", false, "show version number.")
	flag.BoolVar(&showVersion, "v", false, "show version number.")
	flag.BoolVar(&dryRun, "dryrun", false, "dry-run.")
	flag.BoolVar(&dryRun, "n", false, "dry-run.")
	flag.Parse()
	args := flag.Args()

	if showVersion {
		fmt.Printf("grcron %s, %s built for %s/%s\n", version, runtime.Version(), runtime.GOOS, runtime.GOARCH)
		return
	}

	if err := gr.Validate(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	if err := gr.ParseState(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	if len(args) < 1 {
		fmt.Fprintln(os.Stderr, "not enough arguments")
		os.Exit(1)
	}

	isa, err := gr.IsActive()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	if dryRun {
		fmt.Printf("dry-run gr.CurrentState:%s, gr.IsActive:%v finished.\n", gr.CurrentState, isa)
		return
	}

	if !isa {
		return
	}

	// run !!
	binary, err := exec.LookPath(args[0])
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	if err := syscall.Exec(binary, args, os.Environ()); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
<commit_msg>refactoring<commit_after>/* grcron
 *
 * Copyright (c) 2017 Motoaki Nishikawa
 * Distributed under MIT license, see LICENSE file.
 */

package main

import (
	"bufio"
	"flag"
	"fmt"
	"os"
	"os/exec"
	"runtime"
)

const version string = "0.0.4"

type grcron struct {
	StateFile    string
	DefaultState string
	CurrentState string
}

func newGrcron(defaultState string, stateFile string) (*grcron, error) {
	if !(defaultState == "active" || defaultState == "passive") {
		return nil, fmt.Errorf("The Value of DefaultState:%s is incorrect", defaultState)
	}

	f, err := os.Open(stateFile)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	var curr string
	sc := bufio.NewScanner(f)
	sc.Scan()
	st := sc.Text()
	switch st {
	case "active", "passive":
		curr = st
	default:
		fmt.Fprintf(os.Stderr, "corrupted state file('%s') (content='%s'), staying at gr.DefaultState('%s')\n", stateFile, st, defaultState)
		curr = defaultState
	}

	return &grcron{
		DefaultState: defaultState,
		StateFile:    stateFile,
		CurrentState: curr,
	}, nil
}

var testKeepalivedActive func() (bool, error)

func (gr grcron) keepalivedActive() (bool, error) {
	if testKeepalivedActive != nil {
		return testKeepalivedActive()
	}
	cmd := exec.Command("sh", "-c", "ps cax | grep -q keepalived")
	err := cmd.Run()
	// 異常終了はkeepalivedプロセスがいないとみなす
	if _, ok := err.(*exec.ExitError); ok {
		return false, fmt.Errorf("keepalived is probably down")
	}
	return true, nil
}

func (gr grcron) canRun() (bool, error) {
	ka, err := gr.keepalivedActive()
	if err != nil {
		return false, err
	}
	return gr.CurrentState == "active" && ka, nil
}

func main() {
	var (
		showVersion  bool
		dryRun       bool
		stateFile    string
		defaultState string
	)

	flag.StringVar(&stateFile, "f", "/var/lib/grcron/state", "grcron state file.")
	flag.StringVar(&defaultState, "s", "passive", "grcron default state.")
	flag.BoolVar(&showVersion, "version", false, "show version number.")
	flag.BoolVar(&showVersion, "v", false, "show version number.")
	flag.BoolVar(&dryRun, "dryrun", false, "dry-run.")
	flag.BoolVar(&dryRun, "n", false, "dry-run.")
	flag.Parse()
	args := flag.Args()

	if showVersion {
		fmt.Printf("grcron %s, %s built for %s/%s\n", version, runtime.Version(), runtime.GOOS, runtime.GOARCH)
		return
	}

	gr, err := newGrcron(defaultState, stateFile)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	if len(args) < 1 {
		fmt.Fprintln(os.Stderr, "not enough arguments")
		os.Exit(1)
	}

	canrun, err := gr.canRun()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	if dryRun {
		fmt.Printf("dry-run gr.CurrentState:%s, gr.IsActive:%v finished.\n", gr.CurrentState, canrun)
		return
	}

	if !canrun {
		return
	}

	cmd := exec.Command(args[0])
	for _, arg := range args[1:] {
		cmd.Args = append(cmd.Args, arg)
	}

	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	err = cmd.Run()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
<|endoftext|>