<commit_before>// Copyright 2019 The Gitea Authors.
// All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package pull

import (
	"context"
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strings"

	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/modules/git"
	"code.gitea.io/gitea/modules/graceful"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/notification"
	"code.gitea.io/gitea/modules/queue"
	"code.gitea.io/gitea/modules/timeutil"

	"github.com/unknwon/com"
)

// prQueue represents a queue to handle update pull request tests
var prQueue queue.UniqueQueue

// AddToTaskQueue adds itself to pull request test task queue.
func AddToTaskQueue(pr *models.PullRequest) {
	go func() {
		err := prQueue.PushFunc(strconv.FormatInt(pr.ID, 10), func() error {
			pr.Status = models.PullRequestStatusChecking
			err := pr.UpdateColsIfNotMerged("status")
			if err != nil {
				log.Error("AddToTaskQueue.UpdateCols[%d].(add to queue): %v", pr.ID, err)
			} else {
				log.Trace("Adding PR ID: %d to the test pull requests queue", pr.ID)
			}
			return err
		})
		if err != nil && err != queue.ErrAlreadyInQueue {
			log.Error("Error adding prID %d to the test pull requests queue: %v", pr.ID, err)
		}
	}()
}

// checkAndUpdateStatus checks if pull request is possible to leaving checking status,
// and set to be either conflict or mergeable.
func checkAndUpdateStatus(pr *models.PullRequest) {
	// Status is not changed to conflict means mergeable.
	if pr.Status == models.PullRequestStatusChecking {
		pr.Status = models.PullRequestStatusMergeable
	}

	// Make sure there is no waiting test to process before leaving the checking status.
	has, err := prQueue.Has(strconv.FormatInt(pr.ID, 10))
	if err != nil {
		log.Error("Unable to check if the queue is waiting to reprocess pr.ID %d. Error: %v", pr.ID, err)
	}

	if !has {
		if err := pr.UpdateCols("status, conflicted_files"); err != nil {
			log.Error("Update[%d]: %v", pr.ID, err)
		}
	}
}

// getMergeCommit checks if a pull request got merged
// Returns the git.Commit of the pull request if merged
func getMergeCommit(pr *models.PullRequest) (*git.Commit, error) {
	if pr.BaseRepo == nil {
		var err error
		pr.BaseRepo, err = models.GetRepositoryByID(pr.BaseRepoID)
		if err != nil {
			return nil, fmt.Errorf("GetRepositoryByID: %v", err)
		}
	}

	indexTmpPath, err := ioutil.TempDir(os.TempDir(), "gitea-"+pr.BaseRepo.Name)
	if err != nil {
		return nil, fmt.Errorf("Failed to create temp dir for repository %s: %v", pr.BaseRepo.RepoPath(), err)
	}
	defer os.RemoveAll(indexTmpPath)

	headFile := pr.GetGitRefName()

	// Check if a pull request is merged into BaseBranch
	_, err = git.NewCommand("merge-base", "--is-ancestor", headFile, pr.BaseBranch).
		RunInDirWithEnv(pr.BaseRepo.RepoPath(), []string{"GIT_INDEX_FILE=" + indexTmpPath, "GIT_DIR=" + pr.BaseRepo.RepoPath()})
	if err != nil {
		// Errors are signaled by a non-zero status that is not 1
		if strings.Contains(err.Error(), "exit status 1") {
			return nil, nil
		}
		return nil, fmt.Errorf("git merge-base --is-ancestor: %v", err)
	}

	commitIDBytes, err := ioutil.ReadFile(pr.BaseRepo.RepoPath() + "/" + headFile)
	if err != nil {
		return nil, fmt.Errorf("ReadFile(%s): %v", headFile, err)
	}
	commitID := string(commitIDBytes)
	if len(commitID) < 40 {
		return nil, fmt.Errorf(`ReadFile(%s): invalid commit-ID "%s"`, headFile, commitID)
	}
	cmd := commitID[:40] + ".." + pr.BaseBranch

	// Get the commit from BaseBranch where the pull request got merged
	mergeCommit, err := git.NewCommand("rev-list", "--ancestry-path", "--merges", "--reverse", cmd).
		RunInDirWithEnv("", []string{"GIT_INDEX_FILE=" + indexTmpPath, "GIT_DIR=" + pr.BaseRepo.RepoPath()})
	if err != nil {
		return nil, fmt.Errorf("git rev-list --ancestry-path --merges --reverse: %v", err)
	} else if len(mergeCommit) < 40 {
		// PR was fast-forwarded, so just use last commit of PR
		mergeCommit = commitID[:40]
	}

	gitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath())
	if err != nil {
		return nil, fmt.Errorf("OpenRepository: %v", err)
	}
	defer gitRepo.Close()

	commit, err := gitRepo.GetCommit(mergeCommit[:40])
	if err != nil {
		return nil, fmt.Errorf("GetCommit: %v", err)
	}

	return commit, nil
}

// manuallyMerged checks if a pull request got manually merged
// When a pull request got manually merged mark the pull request as merged
func manuallyMerged(pr *models.PullRequest) bool {
	commit, err := getMergeCommit(pr)
	if err != nil {
		log.Error("PullRequest[%d].getMergeCommit: %v", pr.ID, err)
		return false
	}
	if commit != nil {
		pr.MergedCommitID = commit.ID.String()
		pr.MergedUnix = timeutil.TimeStamp(commit.Author.When.Unix())
		pr.Status = models.PullRequestStatusManuallyMerged
		merger, _ := models.GetUserByEmail(commit.Author.Email)

		// When the commit author is unknown set the BaseRepo owner as merger
		if merger == nil {
			if pr.BaseRepo.Owner == nil {
				if err = pr.BaseRepo.GetOwner(); err != nil {
					log.Error("BaseRepo.GetOwner[%d]: %v", pr.ID, err)
					return false
				}
			}
			merger = pr.BaseRepo.Owner
		}
		pr.Merger = merger
		pr.MergerID = merger.ID

		if merged, err := pr.SetMerged(); err != nil {
			log.Error("PullRequest[%d].setMerged : %v", pr.ID, err)
			return false
		} else if !merged {
			return false
		}

		notification.NotifyMergePullRequest(pr, merger)

		log.Info("manuallyMerged[%d]: Marked as manually merged into %s/%s by commit id: %s", pr.ID, pr.BaseRepo.Name, pr.BaseBranch, commit.ID.String())
		return true
	}
	return false
}

// InitializePullRequests checks and tests untested patches of pull requests.
func InitializePullRequests(ctx context.Context) {
	prs, err := models.GetPullRequestIDsByCheckStatus(models.PullRequestStatusChecking)
	if err != nil {
		log.Error("Find Checking PRs: %v", err)
		return
	}
	for _, prID := range prs {
		select {
		case <-ctx.Done():
			return
		default:
			if err := prQueue.PushFunc(strconv.FormatInt(prID, 10), func() error {
				log.Trace("Adding PR ID: %d to the pull requests patch checking queue", prID)
				return nil
			}); err != nil {
				log.Error("Error adding prID: %s to the pull requests patch checking queue %v", prID, err)
			}
		}
	}
}

// handle passed PR IDs and test the PRs
func handle(data ...queue.Data) {
	for _, datum := range data {
		prID := datum.(string)
		id := com.StrTo(prID).MustInt64()

		log.Trace("Testing PR ID %d from the pull requests patch checking queue", id)

		pr, err := models.GetPullRequestByID(id)
		if err != nil {
			log.Error("GetPullRequestByID[%s]: %v", prID, err)
			continue
		} else if pr.HasMerged {
			continue
		} else if manuallyMerged(pr) {
			continue
		} else if err = TestPatch(pr); err != nil {
			log.Error("testPatch[%d]: %v", pr.ID, err)
			pr.Status = models.PullRequestStatusError
			if err := pr.UpdateCols("status"); err != nil {
				log.Error("update pr [%d] status to PullRequestStatusError failed: %v", pr.ID, err)
			}
			continue
		}
		checkAndUpdateStatus(pr)
	}
}

// Init runs the task queue to test all the checking status pull requests
func Init() error {
	prQueue = queue.CreateUniqueQueue("pr_patch_checker", handle, "").(queue.UniqueQueue)

	if prQueue == nil {
		return fmt.Errorf("Unable to create pr_patch_checker Queue")
	}

	go graceful.GetManager().RunWithShutdownFns(prQueue.Run)
	go graceful.GetManager().RunWithShutdownContext(InitializePullRequests)
	return nil
}
<commit_msg>Update mergebase in pr checker (#10586)<commit_after>// Copyright 2019 The Gitea Authors.
// All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package pull

import (
	"context"
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strings"

	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/modules/git"
	"code.gitea.io/gitea/modules/graceful"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/notification"
	"code.gitea.io/gitea/modules/queue"
	"code.gitea.io/gitea/modules/timeutil"

	"github.com/unknwon/com"
)

// prQueue represents a queue to handle update pull request tests
var prQueue queue.UniqueQueue

// AddToTaskQueue adds itself to pull request test task queue.
func AddToTaskQueue(pr *models.PullRequest) {
	go func() {
		err := prQueue.PushFunc(strconv.FormatInt(pr.ID, 10), func() error {
			pr.Status = models.PullRequestStatusChecking
			err := pr.UpdateColsIfNotMerged("status")
			if err != nil {
				log.Error("AddToTaskQueue.UpdateCols[%d].(add to queue): %v", pr.ID, err)
			} else {
				log.Trace("Adding PR ID: %d to the test pull requests queue", pr.ID)
			}
			return err
		})
		if err != nil && err != queue.ErrAlreadyInQueue {
			log.Error("Error adding prID %d to the test pull requests queue: %v", pr.ID, err)
		}
	}()
}

// checkAndUpdateStatus checks if pull request is possible to leaving checking status,
// and set to be either conflict or mergeable.
func checkAndUpdateStatus(pr *models.PullRequest) {
	// Status is not changed to conflict means mergeable.
	if pr.Status == models.PullRequestStatusChecking {
		pr.Status = models.PullRequestStatusMergeable
	}

	// Make sure there is no waiting test to process before leaving the checking status.
	has, err := prQueue.Has(strconv.FormatInt(pr.ID, 10))
	if err != nil {
		log.Error("Unable to check if the queue is waiting to reprocess pr.ID %d. Error: %v", pr.ID, err)
	}

	if !has {
		if err := pr.UpdateCols("merge_base", "status", "conflicted_files"); err != nil {
			log.Error("Update[%d]: %v", pr.ID, err)
		}
	}
}

// getMergeCommit checks if a pull request got merged
// Returns the git.Commit of the pull request if merged
func getMergeCommit(pr *models.PullRequest) (*git.Commit, error) {
	if pr.BaseRepo == nil {
		var err error
		pr.BaseRepo, err = models.GetRepositoryByID(pr.BaseRepoID)
		if err != nil {
			return nil, fmt.Errorf("GetRepositoryByID: %v", err)
		}
	}

	indexTmpPath, err := ioutil.TempDir(os.TempDir(), "gitea-"+pr.BaseRepo.Name)
	if err != nil {
		return nil, fmt.Errorf("Failed to create temp dir for repository %s: %v", pr.BaseRepo.RepoPath(), err)
	}
	defer os.RemoveAll(indexTmpPath)

	headFile := pr.GetGitRefName()

	// Check if a pull request is merged into BaseBranch
	_, err = git.NewCommand("merge-base", "--is-ancestor", headFile, pr.BaseBranch).
		RunInDirWithEnv(pr.BaseRepo.RepoPath(), []string{"GIT_INDEX_FILE=" + indexTmpPath, "GIT_DIR=" + pr.BaseRepo.RepoPath()})
	if err != nil {
		// Errors are signaled by a non-zero status that is not 1
		if strings.Contains(err.Error(), "exit status 1") {
			return nil, nil
		}
		return nil, fmt.Errorf("git merge-base --is-ancestor: %v", err)
	}

	commitIDBytes, err := ioutil.ReadFile(pr.BaseRepo.RepoPath() + "/" + headFile)
	if err != nil {
		return nil, fmt.Errorf("ReadFile(%s): %v", headFile, err)
	}
	commitID := string(commitIDBytes)
	if len(commitID) < 40 {
		return nil, fmt.Errorf(`ReadFile(%s): invalid commit-ID "%s"`, headFile, commitID)
	}
	cmd := commitID[:40] + ".." + pr.BaseBranch

	// Get the commit from BaseBranch where the pull request got merged
	mergeCommit, err := git.NewCommand("rev-list", "--ancestry-path", "--merges", "--reverse", cmd).
		RunInDirWithEnv("", []string{"GIT_INDEX_FILE=" + indexTmpPath, "GIT_DIR=" + pr.BaseRepo.RepoPath()})
	if err != nil {
		return nil, fmt.Errorf("git rev-list --ancestry-path --merges --reverse: %v", err)
	} else if len(mergeCommit) < 40 {
		// PR was fast-forwarded, so just use last commit of PR
		mergeCommit = commitID[:40]
	}

	gitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath())
	if err != nil {
		return nil, fmt.Errorf("OpenRepository: %v", err)
	}
	defer gitRepo.Close()

	commit, err := gitRepo.GetCommit(mergeCommit[:40])
	if err != nil {
		return nil, fmt.Errorf("GetCommit: %v", err)
	}

	return commit, nil
}

// manuallyMerged checks if a pull request got manually merged
// When a pull request got manually merged mark the pull request as merged
func manuallyMerged(pr *models.PullRequest) bool {
	commit, err := getMergeCommit(pr)
	if err != nil {
		log.Error("PullRequest[%d].getMergeCommit: %v", pr.ID, err)
		return false
	}
	if commit != nil {
		pr.MergedCommitID = commit.ID.String()
		pr.MergedUnix = timeutil.TimeStamp(commit.Author.When.Unix())
		pr.Status = models.PullRequestStatusManuallyMerged
		merger, _ := models.GetUserByEmail(commit.Author.Email)

		// When the commit author is unknown set the BaseRepo owner as merger
		if merger == nil {
			if pr.BaseRepo.Owner == nil {
				if err = pr.BaseRepo.GetOwner(); err != nil {
					log.Error("BaseRepo.GetOwner[%d]: %v", pr.ID, err)
					return false
				}
			}
			merger = pr.BaseRepo.Owner
		}
		pr.Merger = merger
		pr.MergerID = merger.ID

		if merged, err := pr.SetMerged(); err != nil {
			log.Error("PullRequest[%d].setMerged : %v", pr.ID, err)
			return false
		} else if !merged {
			return false
		}

		notification.NotifyMergePullRequest(pr, merger)

		log.Info("manuallyMerged[%d]: Marked as manually merged into %s/%s by commit id: %s", pr.ID, pr.BaseRepo.Name, pr.BaseBranch, commit.ID.String())
		return true
	}
	return false
}

// InitializePullRequests checks and tests untested patches of pull requests.
func InitializePullRequests(ctx context.Context) {
	prs, err := models.GetPullRequestIDsByCheckStatus(models.PullRequestStatusChecking)
	if err != nil {
		log.Error("Find Checking PRs: %v", err)
		return
	}
	for _, prID := range prs {
		select {
		case <-ctx.Done():
			return
		default:
			if err := prQueue.PushFunc(strconv.FormatInt(prID, 10), func() error {
				log.Trace("Adding PR ID: %d to the pull requests patch checking queue", prID)
				return nil
			}); err != nil {
				log.Error("Error adding prID: %s to the pull requests patch checking queue %v", prID, err)
			}
		}
	}
}

// handle passed PR IDs and test the PRs
func handle(data ...queue.Data) {
	for _, datum := range data {
		prID := datum.(string)
		id := com.StrTo(prID).MustInt64()

		log.Trace("Testing PR ID %d from the pull requests patch checking queue", id)

		pr, err := models.GetPullRequestByID(id)
		if err != nil {
			log.Error("GetPullRequestByID[%s]: %v", prID, err)
			continue
		} else if pr.HasMerged {
			continue
		} else if manuallyMerged(pr) {
			continue
		} else if err = TestPatch(pr); err != nil {
			log.Error("testPatch[%d]: %v", pr.ID, err)
			pr.Status = models.PullRequestStatusError
			if err := pr.UpdateCols("status"); err != nil {
				log.Error("update pr [%d] status to PullRequestStatusError failed: %v", pr.ID, err)
			}
			continue
		}
		checkAndUpdateStatus(pr)
	}
}

// Init runs the task queue to test all the checking status pull requests
func Init() error {
	prQueue = queue.CreateUniqueQueue("pr_patch_checker", handle, "").(queue.UniqueQueue)

	if prQueue == nil {
		return fmt.Errorf("Unable to create pr_patch_checker Queue")
	}

	go graceful.GetManager().RunWithShutdownFns(prQueue.Run)
	go graceful.GetManager().RunWithShutdownContext(InitializePullRequests)
	return nil
}
<|endoftext|>


<commit_before>package main

// This is a basic example to illustrate how to access the Fidor API
// using Go.
//
// To run this example type:
//
//     $ go run example.go
//
// And point your browser to:
//
//     $ http://localhost:8080

import (
	"crypto/rand"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
)

// The following sections define the settings you require for the
// app to be able to connect to and authorize itself against the api.

type Config struct {
	AppUrl        string // where to reach this application
	ClientId      string // OAuth Client_id parameter
	ClientSecret  string // OAuth Client_secret parameter
	FidorApiUrl   string // API endpoint (this changes between Sandbox and Production)
	FidorOauthUrl string // OAuth endpoint (this changes between Sandbox and Production)
}

const fidorConfig = Config{
	AppUrl:        "<APP_URL>",
	ClientId:      "<CLIENT_ID>",
	ClientSecret:  "<CLIENT_SECRET>",
	FidorApiUrl:   "<FIDOR_API_URL>",
	FidorOauthUrl: "<FIDOR_OAUTH_URL>",
}

func main() {
	// register a handler function (see next function) to service
	// requests ...
	http.HandleFunc("/", indexHandler)
	fmt.Printf("Now open %s\n", fidorConfig.AppUrl)
	// ... and start listening.
	if u, err := url.Parse(fidorConfig.AppUrl); err != nil {
		fmt.Printf("Can't make sense of configured url: %s\nBye.\n", fidorConfig.AppUrl)
	} else {
		var hostPort = strings.Split(u.Host, ":")
		var port = ":8080"
		if len(hostPort) == 2 {
			port = ":" + hostPort[1]
		}
		http.ListenAndServe(port, nil)
	}
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		w.WriteHeader(403)
		return
	}

	switch r.URL.Path {
	case "/":
		renderWelcome(w)
	case "/transactions":
		render("/transactions", w, r)
	case "/accounts":
		render("/accounts", w, r)
	case "/oauth":
		handleOAuthCallback(w, r)
	default:
		w.WriteHeader(404)
	}
}

const COOKIE_NAME = "GO_SESSION"

var sessions = make(map[string]string)

func createSession(w http.ResponseWriter, accessToken string) {
	println(accessToken)
	rnd := make([]byte, 20, 20)
	rand.Read(rnd)
	session := hex.EncodeToString(rnd)
	sessions[session] = accessToken
	cookie := http.Cookie{
		Name:  COOKIE_NAME,
		Value: session,
	}
	http.SetCookie(w, &cookie)
}

func render(endpoint string, w http.ResponseWriter, r *http.Request) {
	// check if request has cookie set
	if cookie, err := r.Cookie(COOKIE_NAME); err != nil {
		// else redirect to OAuth Authorization EP
		redirectToOAuth(w, r, endpoint)
		return
	} else {
		session := cookie.Value
		accessToken := sessions[session]

		// pipe api endpoint
		ep := fmt.Sprintf("%s/%s", fidorConfig.FidorApiUrl, endpoint)
		if api_req, err := http.NewRequest("GET", ep, nil); err != nil {
			w.WriteHeader(500)
			w.Write([]byte(err.Error()))
			return
		} else {
			api_req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken))

			client := &http.Client{}
			if api_resp, err := client.Do(api_req); err != nil {
				w.WriteHeader(500)
				w.Write([]byte(err.Error()))
				return
			} else {

				contentType := http.CanonicalHeaderKey("content-type")
				w.Header().Set(contentType, api_resp.Header.Get(contentType))
				w.WriteHeader(api_resp.StatusCode)
				io.Copy(w, api_resp.Body)
			}
		}
	}
}

func redirectToOAuth(w http.ResponseWriter, r *http.Request, target_endpoint string) {
	_redirectURI := fmt.Sprintf("%s/oauth?ep=%s", fidorConfig.AppUrl, target_endpoint)
	redirectURI := url.QueryEscape(_redirectURI)

	oauthRedirectURL := fmt.Sprintf("%s/authorize?client_id=%s&state=321&response_type=code&redirect_uri=%s", fidorConfig.FidorOauthUrl, fidorConfig.ClientId, redirectURI)
	http.Redirect(w, r, oauthRedirectURL, 307)
}

func handleOAuthCallback(w http.ResponseWriter, r *http.Request) {
	code := r.FormValue("code")
	target := r.FormValue("ep")

	if code == "" || target == "" {
		w.WriteHeader(500)
		w.Write([]byte("missing code or target ep"))
		return
	}

	if token, err := retrieveTokenFromCode(code, target); err != nil {
		w.WriteHeader(500)
		w.Write([]byte(err.Error()))
		return
	} else {
		createSession(w, token)
		http.Redirect(w, r, target, 307)

	}

}

//	// check whether we have a GET parameter named `code`, if so,
//	// this is a redirect back from the Fidor OAuth server.
//	values := r.URL.Query()
//	if values["code"] != nil {
//		// retrieve the actual OAuth access token ....
//		code := values.Get("code")
//		if token, err := retrieveTokenFromCode(code); err != nil {
//			fmt.Printf("err: %v\n", err)
//			w.WriteHeader(500)
//			fmt.Fprintf(w, "Unfortunately, an error occurred retrieving oauth token")
//		} else {
//			// ... and finally, greet the user and assemble links
//			renderWelcome(w, token)
//		}
//	} else {
//		// we don't have an oauth `code` yet, so we need to
//		// redirect the user to the OAuth provider to get one ...
//		oauth_url := fmt.Sprintf("%s/authorize?client_id=%s&state=123&response_type=code&redirect_uri=%s",
//			fidor_oauth_url,
//			client_id,
//			url.QueryEscape(oauth_cb_url))
//
//		header := w.Header()
//		header.Add("location", oauth_url)
//		w.WriteHeader(307)
//	}
//}

// Our TokenResponse representation used to pick it out from the JSON
// returned by the OAuth server.
type TokenResponse struct {
	Token string `json:"access_token"`
}

// Use the OAuth code that the user's browser picked up from the OAuth
// server to request an OAuth access_token to use in API requests.
func retrieveTokenFromCode(code string, target_endpoint string) (token string, err error) {
	// assemble the API endpoint URL and request payload
	redirect_uri := fmt.Sprintf("%s/oauth?ep=%s", fidorConfig.AppUrl, target_endpoint)
	tokenPayload := url.Values{
		"client_id":     {fidorConfig.ClientId},
		"client_secret": {fidorConfig.ClientSecret},
		"code":          {code},
		"redirect_uri":  {url.QueryEscape(redirect_uri)},
		"grant_type":    {"authorization_code"},
	}
	// Call API
	tokenUrl := fmt.Sprintf("%s/token", fidorConfig.FidorOauthUrl)
	if resp, err := http.PostForm(tokenUrl, tokenPayload); err != nil {
		println(err)
		return "", err
	} else {
		if resp.StatusCode != 200 {
			return "", errors.New(resp.Status)
		}
		// if successful, pick the access_token out of the reply.
		var tokenResponse TokenResponse
		decoder := json.NewDecoder(resp.Body)
		if err = decoder.Decode(&tokenResponse); err != nil {
			return "", err
		} else {
			return tokenResponse.Token, nil
		}
	}
}

func renderWelcome(w http.ResponseWriter) {
	w.Write([]byte(indexTemplate))
}

var indexTemplate = `

Welcome!

Transactions

Accounts

`
<commit_msg>API-649 handle logout, cleanup, comment code<commit_after>package main

// This is a basic example to illustrate how to access the Fidor API
// using Go.
//
// To run this example type:
//
//     $ go run example.go
//
// And point your browser to:
//
//     $ http://localhost:8080

import (
	"crypto/rand"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
)

// The following sections define the settings you require for the
// app to be able to connect to and authorize itself against the api.

type Config struct {
	AppUrl        string // where to reach this application
	ClientId      string // OAuth Client_id parameter
	ClientSecret  string // OAuth Client_secret parameter
	FidorApiUrl   string // API endpoint (this changes between Sandbox and Production)
	FidorOauthUrl string // OAuth endpoint (this changes between Sandbox and Production)
}

var fidorConfig = Config{
	AppUrl:        "<APP_URL>",
	ClientId:      "<CLIENT_ID>",
	ClientSecret:  "<CLIENT_SECRET>",
	FidorApiUrl:   "<FIDOR_API_URL>",
	FidorOauthUrl: "<FIDOR_OAUTH_URL>",
}

func main() {
	// register a handler function (see next function) to service
	// requests ...
	http.HandleFunc("/", indexHandler)
	fmt.Printf("Now open %s\n", fidorConfig.AppUrl)
	// ... and start listening.
	if u, err := url.Parse(fidorConfig.AppUrl); err != nil {
		fmt.Printf("Can't make sense of configured url: %s\nBye.\n", fidorConfig.AppUrl)
	} else {
		var hostPort = strings.Split(u.Host, ":")
		var port = ":8080"
		if len(hostPort) == 2 {
			port = ":" + hostPort[1]
		}
		http.ListenAndServe(port, nil)
	}
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		w.WriteHeader(403)
		return
	}

	switch r.URL.Path {
	case "/":
		renderWelcome(w)
	case "/transactions":
		render("/transactions", w, r)
	case "/accounts":
		render("/accounts", w, r)
	case "/oauth":
		handleOAuthCallback(w, r)
	case "/logout":
		handleLogout(w, r, "/")
	default:
		w.WriteHeader(404)
	}
}

const COOKIE_NAME = "GO_SESSION"

// session database, available access_tokens are mapped to their cookie-session keys
var sessions = make(map[string]string)

// stores a retireved access_token both on the server and the reference in a client-side cookie.
func createSession(w http.ResponseWriter, accessToken string) {
	println(accessToken)
	rnd := make([]byte, 20, 20)
	rand.Read(rnd)
	session := hex.EncodeToString(rnd)
	sessions[session] = accessToken
	cookie := http.Cookie{
		Name:  COOKIE_NAME,
		Value: session,
	}
	http.SetCookie(w, &cookie)
}

// proxies an API endpoint. In case the client is not logged in (i.e. no
// session cookie is set), the OAuth procedure is initiated. Once the
// client is logged, a call the the `endpoint` API endpoint is made and
// the results (including errors) are piped to the client.
func render(endpoint string, w http.ResponseWriter, r *http.Request) {
	// check if request has cookie set
	if cookie, err := r.Cookie(COOKIE_NAME); err != nil {
		// else redirect to OAuth Authorization EP
		redirectToOAuth(w, r, endpoint)
	} else {
		session := cookie.Value
		accessToken := sessions[session]

		// pipe api endpoint
		ep := fmt.Sprintf("%s/%s", fidorConfig.FidorApiUrl, endpoint)
		if api_req, err := http.NewRequest("GET", ep, nil); err != nil {
			w.WriteHeader(500)
			w.Write([]byte(err.Error()))
		} else {
			api_req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken))

			client := &http.Client{}
			if api_resp, err := client.Do(api_req); err != nil {
				w.WriteHeader(500)
				w.Write([]byte(err.Error()))
			} else {
				if api_resp.StatusCode == 400 { // token probably expired
					handleLogout(w, r, endpoint)
					return
				}
				contentType := http.CanonicalHeaderKey("content-type")
				w.Header().Set(contentType, api_resp.Header.Get(contentType))
				w.WriteHeader(api_resp.StatusCode)
				io.Copy(w, api_resp.Body)
			}
		}
	}
}

// client browser is redirected to `authorize` oauth endpoints. The
// `target_endpoint` parameter indicates which application endpoint to
// redirect the client to once the access_token has been retrieved.
func redirectToOAuth(w http.ResponseWriter, r *http.Request, target_endpoint string) {
	_redirectURI := fmt.Sprintf("%s/oauth?ep=%s", fidorConfig.AppUrl, target_endpoint)
	redirectURI := url.QueryEscape(_redirectURI)

	oauthRedirectURL := fmt.Sprintf("%s/authorize?client_id=%s&state=321&response_type=code&redirect_uri=%s", fidorConfig.FidorOauthUrl, fidorConfig.ClientId, redirectURI)
	http.Redirect(w, r, oauthRedirectURL, 307)
}

// handles the oauth callback (i.e. the redirect that the oauth
// authorize call "returns" to the client)
func handleOAuthCallback(w http.ResponseWriter, r *http.Request) {
	code := r.FormValue("code")
	target := r.FormValue("ep")

	if code == "" || target == "" {
		w.WriteHeader(500)
		w.Write([]byte("missing code or target ep"))
		return
	}

	if token, err := retrieveTokenFromCode(code, target); err != nil {
		w.WriteHeader(500)
		w.Write([]byte(err.Error()))
		return
	} else {
		createSession(w, token)
		http.Redirect(w, r, target, 307)
	}
}

// clear our application's session, forces user to call the oauth
// authorize endpoint again. This may or may not force the user to have
// to reenter credentials, depending on whether the user's Fidor session
// has expired.
func handleLogout(w http.ResponseWriter, r *http.Request, endpoint string) {
	if cookie, err := r.Cookie(COOKIE_NAME); err == nil {
		// we have a cookie

		// remove it from our stored sessions
		session := cookie.Value
		delete(sessions, session)

		// kill the cookie on the client
		cookie := http.Cookie{
			Name:   COOKIE_NAME,
			Value:  "",
			MaxAge: -1,
		}
		http.SetCookie(w, &cookie)
	}
	http.Redirect(w, r, endpoint, 307)
}

// Our TokenResponse representation used to pick it out from the JSON
// returned by the OAuth server.
type TokenResponse struct {
	Token string `json:"access_token"`
}

// Use the OAuth code that the user's browser picked up from the OAuth
// server to request an OAuth access_token to use in API requests. The
// `target_endpoint` parameter indicates which of this app's endpoints
// to redirect the client to once we have the access_token and stored a
// reference in the client's cookie.
func retrieveTokenFromCode(code string, target_endpoint string) (token string, err error) {
	// assemble the API endpoint URL and request payload
	redirect_uri := fmt.Sprintf("%s/oauth?ep=%s", fidorConfig.AppUrl, target_endpoint)
	tokenPayload := url.Values{
		"client_id":     {fidorConfig.ClientId},
		"client_secret": {fidorConfig.ClientSecret},
		"code":          {code},
		"redirect_uri":  {url.QueryEscape(redirect_uri)},
		"grant_type":    {"authorization_code"},
	}
	// Call the Oauth `token` endpoint
	tokenUrl := fmt.Sprintf("%s/token", fidorConfig.FidorOauthUrl)
	if resp, err := http.PostForm(tokenUrl, tokenPayload); err != nil {
		println(err)
		return "", err
	} else {
		if resp.StatusCode != 200 {
			return "", errors.New(resp.Status)
		}
		// if successful, pick the access_token out of the reply.
		var tokenResponse TokenResponse
		decoder := json.NewDecoder(resp.Body)
		if err = decoder.Decode(&tokenResponse); err != nil {
			return "", err
		} else {
			return tokenResponse.Token, nil
		}
	}
}

func renderWelcome(w http.ResponseWriter) {
	w.Write([]byte(indexTemplate))
}

var indexTemplate = `

Welcome!

Transactions

Accounts

Log Out

`
<|endoftext|>


<commit_before>package design

import (
	. "github.com/goadesign/goa/design"
	. "github.com/goadesign/goa/design/apidsl"
)

var _ = API("goa simple sample", func() {
	// APIのタイトル
	Title("tikasan/goa-simple-sample")
	// APIの説明
	Description("goaのサンプルです")
	// 作成者へのコンタクト情報
	Contact(func() {
		Name("pei")
		Email("satak47cpc@gmail.com")
		URL("https://github.com/pei0804/goa-simple-sample/issues")
	})
	// APIのライセンス
	License(func() {
		Name("MIT")
		URL("https://github.com/tikasan/eventory/blob/master/LICENSE")
	})
	// APIのドキュメント
	Docs(func() {
		Description("wiki")
		URL("https://github.com/pei0804/goa-simple-sample/wiki")
	})
	// ホストの設定
	Host("localhost:8080")
	// 対応しているプロトコル定義、httpかhttpsまたはその両方
	Scheme("http", "https")
	// 全てのエンドポイントのベースパス
	// /usersというエンドポイントがあったら、/api/v1/usersとなる
	BasePath("/api/v1")

	//　CORSポリシーの定義
	Origin("http://localhost:8080/swagger", func() {
		//クライアントに公開された1つ以上のヘッダー
		Expose("X-Time")
		// 1つまたは複数の許可されたHTTPメソッド
		Methods("GET", "POST", "PUT", "DELETE")
		//プリフライト要求応答をキャッシュする時間
		MaxAge(600)
		// Access-Control-Allow-Credentialsヘッダーを設定する
		Credentials()
	})
})
<commit_msg>update<commit_after>package design

import (
	. "github.com/goadesign/goa/design"
	. "github.com/goadesign/goa/design/apidsl"
)

var _ = API("goa simple sample", func() {
	// APIのタイトル
	Title("pei0804/goa-simple-sample")
	// APIの説明
	Description("goaのサンプルです")
	// 作成者へのコンタクト情報
	Contact(func() {
		Name("pei")
		Email("peeeei0804@gmail.com")
		URL("https://github.com/pei0804/goa-simple-sample/issues")
	})
	// APIのライセンス
	License(func() {
		Name("MIT")
	})
	// APIのドキュメント
	Docs(func() {
		Description("wiki")
		URL("https://github.com/pei0804/goa-simple-sample/wiki")
	})
	// ホストの設定
	Host("localhost:8080")
	// 対応しているプロトコル定義、httpかhttpsまたはその両方
	Scheme("http", "https")
	// 全てのエンドポイントのベースパス
	// /usersというエンドポイントがあったら、/api/v1/usersとなる
	BasePath("/api/v1")

	//　CORSポリシーの定義
	Origin("http://localhost:8080/swagger", func() {
		//クライアントに公開された1つ以上のヘッダー
		Expose("X-Time")
		// 1つまたは複数の許可されたHTTPメソッド
		Methods("GET", "POST", "PUT", "DELETE")
		//プリフライト要求応答をキャッシュする時間
		MaxAge(600)
		// Access-Control-Allow-Credentialsヘッダーを設定する
		Credentials()
	})
})
<|endoftext|>


<commit_before>package sphinx

import (
	"bytes"
	"encoding/hex"
	"fmt"
	"log"
	"reflect"
	"testing"

	"github.com/davecgh/go-spew/spew"
	"github.com/roasbeef/btcd/btcec"
	"github.com/roasbeef/btcd/chaincfg"
)

func newTestRoute(numHops int) ([]*SphinxNode, *ForwardingMessage, error) {
	nodes := make([]*SphinxNode, numHops)

	// Create numMaxHops random sphinx nodes.
	for i := 0; i < len(nodes); i++ {
		privKey, err := btcec.NewPrivateKey(btcec.S256())
		if err != nil {
			return nil, nil, fmt.Errorf("Unable to generate random "+
				"key for sphinx node: %v", err)
		}

		nodes[i] = NewSphinxNode(privKey, &chaincfg.MainNetParams)
	}

	// Gather all the pub keys in the path.
	route := make([]*btcec.PublicKey, len(nodes))
	for i := 0; i < len(nodes); i++ {
		route[i] = nodes[i].lnKey.PubKey()
	}

	// Generate a forwarding message to route to the final node via the
	// generated intermdiates nodes above.  Destination should be Hash160,
	// adding padding so parsing still works.
	dest := append([]byte("roasbeef"), bytes.Repeat([]byte{0}, securityParameter-8)...)
	fwdMsg, err := NewForwardingMessage(route, dest, []byte("testing"))
	if err != nil {
		return nil, nil, fmt.Errorf("Unable to create forwarding "+
			"message: %#v", err)
	}

	return nodes, fwdMsg, nil
}

func TestSphinxCorrectness(t *testing.T) {
	dest := append([]byte("roasbeef"), bytes.Repeat([]byte{0}, securityParameter-8)...)
	nodes, fwdMsg, err := newTestRoute(numMaxHops)
	if err != nil {
		t.Fatalf("unable to create random onion packet: %v", err)
	}

	// Now simulate the message propagating through the mix net eventually
	// reaching the final destination.
	for i := 0; i < len(nodes); i++ {
		hop := nodes[i]

		log.Printf("Processing at hop: %v \n", i)
		processAction, err := hop.ProcessForwardingMessage(fwdMsg)
		if err != nil {
			t.Fatalf("Node %v was unabled to process the forwarding message: %v", i, err)
		}

		// If this is the last hop on the path, the node should
		// recognize that it's the exit node.
		if i == len(nodes)-1 {
			if processAction.Action != ExitNode {
				t.Fatalf("Processing error, node %v is the last hop in"+
					"the path, yet it doesn't recognize so", i)
			}

			// The original destination address and message should
			// now be fully decrypted.
			if !bytes.Equal(dest, processAction.DestAddr) {
				t.Fatalf("Destination address parsed incorrectly at final destination!"+
					" Should be %v, is instead %v",
					hex.EncodeToString(dest),
					hex.EncodeToString(processAction.DestAddr))
			}

			if !bytes.HasPrefix(processAction.DestMsg, []byte("testing")) {
				t.Fatalf("Final message parsed incorrectly at final destination!"+
					"Should be %v, is instead %v",
					[]byte("testing"), processAction.DestMsg)
			}

		} else {
			// If this isn't the last node in the path, then the returned
			// action should indicate that there are more hops to go.
			if processAction.Action != MoreHops {
				t.Fatalf("Processing error, node %v is not the final"+
					" hop, yet thinks it is.", i)
			}

			// The next hop should have been parsed as node[i+1].
			parsedNextHop := processAction.NextHop[:]
			if !bytes.Equal(parsedNextHop, nodes[i+1].nodeID[:]) {
				t.Fatalf("Processing error, next hop parsed incorrectly."+
					" next hop shoud be %v, was instead parsed as %v",
					hex.EncodeToString(nodes[i+1].nodeID[:]),
					hex.EncodeToString(parsedNextHop))
			}

			fwdMsg = processAction.FwdMsg
		}
	}
}
func TestSphinxNodeRelpay(t *testing.T) {
	// We'd like to ensure that the sphinx node itself rejects all replayed
	// packets which share the same shared secret.

	nodes, fwdMsg, err := newTestRoute(numMaxHops)
	if err != nil {
		t.Fatalf("unable to create test route: %v", err)
	}

	// Allow the node to process the initial packet, this should proceed
	// without any failures.
	if _, err := nodes[0].ProcessForwardingMessage(fwdMsg); err != nil {
		t.Fatalf("unable to process sphinx packet: %v", err)
	}

	// Now, force the node to process the packet a second time, this should
	// fail with a detected replay error.
	if _, err := nodes[0].ProcessForwardingMessage(fwdMsg); err != ErrReplayedPacket {
		t.Fatalf("sphinx packet replay should be rejected, instead error is %v", err)
	}
}

func TestSphinxEncodeDecode(t *testing.T) {
	// Create some test data with a randomly populated, yet valid onion
	// forwarding message.
	_, fwdMsg, err := newTestRoute(5)
	if err != nil {
		t.Fatalf("unable to create random onion packet: %v", err)
	}

	// Encode the created onion packet into an empty buffer. This should
	// succeeed without any errors.
	var b bytes.Buffer
	if err := fwdMsg.Encode(&b); err != nil {
		t.Fatalf("unable to encode message: %v", err)
	}

	// Now decode the bytes encoded above. Again, this should succeeed
	// without any errors.
	newFwdMsg := &ForwardingMessage{}
	if err := newFwdMsg.Decode(&b); err != nil {
		t.Fatalf("unable to decode message: %v", err)
	}

	// The two forwarding messages should now be identical.
	if !reflect.DeepEqual(fwdMsg, newFwdMsg) {
		t.Fatalf("forwarding messages don't match, %v vs %v",
			spew.Sdump(fwdMsg), spew.Sdump(newFwdMsg))
	}
}
<commit_msg>add tests a basic "single-hop" onion routed payment scenario<commit_after>package sphinx

import (
	"bytes"
	"encoding/hex"
	"fmt"
	"log"
	"reflect"
	"testing"

	"github.com/davecgh/go-spew/spew"
	"github.com/roasbeef/btcd/btcec"
	"github.com/roasbeef/btcd/chaincfg"
)

func newTestRoute(numHops int) ([]*SphinxNode, *ForwardingMessage, error) {
	nodes := make([]*SphinxNode, numHops)

	// Create numMaxHops random sphinx nodes.
	for i := 0; i < len(nodes); i++ {
		privKey, err := btcec.NewPrivateKey(btcec.S256())
		if err != nil {
			return nil, nil, fmt.Errorf("Unable to generate random "+
				"key for sphinx node: %v", err)
		}

		nodes[i] = NewSphinxNode(privKey, &chaincfg.MainNetParams)
	}

	// Gather all the pub keys in the path.
	route := make([]*btcec.PublicKey, len(nodes))
	for i := 0; i < len(nodes); i++ {
		route[i] = nodes[i].lnKey.PubKey()
	}

	// Generate a forwarding message to route to the final node via the
	// generated intermdiates nodes above.  Destination should be Hash160,
	// adding padding so parsing still works.
	dest := append([]byte("roasbeef"), bytes.Repeat([]byte{0}, securityParameter-8)...)
	fwdMsg, err := NewForwardingMessage(route, dest, []byte("testing"))
	if err != nil {
		return nil, nil, fmt.Errorf("Unable to create forwarding "+
			"message: %#v", err)
	}

	return nodes, fwdMsg, nil
}

func TestSphinxCorrectness(t *testing.T) {
	dest := append([]byte("roasbeef"), bytes.Repeat([]byte{0}, securityParameter-8)...)
	nodes, fwdMsg, err := newTestRoute(numMaxHops)
	if err != nil {
		t.Fatalf("unable to create random onion packet: %v", err)
	}

	// Now simulate the message propagating through the mix net eventually
	// reaching the final destination.
	for i := 0; i < len(nodes); i++ {
		hop := nodes[i]

		log.Printf("Processing at hop: %v \n", i)
		processAction, err := hop.ProcessForwardingMessage(fwdMsg)
		if err != nil {
			t.Fatalf("Node %v was unabled to process the forwarding message: %v", i, err)
		}

		// If this is the last hop on the path, the node should
		// recognize that it's the exit node.
		if i == len(nodes)-1 {
			if processAction.Action != ExitNode {
				t.Fatalf("Processing error, node %v is the last hop in"+
					"the path, yet it doesn't recognize so", i)
			}

			// The original destination address and message should
			// now be fully decrypted.
			if !bytes.Equal(dest, processAction.DestAddr) {
				t.Fatalf("Destination address parsed incorrectly at final destination!"+
					" Should be %v, is instead %v",
					hex.EncodeToString(dest),
					hex.EncodeToString(processAction.DestAddr))
			}

			if !bytes.HasPrefix(processAction.DestMsg, []byte("testing")) {
				t.Fatalf("Final message parsed incorrectly at final destination!"+
					"Should be %v, is instead %v",
					[]byte("testing"), processAction.DestMsg)
			}

		} else {
			// If this isn't the last node in the path, then the returned
			// action should indicate that there are more hops to go.
			if processAction.Action != MoreHops {
				t.Fatalf("Processing error, node %v is not the final"+
					" hop, yet thinks it is.", i)
			}

			// The next hop should have been parsed as node[i+1].
			parsedNextHop := processAction.NextHop[:]
			if !bytes.Equal(parsedNextHop, nodes[i+1].nodeID[:]) {
				t.Fatalf("Processing error, next hop parsed incorrectly."+
					" next hop shoud be %v, was instead parsed as %v",
					hex.EncodeToString(nodes[i+1].nodeID[:]),
					hex.EncodeToString(parsedNextHop))
			}

			fwdMsg = processAction.FwdMsg
		}
	}
}

func TestSphinxSingleHop(t *testing.T) {
	// We'd like to test the proper behavior of the correctness of onion
	// packet processing for "single-hop" payments which bare a full onion
	// packet.

	nodes, fwdMsg, err := newTestRoute(1)
	if err != nil {
		t.Fatalf("unable to create test route: %v", err)
	}

	// Simulating a direct single-hop payment, send the sphinx packet to
	// the destination node, making it process the packet fully.
	processedPacket, err := nodes[0].ProcessForwardingMessage(fwdMsg)
	if err != nil {
		t.Fatalf("unable to process sphinx packet: %v", err)
	}

	// The destination node should detect that the packet is destined for
	// itself.
	if processedPacket.Action != ExitNode {
		t.Fatalf("processed action is correct, is %v should be %v",
			processedPacket.Action, ExitNode)
	}
}

func TestSphinxNodeRelpay(t *testing.T) {
	// We'd like to ensure that the sphinx node itself rejects all replayed
	// packets which share the same shared secret.

	nodes, fwdMsg, err := newTestRoute(numMaxHops)
	if err != nil {
		t.Fatalf("unable to create test route: %v", err)
	}

	// Allow the node to process the initial packet, this should proceed
	// without any failures.
	if _, err := nodes[0].ProcessForwardingMessage(fwdMsg); err != nil {
		t.Fatalf("unable to process sphinx packet: %v", err)
	}

	// Now, force the node to process the packet a second time, this should
	// fail with a detected replay error.
	if _, err := nodes[0].ProcessForwardingMessage(fwdMsg); err != ErrReplayedPacket {
		t.Fatalf("sphinx packet replay should be rejected, instead error is %v", err)
	}
}

func TestSphinxEncodeDecode(t *testing.T) {
	// Create some test data with a randomly populated, yet valid onion
	// forwarding message.
	_, fwdMsg, err := newTestRoute(5)
	if err != nil {
		t.Fatalf("unable to create random onion packet: %v", err)
	}

	// Encode the created onion packet into an empty buffer. This should
	// succeeed without any errors.
	var b bytes.Buffer
	if err := fwdMsg.Encode(&b); err != nil {
		t.Fatalf("unable to encode message: %v", err)
	}

	// Now decode the bytes encoded above. Again, this should succeeed
	// without any errors.
	newFwdMsg := &ForwardingMessage{}
	if err := newFwdMsg.Decode(&b); err != nil {
		t.Fatalf("unable to decode message: %v", err)
	}

	// The two forwarding messages should now be identical.
	if !reflect.DeepEqual(fwdMsg, newFwdMsg) {
		t.Fatalf("forwarding messages don't match, %v vs %v",
			spew.Sdump(fwdMsg), spew.Sdump(newFwdMsg))
	}
}
<|endoftext|>


<commit_before><commit_msg>gofmt did for server_hardware resource<commit_after><|endoftext|>


<commit_before>package gherkin

import (
	"fmt"
	"github.com/cucumber/cucumber-messages-go"
	gio "github.com/gogo/protobuf/io"
	"io"
	"io/ioutil"
	"strings"
)

func GherkinMessages(paths []string, sourceStream io.Reader, language string, includeSource bool, includeGherkinDocument bool, includePickles bool) ([]messages.Wrapper, error) {
	var result []messages.Wrapper

	processSource := func(source *messages.Source) error {
		if includeSource {
			result = append(result, messages.Wrapper{
				Message: &messages.Wrapper_Source{
					Source: source,
				},
			})
		}

		doc, err := ParseGherkinDocumentForLanguage(strings.NewReader(source.Data), language)
		if errs, ok := err.(parseErrors); ok {
			// expected parse errors
			for _, err := range errs {
				if pe, ok := err.(*parseError); ok {
					result = append(result, pe.asAttachment(source.Uri))
				} else {
					return fmt.Errorf("parse feature file: %s, unexpected error: %+v\n", source.Uri, err)
				}
			}
			return nil
		}

		if includeGherkinDocument {
			doc.Uri = source.Uri
			result = append(result, messages.Wrapper{
				Message: &messages.Wrapper_GherkinDocument{
					GherkinDocument: doc,
				},
			})
		}

		if includePickles {
			for _, pickle := range Pickles(*doc, source.Uri) {
				result = append(result, messages.Wrapper{
					Message: &messages.Wrapper_Pickle{
						Pickle: pickle,
					},
				})
			}
		}
		return nil
	}

	if len(paths) == 0 {
		reader := gio.NewDelimitedReader(sourceStream, 2048)
		for {
			source := &messages.Source{}
			if err := reader.ReadMsg(source); err != nil {
				break
			}
			processSource(source)
		}
	} else {
		for _, path := range paths {
			in, err := ioutil.ReadFile(path)
			if err != nil {
				return result, fmt.Errorf("read feature file: %s - %+v", path, err)
			}
			source := &messages.Source{
				Uri:  path,
				Data: string(in),
				Media: &messages.Media{
					Encoding:    "UTF-8",
					ContentType: "text/x.cucumber.gherkin+plain",
				},
			}
			processSource(source)
		}
	}

	return result, nil
}

func (a *parseError) asAttachment(uri string) messages.Wrapper {
	return messages.Wrapper{
		Message: &messages.Wrapper_Attachment{
			Attachment: &messages.Attachment{
				Data: a.Error(),
				Source: &messages.SourceReference{
					Uri: uri,
					Location: &messages.Location{
						Line:   uint32(a.loc.Line),
						Column: uint32(a.loc.Column),
					},
				},
			}},
	}
}
<commit_msg>gherkin: go: Set max size to something big. Closes #449<commit_after>package gherkin

import (
	"fmt"
	"github.com/cucumber/cucumber-messages-go"
	gio "github.com/gogo/protobuf/io"
	"io"
	"io/ioutil"
	"math"
	"strings"
)

func GherkinMessages(paths []string, sourceStream io.Reader, language string, includeSource bool, includeGherkinDocument bool, includePickles bool) ([]messages.Wrapper, error) {
	var result []messages.Wrapper

	processSource := func(source *messages.Source) error {
		if includeSource {
			result = append(result, messages.Wrapper{
				Message: &messages.Wrapper_Source{
					Source: source,
				},
			})
		}

		doc, err := ParseGherkinDocumentForLanguage(strings.NewReader(source.Data), language)
		if errs, ok := err.(parseErrors); ok {
			// expected parse errors
			for _, err := range errs {
				if pe, ok := err.(*parseError); ok {
					result = append(result, pe.asAttachment(source.Uri))
				} else {
					return fmt.Errorf("parse feature file: %s, unexpected error: %+v\n", source.Uri, err)
				}
			}
			return nil
		}

		if includeGherkinDocument {
			doc.Uri = source.Uri
			result = append(result, messages.Wrapper{
				Message: &messages.Wrapper_GherkinDocument{
					GherkinDocument: doc,
				},
			})
		}

		if includePickles {
			for _, pickle := range Pickles(*doc, source.Uri) {
				result = append(result, messages.Wrapper{
					Message: &messages.Wrapper_Pickle{
						Pickle: pickle,
					},
				})
			}
		}
		return nil
	}

	if len(paths) == 0 {
		reader := gio.NewDelimitedReader(sourceStream, math.MaxInt32)
		for {
			source := &messages.Source{}
			if err := reader.ReadMsg(source); err != nil {
				break
			}
			processSource(source)
		}
	} else {
		for _, path := range paths {
			in, err := ioutil.ReadFile(path)
			if err != nil {
				return result, fmt.Errorf("read feature file: %s - %+v", path, err)
			}
			source := &messages.Source{
				Uri:  path,
				Data: string(in),
				Media: &messages.Media{
					Encoding:    "UTF-8",
					ContentType: "text/x.cucumber.gherkin+plain",
				},
			}
			processSource(source)
		}
	}

	return result, nil
}

func (a *parseError) asAttachment(uri string) messages.Wrapper {
	return messages.Wrapper{
		Message: &messages.Wrapper_Attachment{
			Attachment: &messages.Attachment{
				Data: a.Error(),
				Source: &messages.SourceReference{
					Uri: uri,
					Location: &messages.Location{
						Line:   uint32(a.loc.Line),
						Column: uint32(a.loc.Column),
					},
				},
			}},
	}
}
<|endoftext|>


<commit_before>package gitfile

import (
	b64 "encoding/base64"
	"os/exec"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"github.com/hashicorp/terraform/helper/schema"
	"strings"
	"syscall"
	"github.com/hashicorp/terraform/terraform"
)

func Provider() terraform.ResourceProvider {
	return &schema.Provider{
		Schema: map[string]*schema.Schema{
			"workdir": &schema.Schema{
				Type: schema.TypeString,
				Required: true,
			},
		},
		ResourcesMap: map[string]*schema.Resource{
			"gitfile_file": fileResource(),
		},
		ConfigureFunc: gitfileConfigure,
	}
}

func gitfileConfigure(data *schema.ResourceData) (interface{}, error) {
	config := &gitfileConfig {
		workDir: data.Get("workdir").(string),
	}
	return config, nil
}

type gitfileConfig struct {
	workDir string
}

func fileResource() *schema.Resource {
	return &schema.Resource {
		Schema: map[string]*schema.Schema {
			"repo": &schema.Schema{
				Type: schema.TypeString,
				Required: true,
			},
			"path": &schema.Schema{
				Type: schema.TypeString,
				Required: true,
			},
			"contents": &schema.Schema{
				Type: schema.TypeString,
				Required: true,
			},
			"branch": &schema.Schema{
				Type: schema.TypeString,
				Optional: true,
				Default: "master",
			},
			"commit_message": &schema.Schema{
				Type: schema.TypeString,
				Optional: true,
				Default: "Created by terraform gitfile_file",
			},
		},
		Create: FileCreate,
		Read: FileRead,
		Update: FileUpdate,
		Delete: FileDelete,
	}
}

func FileCreate(d *schema.ResourceData, meta interface{}) error {
	repo := d.Get("repo").(string)
	branch := d.Get("branch").(string)
	filepath := d.Get("path").(string)
	workdir := meta.(*gitfileConfig).workDir

	d.SetId(fmt.Sprintf("%s %s %s", repo, branch, filepath))

	checkout_dir := path.Join(workdir, mungeGitDir(d.Id()))
	if err := shallowSparseGitCheckout(checkout_dir, repo, branch, filepath); err != nil {
		return err
	}

	return FileUpdate(d, meta)
}
func FileRead(d *schema.ResourceData, meta interface{}) error {
	splits := strings.SplitN(d.Id(), " ", 3)
	repo := splits[0]
	branch := splits[1]
	filepath := splits[2]
	workdir := meta.(*gitfileConfig).workDir

	d.Set("repo", repo)
	d.Set("branch", branch)
	d.Set("path", filepath)

	checkout_dir := path.Join(workdir, mungeGitDir(d.Id()))
	if err := shallowSparseGitCheckout(checkout_dir, repo, branch, filepath); err != nil {
		return err
	}

	contents, err := ioutil.ReadFile(path.Join(checkout_dir, filepath))
	if err != nil {
		if os.IsNotExist(err) {
			d.Set("contents", "")
		} else {
			return err
		}
	} else {
		d.Set("contents", string(contents))
	}
	return nil
}
func FileUpdate(d *schema.ResourceData, meta interface{}) error {
	repo := d.Get("repo").(string)
	branch := d.Get("branch").(string)
	filepath := d.Get("path").(string)
	contents := d.Get("contents").(string)
	commit_message := d.Get("commit_message").(string)
	workdir := meta.(*gitfileConfig).workDir
	checkout_dir := path.Join(workdir, mungeGitDir(d.Id()))

	if err := ioutil.WriteFile(path.Join(checkout_dir, filepath), []byte(contents), 0666); err != nil {
		return err
	}

	// Only bother trying to commit things if the contents have changed.
	// I'm pretty sure this should be relatively accurate, since terraform will generally call FileRead before this.
	if d.HasChange("contents") {
		git_add := exec.Command("git", "add", "--intent-to-add", "--", filepath)
		git_add.Dir = checkout_dir
		if err := git_add.Run(); err != nil {
			return err
		}

		git_commit := exec.Command("git", "commit", "-m", commit_message, "--", filepath)
		git_commit.Dir = checkout_dir
		if err := git_commit.Run(); err != nil {
			return err
		}

		git_push := exec.Command("git", "push", repo, fmt.Sprintf("HEAD:%s", branch))
		git_push.Dir = checkout_dir
		if err := git_push.Run(); err != nil {
			return err
		}
	}
	return nil
}
func FileDelete(d *schema.ResourceData, meta interface{}) error {
	splits := strings.SplitN(d.Id(), " ", 3)
	repo := splits[0]
	branch := splits[1]
	filepath := splits[2]
	workdir := meta.(*gitfileConfig).workDir
	checkout_dir := path.Join(workdir, mungeGitDir(d.Id()))
	commit_message := d.Get("commit_message").(string)

	git_rm := exec.Command("git", "rm", "--ignore-unmatch", "--", filepath)
	git_rm.Dir = checkout_dir
	if err := git_rm.Run(); err != nil {
		return err
	}

	git_diff_index := exec.Command("git", "diff-index", "--exit-code", "--quiet", "HEAD", "--", filepath)
	git_diff_index.Dir = checkout_dir
	if err := git_diff_index.Run(); err != nil {
		exitErr, isExitErr := err.(*exec.ExitError)
		if isExitErr {
			if exitErr.Sys().(syscall.WaitStatus).ExitStatus() != 1 {
				return err
			} else {
				git_commit := exec.Command("git", "commit", "-m", commit_message, "--", filepath)
				git_commit.Dir = checkout_dir
				if err := git_commit.Run(); err != nil {
					return err
				}

				git_push := exec.Command("git", "push", repo, fmt.Sprintf("HEAD:%s", branch))
				git_push.Dir = checkout_dir
				if err := git_push.Run(); err != nil {
					return err
				}
			}
		} else {
			return err
		}
	}

	return nil
}

func mungeGitDir(id string) string {
	return b64.URLEncoding.EncodeToString([]byte(id))
}

func shallowSparseGitCheckout(checkout_dir, repo, branch, filepath string) error {
	if err := os.MkdirAll(checkout_dir, 0755); err != nil {
		return err
	}

	// git init appears to be idempotent.
	git_init := exec.Command("git", "init")
	git_init.Dir = checkout_dir
	if err := git_init.Run(); err != nil {
		return err
	}

	git_config := exec.Command("git", "config", "core.sparsecheckout", "true")
	git_config.Dir = checkout_dir
	if err := git_config.Run(); err != nil {
		return err
	}

	if err := ioutil.WriteFile(
		path.Join(checkout_dir, ".git", "info", "sparse-checkout"),
		[]byte(filepath),
		0666,
	); err != nil {
		return err
	}

	git_fetch := exec.Command("git", "fetch", "--depth", "1", repo, branch)
	git_fetch.Dir = checkout_dir
	if err := git_fetch.Run(); err != nil {
		return err
	}

	git_checkout := exec.Command("git", "checkout", "--force", "FETCH_HEAD")
	git_checkout.Dir = checkout_dir
	if err := git_checkout.Run(); err != nil {
		return err
	}

	git_clean := exec.Command("git", "clean", "-ffdx")
	git_clean.Dir = checkout_dir
	if err := git_clean.Run(); err != nil {
		return err
	}

	return nil
}<commit_msg>Refactor repetitive exec.Commands into a function<commit_after>package gitfile

import (
	b64 "encoding/base64"
	"os/exec"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"github.com/hashicorp/terraform/helper/schema"
	"strings"
	"syscall"
	"github.com/hashicorp/terraform/terraform"
)

func Provider() terraform.ResourceProvider {
	return &schema.Provider{
		Schema: map[string]*schema.Schema{
			"workdir": &schema.Schema{
				Type: schema.TypeString,
				Required: true,
			},
		},
		ResourcesMap: map[string]*schema.Resource{
			"gitfile_file": fileResource(),
		},
		ConfigureFunc: gitfileConfigure,
	}
}

func gitfileConfigure(data *schema.ResourceData) (interface{}, error) {
	config := &gitfileConfig {
		workDir: data.Get("workdir").(string),
	}
	return config, nil
}

type gitfileConfig struct {
	workDir string
}

func fileResource() *schema.Resource {
	return &schema.Resource {
		Schema: map[string]*schema.Schema {
			"repo": &schema.Schema{
				Type: schema.TypeString,
				Required: true,
			},
			"path": &schema.Schema{
				Type: schema.TypeString,
				Required: true,
			},
			"contents": &schema.Schema{
				Type: schema.TypeString,
				Required: true,
			},
			"branch": &schema.Schema{
				Type: schema.TypeString,
				Optional: true,
				Default: "master",
			},
			"commit_message": &schema.Schema{
				Type: schema.TypeString,
				Optional: true,
				Default: "Created by terraform gitfile_file",
			},
		},
		Create: FileCreate,
		Read: FileRead,
		Update: FileUpdate,
		Delete: FileDelete,
	}
}

func FileCreate(d *schema.ResourceData, meta interface{}) error {
	repo := d.Get("repo").(string)
	branch := d.Get("branch").(string)
	filepath := d.Get("path").(string)
	workdir := meta.(*gitfileConfig).workDir

	d.SetId(fmt.Sprintf("%s %s %s", repo, branch, filepath))

	checkout_dir := path.Join(workdir, mungeGitDir(d.Id()))
	if err := shallowSparseGitCheckout(checkout_dir, repo, branch, filepath); err != nil {
		return err
	}

	return FileUpdate(d, meta)
}
func FileRead(d *schema.ResourceData, meta interface{}) error {
	splits := strings.SplitN(d.Id(), " ", 3)
	repo := splits[0]
	branch := splits[1]
	filepath := splits[2]
	workdir := meta.(*gitfileConfig).workDir

	d.Set("repo", repo)
	d.Set("branch", branch)
	d.Set("path", filepath)

	checkout_dir := path.Join(workdir, mungeGitDir(d.Id()))
	if err := shallowSparseGitCheckout(checkout_dir, repo, branch, filepath); err != nil {
		return err
	}

	contents, err := ioutil.ReadFile(path.Join(checkout_dir, filepath))
	if err != nil {
		if os.IsNotExist(err) {
			d.Set("contents", "")
		} else {
			return err
		}
	} else {
		d.Set("contents", string(contents))
	}
	return nil
}
func FileUpdate(d *schema.ResourceData, meta interface{}) error {
	repo := d.Get("repo").(string)
	branch := d.Get("branch").(string)
	filepath := d.Get("path").(string)
	contents := d.Get("contents").(string)
	commit_message := d.Get("commit_message").(string)
	workdir := meta.(*gitfileConfig).workDir
	checkout_dir := path.Join(workdir, mungeGitDir(d.Id()))

	if err := ioutil.WriteFile(path.Join(checkout_dir, filepath), []byte(contents), 0666); err != nil {
		return err
	}

	// Only bother trying to commit things if the contents have changed.
	// I'm pretty sure this should be relatively accurate, since terraform will generally call FileRead before this.
	if d.HasChange("contents") {
		if err := gitCommand(checkout_dir, "add", "--intent-to-add", "--", filepath); err != nil {
			return err
		}

		if err := gitCommand(checkout_dir, "commit", "-m", commit_message, "--", filepath); err != nil {
			return err
		}

		if err := gitCommand(checkout_dir, "push", repo, fmt.Sprintf("HEAD:%s", branch)); err != nil {
			return err
		}
	}
	return nil
}
func FileDelete(d *schema.ResourceData, meta interface{}) error {
	splits := strings.SplitN(d.Id(), " ", 3)
	repo := splits[0]
	branch := splits[1]
	filepath := splits[2]
	workdir := meta.(*gitfileConfig).workDir
	checkout_dir := path.Join(workdir, mungeGitDir(d.Id()))
	commit_message := d.Get("commit_message").(string)

	if err := gitCommand(checkout_dir, "rm", "--ignore-unmatch", "--", filepath); err != nil {
		return err
	}

	if err := gitCommand(checkout_dir, "diff-index", "--exit-code", "--quiet", "HEAD", "--", filepath); err != nil {
		exitErr, isExitErr := err.(*exec.ExitError)
		if isExitErr {
			if exitErr.Sys().(syscall.WaitStatus).ExitStatus() != 1 {
				return err
			} else {
				if err := gitCommand(checkout_dir, "commit", "-m", commit_message, "--", filepath); err != nil {
					return err
				}

				if err := gitCommand(checkout_dir, "push", repo, fmt.Sprintf("HEAD:%s", branch)); err != nil {
					return err
				}
			}
		} else {
			return err
		}
	}

	return nil
}

func gitCommand(checkout_dir string, args ...string) error {
	command := exec.Command("git", args...)
	command.Dir = checkout_dir
	if err := command.Run(); err != nil {
		return err
	}
	return nil
}

func mungeGitDir(id string) string {
	return b64.URLEncoding.EncodeToString([]byte(id))
}

func shallowSparseGitCheckout(checkout_dir, repo, branch, filepath string) error {
	if err := os.MkdirAll(checkout_dir, 0755); err != nil {
		return err
	}

	// git init appears to be idempotent.
	if err := gitCommand(checkout_dir, "init"); err != nil {
		return err
	}

	if err := gitCommand(checkout_dir, "config", "core.sparsecheckout", "true"); err != nil {
		return err
	}

	if err := ioutil.WriteFile(
		path.Join(checkout_dir, ".git", "info", "sparse-checkout"),
		[]byte(filepath),
		0666,
	); err != nil {
		return err
	}

	if err := gitCommand(checkout_dir, "fetch", "--depth", "1", repo, branch); err != nil {
		return err
	}

	if err := gitCommand(checkout_dir, "checkout", "--force", "FETCH_HEAD"); err != nil {
		return err
	}

	if err := gitCommand(checkout_dir, "clean", "-ffdx"); err != nil {
		return err
	}

	return nil
}<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All Rights Reserved.
//
// 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 gitkit

import (
	"net/http"
	"sync"

	"code.google.com/p/goauth2/oauth"
	"code.google.com/p/goauth2/oauth/jwt"
)

type Authenticator interface {
	// AccessToken fetches an OAuth2 token for accessing authentication required
	// identitytoolkit APIs.
	AccessToken(r http.RoundTripper) (string, error)
}

// PEMKeyAuthenticator uses a PEM private key to authenticate.
type PEMKeyAuthenticator struct {
	// assertion is the JWT assertion generated by the service account.
	assertion *jwt.Token
	// token is the identitytookit API OAuth2 token.
	token *oauth.Token
	mu    sync.Mutex
}

// AccessToken implements Authenticator interface.
func (a *PEMKeyAuthenticator) AccessToken(r http.RoundTripper) (string, error) {
	a.mu.Lock()
	defer a.mu.Unlock()

	if a.token == nil || a.token.Expired() {
		token, err := a.assertion.Assert(&http.Client{Transport: r})
		if err != nil {
			return "", err
		}
		a.token = token
	}
	return a.token.AccessToken, nil
}

const clientUserAgent = "gitkit-go-client/0.1"

// ServiceAccountTransport is an implementation of http.RoundTripper that can
// automatically fetch an access token for the service account to access
// authentication required identitytoolkit APIs.
type ServiceAccountTransport struct {
	Auth      Authenticator
	Transport http.RoundTripper // Underlying HTTP transport.
}

// RoundTrip implements the http.RoundTripper interface.
func (t *ServiceAccountTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	token, err := t.Auth.AccessToken(t.Transport)
	if err != nil {
		return nil, err
	}
	// Copy the request to avoid modifying the original request.
	// This is required by the specification of http.RoundTripper.
	newReq := *req
	newReq.Header = make(http.Header)
	for k, v := range req.Header {
		newReq.Header[k] = v
	}
	// Add Authorization header.
	newReq.Header.Set("Authorization", "Bearer "+token)
	newReq.Header.Set("Content-Type", "application/json")
	newReq.Header.Set("User-Agent", clientUserAgent)
	return t.Transport.RoundTrip(&newReq)
}

// APIKeyTransport is an implementation of http.RoundTripper that appends the
// API key to the request to identitytoolkit APIs that don't require
// authentication.
type APIKeyTransport struct {
	APIKey    string
	Transport http.RoundTripper // Underlying HTTP transport.
}

// RoundTrip implements the http.RoundTripper interface.
func (t *APIKeyTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	// Copy the request to avoid modifying the original request.
	// This is required by the specification of http.RoundTripper.
	newReq := *req
	newReq.Header = make(http.Header)
	for k, v := range req.Header {
		newReq.Header[k] = v
	}
	// Append API key.
	q := newReq.URL.Query()
	q.Set("key", t.APIKey)
	newReq.URL.RawQuery = q.Encode()
	newReq.Header.Set("User-Agent", clientUserAgent)
	return t.Transport.RoundTrip(&newReq)
}
<commit_msg>Bump version to 0.1.1<commit_after>// Copyright 2014 Google Inc. All Rights Reserved.
//
// 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 gitkit

import (
	"net/http"
	"sync"

	"code.google.com/p/goauth2/oauth"
	"code.google.com/p/goauth2/oauth/jwt"
)

type Authenticator interface {
	// AccessToken fetches an OAuth2 token for accessing authentication required
	// identitytoolkit APIs.
	AccessToken(r http.RoundTripper) (string, error)
}

// PEMKeyAuthenticator uses a PEM private key to authenticate.
type PEMKeyAuthenticator struct {
	// assertion is the JWT assertion generated by the service account.
	assertion *jwt.Token
	// token is the identitytookit API OAuth2 token.
	token *oauth.Token
	mu    sync.Mutex
}

// AccessToken implements Authenticator interface.
func (a *PEMKeyAuthenticator) AccessToken(r http.RoundTripper) (string, error) {
	a.mu.Lock()
	defer a.mu.Unlock()

	if a.token == nil || a.token.Expired() {
		token, err := a.assertion.Assert(&http.Client{Transport: r})
		if err != nil {
			return "", err
		}
		a.token = token
	}
	return a.token.AccessToken, nil
}

const clientUserAgent = "gitkit-go-client/0.1.1"

// ServiceAccountTransport is an implementation of http.RoundTripper that can
// automatically fetch an access token for the service account to access
// authentication required identitytoolkit APIs.
type ServiceAccountTransport struct {
	Auth      Authenticator
	Transport http.RoundTripper // Underlying HTTP transport.
}

// RoundTrip implements the http.RoundTripper interface.
func (t *ServiceAccountTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	token, err := t.Auth.AccessToken(t.Transport)
	if err != nil {
		return nil, err
	}
	// Copy the request to avoid modifying the original request.
	// This is required by the specification of http.RoundTripper.
	newReq := *req
	newReq.Header = make(http.Header)
	for k, v := range req.Header {
		newReq.Header[k] = v
	}
	// Add Authorization header.
	newReq.Header.Set("Authorization", "Bearer "+token)
	newReq.Header.Set("Content-Type", "application/json")
	newReq.Header.Set("User-Agent", clientUserAgent)
	return t.Transport.RoundTrip(&newReq)
}

// APIKeyTransport is an implementation of http.RoundTripper that appends the
// API key to the request to identitytoolkit APIs that don't require
// authentication.
type APIKeyTransport struct {
	APIKey    string
	Transport http.RoundTripper // Underlying HTTP transport.
}

// RoundTrip implements the http.RoundTripper interface.
func (t *APIKeyTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	// Copy the request to avoid modifying the original request.
	// This is required by the specification of http.RoundTripper.
	newReq := *req
	newReq.Header = make(http.Header)
	for k, v := range req.Header {
		newReq.Header[k] = v
	}
	// Append API key.
	q := newReq.URL.Query()
	q.Set("key", t.APIKey)
	newReq.URL.RawQuery = q.Encode()
	newReq.Header.Set("User-Agent", clientUserAgent)
	return t.Transport.RoundTrip(&newReq)
}
<|endoftext|>


<commit_before>package candidate

import (
	"encoding/json"
	"errors"
	"fmt"
	"sort"
	"strings"
	"sync"
	"time"

	"gigawatt-common/pkg/concurrency"
	zkutil "gigawatt-common/pkg/zk/util"

	"github.com/samuel/go-zookeeper/zk"
)

const (
	LeaderChanSize = 6
)

var (
	AlreadyRegisteredError  = errors.New("already registered")
	NotRegisteredError      = errors.New("not registered")
	NotEnrolledError        = errors.New("candidate is not presently enrolled in the election")
	InvalidChildrenLenError = errors.New("0 children listed afer created protected ephemeral sequential - this should never happen")
)

var (
	worldAllAcl = zk.WorldACL(zk.PermAll)
)

type Candidate struct {
	ElectionPath     string
	Node             *Node
	zxId             string
	zxIdLock         sync.RWMutex
	registered       bool
	registrationLock sync.Mutex
	stopChan         chan chan struct{}
	Debug            bool
}

func NewCandidate(electionPath string, node *Node) *Candidate {
	candidate := &Candidate{
		ElectionPath: electionPath,
		Node:         node,
		stopChan:     make(chan chan struct{}, 1),
	}
	return candidate
}

func (c *Candidate) Registered() bool {
	c.registrationLock.Lock()
	defer c.registrationLock.Unlock()
	return c.registered
}

func (c *Candidate) Register(conn *zk.Conn) (<-chan *Node, error) {
	log.Info("[uuid=%v] Candidate registering..", c.Node.Uuid)

	c.registrationLock.Lock()
	defer c.registrationLock.Unlock()

	if c.registered {
		return nil, AlreadyRegisteredError
	}
	c.registered = true

	enroll := func() (leader *Node, watch <-chan zk.Event, err error) {
		log.Info("[uuid=%v] Candidate enrolling..", c.Node.Uuid)

		var (
			zxId     string
			data     []byte
			children []string
		)

		if zxId, err = c.validZxId(conn); err != nil {
			return
		}
		if zxId == "" {
			if err = c.ensureElectionPathExists(conn); err != nil {
				return
			}
			if data, err = json.Marshal(c.Node); err != nil {
				err = fmt.Errorf("serializing node data: %s", err)
				return
			}
			// log.Debug("CPES for node=%v", string(data))
			if zxId, err = conn.CreateProtectedEphemeralSequential(c.ElectionPath+"/n_", data, worldAllAcl); err != nil {
				err = fmt.Errorf("creating protected ephemeral sequential: %s", err)
				return
			}
			if idx := strings.LastIndex(zxId, "/"); idx > 0 {
				zxId = zxId[idx+1:]
			} else {
				err = fmt.Errorf("received invalid zxid=%v", zxId)
				return
			}
			if c.Debug {
				log.Debug("[uuid=%v] Candidate has new zxId=%v", c.Node.Uuid, zxId)
			}
			c.zxIdLock.Lock()
			c.zxId = zxId
			c.zxIdLock.Unlock()
		}

		if children, _, watch, err = conn.ChildrenW(c.ElectionPath); err != nil {
			return
		}
		sort.Sort(ZxIds(children))
		if c.Debug {
			log.Debug("[uuid=%v] Candidate children=%v", c.Node.Uuid, children)
		}

		if children[0] == zxId {
			leader = c.Node
		} else if leader, err = c.getNode(conn, children[0]); err != nil {
			return
		}

		log.Info("[uuid=%v] Candidate enrolled OK", c.Node.Uuid)
		return
	}

	type asyncEnrollResult struct {
		leader *Node
		watch  <-chan zk.Event
		err    error
	}

	asyncEnroll := func() chan *asyncEnrollResult {
		resultChan := make(chan *asyncEnrollResult)
		go func() {
			leader, watch, err := enroll()
			resultChan <- &asyncEnrollResult{
				leader: leader,
				watch:  watch,
				err:    err,
			}
		}()
		return resultChan
	}

	leaderChan := make(chan *Node, LeaderChanSize)

	// Watcher.
	go func() {
		var (
			leader *Node
			watch  <-chan zk.Event
		)

		for {
			if watch == nil {
				select {
				case result := <-asyncEnroll():
					if result.err != nil {
						if c.Debug {
							log.Debug("[uuid=%v] Candidate watcher enrollment err=%s", c.Node.Uuid, result.err)
						}
						time.Sleep(1 * time.Second) // TODO: Definitely use backoff here.
						continue
					} else if result.leader != leader {
						leader = result.leader

						select {
						case leaderChan <- leader:
							// pass
						default:
						}
					}
					watch = result.watch

				case ackCh := <-c.stopChan:
					close(leaderChan)
					ackCh <- struct{}{}
					return
				}
			}

			select {
			case event, ok := <-watch:
				if !ok {
					if c.Debug {
						log.Debug("[uuid=%v] Candidate watcher detected watch chan closed, triggering enroll", c.Node.Uuid)
					}
					watch = nil
					continue
				}

				switch event.Type {
				case zk.EventNodeDeleted, zk.EventNotWatching, zk.EventNodeChildrenChanged:
					if c.Debug {
						log.Debug("[uuid=%v] Candidate watcher received event=%+v, triggering enroll", c.Node.Uuid, event)
					}
					watch = nil

				default:
					if c.Debug {
						log.Debug("[uuid=%v] Candidate watcher received misc event=%+v", c.Node.Uuid, event)
					}
				}

			case ackCh := <-c.stopChan:
				close(leaderChan)
				c.wipeZxId(conn)
				ackCh <- struct{}{}
				return
			}
		}
	}()

	log.Info("[uuid=%v] Candidate registered OK", c.Node.Uuid)
	return leaderChan, nil
}

func (c *Candidate) wipeZxId(conn *zk.Conn) {
	c.zxIdLock.Lock()
	defer c.zxIdLock.Unlock()

	path := c.ElectionPath + "/" + c.zxId
	exists, stat, err := conn.Exists(path)
	if err != nil {
		log.Warning("[uuid=%v] Candidate zxId=%v deletion skipped due to existence check err=%s", c.Node.Uuid, c.zxId, err)
	} else if exists {
		if err = conn.Delete(path, stat.Version); err != nil {
			log.Warning("[uuid=%v] Candidate zxId=%v deletion failed due to delete err=%s", c.Node.Uuid, c.zxId, err)
		} else {
			log.Info("[uuid=%v] Candidate successfully deleted zxId path=%v", c.Node.Uuid, path)
		}
	} else {
		log.Info("[uuid=%v] Candidate zxId=%v deletion skipped due to !exists", c.Node.Uuid, c.zxId)
	}
}

func (c *Candidate) Unregister() error {
	log.Info("[uuid=%v] Candidate unregistering..", c.Node.Uuid)

	c.registrationLock.Lock()
	defer c.registrationLock.Unlock()

	if !c.registered {
		return NotRegisteredError
	}
	c.registered = false

	ackCh := make(chan struct{})
	c.stopChan <- ackCh
	<-ackCh

	log.Info("[uuid=%v] Candidate unregistered", c.Node.Uuid)
	return nil
}

func (c *Candidate) validZxId(conn *zk.Conn) (zxId string, err error) {
	c.zxIdLock.RLock()
	zxId = c.zxId
	c.zxIdLock.RUnlock()

	if zxId == "" {
		return
	}

	var (
		path   = c.ElectionPath + "/" + zxId
		exists bool
	)

	if exists, _, err = conn.Exists(path); err != nil {
		err = fmt.Errorf("checking if zxId=%v exists: %s", path, err)
	} else if !exists {
		zxId = ""
	}
	return
}

func (c *Candidate) ensureElectionPathExists(conn *zk.Conn) error {
	exists, _, err := conn.Exists(c.ElectionPath)
	if err != nil {
		return fmt.Errorf("checking if electionPath=%v exists: %s", c.ElectionPath, err)
	}
	if !exists {
		if _, err = zkutil.CreateP(conn, c.ElectionPath, []byte{}, 0, worldAllAcl); err != nil && err != zk.ErrNodeExists {
			return fmt.Errorf("creating electionPath=%v", c.ElectionPath, err)
		}
	}
	return nil
}

func (c *Candidate) getNode(conn *zk.Conn, zxId string) (node *Node, err error) {
	var data []byte
	if data, _, err = conn.Get(c.ElectionPath + "/" + zxId); err != nil {
		err = fmt.Errorf("getting node data for zxId=%v: %s", zxId, err)
		return
	}
	node = &Node{}
	if err = json.Unmarshal(data, node); err != nil {
		err = fmt.Errorf("deserializing node data for zxId=%v: %s", zxId, err)
		return
	}
	return
}

func (c *Candidate) Participants(conn *zk.Conn) (participants []Node, err error) {
	var (
		children []string
	)
	if children, err = c.children(conn); err != nil {
		return
	}

	var (
		numChildren      = len(children)
		collectorFuncs   = make([]func() error, 0, numChildren)
		participantsLock sync.Mutex
	)
	participants = make([]Node, 0, numChildren)

	for _, zxId := range children {
		func(zxId string) {
			collectorFunc := func() (err error) {
				var node *Node
				if node, err = c.getNode(conn, zxId); err != nil {
					return
				}
				participantsLock.Lock()
				participants = append(participants, *node)
				participantsLock.Unlock()
				return
			}
			collectorFuncs = append(collectorFuncs, collectorFunc)
		}(zxId)
	}

	if err = concurrency.MultiGo(collectorFuncs...); err != nil {
		return
	}
	return
}

// func (c *Candidate) ZxId() string {
// 	c.zxIdLock.RLock()
// 	defer c.zxIdLock.RUnlock()
// 	return c.zxId
// }

func (c *Candidate) children(conn *zk.Conn) (children []string, err error) {
	if children, _, err = conn.Children(c.ElectionPath); err != nil {
		err = fmt.Errorf("listing children: %s", err)
		return
	}
	if len(children) == 0 {
		err = InvalidChildrenLenError
		return
	}
	sort.Strings(children)
	return
}
<commit_msg>Kafka administrative command helper functions.<commit_after>package candidate

import (
	"encoding/json"
	"errors"
	"fmt"
	"sort"
	"strings"
	"sync"
	"time"

	"gigawatt-common/pkg/concurrency"
	zkutil "gigawatt-common/pkg/zk/util"

	"github.com/samuel/go-zookeeper/zk"
)

const (
	LeaderChanSize = 6
)

var (
	AlreadyRegisteredError  = errors.New("already registered")
	NotRegisteredError      = errors.New("not registered")
	NotEnrolledError        = errors.New("candidate is not presently enrolled in the election")
	InvalidChildrenLenError = errors.New("0 children listed afer created protected ephemeral sequential - this should never happen")
)

var (
	worldAllAcl = zk.WorldACL(zk.PermAll)
)

type Candidate struct {
	ElectionPath     string
	Node             *Node
	zxId             string
	zxIdLock         sync.RWMutex
	registered       bool
	registrationLock sync.Mutex
	stopChan         chan chan struct{}
	Debug            bool
}

func NewCandidate(electionPath string, node *Node) *Candidate {
	candidate := &Candidate{
		ElectionPath: electionPath,
		Node:         node,
		stopChan:     make(chan chan struct{}, 1),
	}
	return candidate
}

func (c *Candidate) Registered() bool {
	c.registrationLock.Lock()
	defer c.registrationLock.Unlock()
	return c.registered
}

func (c *Candidate) Register(conn *zk.Conn) (<-chan *Node, error) {
	log.Info("[uuid=%v] Candidate registering..", c.Node.Uuid)

	c.registrationLock.Lock()
	defer c.registrationLock.Unlock()

	if c.registered {
		return nil, AlreadyRegisteredError
	}
	c.registered = true

	enroll := func() (leader *Node, watch <-chan zk.Event, err error) {
		log.Info("[uuid=%v] Candidate enrolling..", c.Node.Uuid)

		var (
			zxId     string
			data     []byte
			children []string
		)

		if zxId, err = c.validZxId(conn); err != nil {
			return
		}
		if zxId == "" {
			if err = c.ensureElectionPathExists(conn); err != nil {
				return
			}
			if data, err = json.Marshal(c.Node); err != nil {
				err = fmt.Errorf("serializing node data: %s", err)
				return
			}
			// log.Debug("CPES for node=%v", string(data))
			if zxId, err = conn.CreateProtectedEphemeralSequential(c.ElectionPath+"/n_", data, worldAllAcl); err != nil {
				err = fmt.Errorf("creating protected ephemeral sequential %q: %s", c.ElectionPath, err)
				return
			}
			if idx := strings.LastIndex(zxId, "/"); idx > 0 {
				zxId = zxId[idx+1:]
			} else {
				err = fmt.Errorf("received invalid zxid=%v", zxId)
				return
			}
			if c.Debug {
				log.Debug("[uuid=%v] Candidate has new zxId=%v", c.Node.Uuid, zxId)
			}
			c.zxIdLock.Lock()
			c.zxId = zxId
			c.zxIdLock.Unlock()
		}

		if children, _, watch, err = conn.ChildrenW(c.ElectionPath); err != nil {
			return
		}
		sort.Sort(ZxIds(children))
		if c.Debug {
			log.Debug("[uuid=%v] Candidate children=%v", c.Node.Uuid, children)
		}

		if children[0] == zxId {
			leader = c.Node
		} else if leader, err = c.getNode(conn, children[0]); err != nil {
			return
		}

		log.Info("[uuid=%v] Candidate enrolled OK", c.Node.Uuid)
		return
	}

	type asyncEnrollResult struct {
		leader *Node
		watch  <-chan zk.Event
		err    error
	}

	asyncEnroll := func() chan *asyncEnrollResult {
		resultChan := make(chan *asyncEnrollResult)
		go func() {
			leader, watch, err := enroll()
			resultChan <- &asyncEnrollResult{
				leader: leader,
				watch:  watch,
				err:    err,
			}
		}()
		return resultChan
	}

	leaderChan := make(chan *Node, LeaderChanSize)

	// Watcher.
	go func() {
		var (
			leader *Node
			watch  <-chan zk.Event
		)

		for {
			if watch == nil {
				select {
				case result := <-asyncEnroll():
					if result.err != nil {
						log.Error("[uuid=%v] Candidate watcher enrollment err=%s", c.Node.Uuid, result.err)
						time.Sleep(1 * time.Second) // TODO: Definitely use backoff here.
						continue
					} else if result.leader != leader {
						leader = result.leader

						select {
						case leaderChan <- leader:
							// pass
						default:
						}
					}
					watch = result.watch

				case ackCh := <-c.stopChan:
					close(leaderChan)
					ackCh <- struct{}{}
					return
				}
			}

			select {
			case event, ok := <-watch:
				if !ok {
					if c.Debug {
						log.Debug("[uuid=%v] Candidate watcher detected watch chan closed, triggering enroll", c.Node.Uuid)
					}
					watch = nil
					continue
				}

				switch event.Type {
				case zk.EventNodeDeleted, zk.EventNotWatching, zk.EventNodeChildrenChanged:
					if c.Debug {
						log.Debug("[uuid=%v] Candidate watcher received event=%+v, triggering enroll", c.Node.Uuid, event)
					}
					watch = nil

				default:
					if c.Debug {
						log.Debug("[uuid=%v] Candidate watcher received misc event=%+v", c.Node.Uuid, event)
					}
				}

			case ackCh := <-c.stopChan:
				close(leaderChan)
				c.wipeZxId(conn)
				ackCh <- struct{}{}
				return
			}
		}
	}()

	log.Info("[uuid=%v] Candidate registered OK", c.Node.Uuid)
	return leaderChan, nil
}

func (c *Candidate) wipeZxId(conn *zk.Conn) {
	c.zxIdLock.Lock()
	defer c.zxIdLock.Unlock()

	path := c.ElectionPath + "/" + c.zxId
	exists, stat, err := conn.Exists(path)
	if err != nil {
		log.Warning("[uuid=%v] Candidate zxId=%v deletion skipped due to existence check err=%s", c.Node.Uuid, c.zxId, err)
	} else if exists {
		if err = conn.Delete(path, stat.Version); err != nil {
			log.Warning("[uuid=%v] Candidate zxId=%v deletion failed due to delete err=%s", c.Node.Uuid, c.zxId, err)
		} else {
			log.Info("[uuid=%v] Candidate successfully deleted zxId path=%v", c.Node.Uuid, path)
		}
	} else {
		log.Info("[uuid=%v] Candidate zxId=%v deletion skipped due to !exists", c.Node.Uuid, c.zxId)
	}
}

func (c *Candidate) Unregister() error {
	log.Info("[uuid=%v] Candidate unregistering..", c.Node.Uuid)

	c.registrationLock.Lock()
	defer c.registrationLock.Unlock()

	if !c.registered {
		return NotRegisteredError
	}
	c.registered = false

	ackCh := make(chan struct{})
	c.stopChan <- ackCh
	<-ackCh

	log.Info("[uuid=%v] Candidate unregistered", c.Node.Uuid)
	return nil
}

func (c *Candidate) validZxId(conn *zk.Conn) (zxId string, err error) {
	c.zxIdLock.RLock()
	zxId = c.zxId
	c.zxIdLock.RUnlock()

	if zxId == "" {
		return
	}

	var (
		path   = c.ElectionPath + "/" + zxId
		exists bool
	)

	if exists, _, err = conn.Exists(path); err != nil {
		err = fmt.Errorf("checking if zxId=%v exists: %s", path, err)
	} else if !exists {
		zxId = ""
	}
	return
}

func (c *Candidate) ensureElectionPathExists(conn *zk.Conn) error {
	exists, _, err := conn.Exists(c.ElectionPath)
	if err != nil {
		return fmt.Errorf("checking if electionPath=%v exists: %s", c.ElectionPath, err)
	}
	if !exists {
		if _, err = zkutil.CreateP(conn, c.ElectionPath, []byte{}, 0, worldAllAcl); err != nil && err != zk.ErrNodeExists {
			return fmt.Errorf("creating electionPath=%v", c.ElectionPath, err)
		}
	}
	return nil
}

func (c *Candidate) getNode(conn *zk.Conn, zxId string) (node *Node, err error) {
	var data []byte
	if data, _, err = conn.Get(c.ElectionPath + "/" + zxId); err != nil {
		err = fmt.Errorf("getting node data for zxId=%v: %s", zxId, err)
		return
	}
	node = &Node{}
	if err = json.Unmarshal(data, node); err != nil {
		err = fmt.Errorf("deserializing node data for zxId=%v: %s", zxId, err)
		return
	}
	return
}

func (c *Candidate) Participants(conn *zk.Conn) (participants []Node, err error) {
	var (
		children []string
	)
	if children, err = c.children(conn); err != nil {
		return
	}

	var (
		numChildren      = len(children)
		collectorFuncs   = make([]func() error, 0, numChildren)
		participantsLock sync.Mutex
	)
	participants = make([]Node, 0, numChildren)

	for _, zxId := range children {
		func(zxId string) {
			collectorFunc := func() (err error) {
				var node *Node
				if node, err = c.getNode(conn, zxId); err != nil {
					return
				}
				participantsLock.Lock()
				participants = append(participants, *node)
				participantsLock.Unlock()
				return
			}
			collectorFuncs = append(collectorFuncs, collectorFunc)
		}(zxId)
	}

	if err = concurrency.MultiGo(collectorFuncs...); err != nil {
		return
	}
	return
}

// func (c *Candidate) ZxId() string {
// 	c.zxIdLock.RLock()
// 	defer c.zxIdLock.RUnlock()
// 	return c.zxId
// }

func (c *Candidate) children(conn *zk.Conn) (children []string, err error) {
	if children, _, err = conn.Children(c.ElectionPath); err != nil {
		err = fmt.Errorf("listing children: %s", err)
		return
	}
	if len(children) == 0 {
		err = InvalidChildrenLenError
		return
	}
	sort.Strings(children)
	return
}
<|endoftext|>


<commit_before>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package libkb

// Version is the current version (should be MAJOR.MINOR.PATCH)
const Version = "1.0.49"
<commit_msg>Bump version to 1.1.0 for impending release (#12105)<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package libkb

// Version is the current version (should be MAJOR.MINOR.PATCH)
const Version = "2.0.0"
<|endoftext|>


<commit_before>package main

import (
	"context"
	"flag"
	"io/ioutil"
	"log"
	"time"

	"github.com/brotherlogic/keystore/client"
	"google.golang.org/grpc"

	pb "github.com/brotherlogic/cardserver/card"
)

// DoRegister Registers this server
func (s *Server) DoRegister(server *grpc.Server) {
	pb.RegisterCardServiceServer(server, s)
}

// ReportHealth Determines if the server is healthy
func (s *Server) ReportHealth() bool {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
	defer cancel()
	_, err := s.GetCards(ctx, &pb.Empty{})
	return err == nil
}

// Mote promotes this server
func (s *Server) Mote(master bool) error {
	if master {
		err := s.prepareList()
		return err
	}
	return nil
}

// SaveCardList stores the cardlist
func (s *Server) SaveCardList() {
	log.Printf("STARTED SAVE")
	s.Save(key, s.cards)
	log.Printf("FINISHED SAVE")
}

func (s *Server) prepareList() error {
	t := time.Now()
	cl := &pb.CardList{}
	rc, err := s.Read(key, cl)
	log.Printf("READ %v", rc)
	if err != nil {
		log.Printf("Failed to read cards! %v", err)
		return err
	}

	s.cards = rc.(*pb.CardList)
	log.Printf("SERVING: %v (%v)", s.cards, s)
	s.LogFunction("prepareList", t)
	return nil
}

func main() {
	var quiet = flag.Bool("quiet", true, "Show all output")
	flag.Parse()
	//Turn off logging
	if *quiet {
		log.SetFlags(0)
		log.SetOutput(ioutil.Discard)
	}
	log.Printf("Logging is on!")

	server := InitServer()
	server.GoServer.KSclient = *keystoreclient.GetClient(server.GetIP)
	server.PrepServer()
	server.RegisterServer("cardserver", false)
	if server.prepareList() != nil {
		log.Printf("Unable to find cardserver details")
		return
	}
	log.Printf("SERVING WITH %v (%v)", server.cards, server)
	server.Serve()
}
<commit_msg>Fixed health report<commit_after>package main

import (
	"flag"
	"io/ioutil"
	"log"
	"time"

	"github.com/brotherlogic/keystore/client"
	"google.golang.org/grpc"

	pb "github.com/brotherlogic/cardserver/card"
)

// DoRegister Registers this server
func (s *Server) DoRegister(server *grpc.Server) {
	pb.RegisterCardServiceServer(server, s)
}

// ReportHealth Determines if the server is healthy
func (s *Server) ReportHealth() bool {
	return true
}

// Mote promotes this server
func (s *Server) Mote(master bool) error {
	if master {
		err := s.prepareList()
		return err
	}
	return nil
}

// SaveCardList stores the cardlist
func (s *Server) SaveCardList() {
	log.Printf("STARTED SAVE")
	s.Save(key, s.cards)
	log.Printf("FINISHED SAVE")
}

func (s *Server) prepareList() error {
	t := time.Now()
	cl := &pb.CardList{}
	rc, err := s.Read(key, cl)
	log.Printf("READ %v", rc)
	if err != nil {
		log.Printf("Failed to read cards! %v", err)
		return err
	}

	s.cards = rc.(*pb.CardList)
	log.Printf("SERVING: %v (%v)", s.cards, s)
	s.LogFunction("prepareList", t)
	return nil
}

func main() {
	var quiet = flag.Bool("quiet", true, "Show all output")
	flag.Parse()
	//Turn off logging
	if *quiet {
		log.SetFlags(0)
		log.SetOutput(ioutil.Discard)
	}
	log.Printf("Logging is on!")

	server := InitServer()
	server.GoServer.KSclient = *keystoreclient.GetClient(server.GetIP)
	server.PrepServer()
	server.RegisterServer("cardserver", false)
	if server.prepareList() != nil {
		log.Printf("Unable to find cardserver details")
		return
	}
	log.Printf("SERVING WITH %v (%v)", server.cards, server)
	server.Serve()
}
<|endoftext|>


<commit_before>package gointerfaceutils

import (
	"errors"
	"strconv"
)

func SetValueAtDocPath(doc interface{}, docPath string, value interface{}) (interface{}, error) {
	path, err := parseDocPath(docPath)
	if err != nil {
		return nil, err
	}

	return setValueAtPath(doc, path, value)
}

func SetValueAtObjPath(doc interface{}, objPath string, value interface{}) (interface{}, error) {
	path, err := parseObjPath(objPath)
	if err != nil {
		return nil, err
	}

	return setValueAtPath(doc, path, value)
}

func GetValueAtDocPath(doc interface{}, docPath string) (interface{}, error) {
	path, err := parseDocPath(docPath)
	if err != nil {
		return nil, err
	}

	return getValueAtPath(doc, path)
}

func GetValueAtObjPath(doc interface{}, objPath string) (interface{}, error) {
	path, err := parseObjPath(objPath)
	if err != nil {
		return nil, err
	}

	return getValueAtPath(doc, path)
}

func getValueAtSelector(doc interface{}, selector string) (ret interface{}, err error) {
	switch doc.(type) {
	case map[string]interface{}:
		val, ok := doc.(map[string]interface{})[selector]
		if !ok {
			return doc, errors.New("The map didn't have any value at key " + selector)
		}
		return val, nil
	case []interface{}:
		i, err := strconv.Atoi(selector)
		if err != nil {
			return doc, errors.New("The selector " + selector + " wasn't a valid index into the array")
		}
		if 0 > i || i >= len(doc.([]interface{})) {
			return doc, errors.New("The selector " + selector + " was an out of bound index into the array")
		}
		return doc.([]interface{})[i], nil
	default:
		return doc, errors.New("The selector " + selector + " wasn't valid for the document")
	}
}

func getValueAtPath(doc interface{}, path []string) (ret interface{}, err error) {
	ret = doc
	for _, selector := range path {
		ret, err = getValueAtSelector(ret, selector)
		if err != nil {
			return ret, err
		}
	}
	return ret, nil
}

func setValueAtPath(doc interface{}, path []string, value interface{}) (ret interface{}, err error) {
	switch doc.(type) {
	case nil:
		if len(path) == 0 {
			return value, nil
		}
		doc = make(map[string]interface{})
	case map[string]interface{}:
	case []interface{}:
	default:
		if len(path) == 0 {
			return value, nil
		}
		return doc, errors.New("Couldn't non destructivly create given path in doc")
	}

	ret = doc
	for i, selector := range path {
		//If this is the last node in the path, do the set
		if i == len(path)-1 {
			switch ret.(type) {
			case map[string]interface{}:
				ret.(map[string]interface{})[selector] = value
				break
			case []interface{}:

			default:
				return doc, errors.New("Couldn't non destructivly create given path in doc")
			}
			_, ok := ret.(map[string]interface{})
			if ok {

			}

		}
		//Get the value at selector
		ret, err = getValueAtSelector(ret, selector)
		if err != nil {
			switch ret.(type) {
			case map[string]interface{}:
				//TODO If the next value is 0, perhaps I should set this to an array instead?
				ret.(map[string]interface{})[selector] = make(map[string]interface{})
				ret = ret.(map[string]interface{})[selector]
			case []interface{}:
				i, err := strconv.Atoi(selector)
				if err != nil {
					return doc, errors.New("The selector " + selector + " wasn't a valid array index")
				}
				if 0 > i || i > len(ret.([]interface{})) {
					return doc, errors.New("The selector " + selector + " was an out of bound index into the array")
				}
				if i == len(ret.([]interface{})) {
					//TODO If the next value is 0, perhaps I should set this to an array instead?
					ret = append(ret.([]interface{}), make(map[string]interface{}))
					ret = ret.([]interface{})[len(ret.([]interface{}))-1]
				}
				return doc.([]interface{})[i], nil
			default:
				return doc, errors.New("Couldn't non destructivly create given path in doc")
			}
		}
	}
	return doc, nil
}
<commit_msg>Added a method that md5 hashes a document and returns the result<commit_after>package gointerfaceutils

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"errors"
	"strconv"
)

func GetMD5HashForJSONDoc(doc interface{}) (string, error) {
	bytes, err := json.Marshal(doc)
	if err != nil {
		return "", err
	}

	text := string(bytes)

	hasher := md5.New()
	hasher.Write([]byte(text))
	return hex.EncodeToString(hasher.Sum(nil)), nil
}

func SetValueAtDocPath(doc interface{}, docPath string, value interface{}) (interface{}, error) {
	path, err := parseDocPath(docPath)
	if err != nil {
		return nil, err
	}

	return setValueAtPath(doc, path, value)
}

func SetValueAtObjPath(doc interface{}, objPath string, value interface{}) (interface{}, error) {
	path, err := parseObjPath(objPath)
	if err != nil {
		return nil, err
	}

	return setValueAtPath(doc, path, value)
}

func GetValueAtDocPath(doc interface{}, docPath string) (interface{}, error) {
	path, err := parseDocPath(docPath)
	if err != nil {
		return nil, err
	}

	return getValueAtPath(doc, path)
}

func GetValueAtObjPath(doc interface{}, objPath string) (interface{}, error) {
	path, err := parseObjPath(objPath)
	if err != nil {
		return nil, err
	}

	return getValueAtPath(doc, path)
}

func getValueAtSelector(doc interface{}, selector string) (ret interface{}, err error) {
	switch doc.(type) {
	case map[string]interface{}:
		val, ok := doc.(map[string]interface{})[selector]
		if !ok {
			return doc, errors.New("The map didn't have any value at key " + selector)
		}
		return val, nil
	case []interface{}:
		i, err := strconv.Atoi(selector)
		if err != nil {
			return doc, errors.New("The selector " + selector + " wasn't a valid index into the array")
		}
		if 0 > i || i >= len(doc.([]interface{})) {
			return doc, errors.New("The selector " + selector + " was an out of bound index into the array")
		}
		return doc.([]interface{})[i], nil
	default:
		return doc, errors.New("The selector " + selector + " wasn't valid for the document")
	}
}

func getValueAtPath(doc interface{}, path []string) (ret interface{}, err error) {
	ret = doc
	for _, selector := range path {
		ret, err = getValueAtSelector(ret, selector)
		if err != nil {
			return ret, err
		}
	}
	return ret, nil
}

func setValueAtPath(doc interface{}, path []string, value interface{}) (ret interface{}, err error) {
	switch doc.(type) {
	case nil:
		if len(path) == 0 {
			return value, nil
		}
		doc = make(map[string]interface{})
	case map[string]interface{}:
	case []interface{}:
	default:
		if len(path) == 0 {
			return value, nil
		}
		return doc, errors.New("Couldn't non destructivly create given path in doc")
	}

	ret = doc
	for i, selector := range path {
		//If this is the last node in the path, do the set
		if i == len(path)-1 {
			switch ret.(type) {
			case map[string]interface{}:
				ret.(map[string]interface{})[selector] = value
				break
			case []interface{}:

			default:
				return doc, errors.New("Couldn't non destructivly create given path in doc")
			}
			_, ok := ret.(map[string]interface{})
			if ok {

			}

		}
		//Get the value at selector
		ret, err = getValueAtSelector(ret, selector)
		if err != nil {
			switch ret.(type) {
			case map[string]interface{}:
				//TODO If the next value is 0, perhaps I should set this to an array instead?
				ret.(map[string]interface{})[selector] = make(map[string]interface{})
				ret = ret.(map[string]interface{})[selector]
			case []interface{}:
				i, err := strconv.Atoi(selector)
				if err != nil {
					return doc, errors.New("The selector " + selector + " wasn't a valid array index")
				}
				if 0 > i || i > len(ret.([]interface{})) {
					return doc, errors.New("The selector " + selector + " was an out of bound index into the array")
				}
				if i == len(ret.([]interface{})) {
					//TODO If the next value is 0, perhaps I should set this to an array instead?
					ret = append(ret.([]interface{}), make(map[string]interface{}))
					ret = ret.([]interface{})[len(ret.([]interface{}))-1]
				}
				return doc.([]interface{})[i], nil
			default:
				return doc, errors.New("Couldn't non destructivly create given path in doc")
			}
		}
	}
	return doc, nil
}
<|endoftext|>


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

package actions

import (
	"github.com/mozilla/mig"
	migdb "github.com/mozilla/mig/database"
)

type ListActionsPostgres struct {
	db       *migdb.DB
	queueLoc string
}

func NewListActionsPostgres(db *migdb.DB, queue string) ListActionsPostgres {
	return ListActionsPostgres{
		db:       db,
		queueLoc: queue,
	}
}

func (list ListActionsPostgres) ListActions(limit uint) ([]mig.Action, error) {
	return []mig.Action{}, nil
}
<commit_msg>First stab at implementing ListActions<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor: Zack Mullaly zmullaly@mozilla.com [:zack]

package actions

import (
	"fmt"

	"github.com/mozilla/mig"
	migdb "github.com/mozilla/mig/database"
)

type ListActionsPostgres struct {
	db       *migdb.DB
	queueLoc string
}

func NewListActionsPostgres(db *migdb.DB, queue string) ListActionsPostgres {
	return ListActionsPostgres{
		db:       db,
		queueLoc: queue,
	}
}

func (list ListActionsPostgres) ListActions(limit uint) ([]mig.Action, error) {
	now := time.Now().Add(-15 * time.Minute)
	agents, err := list.db.ActiveAgentsByQueue(limit.queueLoc, now)
	if err != nil {
		return []mig.Action{}, err
	}
	if len(agents) == 0 {
		err := fmt.Errorf("No agents listening to queue %s", list.queueLoc)
		return []mig.Action{}, err
	}
	actions, err := list.db.SetupRunnableActionsForAgent(agents[0])
	if err != nil {
		return []mig.Action{}, err
	}
	return actions, nil
}
<|endoftext|>