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

package generator

import (
	"bufio"
	"bytes"
	"crypto/rand"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"math/big"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"text/template"
	"time"
)

const (
	// DefinitionFile is the file containing the generator definition within
	// a generator.
	DefinitionFile = "generator.json"

	// PartialsDir is the directory containing partials within a generator.
	PartialsDir = "partials"

	// FilesDir is the directory containing files within a generator.
	FilesDir = "files"

	// DirPerm is tDe files permissions for the generated directory.
	DirPerm = 0700
)

// Definition contains properties for a template generator definition.
type Definition struct {
	// Name is the name of the generator.
	// It should be short, lowercase, and contain only letters, numbers, and
	// dashes.
	Name string `json:"name"`

	// Version is the version string of the generator.
	Version string `json:"version"`

	// Description is a short description of the generator.
	Description string `json:"description"`

	// Author is the name of the author of the generator.
	Author string `json:"author"`

	// License is the license of the generator (not of the generated code).
	// If the generated project has a license, it should be defined within
	// the templates.
	License string `json:"license"`

	// Variables is a map of variables for the templates and partials.
	Variables map[string]interface{} `json:"variables"`

	// Inputs is a map of user inputs.
	Inputs InputMap `json:"inputs"`

	// Priorities is an array of files which should be parsed first.
	// The paths are relative to the `files` directory.
	Priorities []string `json:"priorities"`
}

// NewDefinitionFromFile loads a generator definition from a file.
// The file is treated as a template and is fed the given variables and
// functions.
// Extra variables and functions given will be added to the template context.
func NewDefinitionFromFile(path string, vars map[string]interface{}, funcs template.FuncMap) (*Definition, error) {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}
	tmpl := template.New("generator")
	tmpl.Funcs(extendFuncs(StdDefinitionFuncs(), funcs))
	if _, err := tmpl.Parse(string(b)); err != nil {
		return nil, err
	}
	var buf bytes.Buffer
	if err := tmpl.Execute(&buf, vars); err != nil {
		return nil, err
	}
	var gen Definition
	if err := json.Unmarshal(buf.Bytes(), &gen); err != nil {
		return nil, err
	}
	return &gen, nil
}

// StdDefinitionFuncs returns the standard function map used when parsing a
// generator definition.
// It adds the following functions:
//
// 	- now(format string) string: returns a formatted representation of the
//	  current date
// 	- nowUTC(format string) string: returns a formatted representation of
//	  the current UTC date
// 	- secret(length int) (string, error): returns a random secret string
func StdDefinitionFuncs() template.FuncMap {
	return template.FuncMap{
		"now":    now,
		"nowUTC": nowUTC,
		"secret": secret,
	}
}

// Options contains options for a generator.
type Options struct {
	// Variables for the definition file.
	DefVars map[string]interface{}

	// Functions for the definition file.
	DefFuncs template.FuncMap

	// Variables for the templates.
	TmplVars map[string]interface{}

	// Functions for the templates.
	TmplFuncs template.FuncMap

	// A reader for user input, default to stdin.
	Reader io.Reader
}

// Generator deals with parsing templates, handling user input, and outputting
// processed templates.
type Generator struct {
	opts     *Options
	src      string
	def      *Definition
	partials *template.Template
	files    *template.Template
	values   map[string]interface{}
	reader   *bufio.Reader
}

// NewFromDir create a new generator from a directory.
func NewFromDir(src string, opts *Options) (*Generator, error) {
	defFile := filepath.Join(src, DefinitionFile)
	def, err := NewDefinitionFromFile(defFile, opts.DefVars, opts.DefFuncs)
	if err != nil {
		return nil, err
	}
	var reader io.Reader
	if opts.Reader != nil {
		reader = opts.Reader
	} else {
		reader = os.Stdin
	}
	return &Generator{
		opts:   opts,
		src:    src,
		def:    def,
		values: map[string]interface{}{},
		reader: bufio.NewReader(reader),
	}, nil
}

// StdTmplFuncs returns the standard function map used when parsing a template
// It adds the following functions:
//
// 	- ask(json string) (interface{}, error): creates an input on-the-fly and
//	  returns its value
// 	- input(id string) (interface{}, error): returns the value of an input
// 	- now(format string) string: returns a formatted representation of the
//	  current date
// 	- nowUTC(format string) string: returns a formatted representation of
//	  the current UTC date
// 	- partial(path, vars ...interface{}) (string, error): executes the
//	  partial with given name
//	  and variables (path relative to `partials` directory)
// 	- secret(length int) (string, error): returns a random secret string
func (gen *Generator) StdTmplFuncs() template.FuncMap {
	return template.FuncMap{
		"ask":     gen.ask,
		"input":   gen.input,
		"now":     now,
		"nowUTC":  nowUTC,
		"partial": gen.partial,
		"secret":  secret,
	}
}

// Exec parses templates, handles user input, and outputs processed templates to
// given dir.
func (gen *Generator) Exec(dst string) error {
	if err := gen.parsePartials(); err != nil {
		return err
	}
	if err := gen.parseFiles(); err != nil {
		return err
	}
	if err := gen.generate(dst); err != nil {
		return err
	}
	return nil
}

// parse parsers templates in given directory into the given template object.
func (gen *Generator) parse(tmpl *template.Template, dir string) error {
	if _, err := os.Stat(dir); err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		return err
	}
	tmpl.Funcs(extendFuncs(gen.StdTmplFuncs(), gen.opts.TmplFuncs))
	return walkTmpl(dir, dir, tmpl)
}

func (gen *Generator) parsePartials() error {
	gen.partials = template.New("partials")
	return gen.parse(gen.partials, filepath.Join(gen.src, PartialsDir))
}

func (gen *Generator) parseFiles() error {
	gen.files = template.New("files")
	return gen.parse(gen.files, filepath.Join(gen.src, FilesDir))
}

func (gen *Generator) partial(name string, opts ...interface{}) (string, error) {
	l := len(opts)
	if l > 1 {
		return "", errors.New("too many arguments")
	}
	var vars interface{}
	if l == 1 {
		vars = opts[0]
	}
	var buf bytes.Buffer
	if err := gen.partials.ExecuteTemplate(&buf, name, vars); err != nil {
		return "", err
	}
	return buf.String(), nil
}

type tmplDesc struct {
	tmpl     *template.Template
	priority int
}

type tmplDescSlice []tmplDesc

func (s tmplDescSlice) Len() int {
	return len(s)
}

func (s tmplDescSlice) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func (s tmplDescSlice) Less(i, j int) bool {
	s1, s2 := s[i], s[j]
	p1, p2 := s1.priority, s2.priority
	if p1 == p2 {
		return s1.tmpl.Name() < s2.tmpl.Name()
	}
	if p1 == -1 {
		return false
	}
	if p2 == -1 {
		return true
	}
	return p1 < p2
}

func (gen *Generator) generate(dst string) error {
	var descs tmplDescSlice
	for _, tmpl := range gen.files.Templates() {
		name := tmpl.Name()
		priority := -1
		for i, v := range gen.def.Priorities {
			if v == name {
				priority = i
				break
			}
		}
		descs = append(descs, tmplDesc{
			tmpl:     tmpl,
			priority: priority,
		})
	}
	sort.Sort(descs)

	for _, desc := range descs {
		tmpl := desc.tmpl
		name := tmpl.Name()
		in := filepath.Join(gen.src, FilesDir, name)
		info, err := os.Stat(in)
		if err != nil {
			return err
		}
		out := filepath.Join(dst, name)
		if err = os.MkdirAll(filepath.Dir(out), DirPerm); err != nil {
			return err
		}
		f, err := os.OpenFile(out, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, info.Mode())
		if err != nil {
			return err
		}
		vars := map[string]interface{}{}
		for k, v := range gen.opts.TmplVars {
			vars[k] = v
		}
		for k, v := range gen.def.Variables {
			vars[k] = v
		}
		if err := tmpl.Execute(f, vars); err != nil {
			return err
		}
	}
	return nil
}

func (gen *Generator) input(id string) (interface{}, error) {
	val, ok := gen.values[id]
	if ok {
		return val, nil
	}
	for k, in := range gen.def.Inputs {
		if k == id {
			val, err := gen.read(in)
			if err != nil {
				return nil, err
			}
			gen.values[id] = val
			return val, nil
		}
	}
	return nil, fmt.Errorf("undefined input %q", id)
}

func (gen *Generator) ask(input string) (interface{}, error) {
	in, err := UnmarshalJSONInput([]byte(input))
	if err != nil {
		return nil, err
	}
	return gen.read(in)
}

func (gen *Generator) read(in Input) (interface{}, error) {
	fmt.Print(in.Msg())
	for {
		fmt.Print("? ")
		str, err := gen.reader.ReadString('\n')
		if err != nil {
			return nil, err
		}
		str = strings.TrimSpace(str)
		if err := in.Set(str); err != nil {
			fmt.Println(err)
			continue
		}
		return in.Get(), nil
	}
}

func walkTmpl(base, dir string, tmpl *template.Template) error {
	files, err := filepath.Glob(filepath.Join(dir, "*"))
	if err != nil {
		return err
	}
	for _, file := range files {
		info, err := os.Stat(file)
		if err != nil {
			return err
		}
		if info.IsDir() {
			if err = walkTmpl(base, file, tmpl); err != nil {
				return err
			}
			continue
		}
		name, err := filepath.Rel(base, file)
		if err != nil {
			return err
		}
		b, err := ioutil.ReadFile(file)
		if err != nil {
			return err
		}
		t := tmpl.New(name)
		if _, err := t.Parse(string(b)); err != nil {
			return err
		}
	}
	return nil
}

func now(format string) string {
	return time.Now().Format(format)
}

func nowUTC(format string) string {
	return time.Now().UTC().Format(format)
}

func extendFuncs(maps ...template.FuncMap) template.FuncMap {
	funcs := template.FuncMap{}
	for _, m := range maps {
		if m != nil {
			for k, v := range m {
				funcs[k] = v
			}
		}
	}
	return funcs
}

var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%&()[]*+-,./:;<=>?^_{}~")

func secret(n int) (string, error) {
	if n < 0 {
		return "", errors.New("size must not be negative")
	}
	r := make([]rune, n)
	max := big.NewInt(int64(len(letters)))
	for i := range r {
		j, err := rand.Int(rand.Reader, max)
		if err != nil {
			return "", err
		}
		r[i] = letters[int(j.Int64())]
	}
	return string(r), nil
}
<commit_msg>generator: typo<commit_after>// Copyright 2016 Stratumn SAS. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package generator

import (
	"bufio"
	"bytes"
	"crypto/rand"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"math/big"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"text/template"
	"time"
)

const (
	// DefinitionFile is the file containing the generator definition within
	// a generator.
	DefinitionFile = "generator.json"

	// PartialsDir is the directory containing partials within a generator.
	PartialsDir = "partials"

	// FilesDir is the directory containing files within a generator.
	FilesDir = "files"

	// DirPerm is the files permissions for the generated directory.
	DirPerm = 0700
)

// Definition contains properties for a template generator definition.
type Definition struct {
	// Name is the name of the generator.
	// It should be short, lowercase, and contain only letters, numbers, and
	// dashes.
	Name string `json:"name"`

	// Version is the version string of the generator.
	Version string `json:"version"`

	// Description is a short description of the generator.
	Description string `json:"description"`

	// Author is the name of the author of the generator.
	Author string `json:"author"`

	// License is the license of the generator (not of the generated code).
	// If the generated project has a license, it should be defined within
	// the templates.
	License string `json:"license"`

	// Variables is a map of variables for the templates and partials.
	Variables map[string]interface{} `json:"variables"`

	// Inputs is a map of user inputs.
	Inputs InputMap `json:"inputs"`

	// Priorities is an array of files which should be parsed first.
	// The paths are relative to the `files` directory.
	Priorities []string `json:"priorities"`
}

// NewDefinitionFromFile loads a generator definition from a file.
// The file is treated as a template and is fed the given variables and
// functions.
// Extra variables and functions given will be added to the template context.
func NewDefinitionFromFile(path string, vars map[string]interface{}, funcs template.FuncMap) (*Definition, error) {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}
	tmpl := template.New("generator")
	tmpl.Funcs(extendFuncs(StdDefinitionFuncs(), funcs))
	if _, err := tmpl.Parse(string(b)); err != nil {
		return nil, err
	}
	var buf bytes.Buffer
	if err := tmpl.Execute(&buf, vars); err != nil {
		return nil, err
	}
	var gen Definition
	if err := json.Unmarshal(buf.Bytes(), &gen); err != nil {
		return nil, err
	}
	return &gen, nil
}

// StdDefinitionFuncs returns the standard function map used when parsing a
// generator definition.
// It adds the following functions:
//
// 	- now(format string) string: returns a formatted representation of the
//	  current date
// 	- nowUTC(format string) string: returns a formatted representation of
//	  the current UTC date
// 	- secret(length int) (string, error): returns a random secret string
func StdDefinitionFuncs() template.FuncMap {
	return template.FuncMap{
		"now":    now,
		"nowUTC": nowUTC,
		"secret": secret,
	}
}

// Options contains options for a generator.
type Options struct {
	// Variables for the definition file.
	DefVars map[string]interface{}

	// Functions for the definition file.
	DefFuncs template.FuncMap

	// Variables for the templates.
	TmplVars map[string]interface{}

	// Functions for the templates.
	TmplFuncs template.FuncMap

	// A reader for user input, default to stdin.
	Reader io.Reader
}

// Generator deals with parsing templates, handling user input, and outputting
// processed templates.
type Generator struct {
	opts     *Options
	src      string
	def      *Definition
	partials *template.Template
	files    *template.Template
	values   map[string]interface{}
	reader   *bufio.Reader
}

// NewFromDir create a new generator from a directory.
func NewFromDir(src string, opts *Options) (*Generator, error) {
	defFile := filepath.Join(src, DefinitionFile)
	def, err := NewDefinitionFromFile(defFile, opts.DefVars, opts.DefFuncs)
	if err != nil {
		return nil, err
	}
	var reader io.Reader
	if opts.Reader != nil {
		reader = opts.Reader
	} else {
		reader = os.Stdin
	}
	return &Generator{
		opts:   opts,
		src:    src,
		def:    def,
		values: map[string]interface{}{},
		reader: bufio.NewReader(reader),
	}, nil
}

// StdTmplFuncs returns the standard function map used when parsing a template.
// It adds the following functions:
//
// 	- ask(json string) (interface{}, error): creates an input on-the-fly and
//	  returns its value
// 	- input(id string) (interface{}, error): returns the value of an input
// 	- now(format string) string: returns a formatted representation of the
//	  current date
// 	- nowUTC(format string) string: returns a formatted representation of
//	  the current UTC date
// 	- partial(path, vars ...interface{}) (string, error): executes the
//	  partial with given name
//	  and variables (path relative to `partials` directory)
// 	- secret(length int) (string, error): returns a random secret string
func (gen *Generator) StdTmplFuncs() template.FuncMap {
	return template.FuncMap{
		"ask":     gen.ask,
		"input":   gen.input,
		"now":     now,
		"nowUTC":  nowUTC,
		"partial": gen.partial,
		"secret":  secret,
	}
}

// Exec parses templates, handles user input, and outputs processed templates to
// given dir.
func (gen *Generator) Exec(dst string) error {
	if err := gen.parsePartials(); err != nil {
		return err
	}
	if err := gen.parseFiles(); err != nil {
		return err
	}
	if err := gen.generate(dst); err != nil {
		return err
	}
	return nil
}

// parse parsers templates in given directory into the given template object.
func (gen *Generator) parse(tmpl *template.Template, dir string) error {
	if _, err := os.Stat(dir); err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		return err
	}
	tmpl.Funcs(extendFuncs(gen.StdTmplFuncs(), gen.opts.TmplFuncs))
	return walkTmpl(dir, dir, tmpl)
}

func (gen *Generator) parsePartials() error {
	gen.partials = template.New("partials")
	return gen.parse(gen.partials, filepath.Join(gen.src, PartialsDir))
}

func (gen *Generator) parseFiles() error {
	gen.files = template.New("files")
	return gen.parse(gen.files, filepath.Join(gen.src, FilesDir))
}

func (gen *Generator) partial(name string, opts ...interface{}) (string, error) {
	l := len(opts)
	if l > 1 {
		return "", errors.New("too many arguments")
	}
	var vars interface{}
	if l == 1 {
		vars = opts[0]
	}
	var buf bytes.Buffer
	if err := gen.partials.ExecuteTemplate(&buf, name, vars); err != nil {
		return "", err
	}
	return buf.String(), nil
}

type tmplDesc struct {
	tmpl     *template.Template
	priority int
}

type tmplDescSlice []tmplDesc

func (s tmplDescSlice) Len() int {
	return len(s)
}

func (s tmplDescSlice) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func (s tmplDescSlice) Less(i, j int) bool {
	s1, s2 := s[i], s[j]
	p1, p2 := s1.priority, s2.priority
	if p1 == p2 {
		return s1.tmpl.Name() < s2.tmpl.Name()
	}
	if p1 == -1 {
		return false
	}
	if p2 == -1 {
		return true
	}
	return p1 < p2
}

func (gen *Generator) generate(dst string) error {
	var descs tmplDescSlice
	for _, tmpl := range gen.files.Templates() {
		name := tmpl.Name()
		priority := -1
		for i, v := range gen.def.Priorities {
			if v == name {
				priority = i
				break
			}
		}
		descs = append(descs, tmplDesc{
			tmpl:     tmpl,
			priority: priority,
		})
	}
	sort.Sort(descs)

	for _, desc := range descs {
		tmpl := desc.tmpl
		name := tmpl.Name()
		in := filepath.Join(gen.src, FilesDir, name)
		info, err := os.Stat(in)
		if err != nil {
			return err
		}
		out := filepath.Join(dst, name)
		if err = os.MkdirAll(filepath.Dir(out), DirPerm); err != nil {
			return err
		}
		f, err := os.OpenFile(out, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, info.Mode())
		if err != nil {
			return err
		}
		vars := map[string]interface{}{}
		for k, v := range gen.opts.TmplVars {
			vars[k] = v
		}
		for k, v := range gen.def.Variables {
			vars[k] = v
		}
		if err := tmpl.Execute(f, vars); err != nil {
			return err
		}
	}
	return nil
}

func (gen *Generator) input(id string) (interface{}, error) {
	val, ok := gen.values[id]
	if ok {
		return val, nil
	}
	for k, in := range gen.def.Inputs {
		if k == id {
			val, err := gen.read(in)
			if err != nil {
				return nil, err
			}
			gen.values[id] = val
			return val, nil
		}
	}
	return nil, fmt.Errorf("undefined input %q", id)
}

func (gen *Generator) ask(input string) (interface{}, error) {
	in, err := UnmarshalJSONInput([]byte(input))
	if err != nil {
		return nil, err
	}
	return gen.read(in)
}

func (gen *Generator) read(in Input) (interface{}, error) {
	fmt.Print(in.Msg())
	for {
		fmt.Print("? ")
		str, err := gen.reader.ReadString('\n')
		if err != nil {
			return nil, err
		}
		str = strings.TrimSpace(str)
		if err := in.Set(str); err != nil {
			fmt.Println(err)
			continue
		}
		return in.Get(), nil
	}
}

func walkTmpl(base, dir string, tmpl *template.Template) error {
	files, err := filepath.Glob(filepath.Join(dir, "*"))
	if err != nil {
		return err
	}
	for _, file := range files {
		info, err := os.Stat(file)
		if err != nil {
			return err
		}
		if info.IsDir() {
			if err = walkTmpl(base, file, tmpl); err != nil {
				return err
			}
			continue
		}
		name, err := filepath.Rel(base, file)
		if err != nil {
			return err
		}
		b, err := ioutil.ReadFile(file)
		if err != nil {
			return err
		}
		t := tmpl.New(name)
		if _, err := t.Parse(string(b)); err != nil {
			return err
		}
	}
	return nil
}

func now(format string) string {
	return time.Now().Format(format)
}

func nowUTC(format string) string {
	return time.Now().UTC().Format(format)
}

func extendFuncs(maps ...template.FuncMap) template.FuncMap {
	funcs := template.FuncMap{}
	for _, m := range maps {
		if m != nil {
			for k, v := range m {
				funcs[k] = v
			}
		}
	}
	return funcs
}

var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%&()[]*+-,./:;<=>?^_{}~")

func secret(n int) (string, error) {
	if n < 0 {
		return "", errors.New("size must not be negative")
	}
	r := make([]rune, n)
	max := big.NewInt(int64(len(letters)))
	for i := range r {
		j, err := rand.Int(rand.Reader, max)
		if err != nil {
			return "", err
		}
		r[i] = letters[int(j.Int64())]
	}
	return string(r), nil
}
<|endoftext|>


<commit_before>package generator

import (
	"go/ast"
	"go/token"
	"../parser"
)

type Any interface{}
type Symbol string

// func generateAST(tree []parser.Node) *ast.File {
// 	return &ast.File{Name: makeIdent("main"), Decls: generateDeclarations(tree)}
// }

// func generateDeclarations(tree []parser.Node) []ast.Decl {
// 	decls := make([]ast.Decl, len(tree))

// 	for i, node := range tree {
// 		switch node.Type() {
// 		case parser.NodeCall:
// 			decls[i] = generateDeclaration(node)
// 		default:
// 			panic("unexpected behaviour!")
// 		}
// 	}

// 	return decls
// }

// func generateDeclaration(node parser.CallNode) ast.Decl {
// 	if node.Callee.(parser.IdentNode).Ident == "def" {
// 		return evalDef(node)
// 	}

// 	return nil
// }

// func evalDef(node parser.CallNode) ast.Decl {
// 	ident := node.Callee.(parser.IdentNode).Ident
// 	val := evalExpr(node.Args[0])

// 	return &ast.GenDecl{
// 		Tok: token.VAR,
// 		Specs: []ast.Spec{
// 			&ast.ValueSpec{
// 				Names:  []*ast.Ident{makeIdent(ident.Value)},
// 				Values: []ast.Expr{val},
// 			},
// 		},
// 	}
// }

func EvalExprs(nodes []parser.Node) []ast.Expr {
	out := make([]ast.Expr, len(nodes))

	for i, node := range nodes {
		out[i] = EvalExpr(node)
	}

	return out
}

func EvalExpr(node parser.Node) ast.Expr {
	switch t := node.Type(); t {
	case parser.NodeCall:
		node := node.(*parser.CallNode)
		return evalFuncCall(node)
	case parser.NodeNumber:
		node := node.(*parser.NumberNode)
		return makeBasicLit(node.NumberType, node.Value)
	case parser.NodeString:
		node := node.(*parser.StringNode)
		return makeBasicLit(token.STRING, node.Value)
	case parser.NodeIdent:
		node := node.(*parser.IdentNode)
		return makeIdent(node.Ident)
	case parser.NodeNil:
		return makeNil()
	default:
		println(t)
		panic("not implemented yet!")
	}
}

func evalFuncCall(node *parser.CallNode) ast.Expr {
	callee := EvalExpr(node.Callee)
	args := EvalExprs(node.Args)

	return makeFunCall(callee, args)
}

// func makeLitFunCall(body []Any) ast.Expr {
// 	return &ast.CallExpr{
// 		Fun:  makeFuncLit([]Any{}, body),
// 		Args: []ast.Expr{},
// 	}
// }

// func wrapExprsWithStmt(exps []ast.Expr) []ast.Stmt {
// 	out := make([]ast.Stmt, len(exps))
// 	for i, v := range exps {
// 		out[i] = &ast.ExprStmt{X: v}
// 	}
// 	return out
// }

func makeFunCall(callee ast.Expr, args []ast.Expr) ast.Expr {
	return &ast.CallExpr{
		Fun:  callee,
		Args: args,
	}
}

// func makeFuncLit(args, body []Any) *ast.FuncLit {
// 	node := &ast.FuncLit{
// 		Type: &ast.FuncType{

// 			Results: &ast.FieldList{
// 				List: []*ast.Field{
// 					&ast.Field{
// 						Type: makeIdent("Any"),
// 					},
// 				},
// 			},
// 		},
// 		Body: &ast.BlockStmt{
// 			List: returnLast(wrapExprsWithStmt(evalExprs(body))),
// 		},
// 	}

// 	if len(args) > 0 {
// 		node.Type.Params = makeParameterList(args)
// 	}

// 	return node
// }

// func makeParameterList(args []Any) *ast.FieldList {
// 	return &ast.FieldList{
// 		List: []*ast.Field{
// 			&ast.Field{
// 				Type:  makeIdent("Any"),
// 				Names: makeIdentSlice(args),
// 			},
// 		},
// 	}
// }

// func returnLast(stmts []ast.Stmt) []ast.Stmt {
// 	if len(stmts) < 1 {
// 		return stmts
// 	}

// 	stmts[len(stmts)-1] = &ast.ReturnStmt{
// 		Results: []ast.Expr{
// 			stmts[len(stmts)-1].(*ast.ExprStmt).X,
// 		},
// 	}
// 	return stmts
// }

// func makeIdentSlice(args []Any) []*ast.Ident {
// 	out := make([]*ast.Ident, len(args))
// 	for i, v := range args {
// 		out[i] = makeIdent(v.(astToken).Value)
// 	}
// 	return out
// }

func makeIdent(name string) *ast.Ident {
	return ast.NewIdent(name)
}

// func makeVector(typ string, elements []Any) *ast.CompositeLit {
// 	return makeCompositeLit(&ast.ArrayType{Elt: makeIdent(typ)}, evalExprs(elements))
// }

// func makeCompositeLit(typ ast.Expr, elements []ast.Expr) *ast.CompositeLit {
// 	return &ast.CompositeLit{
// 		Type: typ,
// 		Elts: elements,
// 	}
// }

func makeBasicLit(kind token.Token, value string) *ast.BasicLit {
	return &ast.BasicLit{Kind: kind, Value: value}
}

func makeNil() *ast.Ident {
	return makeIdent("nil")
}<commit_msg>removed unused types<commit_after>package generator

import (
	"go/ast"
	"go/token"
	"../parser"
)

// func generateAST(tree []parser.Node) *ast.File {
// 	return &ast.File{Name: makeIdent("main"), Decls: generateDeclarations(tree)}
// }

// func generateDeclarations(tree []parser.Node) []ast.Decl {
// 	decls := make([]ast.Decl, len(tree))

// 	for i, node := range tree {
// 		switch node.Type() {
// 		case parser.NodeCall:
// 			decls[i] = generateDeclaration(node)
// 		default:
// 			panic("unexpected behaviour!")
// 		}
// 	}

// 	return decls
// }

// func generateDeclaration(node parser.CallNode) ast.Decl {
// 	if node.Callee.(parser.IdentNode).Ident == "def" {
// 		return evalDef(node)
// 	}

// 	return nil
// }

// func evalDef(node parser.CallNode) ast.Decl {
// 	ident := node.Callee.(parser.IdentNode).Ident
// 	val := evalExpr(node.Args[0])

// 	return &ast.GenDecl{
// 		Tok: token.VAR,
// 		Specs: []ast.Spec{
// 			&ast.ValueSpec{
// 				Names:  []*ast.Ident{makeIdent(ident.Value)},
// 				Values: []ast.Expr{val},
// 			},
// 		},
// 	}
// }

func EvalExprs(nodes []parser.Node) []ast.Expr {
	out := make([]ast.Expr, len(nodes))

	for i, node := range nodes {
		out[i] = EvalExpr(node)
	}

	return out
}

func EvalExpr(node parser.Node) ast.Expr {
	switch t := node.Type(); t {
	case parser.NodeCall:
		node := node.(*parser.CallNode)
		return evalFuncCall(node)
	case parser.NodeNumber:
		node := node.(*parser.NumberNode)
		return makeBasicLit(node.NumberType, node.Value)
	case parser.NodeString:
		node := node.(*parser.StringNode)
		return makeBasicLit(token.STRING, node.Value)
	case parser.NodeIdent:
		node := node.(*parser.IdentNode)
		return makeIdent(node.Ident)
	case parser.NodeNil:
		return makeNil()
	default:
		println(t)
		panic("not implemented yet!")
	}
}

func evalFuncCall(node *parser.CallNode) ast.Expr {
	callee := EvalExpr(node.Callee)
	args := EvalExprs(node.Args)

	return makeFunCall(callee, args)
}

// func makeLitFunCall(body []Any) ast.Expr {
// 	return &ast.CallExpr{
// 		Fun:  makeFuncLit([]Any{}, body),
// 		Args: []ast.Expr{},
// 	}
// }

// func wrapExprsWithStmt(exps []ast.Expr) []ast.Stmt {
// 	out := make([]ast.Stmt, len(exps))
// 	for i, v := range exps {
// 		out[i] = &ast.ExprStmt{X: v}
// 	}
// 	return out
// }

func makeFunCall(callee ast.Expr, args []ast.Expr) ast.Expr {
	return &ast.CallExpr{
		Fun:  callee,
		Args: args,
	}
}

// func makeFuncLit(args, body []Any) *ast.FuncLit {
// 	node := &ast.FuncLit{
// 		Type: &ast.FuncType{

// 			Results: &ast.FieldList{
// 				List: []*ast.Field{
// 					&ast.Field{
// 						Type: makeIdent("Any"),
// 					},
// 				},
// 			},
// 		},
// 		Body: &ast.BlockStmt{
// 			List: returnLast(wrapExprsWithStmt(evalExprs(body))),
// 		},
// 	}

// 	if len(args) > 0 {
// 		node.Type.Params = makeParameterList(args)
// 	}

// 	return node
// }

// func makeParameterList(args []Any) *ast.FieldList {
// 	return &ast.FieldList{
// 		List: []*ast.Field{
// 			&ast.Field{
// 				Type:  makeIdent("Any"),
// 				Names: makeIdentSlice(args),
// 			},
// 		},
// 	}
// }

// func returnLast(stmts []ast.Stmt) []ast.Stmt {
// 	if len(stmts) < 1 {
// 		return stmts
// 	}

// 	stmts[len(stmts)-1] = &ast.ReturnStmt{
// 		Results: []ast.Expr{
// 			stmts[len(stmts)-1].(*ast.ExprStmt).X,
// 		},
// 	}
// 	return stmts
// }

// func makeIdentSlice(args []Any) []*ast.Ident {
// 	out := make([]*ast.Ident, len(args))
// 	for i, v := range args {
// 		out[i] = makeIdent(v.(astToken).Value)
// 	}
// 	return out
// }

func makeIdent(name string) *ast.Ident {
	return ast.NewIdent(name)
}

// func makeVector(typ string, elements []Any) *ast.CompositeLit {
// 	return makeCompositeLit(&ast.ArrayType{Elt: makeIdent(typ)}, evalExprs(elements))
// }

// func makeCompositeLit(typ ast.Expr, elements []ast.Expr) *ast.CompositeLit {
// 	return &ast.CompositeLit{
// 		Type: typ,
// 		Elts: elements,
// 	}
// }

func makeBasicLit(kind token.Token, value string) *ast.BasicLit {
	return &ast.BasicLit{Kind: kind, Value: value}
}

func makeNil() *ast.Ident {
	return makeIdent("nil")
}<|endoftext|>


<commit_before>package main

import "errors"
import "html/template"
import "io"
import "net/http"
import "os"
import "database/sql"
import _ "github.com/mattn/go-sqlite3"

import "github.com/daaku/go.httpgzip"
import "github.com/gorilla/mux"
import "github.com/gorilla/Schema"
import "github.com/gorilla/securecookie"
import "github.com/gorilla/sessions"

import "forums/model"

const (
	DATABASE_FILE = "forums.db"
)

type App struct {
	templates *template.Template
	db        *sql.DB
	sessions  *sessions.CookieStore
}

func newApp() *App {
	db, err := sql.Open("sqlite3", DATABASE_FILE)
	if err != nil {
		panic("error opening database")
	}

	templates := template.Must(template.ParseFiles(
		"templates/header.html",
		"templates/footer.html",
		"templates/index.html",
		"templates/forum.html",
		"templates/topic.html",
		"templates/addPost.html",
		"templates/addTopic.html",
		"templates/register.html",
		"templates/login.html",
	))

	sessionStore := sessions.NewCookieStore(securecookie.GenerateRandomKey(64))

	return &App{templates, db, sessionStore}
}

func (app *App) destroy() {
	app.db.Close()
}

func (app *App) addErrorFlashes(w http.ResponseWriter, r *http.Request, errs []error) {
	for _, err := range errs {
		app.addErrorFlash(w, r, err)
	}
}

func (app *App) addErrorFlash(w http.ResponseWriter, r *http.Request, error error) {
    session, _ := app.sessions.Get(r, "forumSession")
    session.AddFlash(error.Error())
    session.Save(r, w)
}

func (app *App) renderTemplate(w http.ResponseWriter, r *http.Request, tmpl string, data map[string]interface{}) {
    session, _ := app.sessions.Get(r, "forumSession")

    data["flashes"] = session.Flashes()

    if userId, ok := session.Values["user_id"].(int); ok {
	    user, err := model.FindOneUserById(app.db, userId)
		if err == nil {
	    	data["user"] = user
	    }
    }

    session.Save(r, w)

	err := app.templates.ExecuteTemplate(w, tmpl+".html", data)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func (app *App) handleIndex(w http.ResponseWriter, req *http.Request) {
	forums, err := model.FindForums(app.db)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	results := make(map[string]interface{})
	results["forums"] = forums

	app.renderTemplate(w, req, "index", results)
}

func (app *App) handleForum(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	id := vars["id"]

	forum, err := model.FindOneForum(app.db, id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

	topics, err := model.FindTopics(app.db, id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	results := make(map[string]interface{})
	results["forum"] = forum
	results["topics"] = topics

	app.renderTemplate(w, req, "forum", results)
}

func (app *App) handleTopic(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	id := vars["id"]

	topic, err := model.FindOneTopic(app.db, id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	posts, err := model.FindPosts(app.db, id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	results := make(map[string]interface{})
	results["topic"] = topic
	results["posts"] = posts

	app.renderTemplate(w, req, "topic", results)
}

func (app *App) handleAddTopic(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	id := vars["id"]

	results := make(map[string]interface{})
	results["ForumId"] = id
	app.renderTemplate(w, req, "addTopic", results)
}

func (app *App) handleSaveTopic(w http.ResponseWriter, req *http.Request) {
	req.ParseForm()

	topic := model.NewTopic()
    decoder := schema.NewDecoder()
    err := decoder.Decode(topic, req.PostForm)
    if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
    }

    ok, errors := model.ValidateTopic(topic)
    if !ok {
    	app.addErrorFlashes(w, req, errors)
    	http.Redirect(w, req, "/forum/" + req.PostFormValue("ForumId") + "/add", 302)
    	return
    }

	err = model.SaveTopic(app.db, topic)
    if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
    }

	http.Redirect(w, req, "/forum/" + req.PostFormValue("ForumId"), 302)
}

func (app *App) handleAddPost(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	id := vars["id"]

	results := make(map[string]interface{})
	results["TopicId"] = id
	app.renderTemplate(w, req, "addPost", results)
}

func (app *App) handleSavePost(w http.ResponseWriter, req *http.Request) {
	req.ParseForm()

	post := model.NewPost()
    decoder := schema.NewDecoder()
    err := decoder.Decode(post, req.PostForm)
    if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
    }

    ok, errors := model.ValidatePost(post)
    if !ok {
    	app.addErrorFlashes(w, req, errors)
    	http.Redirect(w, req, "/topic/" + req.PostFormValue("TopicId") + "/add", 302)
    	return
    }

	err = model.SavePost(app.db, post)
    if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
    }

	http.Redirect(w, req, "/topic/" + req.PostFormValue("TopicId"), 302)
}

func (app *App) handleRegister(w http.ResponseWriter, req *http.Request) {
	results := make(map[string]interface{})
	app.renderTemplate(w, req, "register", results)
}

func (app *App) saveRegister(w http.ResponseWriter, req *http.Request) {
	req.ParseForm()

	user := model.NewUser()
    // manually grab password so we can convert to byte
    user.Username = req.PostFormValue("Username")
    user.Email = req.PostFormValue("Email")
    user.Password = []byte(req.PostFormValue("Password"))

    ok, errors := model.ValidateUser(user)
    if !ok {
    	app.addErrorFlashes(w, req, errors)
    	http.Redirect(w, req, "/user/add", 302)
    	return
    }

    err := user.HashPassword()
    if err != nil {
    	app.addErrorFlash(w, req, err)
    	http.Redirect(w, req, "/user/add", 302)
    	return
    }

    err = model.SaveUser(app.db, user)
	if err != nil {
    	app.addErrorFlash(w, req, err)
    	http.Redirect(w, req, "/user/add", 302)
    	return
    }

    http.Redirect(w, req, "/", 302)
}

func (app *App) handleLogin(w http.ResponseWriter, req *http.Request) {
	results := make(map[string]interface{})
	app.renderTemplate(w, req, "login", results)
}

func (app *App) saveLogin(w http.ResponseWriter, req *http.Request) {
	req.ParseForm()

	username := req.PostFormValue("Username")
	password := []byte(req.PostFormValue("Password"))

	if username == "" || len(password) == 0 {
		app.addErrorFlash(w, req, errors.New("Enter a username and password."))
		http.Redirect(w, req, "/user/login", 302)
		return
	}

	invalidUserOrPassword := errors.New("Invalid username or password.")

	user, err := model.FindOneUser(app.db, username)
	if err != nil {
		app.addErrorFlash(w, req, invalidUserOrPassword)
		http.Redirect(w, req, "/user/login", 302)
		return
	}

	err = user.CompareHashAndPassword(&password)
	if err != nil {
		app.addErrorFlash(w, req, invalidUserOrPassword)
		http.Redirect(w, req, "/user/login", 302)
		return
	}

    session, _ := app.sessions.Get(req, "forumSession")
    session.Values["user_id"] = user.Id
    session.Save(req, w)

	http.Redirect(w, req, "/", 302)
}

func (app *App) handleLogout(w http.ResponseWriter, req *http.Request) {
    session, _ := app.sessions.Get(req, "forumSession")
    delete(session.Values, "user_id")
    session.Save(req, w)

    http.Redirect(w, req, "/", 302)
}

func (app *App) handleLoginRequired(nextHandler func(http.ResponseWriter, *http.Request), pathToRedirect string) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, req *http.Request) {
	    session, _ := app.sessions.Get(req, "forumSession")
		if _, ok := session.Values["user_id"]; !ok {
			if id, ok := mux.Vars(req)["id"]; ok {
				pathToRedirect += "/" + id
			}

			app.addErrorFlash(w, req, errors.New("Must be logged in!"))
			http.Redirect(w, req, pathToRedirect, 302)
			return
		}

		nextHandler(w, req)
	}
}

func backup() {
	src, err := os.Open(DATABASE_FILE)
	defer src.Close()
	if err != nil {
		panic("could not open database to backup")
	}

	dest, err := os.Create("backup/" + DATABASE_FILE)
	defer dest.Close()
	if err != nil {
		panic("could not open backup/" + DATABASE_FILE)
	}

	io.Copy(dest, src)
}

func main() {
	backup()

	app := newApp()

	r := mux.NewRouter()
	r.HandleFunc("/", app.handleIndex)

	f := r.PathPrefix("/forum").Subrouter()
	f.HandleFunc("/{id:[0-9]+}", app.handleForum)
	f.HandleFunc("/{id:[0-9]+}/add", app.handleLoginRequired(app.handleAddTopic, "/forum")).Methods("GET")
	f.HandleFunc("/{id:[0-9]+}/add", app.handleLoginRequired(app.handleSaveTopic, "/forum")).Methods("POST")

	t := r.PathPrefix("/topic").Subrouter()
	t.HandleFunc("/{id:[0-9]+}", app.handleTopic)
	t.HandleFunc("/{id:[0-9]+}/add", app.handleLoginRequired(app.handleAddPost, "/topic")).Methods("GET")
	t.HandleFunc("/{id:[0-9]+}/add", app.handleLoginRequired(app.handleSavePost, "/topic")).Methods("POST")

	u := r.PathPrefix("/user").Subrouter()
	u.HandleFunc("/add", app.handleRegister).Methods("GET")
	u.HandleFunc("/add", app.saveRegister).Methods("POST")
	u.HandleFunc("/login", app.handleLogin).Methods("GET")
	u.HandleFunc("/login", app.saveLogin).Methods("POST")
	u.HandleFunc("/logout", app.handleLogout)

	http.Handle("/", httpgzip.NewHandler(r))
	http.ListenAndServe(":8080", nil)

	app.destroy()
}
<commit_msg>switch to http constant<commit_after>package main

import "errors"
import "html/template"
import "io"
import "net/http"
import "os"
import "database/sql"
import _ "github.com/mattn/go-sqlite3"

import "github.com/daaku/go.httpgzip"
import "github.com/gorilla/mux"
import "github.com/gorilla/Schema"
import "github.com/gorilla/securecookie"
import "github.com/gorilla/sessions"

import "forums/model"

const (
	DATABASE_FILE = "forums.db"
)

type App struct {
	templates *template.Template
	db        *sql.DB
	sessions  *sessions.CookieStore
}

func newApp() *App {
	db, err := sql.Open("sqlite3", DATABASE_FILE)
	if err != nil {
		panic("error opening database")
	}

	templates := template.Must(template.ParseFiles(
		"templates/header.html",
		"templates/footer.html",
		"templates/index.html",
		"templates/forum.html",
		"templates/topic.html",
		"templates/addPost.html",
		"templates/addTopic.html",
		"templates/register.html",
		"templates/login.html",
	))

	sessionStore := sessions.NewCookieStore(securecookie.GenerateRandomKey(64))

	return &App{templates, db, sessionStore}
}

func (app *App) destroy() {
	app.db.Close()
}

func (app *App) addErrorFlashes(w http.ResponseWriter, r *http.Request, errs []error) {
	for _, err := range errs {
		app.addErrorFlash(w, r, err)
	}
}

func (app *App) addErrorFlash(w http.ResponseWriter, r *http.Request, error error) {
    session, _ := app.sessions.Get(r, "forumSession")
    session.AddFlash(error.Error())
    session.Save(r, w)
}

func (app *App) renderTemplate(w http.ResponseWriter, r *http.Request, tmpl string, data map[string]interface{}) {
    session, _ := app.sessions.Get(r, "forumSession")

    data["flashes"] = session.Flashes()

    if userId, ok := session.Values["user_id"].(int); ok {
	    user, err := model.FindOneUserById(app.db, userId)
		if err == nil {
	    	data["user"] = user
	    }
    }

    session.Save(r, w)

	err := app.templates.ExecuteTemplate(w, tmpl+".html", data)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func (app *App) handleIndex(w http.ResponseWriter, req *http.Request) {
	forums, err := model.FindForums(app.db)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	results := make(map[string]interface{})
	results["forums"] = forums

	app.renderTemplate(w, req, "index", results)
}

func (app *App) handleForum(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	id := vars["id"]

	forum, err := model.FindOneForum(app.db, id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

	topics, err := model.FindTopics(app.db, id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	results := make(map[string]interface{})
	results["forum"] = forum
	results["topics"] = topics

	app.renderTemplate(w, req, "forum", results)
}

func (app *App) handleTopic(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	id := vars["id"]

	topic, err := model.FindOneTopic(app.db, id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	posts, err := model.FindPosts(app.db, id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	results := make(map[string]interface{})
	results["topic"] = topic
	results["posts"] = posts

	app.renderTemplate(w, req, "topic", results)
}

func (app *App) handleAddTopic(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	id := vars["id"]

	results := make(map[string]interface{})
	results["ForumId"] = id
	app.renderTemplate(w, req, "addTopic", results)
}

func (app *App) handleSaveTopic(w http.ResponseWriter, req *http.Request) {
	req.ParseForm()

	topic := model.NewTopic()
    decoder := schema.NewDecoder()
    err := decoder.Decode(topic, req.PostForm)
    if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
    }

    ok, errors := model.ValidateTopic(topic)
    if !ok {
    	app.addErrorFlashes(w, req, errors)
    	http.Redirect(w, req, "/forum/" + req.PostFormValue("ForumId") + "/add", http.StatusFound)
    	return
    }

	err = model.SaveTopic(app.db, topic)
    if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
    }

	http.Redirect(w, req, "/forum/" + req.PostFormValue("ForumId"), http.StatusFound)
}

func (app *App) handleAddPost(w http.ResponseWriter, req *http.Request) {
	vars := mux.Vars(req)
	id := vars["id"]

	results := make(map[string]interface{})
	results["TopicId"] = id
	app.renderTemplate(w, req, "addPost", results)
}

func (app *App) handleSavePost(w http.ResponseWriter, req *http.Request) {
	req.ParseForm()

	post := model.NewPost()
    decoder := schema.NewDecoder()
    err := decoder.Decode(post, req.PostForm)
    if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
    }

    ok, errors := model.ValidatePost(post)
    if !ok {
    	app.addErrorFlashes(w, req, errors)
    	http.Redirect(w, req, "/topic/" + req.PostFormValue("TopicId") + "/add", http.StatusFound)
    	return
    }

	err = model.SavePost(app.db, post)
    if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
    }

	http.Redirect(w, req, "/topic/" + req.PostFormValue("TopicId"), http.StatusFound)
}

func (app *App) handleRegister(w http.ResponseWriter, req *http.Request) {
	results := make(map[string]interface{})
	app.renderTemplate(w, req, "register", results)
}

func (app *App) saveRegister(w http.ResponseWriter, req *http.Request) {
	req.ParseForm()

	user := model.NewUser()
    // manually grab password so we can convert to byte
    user.Username = req.PostFormValue("Username")
    user.Email = req.PostFormValue("Email")
    user.Password = []byte(req.PostFormValue("Password"))

    ok, errors := model.ValidateUser(user)
    if !ok {
    	app.addErrorFlashes(w, req, errors)
    	http.Redirect(w, req, "/user/add", http.StatusFound)
    	return
    }

    err := user.HashPassword()
    if err != nil {
    	app.addErrorFlash(w, req, err)
    	http.Redirect(w, req, "/user/add", http.StatusFound)
    	return
    }

    err = model.SaveUser(app.db, user)
	if err != nil {
    	app.addErrorFlash(w, req, err)
    	http.Redirect(w, req, "/user/add", http.StatusFound)
    	return
    }

    http.Redirect(w, req, "/", http.StatusFound)
}

func (app *App) handleLogin(w http.ResponseWriter, req *http.Request) {
	results := make(map[string]interface{})
	app.renderTemplate(w, req, "login", results)
}

func (app *App) saveLogin(w http.ResponseWriter, req *http.Request) {
	req.ParseForm()

	username := req.PostFormValue("Username")
	password := []byte(req.PostFormValue("Password"))

	if username == "" || len(password) == 0 {
		app.addErrorFlash(w, req, errors.New("Enter a username and password."))
		http.Redirect(w, req, "/user/login", http.StatusFound)
		return
	}

	invalidUserOrPassword := errors.New("Invalid username or password.")

	user, err := model.FindOneUser(app.db, username)
	if err != nil {
		app.addErrorFlash(w, req, invalidUserOrPassword)
		http.Redirect(w, req, "/user/login", http.StatusFound)
		return
	}

	err = user.CompareHashAndPassword(&password)
	if err != nil {
		app.addErrorFlash(w, req, invalidUserOrPassword)
		http.Redirect(w, req, "/user/login", http.StatusFound)
		return
	}

    session, _ := app.sessions.Get(req, "forumSession")
    session.Values["user_id"] = user.Id
    session.Save(req, w)

	http.Redirect(w, req, "/", http.StatusFound)
}

func (app *App) handleLogout(w http.ResponseWriter, req *http.Request) {
    session, _ := app.sessions.Get(req, "forumSession")
    delete(session.Values, "user_id")
    session.Save(req, w)

    http.Redirect(w, req, "/", http.StatusFound)
}

func (app *App) handleLoginRequired(nextHandler func(http.ResponseWriter, *http.Request), pathToRedirect string) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, req *http.Request) {
	    session, _ := app.sessions.Get(req, "forumSession")
		if _, ok := session.Values["user_id"]; !ok {
			if id, ok := mux.Vars(req)["id"]; ok {
				pathToRedirect += "/" + id
			}

			app.addErrorFlash(w, req, errors.New("Must be logged in!"))
			http.Redirect(w, req, pathToRedirect, http.StatusFound)
			return
		}

		nextHandler(w, req)
	}
}

func backup() {
	src, err := os.Open(DATABASE_FILE)
	defer src.Close()
	if err != nil {
		panic("could not open database to backup")
	}

	dest, err := os.Create("backup/" + DATABASE_FILE)
	defer dest.Close()
	if err != nil {
		panic("could not open backup/" + DATABASE_FILE)
	}

	io.Copy(dest, src)
}

func main() {
	backup()

	app := newApp()

	r := mux.NewRouter()
	r.HandleFunc("/", app.handleIndex)

	f := r.PathPrefix("/forum").Subrouter()
	f.HandleFunc("/{id:[0-9]+}", app.handleForum)
	f.HandleFunc("/{id:[0-9]+}/add", app.handleLoginRequired(app.handleAddTopic, "/forum")).Methods("GET")
	f.HandleFunc("/{id:[0-9]+}/add", app.handleLoginRequired(app.handleSaveTopic, "/forum")).Methods("POST")

	t := r.PathPrefix("/topic").Subrouter()
	t.HandleFunc("/{id:[0-9]+}", app.handleTopic)
	t.HandleFunc("/{id:[0-9]+}/add", app.handleLoginRequired(app.handleAddPost, "/topic")).Methods("GET")
	t.HandleFunc("/{id:[0-9]+}/add", app.handleLoginRequired(app.handleSavePost, "/topic")).Methods("POST")

	u := r.PathPrefix("/user").Subrouter()
	u.HandleFunc("/add", app.handleRegister).Methods("GET")
	u.HandleFunc("/add", app.saveRegister).Methods("POST")
	u.HandleFunc("/login", app.handleLogin).Methods("GET")
	u.HandleFunc("/login", app.saveLogin).Methods("POST")
	u.HandleFunc("/logout", app.handleLogout)

	http.Handle("/", httpgzip.NewHandler(r))
	http.ListenAndServe(":8080", nil)

	app.destroy()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"sort"
	"strconv"

	"github.com/gin-gonic/gin"
	"zxq.co/ripple/cheesegull/models"
)

type beatmapPageData struct {
	baseTemplateData

	Found      bool
	Beatmap    models.Beatmap
	Beatmapset models.Set
	SetJSON    string
}

func beatmapInfo(c *gin.Context) {
	data := new(beatmapPageData)
	defer resp(c, 200, "beatmap.html", data)

	b := c.Param("bid")
	if _, err := strconv.Atoi(b); err != nil {
		c.Error(err)
	} else {
		data.Beatmap, err = getBeatmapData(b)
		if err != nil {
			c.Error(err)
			return
		}
		data.Beatmapset, err = getBeatmapSetData(data.Beatmap)
		if err != nil {
			c.Error(err)
			return
		}
		sort.Slice(data.Beatmapset.ChildrenBeatmaps, func(i, j int) bool {
			if data.Beatmapset.ChildrenBeatmaps[i].Mode != data.Beatmapset.ChildrenBeatmaps[j].Mode {
				return data.Beatmapset.ChildrenBeatmaps[i].Mode < data.Beatmapset.ChildrenBeatmaps[j].Mode
			}
			return data.Beatmapset.ChildrenBeatmaps[i].DifficultyRating < data.Beatmapset.ChildrenBeatmaps[j].DifficultyRating
		})
	}

	if data.Beatmapset.ID == 0 {
		data.TitleBar = T(c, "Beatmap not found.")
		data.Messages = append(data.Messages, errorMessage{T(c, "Beatmap could not be found.")})
		return
	}

	setJson, err := json.Marshal(data.Beatmapset)
	if err == nil {
		data.SetJSON = fmt.Sprintf("%s", setJson)
	} else {
		data.SetJSON = "[]"
	}

	data.TitleBar = T(c, "%s - %s", data.Beatmapset.Artist, data.Beatmapset.Title)
	data.Scripts = append(data.Scripts, "/static/beatmap.js")
}

func getBeatmapData(b string) (beatmap models.Beatmap, err error) {
	resp, err := http.Get(config.CheesegullAPI + "/b/" + b)
	if err != nil {
		return beatmap, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return beatmap, err
	}

	err = json.Unmarshal(body, &beatmap)
	if err != nil {
		return beatmap, err
	}

	return beatmap, nil
}

func getBeatmapSetData(beatmap models.Beatmap) (bset models.Set, err error) {
	resp, err := http.Get(config.CheesegullAPI + "/s/" + strconv.Itoa(beatmap.ParentSetID))
	if err != nil {
		return bset, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return bset, err
	}

	err = json.Unmarshal(body, &bset)
	if err != nil {
		return bset, err
	}

	return bset, nil
}
<commit_msg>use string() instead of Sprintf<commit_after>package main

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"sort"
	"strconv"

	"github.com/gin-gonic/gin"
	"zxq.co/ripple/cheesegull/models"
)

type beatmapPageData struct {
	baseTemplateData

	Found      bool
	Beatmap    models.Beatmap
	Beatmapset models.Set
	SetJSON    string
}

func beatmapInfo(c *gin.Context) {
	data := new(beatmapPageData)
	defer resp(c, 200, "beatmap.html", data)

	b := c.Param("bid")
	if _, err := strconv.Atoi(b); err != nil {
		c.Error(err)
	} else {
		data.Beatmap, err = getBeatmapData(b)
		if err != nil {
			c.Error(err)
			return
		}
		data.Beatmapset, err = getBeatmapSetData(data.Beatmap)
		if err != nil {
			c.Error(err)
			return
		}
		sort.Slice(data.Beatmapset.ChildrenBeatmaps, func(i, j int) bool {
			if data.Beatmapset.ChildrenBeatmaps[i].Mode != data.Beatmapset.ChildrenBeatmaps[j].Mode {
				return data.Beatmapset.ChildrenBeatmaps[i].Mode < data.Beatmapset.ChildrenBeatmaps[j].Mode
			}
			return data.Beatmapset.ChildrenBeatmaps[i].DifficultyRating < data.Beatmapset.ChildrenBeatmaps[j].DifficultyRating
		})
	}

	if data.Beatmapset.ID == 0 {
		data.TitleBar = T(c, "Beatmap not found.")
		data.Messages = append(data.Messages, errorMessage{T(c, "Beatmap could not be found.")})
		return
	}

	setJson, err := json.Marshal(data.Beatmapset)
	if err == nil {
		data.SetJSON = string(setJson)
	} else {
		data.SetJSON = "[]"
	}

	data.TitleBar = T(c, "%s - %s", data.Beatmapset.Artist, data.Beatmapset.Title)
	data.Scripts = append(data.Scripts, "/static/beatmap.js")
}

func getBeatmapData(b string) (beatmap models.Beatmap, err error) {
	resp, err := http.Get(config.CheesegullAPI + "/b/" + b)
	if err != nil {
		return beatmap, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return beatmap, err
	}

	err = json.Unmarshal(body, &beatmap)
	if err != nil {
		return beatmap, err
	}

	return beatmap, nil
}

func getBeatmapSetData(beatmap models.Beatmap) (bset models.Set, err error) {
	resp, err := http.Get(config.CheesegullAPI + "/s/" + strconv.Itoa(beatmap.ParentSetID))
	if err != nil {
		return bset, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return bset, err
	}

	err = json.Unmarshal(body, &bset)
	if err != nil {
		return bset, err
	}

	return bset, nil
}
<|endoftext|>


<commit_before>package client

import (
	"encoding/gob"
	"fmt"
	"io"

	"github.com/Symantec/Dominator/lib/errors"
	"github.com/Symantec/Dominator/lib/srpc"
	proto "github.com/Symantec/Dominator/proto/imaginator"
)

func buildImage(client *srpc.Client, request proto.BuildImageRequest,
	response *proto.BuildImageResponse, logWriter io.Writer) error {
	conn, err := client.Call("Imaginator.BuildImage")
	if err != nil {
		return err
	}
	defer conn.Close()
	decoder := gob.NewDecoder(conn)
	encoder := gob.NewEncoder(conn)
	if err := encoder.Encode(request); err != nil {
		return err
	}
	if err := conn.Flush(); err != nil {
		return err
	}
	str, err := conn.ReadString('\n')
	if err != nil {
		return err
	}
	if str != "\n" {
		return errors.New(str[:len(str)-1])
	}
	for {
		var reply proto.BuildImageResponse
		if err := decoder.Decode(&reply); err != nil {
			return fmt.Errorf("error reading reply: %s", err)
		}
		if err := errors.New(reply.ErrorString); err != nil {
			return err
		}
		logWriter.Write(reply.BuildLog)
		reply.BuildLog = nil
		if reply.Image != nil || reply.ImageName != "" {
			*response = reply
			return nil
		}
	}
}
<commit_msg>Switch imagebuilder/client to use connection Decode and Encode methods.<commit_after>package client

import (
	"fmt"
	"io"

	"github.com/Symantec/Dominator/lib/errors"
	"github.com/Symantec/Dominator/lib/srpc"
	proto "github.com/Symantec/Dominator/proto/imaginator"
)

func buildImage(client *srpc.Client, request proto.BuildImageRequest,
	response *proto.BuildImageResponse, logWriter io.Writer) error {
	conn, err := client.Call("Imaginator.BuildImage")
	if err != nil {
		return err
	}
	defer conn.Close()
	if err := conn.Encode(request); err != nil {
		return err
	}
	if err := conn.Flush(); err != nil {
		return err
	}
	str, err := conn.ReadString('\n')
	if err != nil {
		return err
	}
	if str != "\n" {
		return errors.New(str[:len(str)-1])
	}
	for {
		var reply proto.BuildImageResponse
		if err := conn.Decode(&reply); err != nil {
			return fmt.Errorf("error reading reply: %s", err)
		}
		if err := errors.New(reply.ErrorString); err != nil {
			return err
		}
		logWriter.Write(reply.BuildLog)
		reply.BuildLog = nil
		if reply.Image != nil || reply.ImageName != "" {
			*response = reply
			return nil
		}
	}
}
<|endoftext|>


<commit_before>/*
 Copyright 2015 Stack Inc.
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

package cli

import (
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
)

type Compiler struct {
	ConfigPath   string
	TargetName   string
	BaseIncludes []string
	ObjPathList  map[string]bool
	LinkerScript string

	Cflags string
	Aflags string
	Lflags string

	ccPath                string
	asPath                string
	arPath                string
	odPath                string
	osPath                string
	ldFlags               string
	ldResolveCircularDeps bool
	ldMapFile             bool
}

func NewCompiler(ccPath string, cDef string, tName string, includes []string) (
	*Compiler, error) {
	c := &Compiler{
		ConfigPath:   ccPath,
		TargetName:   tName,
		BaseIncludes: includes,
	}

	log.Printf("[INFO] Loading compiler %s, target %s, def %s", ccPath, tName, cDef)

	err := c.ReadSettings(cDef)
	if err != nil {
		return nil, err
	}

	c.ObjPathList = make(map[string]bool)

	return c, nil
}

func (c *Compiler) ReadSettings(cDef string) error {
	v, err := ReadConfig(c.ConfigPath, "compiler")
	if err != nil {
		return err
	}

	c.ccPath = v.GetString("compiler.path.cc")
	c.asPath = v.GetString("compiler.path.as")
	c.arPath = v.GetString("compiler.path.archive")
	c.odPath = v.GetString("compiler.path.objdump")
	c.osPath = v.GetString("compiler.path.objsize")

	cflags := v.GetStringSlice("compiler.flags." + cDef)
	for _, flag := range cflags {
		if strings.HasPrefix(flag, "compiler.flags") {
			c.Cflags += " " + strings.Trim(v.GetString(flag), "\n")
		} else {
			c.Cflags += " " + strings.Trim(flag, "\n")
		}
	}

	c.ldFlags = v.GetString("compiler.ld.flags")
	c.ldResolveCircularDeps = v.GetBool("compiler.ld.resolve_circular_deps")
	c.ldMapFile = v.GetBool("compiler.ld.mapfile")

	log.Printf("[INFO] ccPath = %s, arPath = %s, flags = %s", c.ccPath,
		c.arPath, c.Cflags)

	return nil
}

// file type 0 = cc, file type 1 = as
func (c *Compiler) CompileFile(file string, compilerType int) error {
	wd, _ := os.Getwd()
	objDir := wd + "/obj/" + c.TargetName + "/"

	if NodeNotExist(objDir) {
		os.MkdirAll(objDir, 0755)
	}

	objFile := strings.TrimSuffix(file, filepath.Ext(file)) + ".o"

	objPath := objDir + objFile
	c.ObjPathList[objPath] = true

	var cmd string

	switch compilerType {
	case 0:
		cmd = c.ccPath
	case 1:
		cmd = c.asPath
	default:
		return NewStackError("Unknown compiler type")
	}

	cmd += " -c " + "-o " + objPath + " " + file +
		" " + c.Cflags + " -I" + strings.Join(c.BaseIncludes, " -I")

	_, err := ShellCommand(cmd)
	return err
}

func (c *Compiler) Compile(match string) error {
	files, _ := filepath.Glob(match)

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

	log.Printf("[INFO] Compiling C (%s/%s) %s", wd, match, strings.Join(files, " "))

	for _, file := range files {
		err := c.CompileFile(file, 0)
		if err != nil {
			return err
		}
	}
	return nil
}

func (c *Compiler) CompileAs(match string) error {
	files, _ := filepath.Glob(match)

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

	log.Printf("[INFO] Compiling assembly (%s/%s) %s", wd, match, strings.Join(files, " "))

	for _, file := range files {
		err := c.CompileFile(file, 1)
		if err != nil {
			return err
		}
	}

	return nil
}

func (c *Compiler) RecursiveClean(path string, tName string) error {
	// Find all the subdirectories of path that contain an "obj/" directory, and
	// remove that directory either altogether, or just the arch specific directory.
	dirList, err := ioutil.ReadDir(path)
	if err != nil {
		return NewStackError(err.Error())
	}

	for _, node := range dirList {
		if node.IsDir() {
			if node.Name() == "obj" || node.Name() == "bin" {
				if tName == "" {
					os.RemoveAll(path + "/" + node.Name() + "/")
				} else {
					os.RemoveAll(path + "/" + node.Name() + "/" + tName + "/")
				}
			} else {
				// recurse into the directory.
				err = c.RecursiveClean(path+"/"+node.Name(), tName)
				if err != nil {
					return err
				}
			}
		}
	}

	return nil
}

func (c *Compiler) processEntry(wd string, node os.FileInfo, match string, cType int,
	ignDirs []string) error {
	// check to see if we ignore this element
	for _, entry := range ignDirs {
		if entry == node.Name() {
			return nil
		}
	}

	// if not, recurse into the directory
	os.Chdir(wd + "/" + node.Name())
	return c.RecursiveCompile(match, cType, ignDirs)
}

func (c *Compiler) RecursiveCompile(match string, cType int, ignDirs []string) error {
	// Get a list of files in the current directory, and if they are a directory,
	// and that directory is not in the ignDirs variable, then recurse into that
	// directory and compile the files in there
	wd, err := os.Getwd()
	if err != nil {
		return NewStackError(err.Error())
	}

	dirList, err := ioutil.ReadDir(wd)
	if err != nil {
		return NewStackError(err.Error())
	}

	for _, node := range dirList {
		if node.IsDir() {
			err = c.processEntry(wd, node, match, cType, ignDirs)
			if err != nil {
				return err
			}
		}
	}

	os.Chdir(wd)

	switch cType {
	case 0:
		return c.Compile(match)
	case 1:
		return c.CompileAs(match)
	default:
		return NewStackError("Wrong compiler type specified to RecursiveCompile")
	}
}

func (c *Compiler) getObjFiles(baseObjFiles string) string {
	objList := baseObjFiles
	for objName, _ := range c.ObjPathList {
		objList += " " + objName
	}
	return objList
}

func (c *Compiler) CompileBinary(binFile string, options map[string]bool,
	objFiles string) error {
	objList := c.getObjFiles(objFiles)

	log.Printf("[INFO] Compiling Binary %s with object files %s", binFile,
		objList)

	cmd := c.ccPath + " -o " + binFile + " " + c.ldFlags + " " + c.Cflags
	if c.ldResolveCircularDeps {
		cmd += " -Wl,--start-group -lc " + objList + " -Wl,--end-group "
	} else {
		cmd += " " + objList
	}

	if c.LinkerScript != "" {
		cmd += " -T " + c.LinkerScript
	}
	if checkBoolMap(options, "mapFile") {
		cmd += " -Wl,-Map=" + binFile + ".map"
	}

	_, err := ShellCommand(cmd)
	if err != nil {
		return err
	}

	if checkBoolMap(options, "listFile") {
		listFile := binFile + ".lst"
		// if list file exists, remove it
		if NodeExist(listFile) {
			if err := os.RemoveAll(listFile); err != nil {
				return err
			}
		}

		cmd = c.odPath + " -wxdS " + binFile + " >> " + listFile
		_, err := ShellCommand(cmd)
		if err != nil {
			return err
		}

		sects := []string{".text", ".rodata", ".fc", ".data"}
		for _, sect := range sects {
			cmd = c.odPath + " -s -j " + sect + " " + binFile + " >> " + listFile
			_, err := ShellCommand(cmd)
			if err != nil {
				return err
			}
		}

		cmd = c.osPath + " " + binFile + " >> " + listFile
	}

	return nil

}

func (c *Compiler) CompileElf(binFile string, options map[string]bool,
	objFiles string) error {
	binFile += ".elf"
	return c.CompileBinary(binFile, options, objFiles)
}

func (c *Compiler) CompileArchive(archiveFile string, objFiles string) error {
	objList := c.getObjFiles(objFiles)

	log.Printf("[INFO] Compiling archive %s with object files %s",
		archiveFile, objList)

	cmd := c.arPath + " rcs " + archiveFile + " " + objList

	_, err := ShellCommand(cmd)
	return err
}
<commit_msg>Do not return on error if a section is not present when we try to add it to the .lst file. Remove the .fc section since we dont have that section<commit_after>/*
 Copyright 2015 Stack Inc.
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

package cli

import (
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
)

type Compiler struct {
	ConfigPath   string
	TargetName   string
	BaseIncludes []string
	ObjPathList  map[string]bool
	LinkerScript string

	Cflags string
	Aflags string
	Lflags string

	ccPath                string
	asPath                string
	arPath                string
	odPath                string
	osPath                string
	ldFlags               string
	ldResolveCircularDeps bool
	ldMapFile             bool
}

func NewCompiler(ccPath string, cDef string, tName string, includes []string) (
	*Compiler, error) {
	c := &Compiler{
		ConfigPath:   ccPath,
		TargetName:   tName,
		BaseIncludes: includes,
	}

	log.Printf("[INFO] Loading compiler %s, target %s, def %s", ccPath, tName, cDef)

	err := c.ReadSettings(cDef)
	if err != nil {
		return nil, err
	}

	c.ObjPathList = make(map[string]bool)

	return c, nil
}

func (c *Compiler) ReadSettings(cDef string) error {
	v, err := ReadConfig(c.ConfigPath, "compiler")
	if err != nil {
		return err
	}

	c.ccPath = v.GetString("compiler.path.cc")
	c.asPath = v.GetString("compiler.path.as")
	c.arPath = v.GetString("compiler.path.archive")
	c.odPath = v.GetString("compiler.path.objdump")
	c.osPath = v.GetString("compiler.path.objsize")

	cflags := v.GetStringSlice("compiler.flags." + cDef)
	for _, flag := range cflags {
		if strings.HasPrefix(flag, "compiler.flags") {
			c.Cflags += " " + strings.Trim(v.GetString(flag), "\n")
		} else {
			c.Cflags += " " + strings.Trim(flag, "\n")
		}
	}

	c.ldFlags = v.GetString("compiler.ld.flags")
	c.ldResolveCircularDeps = v.GetBool("compiler.ld.resolve_circular_deps")
	c.ldMapFile = v.GetBool("compiler.ld.mapfile")

	log.Printf("[INFO] ccPath = %s, arPath = %s, flags = %s", c.ccPath,
		c.arPath, c.Cflags)

	return nil
}

// file type 0 = cc, file type 1 = as
func (c *Compiler) CompileFile(file string, compilerType int) error {
	wd, _ := os.Getwd()
	objDir := wd + "/obj/" + c.TargetName + "/"

	if NodeNotExist(objDir) {
		os.MkdirAll(objDir, 0755)
	}

	objFile := strings.TrimSuffix(file, filepath.Ext(file)) + ".o"

	objPath := objDir + objFile
	c.ObjPathList[objPath] = true

	var cmd string

	switch compilerType {
	case 0:
		cmd = c.ccPath
	case 1:
		cmd = c.asPath
	default:
		return NewStackError("Unknown compiler type")
	}

	cmd += " -c " + "-o " + objPath + " " + file +
		" " + c.Cflags + " -I" + strings.Join(c.BaseIncludes, " -I")

	_, err := ShellCommand(cmd)
	return err
}

func (c *Compiler) Compile(match string) error {
	files, _ := filepath.Glob(match)

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

	log.Printf("[INFO] Compiling C (%s/%s) %s", wd, match, strings.Join(files, " "))

	for _, file := range files {
		err := c.CompileFile(file, 0)
		if err != nil {
			return err
		}
	}
	return nil
}

func (c *Compiler) CompileAs(match string) error {
	files, _ := filepath.Glob(match)

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

	log.Printf("[INFO] Compiling assembly (%s/%s) %s", wd, match, strings.Join(files, " "))

	for _, file := range files {
		err := c.CompileFile(file, 1)
		if err != nil {
			return err
		}
	}

	return nil
}

func (c *Compiler) RecursiveClean(path string, tName string) error {
	// Find all the subdirectories of path that contain an "obj/" directory, and
	// remove that directory either altogether, or just the arch specific directory.
	dirList, err := ioutil.ReadDir(path)
	if err != nil {
		return NewStackError(err.Error())
	}

	for _, node := range dirList {
		if node.IsDir() {
			if node.Name() == "obj" || node.Name() == "bin" {
				if tName == "" {
					os.RemoveAll(path + "/" + node.Name() + "/")
				} else {
					os.RemoveAll(path + "/" + node.Name() + "/" + tName + "/")
				}
			} else {
				// recurse into the directory.
				err = c.RecursiveClean(path+"/"+node.Name(), tName)
				if err != nil {
					return err
				}
			}
		}
	}

	return nil
}

func (c *Compiler) processEntry(wd string, node os.FileInfo, match string, cType int,
	ignDirs []string) error {
	// check to see if we ignore this element
	for _, entry := range ignDirs {
		if entry == node.Name() {
			return nil
		}
	}

	// if not, recurse into the directory
	os.Chdir(wd + "/" + node.Name())
	return c.RecursiveCompile(match, cType, ignDirs)
}

func (c *Compiler) RecursiveCompile(match string, cType int, ignDirs []string) error {
	// Get a list of files in the current directory, and if they are a directory,
	// and that directory is not in the ignDirs variable, then recurse into that
	// directory and compile the files in there
	wd, err := os.Getwd()
	if err != nil {
		return NewStackError(err.Error())
	}

	dirList, err := ioutil.ReadDir(wd)
	if err != nil {
		return NewStackError(err.Error())
	}

	for _, node := range dirList {
		if node.IsDir() {
			err = c.processEntry(wd, node, match, cType, ignDirs)
			if err != nil {
				return err
			}
		}
	}

	os.Chdir(wd)

	switch cType {
	case 0:
		return c.Compile(match)
	case 1:
		return c.CompileAs(match)
	default:
		return NewStackError("Wrong compiler type specified to RecursiveCompile")
	}
}

func (c *Compiler) getObjFiles(baseObjFiles string) string {
	objList := baseObjFiles
	for objName, _ := range c.ObjPathList {
		objList += " " + objName
	}
	return objList
}

func (c *Compiler) CompileBinary(binFile string, options map[string]bool,
	objFiles string) error {
	objList := c.getObjFiles(objFiles)

	log.Printf("[INFO] Compiling Binary %s with object files %s", binFile,
		objList)

	cmd := c.ccPath + " -o " + binFile + " " + c.ldFlags + " " + c.Cflags
	if c.ldResolveCircularDeps {
		cmd += " -Wl,--start-group -lc " + objList + " -Wl,--end-group "
	} else {
		cmd += " " + objList
	}

	if c.LinkerScript != "" {
		cmd += " -T " + c.LinkerScript
	}
	if checkBoolMap(options, "mapFile") {
		cmd += " -Wl,-Map=" + binFile + ".map"
	}

	_, err := ShellCommand(cmd)
	if err != nil {
		return err
	}

	if checkBoolMap(options, "listFile") {
		listFile := binFile + ".lst"
		// if list file exists, remove it
		if NodeExist(listFile) {
			if err := os.RemoveAll(listFile); err != nil {
				return err
			}
		}

		cmd = c.odPath + " -wxdS " + binFile + " >> " + listFile
		_, err := ShellCommand(cmd)
		if err != nil {
			return err
		}

		sects := []string{".text", ".rodata", ".data"}
		for _, sect := range sects {
			cmd = c.odPath + " -s -j " + sect + " " + binFile + " >> " + listFile
			ShellCommand(cmd)
		}

		cmd = c.osPath + " " + binFile + " >> " + listFile
	}

	return nil

}

func (c *Compiler) CompileElf(binFile string, options map[string]bool,
	objFiles string) error {
	binFile += ".elf"
	return c.CompileBinary(binFile, options, objFiles)
}

func (c *Compiler) CompileArchive(archiveFile string, objFiles string) error {
	objList := c.getObjFiles(objFiles)

	log.Printf("[INFO] Compiling archive %s with object files %s",
		archiveFile, objList)

	cmd := c.arPath + " rcs " + archiveFile + " " + objList

	_, err := ShellCommand(cmd)
	return err
}
<|endoftext|>


<commit_before>package main

import (
  "log"
  "github.com/gorilla/mux"
  "net/http"
  "net/http/httputil"
  "net/url"
  "github.com/fhs/gompd/mpd"
  "github.com/ascherkus/go-id3/src/id3"
  "os"
  "fmt"
  "encoding/json"
)

// TODO: consider if global is really the best idea, or if we should
//       make some classes, or something...
var mpd_conn *mpd.Client

func main() {
  //mpdConnect("localhost:6600")
  conn, err := mpd.Dial("tcp", "localhost:6600")

  // if we can't connect to MPD everything's fucked, nothing's going to work
  // kill all humans, and die, respectfully, after explaining what the issue
  // is.
  if err != nil {
    log.Println("\n\nServer quiting because it can't connect to MPD");
    log.Fatal(err)
    return
  }
  defer conn.Close()

  // set global mpd_conn to our new connection.
  mpd_conn = conn

  // create a new mux router for our server.
  r := mux.NewRouter()

  // requests to `/stream` are proxied to the MPD httpd.
  r.HandleFunc("/stream",
    httputil.NewSingleHostReverseProxy(
      &url.URL{
        Scheme:"http",
        Host: "localhost:8000",
        Path: "/",
      }).ServeHTTP)

  r.HandleFunc("/songs", listSongs)
  r.HandleFunc("/current", getCurrentSong)

  // This MUST go last! It takes precidence over any after it, meaning
  // the server will try to serve a file, which most likely doesn't exist,
  // and will 404.
  //
  // serve up the frontend files.
  r.PathPrefix("/").Handler(http.FileServer(http.Dir("../frontend/turbo_wookie/web")))

  // sit, waiting, like a hunter, spying on its prey.
  log.Println("Starting server on port 9000")
  http.ListenAndServe(":9000", r)
}

/********************
  Handler Functions
 ********************/

// return all songs known to MPD to the client.
func listSongs(w http.ResponseWriter, r *http.Request) {
  // get all files from MPD
  mpdfiles, err := mpd_conn.GetFiles()
  if err != nil {
    log.Println("Couldn't get a list of files...")
    log.Fatal(err)
  }

  // create a slice of id3.File s
  files := make([]*id3.File, 0)

  for _, song := range mpdfiles {
    // grab the file on the filesystem
    file, err := os.Open("mpd/music/" + song)
    if err != nil {
      log.Println("Couldn't open file: " + song)
      log.Fatal(err)
    }

    // add the current file to our slice
    id3_file := id3.Read(file)
    files = append(files, id3_file)
  }

  // send the json to the client.
  fmt.Fprintf(w, jsoniffy(files))
}

// Return a JSON representation of the currently playing song.
func getCurrentSong(w http.ResponseWriter, r *http.Request) {
  currentSong, err := mpd_conn.CurrentSong()
  if err != nil {
    log.Println("Couldn't get current song info")
    log.Fatal(err)
  }

  fmt.Fprintf(w, jsoniffy(currentSong))
}

/*******************
  Helper Functions
 *******************/

// Connect to MPD's control channel, and set the global mpd_conn to it.
func mpdConnect(url string) {
  conn, err := mpd.Dial("tcp", url)

  // if we can't connect to MPD everything's fucked, nothing's going to work
  // kill all humans, and die, respectfully, after explaining what the issue
  // is.
  if err != nil {
    log.Println("\n\nServer quiting because it can't connect to MPD");
    log.Fatal(err)
    return
  }
  defer conn.Close()

  // set global mpd_conn to our new connection.
  mpd_conn = conn
}

// turn anything into JSON.
func jsoniffy(v interface {}) string {
  obj, err := json.MarshalIndent(v, "", "  ")
  if err != nil {
    log.Print("Couldn't turn something into JSON: ", v)
    log.Fatal(err)
  }

  return string(obj)
}<commit_msg>mpd_conn thing fixed, fo' reals<commit_after>package main

import (
  "log"
  "github.com/gorilla/mux"
  "net/http"
  "net/http/httputil"
  "net/url"
  "github.com/fhs/gompd/mpd"
  "github.com/ascherkus/go-id3/src/id3"
  "os"
  "fmt"
  "encoding/json"
)

// TODO: consider if global is really the best idea, or if we should
//       make some classes, or something...
var mpd_conn *mpd.Client

func main() {
  mpd_conn = mpdConnect("localhost:6600")
  defer mpd_conn.Close()

  //log.Println(mpd_conn)
  if mpd_conn == nil {
    log.Fatal("MPD Connection is nil!")
  }

  // create a new mux router for our server.
  r := mux.NewRouter()

  // requests to `/stream` are proxied to the MPD httpd.
  r.HandleFunc("/stream",
    httputil.NewSingleHostReverseProxy(
      &url.URL{
        Scheme:"http",
        Host: "localhost:8000",
        Path: "/",
      }).ServeHTTP)

  r.HandleFunc("/songs", listSongs)
  r.HandleFunc("/current", getCurrentSong)

  // This MUST go last! It takes precidence over any after it, meaning
  // the server will try to serve a file, which most likely doesn't exist,
  // and will 404.
  //
  // serve up the frontend files.
  r.PathPrefix("/").Handler(http.FileServer(http.Dir("../frontend/turbo_wookie/web")))

  // sit, waiting, like a hunter, spying on its prey.
  log.Println("Starting server on port 9000")
  http.ListenAndServe(":9000", r)
}

/********************
  Handler Functions
 ********************/

// return all songs known to MPD to the client.
func listSongs(w http.ResponseWriter, r *http.Request) {
  // get all files from MPD
  mpdfiles, err := mpd_conn.GetFiles()
  if err != nil {
    log.Println("Couldn't get a list of files...")
    log.Fatal(err)
  }

  // create a slice of id3.File s
  files := make([]*id3.File, 0)

  for _, song := range mpdfiles {
    // grab the file on the filesystem
    file, err := os.Open("mpd/music/" + song)
    if err != nil {
      log.Println("Couldn't open file: " + song)
      log.Fatal(err)
    }

    // add the current file to our slice
    id3_file := id3.Read(file)
    files = append(files, id3_file)
  }

  // send the json to the client.
  fmt.Fprintf(w, jsoniffy(files))
}

// Return a JSON representation of the currently playing song.
func getCurrentSong(w http.ResponseWriter, r *http.Request) {
  currentSong, err := mpd_conn.CurrentSong()
  if err != nil {
    log.Println("Couldn't get current song info")
    log.Fatal(err)
  }

  fmt.Fprintf(w, jsoniffy(currentSong))
}

/*******************
  Helper Functions
 *******************/

// Connect to MPD's control channel, and set the global mpd_conn to it.
func mpdConnect(url string) *mpd.Client {
  conn, err := mpd.Dial("tcp", url)

  // if we can't connect to MPD everything's fucked, nothing's going to work
  // kill all humans, and die, respectfully, after explaining what the issue
  // is.
  if err != nil {
    log.Println("\n\nServer quiting because it can't connect to MPD");
    log.Println(err)

    conn.Close()
    return nil
  }
  //defer conn.Close()

  // set global mpd_conn to our new connection.
  return conn
}

// turn anything into JSON.
func jsoniffy(v interface {}) string {
  obj, err := json.MarshalIndent(v, "", "  ")
  if err != nil {
    log.Print("Couldn't turn something into JSON: ", v)
    log.Fatal(err)
  }

  return string(obj)
}<|endoftext|>


<commit_before>package github

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

type PullRequest struct {
	Body   string `json:"body"`
	State  string `json:"state"`
	Title  string `json:"title"`
	Number int    `json:"number"`
	Head   GitRef `json:"head"`
	Base   GitRef `json:"base"`
}

// PostComment posts a new comment on pull request via GitHub API
func (pr PullRequest) PostComment(msg string) (Comment, error) {
	log.Println("github.pr.comments.create.started")

	var err error
	var comment Comment

	createCommentPath := fmt.Sprintf("/repos/%s/issues/%d/comments", pr.Base.Repository.FullName, pr.Number)
	requestBodyAsBytes := []byte(fmt.Sprintf(`{"body":"%s"}`, msg))
	requestBody := ioutil.NopCloser(bytes.NewReader(requestBodyAsBytes))

	request := NewGitHubRequest(createCommentPath)
	request.Method = "POST"
	request.Header.Set("ContentLength", string(len(requestBodyAsBytes)))
	request.Body = requestBody
	response, err := httpClient.Do(request)
	defer response.Body.Close()

	var responseBodyAsBytes []byte

	if err != nil {
		log.Println("github.pr.comments.create.failed error:", err.Error())
		return comment, err
	}

	responseBodyAsBytes, err = ioutil.ReadAll(response.Body)
	if err != nil {
		log.Println("github.pr.comments.create.failed error:", err)
		return comment, err
	}

	if response.StatusCode != http.StatusCreated {
		apiError := new(Error)
		json.Unmarshal(responseBodyAsBytes, apiError)
		log.Printf("github.pr.comments.create.failed status: %d, msg: %s \n", response.StatusCode, apiError.Message)
		return comment, err
	}

	json.Unmarshal(responseBodyAsBytes, &comment)

	log.Println("github.pr.comments.create.completed number:", pr.Number)
	return comment, nil
}
<commit_msg>Don't always close the response body<commit_after>package github

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

type PullRequest struct {
	Body   string `json:"body"`
	State  string `json:"state"`
	Title  string `json:"title"`
	Number int    `json:"number"`
	Head   GitRef `json:"head"`
	Base   GitRef `json:"base"`
}

// PostComment posts a new comment on pull request via GitHub API
func (pr PullRequest) PostComment(msg string) (Comment, error) {
	log.Println("github.pr.comments.create.started")

	var err error
	var comment Comment

	createCommentPath := fmt.Sprintf("/repos/%s/issues/%d/comments", pr.Base.Repository.FullName, pr.Number)
	requestBodyAsBytes := []byte(fmt.Sprintf(`{"body":"%s"}`, msg))
	requestBody := ioutil.NopCloser(bytes.NewReader(requestBodyAsBytes))

	request := NewGitHubRequest(createCommentPath)
	request.Method = "POST"
	request.Header.Set("ContentLength", string(len(requestBodyAsBytes)))
	request.Body = requestBody
	response, err := httpClient.Do(request)

	var responseBodyAsBytes []byte

	if err != nil {
		log.Println("github.pr.comments.create.failed error:", err.Error())
		return comment, err
	}

	defer response.Body.Close()

	responseBodyAsBytes, err = ioutil.ReadAll(response.Body)
	if err != nil {
		log.Println("github.pr.comments.create.failed error:", err)
		return comment, err
	}

	if response.StatusCode != http.StatusCreated {
		apiError := new(Error)
		json.Unmarshal(responseBodyAsBytes, apiError)
		log.Printf("github.pr.comments.create.failed status: %d, msg: %s \n", response.StatusCode, apiError.Message)
		return comment, err
	}

	json.Unmarshal(responseBodyAsBytes, &comment)

	log.Println("github.pr.comments.create.completed number:", pr.Number)
	return comment, nil
}
<|endoftext|>


<commit_before>package coolmaze

import (
	"fmt"
	"net/http"
)

func init() {
	//
	// Wake Up is a sort of manual (explicit) warmup request.
	// It should be triggered by all clients at startup (browser, mobile device) to
	// make sure the subsequent request won't face a cold start (Loading request).
	// See also https://cloud.google.com/appengine/docs/go/warmup-requests/
	//
	http.HandleFunc("/wakeup",
		func(w http.ResponseWriter, r *http.Request) {
			fmt.Fprintln(w, "ok")
			// Instance should be warm by now
		})
}
<commit_msg>Access-Control-Allow-Origin for /wakeup.<commit_after>package coolmaze

import (
	"fmt"
	"net/http"
)

func init() {
	//
	// Wake Up is a sort of manual (explicit) warmup request.
	// It should be triggered by all clients at startup (browser, mobile device) to
	// make sure the subsequent request won't face a cold start (Loading request).
	// See also https://cloud.google.com/appengine/docs/go/warmup-requests/
	//
	http.HandleFunc("/wakeup",
		func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("Access-Control-Allow-Origin", "*")
			fmt.Fprintln(w, "ok")
			// Instance should be warm by now
		})
}
<|endoftext|>


<commit_before>package applications

import (
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

func schemaOptionalClaims() *schema.Schema {
	return &schema.Schema{
		Type:     schema.TypeList,
		Optional: true,
		Elem: &schema.Resource{
			Schema: map[string]*schema.Schema{
				"name": {
					Description: "The name of the optional claim",
					Type:        schema.TypeString,
					Required:    true,
				},

				"source": {
					Description: "The source of the claim. If `source` is absent, the claim is a predefined optional claim. If `source` is `user`, the value of `name` is the extension property from the user object",
					Type:        schema.TypeString,
					Optional:    true,
					ValidateFunc: validation.StringInSlice(
						[]string{"user"},
						false,
					),
				},

				"essential": {
					Description: "Whether the claim specified by the client is necessary to ensure a smooth authorization experience",
					Type:        schema.TypeBool,
					Optional:    true,
					Default:     false,
				},

				"additional_properties": {
					Description: "List of additional properties of the claim. If a property exists in this list, it modifies the behaviour of the optional claim",
					Type:        schema.TypeList,
					Optional:    true,
					Elem: &schema.Schema{
						Type: schema.TypeString,
						ValidateFunc: validation.StringInSlice(
							[]string{
								"dns_domain_and_sam_account_name",
								"emit_as_roles",
								"include_externally_authenticated_upn",
								"include_externally_authenticated_upn_without_hash",
								"netbios_domain_and_sam_account_name",
								"on_premise_security_identifier",
								"sam_account_name",
								"use_guid",
							},
							false,
						),
					},
				},
			},
		},
	}
}
<commit_msg>Add Support for optional additional property (#864)<commit_after>package applications

import (
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

func schemaOptionalClaims() *schema.Schema {
	return &schema.Schema{
		Type:     schema.TypeList,
		Optional: true,
		Elem: &schema.Resource{
			Schema: map[string]*schema.Schema{
				"name": {
					Description: "The name of the optional claim",
					Type:        schema.TypeString,
					Required:    true,
				},

				"source": {
					Description: "The source of the claim. If `source` is absent, the claim is a predefined optional claim. If `source` is `user`, the value of `name` is the extension property from the user object",
					Type:        schema.TypeString,
					Optional:    true,
					ValidateFunc: validation.StringInSlice(
						[]string{"user"},
						false,
					),
				},

				"essential": {
					Description: "Whether the claim specified by the client is necessary to ensure a smooth authorization experience",
					Type:        schema.TypeBool,
					Optional:    true,
					Default:     false,
				},

				"additional_properties": {
					Description: "List of additional properties of the claim. If a property exists in this list, it modifies the behaviour of the optional claim",
					Type:        schema.TypeList,
					Optional:    true,
					Elem: &schema.Schema{
						Type: schema.TypeString,
						ValidateFunc: validation.StringInSlice(
							[]string{
								"dns_domain_and_sam_account_name",
								"emit_as_roles",
								"include_externally_authenticated_upn",
								"include_externally_authenticated_upn_without_hash",
								"max_size_limit",
								"netbios_domain_and_sam_account_name",
								"on_premise_security_identifier",
								"sam_account_name",
								"use_guid",
							},
							false,
						),
					},
				},
			},
		},
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 Mathias Monnerville. All rights reserved.
// Use of this source code is governed by a GPL
// license that can be found in the LICENSE file.

package mango

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"
)

// AuthMode defines authentication methods for communicating with
// the service.
type AuthMode int

const (
	// Basic Access Authentication
	BasicAuth AuthMode = iota
	// OAuth 2.0, token based authentication
	OAuth
)

// Holds OAuth2.0 token info.
type oAuth2 struct {
	Token     string `json:"access_token"`
	Type      string `json:"token_type"`
	ExpiresIn int64  `json:"expires_in"`
	created   int64
}

func newToken(m *MangoPay) (*oAuth2, error) {
	if m == nil {
		return nil, errors.New("newToken: nil service")
	}

	gentoken := func(m *MangoPay) (*oAuth2, error) {
		// Let's get a new access token
		auth := basicAuthorization(m.clientId, m.password)
		u, err := url.Parse(rootURLs[m.env] + "oauth/token")
		if err != nil {
			return nil, err
		}

		body := "grant_type=client_credentials"
		req, err := http.NewRequest("POST", u.String(), strings.NewReader(body))
		if err != nil {
			return nil, err
		}
		req.Header.Set("Authorization", auth)
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
		resp, err := http.DefaultClient.Do(req)
		b, err := ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		if err != nil {
			return nil, err
		}
		access := new(oAuth2)
		if err := json.Unmarshal(b, access); err != nil {
			return nil, err
		}
		access.created = time.Now().Unix()
		// Now we can track the token during its lifetime
		m.oauth = access
		return access, nil
	}

	if m.oauth != nil {
		if time.Now().Unix()-m.oauth.created < m.oauth.ExpiresIn-60 {
			return m.oauth, nil // Reuse token
		}
	}
	access, err := gentoken(m)
	return access, err
}

// Returns authorization string for basic auth.
func basicAuthorization(clientId, passwd string) string {
	credential := clientId + ":" + passwd
	return "Basic " + base64.StdEncoding.EncodeToString([]byte(credential))
}

// Returns authorization string for OAuth2.0 auth.
func oAuthAuthorization(m *MangoPay) (string, error) {
	if m == nil {
		return "", errors.New("oAuth2.0: nil service")
	}
	o, err := newToken(m)
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("%s %s", o.Type, o.Token), nil
}

// Config hold environment credentials required for using the API.
//
// See http://docs.mangopay.com/api-references/sandbox-credentials/
type Config struct {
	ClientId   string
	Name       string
	Email      string
	Passphrase string
	Env        string
	env        ExecEnvironment
}

func (c *Config) String() string {
	return struct2string(c)
}

// NewConfig creates a config suitable for NewMangoPay().
func NewConfig(clientId, name, email, passwd, env string) (*Config, error) {
	c := &Config{ClientId: clientId, Name: name, Email: email, Passphrase: passwd, Env: env}
	if env == "sandbox" {
		c.env = Sandbox
	} else if env == "production" {
		c.env = Production
	} else {
		return nil, errors.New(fmt.Sprintf("unknown exec environment '%s'. "+
			"Must be one of production or sandbox.", env))
	}
	return c, nil
}

// RegisterClient asks MangoPay to create a new client account.
func RegisterClient(clientId, name, email string, env ExecEnvironment) (*Config, error) {
	c := &Config{ClientId: clientId, Name: name, Email: email}
	body, err := json.Marshal(c)
	if err != nil {
		return nil, err
	}
	u, err := url.Parse(fmt.Sprintf("%sclients/", rootURLs[env]))
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest("POST", u.String(), strings.NewReader(string(body)))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/json")
	resp, err := http.DefaultClient.Do(req)
	b, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return nil, err
	}
	if err := json.Unmarshal(b, c); err != nil {
		return nil, err
	}
	if env == Sandbox {
		c.Env = "sandbox"
	} else {
		c.Env = "production"
	}
	c.env = env
	return c, nil
}
<commit_msg>More error catching<commit_after>// Copyright 2014 Mathias Monnerville. All rights reserved.
// Use of this source code is governed by a GPL
// license that can be found in the LICENSE file.

package mango

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"
)

// AuthMode defines authentication methods for communicating with
// the service.
type AuthMode int

const (
	// Basic Access Authentication
	BasicAuth AuthMode = iota
	// OAuth 2.0, token based authentication
	OAuth
)

// Holds OAuth2.0 token info.
type oAuth2 struct {
	Token     string `json:"access_token"`
	Type      string `json:"token_type"`
	ExpiresIn int64  `json:"expires_in"`
	created   int64
}

func newToken(m *MangoPay) (*oAuth2, error) {
	if m == nil {
		return nil, errors.New("newToken: nil service")
	}

	gentoken := func(m *MangoPay) (*oAuth2, error) {
		// Let's get a new access token
		auth := basicAuthorization(m.clientId, m.password)
		u, err := url.Parse(rootURLs[m.env] + "oauth/token")
		if err != nil {
			return nil, err
		}

		body := "grant_type=client_credentials"
		req, err := http.NewRequest("POST", u.String(), strings.NewReader(body))
		if err != nil {
			return nil, err
		}
		req.Header.Set("Authorization", auth)
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
		resp, err := http.DefaultClient.Do(req)
		if err != nil {
			return nil, err
		}
		b, err := ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		if err != nil {
			return nil, err
		}
		access := new(oAuth2)
		if err := json.Unmarshal(b, access); err != nil {
			return nil, err
		}
		access.created = time.Now().Unix()
		// Now we can track the token during its lifetime
		m.oauth = access
		return access, nil
	}

	if m.oauth != nil {
		if time.Now().Unix()-m.oauth.created < m.oauth.ExpiresIn-60 {
			return m.oauth, nil // Reuse token
		}
	}
	access, err := gentoken(m)
	return access, err
}

// Returns authorization string for basic auth.
func basicAuthorization(clientId, passwd string) string {
	credential := clientId + ":" + passwd
	return "Basic " + base64.StdEncoding.EncodeToString([]byte(credential))
}

// Returns authorization string for OAuth2.0 auth.
func oAuthAuthorization(m *MangoPay) (string, error) {
	if m == nil {
		return "", errors.New("oAuth2.0: nil service")
	}
	o, err := newToken(m)
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("%s %s", o.Type, o.Token), nil
}

// Config hold environment credentials required for using the API.
//
// See http://docs.mangopay.com/api-references/sandbox-credentials/
type Config struct {
	ClientId   string
	Name       string
	Email      string
	Passphrase string
	Env        string
	env        ExecEnvironment
}

func (c *Config) String() string {
	return struct2string(c)
}

// NewConfig creates a config suitable for NewMangoPay().
func NewConfig(clientId, name, email, passwd, env string) (*Config, error) {
	c := &Config{ClientId: clientId, Name: name, Email: email, Passphrase: passwd, Env: env}
	if env == "sandbox" {
		c.env = Sandbox
	} else if env == "production" {
		c.env = Production
	} else {
		return nil, errors.New(fmt.Sprintf("unknown exec environment '%s'. "+
			"Must be one of production or sandbox.", env))
	}
	return c, nil
}

// RegisterClient asks MangoPay to create a new client account.
func RegisterClient(clientId, name, email string, env ExecEnvironment) (*Config, error) {
	c := &Config{ClientId: clientId, Name: name, Email: email}
	body, err := json.Marshal(c)
	if err != nil {
		return nil, err
	}
	u, err := url.Parse(fmt.Sprintf("%sclients/", rootURLs[env]))
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest("POST", u.String(), strings.NewReader(string(body)))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/json")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, err
	}
	b, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return nil, err
	}
	if err := json.Unmarshal(b, c); err != nil {
		return nil, err
	}
	if env == Sandbox {
		c.Env = "sandbox"
	} else {
		c.Env = "production"
	}
	c.env = env
	return c, nil
}
<|endoftext|>