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

package main

import (
	"bytes"
	"context"
	"fmt"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"time"

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

// Github represents a control version repository to
// interact with github.com
type Github struct {
	client *github.Client
	owner  string
	repo   string
	url    string
}

const (
	timeoutShortRequest = 10 * time.Second
	timeoutLongRequest  = 20 * time.Second
)

// newGithub returns an object of type Github
func newGithub(url, token string) (CVR, error) {
	url = strings.TrimSpace(url)

	ownerRepo := strings.SplitAfter(url, "/"+githubDomain+"/")

	// at least we need two tokens
	if len(ownerRepo) < 2 {
		return nil, fmt.Errorf("missing owner and repo %s", url)
	}

	ownerRepo = strings.Split(ownerRepo[1], "/")

	// at least we need two tokens: owner and repo
	if len(ownerRepo) < 2 {
		return nil, fmt.Errorf("failed to get owner and repo %s", url)
	}

	if len(ownerRepo[0]) == 0 {
		return nil, fmt.Errorf("missing owner in url %s", url)
	}

	if len(ownerRepo[1]) == 0 {
		return nil, fmt.Errorf("missing repository in url %s", url)
	}

	// create a new http client using the token
	var client *http.Client
	if token != "" {
		ts := oauth2.StaticTokenSource(
			&oauth2.Token{AccessToken: token},
		)
		client = oauth2.NewClient(context.Background(), ts)
	}

	return &Github{
		client: github.NewClient(client),
		owner:  ownerRepo[0],
		repo:   ownerRepo[1],
		url:    url,
	}, nil
}

// getDomain returns the domain name
func (g *Github) getDomain() string {
	return githubDomain
}

// getOwner returns the owner of the repo
func (g *Github) getOwner() string {
	return g.owner
}

// getRepo returns the repository name
func (g *Github) getRepo() string {
	return g.repo
}

// getOpenPullRequests returns the open pull requests
func (g *Github) getOpenPullRequests() (map[string]*PullRequest, error) {
	ctx, cancel := context.WithTimeout(context.Background(), timeoutShortRequest)
	defer cancel()

	pullRequests, _, err := g.client.PullRequests.List(ctx, g.owner, g.repo, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to list pull requests %s", err)
	}

	prs := make(map[string]*PullRequest)

	for _, pr := range pullRequests {
		if pr == nil || pr.Number == nil {
			continue
		}
		number := *pr.Number

		pullRequest, err := g.getPullRequest(number)
		if err != nil {
			continue
		}

		prs[strconv.Itoa(number)] = pullRequest
	}

	return prs, nil
}

// getPullRequest returns a specific pull request
func (g *Github) getPullRequest(pr int) (*PullRequest, error) {
	ctx, cancel := context.WithTimeout(context.Background(), timeoutShortRequest)
	defer cancel()

	// get all commits of the pull request
	listCommits, _, err := g.client.PullRequests.ListCommits(ctx, g.owner, g.repo, pr, nil)
	if err != nil {
		return nil, err
	}

	var commits []PullRequestCommit
	for _, c := range listCommits {
		if c == nil {
			return nil, fmt.Errorf("failed to get all commits of the pull request %d", pr)
		}

		if c.SHA == nil {
			return nil, fmt.Errorf("failed to get commit SHA of the pull request %d", pr)
		}
		sha := *c.SHA

		if c.Commit == nil || c.Commit.Committer == nil || c.Commit.Committer.Date == nil {
			return nil, fmt.Errorf("failed to get commit time of the pull request %d", pr)
		}
		time := *c.Commit.Committer.Date

		commits = append(commits,
			PullRequestCommit{
				Sha:  sha,
				Time: time,
			},
		)
	}

	pullRequest, _, err := g.client.PullRequests.Get(ctx, g.owner, g.repo, pr)
	if err != nil {
		return nil, err
	}

	// check the integrity of the pullRuest object before use it
	if pullRequest == nil {
		return nil, fmt.Errorf("failed to get pull request %d", pr)
	}

	if pullRequest.User == nil || pullRequest.User.Login == nil {
		return nil, fmt.Errorf("failed to get the author of the pull request %d", pr)
	}

	author := *pullRequest.User.Login

	if pullRequest.Mergeable == nil {
		return nil, fmt.Errorf("Unable to know if the pull request %d is mergeable", pr)
	}

	mergeable := *pullRequest.Mergeable

	if pullRequest.Head == nil || pullRequest.Head.Ref == nil {
		return nil, fmt.Errorf("failed to get the branch name of the pull request %d", pr)
	}

	branchName := *pullRequest.Head.Ref

	return &PullRequest{
		Number:     pr,
		Commits:    commits,
		Author:     author,
		Mergeable:  mergeable,
		BranchName: branchName,
	}, nil
}

// getLatestPullRequestComment returns the latest comment of a specific
// user in the specific pr. If comment.User is an empty string then any user
// could be the author of the latest pull request. If comment.Comment is an empty
// string an error is returned.
func (g *Github) getLatestPullRequestComment(pr int, comment PullRequestComment) (*PullRequestComment, error) {
	if len(comment.Comment) == 0 {
		return nil, fmt.Errorf("comment cannot be an empty string")
	}

	ctx, cancel := context.WithTimeout(context.Background(), timeoutLongRequest)
	defer cancel()

	comments, _, err := g.client.Issues.ListComments(ctx, g.owner, g.repo, pr, nil)
	if err != nil {
		return nil, err
	}

	for i := len(comments) - 1; i >= 0; i-- {
		c := comments[i]
		if len(comment.User) != 0 {
			if strings.Compare(*c.User.Login, comment.User) != 0 {
				continue
			}
		}

		if strings.Compare(*c.Body, comment.Comment) == 0 {
			return &PullRequestComment{
				User:    comment.User,
				Comment: comment.Comment,
				time:    *c.CreatedAt,
			}, nil
		}
	}

	return nil, fmt.Errorf("comment '%+v' not found", comment)
}

func (g *Github) downloadPullRequest(pr PullRequest, workingDirectory string) (string, error) {
	projectDirectory, err := filepath.Abs(workingDirectory)
	if err != nil {
		return "", err
	}

	projectDirectory = filepath.Join(projectDirectory, g.repo)
	if err := os.MkdirAll(projectDirectory, 0755); err != nil {
		return "", fmt.Errorf("failed to create project directory %s", err)
	}

	var stderr bytes.Buffer

	// clone the project
	cmd := exec.Command("git", "clone", g.url, ".")
	cmd.Dir = projectDirectory
	cmd.Stderr = &stderr
	if err := cmd.Run(); err != nil {
		return "", fmt.Errorf("failed to run git clone %s %s", stderr.String(), err)
	}

	// fetch the branch
	stderr.Reset()
	cmd = exec.Command("git", "fetch", "origin", fmt.Sprintf("pull/%d/head:%s", pr.Number, pr.BranchName))
	cmd.Dir = projectDirectory
	cmd.Stderr = &stderr
	if err := cmd.Run(); err != nil {
		return "", fmt.Errorf("failed to run git fetch %s %s", stderr.String(), err)
	}

	// checkout the branch
	stderr.Reset()
	cmd = exec.Command("git", "checkout", pr.BranchName)
	cmd.Dir = projectDirectory
	cmd.Stderr = &stderr
	if err := cmd.Run(); err != nil {
		return "", fmt.Errorf("failed to run git checkout %s %s", stderr.String(), err)
	}

	return projectDirectory, nil
}

// createComment creates a comment in the specific pr
func (g *Github) createComment(pr int, comment string) error {
	ctx, cancel := context.WithTimeout(context.Background(), timeoutLongRequest)
	defer cancel()

	c := &github.IssueComment{Body: &comment}

	_, _, err := g.client.Issues.CreateComment(ctx, g.owner, g.repo, pr, c)

	return err
}

// isMember returns true if the user is member of the organization, else false
func (g *Github) isMember(user string) (bool, error) {
	ctx, cancel := context.WithTimeout(context.Background(), timeoutShortRequest)
	defer cancel()

	ret, _, err := g.client.Organizations.IsMember(ctx, g.owner, user)

	return ret, err
}
<commit_msg>localCI: do not fail if we don't know if the pr is mergeable<commit_after>// Copyright (c) 2017 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"bytes"
	"context"
	"fmt"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"time"

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

// Github represents a control version repository to
// interact with github.com
type Github struct {
	client *github.Client
	owner  string
	repo   string
	url    string
}

const (
	timeoutShortRequest = 10 * time.Second
	timeoutLongRequest  = 20 * time.Second
)

// newGithub returns an object of type Github
func newGithub(url, token string) (CVR, error) {
	url = strings.TrimSpace(url)

	ownerRepo := strings.SplitAfter(url, "/"+githubDomain+"/")

	// at least we need two tokens
	if len(ownerRepo) < 2 {
		return nil, fmt.Errorf("missing owner and repo %s", url)
	}

	ownerRepo = strings.Split(ownerRepo[1], "/")

	// at least we need two tokens: owner and repo
	if len(ownerRepo) < 2 {
		return nil, fmt.Errorf("failed to get owner and repo %s", url)
	}

	if len(ownerRepo[0]) == 0 {
		return nil, fmt.Errorf("missing owner in url %s", url)
	}

	if len(ownerRepo[1]) == 0 {
		return nil, fmt.Errorf("missing repository in url %s", url)
	}

	// create a new http client using the token
	var client *http.Client
	if token != "" {
		ts := oauth2.StaticTokenSource(
			&oauth2.Token{AccessToken: token},
		)
		client = oauth2.NewClient(context.Background(), ts)
	}

	return &Github{
		client: github.NewClient(client),
		owner:  ownerRepo[0],
		repo:   ownerRepo[1],
		url:    url,
	}, nil
}

// getDomain returns the domain name
func (g *Github) getDomain() string {
	return githubDomain
}

// getOwner returns the owner of the repo
func (g *Github) getOwner() string {
	return g.owner
}

// getRepo returns the repository name
func (g *Github) getRepo() string {
	return g.repo
}

// getOpenPullRequests returns the open pull requests
func (g *Github) getOpenPullRequests() (map[string]*PullRequest, error) {
	ctx, cancel := context.WithTimeout(context.Background(), timeoutShortRequest)
	defer cancel()

	pullRequests, _, err := g.client.PullRequests.List(ctx, g.owner, g.repo, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to list pull requests %s", err)
	}

	prs := make(map[string]*PullRequest)

	for _, pr := range pullRequests {
		if pr == nil || pr.Number == nil {
			continue
		}
		number := *pr.Number

		pullRequest, err := g.getPullRequest(number)
		if err != nil {
			continue
		}

		prs[strconv.Itoa(number)] = pullRequest
	}

	return prs, nil
}

// getPullRequest returns a specific pull request
func (g *Github) getPullRequest(pr int) (*PullRequest, error) {
	ctx, cancel := context.WithTimeout(context.Background(), timeoutShortRequest)
	defer cancel()

	// get all commits of the pull request
	listCommits, _, err := g.client.PullRequests.ListCommits(ctx, g.owner, g.repo, pr, nil)
	if err != nil {
		return nil, err
	}

	var commits []PullRequestCommit
	for _, c := range listCommits {
		if c == nil {
			return nil, fmt.Errorf("failed to get all commits of the pull request %d", pr)
		}

		if c.SHA == nil {
			return nil, fmt.Errorf("failed to get commit SHA of the pull request %d", pr)
		}
		sha := *c.SHA

		if c.Commit == nil || c.Commit.Committer == nil || c.Commit.Committer.Date == nil {
			return nil, fmt.Errorf("failed to get commit time of the pull request %d", pr)
		}
		time := *c.Commit.Committer.Date

		commits = append(commits,
			PullRequestCommit{
				Sha:  sha,
				Time: time,
			},
		)
	}

	pullRequest, _, err := g.client.PullRequests.Get(ctx, g.owner, g.repo, pr)
	if err != nil {
		return nil, err
	}

	// check the integrity of the pullRuest object before use it
	if pullRequest == nil {
		return nil, fmt.Errorf("failed to get pull request %d", pr)
	}

	if pullRequest.User == nil || pullRequest.User.Login == nil {
		return nil, fmt.Errorf("failed to get the author of the pull request %d", pr)
	}

	author := *pullRequest.User.Login

	// do not fail if we don't know if the pull request is
	// mergeable, just test it
	mergeable := true
	if pullRequest.Mergeable != nil {
		mergeable = *pullRequest.Mergeable
	}

	if pullRequest.Head == nil || pullRequest.Head.Ref == nil {
		return nil, fmt.Errorf("failed to get the branch name of the pull request %d", pr)
	}

	branchName := *pullRequest.Head.Ref

	return &PullRequest{
		Number:     pr,
		Commits:    commits,
		Author:     author,
		Mergeable:  mergeable,
		BranchName: branchName,
	}, nil
}

// getLatestPullRequestComment returns the latest comment of a specific
// user in the specific pr. If comment.User is an empty string then any user
// could be the author of the latest pull request. If comment.Comment is an empty
// string an error is returned.
func (g *Github) getLatestPullRequestComment(pr int, comment PullRequestComment) (*PullRequestComment, error) {
	if len(comment.Comment) == 0 {
		return nil, fmt.Errorf("comment cannot be an empty string")
	}

	ctx, cancel := context.WithTimeout(context.Background(), timeoutLongRequest)
	defer cancel()

	comments, _, err := g.client.Issues.ListComments(ctx, g.owner, g.repo, pr, nil)
	if err != nil {
		return nil, err
	}

	for i := len(comments) - 1; i >= 0; i-- {
		c := comments[i]
		if len(comment.User) != 0 {
			if strings.Compare(*c.User.Login, comment.User) != 0 {
				continue
			}
		}

		if strings.Compare(*c.Body, comment.Comment) == 0 {
			return &PullRequestComment{
				User:    comment.User,
				Comment: comment.Comment,
				time:    *c.CreatedAt,
			}, nil
		}
	}

	return nil, fmt.Errorf("comment '%+v' not found", comment)
}

func (g *Github) downloadPullRequest(pr PullRequest, workingDirectory string) (string, error) {
	projectDirectory, err := filepath.Abs(workingDirectory)
	if err != nil {
		return "", err
	}

	projectDirectory = filepath.Join(projectDirectory, g.repo)
	if err := os.MkdirAll(projectDirectory, 0755); err != nil {
		return "", fmt.Errorf("failed to create project directory %s", err)
	}

	var stderr bytes.Buffer

	// clone the project
	cmd := exec.Command("git", "clone", g.url, ".")
	cmd.Dir = projectDirectory
	cmd.Stderr = &stderr
	if err := cmd.Run(); err != nil {
		return "", fmt.Errorf("failed to run git clone %s %s", stderr.String(), err)
	}

	// fetch the branch
	stderr.Reset()
	cmd = exec.Command("git", "fetch", "origin", fmt.Sprintf("pull/%d/head:%s", pr.Number, pr.BranchName))
	cmd.Dir = projectDirectory
	cmd.Stderr = &stderr
	if err := cmd.Run(); err != nil {
		return "", fmt.Errorf("failed to run git fetch %s %s", stderr.String(), err)
	}

	// checkout the branch
	stderr.Reset()
	cmd = exec.Command("git", "checkout", pr.BranchName)
	cmd.Dir = projectDirectory
	cmd.Stderr = &stderr
	if err := cmd.Run(); err != nil {
		return "", fmt.Errorf("failed to run git checkout %s %s", stderr.String(), err)
	}

	return projectDirectory, nil
}

// createComment creates a comment in the specific pr
func (g *Github) createComment(pr int, comment string) error {
	ctx, cancel := context.WithTimeout(context.Background(), timeoutLongRequest)
	defer cancel()

	c := &github.IssueComment{Body: &comment}

	_, _, err := g.client.Issues.CreateComment(ctx, g.owner, g.repo, pr, c)

	return err
}

// isMember returns true if the user is member of the organization, else false
func (g *Github) isMember(user string) (bool, error) {
	ctx, cancel := context.WithTimeout(context.Background(), timeoutShortRequest)
	defer cancel()

	ret, _, err := g.client.Organizations.IsMember(ctx, g.owner, user)

	return ret, err
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"go/format"
	"os"
	"path/filepath"
	"strings"
	"text/template"
)

type generateType struct {
	Name    string
	Initial string
	Fields  []generateField
}

type generateField struct {
	Name     string
	Initial  string
	TypeName string
	JSONName string
	View     string
}

// following the type, an optional third param could designate the editor.Input-like
// func to call which would output different text based on the element returned
// blog title:string Author:string PostCategory:string content:string:richtext some_thing:int

// blog title:string Author:string PostCategory:string content:string some_thing:int
func parseType(args []string) (generateType, error) {
	t := generateType{
		Name: fieldName(args[0]),
	}
	t.Initial = strings.ToLower(string(t.Name[0]))

	fields := args[1:]
	for _, field := range fields {
		f, err := parseField(field, t)
		if err != nil {
			return generateType{}, err
		}
		// NEW
		// set initial (1st character of the type's name) on field so we don't need
		// to set the template variable like was done in prior version
		f.Initial = t.Initial

		t.Fields = append(t.Fields, f)
	}

	return t, nil
}

func parseField(raw string, gt generateType) (generateField, error) {
	// contents:string or // contents:string:richtext
	if !strings.Contains(raw, ":") {
		return generateField{}, fmt.Errorf("Invalid generate argument. [%s]", raw)
	}

	data := strings.Split(raw, ":")

	field := generateField{
		Name:     fieldName(data[0]),
		Initial:  gt.Initial,
		TypeName: strings.ToLower(data[1]),
		JSONName: fieldJSONName(data[0]),
	}

	fieldType := "input"
	if len(data) == 3 {
		fieldType = data[2]
	}

	err := setFieldView(&field, fieldType)
	if err != nil {
		return generateField{}, err
	}

	return field, nil
}

// get the initial field name passed and check it for all possible cases
// MyTitle:string myTitle:string my_title:string -> MyTitle
// error-message:string -> ErrorMessage
func fieldName(name string) string {
	// remove _ or - if first character
	if name[0] == '-' || name[0] == '_' {
		name = name[1:]
	}

	// remove _ or - if last character
	if name[len(name)-1] == '-' || name[len(name)-1] == '_' {
		name = name[:len(name)-1]
	}

	// upcase the first character
	name = strings.ToUpper(string(name[0])) + name[1:]

	// remove _ or - character, and upcase the character immediately following
	for i := 0; i < len(name); i++ {
		r := rune(name[i])
		if isUnderscore(r) || isHyphen(r) {
			up := strings.ToUpper(string(name[i+1]))
			name = name[:i] + up + name[i+2:]
		}
	}

	return name
}

// get the initial field name passed and convert to json-like name
// MyTitle:string myTitle:string my_title:string -> my_title
// error-message:string -> error-message
func fieldJSONName(name string) string {
	// remove _ or - if first character
	if name[0] == '-' || name[0] == '_' {
		name = name[1:]
	}

	// downcase the first character
	name = strings.ToLower(string(name[0])) + name[1:]

	// check for uppercase character, downcase and insert _ before it if i-1
	// isn't already _ or -
	for i := 0; i < len(name); i++ {
		r := rune(name[i])
		if isUpper(r) {
			low := strings.ToLower(string(r))
			if name[i-1] == '_' || name[i-1] == '-' {
				name = name[:i] + low + name[i+1:]
			} else {
				name = name[:i] + "_" + low + name[i+1:]
			}
		}
	}

	return name
}

// set the specified view inside the editor field for a generated field for a type
func setFieldView(field *generateField, viewType string) error {
	var err error
	var tmpl *template.Template
	buf := &bytes.Buffer{}

	pwd, err := os.Getwd()
	if err != nil {
		return err
	}

	tmplDir := filepath.Join(pwd, "cmd", "ponzu", "templates")
	tmplFrom := func(filename string) (*template.Template, error) {
		return template.ParseFiles(filepath.Join(tmplDir, filename))
	}

	viewType = strings.ToLower(viewType)
	switch viewType {
	case "checkbox":
		tmpl, err = tmplFrom("gen-checkbox.tmpl")
	case "custom":
		tmpl, err = tmplFrom("gen-custom.tmpl")
	case "file":
		tmpl, err = tmplFrom("gen-file.tmpl")
	case "hidden":
		tmpl, err = tmplFrom("gen-hidden.tmpl")
	case "input", "text":
		tmpl, err = tmplFrom("gen-input.tmpl")
	case "richtext":
		tmpl, err = tmplFrom("gen-richtext.tmpl")
	case "select":
		tmpl, err = tmplFrom("gen-select.tmpl")
	case "textarea":
		tmpl, err = tmplFrom("gen-textarea.tmpl")
	case "tags":
		tmpl, err = tmplFrom("gen-tags.tmpl")
	default:
		msg := fmt.Sprintf("'%s' is not a recognized view type. Using 'input' instead.", viewType)
		fmt.Println(msg)
		tmpl, err = tmplFrom("gen-input.tmpl")
	}

	if err != nil {
		return err
	}

	err = tmpl.Execute(buf, field)
	if err != nil {
		return err
	}

	field.View = buf.String()

	return nil
}

func isUpper(char rune) bool {
	if char >= 'A' && char <= 'Z' {
		return true
	}

	return false
}

func isUnderscore(char rune) bool {
	return char == '_'
}

func isHyphen(char rune) bool {
	return char == '-'
}

func generateContentType(args []string) error {
	name := args[0]
	fileName := strings.ToLower(name) + ".go"

	// open file in ./content/ dir
	// if exists, alert user of conflict
	pwd, err := os.Getwd()
	if err != nil {
		return err
	}

	contentDir := filepath.Join(pwd, "content")
	filePath := filepath.Join(contentDir, fileName)

	if _, err := os.Stat(filePath); !os.IsNotExist(err) {
		return fmt.Errorf("Please remove '%s' before executing this command.", fileName)
	}

	// no file exists.. ok to write new one
	file, err := os.Create(filePath)
	defer file.Close()
	if err != nil {
		return err
	}

	// parse type info from args
	gt, err := parseType(args)
	if err != nil {
		return fmt.Errorf("Failed to parse type args: %s", err.Error())
	}

	tmplPath := filepath.Join(pwd, "cmd", "ponzu", "templates", "gen-content.tmpl")
	tmpl, err := template.ParseFiles(tmplPath)
	if err != nil {
		return fmt.Errorf("Failed to parse template: %s", err.Error())
	}

	buf := &bytes.Buffer{}
	err = tmpl.Execute(buf, gt)
	if err != nil {
		return fmt.Errorf("Failed to execute template: %s", err.Error())
	}

	fmtBuf, err := format.Source(buf.Bytes())
	if err != nil {
		return fmt.Errorf("Failed to format template: %s", err.Error())
	}

	_, err = file.Write(fmtBuf)
	if err != nil {
		return fmt.Errorf("Failed to write generated file buffer: %s", err.Error())
	}

	return nil
}
<commit_msg>remove old comment/reminder<commit_after>package main

import (
	"bytes"
	"fmt"
	"go/format"
	"os"
	"path/filepath"
	"strings"
	"text/template"
)

type generateType struct {
	Name    string
	Initial string
	Fields  []generateField
}

type generateField struct {
	Name     string
	Initial  string
	TypeName string
	JSONName string
	View     string
}

// blog title:string Author:string PostCategory:string content:string some_thing:int
func parseType(args []string) (generateType, error) {
	t := generateType{
		Name: fieldName(args[0]),
	}
	t.Initial = strings.ToLower(string(t.Name[0]))

	fields := args[1:]
	for _, field := range fields {
		f, err := parseField(field, t)
		if err != nil {
			return generateType{}, err
		}
		// NEW
		// set initial (1st character of the type's name) on field so we don't need
		// to set the template variable like was done in prior version
		f.Initial = t.Initial

		t.Fields = append(t.Fields, f)
	}

	return t, nil
}

func parseField(raw string, gt generateType) (generateField, error) {
	// contents:string or // contents:string:richtext
	if !strings.Contains(raw, ":") {
		return generateField{}, fmt.Errorf("Invalid generate argument. [%s]", raw)
	}

	data := strings.Split(raw, ":")

	field := generateField{
		Name:     fieldName(data[0]),
		Initial:  gt.Initial,
		TypeName: strings.ToLower(data[1]),
		JSONName: fieldJSONName(data[0]),
	}

	fieldType := "input"
	if len(data) == 3 {
		fieldType = data[2]
	}

	err := setFieldView(&field, fieldType)
	if err != nil {
		return generateField{}, err
	}

	return field, nil
}

// get the initial field name passed and check it for all possible cases
// MyTitle:string myTitle:string my_title:string -> MyTitle
// error-message:string -> ErrorMessage
func fieldName(name string) string {
	// remove _ or - if first character
	if name[0] == '-' || name[0] == '_' {
		name = name[1:]
	}

	// remove _ or - if last character
	if name[len(name)-1] == '-' || name[len(name)-1] == '_' {
		name = name[:len(name)-1]
	}

	// upcase the first character
	name = strings.ToUpper(string(name[0])) + name[1:]

	// remove _ or - character, and upcase the character immediately following
	for i := 0; i < len(name); i++ {
		r := rune(name[i])
		if isUnderscore(r) || isHyphen(r) {
			up := strings.ToUpper(string(name[i+1]))
			name = name[:i] + up + name[i+2:]
		}
	}

	return name
}

// get the initial field name passed and convert to json-like name
// MyTitle:string myTitle:string my_title:string -> my_title
// error-message:string -> error-message
func fieldJSONName(name string) string {
	// remove _ or - if first character
	if name[0] == '-' || name[0] == '_' {
		name = name[1:]
	}

	// downcase the first character
	name = strings.ToLower(string(name[0])) + name[1:]

	// check for uppercase character, downcase and insert _ before it if i-1
	// isn't already _ or -
	for i := 0; i < len(name); i++ {
		r := rune(name[i])
		if isUpper(r) {
			low := strings.ToLower(string(r))
			if name[i-1] == '_' || name[i-1] == '-' {
				name = name[:i] + low + name[i+1:]
			} else {
				name = name[:i] + "_" + low + name[i+1:]
			}
		}
	}

	return name
}

// set the specified view inside the editor field for a generated field for a type
func setFieldView(field *generateField, viewType string) error {
	var err error
	var tmpl *template.Template
	buf := &bytes.Buffer{}

	pwd, err := os.Getwd()
	if err != nil {
		return err
	}

	tmplDir := filepath.Join(pwd, "cmd", "ponzu", "templates")
	tmplFrom := func(filename string) (*template.Template, error) {
		return template.ParseFiles(filepath.Join(tmplDir, filename))
	}

	viewType = strings.ToLower(viewType)
	switch viewType {
	case "checkbox":
		tmpl, err = tmplFrom("gen-checkbox.tmpl")
	case "custom":
		tmpl, err = tmplFrom("gen-custom.tmpl")
	case "file":
		tmpl, err = tmplFrom("gen-file.tmpl")
	case "hidden":
		tmpl, err = tmplFrom("gen-hidden.tmpl")
	case "input", "text":
		tmpl, err = tmplFrom("gen-input.tmpl")
	case "richtext":
		tmpl, err = tmplFrom("gen-richtext.tmpl")
	case "select":
		tmpl, err = tmplFrom("gen-select.tmpl")
	case "textarea":
		tmpl, err = tmplFrom("gen-textarea.tmpl")
	case "tags":
		tmpl, err = tmplFrom("gen-tags.tmpl")
	default:
		msg := fmt.Sprintf("'%s' is not a recognized view type. Using 'input' instead.", viewType)
		fmt.Println(msg)
		tmpl, err = tmplFrom("gen-input.tmpl")
	}

	if err != nil {
		return err
	}

	err = tmpl.Execute(buf, field)
	if err != nil {
		return err
	}

	field.View = buf.String()

	return nil
}

func isUpper(char rune) bool {
	if char >= 'A' && char <= 'Z' {
		return true
	}

	return false
}

func isUnderscore(char rune) bool {
	return char == '_'
}

func isHyphen(char rune) bool {
	return char == '-'
}

func generateContentType(args []string) error {
	name := args[0]
	fileName := strings.ToLower(name) + ".go"

	// open file in ./content/ dir
	// if exists, alert user of conflict
	pwd, err := os.Getwd()
	if err != nil {
		return err
	}

	contentDir := filepath.Join(pwd, "content")
	filePath := filepath.Join(contentDir, fileName)

	if _, err := os.Stat(filePath); !os.IsNotExist(err) {
		return fmt.Errorf("Please remove '%s' before executing this command.", fileName)
	}

	// no file exists.. ok to write new one
	file, err := os.Create(filePath)
	defer file.Close()
	if err != nil {
		return err
	}

	// parse type info from args
	gt, err := parseType(args)
	if err != nil {
		return fmt.Errorf("Failed to parse type args: %s", err.Error())
	}

	tmplPath := filepath.Join(pwd, "cmd", "ponzu", "templates", "gen-content.tmpl")
	tmpl, err := template.ParseFiles(tmplPath)
	if err != nil {
		return fmt.Errorf("Failed to parse template: %s", err.Error())
	}

	buf := &bytes.Buffer{}
	err = tmpl.Execute(buf, gt)
	if err != nil {
		return fmt.Errorf("Failed to execute template: %s", err.Error())
	}

	fmtBuf, err := format.Source(buf.Bytes())
	if err != nil {
		return fmt.Errorf("Failed to format template: %s", err.Error())
	}

	_, err = file.Write(fmtBuf)
	if err != nil {
		return fmt.Errorf("Failed to write generated file buffer: %s", err.Error())
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/codegangsta/cli"
	"image/png"
	"io/ioutil"
	"log"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/DexterLB/traytor"
	"github.com/DexterLB/traytor/rpc"
	"github.com/valyala/gorpc"
)

type SampleCounter struct {
	sync.Mutex
	Counter int
}

func NewSampleCounter(value int) *SampleCounter {
	return &SampleCounter{Counter: value}
}

func (sc *SampleCounter) Dec() bool {
	sc.Lock()
	defer sc.Unlock()

	if sc.Counter > 0 {
		sc.Counter--
		return true
	}
	return false
}

func RenderLoop(
	sampleCounter *SampleCounter,
	client *gorpc.DispatcherClient,
	renderedImages chan<- *traytor.Image,
	width int,
	height int,
) {
	for {
		if !sampleCounter.Dec() {
			return
		}
		image, err := client.CallTimeout("Sample", [2]int{width, height}, 10*time.Minute)
		if err == nil {
			renderedImages <- image.(*traytor.Image)
			log.Printf("Rendered sample :)\n")
		} else {
			log.Printf("No sample :( %s\n", err)
		}
	}
}

func JoinSamples(
	renderedImages <-chan *traytor.Image,
	width int,
	height int,
) *traytor.Image {
	averageImage := traytor.NewImage(width, height)
	averageImage.Divisor = 0
	for image := range renderedImages {
		averageImage.Add(image)
		averageImage.Divisor += image.Divisor
	}
	return averageImage
}

func runClient(c *cli.Context) error {
	scene, image := getArguments(c)
	workers := c.StringSlice("worker")
	if len(workers) == 0 {
		showError(c, "can't render on zero workers :(")
	}

	fmt.Printf(
		"will render %s to %s of size %dx%d with %d threads on those workers: %s\n",
		scene, image,
		c.Int("width"), c.Int("height"),
		c.GlobalInt("max-jobs"),
		strings.Join(workers, ", "),
	)
	rr := rpc.NewRemoteRaytracer(time.Now().Unix())

	width, height := c.Int("width"), c.Int("height")
	sampleCounter := NewSampleCounter(30)
	renderedImages := make(chan *traytor.Image, 30)
	clients := make([]*gorpc.Client, len(workers))

	data, err := ioutil.ReadFile(scene)
	if err != nil {
		return fmt.Errorf("Error when loading scene: %s", err)
	}

	finishRender := &sync.WaitGroup{}
	finishRender.Add(len(workers))

	for i := range workers {
		clients[i] = &gorpc.Client{Addr: workers[i]}
		clients[i].Start()
		dispatcher := rr.Dispatcher.NewFuncClient(clients[i])
		_, err = dispatcher.CallTimeout("LoadScene", data, 10*time.Minute)
		if err != nil {
			return fmt.Errorf("Can't load scene: %s", err)
		}
		go func() {
			RenderLoop(sampleCounter, dispatcher, renderedImages, width, height)
			finishRender.Done()
		}()
	}

	go func() {
		finishRender.Wait()
		close(renderedImages)
	}()

	averageImage := JoinSamples(renderedImages, width, height)
	file, err := os.Create(image)
	defer file.Close()

	if err != nil {
		return fmt.Errorf("Error when saving image: %s", err)
	}
	png.Encode(file, averageImage)
	return nil
}
<commit_msg>Try remote render with 4 workers<commit_after>package main

import (
	"fmt"
	"github.com/codegangsta/cli"
	"image/png"
	"io/ioutil"
	"log"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/DexterLB/traytor"
	"github.com/DexterLB/traytor/rpc"
	"github.com/valyala/gorpc"
)

type SampleCounter struct {
	sync.Mutex
	Counter int
}

func NewSampleCounter(value int) *SampleCounter {
	return &SampleCounter{Counter: value}
}

func (sc *SampleCounter) Dec() bool {
	sc.Lock()
	defer sc.Unlock()

	if sc.Counter > 0 {
		sc.Counter--
		return true
	}
	return false
}

func RenderLoop(
	sampleCounter *SampleCounter,
	client *gorpc.DispatcherClient,
	renderedImages chan<- *traytor.Image,
	width int,
	height int,
) {
	for {
		if !sampleCounter.Dec() {
			return
		}
		image, err := client.CallTimeout("Sample", [2]int{width, height}, 10*time.Minute)
		if err == nil {
			renderedImages <- image.(*traytor.Image)
			log.Printf("Rendered sample :)\n")
		} else {
			log.Printf("No sample :( %s\n", err)
		}
	}
}

func JoinSamples(
	renderedImages <-chan *traytor.Image,
	width int,
	height int,
) *traytor.Image {
	averageImage := traytor.NewImage(width, height)
	averageImage.Divisor = 0
	for image := range renderedImages {
		averageImage.Add(image)
		averageImage.Divisor += image.Divisor
	}
	return averageImage
}

func runClient(c *cli.Context) error {
	scene, image := getArguments(c)
	workers := c.StringSlice("worker")
	if len(workers) == 0 {
		showError(c, "can't render on zero workers :(")
	}

	fmt.Printf(
		"will render %s to %s of size %dx%d with %d threads on those workers: %s\n",
		scene, image,
		c.Int("width"), c.Int("height"),
		c.GlobalInt("max-jobs"),
		strings.Join(workers, ", "),
	)
	rr := rpc.NewRemoteRaytracer(time.Now().Unix())

	width, height := c.Int("width"), c.Int("height")
	sampleCounter := NewSampleCounter(50)
	renderedImages := make(chan *traytor.Image, 50)
	clients := make([]*gorpc.Client, len(workers))

	data, err := ioutil.ReadFile(scene)
	if err != nil {
		return fmt.Errorf("Error when loading scene: %s", err)
	}

	finishRender := &sync.WaitGroup{}
	finishRender.Add(len(workers))

	for i := range workers {
		clients[i] = &gorpc.Client{Addr: workers[i]}
		clients[i].Start()
		dispatcher := rr.Dispatcher.NewFuncClient(clients[i])
		_, err = dispatcher.CallTimeout("LoadScene", data, 10*time.Minute)
		if err != nil {
			return fmt.Errorf("Can't load scene: %s", err)
		}
		go func() {
			RenderLoop(sampleCounter, dispatcher, renderedImages, width, height)
			finishRender.Done()
		}()
	}

	go func() {
		finishRender.Wait()
		close(renderedImages)
	}()

	averageImage := JoinSamples(renderedImages, width, height)
	file, err := os.Create(image)
	defer file.Close()

	if err != nil {
		return fmt.Errorf("Error when saving image: %s", err)
	}
	png.Encode(file, averageImage)
	return nil
}
<|endoftext|>


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

package main

import (
	"flag"
	"fmt"
	"image"
	"image/color"
	"image/draw"
	"image/png"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/astrogo/fitsio"

	"golang.org/x/exp/shiny/driver"
	"golang.org/x/exp/shiny/screen"
	"golang.org/x/mobile/event/key"
	"golang.org/x/mobile/event/lifecycle"
	"golang.org/x/mobile/event/paint"
	"golang.org/x/mobile/event/size"
)

type fileInfo struct {
	Name   string
	Images []image.Image
}

func main() {

	help := flag.Bool("help", false, "show help")

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, `view-fits - a FITS image viewer.

Usage of view-fits:
$ view-fits [file1 [file2 [...]]]

Examples:
$ view-fits astrogo/fitsio/testdata/file-img2-bitpix+08.fits
$ view-fits astrogo/fitsio/testdata/file-img2-bitpix*.fits
$ view-fits http://data.astropy.org/tutorials/FITS-images/HorseHead.fits
$ view-fits file:///some/file.fits

Controls:
- left/right arrows: switch to previous/next file
- up/down arrows:    switch to previous/next image in the current file
- r:                 reload/redisplay current image
- z:                 resize window to fit current image
- p:                 print current image to 'output.png'
- ?:                 show help
- q/ESC:             quit
`)
	}

	flag.Parse()

	if *help || len(os.Args) < 2 {
		flag.Usage()
		os.Exit(0)
	}

	log.SetFlags(0)
	log.SetPrefix("[view-fits] ")

	infos := processFiles()
	if len(infos) == 0 {
		log.Fatal("No image among given FITS files.")
	}

	type cursor struct {
		file int
		img  int
	}

	driver.Main(func(s screen.Screen) {

		// Number of files.
		nbFiles := len(infos)

		// Current displayed file and image in file.
		cur := cursor{file: 0, img: 0}

		// Building the main window.
		w, err := s.NewWindow(&screen.NewWindowOptions{
			Width:  500,
			Height: 500,
		})
		if err != nil {
			log.Fatal(err)
		}
		defer w.Release()

		// Building the screen buffer.
		b, err := s.NewBuffer(image.Point{500, 500})
		if err != nil {
			log.Fatal(err)
		}
		defer release(b)

		w.Fill(b.Bounds(), color.Black, draw.Src)
		w.Publish()

		repaint := true
		var (
			sz size.Event
			//bkg = color.Black
			bkg = color.RGBA{0xe0, 0xe0, 0xe0, 0xff} // Material Design "Grey 300"
		)

		for {
			switch e := w.NextEvent().(type) {
			default:
				// ignore

			case lifecycle.Event:
				switch {
				case e.From == lifecycle.StageVisible && e.To == lifecycle.StageFocused:
					repaint = true
				default:
					repaint = false
				}
				if repaint {
					w.Send(paint.Event{})
				}

			case key.Event:
				switch e.Code {
				case key.CodeEscape, key.CodeQ:
					return

				case key.CodeSlash:
					if e.Direction == key.DirPress && e.Modifiers&key.ModShift != 0 {
						flag.Usage()
						continue
					}

				case key.CodeRightArrow:
					if e.Direction == key.DirPress {
						repaint = true
						if cur.file < nbFiles-1 {
							cur.file++
						} else {
							cur.file = 0
						}
						cur.img = 0
						log.Printf("file:   %v\n", infos[cur.file].Name)
						log.Printf("images: %d\n", len(infos[cur.file].Images))
					}

				case key.CodeLeftArrow:
					if e.Direction == key.DirPress {
						repaint = true
						if cur.file == 0 {
							cur.file = nbFiles - 1
						} else {
							cur.file--
						}
						cur.img = 0
						log.Printf("file:   %v\n", infos[cur.file].Name)
						log.Printf("images: %d\n", len(infos[cur.file].Images))
					}

				case key.CodeDownArrow:
					if e.Direction == key.DirPress {
						repaint = true
						nbImg := len(infos[cur.file].Images)
						if cur.img < nbImg-1 {
							cur.img++
						} else {
							cur.img = 0
						}
					}

				case key.CodeUpArrow:
					if e.Direction == key.DirPress {
						repaint = true
						nbImg := len(infos[cur.file].Images)
						if cur.img == 0 {
							cur.img = nbImg - 1
						} else {
							cur.img--
						}
					}

				case key.CodeR:
					if e.Direction == key.DirPress {
						repaint = true
					}

				case key.CodeZ:
					if e.Direction == key.DirPress {
						// resize to current image
						// TODO(sbinet)
						repaint = true
					}

				case key.CodeP:
					if e.Direction != key.DirPress {
						continue
					}
					out, err := os.Create("output.png")
					if err != nil {
						log.Fatalf("error printing image: %v\n", err)
					}
					defer out.Close()
					err = png.Encode(out, infos[cur.file].Images[cur.img])
					if err != nil {
						log.Fatalf("error printing image: %v\n", err)
					}
					err = out.Close()
					if err != nil {
						log.Fatalf("error printing image: %v\n", err)
					}
					log.Printf("printed current image to [%s]\n", out.Name())
				}

				if repaint {
					w.Send(paint.Event{})
				}

			case size.Event:
				sz = e

			case paint.Event:
				if !repaint {
					continue
				}
				repaint = false
				img := infos[cur.file].Images[cur.img]

				release(b)
				b, err = s.NewBuffer(img.Bounds().Size())
				if err != nil {
					log.Fatal(err)
				}
				defer release(b)

				draw.Draw(b.RGBA(), b.Bounds(), img, image.Point{}, draw.Src)

				w.Fill(sz.Bounds(), bkg, draw.Src)
				w.Upload(image.Point{}, b, img.Bounds())
				w.Publish()
			}

		}

	})
}

func processFiles() []fileInfo {
	infos := make([]fileInfo, 0, len(flag.Args()))
	// Parsing input files.
	for _, fname := range flag.Args() {

		finfo := fileInfo{Name: fname}

		r, err := openStream(fname)
		if err != nil {
			log.Fatalf("Can not open the input file: %v", err)
		}
		defer r.Close()

		// Opening the FITS file.
		f, err := fitsio.Open(r)
		if err != nil {
			log.Fatalf("Can not open the FITS input file: %v", err)
		}
		defer f.Close()

		// Getting the file HDUs.
		hdus := f.HDUs()
		for _, hdu := range hdus {
			// Getting the header informations.
			header := hdu.Header()
			axes := header.Axes()

			// Discarding HDU with no axes.
			if len(axes) != 0 {
				if hdu, ok := hdu.(fitsio.Image); ok {
					img := hdu.Image()
					if img != nil {
						finfo.Images = append(finfo.Images, img)
					}
				}
			}
		}

		if len(finfo.Images) > 0 {
			infos = append(infos, finfo)
		}
	}

	return infos
}

func openStream(name string) (io.ReadCloser, error) {
	switch {
	case strings.HasPrefix(name, "http://") || strings.HasPrefix(name, "https://"):
		resp, err := http.Get(name)
		if err != nil {
			return nil, err
		}
		defer resp.Body.Close()

		f, err := ioutil.TempFile("", "view-fits-")
		if err != nil {
			return nil, err
		}

		_, err = io.Copy(f, resp.Body)
		if err != nil {
			f.Close()
			return nil, err
		}

		// make sure we have at least a full FITS block
		f.Seek(0, 2880)
		f.Seek(0, 0)

		return f, nil

	case strings.HasPrefix(name, "file://"):
		name = name[len("file://"):]
		return os.Open(name)
	default:
		return os.Open(name)
	}
}

type releaser interface {
	Release()
}

func release(r releaser) {
	if r != nil {
		r.Release()
	}
}
<commit_msg>cmd/view-fits: add godoc doc-string<commit_after>// Copyright 2016 The astrogo Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// view-fits is a simple program to display images in a FITS file.
//
// Usage of view-fits:
// $ view-fits [file1 [file2 [...]]]
//
// Examples:
//  $ view-fits astrogo/fitsio/testdata/file-img2-bitpix+08.fits
//  $ view-fits astrogo/fitsio/testdata/file-img2-bitpix*.fits
//  $ view-fits http://data.astropy.org/tutorials/FITS-images/HorseHead.fits
//  $ view-fits file:///some/file.fits
//
// Controls:
//  - left/right arrows: switch to previous/next file
//  - up/down arrows:    switch to previous/next image in the current file
//  - r:                 reload/redisplay current image
//  - z:                 resize window to fit current image
//  - p:                 print current image to 'output.png'
//  - ?:                 show help
//  - q/ESC:             quit
//
package main

import (
	"flag"
	"fmt"
	"image"
	"image/color"
	"image/draw"
	"image/png"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/astrogo/fitsio"

	"golang.org/x/exp/shiny/driver"
	"golang.org/x/exp/shiny/screen"
	"golang.org/x/mobile/event/key"
	"golang.org/x/mobile/event/lifecycle"
	"golang.org/x/mobile/event/paint"
	"golang.org/x/mobile/event/size"
)

type fileInfo struct {
	Name   string
	Images []image.Image
}

func main() {

	help := flag.Bool("help", false, "show help")

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, `view-fits - a FITS image viewer.

Usage of view-fits:
$ view-fits [file1 [file2 [...]]]

Examples:
$ view-fits astrogo/fitsio/testdata/file-img2-bitpix+08.fits
$ view-fits astrogo/fitsio/testdata/file-img2-bitpix*.fits
$ view-fits http://data.astropy.org/tutorials/FITS-images/HorseHead.fits
$ view-fits file:///some/file.fits

Controls:
- left/right arrows: switch to previous/next file
- up/down arrows:    switch to previous/next image in the current file
- r:                 reload/redisplay current image
- z:                 resize window to fit current image
- p:                 print current image to 'output.png'
- ?:                 show help
- q/ESC:             quit
`)
	}

	flag.Parse()

	if *help || len(os.Args) < 2 {
		flag.Usage()
		os.Exit(0)
	}

	log.SetFlags(0)
	log.SetPrefix("[view-fits] ")

	infos := processFiles()
	if len(infos) == 0 {
		log.Fatal("No image among given FITS files.")
	}

	type cursor struct {
		file int
		img  int
	}

	driver.Main(func(s screen.Screen) {

		// Number of files.
		nbFiles := len(infos)

		// Current displayed file and image in file.
		cur := cursor{file: 0, img: 0}

		// Building the main window.
		w, err := s.NewWindow(&screen.NewWindowOptions{
			Width:  500,
			Height: 500,
		})
		if err != nil {
			log.Fatal(err)
		}
		defer w.Release()

		// Building the screen buffer.
		b, err := s.NewBuffer(image.Point{500, 500})
		if err != nil {
			log.Fatal(err)
		}
		defer release(b)

		w.Fill(b.Bounds(), color.Black, draw.Src)
		w.Publish()

		repaint := true
		var (
			sz size.Event
			//bkg = color.Black
			bkg = color.RGBA{0xe0, 0xe0, 0xe0, 0xff} // Material Design "Grey 300"
		)

		for {
			switch e := w.NextEvent().(type) {
			default:
				// ignore

			case lifecycle.Event:
				switch {
				case e.From == lifecycle.StageVisible && e.To == lifecycle.StageFocused:
					repaint = true
				default:
					repaint = false
				}
				if repaint {
					w.Send(paint.Event{})
				}

			case key.Event:
				switch e.Code {
				case key.CodeEscape, key.CodeQ:
					return

				case key.CodeSlash:
					if e.Direction == key.DirPress && e.Modifiers&key.ModShift != 0 {
						flag.Usage()
						continue
					}

				case key.CodeRightArrow:
					if e.Direction == key.DirPress {
						repaint = true
						if cur.file < nbFiles-1 {
							cur.file++
						} else {
							cur.file = 0
						}
						cur.img = 0
						log.Printf("file:   %v\n", infos[cur.file].Name)
						log.Printf("images: %d\n", len(infos[cur.file].Images))
					}

				case key.CodeLeftArrow:
					if e.Direction == key.DirPress {
						repaint = true
						if cur.file == 0 {
							cur.file = nbFiles - 1
						} else {
							cur.file--
						}
						cur.img = 0
						log.Printf("file:   %v\n", infos[cur.file].Name)
						log.Printf("images: %d\n", len(infos[cur.file].Images))
					}

				case key.CodeDownArrow:
					if e.Direction == key.DirPress {
						repaint = true
						nbImg := len(infos[cur.file].Images)
						if cur.img < nbImg-1 {
							cur.img++
						} else {
							cur.img = 0
						}
					}

				case key.CodeUpArrow:
					if e.Direction == key.DirPress {
						repaint = true
						nbImg := len(infos[cur.file].Images)
						if cur.img == 0 {
							cur.img = nbImg - 1
						} else {
							cur.img--
						}
					}

				case key.CodeR:
					if e.Direction == key.DirPress {
						repaint = true
					}

				case key.CodeZ:
					if e.Direction == key.DirPress {
						// resize to current image
						// TODO(sbinet)
						repaint = true
					}

				case key.CodeP:
					if e.Direction != key.DirPress {
						continue
					}
					out, err := os.Create("output.png")
					if err != nil {
						log.Fatalf("error printing image: %v\n", err)
					}
					defer out.Close()
					err = png.Encode(out, infos[cur.file].Images[cur.img])
					if err != nil {
						log.Fatalf("error printing image: %v\n", err)
					}
					err = out.Close()
					if err != nil {
						log.Fatalf("error printing image: %v\n", err)
					}
					log.Printf("printed current image to [%s]\n", out.Name())
				}

				if repaint {
					w.Send(paint.Event{})
				}

			case size.Event:
				sz = e

			case paint.Event:
				if !repaint {
					continue
				}
				repaint = false
				img := infos[cur.file].Images[cur.img]

				release(b)
				b, err = s.NewBuffer(img.Bounds().Size())
				if err != nil {
					log.Fatal(err)
				}
				defer release(b)

				draw.Draw(b.RGBA(), b.Bounds(), img, image.Point{}, draw.Src)

				w.Fill(sz.Bounds(), bkg, draw.Src)
				w.Upload(image.Point{}, b, img.Bounds())
				w.Publish()
			}

		}

	})
}

func processFiles() []fileInfo {
	infos := make([]fileInfo, 0, len(flag.Args()))
	// Parsing input files.
	for _, fname := range flag.Args() {

		finfo := fileInfo{Name: fname}

		r, err := openStream(fname)
		if err != nil {
			log.Fatalf("Can not open the input file: %v", err)
		}
		defer r.Close()

		// Opening the FITS file.
		f, err := fitsio.Open(r)
		if err != nil {
			log.Fatalf("Can not open the FITS input file: %v", err)
		}
		defer f.Close()

		// Getting the file HDUs.
		hdus := f.HDUs()
		for _, hdu := range hdus {
			// Getting the header informations.
			header := hdu.Header()
			axes := header.Axes()

			// Discarding HDU with no axes.
			if len(axes) != 0 {
				if hdu, ok := hdu.(fitsio.Image); ok {
					img := hdu.Image()
					if img != nil {
						finfo.Images = append(finfo.Images, img)
					}
				}
			}
		}

		if len(finfo.Images) > 0 {
			infos = append(infos, finfo)
		}
	}

	return infos
}

func openStream(name string) (io.ReadCloser, error) {
	switch {
	case strings.HasPrefix(name, "http://") || strings.HasPrefix(name, "https://"):
		resp, err := http.Get(name)
		if err != nil {
			return nil, err
		}
		defer resp.Body.Close()

		f, err := ioutil.TempFile("", "view-fits-")
		if err != nil {
			return nil, err
		}

		_, err = io.Copy(f, resp.Body)
		if err != nil {
			f.Close()
			return nil, err
		}

		// make sure we have at least a full FITS block
		f.Seek(0, 2880)
		f.Seek(0, 0)

		return f, nil

	case strings.HasPrefix(name, "file://"):
		name = name[len("file://"):]
		return os.Open(name)
	default:
		return os.Open(name)
	}
}

type releaser interface {
	Release()
}

func release(r releaser) {
	if r != nil {
		r.Release()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	log "github.com/whosonfirst/go-whosonfirst-log"
	pip "github.com/whosonfirst/go-whosonfirst-pip"
	"io"
	"net/http"
	"os"
	"strconv"
	"sync"
	"time"
)

func main() {

	var host = flag.String("host", "localhost", "The hostname to listen for requests on")
	var port = flag.Int("port", 8080, "The port number to listen for requests on")
	var data = flag.String("data", "", "The data directory where WOF data lives, required")
	var cache_all = flag.Bool("cache_all", false, "Just cache everything, regardless of size")
	var cache_size = flag.Int("cache_size", 1024, "The number of WOF records with large geometries to cache")
	var cache_trigger = flag.Int("cache_trigger", 2000, "The minimum number of coordinates in a WOF record that will trigger caching")
	var strict = flag.Bool("strict", false, "Enable strict placetype checking")
	var loglevel = flag.String("loglevel", "info", "Log level for reporting")
	var logs = flag.String("logs", "", "Where to write logs to disk")
	var metrics = flag.String("metrics", "", "Where to write (@rcrowley go-metrics style) metrics to disk")
	var format = flag.String("metrics-as", "plain", "Format metrics as... ? Valid options are \"json\" and \"plain\"")
	var cors = flag.Bool("cors", false, "Enable CORS headers")

	flag.Parse()
	args := flag.Args()

	if *data == "" {
		panic("missing data")
	}

	_, err := os.Stat(*data)

	if os.IsNotExist(err) {
		panic("data does not exist")
	}

	var l_writer io.Writer
	var m_writer io.Writer

	l_writer = io.MultiWriter(os.Stdout)

	if *logs != "" {

		l_file, l_err := os.OpenFile(*logs, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0660)

		if l_err != nil {
			panic(l_err)
		}

		l_writer = io.MultiWriter(os.Stdout, l_file)
	}

	logger := log.NewWOFLogger("[wof-pip-server] ")
	logger.AddLogger(l_writer, *loglevel)

	if *cache_all {

		*cache_size = 0
		*cache_trigger = 1

		mu := new(sync.Mutex)
		wg := new(sync.WaitGroup)

		for _, path := range args {

			wg.Add(1)

			go func(path string) {
				defer wg.Done()

				count := 0

				fh, err := os.Open(path)

				if err != nil {
					logger.Error("failed to open %s for reading, because %v", path, err)
					os.Exit(1)
				}

				scanner := bufio.NewScanner(fh)

				for scanner.Scan() {
					count += 1
				}

				mu.Lock()
				*cache_size += count
				mu.Unlock()

			}(path)
		}

		wg.Wait()

		logger.Status("set cache_size to %d and cache_trigger to %d", *cache_size, *cache_trigger)
	}

	p, p_err := pip.NewPointInPolygon(*data, *cache_size, *cache_trigger, logger)

	if p_err != nil {
		panic(p_err)
	}

	if *metrics != "" {

		m_file, m_err := os.OpenFile(*metrics, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0660)

		if m_err != nil {
			panic(m_err)
		}

		m_writer = io.MultiWriter(m_file)
		_ = p.SendMetricsTo(m_writer, 60e9, *format)
	}

	t1 := time.Now()

	for _, path := range args {
		p.IndexMetaFile(path)
	}

	t2 := float64(time.Since(t1)) / 1e9

	p.Logger.Status("indexed %d records in %.3f seconds", p.Rtree.Size(), t2)

	for pt, count := range p.Placetypes {
		p.Logger.Status("indexed %s: %d", pt, count)
	}

	handler := func(rsp http.ResponseWriter, req *http.Request) {

		query := req.URL.Query()

		str_lat := query.Get("latitude")
		str_lon := query.Get("longitude")
		placetype := query.Get("placetype")

		if str_lat == "" {
			http.Error(rsp, "Missing latitude parameter", http.StatusBadRequest)
			return
		}

		if str_lon == "" {
			http.Error(rsp, "Missing longitude parameter", http.StatusBadRequest)
			return
		}

		lat, lat_err := strconv.ParseFloat(str_lat, 64)
		lon, lon_err := strconv.ParseFloat(str_lon, 64)

		if lat_err != nil {
			http.Error(rsp, "Invalid latitude parameter", http.StatusBadRequest)
			return
		}

		if lon_err != nil {
			http.Error(rsp, "Invalid longitude parameter", http.StatusBadRequest)
			return
		}

		if lat > 90.0 || lat < -90.0 {
			http.Error(rsp, "E_IMPOSSIBLE_LATITUDE", http.StatusBadRequest)
			return
		}

		if lon > 180.0 || lon < -180.0 {
			http.Error(rsp, "E_IMPOSSIBLE_LONGITUDE", http.StatusBadRequest)
			return
		}

		if placetype != "" {

			if *strict && !p.IsKnownPlacetype(placetype) {
				http.Error(rsp, "Unknown placetype", http.StatusBadRequest)
				return
			}
		}

		results, timings := p.GetByLatLonForPlacetype(lat, lon, placetype)

		count := len(results)
		ttp := 0.0

		for _, t := range timings {
			ttp += t.Duration
		}

		if placetype != "" {
			p.Logger.Debug("time to reverse geocode %f, %f @%s: %d results in %f seconds ", lat, lon, placetype, count, ttp)
		} else {
			p.Logger.Debug("time to reverse geocode %f, %f: %d results in %f seconds ", lat, lon, count, ttp)
		}

		js, err := json.Marshal(results)

		if err != nil {
			http.Error(rsp, err.Error(), http.StatusInternalServerError)
			return
		}

		// maybe this although it seems like it adds functionality for a lot of
		// features this server does not need - https://github.com/rs/cors
		// (20151022/thisisaaronland)

		if *cors {
			rsp.Header().Set("Access-Control-Allow-Origin", "*")
		}

		rsp.Header().Set("Content-Type", "application/json")
		rsp.Write(js)
	}

	endpoint := fmt.Sprintf("%s:%d", *host, *port)

	http.HandleFunc("/", handler)
	http.ListenAndServe(endpoint, nil)
}
<commit_msg>add proper error checking when starting pip-server (thanks @dphiffer!)<commit_after>package main

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	log "github.com/whosonfirst/go-whosonfirst-log"
	pip "github.com/whosonfirst/go-whosonfirst-pip"
	"io"
	"net/http"
	"os"
	"strconv"
	"sync"
	"time"
)

func main() {

	var host = flag.String("host", "localhost", "The hostname to listen for requests on")
	var port = flag.Int("port", 8080, "The port number to listen for requests on")
	var data = flag.String("data", "", "The data directory where WOF data lives, required")
	var cache_all = flag.Bool("cache_all", false, "Just cache everything, regardless of size")
	var cache_size = flag.Int("cache_size", 1024, "The number of WOF records with large geometries to cache")
	var cache_trigger = flag.Int("cache_trigger", 2000, "The minimum number of coordinates in a WOF record that will trigger caching")
	var strict = flag.Bool("strict", false, "Enable strict placetype checking")
	var loglevel = flag.String("loglevel", "info", "Log level for reporting")
	var logs = flag.String("logs", "", "Where to write logs to disk")
	var metrics = flag.String("metrics", "", "Where to write (@rcrowley go-metrics style) metrics to disk")
	var format = flag.String("metrics-as", "plain", "Format metrics as... ? Valid options are \"json\" and \"plain\"")
	var cors = flag.Bool("cors", false, "Enable CORS headers")

	flag.Parse()
	args := flag.Args()

	if *data == "" {
		panic("missing data")
	}

	_, err := os.Stat(*data)

	if os.IsNotExist(err) {
		panic("data does not exist")
	}

	var l_writer io.Writer
	var m_writer io.Writer

	l_writer = io.MultiWriter(os.Stdout)

	if *logs != "" {

		l_file, l_err := os.OpenFile(*logs, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0660)

		if l_err != nil {
			panic(l_err)
		}

		l_writer = io.MultiWriter(os.Stdout, l_file)
	}

	logger := log.NewWOFLogger("[wof-pip-server] ")
	logger.AddLogger(l_writer, *loglevel)

	if *cache_all {

		*cache_size = 0
		*cache_trigger = 1

		mu := new(sync.Mutex)
		wg := new(sync.WaitGroup)

		for _, path := range args {

			wg.Add(1)

			go func(path string) {
				defer wg.Done()

				count := 0

				fh, err := os.Open(path)

				if err != nil {
					logger.Error("failed to open %s for reading, because %v", path, err)
					os.Exit(1)
				}

				scanner := bufio.NewScanner(fh)

				for scanner.Scan() {
					count += 1
				}

				mu.Lock()
				*cache_size += count
				mu.Unlock()

			}(path)
		}

		wg.Wait()

		logger.Status("set cache_size to %d and cache_trigger to %d", *cache_size, *cache_trigger)
	}

	p, p_err := pip.NewPointInPolygon(*data, *cache_size, *cache_trigger, logger)

	if p_err != nil {
		panic(p_err)
	}

	if *metrics != "" {

		m_file, m_err := os.OpenFile(*metrics, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0660)

		if m_err != nil {
			panic(m_err)
		}

		m_writer = io.MultiWriter(m_file)
		_ = p.SendMetricsTo(m_writer, 60e9, *format)
	}

	t1 := time.Now()

	for _, path := range args {
		p.IndexMetaFile(path)
	}

	t2 := float64(time.Since(t1)) / 1e9

	p.Logger.Status("indexed %d records in %.3f seconds", p.Rtree.Size(), t2)

	for pt, count := range p.Placetypes {
		p.Logger.Status("indexed %s: %d", pt, count)
	}

	handler := func(rsp http.ResponseWriter, req *http.Request) {

		query := req.URL.Query()

		str_lat := query.Get("latitude")
		str_lon := query.Get("longitude")
		placetype := query.Get("placetype")

		if str_lat == "" {
			http.Error(rsp, "Missing latitude parameter", http.StatusBadRequest)
			return
		}

		if str_lon == "" {
			http.Error(rsp, "Missing longitude parameter", http.StatusBadRequest)
			return
		}

		lat, lat_err := strconv.ParseFloat(str_lat, 64)
		lon, lon_err := strconv.ParseFloat(str_lon, 64)

		if lat_err != nil {
			http.Error(rsp, "Invalid latitude parameter", http.StatusBadRequest)
			return
		}

		if lon_err != nil {
			http.Error(rsp, "Invalid longitude parameter", http.StatusBadRequest)
			return
		}

		if lat > 90.0 || lat < -90.0 {
			http.Error(rsp, "E_IMPOSSIBLE_LATITUDE", http.StatusBadRequest)
			return
		}

		if lon > 180.0 || lon < -180.0 {
			http.Error(rsp, "E_IMPOSSIBLE_LONGITUDE", http.StatusBadRequest)
			return
		}

		if placetype != "" {

			if *strict && !p.IsKnownPlacetype(placetype) {
				http.Error(rsp, "Unknown placetype", http.StatusBadRequest)
				return
			}
		}

		results, timings := p.GetByLatLonForPlacetype(lat, lon, placetype)

		count := len(results)
		ttp := 0.0

		for _, t := range timings {
			ttp += t.Duration
		}

		if placetype != "" {
			p.Logger.Debug("time to reverse geocode %f, %f @%s: %d results in %f seconds ", lat, lon, placetype, count, ttp)
		} else {
			p.Logger.Debug("time to reverse geocode %f, %f: %d results in %f seconds ", lat, lon, count, ttp)
		}

		js, err := json.Marshal(results)

		if err != nil {
			http.Error(rsp, err.Error(), http.StatusInternalServerError)
			return
		}

		// maybe this although it seems like it adds functionality for a lot of
		// features this server does not need - https://github.com/rs/cors
		// (20151022/thisisaaronland)

		if *cors {
			rsp.Header().Set("Access-Control-Allow-Origin", "*")
		}

		rsp.Header().Set("Content-Type", "application/json")
		rsp.Write(js)
	}

	endpoint := fmt.Sprintf("%s:%d", *host, *port)

	http.HandleFunc("/", handler)
	err = http.ListenAndServe(endpoint, nil)

	if err != nil {
	       logger.Error("failed to start server, because %v", err)
	       os.Exit(1)
	}

	os.Exit(0)
}
<|endoftext|>


<commit_before>package handlers

import (
	"database/sql"
	"fmt"
	"log"
	"os"

	"github.com/kisielk/sqlstruct"
	"github.com/nelsonleduc/calmanbot/service"
)

type Cached struct {
	ID     int    `sql:"id"`
	Query  string `sql:"query"`
	Result string `sql:"result"`
}

type SmartCache struct {
	monitor service.Monitor
}

func NewSmartCache(monitor service.Monitor) SmartCache {
	return SmartCache{monitor}
}

func (s SmartCache) CachedResponse(message string) *string {

	cached, _ := cacheFetch("WHERE query = $1", []interface{}{message})

	first := cached[0]
	s.monitor.ValueFor(first.ID)

	return nil
}

func (s SmartCache) CacheQuery(query, result string) int {
	queryStr := "INSERT INTO cached(query, result) VALUES($1, $2) RETURNING id"
	row := currentDB.QueryRow(queryStr, query, result)

	var id int
	row.Scan(&id)

	return id
}

//Temp DB
var currentDB *sql.DB

func init() {
	currentDB = connect()
}

func connect() *sql.DB {
	dbUrl := os.Getenv("DATABASE_URL")
	database, err := sql.Open("postgres", dbUrl)
	if err != nil {
		log.Fatalf("[x] Could not open the connection to the database. Reason: %s", err.Error())
	}
	return database
}

func cacheFetch(whereStr string, values []interface{}) ([]Cached, error) {

	queryStr := fmt.Sprintf("SELECT %s FROM cached", sqlstruct.Columns(Cached{}))

	fmt.Println(queryStr)

	rows, err := currentDB.Query(queryStr+" "+whereStr, values...)
	if err != nil {
		return []Cached{}, err
	}
	defer rows.Close()

	actions := []Cached{}
	for rows.Next() {
		var act Cached
		err := sqlstruct.Scan(&act, rows)
		if err == nil {
			actions = append(actions, act)
		}
	}

	return actions, nil
}
<commit_msg>Minor safety<commit_after>package handlers

import (
	"database/sql"
	"fmt"
	"log"
	"os"

	"github.com/kisielk/sqlstruct"
	"github.com/nelsonleduc/calmanbot/service"
)

type Cached struct {
	ID     int    `sql:"id"`
	Query  string `sql:"query"`
	Result string `sql:"result"`
}

type SmartCache struct {
	monitor service.Monitor
}

func NewSmartCache(monitor service.Monitor) SmartCache {
	return SmartCache{monitor}
}

func (s SmartCache) CachedResponse(message string) *string {

	cached, _ := cacheFetch("WHERE query = $1", []interface{}{message})

	if len(cached) == 0 {
		return nil
	}

	first := cached[0]
	s.monitor.ValueFor(first.ID)

	return nil
}

func (s SmartCache) CacheQuery(query, result string) int {
	queryStr := "INSERT INTO cached(query, result) VALUES($1, $2) RETURNING id"
	row := currentDB.QueryRow(queryStr, query, result)

	var id int
	row.Scan(&id)

	return id
}

//Temp DB
var currentDB *sql.DB

func init() {
	currentDB = connect()
}

func connect() *sql.DB {
	dbUrl := os.Getenv("DATABASE_URL")
	database, err := sql.Open("postgres", dbUrl)
	if err != nil {
		log.Fatalf("[x] Could not open the connection to the database. Reason: %s", err.Error())
	}
	return database
}

func cacheFetch(whereStr string, values []interface{}) ([]Cached, error) {

	queryStr := fmt.Sprintf("SELECT %s FROM cached", sqlstruct.Columns(Cached{}))

	fmt.Println(queryStr)

	rows, err := currentDB.Query(queryStr+" "+whereStr, values...)
	if err != nil {
		return []Cached{}, err
	}
	defer rows.Close()

	actions := []Cached{}
	for rows.Next() {
		var act Cached
		err := sqlstruct.Scan(&act, rows)
		if err == nil {
			actions = append(actions, act)
		}
	}

	return actions, 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:
// - Aaron Meihm ameihm@mozilla.com

package main

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"net/http"
	slib "servicelib"
	"strconv"
)

func getRRA(op opContext, rraid string) (slib.RRAService, error) {
	var rr slib.RRAService

	err := op.QueryRow(`SELECT rraid, service,
		ari, api, afi, cri, cpi, cfi,
		iri, ipi, ifi,
		arp, app, afp, crp, cpp, cfp,
		irp, ipp, ifp, datadefault, raw
		FROM rra WHERE rraid = $1`, rraid).Scan(&rr.ID,
		&rr.Name, &rr.AvailRepImpact, &rr.AvailPrdImpact,
		&rr.AvailFinImpact, &rr.ConfiRepImpact, &rr.ConfiPrdImpact, &rr.ConfiFinImpact,
		&rr.IntegRepImpact, &rr.IntegPrdImpact, &rr.IntegFinImpact,
		&rr.AvailRepProb, &rr.AvailPrdProb, &rr.AvailFinProb,
		&rr.ConfiRepProb, &rr.ConfiPrdProb, &rr.ConfiFinProb,
		&rr.IntegRepProb, &rr.IntegPrdProb, &rr.IntegFinProb,
		&rr.DefData, &rr.RawRRA)
	if err != nil {
		if err == sql.ErrNoRows {
			return rr, nil
		} else {
			return rr, err
		}
	}
	err = rraResolveSupportGroups(op, &rr)
	if err != nil {
		return rr, err
	}

	return rr, nil
}

func rraResolveSupportGroups(op opContext, r *slib.RRAService) error {
	r.SupportGrps = make([]slib.SystemGroup, 0)
	rows, err := op.Query(`SELECT sysgroupid FROM
		rra_sysgroup WHERE rraid = $1`,
		r.ID)
	if err != nil {
		return err
	}
	for rows.Next() {
		var sgid string
		err = rows.Scan(&sgid)
		if err != nil {
			rows.Close()
			return err
		}
		sg, err := getSysGroup(op, sgid)
		if err != nil {
			rows.Close()
			return err
		}
		if sg.Name == "" {
			continue
		}
		r.SupportGrps = append(r.SupportGrps, sg)
	}
	err = rows.Err()
	if err != nil {
		return err
	}
	return nil
}

// Return a risk document that includes all RRAs
func serviceRisks(rw http.ResponseWriter, req *http.Request) {
	op := opContext{}
	op.newContext(dbconn, false, req.RemoteAddr)

	rows, err := op.Query(`SELECT rraid FROM rra`)
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}
	resp := slib.RisksResponse{}
	for rows.Next() {
		var rraid int
		err = rows.Scan(&rraid)
		if err != nil {
			rows.Close()
			op.logf(err.Error())
			http.Error(rw, err.Error(), 500)
			return
		}
		rs, err := riskForRRA(op, true, rraid)
		if err != nil {
			rows.Close()
			op.logf(err.Error())
			http.Error(rw, err.Error(), 500)
			return
		}
		resp.Risks = append(resp.Risks, rs)
	}
	err = rows.Err()
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}

	buf, err := json.Marshal(&resp)
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}
	fmt.Fprintf(rw, string(buf))
}

// Calculate the risk for the requested RRA
func serviceGetRRARisk(rw http.ResponseWriter, req *http.Request) {
	req.ParseForm()

	op := opContext{}
	op.newContext(dbconn, false, req.RemoteAddr)

	rraid := req.FormValue("id")
	if rraid == "" {
		err := fmt.Errorf("no rra id specified")
		op.logf(err.Error())
		http.Error(rw, err.Error(), 400)
		return
	}
	r, err := strconv.Atoi(rraid)
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}
	rs, err := riskForRRA(op, true, r)
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}

	buf, err := json.Marshal(&rs)
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}
	fmt.Fprintf(rw, string(buf))
}

// Read incoming RRA and update database as required. This can result in a
// new RRA being added, or an existing RRA being updated.
func serviceUpdateRRA(rw http.ResponseWriter, req *http.Request) {
	req.ParseMultipartForm(10000000)

	rawrra := req.FormValue("rra")
	if rawrra == "" {
		logf("no rra parameter in update request")
		http.Error(rw, "no rra parameter in update request", 500)
		return
	}

	op := opContext{}
	op.newContext(dbconn, false, req.RemoteAddr)

	// XXX Use the same import function we use in the RRA importer for now.
	// This can be cleaned up once the RRA importer is removed and the POST
	// functionality for RRAs is being used exclusively.
	var (
		nrra    rraESData
		rraList []rraESData
	)
	err := json.Unmarshal([]byte(rawrra), &nrra.rra)
	if err != nil {
		logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}
	err = json.Unmarshal([]byte(rawrra), &nrra.raw)
	if err != nil {
		logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}
	err = nrra.rra.validate()
	if err != nil {
		logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}
	rraList = append(rraList, nrra)

	err = dbUpdateRRAs(rraList)
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}

	ur := slib.RRAUpdateResponse{OK: true}
	buf, err := json.Marshal(&ur)
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}
	fmt.Fprintf(rw, string(buf))
}

// API entry point to retrieve specific RRA details
func serviceGetRRA(rw http.ResponseWriter, req *http.Request) {
	req.ParseForm()

	rraid := req.FormValue("id")

	op := opContext{}
	op.newContext(dbconn, false, req.RemoteAddr)

	r, err := getRRA(op, rraid)
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}

	buf, err := json.Marshal(&r)
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}
	fmt.Fprintf(rw, string(buf))
}

// API entry point to retrieve all RRAs
func serviceRRAs(rw http.ResponseWriter, req *http.Request) {
	op := opContext{}
	op.newContext(dbconn, false, req.RemoteAddr)

	rows, err := op.Query(`SELECT rraid, service, datadefault
		FROM rra x WHERE lastmodified = (
			SELECT MAX(lastmodified) FROM rra y WHERE
			x.service = y.service
		)`)
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}
	srr := slib.RRAsResponse{}
	srr.Results = make([]slib.RRAService, 0)
	for rows.Next() {
		var s slib.RRAService
		err = rows.Scan(&s.ID, &s.Name, &s.DefData)
		if err != nil {
			rows.Close()
			op.logf(err.Error())
			http.Error(rw, err.Error(), 500)
			return
		}
		srr.Results = append(srr.Results, s)
	}
	err = rows.Err()
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}

	buf, err := json.Marshal(&srr)
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}

	fmt.Fprint(rw, string(buf))
}
<commit_msg>when retrieving all risks, only include latest rra per service<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:
// - Aaron Meihm ameihm@mozilla.com

package main

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"net/http"
	slib "servicelib"
	"strconv"
)

func getRRA(op opContext, rraid string) (slib.RRAService, error) {
	var rr slib.RRAService

	err := op.QueryRow(`SELECT rraid, service,
		ari, api, afi, cri, cpi, cfi,
		iri, ipi, ifi,
		arp, app, afp, crp, cpp, cfp,
		irp, ipp, ifp, datadefault, raw
		FROM rra WHERE rraid = $1`, rraid).Scan(&rr.ID,
		&rr.Name, &rr.AvailRepImpact, &rr.AvailPrdImpact,
		&rr.AvailFinImpact, &rr.ConfiRepImpact, &rr.ConfiPrdImpact, &rr.ConfiFinImpact,
		&rr.IntegRepImpact, &rr.IntegPrdImpact, &rr.IntegFinImpact,
		&rr.AvailRepProb, &rr.AvailPrdProb, &rr.AvailFinProb,
		&rr.ConfiRepProb, &rr.ConfiPrdProb, &rr.ConfiFinProb,
		&rr.IntegRepProb, &rr.IntegPrdProb, &rr.IntegFinProb,
		&rr.DefData, &rr.RawRRA)
	if err != nil {
		if err == sql.ErrNoRows {
			return rr, nil
		} else {
			return rr, err
		}
	}
	err = rraResolveSupportGroups(op, &rr)
	if err != nil {
		return rr, err
	}

	return rr, nil
}

func rraResolveSupportGroups(op opContext, r *slib.RRAService) error {
	r.SupportGrps = make([]slib.SystemGroup, 0)
	rows, err := op.Query(`SELECT sysgroupid FROM
		rra_sysgroup WHERE rraid = $1`,
		r.ID)
	if err != nil {
		return err
	}
	for rows.Next() {
		var sgid string
		err = rows.Scan(&sgid)
		if err != nil {
			rows.Close()
			return err
		}
		sg, err := getSysGroup(op, sgid)
		if err != nil {
			rows.Close()
			return err
		}
		if sg.Name == "" {
			continue
		}
		r.SupportGrps = append(r.SupportGrps, sg)
	}
	err = rows.Err()
	if err != nil {
		return err
	}
	return nil
}

// Return a risk document that includes all RRAs
func serviceRisks(rw http.ResponseWriter, req *http.Request) {
	op := opContext{}
	op.newContext(dbconn, false, req.RemoteAddr)

	rows, err := op.Query(`SELECT rraid FROM rra x
		WHERE lastmodified = (
			SELECT MAX(lastmodified) FROM rra y
			WHERE x.service = y.service
		)`)
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}
	resp := slib.RisksResponse{}
	for rows.Next() {
		var rraid int
		err = rows.Scan(&rraid)
		if err != nil {
			rows.Close()
			op.logf(err.Error())
			http.Error(rw, err.Error(), 500)
			return
		}
		rs, err := riskForRRA(op, true, rraid)
		if err != nil {
			rows.Close()
			op.logf(err.Error())
			http.Error(rw, err.Error(), 500)
			return
		}
		resp.Risks = append(resp.Risks, rs)
	}
	err = rows.Err()
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}

	buf, err := json.Marshal(&resp)
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}
	fmt.Fprintf(rw, string(buf))
}

// Calculate the risk for the requested RRA
func serviceGetRRARisk(rw http.ResponseWriter, req *http.Request) {
	req.ParseForm()

	op := opContext{}
	op.newContext(dbconn, false, req.RemoteAddr)

	rraid := req.FormValue("id")
	if rraid == "" {
		err := fmt.Errorf("no rra id specified")
		op.logf(err.Error())
		http.Error(rw, err.Error(), 400)
		return
	}
	r, err := strconv.Atoi(rraid)
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}
	rs, err := riskForRRA(op, true, r)
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}

	buf, err := json.Marshal(&rs)
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}
	fmt.Fprintf(rw, string(buf))
}

// Read incoming RRA and update database as required. This can result in a
// new RRA being added, or an existing RRA being updated.
func serviceUpdateRRA(rw http.ResponseWriter, req *http.Request) {
	req.ParseMultipartForm(10000000)

	rawrra := req.FormValue("rra")
	if rawrra == "" {
		logf("no rra parameter in update request")
		http.Error(rw, "no rra parameter in update request", 500)
		return
	}

	op := opContext{}
	op.newContext(dbconn, false, req.RemoteAddr)

	// XXX Use the same import function we use in the RRA importer for now.
	// This can be cleaned up once the RRA importer is removed and the POST
	// functionality for RRAs is being used exclusively.
	var (
		nrra    rraESData
		rraList []rraESData
	)
	err := json.Unmarshal([]byte(rawrra), &nrra.rra)
	if err != nil {
		logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}
	err = json.Unmarshal([]byte(rawrra), &nrra.raw)
	if err != nil {
		logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}
	err = nrra.rra.validate()
	if err != nil {
		logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}
	rraList = append(rraList, nrra)

	err = dbUpdateRRAs(rraList)
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}

	ur := slib.RRAUpdateResponse{OK: true}
	buf, err := json.Marshal(&ur)
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}
	fmt.Fprintf(rw, string(buf))
}

// API entry point to retrieve specific RRA details
func serviceGetRRA(rw http.ResponseWriter, req *http.Request) {
	req.ParseForm()

	rraid := req.FormValue("id")

	op := opContext{}
	op.newContext(dbconn, false, req.RemoteAddr)

	r, err := getRRA(op, rraid)
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}

	buf, err := json.Marshal(&r)
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}
	fmt.Fprintf(rw, string(buf))
}

// API entry point to retrieve all RRAs
func serviceRRAs(rw http.ResponseWriter, req *http.Request) {
	op := opContext{}
	op.newContext(dbconn, false, req.RemoteAddr)

	rows, err := op.Query(`SELECT rraid, service, datadefault
		FROM rra x WHERE lastmodified = (
			SELECT MAX(lastmodified) FROM rra y WHERE
			x.service = y.service
		)`)
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}
	srr := slib.RRAsResponse{}
	srr.Results = make([]slib.RRAService, 0)
	for rows.Next() {
		var s slib.RRAService
		err = rows.Scan(&s.ID, &s.Name, &s.DefData)
		if err != nil {
			rows.Close()
			op.logf(err.Error())
			http.Error(rw, err.Error(), 500)
			return
		}
		srr.Results = append(srr.Results, s)
	}
	err = rows.Err()
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}

	buf, err := json.Marshal(&srr)
	if err != nil {
		op.logf(err.Error())
		http.Error(rw, err.Error(), 500)
		return
	}

	fmt.Fprint(rw, string(buf))
}
<|endoftext|>


<commit_before>package remote

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"testing"

	"github.com/hashicorp/terraform/state"
	"github.com/hashicorp/terraform/terraform"
)

// testClient is a generic function to test any client.
func testClient(t *testing.T, c Client) {
	var buf bytes.Buffer
	s := state.TestStateInitial()
	if err := terraform.WriteState(s, &buf); err != nil {
		t.Fatalf("err: %s", err)
	}
	data := buf.Bytes()

	if err := c.Put(data); err != nil {
		t.Fatalf("put: %s", err)
	}

	p, err := c.Get()
	if err != nil {
		t.Fatalf("get: %s", err)
	}
	if !bytes.Equal(p.Data, data) {
		t.Fatalf("bad: %#v", p)
	}

	if err := c.Delete(); err != nil {
		t.Fatalf("delete: %s", err)
	}

	p, err = c.Get()
	if err != nil {
		t.Fatalf("get: %s", err)
	}
	if p != nil {
		t.Fatalf("bad: %#v", p)
	}
}

func TestRemoteClient_noPayload(t *testing.T) {
	s := &State{
		Client: nilClient{},
	}
	if err := s.RefreshState(); err != nil {
		t.Fatal("error refreshing empty remote state")
	}
}

// nilClient returns nil for everything
type nilClient struct{}

func (nilClient) Get() (*Payload, error) { return nil, nil }

func (c nilClient) Put([]byte) error { return nil }

func (c nilClient) Delete() error { return nil }

// ensure that remote state can be properly initialized
func TestRemoteClient_stateInit(t *testing.T) {
	localStateFile, err := ioutil.TempFile("", "tf")
	if err != nil {
		t.Fatal(err)
	}

	// we need to remove the temp files so we recognize there's no local or
	// remote state.
	localStateFile.Close()
	os.Remove(localStateFile.Name())
	//defer os.Remove(localStateFile.Name())
	fmt.Println("LOCAL:", localStateFile.Name())

	local := &state.LocalState{
		Path: localStateFile.Name(),
	}
	if err := local.RefreshState(); err != nil {
		t.Fatal(err)
	}
	localState := local.State()

	fmt.Println("localState.Empty():", localState.Empty())

	remoteStateFile, err := ioutil.TempFile("", "tf")
	if err != nil {
		t.Fatal(err)
	}
	remoteStateFile.Close()
	os.Remove(remoteStateFile.Name())
	//defer os.Remove(remoteStateFile.Name()
	fmt.Println("LOCAL:", localStateFile.Name())
	fmt.Println("REMOTE:", remoteStateFile.Name())

	remoteClient := &FileClient{
		Path: remoteStateFile.Name(),
	}

	durable := &State{
		Client: remoteClient,
	}

	cache := &state.CacheState{
		Cache:   local,
		Durable: durable,
	}

	if err := cache.RefreshState(); err != nil {
		t.Fatal(err)
	}

	switch cache.RefreshResult() {

	// we should be "refreshing" the remote state to initialize it
	case state.CacheRefreshLocalNewer:
		// Write our local state out to the durable storage to start.
		if err := cache.WriteState(localState); err != nil {
			t.Fatal("Error preparing remote state:", err)
		}
		if err := cache.PersistState(); err != nil {
			t.Fatal("Error preparing remote state:", err)
		}
	default:

		t.Fatal("unexpected refresh result:", cache.RefreshResult())
	}

}
<commit_msg>Add remote state init test<commit_after>package remote

import (
	"bytes"
	"io/ioutil"
	"os"
	"testing"

	"github.com/hashicorp/terraform/state"
	"github.com/hashicorp/terraform/terraform"
)

// testClient is a generic function to test any client.
func testClient(t *testing.T, c Client) {
	var buf bytes.Buffer
	s := state.TestStateInitial()
	if err := terraform.WriteState(s, &buf); err != nil {
		t.Fatalf("err: %s", err)
	}
	data := buf.Bytes()

	if err := c.Put(data); err != nil {
		t.Fatalf("put: %s", err)
	}

	p, err := c.Get()
	if err != nil {
		t.Fatalf("get: %s", err)
	}
	if !bytes.Equal(p.Data, data) {
		t.Fatalf("bad: %#v", p)
	}

	if err := c.Delete(); err != nil {
		t.Fatalf("delete: %s", err)
	}

	p, err = c.Get()
	if err != nil {
		t.Fatalf("get: %s", err)
	}
	if p != nil {
		t.Fatalf("bad: %#v", p)
	}
}

func TestRemoteClient_noPayload(t *testing.T) {
	s := &State{
		Client: nilClient{},
	}
	if err := s.RefreshState(); err != nil {
		t.Fatal("error refreshing empty remote state")
	}
}

// nilClient returns nil for everything
type nilClient struct{}

func (nilClient) Get() (*Payload, error) { return nil, nil }

func (c nilClient) Put([]byte) error { return nil }

func (c nilClient) Delete() error { return nil }

// ensure that remote state can be properly initialized
func TestRemoteClient_stateInit(t *testing.T) {
	localStateFile, err := ioutil.TempFile("", "tf")
	if err != nil {
		t.Fatal(err)
	}

	// we need to remove the temp files so we recognize there's no local or
	// remote state.
	localStateFile.Close()
	os.Remove(localStateFile.Name())
	defer os.Remove(localStateFile.Name())

	remoteStateFile, err := ioutil.TempFile("", "tf")
	if err != nil {
		t.Fatal(err)
	}
	remoteStateFile.Close()
	os.Remove(remoteStateFile.Name())
	defer os.Remove(remoteStateFile.Name())

	// Now we need an empty state to initialize the state files.
	newState := terraform.NewState()
	newState.Remote = &terraform.RemoteState{
		Type:   "_local",
		Config: map[string]string{"path": remoteStateFile.Name()},
	}

	remoteClient := &FileClient{
		Path: remoteStateFile.Name(),
	}

	cache := &state.CacheState{
		Cache: &state.LocalState{
			Path: localStateFile.Name(),
		},
		Durable: &State{
			Client: remoteClient,
		},
	}

	// This will write the local state file, and set the state field in the CacheState
	err = cache.WriteState(newState)
	if err != nil {
		t.Fatal(err)
	}

	// This will persist the local state we just wrote to the remote state file
	err = cache.PersistState()
	if err != nil {
		t.Fatal(err)
	}

	// now compare the two state files just to be sure
	localData, err := ioutil.ReadFile(localStateFile.Name())
	if err != nil {
		t.Fatal(err)
	}

	remoteData, err := ioutil.ReadFile(remoteStateFile.Name())
	if err != nil {
		t.Fatal(err)
	}

	if !bytes.Equal(localData, remoteData) {
		t.Log("state files don't match")
		t.Log("Local:\n", string(localData))
		t.Log("Remote:\n", string(remoteData))
		t.Fatal("failed to initialize remote state")
	}
}
<|endoftext|>


<commit_before>package helpers

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/vito/cmdtest/matchers"

	"github.com/pivotal-cf-experimental/cf-test-helpers/cf"
)

var AdminUserContext cf.UserContext
var RegularUserContext cf.UserContext

type SuiteContext interface {
	Setup()
	Teardown()

	AdminUserContext() cf.UserContext
	RegularUserContext() cf.UserContext
}

func SetupEnvironment(context SuiteContext) {
	var originalCfHomeDir, currentCfHomeDir string

	BeforeEach(func() {
		AdminUserContext = context.AdminUserContext()
		RegularUserContext = context.RegularUserContext()

		context.Setup()

		cf.AsUser(AdminUserContext, func() {
			SetUpSpaceWithUserAccess(RegularUserContext, RegularUserContext.Space)
		})

		originalCfHomeDir, currentCfHomeDir = cf.InitiateUserContext(RegularUserContext)
		cf.TargetSpace(RegularUserContext)
	})

	AfterEach(func() {
		cf.RestoreUserContext(RegularUserContext, originalCfHomeDir, currentCfHomeDir)

		context.Teardown()
	})
}

func SetUpSpaceWithUserAccess(uc cf.UserContext, sname string) {
	Expect(cf.Cf("create-space", "-o", uc.Org, sname)).To(ExitWith(0))
	Expect(cf.Cf("set-space-role", uc.Username, uc.Org, sname, "SpaceManager")).To(ExitWith(0))
	Expect(cf.Cf("set-space-role", uc.Username, uc.Org, sname, "SpaceDeveloper")).To(ExitWith(0))
	Expect(cf.Cf("set-space-role", uc.Username, uc.Org, sname, "SpaceAuditor")).To(ExitWith(0))
}
<commit_msg>Remove explicit space argument from space setup helper function<commit_after>package helpers

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/vito/cmdtest/matchers"

	"github.com/pivotal-cf-experimental/cf-test-helpers/cf"
)

var AdminUserContext cf.UserContext
var RegularUserContext cf.UserContext

type SuiteContext interface {
	Setup()
	Teardown()

	AdminUserContext() cf.UserContext
	RegularUserContext() cf.UserContext
}

func SetupEnvironment(context SuiteContext) {
	var originalCfHomeDir, currentCfHomeDir string

	BeforeEach(func() {
		AdminUserContext = context.AdminUserContext()
		RegularUserContext = context.RegularUserContext()

		context.Setup()

		cf.AsUser(AdminUserContext, func() {
			setUpSpaceWithUserAccess(RegularUserContext)
		})

		originalCfHomeDir, currentCfHomeDir = cf.InitiateUserContext(RegularUserContext)
		cf.TargetSpace(RegularUserContext)
	})

	AfterEach(func() {
		cf.RestoreUserContext(RegularUserContext, originalCfHomeDir, currentCfHomeDir)

		context.Teardown()
	})
}

func setUpSpaceWithUserAccess(uc cf.UserContext) {
	Expect(cf.Cf("create-space", "-o", uc.Org, uc.Space)).To(ExitWith(0))
	Expect(cf.Cf("set-space-role", uc.Username, uc.Org, uc.Space, "SpaceManager")).To(ExitWith(0))
	Expect(cf.Cf("set-space-role", uc.Username, uc.Org, uc.Space, "SpaceDeveloper")).To(ExitWith(0))
	Expect(cf.Cf("set-space-role", uc.Username, uc.Org, uc.Space, "SpaceAuditor")).To(ExitWith(0))
}
<|endoftext|>


<commit_before>// Copyright 2019 Google LLC
//
// 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 commands

import (
	"github.com/GoogleContainerTools/kpt/internal/docs/generated/cfgdocs"
	"github.com/spf13/cobra"
	"sigs.k8s.io/kustomize/cmd/config/configcobra"
)

func GetConfigCommand(name string) *cobra.Command {
	cfgCmd := &cobra.Command{
		Use:     "cfg",
		Short:   cfgdocs.READMEShort,
		Long:    cfgdocs.READMEShort + "\n" + cfgdocs.READMELong,
		Example: cfgdocs.READMEExamples,
		Aliases: []string{"config"},
		RunE: func(cmd *cobra.Command, args []string) error {
			h, err := cmd.Flags().GetBool("help")
			if err != nil {
				return err
			}
			if h {
				return cmd.Help()
			}
			return cmd.Usage()
		},
	}

	an := configcobra.Annotate(name)
	an.Short = cfgdocs.AnnotateShort
	an.Long = cfgdocs.AnnotateShort + "\n" + cfgdocs.AnnotateLong
	an.Example = cfgdocs.AnnotateExamples

	cat := configcobra.Cat(name)
	cat.Short = cfgdocs.CatShort
	cat.Long = cfgdocs.CatShort + "\n" + cfgdocs.CatLong
	cat.Example = cfgdocs.CatExamples

	count := configcobra.Count(name)
	count.Short = cfgdocs.CountShort
	count.Long = cfgdocs.CountShort + "\n" + cfgdocs.CountLong
	count.Example = cfgdocs.CountExamples

	createSetter := configcobra.CreateSetter(name)
	createSetter.Short = cfgdocs.CreateSetterShort
	createSetter.Long = cfgdocs.CreateSetterShort + "\n" + cfgdocs.CreateSetterLong
	createSetter.Example = cfgdocs.CreateSetterExamples

	fmt := configcobra.Fmt(name)
	fmt.Short = cfgdocs.FmtShort
	fmt.Long = cfgdocs.FmtShort + "\n" + cfgdocs.FmtLong
	fmt.Example = cfgdocs.FmtExamples

	grep := configcobra.Grep(name)
	grep.Short = cfgdocs.GrepShort
	grep.Long = cfgdocs.GrepShort + "\n" + cfgdocs.GrepLong
	grep.Example = cfgdocs.GrepExamples

	listSetters := configcobra.ListSetters(name)
	listSetters.Short = cfgdocs.ListSettersShort
	listSetters.Long = cfgdocs.ListSettersShort + "\n" + cfgdocs.ListSettersLong
	listSetters.Example = cfgdocs.ListSettersExamples

	set := configcobra.Set(name)
	set.Short = cfgdocs.SetShort
	set.Long = cfgdocs.SetShort + "\n" + cfgdocs.SetLong
	set.Example = cfgdocs.SetExamples

	tree := configcobra.Tree(name)
	tree.Short = cfgdocs.TreeShort
	tree.Long = cfgdocs.TreeShort + "\n" + cfgdocs.TreeLong
	tree.Example = cfgdocs.TreeExamples

	cfgCmd.AddCommand(an, cat, count, createSetter, fmt,
		grep, listSetters, set, tree)
	return cfgCmd
}
<commit_msg>wrap cfg set to add implicit project number set<commit_after>// Copyright 2019 Google LLC
//
// 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 commands

import (
	"github.com/GoogleContainerTools/kpt/internal/docs/generated/cfgdocs"
	"github.com/GoogleContainerTools/kpt/internal/util/setters"
	"github.com/spf13/cobra"
	"sigs.k8s.io/kustomize/cmd/config/configcobra"
)

func GetConfigCommand(name string) *cobra.Command {
	cfgCmd := &cobra.Command{
		Use:     "cfg",
		Short:   cfgdocs.READMEShort,
		Long:    cfgdocs.READMEShort + "\n" + cfgdocs.READMELong,
		Example: cfgdocs.READMEExamples,
		Aliases: []string{"config"},
		RunE: func(cmd *cobra.Command, args []string) error {
			h, err := cmd.Flags().GetBool("help")
			if err != nil {
				return err
			}
			if h {
				return cmd.Help()
			}
			return cmd.Usage()
		},
	}

	an := configcobra.Annotate(name)
	an.Short = cfgdocs.AnnotateShort
	an.Long = cfgdocs.AnnotateShort + "\n" + cfgdocs.AnnotateLong
	an.Example = cfgdocs.AnnotateExamples

	cat := configcobra.Cat(name)
	cat.Short = cfgdocs.CatShort
	cat.Long = cfgdocs.CatShort + "\n" + cfgdocs.CatLong
	cat.Example = cfgdocs.CatExamples

	count := configcobra.Count(name)
	count.Short = cfgdocs.CountShort
	count.Long = cfgdocs.CountShort + "\n" + cfgdocs.CountLong
	count.Example = cfgdocs.CountExamples

	createSetter := configcobra.CreateSetter(name)
	createSetter.Short = cfgdocs.CreateSetterShort
	createSetter.Long = cfgdocs.CreateSetterShort + "\n" + cfgdocs.CreateSetterLong
	createSetter.Example = cfgdocs.CreateSetterExamples

	fmt := configcobra.Fmt(name)
	fmt.Short = cfgdocs.FmtShort
	fmt.Long = cfgdocs.FmtShort + "\n" + cfgdocs.FmtLong
	fmt.Example = cfgdocs.FmtExamples

	grep := configcobra.Grep(name)
	grep.Short = cfgdocs.GrepShort
	grep.Long = cfgdocs.GrepShort + "\n" + cfgdocs.GrepLong
	grep.Example = cfgdocs.GrepExamples

	listSetters := configcobra.ListSetters(name)
	listSetters.Short = cfgdocs.ListSettersShort
	listSetters.Long = cfgdocs.ListSettersShort + "\n" + cfgdocs.ListSettersLong
	listSetters.Example = cfgdocs.ListSettersExamples

	set := SetCommand(name)
	set.Short = cfgdocs.SetShort
	set.Long = cfgdocs.SetShort + "\n" + cfgdocs.SetLong
	set.Example = cfgdocs.SetExamples

	tree := configcobra.Tree(name)
	tree.Short = cfgdocs.TreeShort
	tree.Long = cfgdocs.TreeShort + "\n" + cfgdocs.TreeLong
	tree.Example = cfgdocs.TreeExamples

	cfgCmd.AddCommand(an, cat, count, createSetter, fmt,
		grep, listSetters, set, tree)
	return cfgCmd
}

// SetCommand wraps the kustomize set command in order to automatically update
// a project number if a project id is set.
func SetCommand(parent string) *cobra.Command {
	kustomizeCmd := configcobra.Set(parent)
	setCmd := *kustomizeCmd
	setCmd.RunE = func(c *cobra.Command, args []string) error {
		kustomizeCmd.SetArgs(args)
		if err := kustomizeCmd.Execute(); err != nil {
			return nil
		}
		if len(args) != 3 || args[1] != "gcloud.core.project" {
			return nil
		}
		projectNumber, err := setters.GetProjectNumberFromProjectID(args[2])
		if err != nil {
			return nil
		}
		kustomizeCmd.SetArgs([]string{args[0], "gcloud.project.projectNumber", projectNumber})
		return kustomizeCmd.Execute()
	}
	return &setCmd
}
<|endoftext|>