<commit_before>package resource

import (
	"context"
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"strings"

	"github.com/google/go-github/v39/github"
	"github.com/shurcooL/githubv4"
	"golang.org/x/oauth2"
)

// Last run with counterfeiter v6
//go:generate counterfeiter -o fakes/fake_git_hub.go . GitHub

type GitHub interface {
	ListReleases() ([]*github.RepositoryRelease, error)
	GetReleaseByTag(tag string) (*github.RepositoryRelease, error)
	GetRelease(id int) (*github.RepositoryRelease, error)
	CreateRelease(release github.RepositoryRelease) (*github.RepositoryRelease, error)
	UpdateRelease(release github.RepositoryRelease) (*github.RepositoryRelease, error)

	ListReleaseAssets(release github.RepositoryRelease) ([]*github.ReleaseAsset, error)
	UploadReleaseAsset(release github.RepositoryRelease, name string, file *os.File) error
	DeleteReleaseAsset(asset github.ReleaseAsset) error
	DownloadReleaseAsset(asset github.ReleaseAsset) (io.ReadCloser, error)

	GetTarballLink(tag string) (*url.URL, error)
	GetZipballLink(tag string) (*url.URL, error)
	ResolveTagToCommitSHA(tag string) (string, error)
}

type GitHubClient struct {
	client       *github.Client
	clientV4     *githubv4.Client
	isEnterprise bool

	owner       string
	repository  string
	accessToken string
}

func NewGitHubClient(source Source) (*GitHubClient, error) {
	var httpClient = &http.Client{}
	var ctx = context.TODO()

	if source.Insecure {
		httpClient.Transport = &http.Transport{
			Proxy:           http.ProxyFromEnvironment,
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		}
		ctx = context.WithValue(ctx, oauth2.HTTPClient, httpClient)
	}

	if source.AccessToken != "" {
		var err error
		httpClient, err = oauthClient(ctx, source)
		if err != nil {
			return nil, err
		}
	}

	client := github.NewClient(httpClient)

	clientV4 := githubv4.NewClient(httpClient)
	var isEnterprise bool

	if source.GitHubAPIURL != "" {
		var err error
		if !strings.HasSuffix(source.GitHubAPIURL, "/") {
			source.GitHubAPIURL += "/"
		}
		client.BaseURL, err = url.Parse(source.GitHubAPIURL)
		if err != nil {
			return nil, err
		}

		client.UploadURL, err = url.Parse(source.GitHubAPIURL)
		if err != nil {
			return nil, err
		}

		var v4URL string
		if strings.HasSuffix(source.GitHubAPIURL, "/v3/") {
			v4URL = strings.TrimSuffix(source.GitHubAPIURL, "/v3/") + "/graphql"
		} else {
			v4URL = source.GitHubAPIURL + "graphql"
		}
		clientV4 = githubv4.NewEnterpriseClient(v4URL, httpClient)
		isEnterprise = true
	}

	if source.GitHubV4APIURL != "" {
		clientV4 = githubv4.NewEnterpriseClient(source.GitHubV4APIURL, httpClient)
	}

	if source.GitHubUploadsURL != "" {
		var err error
		client.UploadURL, err = url.Parse(source.GitHubUploadsURL)
		if err != nil {
			return nil, err
		}
	}

	owner := source.Owner
	if source.User != "" {
		owner = source.User
	}

	return &GitHubClient{
		client:       client,
		clientV4:     clientV4,
		isEnterprise: isEnterprise,
		owner:        owner,
		repository:   source.Repository,
		accessToken:  source.AccessToken,
	}, nil
}

func (g *GitHubClient) ListReleases() ([]*github.RepositoryRelease, error) {
	if g.accessToken != "" {
		if g.isEnterprise {
			return g.listReleasesV4EnterPrice()
		}
		return g.listReleasesV4()
	}
	opt := &github.ListOptions{PerPage: 100}
	var allReleases []*github.RepositoryRelease
	for {
		releases, res, err := g.client.Repositories.ListReleases(context.TODO(), g.owner, g.repository, opt)
		if err != nil {
			return []*github.RepositoryRelease{}, err
		}
		allReleases = append(allReleases, releases...)
		if res.NextPage == 0 {
			err = res.Body.Close()
			if err != nil {
				return nil, err
			}
			break
		}
		opt.Page = res.NextPage
	}

	return allReleases, nil
}

func (g *GitHubClient) GetReleaseByTag(tag string) (*github.RepositoryRelease, error) {
	release, res, err := g.client.Repositories.GetReleaseByTag(context.TODO(), g.owner, g.repository, tag)
	if err != nil {
		return &github.RepositoryRelease{}, err
	}

	err = res.Body.Close()
	if err != nil {
		return nil, err
	}

	return release, nil
}

func (g *GitHubClient) GetRelease(id int) (*github.RepositoryRelease, error) {
	release, res, err := g.client.Repositories.GetRelease(context.TODO(), g.owner, g.repository, int64(id))
	if err != nil {
		return &github.RepositoryRelease{}, err
	}

	err = res.Body.Close()
	if err != nil {
		return nil, err
	}

	return release, nil
}

func (g *GitHubClient) CreateRelease(release github.RepositoryRelease) (*github.RepositoryRelease, error) {
	createdRelease, res, err := g.client.Repositories.CreateRelease(context.TODO(), g.owner, g.repository, &release)
	if err != nil {
		return &github.RepositoryRelease{}, err
	}

	err = res.Body.Close()
	if err != nil {
		return nil, err
	}

	return createdRelease, nil
}

func (g *GitHubClient) UpdateRelease(release github.RepositoryRelease) (*github.RepositoryRelease, error) {
	if release.ID == nil {
		return nil, errors.New("release did not have an ID: has it been saved yet?")
	}

	updatedRelease, res, err := g.client.Repositories.EditRelease(context.TODO(), g.owner, g.repository, *release.ID, &release)
	if err != nil {
		return &github.RepositoryRelease{}, err
	}

	err = res.Body.Close()
	if err != nil {
		return nil, err
	}

	return updatedRelease, nil
}

func (g *GitHubClient) ListReleaseAssets(release github.RepositoryRelease) ([]*github.ReleaseAsset, error) {
	opt := &github.ListOptions{PerPage: 100}
	assets, res, err := g.client.Repositories.ListReleaseAssets(context.TODO(), g.owner, g.repository, *release.ID, opt)
	if err != nil {
		return nil, err
	}

	err = res.Body.Close()
	if err != nil {
		return nil, err
	}

	return assets, nil
}

func (g *GitHubClient) UploadReleaseAsset(release github.RepositoryRelease, name string, file *os.File) error {
	_, res, err := g.client.Repositories.UploadReleaseAsset(
		context.TODO(),
		g.owner,
		g.repository,
		*release.ID,
		&github.UploadOptions{
			Name: name,
		},
		file,
	)
	if err != nil {
		return err
	}

	return res.Body.Close()
}

func (g *GitHubClient) DeleteReleaseAsset(asset github.ReleaseAsset) error {
	res, err := g.client.Repositories.DeleteReleaseAsset(context.TODO(), g.owner, g.repository, *asset.ID)
	if err != nil {
		return err
	}

	return res.Body.Close()
}

func (g *GitHubClient) DownloadReleaseAsset(asset github.ReleaseAsset) (io.ReadCloser, error) {
	bodyReader, redirectURL, err := g.client.Repositories.DownloadReleaseAsset(context.TODO(), g.owner, g.repository, *asset.ID, nil)
	if err != nil {
		return nil, err
	}

	if redirectURL == "" {
		return bodyReader, err
	}

	req, err := g.client.NewRequest("GET", redirectURL, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Accept", "application/octet-stream")
	if g.accessToken != "" && req.URL.Host == g.client.BaseURL.Host {
		req.Header.Set("Authorization", "Bearer "+g.accessToken)
	}

	httpClient := &http.Client{}
	resp, err := httpClient.Do(req)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode < 200 || resp.StatusCode > 299 {
		resp.Body.Close()
		return nil, fmt.Errorf("redirect URL %q responded with bad status code: %d", redirectURL, resp.StatusCode)
	}

	return resp.Body, nil
}

func (g *GitHubClient) GetTarballLink(tag string) (*url.URL, error) {
	opt := &github.RepositoryContentGetOptions{Ref: tag}
	u, res, err := g.client.Repositories.GetArchiveLink(context.TODO(), g.owner, g.repository, github.Tarball, opt, true)
	if err != nil {
		return nil, err
	}
	res.Body.Close()
	return u, nil
}

func (g *GitHubClient) GetZipballLink(tag string) (*url.URL, error) {
	opt := &github.RepositoryContentGetOptions{Ref: tag}
	u, res, err := g.client.Repositories.GetArchiveLink(context.TODO(), g.owner, g.repository, github.Zipball, opt, true)
	if err != nil {
		return nil, err
	}
	res.Body.Close()
	return u, nil
}

func (g *GitHubClient) ResolveTagToCommitSHA(tagName string) (string, error) {
	ref, res, err := g.client.Git.GetRef(context.TODO(), g.owner, g.repository, "tags/"+tagName)

	if err != nil {
		return "", err
	}

	res.Body.Close()

	// Lightweight tag
	if *ref.Object.Type == "commit" {
		return *ref.Object.SHA, nil
	}

	// Fail if we're not pointing to a annotated tag
	if *ref.Object.Type != "tag" {
		return "", fmt.Errorf("could not resolve tag %q to commit: returned type is not 'commit' or 'tag'", tagName)
	}

	// Resolve tag to commit sha
	tag, res, err := g.client.Git.GetTag(context.TODO(), g.owner, g.repository, *ref.Object.SHA)

	if err != nil {
		return "", err
	}

	res.Body.Close()

	if *tag.Object.Type != "commit" {
		return "", fmt.Errorf("could not resolve tag %q to commit: returned type is not 'commit'", tagName)
	}

	return *tag.Object.SHA, nil
}

func oauthClient(ctx context.Context, source Source) (*http.Client, error) {
	ts := oauth2.StaticTokenSource(&oauth2.Token{
		AccessToken: source.AccessToken,
	})

	oauthClient := oauth2.NewClient(ctx, ts)

	githubHTTPClient := &http.Client{
		Transport: oauthClient.Transport,
	}

	return githubHTTPClient, nil
}
<commit_msg>Add missed initialisation for isEnterprise in case of GitHubV4APIURL is set to custom<commit_after>package resource

import (
	"context"
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"strings"

	"github.com/google/go-github/v39/github"
	"github.com/shurcooL/githubv4"
	"golang.org/x/oauth2"
)

// Last run with counterfeiter v6
//go:generate counterfeiter -o fakes/fake_git_hub.go . GitHub

type GitHub interface {
	ListReleases() ([]*github.RepositoryRelease, error)
	GetReleaseByTag(tag string) (*github.RepositoryRelease, error)
	GetRelease(id int) (*github.RepositoryRelease, error)
	CreateRelease(release github.RepositoryRelease) (*github.RepositoryRelease, error)
	UpdateRelease(release github.RepositoryRelease) (*github.RepositoryRelease, error)

	ListReleaseAssets(release github.RepositoryRelease) ([]*github.ReleaseAsset, error)
	UploadReleaseAsset(release github.RepositoryRelease, name string, file *os.File) error
	DeleteReleaseAsset(asset github.ReleaseAsset) error
	DownloadReleaseAsset(asset github.ReleaseAsset) (io.ReadCloser, error)

	GetTarballLink(tag string) (*url.URL, error)
	GetZipballLink(tag string) (*url.URL, error)
	ResolveTagToCommitSHA(tag string) (string, error)
}

type GitHubClient struct {
	client       *github.Client
	clientV4     *githubv4.Client
	isEnterprise bool

	owner       string
	repository  string
	accessToken string
}

func NewGitHubClient(source Source) (*GitHubClient, error) {
	var httpClient = &http.Client{}
	var ctx = context.TODO()

	if source.Insecure {
		httpClient.Transport = &http.Transport{
			Proxy:           http.ProxyFromEnvironment,
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		}
		ctx = context.WithValue(ctx, oauth2.HTTPClient, httpClient)
	}

	if source.AccessToken != "" {
		var err error
		httpClient, err = oauthClient(ctx, source)
		if err != nil {
			return nil, err
		}
	}

	client := github.NewClient(httpClient)

	clientV4 := githubv4.NewClient(httpClient)
	var isEnterprise bool

	if source.GitHubAPIURL != "" {
		var err error
		if !strings.HasSuffix(source.GitHubAPIURL, "/") {
			source.GitHubAPIURL += "/"
		}
		client.BaseURL, err = url.Parse(source.GitHubAPIURL)
		if err != nil {
			return nil, err
		}

		client.UploadURL, err = url.Parse(source.GitHubAPIURL)
		if err != nil {
			return nil, err
		}

		var v4URL string
		if strings.HasSuffix(source.GitHubAPIURL, "/v3/") {
			v4URL = strings.TrimSuffix(source.GitHubAPIURL, "/v3/") + "/graphql"
		} else {
			v4URL = source.GitHubAPIURL + "graphql"
		}
		clientV4 = githubv4.NewEnterpriseClient(v4URL, httpClient)
		isEnterprise = true
	}

	if source.GitHubV4APIURL != "" {
		clientV4 = githubv4.NewEnterpriseClient(source.GitHubV4APIURL, httpClient)
		isEnterprise = true
	}

	if source.GitHubUploadsURL != "" {
		var err error
		client.UploadURL, err = url.Parse(source.GitHubUploadsURL)
		if err != nil {
			return nil, err
		}
	}

	owner := source.Owner
	if source.User != "" {
		owner = source.User
	}

	return &GitHubClient{
		client:       client,
		clientV4:     clientV4,
		isEnterprise: isEnterprise,
		owner:        owner,
		repository:   source.Repository,
		accessToken:  source.AccessToken,
	}, nil
}

func (g *GitHubClient) ListReleases() ([]*github.RepositoryRelease, error) {
	if g.accessToken != "" {
		if g.isEnterprise {
			return g.listReleasesV4EnterPrice()
		}
		return g.listReleasesV4()
	}
	opt := &github.ListOptions{PerPage: 100}
	var allReleases []*github.RepositoryRelease
	for {
		releases, res, err := g.client.Repositories.ListReleases(context.TODO(), g.owner, g.repository, opt)
		if err != nil {
			return []*github.RepositoryRelease{}, err
		}
		allReleases = append(allReleases, releases...)
		if res.NextPage == 0 {
			err = res.Body.Close()
			if err != nil {
				return nil, err
			}
			break
		}
		opt.Page = res.NextPage
	}

	return allReleases, nil
}

func (g *GitHubClient) GetReleaseByTag(tag string) (*github.RepositoryRelease, error) {
	release, res, err := g.client.Repositories.GetReleaseByTag(context.TODO(), g.owner, g.repository, tag)
	if err != nil {
		return &github.RepositoryRelease{}, err
	}

	err = res.Body.Close()
	if err != nil {
		return nil, err
	}

	return release, nil
}

func (g *GitHubClient) GetRelease(id int) (*github.RepositoryRelease, error) {
	release, res, err := g.client.Repositories.GetRelease(context.TODO(), g.owner, g.repository, int64(id))
	if err != nil {
		return &github.RepositoryRelease{}, err
	}

	err = res.Body.Close()
	if err != nil {
		return nil, err
	}

	return release, nil
}

func (g *GitHubClient) CreateRelease(release github.RepositoryRelease) (*github.RepositoryRelease, error) {
	createdRelease, res, err := g.client.Repositories.CreateRelease(context.TODO(), g.owner, g.repository, &release)
	if err != nil {
		return &github.RepositoryRelease{}, err
	}

	err = res.Body.Close()
	if err != nil {
		return nil, err
	}

	return createdRelease, nil
}

func (g *GitHubClient) UpdateRelease(release github.RepositoryRelease) (*github.RepositoryRelease, error) {
	if release.ID == nil {
		return nil, errors.New("release did not have an ID: has it been saved yet?")
	}

	updatedRelease, res, err := g.client.Repositories.EditRelease(context.TODO(), g.owner, g.repository, *release.ID, &release)
	if err != nil {
		return &github.RepositoryRelease{}, err
	}

	err = res.Body.Close()
	if err != nil {
		return nil, err
	}

	return updatedRelease, nil
}

func (g *GitHubClient) ListReleaseAssets(release github.RepositoryRelease) ([]*github.ReleaseAsset, error) {
	opt := &github.ListOptions{PerPage: 100}
	assets, res, err := g.client.Repositories.ListReleaseAssets(context.TODO(), g.owner, g.repository, *release.ID, opt)
	if err != nil {
		return nil, err
	}

	err = res.Body.Close()
	if err != nil {
		return nil, err
	}

	return assets, nil
}

func (g *GitHubClient) UploadReleaseAsset(release github.RepositoryRelease, name string, file *os.File) error {
	_, res, err := g.client.Repositories.UploadReleaseAsset(
		context.TODO(),
		g.owner,
		g.repository,
		*release.ID,
		&github.UploadOptions{
			Name: name,
		},
		file,
	)
	if err != nil {
		return err
	}

	return res.Body.Close()
}

func (g *GitHubClient) DeleteReleaseAsset(asset github.ReleaseAsset) error {
	res, err := g.client.Repositories.DeleteReleaseAsset(context.TODO(), g.owner, g.repository, *asset.ID)
	if err != nil {
		return err
	}

	return res.Body.Close()
}

func (g *GitHubClient) DownloadReleaseAsset(asset github.ReleaseAsset) (io.ReadCloser, error) {
	bodyReader, redirectURL, err := g.client.Repositories.DownloadReleaseAsset(context.TODO(), g.owner, g.repository, *asset.ID, nil)
	if err != nil {
		return nil, err
	}

	if redirectURL == "" {
		return bodyReader, err
	}

	req, err := g.client.NewRequest("GET", redirectURL, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Accept", "application/octet-stream")
	if g.accessToken != "" && req.URL.Host == g.client.BaseURL.Host {
		req.Header.Set("Authorization", "Bearer "+g.accessToken)
	}

	httpClient := &http.Client{}
	resp, err := httpClient.Do(req)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode < 200 || resp.StatusCode > 299 {
		resp.Body.Close()
		return nil, fmt.Errorf("redirect URL %q responded with bad status code: %d", redirectURL, resp.StatusCode)
	}

	return resp.Body, nil
}

func (g *GitHubClient) GetTarballLink(tag string) (*url.URL, error) {
	opt := &github.RepositoryContentGetOptions{Ref: tag}
	u, res, err := g.client.Repositories.GetArchiveLink(context.TODO(), g.owner, g.repository, github.Tarball, opt, true)
	if err != nil {
		return nil, err
	}
	res.Body.Close()
	return u, nil
}

func (g *GitHubClient) GetZipballLink(tag string) (*url.URL, error) {
	opt := &github.RepositoryContentGetOptions{Ref: tag}
	u, res, err := g.client.Repositories.GetArchiveLink(context.TODO(), g.owner, g.repository, github.Zipball, opt, true)
	if err != nil {
		return nil, err
	}
	res.Body.Close()
	return u, nil
}

func (g *GitHubClient) ResolveTagToCommitSHA(tagName string) (string, error) {
	ref, res, err := g.client.Git.GetRef(context.TODO(), g.owner, g.repository, "tags/"+tagName)

	if err != nil {
		return "", err
	}

	res.Body.Close()

	// Lightweight tag
	if *ref.Object.Type == "commit" {
		return *ref.Object.SHA, nil
	}

	// Fail if we're not pointing to a annotated tag
	if *ref.Object.Type != "tag" {
		return "", fmt.Errorf("could not resolve tag %q to commit: returned type is not 'commit' or 'tag'", tagName)
	}

	// Resolve tag to commit sha
	tag, res, err := g.client.Git.GetTag(context.TODO(), g.owner, g.repository, *ref.Object.SHA)

	if err != nil {
		return "", err
	}

	res.Body.Close()

	if *tag.Object.Type != "commit" {
		return "", fmt.Errorf("could not resolve tag %q to commit: returned type is not 'commit'", tagName)
	}

	return *tag.Object.SHA, nil
}

func oauthClient(ctx context.Context, source Source) (*http.Client, error) {
	ts := oauth2.StaticTokenSource(&oauth2.Token{
		AccessToken: source.AccessToken,
	})

	oauthClient := oauth2.NewClient(ctx, ts)

	githubHTTPClient := &http.Client{
		Transport: oauthClient.Transport,
	}

	return githubHTTPClient, nil
}
<|endoftext|>


<commit_before>package gddoexp

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

// httpClient contains all used methods to perform requests in Github API.
// This is useful for mocking and building tests.
type httpClient interface {
	Get(string) (*http.Response, error)
}

// HTTPClient is going to be used to perform the Github HTTP requests. We use
// a global variable, as it is safe for concurrent use by multiple goroutines
var HTTPClient httpClient

// IsCacheResponse detects if a HTTP response was retrieved from cache or
// not.
var IsCacheResponse func(*http.Response) bool

func init() {
	HTTPClient = new(http.Client)
}

// githubInfo stores the information of a repository. For more information
// check: https://developer.github.com/v3/repos/
type githubInfo struct {
	CreatedAt       time.Time `json:"created_at"`
	Fork            bool      `json:"fork"`
	ForksCount      int       `json:"forks_count"`
	NetworkCount    int       `json:"network_count"`
	StargazersCount int       `json:"stargazers_count"`
	UpdatedAt       time.Time `json:"updated_at"`
}

// GithubAuth store the authentication information to allow a less
// restrictive rate limit in Github API. Authenticated requests can make up
// to 5000 requests per hour, otherwise you will be limited in 60 requests
// per hour (https://developer.github.com/v3/#rate-limiting).
type GithubAuth struct {
	ID     string
	Secret string
}

// getGithubInfo will retrieve the path project information. For a better
// rate limit the requests must be authenticated, for more information check:
// https://developer.github.com/v3/search/#rate-limit. This function also
// returns if the response was retrieved from a local cache.
func getGithubInfo(path string, auth *GithubAuth) (info githubInfo, cache bool, err error) {
	if !strings.HasPrefix(path, "github.com/") {
		return info, false, NewError(path, ErrorCodeNonGithub, nil)
	}

	normalizedPath := strings.TrimPrefix(path, "github.com/")
	normalizedPath = strings.Join(strings.Split(normalizedPath, "/")[:2], "/")

	var url string

	if auth == nil {
		url = "https://api.github.com/repos/" + normalizedPath
	} else {
		url = fmt.Sprintf("https://api.github.com/repos/%s?client_id=%s&client_secret=%s",
			normalizedPath, auth.ID, auth.Secret)
	}

	rsp, err := HTTPClient.Get(url)
	if err != nil {
		return info, false, NewError(path, ErrorCodeGithubFetch, err)
	}
	defer func() {
		if rsp.Body != nil {
			// for now we aren't checking the error
			rsp.Body.Close()
		}
	}()

	if rsp.StatusCode != http.StatusOK {
		return info, false, NewError(path, ErrorCodeGithubStatusCode, nil)
	}

	decoder := json.NewDecoder(rsp.Body)
	if err := decoder.Decode(&info); err != nil {
		return info, false, NewError(path, ErrorCodeGithubParse, err)
	}

	if IsCacheResponse != nil {
		cache = IsCacheResponse(rsp)
	}

	return info, cache, nil
}
<commit_msg>GithubAuth must known how to build itself<commit_after>package gddoexp

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

// httpClient contains all used methods to perform requests in Github API.
// This is useful for mocking and building tests.
type httpClient interface {
	Get(string) (*http.Response, error)
}

// HTTPClient is going to be used to perform the Github HTTP requests. We use
// a global variable, as it is safe for concurrent use by multiple goroutines
var HTTPClient httpClient

// IsCacheResponse detects if a HTTP response was retrieved from cache or
// not.
var IsCacheResponse func(*http.Response) bool

func init() {
	HTTPClient = new(http.Client)
}

// githubInfo stores the information of a repository. For more information
// check: https://developer.github.com/v3/repos/
type githubInfo struct {
	CreatedAt       time.Time `json:"created_at"`
	Fork            bool      `json:"fork"`
	ForksCount      int       `json:"forks_count"`
	NetworkCount    int       `json:"network_count"`
	StargazersCount int       `json:"stargazers_count"`
	UpdatedAt       time.Time `json:"updated_at"`
}

// GithubAuth store the authentication information to allow a less
// restrictive rate limit in Github API. Authenticated requests can make up
// to 5000 requests per hour, otherwise you will be limited in 60 requests
// per hour (https://developer.github.com/v3/#rate-limiting).
type GithubAuth struct {
	ID     string
	Secret string
}

// String build the Github authentication in the request query string format.
func (g GithubAuth) String() string {
	return fmt.Sprintf("client_id=%s&client_secret=%s", g.ID, g.Secret)
}

// getGithubInfo will retrieve the path project information. For a better
// rate limit the requests must be authenticated, for more information check:
// https://developer.github.com/v3/search/#rate-limit. This function also
// returns if the response was retrieved from a local cache.
func getGithubInfo(path string, auth *GithubAuth) (info githubInfo, cache bool, err error) {
	if !strings.HasPrefix(path, "github.com/") {
		return info, false, NewError(path, ErrorCodeNonGithub, nil)
	}

	normalizedPath := strings.TrimPrefix(path, "github.com/")
	normalizedPath = strings.Join(strings.Split(normalizedPath, "/")[:2], "/")

	var url string

	if auth == nil {
		url = "https://api.github.com/repos/" + normalizedPath
	} else {
		url = fmt.Sprintf("https://api.github.com/repos/%s?%s", normalizedPath, auth)
	}

	rsp, err := HTTPClient.Get(url)
	if err != nil {
		return info, false, NewError(path, ErrorCodeGithubFetch, err)
	}
	defer func() {
		if rsp.Body != nil {
			// for now we aren't checking the error
			rsp.Body.Close()
		}
	}()

	if rsp.StatusCode != http.StatusOK {
		return info, false, NewError(path, ErrorCodeGithubStatusCode, nil)
	}

	decoder := json.NewDecoder(rsp.Body)
	if err := decoder.Decode(&info); err != nil {
		return info, false, NewError(path, ErrorCodeGithubParse, err)
	}

	if IsCacheResponse != nil {
		cache = IsCacheResponse(rsp)
	}

	return info, cache, nil
}
<|endoftext|>


<commit_before>/*
Package goJson implements a simple library for json parsing.
*/
package goJson

import (
	"bytes"
	"encoding/json"
	"reflect"
)

func ParseJson(b []byte) (*Root, error) {
	r := bytes.NewReader(b)
	j := new(Root)
	var Val map[string]interface{}
	err := json.NewDecoder(r).Decode(&Val)
	j.Val = Val
	return j, err
}

type Root struct {
	Val interface{}
}

func (r *Root) Get(Name string) *Root {
	currentItem := r.Val.(map[string]interface{})[Name]
	root := new(Root)
	root.Val = currentItem.(map[string]interface{})
	return root
}

func (r *Root) GetAll(Name string) ([]*Root, error) {
	currentItem := r.Val.(map[string]interface{})[Name]
	result := []*Root{}
	if reflect.TypeOf(currentItem) != "map[string]interface {}" {
            return nil, errors.New(name+" is not array!")
        }
	items := currentItem.([]interface{})
	for _, elem := range items {
		root := new(Root)
		root.Val = elem
		result = append(result, root)
	}
	return result, nil
}

func (r *Root) String(Name string) string {
	return r.Val.(map[string]interface{})[Name].(string)
}

func (r *Root) Float(Name string) float64 {
	return r.Val.(map[string]interface{})[Name].(float64)
}

func (r *Root) Int(Name string) int {
	return int(r.Val.(map[string]interface{})[Name].(float64))
}

func (r *Root) Strings(Name string) []string {
	s := reflect.ValueOf(r.Val.(map[string]interface{})[Name])
	arr := make([]string, s.Len())
	for i := 0; i < s.Len(); i++ {
		arr[i] = s.Index(i).Interface().(string)
	}
	return arr
}
<commit_msg>error<commit_after>/*
Package goJson implements a simple library for json parsing.
*/
package goJson

import (
	"bytes"
	"encoding/json"
	"reflect"
)

func ParseJson(b []byte) (*Root, error) {
	r := bytes.NewReader(b)
	j := new(Root)
	var Val map[string]interface{}
	err := json.NewDecoder(r).Decode(&Val)
	j.Val = Val
	return j, err
}

type Root struct {
	Val interface{}
}

func (r *Root) Get(Name string) *Root {
	currentItem := r.Val.(map[string]interface{})[Name]
	root := new(Root)
	root.Val = currentItem.(map[string]interface{})
	return root
}

func (r *Root) GetAll(Name string) ([]*Root, error) {
	currentItem := r.Val.(map[string]interface{})[Name]
	result := []*Root{}
	if reflect.TypeOf(currentItem) != map[string]interface{} {
            return nil, errors.New(name+" is not array!")
        }
	items := currentItem.([]interface{})
	for _, elem := range items {
		root := new(Root)
		root.Val = elem
		result = append(result, root)
	}
	return result, nil
}

func (r *Root) String(Name string) string {
	return r.Val.(map[string]interface{})[Name].(string)
}

func (r *Root) Float(Name string) float64 {
	return r.Val.(map[string]interface{})[Name].(float64)
}

func (r *Root) Int(Name string) int {
	return int(r.Val.(map[string]interface{})[Name].(float64))
}

func (r *Root) Strings(Name string) []string {
	s := reflect.ValueOf(r.Val.(map[string]interface{})[Name])
	arr := make([]string, s.Len())
	for i := 0; i < s.Len(); i++ {
		arr[i] = s.Index(i).Interface().(string)
	}
	return arr
}
<|endoftext|>


<commit_before>package gobolt

import (
	"encoding/json"
	"errors"
	"fmt"

	"github.com/boltdb/bolt"
	//"github.com/gorilla/schema"
)

// Data base location settings
type GoBoltConf struct {
	Path string
}

// Gobolt struct
type Gobolt struct {
	gb *bolt.DB
}

// Bucket data struct
type BucketData struct {
	Key  string
	Data interface{}
}

// Open database
func (gbase *Gobolt) Open(gbc GoBoltConf) error {
	var err error

	// ToDo: in safe mode don't create database if it's not exist.
	gbase.gb, err = bolt.Open(gbc.Path, 0644, nil)

	return err
}

// Safe close database.
// Don't forget to use it after opening.
// Ex.: defer database.Close()
func (gbase *Gobolt) Close() {
	gbase.gb.Close()
}

// Get list of all buckets in the database
func (gbase *Gobolt) GetBucketList() ([]string, error) {
	var buckets []string

	err := gbase.gb.View(func(tx *bolt.Tx) error {
		return tx.ForEach(func(name []byte, _ *bolt.Bucket) error {
			buckets = append(buckets, string(name))
			return nil
		})
	})

	return buckets, err
}

// Create new bucket
func (gbase *Gobolt) CreateBucket(bucket_name string) (*bolt.Bucket, error) {
	bucket := new(bolt.Bucket)
	err := gbase.gb.Update(func(tx *bolt.Tx) error {
		var err error
		bucket, err = tx.CreateBucketIfNotExists([]byte(bucket_name))
		return err
	})
	return bucket, err
}

// Get all data from bucket
func (gbase *Gobolt) GetBucketData(bucket_name string) (interface{}, error) {
	var bucket_data_list []BucketData

	err := gbase.gb.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket([]byte(bucket_name))
		if bucket == nil {
			return fmt.Errorf("Bucket %q not found!", bucket_name)
		}

		err := bucket.ForEach(func(k, v []byte) error {
			var bucket_data BucketData
			bucket_data.Key = string(k[:])

			err := json.Unmarshal(v, &bucket_data.Data)
			if err != nil {
				return err
			}

			bucket_data_list = append(bucket_data_list, bucket_data)
			return nil
		})

		return err
	})

	return bucket_data_list, err
}

// Create new object in bucket or rewrite existing (safe mode enabled)
func (gbase *Gobolt) SetByKey(bucket_name string, key_name string, obj interface{}) error {
	err := gbase.gb.Update(func(tx *bolt.Tx) error {
		bucket, err := tx.CreateBucketIfNotExists([]byte(bucket_name))
		if err != nil {
			return err
		}

		//id, _ := bucket.NextSequence()
		//obj.ID = int(id)
		id := []byte(key_name)

		buf, err := json.Marshal(obj)
		if err != nil {
			return err
		}

		err = bucket.Put(id, buf)
		if err != nil {
			return err
		}

		return nil
	})

	return err
}

// Get object by key
func (gbase *Gobolt) GetByKey(bucket_name string, key_name string, obj interface{}) error {
	err := gbase.gb.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket([]byte(bucket_name))
		if bucket == nil {
			return fmt.Errorf("Bucket %s not found!", bucket_name)
		}
		v := bucket.Get([]byte(key_name))
		if v != nil {
			err := json.Unmarshal(v, &obj)
			if err != nil {
				return err
			}
			return nil
		}
		err := errors.New("Key: '" + key_name + "' not found")

		return err
	})
	return err
}

// Delete object from bucket
func (gbase *Gobolt) Delete(bucket_name string, key_name string) error {
	err := gbase.gb.Update(func(tx *bolt.Tx) error {
		return tx.Bucket([]byte(bucket_name)).Delete([]byte(key_name))
	})
	return err
}

// Get next sequence for the bucket
func (gbase *Gobolt) GetNextSequence(bucket_name string) (int, error) {
	var id int
	err := gbase.gb.Update(func(tx *bolt.Tx) error {
		bucket, err := tx.CreateBucketIfNotExists([]byte(bucket_name))
		if err != nil {
			return err
		}

		data_id, _ := bucket.NextSequence()
		id = int(data_id)
		return nil
	})
	return id, err
}

// type mySubObject struct {
// 	F1 string `json:"F1"`
// 	F2 string
// }

// type myObject struct {
// 	F1 string
// 	F2 string
// 	F3 mySubObject
// }

// func main() {
// 	var gbc GoBoltConf
// 	var bname1 = "bucket_one"
// 	var bname2 = "bucket_two"

// 	gbc.Path = "testdb.bdb"

// 	db := new(Gobolt)
// 	err := db.Open(gbc)
// 	if err != nil {
// 		fmt.Println(err.Error())
// 	}

// 	_, err = db.CreateBucket(bname1)
// 	if err != nil {
// 		fmt.Println(err.Error())
// 	}

// 	_, err = db.CreateBucket(bname2)
// 	if err != nil {
// 		fmt.Println(err.Error())
// 	}

// 	mo1 := myObject{F1: "aa", F2: "ab", F3: mySubObject{F1: "aca", F2: "acb"}}
// 	mo2 := myObject{F1: "ba", F2: "bb", F3: mySubObject{F1: "bca", F2: "bcb"}}
// 	mo3 := myObject{F1: "ca", F2: "cb", F3: mySubObject{F1: "cca", F2: "ccb"}}

// 	err = db.SetByKey(bname1, "mo1", mo1)
// 	if err != nil {
// 		fmt.Println(err.Error())
// 	}

// 	err = db.SetByKey(bname1, "mo2", mo2)
// 	if err != nil {
// 		fmt.Println(err.Error())
// 	}

// 	err = db.SetByKey(bname1, "mo3", mo3)
// 	if err != nil {
// 		fmt.Println(err.Error())
// 	}

// 	err = db.SetByKey(bname2, "mo1", mo1)
// 	if err != nil {
// 		fmt.Println(err.Error())
// 	}

// 	err = db.SetByKey(bname2, "mo2", mo2)
// 	if err != nil {
// 		fmt.Println(err.Error())
// 	}

// 	err = db.SetByKey(bname2, "mo3", mo3)
// 	if err != nil {
// 		fmt.Println(err.Error())
// 	}

// 	// var list interface{}
// 	// list, err = db.GetBucketList()
// 	// if err != nil {
// 	// 	fmt.Println(err.Error())
// 	// } else {
// 	// 	fmt.Println("readed from db:")
// 	// 	fmt.Println(list)
// 	// }

// 	// var bucket_data interface{}
// 	// bucket_data, err = db.GetBucketData(bname1)
// 	// if err != nil {
// 	// 	fmt.Println("error: " + err.Error())
// 	// } else {
// 	// 	fmt.Printf("bucket1: %q\n", bucket_data)
// 	// }

// 	// bucket_data, err = db.GetBucketData(bname2)
// 	// if err != nil {
// 	// 	fmt.Println("error: " + err.Error())
// 	// } else {
// 	// 	fmt.Printf("bucket2: %q\n", bucket_data)
// 	// }

// 	var mo myObject
// 	err = db.GetByKey(bname1, "mo1", &mo)
// 	if err != nil {
// 		fmt.Println("error: " + err.Error())
// 	} else {
// 		fmt.Printf("GetByKey: mo1 ==  %q\n", mo)
// 		fmt.Printf("mo.F1: %s\n", mo.F1)
// 		fmt.Printf("mo.F2: %s\n", mo.F2)
// 	}

// 	err = db.Delete(bname1, "mo1")
// 	if err != nil {
// 		fmt.Println("error: " + err.Error())
// 	}

// 	err = db.GetByKey(bname1, "mo1", &mo)
// 	if err != nil {
// 		fmt.Println("error: " + err.Error())
// 	} else {
// 		fmt.Printf("GetByKey: mo1 ==  %q\n", mo)
// 		fmt.Printf("mo.F1: %s\n", mo.F1)
// 		fmt.Printf("mo.F2: %s\n", mo.F2)
// 	}
// }
<commit_msg>Fix:GetNewSequence: return null pointer<commit_after>package gobolt

import (
	"encoding/json"
	"errors"
	"fmt"

	"github.com/boltdb/bolt"
	//"github.com/gorilla/schema"
)

// Data base location settings
type GoBoltConf struct {
	Path string
}

// Gobolt struct
type Gobolt struct {
	gb *bolt.DB
}

// Bucket data struct
type BucketData struct {
	Key  string
	Data interface{}
}

// Open database
func (gbase *Gobolt) Open(gbc GoBoltConf) error {
	var err error

	// ToDo: in safe mode don't create database if it's not exist.
	gbase.gb, err = bolt.Open(gbc.Path, 0644, nil)

	return err
}

// Safe close database.
// Don't forget to use it after opening.
// Ex.: defer database.Close()
func (gbase *Gobolt) Close() {
	gbase.gb.Close()
}

// Get list of all buckets in the database
func (gbase *Gobolt) GetBucketList() ([]string, error) {
	var buckets []string

	err := gbase.gb.View(func(tx *bolt.Tx) error {
		return tx.ForEach(func(name []byte, _ *bolt.Bucket) error {
			buckets = append(buckets, string(name))
			return nil
		})
	})

	return buckets, err
}

// Create new bucket
func (gbase *Gobolt) CreateBucket(bucket_name string) (*bolt.Bucket, error) {
	bucket := new(bolt.Bucket)
	err := gbase.gb.Update(func(tx *bolt.Tx) error {
		var err error
		bucket, err = tx.CreateBucketIfNotExists([]byte(bucket_name))
		return err
	})
	return bucket, err
}

// Get all data from bucket
func (gbase *Gobolt) GetBucketData(bucket_name string) (interface{}, error) {
	var bucket_data_list []BucketData

	err := gbase.gb.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket([]byte(bucket_name))
		if bucket == nil {
			return fmt.Errorf("Bucket %q not found!", bucket_name)
		}

		err := bucket.ForEach(func(k, v []byte) error {
			var bucket_data BucketData
			bucket_data.Key = string(k[:])

			err := json.Unmarshal(v, &bucket_data.Data)
			if err != nil {
				return err
			}

			bucket_data_list = append(bucket_data_list, bucket_data)
			return nil
		})

		return err
	})

	return bucket_data_list, err
}

// Create new object in bucket or rewrite existing (safe mode enabled)
func (gbase *Gobolt) SetByKey(bucket_name string, key_name string, obj interface{}) error {
	err := gbase.gb.Update(func(tx *bolt.Tx) error {
		bucket, err := tx.CreateBucketIfNotExists([]byte(bucket_name))
		if err != nil {
			return err
		}

		//id, _ := bucket.NextSequence()
		//obj.ID = int(id)
		id := []byte(key_name)

		buf, err := json.Marshal(obj)
		if err != nil {
			return err
		}

		err = bucket.Put(id, buf)
		if err != nil {
			return err
		}

		return nil
	})

	return err
}

// Get object by key
func (gbase *Gobolt) GetByKey(bucket_name string, key_name string, obj interface{}) error {
	err := gbase.gb.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket([]byte(bucket_name))
		if bucket == nil {
			return fmt.Errorf("Bucket %s not found!", bucket_name)
		}
		v := bucket.Get([]byte(key_name))
		if v != nil {
			err := json.Unmarshal(v, &obj)
			if err != nil {
				return err
			}
			return nil
		}
		err := errors.New("Key: '" + key_name + "' not found")

		return err
	})
	return err
}

// Delete object from bucket
func (gbase *Gobolt) Delete(bucket_name string, key_name string) error {
	err := gbase.gb.Update(func(tx *bolt.Tx) error {
		return tx.Bucket([]byte(bucket_name)).Delete([]byte(key_name))
	})
	return err
}

// Get next sequence for the bucket
func (gbase *Gobolt) GetNextSequence(bucket_name string) (int, error) {
	var id int
	err := gbase.gb.Update(func(tx *bolt.Tx) error {
		bucket, err := tx.CreateBucketIfNotExists([]byte(bucket_name))
		if err != nil {
			return err
		}

		data_id, _ := bucket.NextSequence()
		id = int(data_id)
		return nil
	})
	if err != nil {
		return nil, err
	} else {
		return id, nil
	}
}

// type mySubObject struct {
// 	F1 string `json:"F1"`
// 	F2 string
// }

// type myObject struct {
// 	F1 string
// 	F2 string
// 	F3 mySubObject
// }

// func main() {
// 	var gbc GoBoltConf
// 	var bname1 = "bucket_one"
// 	var bname2 = "bucket_two"

// 	gbc.Path = "testdb.bdb"

// 	db := new(Gobolt)
// 	err := db.Open(gbc)
// 	if err != nil {
// 		fmt.Println(err.Error())
// 	}

// 	_, err = db.CreateBucket(bname1)
// 	if err != nil {
// 		fmt.Println(err.Error())
// 	}

// 	_, err = db.CreateBucket(bname2)
// 	if err != nil {
// 		fmt.Println(err.Error())
// 	}

// 	mo1 := myObject{F1: "aa", F2: "ab", F3: mySubObject{F1: "aca", F2: "acb"}}
// 	mo2 := myObject{F1: "ba", F2: "bb", F3: mySubObject{F1: "bca", F2: "bcb"}}
// 	mo3 := myObject{F1: "ca", F2: "cb", F3: mySubObject{F1: "cca", F2: "ccb"}}

// 	err = db.SetByKey(bname1, "mo1", mo1)
// 	if err != nil {
// 		fmt.Println(err.Error())
// 	}

// 	err = db.SetByKey(bname1, "mo2", mo2)
// 	if err != nil {
// 		fmt.Println(err.Error())
// 	}

// 	err = db.SetByKey(bname1, "mo3", mo3)
// 	if err != nil {
// 		fmt.Println(err.Error())
// 	}

// 	err = db.SetByKey(bname2, "mo1", mo1)
// 	if err != nil {
// 		fmt.Println(err.Error())
// 	}

// 	err = db.SetByKey(bname2, "mo2", mo2)
// 	if err != nil {
// 		fmt.Println(err.Error())
// 	}

// 	err = db.SetByKey(bname2, "mo3", mo3)
// 	if err != nil {
// 		fmt.Println(err.Error())
// 	}

// 	// var list interface{}
// 	// list, err = db.GetBucketList()
// 	// if err != nil {
// 	// 	fmt.Println(err.Error())
// 	// } else {
// 	// 	fmt.Println("readed from db:")
// 	// 	fmt.Println(list)
// 	// }

// 	// var bucket_data interface{}
// 	// bucket_data, err = db.GetBucketData(bname1)
// 	// if err != nil {
// 	// 	fmt.Println("error: " + err.Error())
// 	// } else {
// 	// 	fmt.Printf("bucket1: %q\n", bucket_data)
// 	// }

// 	// bucket_data, err = db.GetBucketData(bname2)
// 	// if err != nil {
// 	// 	fmt.Println("error: " + err.Error())
// 	// } else {
// 	// 	fmt.Printf("bucket2: %q\n", bucket_data)
// 	// }

// 	var mo myObject
// 	err = db.GetByKey(bname1, "mo1", &mo)
// 	if err != nil {
// 		fmt.Println("error: " + err.Error())
// 	} else {
// 		fmt.Printf("GetByKey: mo1 ==  %q\n", mo)
// 		fmt.Printf("mo.F1: %s\n", mo.F1)
// 		fmt.Printf("mo.F2: %s\n", mo.F2)
// 	}

// 	err = db.Delete(bname1, "mo1")
// 	if err != nil {
// 		fmt.Println("error: " + err.Error())
// 	}

// 	err = db.GetByKey(bname1, "mo1", &mo)
// 	if err != nil {
// 		fmt.Println("error: " + err.Error())
// 	} else {
// 		fmt.Printf("GetByKey: mo1 ==  %q\n", mo)
// 		fmt.Printf("mo.F1: %s\n", mo.F1)
// 		fmt.Printf("mo.F2: %s\n", mo.F2)
// 	}
// }
<|endoftext|>


<commit_before>package goddos

import (
	"net/http"
	"strings"

	"github.com/pilu/traffic"
)

var (
	uriFragments map[uint8]string
)

func init() {
	uriFragments = make(map[string]bool)
	uriFragments["manager/html"] = true
	uriFragments["POST_ip_port.php"] = true
	uriFragments["tmUnblock.cgi"] = true
	uriFragments["HNAP1"] = true
	uriFragments["phpMyAdmin/scripts/setup.php"] = true
	uriFragments["pma/scripts/setup.php"] = true
	uriFragments["myadmin/scripts/setup.php"] = true
	uriFragments["MyAdmin/scripts/setup.php"] = true
	uriFragments["vyvy/vyv/vy.php"] = true
	uriFragments["cgi-sys/php5"] = true
	uriFragments["cgi-bin/test-cgi"] = true
	uriFragments["cgi-bin/printenv"] = true
	uriFragments["cgi-bin/test.cgi"] = true
	uriFragments["cgi-bin/test.pl"] = true
	uriFragments["cgi-bin/test.sh"] = true
	uriFragments["cgi-bin/teste.pl"] = true
	uriFragments["cgi-bin/teste.cgi"] = true
	uriFragments["cgi-bin/teste.sh"] = true
	uriFragments["cgi-bin/print-env"] = true
	uriFragments["cgi-bin/print.pl"] = true
	uriFragments["cgi-bin/print.cgi"] = true
	uriFragments["cgi-bin/printenv.sh"] = true
	uriFragments["dpdp/dpd/dp.php"] = true
	uriFragments["upup/upu/up.php"] = true
	uriFragments["admin/fckeditor/editor/filemanager/browser/default/connectors/test.html"] = true
	uriFragments["web-console/ServerInfo.jsp"] = true
	uriFragments["vtigercrm"] = true
	uriFragments["operator/basic.shtml"] = true
	uriFragments["secure/ltx_conf.htm"] = true
	uriFragments["syslog.htm"] = true
}

func main() {

}

func CheckForDdosString(w traffic.ResponseWriter, r *traffic.Request) {
	for k, _ := range uriFragments {
		if strings.Contains(k, r.RequestURI) {
			w.WriteHeader(http.StatusGatewayTimeout)
			w.WriteText("connection timed out")
		}
	}
}
<commit_msg>forgot to change the var declaration of the map<commit_after>package goddos

import (
	"net/http"
	"strings"

	"github.com/pilu/traffic"
)

var (
	uriFragments map[string]bool
)

func init() {
	uriFragments = make(map[string]bool)
	uriFragments["manager/html"] = true
	uriFragments["POST_ip_port.php"] = true
	uriFragments["tmUnblock.cgi"] = true
	uriFragments["HNAP1"] = true
	uriFragments["phpMyAdmin/scripts/setup.php"] = true
	uriFragments["pma/scripts/setup.php"] = true
	uriFragments["myadmin/scripts/setup.php"] = true
	uriFragments["MyAdmin/scripts/setup.php"] = true
	uriFragments["vyvy/vyv/vy.php"] = true
	uriFragments["cgi-sys/php5"] = true
	uriFragments["cgi-bin/test-cgi"] = true
	uriFragments["cgi-bin/printenv"] = true
	uriFragments["cgi-bin/test.cgi"] = true
	uriFragments["cgi-bin/test.pl"] = true
	uriFragments["cgi-bin/test.sh"] = true
	uriFragments["cgi-bin/teste.pl"] = true
	uriFragments["cgi-bin/teste.cgi"] = true
	uriFragments["cgi-bin/teste.sh"] = true
	uriFragments["cgi-bin/print-env"] = true
	uriFragments["cgi-bin/print.pl"] = true
	uriFragments["cgi-bin/print.cgi"] = true
	uriFragments["cgi-bin/printenv.sh"] = true
	uriFragments["dpdp/dpd/dp.php"] = true
	uriFragments["upup/upu/up.php"] = true
	uriFragments["admin/fckeditor/editor/filemanager/browser/default/connectors/test.html"] = true
	uriFragments["web-console/ServerInfo.jsp"] = true
	uriFragments["vtigercrm"] = true
	uriFragments["operator/basic.shtml"] = true
	uriFragments["secure/ltx_conf.htm"] = true
	uriFragments["syslog.htm"] = true
}

func main() {

}

func CheckForDdosString(w traffic.ResponseWriter, r *traffic.Request) {
	for k, _ := range uriFragments {
		if strings.Contains(k, r.RequestURI) {
			w.WriteHeader(http.StatusGatewayTimeout)
			w.WriteText("connection timed out")
		}
	}
}
<|endoftext|>


<commit_before>package main
// Author: Robert B Frangioso

import (
	"path/filepath"
	"os"
	"flag"
	"fmt"
	"io/ioutil"
	"sync"
	"os/exec"
	"bytes"
	"strconv"
)

type msg_type int

const (
	OUTPUT msg_type = 1 + iota
	ERROR
	CLOSE
)

type output_msg struct {
	mtype	msg_type
	buffer	bytes.Buffer
}

func find(root string, wg *sync.WaitGroup, flags []string, args []string, output chan output_msg) {

	defer wg.Done()
	var cmd_out, cmd_err bytes.Buffer
	var msg output_msg

	findstr := append(append(append([]string{}, flags... ), []string{root}... ), args... )
	cmd := exec.Command("find", findstr... )
	cmd.Stdout = &cmd_out
	cmd.Stderr = &cmd_err
	err := cmd.Run()

	if err == nil {
		msg.mtype = OUTPUT
		msg.buffer = cmd_out
		output <- msg
	} else {
		msg.mtype = ERROR
		msg.buffer = cmd_err
		output <- msg
	}

	return
}

func aggregator(wg *sync.WaitGroup, input chan output_msg) {

	defer wg.Done()
	var msg output_msg

	for true {
		msg = <- input
		switch msg.mtype {
		case CLOSE:
			return
		case OUTPUT:
			if msg.buffer.Len() > 0 {
				fmt.Printf("%s", msg.buffer.String())
			}
		case ERROR:
			if msg.buffer.Len() > 0 {
				fmt.Fprintf(os.Stderr, "%s", msg.buffer.String())
			}
		default:
		}
	}

}

func parseflags() []string {

	osx_find_flags := []string{"L", "H", "P", "E", "X", "d", "s", "x"}
	set_flags := []string{}

	for f := range osx_find_flags {
		flag.Bool(osx_find_flags[f], false, "bool")
	}

	flag.Parse()
	for f := range osx_find_flags {
		flag_p := flag.Lookup(osx_find_flags[f])
		val, err := strconv.ParseBool(flag_p.Value.String())
		if err == nil && val == true {
			set_flags = append(set_flags, "-"+flag_p.Name)
		}
	}

	return set_flags
}

func main() {

	var wg, wga sync.WaitGroup
	msg_channel := make(chan output_msg)

	set_flags := parseflags()

	argslice := flag.Args()
	root := argslice[0]
	basedirs, direrr := ioutil.ReadDir(root)

	if(direrr != nil) {
		fmt.Printf("ReadDir err %v \n", direrr)
		fmt.Printf("Usage: gofind rootsearchdir <other-find-args> \n")
		return
	}

	shallowfind := append(append([]string{},[]string{"-maxdepth", "1"}... ), argslice[1:]... )
	wg.Add(1)
	go find(root, &wg, set_flags, shallowfind, msg_channel)

	for  dir := range basedirs {
		if basedirs[dir].IsDir() {
			wg.Add(1)
			go find(filepath.Join(root, basedirs[dir].Name()), &wg, set_flags, argslice[1:], msg_channel)
		}
	}

	wga.Add(1)
	go aggregator(&wga, msg_channel)
	wg.Wait()

	msg_channel <- output_msg{CLOSE, bytes.Buffer{}}
	wga.Wait()
}

<commit_msg>add -f<commit_after>package main
// Author: Robert B Frangioso

import (
	"path/filepath"
	"os"
	"flag"
	"fmt"
	"io/ioutil"
	"sync"
	"os/exec"
	"bytes"
	"strconv"
)

type msg_type int

const (
	OUTPUT msg_type = 1 + iota
	ERROR
	CLOSE
)

type output_msg struct {
	mtype	msg_type
	buffer	bytes.Buffer
}

func find(root string, wg *sync.WaitGroup, flags []string, args []string, output chan output_msg) {

	defer wg.Done()
	var cmd_out, cmd_err bytes.Buffer
	var msg output_msg

	findstr := append(append(append([]string{}, flags... ), []string{root}... ), args... )
	cmd := exec.Command("find", findstr... )
	cmd.Stdout = &cmd_out
	cmd.Stderr = &cmd_err
	err := cmd.Run()

	if err == nil {
		msg.mtype = OUTPUT
		msg.buffer = cmd_out
		output <- msg
	} else {
		msg.mtype = ERROR
		msg.buffer = cmd_err
		output <- msg
	}

	return
}

func aggregator(wg *sync.WaitGroup, input chan output_msg) {

	defer wg.Done()
	var msg output_msg

	for true {
		msg = <- input
		switch msg.mtype {
		case CLOSE:
			return
		case OUTPUT:
			if msg.buffer.Len() > 0 {
				fmt.Printf("%s", msg.buffer.String())
			}
		case ERROR:
			if msg.buffer.Len() > 0 {
				fmt.Fprintf(os.Stderr, "%s", msg.buffer.String())
			}
		default:
		}
	}

}

func parseflags() []string {

	osx_find_flags := []string{"L", "H", "P", "E", "X", "d", "s", "x", "f"}
	set_flags := []string{}

	for f := range osx_find_flags {
		flag.Bool(osx_find_flags[f], false, "bool")
	}

	flag.Parse()
	for f := range osx_find_flags {
		flag_p := flag.Lookup(osx_find_flags[f])
		val, err := strconv.ParseBool(flag_p.Value.String())
		if err == nil && val == true {
			set_flags = append(set_flags, "-"+flag_p.Name)
		}
	}

	return set_flags
}

func main() {

	var wg, wga sync.WaitGroup
	msg_channel := make(chan output_msg)

	set_flags := parseflags()

	argslice := flag.Args()
	root := argslice[0]
	basedirs, direrr := ioutil.ReadDir(root)

	if(direrr != nil) {
		fmt.Printf("ReadDir err %v \n", direrr)
		fmt.Printf("Usage: gofind rootsearchdir <other-find-args> \n")
		return
	}

	shallowfind := append(append([]string{},[]string{"-maxdepth", "1"}... ), argslice[1:]... )
	wg.Add(1)
	go find(root, &wg, set_flags, shallowfind, msg_channel)

	for  dir := range basedirs {
		if basedirs[dir].IsDir() {
			wg.Add(1)
			go find(filepath.Join(root, basedirs[dir].Name()), &wg, set_flags, argslice[1:], msg_channel)
		}
	}

	wga.Add(1)
	go aggregator(&wga, msg_channel)
	wg.Wait()

	msg_channel <- output_msg{CLOSE, bytes.Buffer{}}
	wga.Wait()
}

<|endoftext|>


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

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"text/template"

	"errors"

	"github.com/pmezard/go-difflib/difflib"
	"github.com/sergi/go-diff/diffmatchpatch"
)

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

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

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

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

	// defaultDiffEngine sets which diff engine to use if not defined.
	defaultDiffEngine = ClassicDiff

	// defaultIgnoreTemplateErrors sets the default value for the
	// WithIgnoreTemplateErrors option.
	defaultIgnoreTemplateErrors = false

	// defaultUseTestNameForDir sets the default value for the
	// WithTestNameForDir option.
	defaultUseTestNameForDir = false

	// defaultUseSubTestNameForDir sets the default value for the
	// WithSubTestNameForDir option.
	defaultUseSubTestNameForDir = false
)

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

type goldie struct {
	fixtureDir     string
	fileNameSuffix string
	filePerms      os.FileMode
	dirPerms       os.FileMode

	diffEngine           DiffEngine
	diffFn               DiffFn
	ignoreTemplateErrors bool
	useTestNameForDir    bool
	useSubTestNameForDir bool
}

// === Create new testers ==================================

// New creates a new golden file tester. If there is an issue with applying any
// of the options, an error will be reported and t.FailNow() will be called.
func New(t *testing.T, options ...Option) *goldie {
	g := goldie{
		fixtureDir:           defaultFixtureDir,
		fileNameSuffix:       defaultFileNameSuffix,
		filePerms:            defaultFilePerms,
		dirPerms:             defaultDirPerms,
		diffEngine:           defaultDiffEngine,
		ignoreTemplateErrors: defaultIgnoreTemplateErrors,
		useTestNameForDir:    defaultUseTestNameForDir,
		useSubTestNameForDir: defaultUseSubTestNameForDir,
	}

	var err error
	for _, option := range options {
		err = option(&g)
		if err != nil {
			t.Error(fmt.Errorf("Could not apply option: %w", err))
			t.FailNow()
		}
	}

	return &g
}

// Diff generates a string that shows the difference between the actual and the
// expected. This method could be called in your own DiffFn in case you want
// to leverage any of the engines defined.
func Diff(engine DiffEngine, actual string, expected string) string {
	var diff string

	switch engine {
	case Simple:
		diff = fmt.Sprintf("Expected: %s\nGot: %s", expected, actual)

	case ClassicDiff:
		diff, _ = difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
			A:        difflib.SplitLines(expected),
			B:        difflib.SplitLines(actual),
			FromFile: "Expected",
			FromDate: "",
			ToFile:   "Actual",
			ToDate:   "",
			Context:  1,
		})

	case ColoredDiff:
		dmp := diffmatchpatch.New()
		diffs := dmp.DiffMain(actual, expected, false)
		diff = dmp.DiffPrettyText(diffs)
	}

	return diff
}

// === OptionProcessor ===============================

// WithFixtureDir sets the fixture directory.
//
// Defaults to `testdata`
func (g *goldie) WithFixtureDir(dir string) error {
	g.fixtureDir = dir
	return nil
}

// WithNameSuffix sets the file suffix to be used for the golden file.
//
// Defaults to `.golden`
func (g *goldie) WithNameSuffix(suffix string) error {
	g.fileNameSuffix = suffix
	return nil
}

// WithFilePerms sets the file permissions on the golden files that are
// created.
//
// Defaults to 0644.
func (g *goldie) WithFilePerms(mode os.FileMode) error {
	g.filePerms = mode
	return nil
}

// WithDirPerms sets the directory permissions for the directories in which the
// golden files are created.
//
// Defaults to 0755.
func (g *goldie) WithDirPerms(mode os.FileMode) error {
	g.dirPerms = mode
	return nil
}

// WithDiffEngine sets the `diff` engine that will be used to generate the
// `diff` text.
func (g *goldie) WithDiffEngine(engine DiffEngine) error {
	g.diffEngine = engine
	return nil
}

// WithDiffFn sets the `diff` engine to be a function that implements the
// DiffFn signature. This allows for any customized diff logic you would like
// to create.
func (g *goldie) WithDiffFn(fn DiffFn) error {
	g.diffFn = fn
	return nil
}

// WithIgnoreTemplateErrors allows template processing to ignore any variables
// in the template that do not have corresponding data values passed in.
//
// Default value is false.
func (g *goldie) WithIgnoreTemplateErrors(ignoreErrors bool) error {
	g.ignoreTemplateErrors = ignoreErrors
	return nil
}

// WithTestNameForDir will create a directory with the test's name in the
// fixture directory to store all the golden files.
//
// Default value is false.
func (g *goldie) WithTestNameForDir(use bool) error {
	g.useTestNameForDir = use
	return nil
}

// WithSubTestNameForDir will create a directory with the sub test's name to
// store all the golden files. If WithTestNameForDir is enabled, it will be in
// the test name's directory. Otherwise, it will be in the fixture directory.
//
// Default value is false.
func (g *goldie) WithSubTestNameForDir(use bool) error {
	g.useSubTestNameForDir = use
	return nil
}

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

	err := g.compare(t, name, actualData)
	if err != nil {
		{
			var e *errFixtureNotFound
			if errors.As(err, &e) {
				t.Error(err)
				t.FailNow()
				return
			}
		}

		{
			var e *errFixtureMismatch
			if errors.As(err, &e) {
				t.Error(err)
				return
			}
		}

		t.Error(err)
	}
}

// AssertJson compares the actual json data received with expected data in the
// golden files. If the update flag is set, it will also update the golden
// file.
//
// `name` refers to the name of the test and it should typically be unique
// within the package. Also it should be a valid file name (so keeping to
// `a-z0-9\-\_` is a good idea).
func (g *goldie) AssertJson(t *testing.T, name string, actualJsonData interface{}) {
	js, err := json.MarshalIndent(actualJsonData, "", "  ")

	if err != nil {
		t.Error(err)
		t.FailNow()
	}

	g.Assert(t, name, normalizeLF(js))
}

// normalizeLF normalizes line feed character set across os (es)
// \r\n (windows) & \r (mac) into \n (unix)
func normalizeLF(d []byte) []byte {
	// if empty / nil return as is
	if len(d) == 0 {
		return d
	}
	// replace CR LF \r\n (windows) with LF \n (unix)
	d = bytes.Replace(d, []byte{13, 10}, []byte{10}, -1)
	// replace CF \r (mac) with LF \n (unix)
	d = bytes.Replace(d, []byte{13}, []byte{10}, -1)
	return d
}

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

	err := g.compareTemplate(t, name, data, actualData)
	if err != nil {
		{
			var e *errFixtureNotFound
			if errors.As(err, &e) {
				t.Error(err)
				t.FailNow()
				return
			}
		}

		{
			var e *errFixtureMismatch
			if errors.As(err, &e) {
				t.Error(err)
				return
			}
		}

		t.Error(err)
	}
}

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

	return ioutil.WriteFile(g.goldenFileName(t, name), actualData, g.filePerms)
}

// compare is reading the golden fixture file and compare the stored data with
// the actual data.
func (g *goldie) compare(t *testing.T, name string, actualData []byte) error {
	expectedData, err := ioutil.ReadFile(g.goldenFileName(t, name))

	if err != nil {
		if os.IsNotExist(err) {
			return newErrFixtureNotFound()
		}

		return fmt.Errorf("Expected %s to be nil", err.Error())
	}

	if !bytes.Equal(actualData, expectedData) {
		msg := "Result did not match the golden fixture. Diff is below:\n\n"
		actual := string(actualData)
		expected := string(expectedData)

		if g.diffFn != nil {
			msg += g.diffFn(actual, expected)
		} else {
			msg += Diff(g.diffEngine, actual, expected)
		}

		return newErrFixtureMismatch(msg)
	}

	return nil
}

// compareTemplate is reading the golden fixture file and compare the stored
// data with the actual data.
func (g *goldie) compareTemplate(t *testing.T, name string, data interface{}, actualData []byte) error {
	expectedDataTmpl, err := ioutil.ReadFile(g.goldenFileName(t, name))

	if err != nil {
		if os.IsNotExist(err) {
			return newErrFixtureNotFound()
		}

		return fmt.Errorf("Expected %s to be nil", err.Error())
	}

	missingKey := "error"
	if g.ignoreTemplateErrors {
		missingKey = "default"
	}
	tmpl, err := template.New("test").Option("missingkey=" + missingKey).Parse(string(expectedDataTmpl))
	if err != nil {
		return fmt.Errorf("Expected %s to be nil", err.Error())
	}

	var expectedData bytes.Buffer
	err = tmpl.Execute(&expectedData, data)
	if err != nil {
		return newErrMissingKey(fmt.Sprintf("Template error: %s", err.Error()))
	}

	if !bytes.Equal(actualData, expectedData.Bytes()) {
		msg := "Result did not match the golden fixture. Diff is below:\n\n"
		actual := string(actualData)
		expected := expectedData.String()

		if g.diffFn != nil {
			msg += g.diffFn(actual, expected)
		} else {
			msg += Diff(g.diffEngine, actual, expected)
		}

		return newErrFixtureMismatch(msg)
	}

	return nil
}

// ensureDir will create the fixture folder if it does not already exist.
func (g *goldie) ensureDir(loc string) error {
	s, err := os.Stat(loc)
	switch {
	case err != nil && os.IsNotExist(err):
		// the location does not exist, so make directories to there
		return os.MkdirAll(loc, g.dirPerms)
	case err == nil && !s.IsDir():
		return newErrFixtureDirectoryIsFile(loc)
	}

	return err
}

// goldenFileName simply returns the file name of the golden file fixture.
func (g *goldie) goldenFileName(t *testing.T, name string) string {

	dir := g.fixtureDir

	if g.useTestNameForDir {
		dir = filepath.Join(dir, strings.Split(t.Name(), "/")[0])
	}

	if g.useSubTestNameForDir {
		n := strings.Split(t.Name(), "/")
		if len(n) > 1 {

			dir = filepath.Join(dir, n[1])
		}
	}

	return filepath.Join(dir, fmt.Sprintf("%s%s", name, g.fileNameSuffix))
}
<commit_msg>mark the assertion functions as test helpers<commit_after>// Package goldie provides test assertions based on golden files. It's
// typically used for testing responses with larger data bodies.
//
// The concept is straight forward. Valid response data is stored in a "golden
// file". The actual response data will be byte compared with the golden file
// and the test will fail if there is a difference.
//
// Updating the golden file can be done by running `go test -update ./...`.
package goldie

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"text/template"

	"errors"

	"github.com/pmezard/go-difflib/difflib"
	"github.com/sergi/go-diff/diffmatchpatch"
)

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

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

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

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

	// defaultDiffEngine sets which diff engine to use if not defined.
	defaultDiffEngine = ClassicDiff

	// defaultIgnoreTemplateErrors sets the default value for the
	// WithIgnoreTemplateErrors option.
	defaultIgnoreTemplateErrors = false

	// defaultUseTestNameForDir sets the default value for the
	// WithTestNameForDir option.
	defaultUseTestNameForDir = false

	// defaultUseSubTestNameForDir sets the default value for the
	// WithSubTestNameForDir option.
	defaultUseSubTestNameForDir = false
)

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

type goldie struct {
	fixtureDir     string
	fileNameSuffix string
	filePerms      os.FileMode
	dirPerms       os.FileMode

	diffEngine           DiffEngine
	diffFn               DiffFn
	ignoreTemplateErrors bool
	useTestNameForDir    bool
	useSubTestNameForDir bool
}

// === Create new testers ==================================

// New creates a new golden file tester. If there is an issue with applying any
// of the options, an error will be reported and t.FailNow() will be called.
func New(t *testing.T, options ...Option) *goldie {
	g := goldie{
		fixtureDir:           defaultFixtureDir,
		fileNameSuffix:       defaultFileNameSuffix,
		filePerms:            defaultFilePerms,
		dirPerms:             defaultDirPerms,
		diffEngine:           defaultDiffEngine,
		ignoreTemplateErrors: defaultIgnoreTemplateErrors,
		useTestNameForDir:    defaultUseTestNameForDir,
		useSubTestNameForDir: defaultUseSubTestNameForDir,
	}

	var err error
	for _, option := range options {
		err = option(&g)
		if err != nil {
			t.Error(fmt.Errorf("Could not apply option: %w", err))
			t.FailNow()
		}
	}

	return &g
}

// Diff generates a string that shows the difference between the actual and the
// expected. This method could be called in your own DiffFn in case you want
// to leverage any of the engines defined.
func Diff(engine DiffEngine, actual string, expected string) string {
	var diff string

	switch engine {
	case Simple:
		diff = fmt.Sprintf("Expected: %s\nGot: %s", expected, actual)

	case ClassicDiff:
		diff, _ = difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
			A:        difflib.SplitLines(expected),
			B:        difflib.SplitLines(actual),
			FromFile: "Expected",
			FromDate: "",
			ToFile:   "Actual",
			ToDate:   "",
			Context:  1,
		})

	case ColoredDiff:
		dmp := diffmatchpatch.New()
		diffs := dmp.DiffMain(actual, expected, false)
		diff = dmp.DiffPrettyText(diffs)
	}

	return diff
}

// === OptionProcessor ===============================

// WithFixtureDir sets the fixture directory.
//
// Defaults to `testdata`
func (g *goldie) WithFixtureDir(dir string) error {
	g.fixtureDir = dir
	return nil
}

// WithNameSuffix sets the file suffix to be used for the golden file.
//
// Defaults to `.golden`
func (g *goldie) WithNameSuffix(suffix string) error {
	g.fileNameSuffix = suffix
	return nil
}

// WithFilePerms sets the file permissions on the golden files that are
// created.
//
// Defaults to 0644.
func (g *goldie) WithFilePerms(mode os.FileMode) error {
	g.filePerms = mode
	return nil
}

// WithDirPerms sets the directory permissions for the directories in which the
// golden files are created.
//
// Defaults to 0755.
func (g *goldie) WithDirPerms(mode os.FileMode) error {
	g.dirPerms = mode
	return nil
}

// WithDiffEngine sets the `diff` engine that will be used to generate the
// `diff` text.
func (g *goldie) WithDiffEngine(engine DiffEngine) error {
	g.diffEngine = engine
	return nil
}

// WithDiffFn sets the `diff` engine to be a function that implements the
// DiffFn signature. This allows for any customized diff logic you would like
// to create.
func (g *goldie) WithDiffFn(fn DiffFn) error {
	g.diffFn = fn
	return nil
}

// WithIgnoreTemplateErrors allows template processing to ignore any variables
// in the template that do not have corresponding data values passed in.
//
// Default value is false.
func (g *goldie) WithIgnoreTemplateErrors(ignoreErrors bool) error {
	g.ignoreTemplateErrors = ignoreErrors
	return nil
}

// WithTestNameForDir will create a directory with the test's name in the
// fixture directory to store all the golden files.
//
// Default value is false.
func (g *goldie) WithTestNameForDir(use bool) error {
	g.useTestNameForDir = use
	return nil
}

// WithSubTestNameForDir will create a directory with the sub test's name to
// store all the golden files. If WithTestNameForDir is enabled, it will be in
// the test name's directory. Otherwise, it will be in the fixture directory.
//
// Default value is false.
func (g *goldie) WithSubTestNameForDir(use bool) error {
	g.useSubTestNameForDir = use
	return nil
}

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

	err := g.compare(t, name, actualData)
	if err != nil {
		{
			var e *errFixtureNotFound
			if errors.As(err, &e) {
				t.Error(err)
				t.FailNow()
				return
			}
		}

		{
			var e *errFixtureMismatch
			if errors.As(err, &e) {
				t.Error(err)
				return
			}
		}

		t.Error(err)
	}
}

// AssertJson compares the actual json data received with expected data in the
// golden files. If the update flag is set, it will also update the golden
// file.
//
// `name` refers to the name of the test and it should typically be unique
// within the package. Also it should be a valid file name (so keeping to
// `a-z0-9\-\_` is a good idea).
func (g *goldie) AssertJson(t *testing.T, name string, actualJsonData interface{}) {
	t.Helper()
	js, err := json.MarshalIndent(actualJsonData, "", "  ")

	if err != nil {
		t.Error(err)
		t.FailNow()
	}

	g.Assert(t, name, normalizeLF(js))
}

// normalizeLF normalizes line feed character set across os (es)
// \r\n (windows) & \r (mac) into \n (unix)
func normalizeLF(d []byte) []byte {
	// if empty / nil return as is
	if len(d) == 0 {
		return d
	}
	// replace CR LF \r\n (windows) with LF \n (unix)
	d = bytes.Replace(d, []byte{13, 10}, []byte{10}, -1)
	// replace CF \r (mac) with LF \n (unix)
	d = bytes.Replace(d, []byte{13}, []byte{10}, -1)
	return d
}

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

	err := g.compareTemplate(t, name, data, actualData)
	if err != nil {
		{
			var e *errFixtureNotFound
			if errors.As(err, &e) {
				t.Error(err)
				t.FailNow()
				return
			}
		}

		{
			var e *errFixtureMismatch
			if errors.As(err, &e) {
				t.Error(err)
				return
			}
		}

		t.Error(err)
	}
}

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

	return ioutil.WriteFile(g.goldenFileName(t, name), actualData, g.filePerms)
}

// compare is reading the golden fixture file and compare the stored data with
// the actual data.
func (g *goldie) compare(t *testing.T, name string, actualData []byte) error {
	expectedData, err := ioutil.ReadFile(g.goldenFileName(t, name))

	if err != nil {
		if os.IsNotExist(err) {
			return newErrFixtureNotFound()
		}

		return fmt.Errorf("Expected %s to be nil", err.Error())
	}

	if !bytes.Equal(actualData, expectedData) {
		msg := "Result did not match the golden fixture. Diff is below:\n\n"
		actual := string(actualData)
		expected := string(expectedData)

		if g.diffFn != nil {
			msg += g.diffFn(actual, expected)
		} else {
			msg += Diff(g.diffEngine, actual, expected)
		}

		return newErrFixtureMismatch(msg)
	}

	return nil
}

// compareTemplate is reading the golden fixture file and compare the stored
// data with the actual data.
func (g *goldie) compareTemplate(t *testing.T, name string, data interface{}, actualData []byte) error {
	expectedDataTmpl, err := ioutil.ReadFile(g.goldenFileName(t, name))

	if err != nil {
		if os.IsNotExist(err) {
			return newErrFixtureNotFound()
		}

		return fmt.Errorf("Expected %s to be nil", err.Error())
	}

	missingKey := "error"
	if g.ignoreTemplateErrors {
		missingKey = "default"
	}
	tmpl, err := template.New("test").Option("missingkey=" + missingKey).Parse(string(expectedDataTmpl))
	if err != nil {
		return fmt.Errorf("Expected %s to be nil", err.Error())
	}

	var expectedData bytes.Buffer
	err = tmpl.Execute(&expectedData, data)
	if err != nil {
		return newErrMissingKey(fmt.Sprintf("Template error: %s", err.Error()))
	}

	if !bytes.Equal(actualData, expectedData.Bytes()) {
		msg := "Result did not match the golden fixture. Diff is below:\n\n"
		actual := string(actualData)
		expected := expectedData.String()

		if g.diffFn != nil {
			msg += g.diffFn(actual, expected)
		} else {
			msg += Diff(g.diffEngine, actual, expected)
		}

		return newErrFixtureMismatch(msg)
	}

	return nil
}

// ensureDir will create the fixture folder if it does not already exist.
func (g *goldie) ensureDir(loc string) error {
	s, err := os.Stat(loc)
	switch {
	case err != nil && os.IsNotExist(err):
		// the location does not exist, so make directories to there
		return os.MkdirAll(loc, g.dirPerms)
	case err == nil && !s.IsDir():
		return newErrFixtureDirectoryIsFile(loc)
	}

	return err
}

// goldenFileName simply returns the file name of the golden file fixture.
func (g *goldie) goldenFileName(t *testing.T, name string) string {

	dir := g.fixtureDir

	if g.useTestNameForDir {
		dir = filepath.Join(dir, strings.Split(t.Name(), "/")[0])
	}

	if g.useSubTestNameForDir {
		n := strings.Split(t.Name(), "/")
		if len(n) > 1 {

			dir = filepath.Join(dir, n[1])
		}
	}

	return filepath.Join(dir, fmt.Sprintf("%s%s", name, g.fileNameSuffix))
}
<|endoftext|>


<commit_before>package gomapr

import (
	"errors"
	"log"
	"reflect"
	"sync"
)

var (
	EndOfEmit = errors.New("Nothing left to emit")
)

type Event interface{}
type Partial interface{}
type ReduceKey interface{}

type MapReduce interface {
	Emit() (Event, error)
	Map(Event) (ReduceKey, Partial)
	Reduce(ReduceKey, []Partial) (ReduceKey, Partial)
}

// Corresponds to a set of values that a reducer can join.
type partialGroup struct {
	values []Partial
	l      *sync.RWMutex
}

func newPartialGroup() *partialGroup {
	return &partialGroup{
		values: make([]Partial, 0),
		l:      &sync.RWMutex{},
	}
}

// Adds a value to the group.
func (p *partialGroup) add(v interface{}) {
	p.values = append(p.values, v)
}

// Replaces the contents of the partial group.
func (p *partialGroup) replace(v interface{}) {
	p.values = []Partial{v}
}

// Contains all partial groups.
type reduceWorkspace struct {
	groups map[ReduceKey]*partialGroup
	l      *sync.RWMutex
}

func newReduceWorkspace() *reduceWorkspace {
	return &reduceWorkspace{
		make(map[ReduceKey]*partialGroup),
		&sync.RWMutex{},
	}
}

// Returns a partial group by its key.
func (r *reduceWorkspace) getPartialGroup(key ReduceKey) *partialGroup {
	r.l.Lock()
	defer r.l.Unlock()

	partialGroup, ok := r.groups[key]
	if !ok {
		partialGroup = newPartialGroup()
		r.groups[key] = partialGroup
	}

	return partialGroup
}

// Adds a key-value pair to its appropriate partial group.
func (r *reduceWorkspace) add(key ReduceKey, value Partial) {
	partialGroup := r.getPartialGroup(key)

	partialGroup.l.Lock()
	partialGroup.add(value)
	partialGroup.l.Unlock()
}

// Replaces an existing partial group with the input arguments.
func (r *reduceWorkspace) replace(key ReduceKey, value Partial) {
	partialGroup := r.getPartialGroup(key)

	partialGroup.l.Lock()
	partialGroup.replace(value)
	partialGroup.l.Unlock()
}

// Contains configuration for a MapReduce task.
type Runner struct {
	reduceWorkspace *reduceWorkspace
	mr              MapReduce
	wg              *sync.WaitGroup
}

func NewRunner(m MapReduce) *Runner {
	return &Runner{
		reduceWorkspace: newReduceWorkspace(),
		mr:              m,
		wg:              &sync.WaitGroup{},
	}
}

// Returns the map containing all groups. Only safe to call after
// the task has completed.
func (r *Runner) Groups() map[ReduceKey]Partial {
	r.reduceWorkspace.l.Lock()
	defer r.reduceWorkspace.l.Unlock()

	groups := make(map[ReduceKey]Partial)

	for k, v := range r.reduceWorkspace.groups {
		groups[k] = v.values[0]
	}

	return groups
}

// Maps the input it receives on its emitted channel, spawning
// a reduce task when appropriate.
func (r *Runner) mapWorker(emitted chan Event) {
	for val := range emitted {
		key, mapped := r.mr.Map(val)
		r.reduceWorkspace.add(key, mapped)
		r.wg.Add(1)
		go r.reduce(key)
	}

	r.wg.Done()
}

// Reduces the partial group with the matching input key.
func (r *Runner) reduce(key ReduceKey) {
	partialGroup := r.reduceWorkspace.getPartialGroup(key)

	partialGroup.l.Lock()
	defer partialGroup.l.Unlock()

	if len(partialGroup.values) > 1 {
		newKey, partial := r.mr.Reduce(key, partialGroup.values)

		if reflect.DeepEqual(key, newKey) {
			partialGroup.replace(partial)
		} else {
			r.reduceWorkspace.replace(key, partial)
		}
	}

	r.wg.Done()
}

// Starts the MapReduce task.
func (r *Runner) Run(mappers int) {
	emit := make(chan Event, mappers)

	// Create background mapping workers.
	for i := 0; i < mappers; i++ {
		r.wg.Add(1)
		go r.mapWorker(emit)
	}

	// Emit all events.
	go func() {
		for {
			emitted, err := r.mr.Emit()
			if err != EndOfEmit && err != nil {
				log.Printf("Error emitting: %v", err)
				break
			}

			emit <- emitted

			if err == EndOfEmit {
				break
			}

		}
		close(emit)
	}()

	r.wg.Wait()
}
<commit_msg>Don't use deep equality<commit_after>package gomapr

import (
	"errors"
	"log"
	"sync"
)

var (
	EndOfEmit = errors.New("Nothing left to emit")
)

type Event interface{}
type Partial interface{}
type ReduceKey interface{}

type MapReduce interface {
	Emit() (Event, error)
	Map(Event) (ReduceKey, Partial)
	Reduce(ReduceKey, []Partial) (ReduceKey, Partial)
}

// Corresponds to a set of values that a reducer can join.
type partialGroup struct {
	values []Partial
	l      *sync.RWMutex
}

func newPartialGroup() *partialGroup {
	return &partialGroup{
		values: make([]Partial, 0),
		l:      &sync.RWMutex{},
	}
}

// Adds a value to the group.
func (p *partialGroup) add(v interface{}) {
	p.values = append(p.values, v)
}

// Replaces the contents of the partial group.
func (p *partialGroup) replace(v interface{}) {
	p.values = []Partial{v}
}

// Contains all partial groups.
type reduceWorkspace struct {
	groups map[ReduceKey]*partialGroup
	l      *sync.RWMutex
}

func newReduceWorkspace() *reduceWorkspace {
	return &reduceWorkspace{
		make(map[ReduceKey]*partialGroup),
		&sync.RWMutex{},
	}
}

// Returns a partial group by its key.
func (r *reduceWorkspace) getPartialGroup(key ReduceKey) *partialGroup {
	r.l.Lock()
	defer r.l.Unlock()

	partialGroup, ok := r.groups[key]
	if !ok {
		partialGroup = newPartialGroup()
		r.groups[key] = partialGroup
	}

	return partialGroup
}

// Adds a key-value pair to its appropriate partial group.
func (r *reduceWorkspace) add(key ReduceKey, value Partial) {
	partialGroup := r.getPartialGroup(key)

	partialGroup.l.Lock()
	partialGroup.add(value)
	partialGroup.l.Unlock()
}

// Replaces an existing partial group with the input arguments.
func (r *reduceWorkspace) replace(key ReduceKey, value Partial) {
	partialGroup := r.getPartialGroup(key)

	partialGroup.l.Lock()
	partialGroup.replace(value)
	partialGroup.l.Unlock()
}

// Contains configuration for a MapReduce task.
type Runner struct {
	reduceWorkspace *reduceWorkspace
	mr              MapReduce
	wg              *sync.WaitGroup
}

func NewRunner(m MapReduce) *Runner {
	return &Runner{
		reduceWorkspace: newReduceWorkspace(),
		mr:              m,
		wg:              &sync.WaitGroup{},
	}
}

// Returns the map containing all groups. Only safe to call after
// the task has completed.
func (r *Runner) Groups() map[ReduceKey]Partial {
	r.reduceWorkspace.l.Lock()
	defer r.reduceWorkspace.l.Unlock()

	groups := make(map[ReduceKey]Partial)

	for k, v := range r.reduceWorkspace.groups {
		groups[k] = v.values[0]
	}

	return groups
}

// Maps the input it receives on its emitted channel, spawning
// a reduce task when appropriate.
func (r *Runner) mapWorker(emitted chan Event) {
	for val := range emitted {
		key, mapped := r.mr.Map(val)
		r.reduceWorkspace.add(key, mapped)
		r.wg.Add(1)
		go r.reduce(key)
	}

	r.wg.Done()
}

// Reduces the partial group with the matching input key.
func (r *Runner) reduce(key ReduceKey) {
	partialGroup := r.reduceWorkspace.getPartialGroup(key)

	partialGroup.l.Lock()
	defer partialGroup.l.Unlock()

	if len(partialGroup.values) > 1 {
		newKey, partial := r.mr.Reduce(key, partialGroup.values)

		if key == newKey {
			partialGroup.replace(partial)
		} else {
			r.reduceWorkspace.replace(key, partial)
		}
	}

	r.wg.Done()
}

// Starts the MapReduce task.
func (r *Runner) Run(mappers int) {
	emit := make(chan Event, mappers)

	// Create background mapping workers.
	for i := 0; i < mappers; i++ {
		r.wg.Add(1)
		go r.mapWorker(emit)
	}

	// Emit all events.
	go func() {
		for {
			emitted, err := r.mr.Emit()
			if err != EndOfEmit && err != nil {
				log.Printf("Error emitting: %v", err)
				break
			}

			emit <- emitted

			if err == EndOfEmit {
				break
			}

		}
		close(emit)
	}()

	r.wg.Wait()
}
<|endoftext|>


<commit_before>package goplus

import (
	"net/http"

	// Import appengine urlfetch package, that is needed to make http call to the api
	"appengine"
	"appengine/urlfetch"

	// Import google api go client library
	"code.google.com/p/google-api-go-client/googleapi/transport"
	// Import Google+ package, the package will be named "plus"
	"code.google.com/p/google-api-go-client/plus/v1"
)

// gopherFallback is the official gopher URL (in case we don't find any in the Google+ stream)
const gopherFallback = "http://golang.org/doc/gopher/gophercolor.png"

// init is called before the application start
func init() {
	// Register a handler for /gopher URLs.
	http.HandleFunc("/gopher", gopher)
}

// gopher is an HTTP handler that searches Google+ for an activity
// with a Gopher photo and redirects to the image thumbnail.
func gopher(w http.ResponseWriter, r *http.Request) {
	// Create appengine context, needed to do urlfetch call
	c := appengine.NewContext(r)

	// Create a new http client, supplying the API key we
	// generated to identify our application, and the urlfetch
	// transport necessary to make HTTP calls on App Engine
	transport := &transport.APIKey{
		Key:       apiKey,
		Transport: &urlfetch.Transport{Context: c}}
	client := &http.Client{Transport: transport}

	// Create the plus service object with which we can make an API call
	service, err := plus.New(client)
	if err != nil {
		// error creating the Google+ client
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Search the stream for "gopher" related activities
	result, err := service.Activities.Search("#gopher").Do()
	if err != nil {
		// error searching Google+ for gopher
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Iterate through the activities search result until we find a photo or album attachment
	for _, item := range result.Items {
		for _, att := range item.Object.Attachments {
			switch att.ObjectType {
			case "photo":
				// Redirect to the gopher thumbnail
				http.Redirect(w, r, att.Image.Url, 302)
				return
			case "album":
				http.Redirect(w, r, att.Thumbnails[0].Image.Url, 302)
				return
			}
		}
	}
	// Fallback on the official gopher if we didn't found any gophers in the stream
	http.Redirect(w, r, gopherFallback, http.StatusFound)
}
<commit_msg>fix typo<commit_after>package goplus

import (
	"net/http"

	// Import appengine urlfetch package, that is needed to make http call to the api
	"appengine"
	"appengine/urlfetch"

	// Import google api go client library
	"code.google.com/p/google-api-go-client/googleapi/transport"
	// Import Google+ package, the package will be named "plus"
	"code.google.com/p/google-api-go-client/plus/v1"
)

// gopherFallback is the official gopher URL (in case we don't find any in the Google+ stream)
const gopherFallback = "http://golang.org/doc/gopher/gophercolor.png"

// init is called before the application start
func init() {
	// Register a handler for /gopher URLs.
	http.HandleFunc("/gopher", gopher)
}

// gopher is an HTTP handler that searches Google+ for an activity
// with a Gopher photo and redirects to the image thumbnail.
func gopher(w http.ResponseWriter, r *http.Request) {
	// Create appengine context, needed to do urlfetch call
	c := appengine.NewContext(r)

	// Create a new http client, supplying the API key we
	// generated to identify our application, and the urlfetch
	// transport necessary to make HTTP calls on App Engine
	transport := &transport.APIKey{
		Key:       apiKey,
		Transport: &urlfetch.Transport{Context: c}}
	client := &http.Client{Transport: transport}

	// Create the plus service object with which we can make an API call
	service, err := plus.New(client)
	if err != nil {
		// error creating the Google+ client
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Search the stream for "gopher" related activities
	result, err := service.Activities.Search("#gopher").Do()
	if err != nil {
		// error searching Google+ for gopher
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Iterate through the activities search result until we find a photo or album attachment
	for _, item := range result.Items {
		for _, att := range item.Object.Attachments {
			switch att.ObjectType {
			case "photo":
				// Redirect to the gopher thumbnail
				http.Redirect(w, r, att.Image.Url, 302)
				return
			case "album":
				http.Redirect(w, r, att.Thumbnails[0].Image.Url, 302)
				return
			}
		}
	}
	// Fallback on the official gopher if we didn't find any gophers in the stream
	http.Redirect(w, r, gopherFallback, http.StatusFound)
}
<|endoftext|>