<commit_before>package main

import (
	"fmt"
	"errors"
	"bytes"
	"io/ioutil"
	"bufio"
	"os"
	"strings"
	"regexp"
	flags "github.com/jessevdk/go-flags"
)

const (
	Author  = "webdevops.io"
	Version = "1.0"
)

var opts struct {
	Search            string   `short:"s"  long:"search"       required:"true"  description:"search term"`
	SearchRegex       *regexp.Regexp
	Replace           string   `short:"r"  long:"replace"      required:"true"  description:"replacement term" `
	IgnoreCase        bool     `short:"i"  long:"ignore-case"                   description:"ignore pattern case"`
	WholeLine         bool     `           long:"whole-line"                    description:"replace whole line"`
	Regex             bool     `           long:"regex"                         description:"treat pattern as regex"`
	Verbose           bool     `short:"v"  long:"verbose"                       description:"verbose mode"`
	DryRun            bool     `           long:"dry-run"                       description:"dry run mode"`
	ShowVersion       bool     `short:"V"  long:"version"                       description:"show version and exit"`
	ShowHelp          bool     `short:"h"  long:"help"                          description:"show this help message"`
}

// Replace content parts in file
func replaceContentInFile(filepath string) {
	var err error

    read, err := ioutil.ReadFile(filepath)
    if err != nil {
        panic(err)
    }

    content, replaceStatus := replaceText(string(read))

    if replaceStatus {
        writeContentToFile(filepath, content)
    } else {
        logMessage(fmt.Sprintf("%s no match", filepath))
    }

}

// Replace line (if match is found) in file
func replaceLineInFile(filepath string) {
    file, err := os.Open(filepath)
    if err != nil {
        panic(err)
    }

    replaceStatus := false
    var buffer bytes.Buffer

    r := bufio.NewReader(file)
    line, e := Readln(r)
    for e == nil {
        if searchMatch(line) {
            buffer.WriteString(opts.Replace + "\n")
            replaceStatus = true
        } else {
            buffer.WriteString(line + "\n")
        }

        line, e = Readln(r)
    }

    if replaceStatus {
        writeContentToFile(filepath, buffer.String())
    } else {
        logMessage(fmt.Sprintf("%s no match", filepath))
    }
}

// Readln returns a single line (without the ending \n)
// from the input buffered reader.
// An error is returned iff there is an error with the
// buffered reader.
func Readln(r *bufio.Reader) (string, error) {
  var (isPrefix bool = true
       err error = nil
       line, ln []byte
      )
  for isPrefix && err == nil {
      line, isPrefix, err = r.ReadLine()
      ln = append(ln, line...)
  }
  return string(ln),err
}

// Checks if there is a match in content, based on search options
func searchMatch(content string) (bool) {
    if opts.Regex {
        if opts.SearchRegex.MatchString(content) {
            return true
        }
    } else {
        if strings.Contains(content, opts.Search) {
            return true
        }
    }

    return false
}

// Replace text in whole content based on search options
func replaceText(content string) (string, bool) {
    status := false

    if searchMatch(content) {
        status = true

        if opts.Regex {
            content = opts.SearchRegex.ReplaceAllString(content, opts.Replace)
        } else {
            content = strings.Replace(content, opts.Search, opts.Replace, -1)
        }
    }

    return content, status
}

// Write content to file
func writeContentToFile(filepath string, content string) {
    if opts.DryRun {
        title := fmt.Sprintf("%s:", filepath)

        fmt.Println(title)
        fmt.Println(strings.Repeat("-", len(title)))
        fmt.Println(content)
        fmt.Println()
        fmt.Println()
    } else {
        var err error
        err = ioutil.WriteFile(filepath, []byte(content), 0)
        if err != nil {
            panic(err)
        }
    }
}

// Log message
func logMessage(message string) {
    if opts.Verbose {
        fmt.Println(message)
    }
}

func logError(err error) {
    fmt.Printf("Error: %s\n", err)
}

// Process search option
// Compiles regexp if regexp is used
func processSearch() {
    if opts.Regex {
        regex := opts.Search

        if opts.IgnoreCase {
            regex = "(?i:" + regex + ")"
        }

        opts.SearchRegex = regexp.MustCompile(regex)
    }
}

func handleSpecialOptions(argparser *flags.Parser, args []string) {
    if (opts.ShowVersion) {
        fmt.Printf("goreplace %s\n", Version)
        os.Exit(0)
    }

    if (opts.ShowHelp) {
		argparser.WriteHelp(os.Stdout)
		os.Exit(1)
	}

	if (len(args) == 0) {
	    err := errors.New("No files specified")
	    logError(err)
	    fmt.Println()
		argparser.WriteHelp(os.Stdout)
		os.Exit(1)
	}
}

func main() {
    var argparser = flags.NewParser(&opts, flags.PassDoubleDash)
	args, err := argparser.Parse()

    if err != nil {
        handleSpecialOptions(argparser, args)

        logError(err)
        fmt.Println()
        argparser.WriteHelp(os.Stdout)
        os.Exit(1)
    }

	handleSpecialOptions(argparser, args)

	processSearch()

    for i := range args {
        var file string
        file = args[i]

        if opts.WholeLine {
            replaceLineInFile(file)
        } else {
            replaceContentInFile(file)
        }
    }

    os.Exit(0)
}<commit_msg>Improved search and replace<commit_after>package main

import (
	"fmt"
	"errors"
	"bytes"
	"io/ioutil"
	"bufio"
	"os"
	"strings"
	"regexp"
	flags "github.com/jessevdk/go-flags"
)

const (
	Author  = "webdevops.io"
	Version = "1.0"
)

var opts struct {
	Search            string   `short:"s"  long:"search"       required:"true"  description:"search term"`
	SearchRegex       *regexp.Regexp
	Replace           string   `short:"r"  long:"replace"      required:"true"  description:"replacement term" `
	IgnoreCase        bool     `short:"i"  long:"ignore-case"                   description:"ignore pattern case"`
	WholeLine         bool     `           long:"whole-line"                    description:"replace whole line"`
	Regex             bool     `           long:"regex"                         description:"treat pattern as regex"`
	Verbose           bool     `short:"v"  long:"verbose"                       description:"verbose mode"`
	DryRun            bool     `           long:"dry-run"                       description:"dry run mode"`
	ShowVersion       bool     `short:"V"  long:"version"                       description:"show version and exit"`
	ShowHelp          bool     `short:"h"  long:"help"                          description:"show this help message"`
}

// Replace content parts in file
func replaceContentInFile(filepath string) {
	var err error

    read, err := ioutil.ReadFile(filepath)
    if err != nil {
        panic(err)
    }

    content, replaceStatus := replaceText(string(read))

    if replaceStatus {
        writeContentToFile(filepath, content)
    } else {
        logMessage(fmt.Sprintf("%s no match", filepath))
    }

}

// Replace line (if match is found) in file
func replaceLineInFile(filepath string) {
    file, err := os.Open(filepath)
    if err != nil {
        panic(err)
    }

    replaceStatus := false
    var buffer bytes.Buffer

    r := bufio.NewReader(file)
    line, e := Readln(r)
    for e == nil {
        if searchMatch(line) {
            buffer.WriteString(opts.Replace + "\n")
            replaceStatus = true
        } else {
            buffer.WriteString(line + "\n")
        }

        line, e = Readln(r)
    }

    if replaceStatus {
        writeContentToFile(filepath, buffer.String())
    } else {
        logMessage(fmt.Sprintf("%s no match", filepath))
    }
}

// Readln returns a single line (without the ending \n)
// from the input buffered reader.
// An error is returned iff there is an error with the
// buffered reader.
func Readln(r *bufio.Reader) (string, error) {
  var (isPrefix bool = true
       err error = nil
       line, ln []byte
      )
  for isPrefix && err == nil {
      line, isPrefix, err = r.ReadLine()
      ln = append(ln, line...)
  }
  return string(ln),err
}

// Checks if there is a match in content, based on search options
func searchMatch(content string) (bool) {
    if opts.SearchRegex.MatchString(content) {
        return true
    }

    return false
}

// Replace text in whole content based on search options
func replaceText(content string) (string, bool) {
    status := false

    if searchMatch(content) {
        status = true
        content = opts.SearchRegex.ReplaceAllString(content, opts.Replace)
    }

    return content, status
}

// Write content to file
func writeContentToFile(filepath string, content string) {
    if opts.DryRun {
        title := fmt.Sprintf("%s:", filepath)

        fmt.Println(title)
        fmt.Println(strings.Repeat("-", len(title)))
        fmt.Println(content)
        fmt.Println()
        fmt.Println()
    } else {
        var err error
        err = ioutil.WriteFile(filepath, []byte(content), 0)
        if err != nil {
            panic(err)
        }

        logMessage(fmt.Sprintf("%s found and replaced match", filepath))
    }
}

// Log message
func logMessage(message string) {
    if opts.Verbose {
        fmt.Println(message)
    }
}

func logError(err error) {
    fmt.Printf("Error: %s\n", err)
}

// Process search term
// Compiles regexp if regexp is used
func processSearchTerm() {
    var regex string

    if opts.Regex {
        regex = opts.Search
    } else {
        regex = regexp.QuoteMeta(opts.Search)
    }

    if opts.IgnoreCase {
        regex = "(?i:" + regex + ")"
    }

    if opts.Verbose {
        logMessage(fmt.Sprintf("Using regular expression: %s", regex))
    }

    opts.SearchRegex = regexp.MustCompile(regex)
}

func handleSpecialOptions(argparser *flags.Parser, args []string) {
    if (opts.ShowVersion) {
        fmt.Printf("goreplace %s\n", Version)
        os.Exit(0)
    }

    if (opts.ShowHelp) {
		argparser.WriteHelp(os.Stdout)
		os.Exit(1)
	}

	if (len(args) == 0) {
	    err := errors.New("No files specified")
	    logError(err)
	    fmt.Println()
		argparser.WriteHelp(os.Stdout)
		os.Exit(1)
	}
}

func main() {
    var argparser = flags.NewParser(&opts, flags.PassDoubleDash)
	args, err := argparser.Parse()

    if err != nil {
        handleSpecialOptions(argparser, args)

        logError(err)
        fmt.Println()
        argparser.WriteHelp(os.Stdout)
        os.Exit(1)
    }

	handleSpecialOptions(argparser, args)

	processSearchTerm()

    for i := range args {
        var file string
        file = args[i]

        if opts.WholeLine {
            replaceLineInFile(file)
        } else {
            replaceContentInFile(file)
        }
    }

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


<commit_before>package main

import (
	"fmt"
	"github.com/RyanCarrier/dijkstra"
	"github.com/jyggen/advent-of-go/internal/solver"
	"github.com/jyggen/advent-of-go/internal/utils"
	"os"
	"strconv"
)

func main() {
	p1, p2, err := solver.SolveFromFile(os.Stdin, SolvePart1, SolvePart2)
	if err != nil {
		panic(err)
	}

	fmt.Println(p1)
	fmt.Println(p2)
}

func createGridAndGraph(input string, multiplier int) *dijkstra.Graph {
	rows := utils.ToStringSlice(input, "\n")
	colLength := len(rows[0])
	rowLength := len(rows)
	data := make([]int64, rowLength*multiplier*colLength*multiplier)
	graph := dijkstra.NewGraph()
	vertexId, aboveId, leftId := 0, 0-(colLength*multiplier), -1

	for j := 0; j < multiplier; j++ {
		for i, r := range rows {
			integers, _ := utils.ToIntegerSlice(r, "")

			for k := 0; k < multiplier; k++ {
				for l, v := range integers {
					value := int64(v + j + k)

					if value > 9 {
						value -= 9
					}

					data[vertexId] = value

					graph.AddVertex(vertexId)

					if i != 0 || (i == 0 && j != 0) {
						graph.AddArc(vertexId, aboveId, data[aboveId])
						graph.AddArc(aboveId, vertexId, value)
					}

					if l != 0 || (l == 0 && k != 0) {
						graph.AddArc(vertexId, leftId, data[leftId])
						graph.AddArc(leftId, vertexId, value)
					}

					vertexId, aboveId, leftId = vertexId+1, aboveId+1, leftId+1
				}
			}
		}
	}

	return graph
}

func SolvePart1(input string) (string, error) {
	graph := createGridAndGraph(input, 1)
	best, err := graph.Shortest(0, len(graph.Verticies)-1)

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

	return strconv.Itoa(int(best.Distance)), nil
}

func SolvePart2(input string) (string, error) {
	graph := createGridAndGraph(input, 5)
	best, err := graph.Shortest(0, len(graph.Verticies)-1)

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

	return strconv.Itoa(int(best.Distance)), nil
}
<commit_msg>refactor(2021.15): rename function<commit_after>package main

import (
	"fmt"
	"github.com/RyanCarrier/dijkstra"
	"github.com/jyggen/advent-of-go/internal/solver"
	"github.com/jyggen/advent-of-go/internal/utils"
	"os"
	"strconv"
)

func main() {
	p1, p2, err := solver.SolveFromFile(os.Stdin, SolvePart1, SolvePart2)
	if err != nil {
		panic(err)
	}

	fmt.Println(p1)
	fmt.Println(p2)
}

func createGraph(input string, multiplier int) *dijkstra.Graph {
	rows := utils.ToStringSlice(input, "\n")
	colLength := len(rows[0])
	rowLength := len(rows)
	data := make([]int64, rowLength*multiplier*colLength*multiplier)
	graph := dijkstra.NewGraph()
	vertexId, aboveId, leftId := 0, 0-(colLength*multiplier), -1

	for j := 0; j < multiplier; j++ {
		for i, r := range rows {
			integers, _ := utils.ToIntegerSlice(r, "")

			for k := 0; k < multiplier; k++ {
				for l, v := range integers {
					value := int64(v + j + k)

					if value > 9 {
						value -= 9
					}

					data[vertexId] = value

					graph.AddVertex(vertexId)

					if i != 0 || (i == 0 && j != 0) {
						graph.AddArc(vertexId, aboveId, data[aboveId])
						graph.AddArc(aboveId, vertexId, value)
					}

					if l != 0 || (l == 0 && k != 0) {
						graph.AddArc(vertexId, leftId, data[leftId])
						graph.AddArc(leftId, vertexId, value)
					}

					vertexId, aboveId, leftId = vertexId+1, aboveId+1, leftId+1
				}
			}
		}
	}

	return graph
}

func SolvePart1(input string) (string, error) {
	graph := createGraph(input, 1)
	best, err := graph.Shortest(0, len(graph.Verticies)-1)

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

	return strconv.Itoa(int(best.Distance)), nil
}

func SolvePart2(input string) (string, error) {
	graph := createGraph(input, 5)
	best, err := graph.Shortest(0, len(graph.Verticies)-1)

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

	return strconv.Itoa(int(best.Distance)), nil
}
<|endoftext|>


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

// Package grok provides helpers and tooling for reading, understanding and writing Serulian
// code.
package grok

import (
	"sync"

	"github.com/serulian/compiler/compilercommon"
	"github.com/serulian/compiler/compilerutil"
	"github.com/serulian/compiler/graphs/scopegraph"
	"github.com/serulian/compiler/packageloader"

	cmap "github.com/streamrail/concurrent-map"
)

// Groker defines a toolkit for providing IDE tooling for Serulian projects.
type Groker struct {
	// entrypoint is the entrypoint of the project being groked.
	entrypoint packageloader.Entrypoint

	// vcsDevelopmentDirectories defines the development directories (if any) to use.
	vcsDevelopmentDirectories []string

	// libraries holds the libraries to be imported.
	libraries []packageloader.Library

	// pathLoader is the path loader to use.
	pathLoader packageloader.PathLoader

	// scopePathMap, if not empty, indicates the paths that should be considered by the
	// compiler when scoping.
	scopePathMap map[compilercommon.InputSource]bool

	// currentHandle returns the currently cached handle, if any.
	currentHandle *Handle

	// buildingHandleCancel is the cancel function for the handle currently building, if any.
	buildingHandleCancel compilerutil.CancelFunction

	// buildHandleLock defines a lock around the cancelation of an existing handle build
	// and the start of a new one.
	buildHandleLock *sync.Mutex
}

// Config defines the config for creating a Grok.
type Config struct {
	// EntrypointPath is the path to the entrypoint of the project being groked.
	EntrypointPath string

	// VCSDevelopmentDirectories defines the development directories (if any) to use.
	VCSDevelopmentDirectories []string

	// Libraries holds the libraries to be imported.
	Libraries []packageloader.Library

	// PathLoader is the path loader to use.
	PathLoader packageloader.PathLoader

	// ScopePaths, if not empty, indicates the paths that should be considered by the
	// compiler when scoping.
	ScopePaths []compilercommon.InputSource
}

// NewGroker returns a new Groker for the given entrypoint file/directory path.
func NewGroker(entrypointPath string, vcsDevelopmentDirectories []string, libraries []packageloader.Library) *Groker {
	return NewGrokerWithConfig(Config{
		EntrypointPath:            entrypointPath,
		VCSDevelopmentDirectories: vcsDevelopmentDirectories,
		Libraries:                 libraries,
		PathLoader:                packageloader.LocalFilePathLoader{},
		ScopePaths:                []compilercommon.InputSource{},
	})
}

// NewGrokerWithConfig returns a new Groker with the given config.
func NewGrokerWithConfig(config Config) *Groker {
	scopePathMap := map[compilercommon.InputSource]bool{}
	for _, path := range config.ScopePaths {
		scopePathMap[path] = true
	}

	return &Groker{
		entrypoint:                packageloader.Entrypoint(config.EntrypointPath),
		vcsDevelopmentDirectories: config.VCSDevelopmentDirectories,
		libraries:                 config.Libraries,
		pathLoader:                config.PathLoader,
		scopePathMap:              scopePathMap,

		buildHandleLock: &sync.Mutex{},
	}
}

// HandleFreshnessOption defines the options around code freshness when retrieving a handle.
type HandleFreshnessOption int

const (
	// HandleMustBeFresh indicates that all code must be up-to-date before returning the handle.
	HandleMustBeFresh HandleFreshnessOption = iota

	// HandleAllowStale indicates that a stale cached handle can be returned.
	HandleAllowStale
)

// GetHandle returns a handle for querying the Grok toolkit.
func (g *Groker) GetHandle() (Handle, error) {
	return g.GetHandleWithOption(HandleMustBeFresh)
}

// GetHandleWithOption returns a handle for querying the Grok toolkit.
func (g *Groker) GetHandleWithOption(freshnessOption HandleFreshnessOption) (Handle, error) {
	// If there is a cached handle, return it if nothing has changed.
	// TODO: Support partial re-build here once supported by the rest of the pipeline.
	currentHandle := g.currentHandle
	if currentHandle != nil {
		handle := *currentHandle
		if freshnessOption == HandleAllowStale {
			return handle, nil
		}

		modified, err := handle.scopeResult.SourceTracker.ModifiedSourcePaths()
		if err == nil && len(modified) == 0 {
			return handle, nil
		}
	}

	handleResult := <-g.BuildHandle()
	return handleResult.Handle, handleResult.Error
}

// HandleResult is the result of a BuildHandle call.
type HandleResult struct {
	// Handle is the Grok handle constructed, if there was no error.
	Handle Handle

	// Error is the error that occurred, if any.
	Error error
}

// BuildHandle builds a new handle for this Grok. If an existing handle is being
// built, it will be canceled.
func (g *Groker) BuildHandle() chan HandleResult {
	resultChan := make(chan HandleResult, 1)

	g.buildHandleLock.Lock()

	// Cancel the exist handle construction.
	cancelationFunction := g.buildingHandleCancel
	if cancelationFunction != nil {
		cancelationFunction()
	}

	// Spin off construction of a new handle.
	internalChan, newCancelationFunction := g.startScope()
	g.buildingHandleCancel = newCancelationFunction

	g.buildHandleLock.Unlock()

	go func() {
		result := <-internalChan
		if result.err != nil {
			resultChan <- HandleResult{Handle{}, result.err}
			return
		}

		scopeResult := result.scopeResult
		if scopeResult.Graph == nil {
			resultChan <- HandleResult{Handle{}, result.err}
			return
		}

		newHandle := Handle{
			scopeResult:        scopeResult,
			structureFinder:    scopeResult.Graph.SourceGraph().NewSourceStructureFinder(),
			groker:             g,
			importInspectCache: cmap.New(),
			pathFiltersMap:     g.scopePathMap,
		}

		g.currentHandle = &newHandle
		resultChan <- HandleResult{newHandle, nil}
	}()

	return resultChan
}

type asyncResult struct {
	scopeResult scopegraph.Result
	err         error
}

// startScope causes the Groker to perform a full refresh of the source, starting at the
// root source file. Returns a channel that will be filled with the result, as well as a
// function for cancelation of the scoping.
func (g *Groker) startScope() (chan asyncResult, compilerutil.CancelFunction) {
	var scopeFilter scopegraph.ScopeFilter
	if len(g.scopePathMap) > 0 {
		scopeFilter = func(path compilercommon.InputSource) bool {
			return g.scopePathMap[path]
		}
	}

	config := scopegraph.Config{
		Entrypoint:                g.entrypoint,
		VCSDevelopmentDirectories: g.vcsDevelopmentDirectories,
		Libraries:                 g.libraries,
		Target:                    scopegraph.Tooling,
		PathLoader:                g.pathLoader,
		ScopeFilter:               scopeFilter,
	}

	configWithCancel, canceler := config.WithCancel()
	resultChan := make(chan asyncResult, 1)
	go func() {
		result, err := scopegraph.ParseAndBuildScopeGraphWithConfig(configWithCancel)
		resultChan <- asyncResult{result, err}
	}()

	return resultChan, canceler
}
<commit_msg>Fix bug in Grok cancelation that made it appear a valid handle was being returned<commit_after>// Copyright 2017 The Serulian Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package grok provides helpers and tooling for reading, understanding and writing Serulian
// code.
package grok

import (
	"fmt"
	"sync"

	"github.com/serulian/compiler/compilercommon"
	"github.com/serulian/compiler/compilerutil"
	"github.com/serulian/compiler/graphs/scopegraph"
	"github.com/serulian/compiler/packageloader"

	cmap "github.com/streamrail/concurrent-map"
)

// Groker defines a toolkit for providing IDE tooling for Serulian projects.
type Groker struct {
	// entrypoint is the entrypoint of the project being groked.
	entrypoint packageloader.Entrypoint

	// vcsDevelopmentDirectories defines the development directories (if any) to use.
	vcsDevelopmentDirectories []string

	// libraries holds the libraries to be imported.
	libraries []packageloader.Library

	// pathLoader is the path loader to use.
	pathLoader packageloader.PathLoader

	// scopePathMap, if not empty, indicates the paths that should be considered by the
	// compiler when scoping.
	scopePathMap map[compilercommon.InputSource]bool

	// currentHandle returns the currently cached handle, if any.
	currentHandle *Handle

	// buildingHandleCancel is the cancel function for the handle currently building, if any.
	buildingHandleCancel compilerutil.CancelFunction

	// buildHandleLock defines a lock around the cancelation of an existing handle build
	// and the start of a new one.
	buildHandleLock *sync.Mutex
}

// Config defines the config for creating a Grok.
type Config struct {
	// EntrypointPath is the path to the entrypoint of the project being groked.
	EntrypointPath string

	// VCSDevelopmentDirectories defines the development directories (if any) to use.
	VCSDevelopmentDirectories []string

	// Libraries holds the libraries to be imported.
	Libraries []packageloader.Library

	// PathLoader is the path loader to use.
	PathLoader packageloader.PathLoader

	// ScopePaths, if not empty, indicates the paths that should be considered by the
	// compiler when scoping.
	ScopePaths []compilercommon.InputSource
}

// NewGroker returns a new Groker for the given entrypoint file/directory path.
func NewGroker(entrypointPath string, vcsDevelopmentDirectories []string, libraries []packageloader.Library) *Groker {
	return NewGrokerWithConfig(Config{
		EntrypointPath:            entrypointPath,
		VCSDevelopmentDirectories: vcsDevelopmentDirectories,
		Libraries:                 libraries,
		PathLoader:                packageloader.LocalFilePathLoader{},
		ScopePaths:                []compilercommon.InputSource{},
	})
}

// NewGrokerWithConfig returns a new Groker with the given config.
func NewGrokerWithConfig(config Config) *Groker {
	scopePathMap := map[compilercommon.InputSource]bool{}
	for _, path := range config.ScopePaths {
		scopePathMap[path] = true
	}

	return &Groker{
		entrypoint:                packageloader.Entrypoint(config.EntrypointPath),
		vcsDevelopmentDirectories: config.VCSDevelopmentDirectories,
		libraries:                 config.Libraries,
		pathLoader:                config.PathLoader,
		scopePathMap:              scopePathMap,

		buildHandleLock: &sync.Mutex{},
	}
}

// HandleFreshnessOption defines the options around code freshness when retrieving a handle.
type HandleFreshnessOption int

const (
	// HandleMustBeFresh indicates that all code must be up-to-date before returning the handle.
	HandleMustBeFresh HandleFreshnessOption = iota

	// HandleAllowStale indicates that a stale cached handle can be returned.
	HandleAllowStale
)

// GetHandle returns a handle for querying the Grok toolkit.
func (g *Groker) GetHandle() (Handle, error) {
	return g.GetHandleWithOption(HandleMustBeFresh)
}

// GetHandleWithOption returns a handle for querying the Grok toolkit.
func (g *Groker) GetHandleWithOption(freshnessOption HandleFreshnessOption) (Handle, error) {
	// If there is a cached handle, return it if nothing has changed.
	// TODO: Support partial re-build here once supported by the rest of the pipeline.
	currentHandle := g.currentHandle
	if currentHandle != nil {
		handle := *currentHandle
		if freshnessOption == HandleAllowStale {
			return handle, nil
		}

		modified, err := handle.scopeResult.SourceTracker.ModifiedSourcePaths()
		if err == nil && len(modified) == 0 {
			return handle, nil
		}
	}

	handleResult := <-g.BuildHandle()
	return handleResult.Handle, handleResult.Error
}

// HandleResult is the result of a BuildHandle call.
type HandleResult struct {
	// Handle is the Grok handle constructed, if there was no error.
	Handle Handle

	// Error is the error that occurred, if any.
	Error error
}

// BuildHandle builds a new handle for this Grok. If an existing handle is being
// built, it will be canceled.
func (g *Groker) BuildHandle() chan HandleResult {
	resultChan := make(chan HandleResult, 1)

	g.buildHandleLock.Lock()

	// Cancel the exist handle construction.
	cancelationFunction := g.buildingHandleCancel
	if cancelationFunction != nil {
		cancelationFunction()
	}

	// Spin off construction of a new handle.
	internalChan, newCancelationFunction := g.startScope()
	g.buildingHandleCancel = newCancelationFunction

	g.buildHandleLock.Unlock()

	go func() {
		result := <-internalChan
		if result.err != nil {
			resultChan <- HandleResult{Handle{}, result.err}
			return
		}

		scopeResult := result.scopeResult
		if scopeResult.Graph == nil {
			resultChan <- HandleResult{Handle{}, fmt.Errorf("Handle construction was canceled")}
			return
		}

		newHandle := Handle{
			scopeResult:        scopeResult,
			structureFinder:    scopeResult.Graph.SourceGraph().NewSourceStructureFinder(),
			groker:             g,
			importInspectCache: cmap.New(),
			pathFiltersMap:     g.scopePathMap,
		}

		g.currentHandle = &newHandle
		resultChan <- HandleResult{newHandle, nil}
	}()

	return resultChan
}

type asyncResult struct {
	scopeResult scopegraph.Result
	err         error
}

// startScope causes the Groker to perform a full refresh of the source, starting at the
// root source file. Returns a channel that will be filled with the result, as well as a
// function for cancelation of the scoping.
func (g *Groker) startScope() (chan asyncResult, compilerutil.CancelFunction) {
	var scopeFilter scopegraph.ScopeFilter
	if len(g.scopePathMap) > 0 {
		scopeFilter = func(path compilercommon.InputSource) bool {
			return g.scopePathMap[path]
		}
	}

	config := scopegraph.Config{
		Entrypoint:                g.entrypoint,
		VCSDevelopmentDirectories: g.vcsDevelopmentDirectories,
		Libraries:                 g.libraries,
		Target:                    scopegraph.Tooling,
		PathLoader:                g.pathLoader,
		ScopeFilter:               scopeFilter,
	}

	configWithCancel, canceler := config.WithCancel()
	resultChan := make(chan asyncResult, 1)
	go func() {
		result, err := scopegraph.ParseAndBuildScopeGraphWithConfig(configWithCancel)
		resultChan <- asyncResult{result, err}
	}()

	return resultChan, canceler
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/printer"
	"go/token"
	"strings"

	"github.com/tmc/refactor_utils/pos"
)

func commandAddArgument(options Options) error {
	r, err := newRefactor(options.args)
	if err != nil {
		return err
	}
	parts := strings.SplitN(options.argument, " ", 2)
	argumentName, argumentType := parts[0], parts[1]

	return r.addArgument(argumentName, argumentType, options.position)
}

func (r *refactor) addArgument(argumentName, argumentType, position string) error {
	qpos, err := r.queryPos(position, false)
	if err != nil {
		return err
	}

	callPositions, callSites, err := r.callersAndCallsites(qpos)

	if err != nil {
		return err
	}

	for _, callPos := range callPositions {
		if err := addArgument(argumentName, argumentType, callPos); err != nil {
			return err
		}
	}

	for _, callSite := range callSites {
		if err := addParameter(argumentName, callSite); err != nil {
			return err
		}
	}

	fmt.Println("callers:", callPositions)
	fmt.Println("call sites:", callSites)

	modifiedFiles := map[*ast.File]bool{}
	for _, pos := range append(callPositions, callSites...) {
		fileNode := pos.Path[len(pos.Path)-1].(*ast.File)
		modifiedFiles[fileNode] = true
	}

	for file, _ := range modifiedFiles {
		var buf bytes.Buffer
		printer.Fprint(&buf, qpos.Fset, file)
		fmt.Println(string(buf.Bytes()))
	}

	if options.write {
		return fmt.Errorf("not implemented")
	}
	return nil
}

func addArgument(name, argType string, position *pos.QueryPos) error {
	if len(position.Path) == 0 {
		return fmt.Errorf("got empty node path")
	}
	node := position.Path[0]

	fieldList, ok := node.(*ast.FieldList)
	if !ok {
		return fmt.Errorf("pos must be in a FieldList, got: %T instead", node)
	}

	newField := &ast.Field{
		Names: []*ast.Ident{{Name: name}},
		Type:  &ast.Ident{Name: argType},
	}
	fieldList.List = append([]*ast.Field{newField}, fieldList.List...)
	return nil
}

func addParameter(name string, position *pos.QueryPos) error {
	if len(position.Path) == 0 {
		return fmt.Errorf("got empty node path")
	}
	node := position.Path[0]

	fieldList, ok := node.(*ast.CallExpr)
	if !ok {
		return fmt.Errorf("pos must be in a CallExpr, got: %T instead", node)
	}

	newParam := &ast.BasicLit{Kind: token.STRING, Value: name}
	fieldList.Args = append([]ast.Expr{newParam}, fieldList.Args...)
	return nil
}
<commit_msg>Only print errors<commit_after>package main

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/printer"
	"go/token"
	"log"
	"strings"

	"github.com/tmc/refactor_utils/pos"
)

func commandAddArgument(options Options) error {
	r, err := newRefactor(options.args)
	if err != nil {
		return err
	}
	parts := strings.SplitN(options.argument, " ", 2)
	argumentName, argumentType := parts[0], parts[1]

	return r.addArgument(argumentName, argumentType, options.position)
}

func (r *refactor) addArgument(argumentName, argumentType, position string) error {
	qpos, err := r.queryPos(position, false)
	if err != nil {
		return err
	}

	callPositions, callSites, err := r.callersAndCallsites(qpos)

	if err != nil {
		return err
	}

	for _, callPos := range callPositions {
		if err := addArgument(argumentName, argumentType, callPos); err != nil {
			log.Println(err)
		}
	}

	for _, callSite := range callSites {
		if err := addParameter(argumentName, callSite); err != nil {
			log.Println(err)
		}
	}

	fmt.Println("callers:", callPositions)
	fmt.Println("call sites:", callSites)

	modifiedFiles := map[*ast.File]bool{}
	for _, pos := range append(callPositions, callSites...) {
		fileNode := pos.Path[len(pos.Path)-1].(*ast.File)
		modifiedFiles[fileNode] = true
	}

	for file, _ := range modifiedFiles {
		var buf bytes.Buffer
		printer.Fprint(&buf, qpos.Fset, file)
		fmt.Println(string(buf.Bytes()))
	}

	if options.write {
		return fmt.Errorf("not implemented")
	}
	return nil
}

func addArgument(name, argType string, position *pos.QueryPos) error {
	if len(position.Path) == 0 {
		return fmt.Errorf("got empty node path")
	}
	node := position.Path[0]

	fieldList, ok := node.(*ast.FieldList)
	if !ok {
		ast.Print(position.Fset, node)
		return fmt.Errorf("pos must be in a FieldList, got: %T instead", node)
	}

	newField := &ast.Field{
		Names: []*ast.Ident{{Name: name}},
		Type:  &ast.Ident{Name: argType},
	}
	fieldList.List = append([]*ast.Field{newField}, fieldList.List...)
	return nil
}

func addParameter(name string, position *pos.QueryPos) error {
	if len(position.Path) == 0 {
		return fmt.Errorf("got empty node path")
	}
	node := position.Path[0]

	fieldList, ok := node.(*ast.CallExpr)
	if !ok {
		return fmt.Errorf("pos must be in a CallExpr, got: %T instead", node)
	}

	newParam := &ast.BasicLit{Kind: token.STRING, Value: name}
	fieldList.Args = append([]ast.Expr{newParam}, fieldList.Args...)
	return nil
}
<|endoftext|>


<commit_before>package moves

import (
	"errors"
	"github.com/jkomoros/boardgame"
	"github.com/jkomoros/boardgame/moves/interfaces"
	"strconv"
)

//targetCountString is a simple helper that returns the string of the target count.
func targetCountString(topLevelStruct boardgame.Move) string {
	moveCounter, ok := topLevelStruct.(interfaces.TargetCounter)

	if !ok {
		return "unknown"
	}

	targetCount := moveCounter.TargetCount()

	return strconv.Itoa(targetCount)

}

//ApplyUntil is a simple move that is legal to apply in succession until its
//ConditionMet returns nil. You need to implement
//interfaces.ConditionMetter by implementing a ConditionMet method.
//
//boardgame:codegen
type ApplyUntil struct {
	FixUpMulti
}

func (a *ApplyUntil) ValidConfiguration(exampleState boardgame.State) error {

	if _, ok := a.TopLevelStruct().(interfaces.ConditionMetter); !ok {
		return errors.New("Embedding Move doesn't have ConditionMet")
	}

	return a.FixUpMulti.ValidConfiguration(exampleState)
}

//Legal returns an error until ConditionMet returns nil.
func (a *ApplyUntil) Legal(state boardgame.ImmutableState, proposer boardgame.PlayerIndex) error {
	if err := a.Base.Legal(state, proposer); err != nil {
		return err
	}

	conditionMet, ok := a.TopLevelStruct().(interfaces.ConditionMetter)

	if !ok {
		//This should be extremely rare since we ourselves have the right method.
		return errors.New("ApplyUntil top level struct unexpectedly did not have ConditionMet method")
	}

	if err := conditionMet.ConditionMet(state); err != nil {
		//The condition is not yet met, which means it's legal.
		return nil
	}

	return errors.New("The condition was met, so the move is no longer legal.")

}

//FallbackName simply returns "Apply Until"
func (a *ApplyUntil) FallbackName(m *boardgame.GameManager) string {
	return "Apply Until"
}

//FallbackHelpText simply returns "Applies the move until a condition is met."
func (a *ApplyUntil) FallbackHelpText() string {
	return "Applies the move until a condition is met."
}

type counter interface {
	Count(state boardgame.ImmutableState) int
	interfaces.TargetCounter
	CountDown(state boardgame.ImmutableState) bool
}

//ApplyUntilCount is a subclass of ApplyUntil that is legal until Count() is
//one past TargetCount()'s value (which direction "past" is determined by the
//result of CountDown()). At the minimum you'll want to provide your own
//Count() and Apply() methods, or use the moves that subclass from this, like
//MoveComponentsUntilCountReached.
//
//boardgame:codegen
type ApplyUntilCount struct {
	ApplyUntil
}

func (a *ApplyUntilCount) ValidConfiguration(exampleState boardgame.State) error {
	if err := a.ApplyUntil.ValidConfiguration(exampleState); err != nil {
		return err
	}

	theCounter, ok := a.TopLevelStruct().(counter)

	if !ok {
		return errors.New("EmeddingMove doesn't have Count/TargetCount")
	}

	if theCounter.Count(exampleState) < 0 {
		return errors.New("Count returned a value below 0, which signals an error")
	}

	if theCounter.TargetCount() < 0 {
		return errors.New("TargetCount returned a value below 0, which signals an error")
	}

	return nil
}

//Count is consulted in ConditionMet to see what the current count is. Simply
//returns 1 by default. You almost certainly want to override this.
func (a *ApplyUntilCount) Count(state boardgame.ImmutableState) int {
	return 1
}

//TargetCount should return the count that you want to target. Note that it's
//also important to override CountDown() if you're counting down, not up. Will
//return the configuration option passed via WithTargetCount in DefaultConfig,
//or 1 if that wasn't provided.
func (a *ApplyUntilCount) TargetCount() int {

	config := a.CustomConfiguration()

	val, ok := config[configPropTargetCount]

	if !ok {
		//No configuration provided, just return default
		return 1
	}

	intVal, ok := val.(int)

	if !ok {
		//signal error
		return -1
	}

	return intVal

}

//CountDown should return true if we're counting downward, or false if we're
//counting up. ConditionMet() needs to know if we're counting down or we're
//counting up because it can't tell that by itself, and needs to stop one
//after the target is reached. Defaults to false.
func (a *ApplyUntilCount) CountDown(state boardgame.ImmutableState) bool {
	return false
}

//ConditionMet returns nil once TargetCount() is one past Count() (which
//direction is picked based on CountDown()). In general you override Count()
//and TargetCount() to customize behavior instead of overriding this.
func (a *ApplyUntilCount) ConditionMet(state boardgame.ImmutableState) error {

	embeddingMove := a.TopLevelStruct()

	moveCounter, ok := embeddingMove.(counter)

	if !ok {
		return errors.New("Embedding move unexpectedly did not have Count/TargetCount")
	}

	count := moveCounter.Count(state)
	targetCount := moveCounter.TargetCount()
	countDown := moveCounter.CountDown(state)

	if targetCount == count {
		return errors.New("Count is equal to TargetCount. This will be our last move")
	}

	if countDown {
		if count > targetCount {
			return errors.New("Counting down, and still greater than TargetCount")
		}
	} else {
		if count < targetCount {
			return errors.New("Counting up, and still less than target count")
		}
	}

	return nil

}

//FallbackName returns "Apply Until Count of INT", where INT is the
//target count.
func (a *ApplyUntilCount) FallbackName(m *boardgame.GameManager) string {

	return "Apply Until Count of " + targetCountString(a.TopLevelStruct())
}

//FallbackHelpText returns "Applies the move until a target count of
//INT is met.", where INT is the target count.
func (a *ApplyUntilCount) FallbackHelpText() string {
	return "Applies the move until a target count of " + targetCountString(a.TopLevelStruct()) + " is met."
}

//countMovesApplied is where the majority of logic for the count method of
//ApplyUntilCount goes. It makes it easy to plug in the logic in multiple
//types of moves that have the same type of behavior for Count() but can't
//directly subclass one another.
func countMovesApplied(topLevelStruct boardgame.Move, state boardgame.ImmutableState) int {

	records := state.Game().MoveRecords(state.Version())

	if len(records) == 0 {
		return 0
	}

	targetName := topLevelStruct.Info().Name()
	targetPhase := state.Game().Manager().Delegate().CurrentPhase(state)

	count := 0

	for i := len(records) - 1; i >= 0; i-- {
		record := records[i]

		if record.Phase != targetPhase {
			break
		}

		if record.Name != targetName {
			break
		}

		count++
	}

	return count
}

//ApplyCountTimes subclasses ApplyUntilCount. It applies the move until
//TargetCount() number of this move have been applied in a row within the
//current phase. Override TargetCount() to return the number of moves you
//actually want to apply. You'll need to provide your own Apply() method.
//
//boardgame:codegen
type ApplyCountTimes struct {
	ApplyUntilCount
}

//Count returns the number of times this move has been applied in a row in the
//immediate past in the current phase.
func (a *ApplyCountTimes) Count(state boardgame.ImmutableState) int {
	return countMovesApplied(a.TopLevelStruct(), state)
}

//FallbackName returns "Apply INT Times", where INT is the target
//count.
func (a *ApplyCountTimes) FallbackName(m *boardgame.GameManager) string {

	return "Apply " + targetCountString(a.TopLevelStruct()) + " Times"
}

//FallbackHelpText returns "Applies the move INT times in a row.",
//where INT is the target count.
func (a *ApplyCountTimes) FallbackHelpText() string {
	return "Applies the move " + targetCountString(a.TopLevelStruct()) + " times in a row."
}
<commit_msg>Fixed long-broken behavior of ApplyUntilCount and all subclasses, where we would stop one past where we should have stopped. Part of #705.<commit_after>package moves

import (
	"errors"
	"github.com/jkomoros/boardgame"
	"github.com/jkomoros/boardgame/moves/interfaces"
	"strconv"
)

//targetCountString is a simple helper that returns the string of the target count.
func targetCountString(topLevelStruct boardgame.Move) string {
	moveCounter, ok := topLevelStruct.(interfaces.TargetCounter)

	if !ok {
		return "unknown"
	}

	targetCount := moveCounter.TargetCount()

	return strconv.Itoa(targetCount)

}

//ApplyUntil is a simple move that is legal to apply in succession until its
//ConditionMet returns nil. You need to implement
//interfaces.ConditionMetter by implementing a ConditionMet method.
//
//boardgame:codegen
type ApplyUntil struct {
	FixUpMulti
}

func (a *ApplyUntil) ValidConfiguration(exampleState boardgame.State) error {

	if _, ok := a.TopLevelStruct().(interfaces.ConditionMetter); !ok {
		return errors.New("Embedding Move doesn't have ConditionMet")
	}

	return a.FixUpMulti.ValidConfiguration(exampleState)
}

//Legal returns an error until ConditionMet returns nil.
func (a *ApplyUntil) Legal(state boardgame.ImmutableState, proposer boardgame.PlayerIndex) error {
	if err := a.Base.Legal(state, proposer); err != nil {
		return err
	}

	conditionMet, ok := a.TopLevelStruct().(interfaces.ConditionMetter)

	if !ok {
		//This should be extremely rare since we ourselves have the right method.
		return errors.New("ApplyUntil top level struct unexpectedly did not have ConditionMet method")
	}

	if err := conditionMet.ConditionMet(state); err != nil {
		//The condition is not yet met, which means it's legal.
		return nil
	}

	return errors.New("The condition was met, so the move is no longer legal.")

}

//FallbackName simply returns "Apply Until"
func (a *ApplyUntil) FallbackName(m *boardgame.GameManager) string {
	return "Apply Until"
}

//FallbackHelpText simply returns "Applies the move until a condition is met."
func (a *ApplyUntil) FallbackHelpText() string {
	return "Applies the move until a condition is met."
}

type counter interface {
	Count(state boardgame.ImmutableState) int
	interfaces.TargetCounter
	CountDown(state boardgame.ImmutableState) bool
}

//ApplyUntilCount is a subclass of ApplyUntil that is legal until Count() is
//one past TargetCount()'s value (which direction "past" is determined by the
//result of CountDown()). At the minimum you'll want to provide your own
//Count() and Apply() methods, or use the moves that subclass from this, like
//MoveComponentsUntilCountReached.
//
//boardgame:codegen
type ApplyUntilCount struct {
	ApplyUntil
}

func (a *ApplyUntilCount) ValidConfiguration(exampleState boardgame.State) error {
	if err := a.ApplyUntil.ValidConfiguration(exampleState); err != nil {
		return err
	}

	theCounter, ok := a.TopLevelStruct().(counter)

	if !ok {
		return errors.New("EmeddingMove doesn't have Count/TargetCount")
	}

	if theCounter.Count(exampleState) < 0 {
		return errors.New("Count returned a value below 0, which signals an error")
	}

	if theCounter.TargetCount() < 0 {
		return errors.New("TargetCount returned a value below 0, which signals an error")
	}

	return nil
}

//Count is consulted in ConditionMet to see what the current count is. Simply
//returns 1 by default. You almost certainly want to override this.
func (a *ApplyUntilCount) Count(state boardgame.ImmutableState) int {
	return 1
}

//TargetCount should return the count that you want to target. Note that it's
//also important to override CountDown() if you're counting down, not up. Will
//return the configuration option passed via WithTargetCount in DefaultConfig,
//or 1 if that wasn't provided.
func (a *ApplyUntilCount) TargetCount() int {

	config := a.CustomConfiguration()

	val, ok := config[configPropTargetCount]

	if !ok {
		//No configuration provided, just return default
		return 1
	}

	intVal, ok := val.(int)

	if !ok {
		//signal error
		return -1
	}

	return intVal

}

//CountDown should return true if we're counting downward, or false if we're
//counting up. ConditionMet() needs to know if we're counting down or we're
//counting up because it can't tell that by itself, and needs to stop one
//after the target is reached. Defaults to false.
func (a *ApplyUntilCount) CountDown(state boardgame.ImmutableState) bool {
	return false
}

//ConditionMet returns nil once TargetCount() is one past Count() (which
//direction is picked based on CountDown()). In general you override Count()
//and TargetCount() to customize behavior instead of overriding this.
func (a *ApplyUntilCount) ConditionMet(state boardgame.ImmutableState) error {

	embeddingMove := a.TopLevelStruct()

	moveCounter, ok := embeddingMove.(counter)

	if !ok {
		return errors.New("Embedding move unexpectedly did not have Count/TargetCount")
	}

	count := moveCounter.Count(state)
	targetCount := moveCounter.TargetCount()
	countDown := moveCounter.CountDown(state)

	if targetCount == count {
		//We're at the goal!
		return nil
	}

	if countDown {
		if count > targetCount {
			return errors.New("Counting down, and still greater than TargetCount")
		}
	} else {
		if count < targetCount {
			return errors.New("Counting up, and still less than target count")
		}
	}

	return errors.New("Our condition is met, but we seem to have over-shot the goal, which shouldn't happen. Perhaps CountDown is set wrong?")

}

//FallbackName returns "Apply Until Count of INT", where INT is the
//target count.
func (a *ApplyUntilCount) FallbackName(m *boardgame.GameManager) string {

	return "Apply Until Count of " + targetCountString(a.TopLevelStruct())
}

//FallbackHelpText returns "Applies the move until a target count of
//INT is met.", where INT is the target count.
func (a *ApplyUntilCount) FallbackHelpText() string {
	return "Applies the move until a target count of " + targetCountString(a.TopLevelStruct()) + " is met."
}

//countMovesApplied is where the majority of logic for the count method of
//ApplyUntilCount goes. It makes it easy to plug in the logic in multiple
//types of moves that have the same type of behavior for Count() but can't
//directly subclass one another.
func countMovesApplied(topLevelStruct boardgame.Move, state boardgame.ImmutableState) int {

	records := state.Game().MoveRecords(state.Version())

	if len(records) == 0 {
		return 0
	}

	targetName := topLevelStruct.Info().Name()
	targetPhase := state.Game().Manager().Delegate().CurrentPhase(state)

	count := 0

	for i := len(records) - 1; i >= 0; i-- {
		record := records[i]

		if record.Phase != targetPhase {
			break
		}

		if record.Name != targetName {
			break
		}

		count++
	}

	return count
}

//ApplyCountTimes subclasses ApplyUntilCount. It applies the move until
//TargetCount() number of this move have been applied in a row within the
//current phase. Override TargetCount() to return the number of moves you
//actually want to apply. You'll need to provide your own Apply() method.
//
//boardgame:codegen
type ApplyCountTimes struct {
	ApplyUntilCount
}

//Count returns the number of times this move has been applied in a row in the
//immediate past in the current phase.
func (a *ApplyCountTimes) Count(state boardgame.ImmutableState) int {
	return countMovesApplied(a.TopLevelStruct(), state)
}

//FallbackName returns "Apply INT Times", where INT is the target
//count.
func (a *ApplyCountTimes) FallbackName(m *boardgame.GameManager) string {

	return "Apply " + targetCountString(a.TopLevelStruct()) + " Times"
}

//FallbackHelpText returns "Applies the move INT times in a row.",
//where INT is the target count.
func (a *ApplyCountTimes) FallbackHelpText() string {
	return "Applies the move " + targetCountString(a.TopLevelStruct()) + " times in a row."
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"

	"github.com/ecc1/cc1100"
	"github.com/ecc1/spi"
)

func main() {
	dev, err := spi.Open(cc1100.SpiSpeed, 0)
	if err != nil {
		log.Fatal(err)
	}
	err = dev.SetMaxSpeed(cc1100.SpiSpeed)
	if err != nil {
		log.Fatal(err)
	}
	speed, err := dev.MaxSpeed()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Max speed: %d Hz\n", speed)

	cc1100.Reset(dev)
	fmt.Printf("\nDefault RF settings:\n")
	cc1100.DumpRF(dev)

	cc1100.InitRF(dev)
	fmt.Printf("\nRF settings after initialization:\n")
	cc1100.DumpRF(dev)
}
<commit_msg>Remove custom CSn<commit_after>package main

import (
	"fmt"
	"log"

	"github.com/ecc1/cc1100"
	"github.com/ecc1/spi"
)

func main() {
	dev, err := spi.Open(cc1100.SpiSpeed)
	if err != nil {
		log.Fatal(err)
	}
	err = dev.SetMaxSpeed(cc1100.SpiSpeed)
	if err != nil {
		log.Fatal(err)
	}
	speed, err := dev.MaxSpeed()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Max speed: %d Hz\n", speed)

	cc1100.Reset(dev)
	fmt.Printf("\nDefault RF settings:\n")
	cc1100.DumpRF(dev)

	cc1100.InitRF(dev)
	fmt.Printf("\nRF settings after initialization:\n")
	cc1100.DumpRF(dev)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/gorilla/handlers"
	"github.com/robarchibald/configReader"
	"html/template"
	"log"
	"net/http"
	"os"
	"path"
	"strings"
)

type authConf struct {
	AuthServerListenPort                     int
	StoragePrefix                            string
	DbType                                   string
	DbServer                                 string
	DbPort                                   int
	DbUser                                   string
	DbDatabase                               string
	DbPassword                               string
	LdapServer                               string
	LdapPort                                 int
	LdapBindDn                               string
	LdapPassword                             string
	LdapBaseDn                               string
	LdapUserFilter                           string
	GetSessionQuery                          string
	RenewSessionQuery                        string
	GetRememberMeQuery                       string
	RenewRememberMeQuery                     string
	AddUserQuery                             string
	GetUserQuery                             string
	UpdateUserQuery                          string
	CreateLoginQuery                         string
	UpdateEmailAndInvalidateSessionsQuery    string
	UpdatePasswordAndInvalidateSessionsQuery string
	InvalidateUserSessionsQuery              string

	RedisServer         string
	RedisPort           int
	RedisPassword       string
	RedisMaxIdle        int
	RedisMaxConnections int
	ConcurrentDownloads int

	CookieBase64Key string

	SMTPServer              string
	SMTPPort                int
	SMTPFromEmail           string
	SMTPPassword            string
	EmailFromDisplayName    string
	VerifyEmailTemplate     string
	VerifyEmailSubject      string
	WelcomeTemplate         string
	WelcomeSubject          string
	NewLoginTemplate        string
	NewLoginSubject         string
	LockedOutTemplate       string
	LockedOutSubject        string
	EmailChangedTemplate    string
	EmailChangedSubject     string
	PasswordChangedTemplate string
	PasswordChangedSubject  string
}

type nginxauth struct {
	backend   backender
	mailer    mailer
	cookieKey []byte
	conf      authConf
	accessLog *os.File
}

func main() {
	configFile := flag.String("c", "/etc/nginxauth/nginxauth.conf", "config file location")
	logfile := flag.String("l", "/var/log/nginxauth.log", "log file")
	flag.Parse()

	server, err := newNginxAuth(*configFile, *logfile)
	if err != nil {
		log.Fatal(err)
	}
	defer server.backend.Close()
	defer server.accessLog.Close()

	server.serve(server.conf.AuthServerListenPort)
}

func newNginxAuth(configFle, logfile string) (*nginxauth, error) {
	eLog, err := createLogfile(logfile)
	if err != nil {
		return nil, err
	}
	log.Println("Starting auth server")

	config := authConf{}
	err = configReader.ReadFile(configFle, &config)
	if err != nil {
		log.Fatal(err)
	}

	s := newBackendRedisSession(config.RedisServer, config.RedisPort, config.RedisPassword, config.RedisMaxIdle, config.RedisMaxConnections, config.StoragePrefix)
	l, err := newBackendLDAPLogin(config.LdapServer, config.LdapPort, config.LdapBindDn, config.LdapPassword, config.LdapBaseDn, config.LdapUserFilter)
	if err != nil {
		return nil, err
	}
	u, err := newBackendDbUser(config.DbServer, config.DbPort, config.DbUser, config.DbPassword, config.DbDatabase, config.AddUserQuery, config.GetUserQuery, config.UpdateUserQuery)
	if err != nil {
		return nil, err
	}
	b := &backend{u: u, l: l, s: s}

	mailer, err := config.NewEmailer()
	if err != nil {
		return nil, err
	}

	cookieKey, err := decodeFromString(config.CookieBase64Key)
	if err != nil {
		return nil, err
	}

	return &nginxauth{b, mailer, cookieKey, config, eLog}, nil
}

func (n *authConf) NewEmailer() (*emailer, error) {
	sender := &smtpSender{n.SMTPServer, n.SMTPPort, n.SMTPFromEmail, n.SMTPPassword, n.EmailFromDisplayName}
	templateCache, err := template.ParseFiles(n.VerifyEmailTemplate, n.WelcomeTemplate,
		n.NewLoginTemplate, n.LockedOutTemplate, n.EmailChangedTemplate, n.PasswordChangedTemplate)
	if err != nil {
		return nil, err
	}
	return &emailer{
		templateCache:           templateCache,
		sender:                  sender,
		VerifyEmailTemplate:     n.VerifyEmailTemplate,
		VerifyEmailSubject:      n.VerifyEmailSubject,
		WelcomeTemplate:         n.WelcomeTemplate,
		WelcomeSubject:          n.WelcomeSubject,
		NewLoginTemplate:        n.NewLoginTemplate,
		NewLoginSubject:         n.NewLoginSubject,
		LockedOutTemplate:       n.LockedOutTemplate,
		LockedOutSubject:        n.LockedOutSubject,
		EmailChangedTemplate:    n.EmailChangedTemplate,
		EmailChangedSubject:     n.EmailChangedSubject,
		PasswordChangedTemplate: n.PasswordChangedTemplate,
		PasswordChangedSubject:  n.PasswordChangedSubject,
	}, nil
}

func (s *nginxauth) serve(port int) {
	http.HandleFunc("/auth", s.method("GET", auth))
	http.HandleFunc("/authBasic", s.method("GET", authBasic))
	http.HandleFunc("/createProfile", s.method("POST", createProfile))
	http.HandleFunc("/login", s.method("POST", login))
	http.HandleFunc("/register", s.method("POST", register))
	http.HandleFunc("/verifyEmail", s.method("POST", verifyEmail))
	http.HandleFunc("/updateEmail", s.method("POST", updateEmail))
	http.HandleFunc("/updatePassword", s.method("POST", updatePassword))

	http.ListenAndServe(fmt.Sprintf(":%d", port), s.fileLoggerHandler(handlers.CompressHandler(http.DefaultServeMux)))
}

func (s *nginxauth) fileLoggerHandler(h http.Handler) http.Handler {
	return handlers.CombinedLoggingHandler(s.accessLog, h)
}

func (s *nginxauth) method(name string, handler func(authStore authStorer, w http.ResponseWriter, r *http.Request)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if r.Method != name {
			http.Error(w, "Unsupported method", http.StatusInternalServerError)
			return
		}
		secureOnly := strings.HasPrefix(r.Referer(), "https") // proxy to back-end so if referer is secure connection, we can use secureOnly cookies
		authStore := newAuthStore(s.backend, s.mailer, &cryptoHashStore{}, w, r, s.conf.StoragePrefix, s.cookieKey, secureOnly)
		handler(authStore, w, r)
	}
}

func auth(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	session, err := authStore.GetSession()
	if err != nil {
		authErr(w, r, err)
		return
	}

	user, err := json.Marshal(&userLogin{Email: session.Email, UserID: session.UserID, FullName: session.FullName})
	if err != nil {
		authErr(w, r, err)
		return
	}

	addUserHeader(string(user), w)
}

func authErr(w http.ResponseWriter, r *http.Request, err error) {
	http.Error(w, "Authentication required: "+err.Error(), http.StatusUnauthorized)
	logError(err)
}

func logError(err error) {
	if a, ok := err.(*authError); ok {
		log.Println(a.Trace())
	} else {
		log.Println(err)
	}
}

func authBasic(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	session, err := authStore.GetBasicAuth()
	if err != nil {
		basicErr(w, r, err)
		return
	}

	user, err := json.Marshal(&userLogin{Email: session.Email, UserID: session.UserID, FullName: session.FullName})
	if err != nil {
		basicErr(w, r, err)
		return
	}

	addUserHeader(string(user), w)
}

func basicErr(w http.ResponseWriter, r *http.Request, err error) {
	w.Header().Set("WWW-Authenticate", "Basic realm='Endfirst.com'")
	http.Error(w, "Authentication required: "+err.Error(), http.StatusUnauthorized)
	logError(err)
}

func login(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	run("login", authStore.Login, w)
}

func register(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	run("register", authStore.Register, w)
}

func createProfile(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	run("createProfile", authStore.CreateProfile, w)
}

func updateEmail(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	run("updateEmail", authStore.UpdateEmail, w)
}

func updatePassword(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	run("updatePassword", authStore.UpdatePassword, w)
}

func verifyEmail(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	destinationURL, err := authStore.VerifyEmail()
	writeOutput(w, fmt.Sprintf("{ \"result\": \"Success\", \"destinationURL\": \"%s\" }", destinationURL), err)
}

func run(name string, method func() error, w http.ResponseWriter) {
	writeOutput(w, "{ \"result\": \"Success\" }", method())
}

func writeOutput(w http.ResponseWriter, message string, err error) {
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		logError(err)
	} else {
		w.Header().Add("Access-Control-Allow-Origin", "*")
		w.Header().Add("Content-Type", "application/javascript")
		fmt.Fprint(w, "{ \"result\": \"Success\" }")
	}
}

func addUserHeader(userJSON string, w http.ResponseWriter) {
	w.Header().Add("X-User", userJSON)
}

func createLogfile(logFile string) (*os.File, error) {
	dir := path.Dir(logFile)
	if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
		os.MkdirAll(dir, 0755)
	}
	eLog, err := os.OpenFile(logFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
	if err != nil {
		return nil, err
	}
	log.SetOutput(eLog)
	return eLog, nil
}
<commit_msg>remove access log<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/gorilla/handlers"
	"github.com/robarchibald/configReader"
	"html/template"
	"log"
	"net/http"
	"os"
	"path"
	"strings"
)

type authConf struct {
	AuthServerListenPort                     int
	StoragePrefix                            string
	DbType                                   string
	DbServer                                 string
	DbPort                                   int
	DbUser                                   string
	DbDatabase                               string
	DbPassword                               string
	LdapServer                               string
	LdapPort                                 int
	LdapBindDn                               string
	LdapPassword                             string
	LdapBaseDn                               string
	LdapUserFilter                           string
	GetSessionQuery                          string
	RenewSessionQuery                        string
	GetRememberMeQuery                       string
	RenewRememberMeQuery                     string
	AddUserQuery                             string
	GetUserQuery                             string
	UpdateUserQuery                          string
	CreateLoginQuery                         string
	UpdateEmailAndInvalidateSessionsQuery    string
	UpdatePasswordAndInvalidateSessionsQuery string
	InvalidateUserSessionsQuery              string

	RedisServer         string
	RedisPort           int
	RedisPassword       string
	RedisMaxIdle        int
	RedisMaxConnections int
	ConcurrentDownloads int

	CookieBase64Key string

	SMTPServer              string
	SMTPPort                int
	SMTPFromEmail           string
	SMTPPassword            string
	EmailFromDisplayName    string
	VerifyEmailTemplate     string
	VerifyEmailSubject      string
	WelcomeTemplate         string
	WelcomeSubject          string
	NewLoginTemplate        string
	NewLoginSubject         string
	LockedOutTemplate       string
	LockedOutSubject        string
	EmailChangedTemplate    string
	EmailChangedSubject     string
	PasswordChangedTemplate string
	PasswordChangedSubject  string
}

type nginxauth struct {
	backend   backender
	mailer    mailer
	cookieKey []byte
	conf      authConf
	errorLog  *os.File
}

func main() {
	configFile := flag.String("c", "/etc/nginxauth/nginxauth.conf", "config file location")
	logfile := flag.String("l", "/var/log/nginxauth.log", "log file")
	flag.Parse()

	server, err := newNginxAuth(*configFile, *logfile)
	if err != nil {
		log.Fatal(err)
	}
	defer server.backend.Close()
	defer server.errorLog.Close()

	server.serve(server.conf.AuthServerListenPort)
}

func newNginxAuth(configFle, logfile string) (*nginxauth, error) {
	eLog, err := createLogfile(logfile)
	if err != nil {
		return nil, err
	}
	log.Println("Starting auth server")

	config := authConf{}
	err = configReader.ReadFile(configFle, &config)
	if err != nil {
		log.Fatal(err)
	}

	s := newBackendRedisSession(config.RedisServer, config.RedisPort, config.RedisPassword, config.RedisMaxIdle, config.RedisMaxConnections, config.StoragePrefix)
	l, err := newBackendLDAPLogin(config.LdapServer, config.LdapPort, config.LdapBindDn, config.LdapPassword, config.LdapBaseDn, config.LdapUserFilter)
	if err != nil {
		return nil, err
	}
	u, err := newBackendDbUser(config.DbServer, config.DbPort, config.DbUser, config.DbPassword, config.DbDatabase, config.AddUserQuery, config.GetUserQuery, config.UpdateUserQuery)
	if err != nil {
		return nil, err
	}
	b := &backend{u: u, l: l, s: s}

	mailer, err := config.NewEmailer()
	if err != nil {
		return nil, err
	}

	cookieKey, err := decodeFromString(config.CookieBase64Key)
	if err != nil {
		return nil, err
	}

	return &nginxauth{b, mailer, cookieKey, config, eLog}, nil
}

func (n *authConf) NewEmailer() (*emailer, error) {
	sender := &smtpSender{n.SMTPServer, n.SMTPPort, n.SMTPFromEmail, n.SMTPPassword, n.EmailFromDisplayName}
	templateCache, err := template.ParseFiles(n.VerifyEmailTemplate, n.WelcomeTemplate,
		n.NewLoginTemplate, n.LockedOutTemplate, n.EmailChangedTemplate, n.PasswordChangedTemplate)
	if err != nil {
		return nil, err
	}
	return &emailer{
		templateCache:           templateCache,
		sender:                  sender,
		VerifyEmailTemplate:     n.VerifyEmailTemplate,
		VerifyEmailSubject:      n.VerifyEmailSubject,
		WelcomeTemplate:         n.WelcomeTemplate,
		WelcomeSubject:          n.WelcomeSubject,
		NewLoginTemplate:        n.NewLoginTemplate,
		NewLoginSubject:         n.NewLoginSubject,
		LockedOutTemplate:       n.LockedOutTemplate,
		LockedOutSubject:        n.LockedOutSubject,
		EmailChangedTemplate:    n.EmailChangedTemplate,
		EmailChangedSubject:     n.EmailChangedSubject,
		PasswordChangedTemplate: n.PasswordChangedTemplate,
		PasswordChangedSubject:  n.PasswordChangedSubject,
	}, nil
}

func (s *nginxauth) serve(port int) {
	http.HandleFunc("/auth", s.method("GET", auth))
	http.HandleFunc("/authBasic", s.method("GET", authBasic))
	http.HandleFunc("/createProfile", s.method("POST", createProfile))
	http.HandleFunc("/login", s.method("POST", login))
	http.HandleFunc("/register", s.method("POST", register))
	http.HandleFunc("/verifyEmail", s.method("POST", verifyEmail))
	http.HandleFunc("/updateEmail", s.method("POST", updateEmail))
	http.HandleFunc("/updatePassword", s.method("POST", updatePassword))

	http.ListenAndServe(fmt.Sprintf(":%d", port), handlers.CompressHandler(http.DefaultServeMux))
}

func (s *nginxauth) method(name string, handler func(authStore authStorer, w http.ResponseWriter, r *http.Request)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if r.Method != name {
			http.Error(w, "Unsupported method", http.StatusInternalServerError)
			return
		}
		secureOnly := strings.HasPrefix(r.Referer(), "https") // proxy to back-end so if referer is secure connection, we can use secureOnly cookies
		authStore := newAuthStore(s.backend, s.mailer, &cryptoHashStore{}, w, r, s.conf.StoragePrefix, s.cookieKey, secureOnly)
		handler(authStore, w, r)
	}
}

func auth(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	session, err := authStore.GetSession()
	if err != nil {
		authErr(w, r, err)
		return
	}

	user, err := json.Marshal(&userLogin{Email: session.Email, UserID: session.UserID, FullName: session.FullName})
	if err != nil {
		authErr(w, r, err)
		return
	}

	addUserHeader(string(user), w)
}

func authErr(w http.ResponseWriter, r *http.Request, err error) {
	http.Error(w, "Authentication required: "+err.Error(), http.StatusUnauthorized)
	logError(err)
}

func logError(err error) {
	if a, ok := err.(*authError); ok {
		log.Println(a.Trace())
	} else {
		log.Println(err)
	}
}

func authBasic(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	session, err := authStore.GetBasicAuth()
	if err != nil {
		basicErr(w, r, err)
		return
	}

	user, err := json.Marshal(&userLogin{Email: session.Email, UserID: session.UserID, FullName: session.FullName})
	if err != nil {
		basicErr(w, r, err)
		return
	}

	addUserHeader(string(user), w)
}

func basicErr(w http.ResponseWriter, r *http.Request, err error) {
	w.Header().Set("WWW-Authenticate", "Basic realm='Endfirst.com'")
	http.Error(w, "Authentication required: "+err.Error(), http.StatusUnauthorized)
	logError(err)
}

func login(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	run("login", authStore.Login, w)
}

func register(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	run("register", authStore.Register, w)
}

func createProfile(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	run("createProfile", authStore.CreateProfile, w)
}

func updateEmail(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	run("updateEmail", authStore.UpdateEmail, w)
}

func updatePassword(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	run("updatePassword", authStore.UpdatePassword, w)
}

func verifyEmail(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	destinationURL, err := authStore.VerifyEmail()
	writeOutput(w, fmt.Sprintf("{ \"result\": \"Success\", \"destinationURL\": \"%s\" }", destinationURL), err)
}

func run(name string, method func() error, w http.ResponseWriter) {
	writeOutput(w, "{ \"result\": \"Success\" }", method())
}

func writeOutput(w http.ResponseWriter, message string, err error) {
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		logError(err)
	} else {
		w.Header().Add("Access-Control-Allow-Origin", "*")
		w.Header().Add("Content-Type", "application/javascript")
		fmt.Fprint(w, "{ \"result\": \"Success\" }")
	}
}

func addUserHeader(userJSON string, w http.ResponseWriter) {
	w.Header().Add("X-User", userJSON)
}

func createLogfile(logFile string) (*os.File, error) {
	dir := path.Dir(logFile)
	if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
		os.MkdirAll(dir, 0755)
	}
	eLog, err := os.OpenFile(logFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
	if err != nil {
		return nil, err
	}
	log.SetOutput(eLog)
	return eLog, nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/gorilla/handlers"
	"github.com/robarchibald/configReader"
	"html/template"
	"log"
	"net/http"
	"os"
	"path"
	"strings"
)

type authConf struct {
	AuthServerListenPort                     int
	StoragePrefix                            string
	DbType                                   string
	DbServer                                 string
	DbPort                                   int
	DbUser                                   string
	DbDatabase                               string
	DbPassword                               string
	LdapServer                               string
	LdapPort                                 int
	LdapBindDn                               string
	LdapPassword                             string
	LdapBaseDn                               string
	LdapUserFilter                           string
	GetSessionQuery                          string
	RenewSessionQuery                        string
	GetRememberMeQuery                       string
	RenewRememberMeQuery                     string
	AddUserQuery                             string
	GetUserQuery                             string
	UpdateUserQuery                          string
	CreateLoginQuery                         string
	UpdateEmailAndInvalidateSessionsQuery    string
	UpdatePasswordAndInvalidateSessionsQuery string
	InvalidateUserSessionsQuery              string

	RedisServer         string
	RedisPort           int
	RedisPassword       string
	RedisMaxIdle        int
	RedisMaxConnections int
	ConcurrentDownloads int

	CookieBase64Key string

	SMTPServer              string
	SMTPPort                int
	SMTPFromEmail           string
	SMTPPassword            string
	EmailFromDisplayName    string
	VerifyEmailTemplate     string
	VerifyEmailSubject      string
	WelcomeTemplate         string
	WelcomeSubject          string
	NewLoginTemplate        string
	NewLoginSubject         string
	LockedOutTemplate       string
	LockedOutSubject        string
	EmailChangedTemplate    string
	EmailChangedSubject     string
	PasswordChangedTemplate string
	PasswordChangedSubject  string
}

type nginxauth struct {
	backend   backender
	mailer    mailer
	cookieKey []byte
	conf      authConf
	errorLog  *os.File
}

func main() {
	configFile := flag.String("c", "/etc/nginxauth/nginxauth.conf", "config file location")
	logfile := flag.String("l", "/var/log/nginxauth.log", "log file")
	flag.Parse()

	server, err := newNginxAuth(*configFile, *logfile)
	if err != nil {
		log.Fatal(err)
	}
	defer server.backend.Close()
	defer server.errorLog.Close()

	server.serve(server.conf.AuthServerListenPort)
}

func newNginxAuth(configFle, logfile string) (*nginxauth, error) {
	eLog, err := createLogfile(logfile)
	if err != nil {
		return nil, err
	}
	log.Println("Starting auth server")

	config := authConf{}
	err = configReader.ReadFile(configFle, &config)
	if err != nil {
		log.Fatal(err)
	}

	s := newBackendRedisSession(config.RedisServer, config.RedisPort, config.RedisPassword, config.RedisMaxIdle, config.RedisMaxConnections, config.StoragePrefix)
	l, err := newBackendLDAPLogin(config.LdapServer, config.LdapPort, config.LdapBindDn, config.LdapPassword, config.LdapBaseDn, config.LdapUserFilter)
	if err != nil {
		return nil, err
	}
	u, err := newBackendDbUser(config.DbServer, config.DbPort, config.DbUser, config.DbPassword, config.DbDatabase, config.AddUserQuery, config.GetUserQuery, config.UpdateUserQuery)
	if err != nil {
		return nil, err
	}
	b := &backend{u: u, l: l, s: s}

	mailer, err := config.NewEmailer()
	if err != nil {
		return nil, err
	}

	cookieKey, err := decodeFromString(config.CookieBase64Key)
	if err != nil {
		return nil, err
	}

	return &nginxauth{b, mailer, cookieKey, config, eLog}, nil
}

func (n *authConf) NewEmailer() (*emailer, error) {
	sender := &smtpSender{n.SMTPServer, n.SMTPPort, n.SMTPFromEmail, n.SMTPPassword, n.EmailFromDisplayName}
	templateCache, err := template.ParseFiles(n.VerifyEmailTemplate, n.WelcomeTemplate,
		n.NewLoginTemplate, n.LockedOutTemplate, n.EmailChangedTemplate, n.PasswordChangedTemplate)
	if err != nil {
		return nil, err
	}
	return &emailer{
		templateCache:           templateCache,
		sender:                  sender,
		VerifyEmailTemplate:     n.VerifyEmailTemplate,
		VerifyEmailSubject:      n.VerifyEmailSubject,
		WelcomeTemplate:         n.WelcomeTemplate,
		WelcomeSubject:          n.WelcomeSubject,
		NewLoginTemplate:        n.NewLoginTemplate,
		NewLoginSubject:         n.NewLoginSubject,
		LockedOutTemplate:       n.LockedOutTemplate,
		LockedOutSubject:        n.LockedOutSubject,
		EmailChangedTemplate:    n.EmailChangedTemplate,
		EmailChangedSubject:     n.EmailChangedSubject,
		PasswordChangedTemplate: n.PasswordChangedTemplate,
		PasswordChangedSubject:  n.PasswordChangedSubject,
	}, nil
}

func (s *nginxauth) serve(port int) {
	http.HandleFunc("/auth", s.method("GET", auth))
	http.HandleFunc("/authBasic", s.method("GET", authBasic))
	http.HandleFunc("/createProfile", s.method("POST", createProfile))
	http.HandleFunc("/login", s.method("POST", login))
	http.HandleFunc("/oauth", s.method("GET", oauthLogin))
	http.HandleFunc("/register", s.method("POST", register))
	http.HandleFunc("/verifyEmail", s.method("POST", verifyEmail))
	http.HandleFunc("/updateEmail", s.method("POST", updateEmail))
	http.HandleFunc("/updatePassword", s.method("POST", updatePassword))

	http.ListenAndServe(fmt.Sprintf(":%d", port), handlers.CompressHandler(http.DefaultServeMux))
}

func (s *nginxauth) method(name string, handler func(authStore authStorer, w http.ResponseWriter, r *http.Request)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if r.Method != name {
			http.Error(w, "Unsupported method", http.StatusInternalServerError)
			return
		}
		secureOnly := strings.HasPrefix(r.Referer(), "https") // proxy to back-end so if referer is secure connection, we can use secureOnly cookies
		authStore := newAuthStore(s.backend, s.mailer, &cryptoHashStore{}, w, r, s.conf.StoragePrefix, s.cookieKey, secureOnly)
		handler(authStore, w, r)
	}
}

func auth(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	session, err := authStore.GetSession()
	if err != nil {
		authErr(w, r, err)
		return
	}

	user, err := json.Marshal(&userLogin{Email: session.Email, UserID: session.UserID, FullName: session.FullName})
	if err != nil {
		authErr(w, r, err)
		return
	}

	addUserHeader(string(user), w)
}

func authErr(w http.ResponseWriter, r *http.Request, err error) {
	http.Error(w, "Authentication required: "+err.Error(), http.StatusUnauthorized)
	logError(err)
}

func logError(err error) {
	if a, ok := err.(*authError); ok {
		log.Println(a.Trace())
	} else {
		log.Println(err)
	}
}

func authBasic(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	session, err := authStore.GetBasicAuth()
	if err != nil {
		basicErr(w, r, err)
		return
	}

	user, err := json.Marshal(&userLogin{Email: session.Email, UserID: session.UserID, FullName: session.FullName})
	if err != nil {
		basicErr(w, r, err)
		return
	}

	addUserHeader(string(user), w)
}

func basicErr(w http.ResponseWriter, r *http.Request, err error) {
	w.Header().Set("WWW-Authenticate", "Basic realm='Endfirst.com'")
	http.Error(w, "Authentication required: "+err.Error(), http.StatusUnauthorized)
	logError(err)
}

func oauthLogin(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	run("oauthLogin", authStore.OAuthLogin, w)
}

func login(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	run("login", authStore.Login, w)
}

func register(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	run("register", authStore.Register, w)
}

func createProfile(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	run("createProfile", authStore.CreateProfile, w)
}

func updateEmail(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	run("updateEmail", authStore.UpdateEmail, w)
}

func updatePassword(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	run("updatePassword", authStore.UpdatePassword, w)
}

func verifyEmail(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	destinationURL, err := authStore.VerifyEmail()
	writeOutput(w, fmt.Sprintf("{ \"result\": \"Success\", \"destinationURL\": \"%s\" }", destinationURL), err)
}

func run(name string, method func() error, w http.ResponseWriter) {
	writeOutput(w, "{ \"result\": \"Success\" }", method())
}

func writeOutput(w http.ResponseWriter, message string, err error) {
	w.Header().Add("Access-Control-Allow-Origin", "*")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		logError(err)
	} else {
		w.Header().Add("Content-Type", "application/javascript")
		fmt.Fprint(w, "{ \"result\": \"Success\" }")
	}
}

func addUserHeader(userJSON string, w http.ResponseWriter) {
	w.Header().Add("X-User", userJSON)
}

func createLogfile(logFile string) (*os.File, error) {
	dir := path.Dir(logFile)
	if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
		os.MkdirAll(dir, 0755)
	}
	eLog, err := os.OpenFile(logFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
	if err != nil {
		return nil, err
	}
	log.SetOutput(eLog)
	return eLog, nil
}
<commit_msg>Return type should be application/json<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/gorilla/handlers"
	"github.com/robarchibald/configReader"
	"html/template"
	"log"
	"net/http"
	"os"
	"path"
	"strings"
)

type authConf struct {
	AuthServerListenPort                     int
	StoragePrefix                            string
	DbType                                   string
	DbServer                                 string
	DbPort                                   int
	DbUser                                   string
	DbDatabase                               string
	DbPassword                               string
	LdapServer                               string
	LdapPort                                 int
	LdapBindDn                               string
	LdapPassword                             string
	LdapBaseDn                               string
	LdapUserFilter                           string
	GetSessionQuery                          string
	RenewSessionQuery                        string
	GetRememberMeQuery                       string
	RenewRememberMeQuery                     string
	AddUserQuery                             string
	GetUserQuery                             string
	UpdateUserQuery                          string
	CreateLoginQuery                         string
	UpdateEmailAndInvalidateSessionsQuery    string
	UpdatePasswordAndInvalidateSessionsQuery string
	InvalidateUserSessionsQuery              string

	RedisServer         string
	RedisPort           int
	RedisPassword       string
	RedisMaxIdle        int
	RedisMaxConnections int
	ConcurrentDownloads int

	CookieBase64Key string

	SMTPServer              string
	SMTPPort                int
	SMTPFromEmail           string
	SMTPPassword            string
	EmailFromDisplayName    string
	VerifyEmailTemplate     string
	VerifyEmailSubject      string
	WelcomeTemplate         string
	WelcomeSubject          string
	NewLoginTemplate        string
	NewLoginSubject         string
	LockedOutTemplate       string
	LockedOutSubject        string
	EmailChangedTemplate    string
	EmailChangedSubject     string
	PasswordChangedTemplate string
	PasswordChangedSubject  string
}

type nginxauth struct {
	backend   backender
	mailer    mailer
	cookieKey []byte
	conf      authConf
	errorLog  *os.File
}

func main() {
	configFile := flag.String("c", "/etc/nginxauth/nginxauth.conf", "config file location")
	logfile := flag.String("l", "/var/log/nginxauth.log", "log file")
	flag.Parse()

	server, err := newNginxAuth(*configFile, *logfile)
	if err != nil {
		log.Fatal(err)
	}
	defer server.backend.Close()
	defer server.errorLog.Close()

	server.serve(server.conf.AuthServerListenPort)
}

func newNginxAuth(configFle, logfile string) (*nginxauth, error) {
	eLog, err := createLogfile(logfile)
	if err != nil {
		return nil, err
	}
	log.Println("Starting auth server")

	config := authConf{}
	err = configReader.ReadFile(configFle, &config)
	if err != nil {
		log.Fatal(err)
	}

	s := newBackendRedisSession(config.RedisServer, config.RedisPort, config.RedisPassword, config.RedisMaxIdle, config.RedisMaxConnections, config.StoragePrefix)
	l, err := newBackendLDAPLogin(config.LdapServer, config.LdapPort, config.LdapBindDn, config.LdapPassword, config.LdapBaseDn, config.LdapUserFilter)
	if err != nil {
		return nil, err
	}
	u, err := newBackendDbUser(config.DbServer, config.DbPort, config.DbUser, config.DbPassword, config.DbDatabase, config.AddUserQuery, config.GetUserQuery, config.UpdateUserQuery)
	if err != nil {
		return nil, err
	}
	b := &backend{u: u, l: l, s: s}

	mailer, err := config.NewEmailer()
	if err != nil {
		return nil, err
	}

	cookieKey, err := decodeFromString(config.CookieBase64Key)
	if err != nil {
		return nil, err
	}

	return &nginxauth{b, mailer, cookieKey, config, eLog}, nil
}

func (n *authConf) NewEmailer() (*emailer, error) {
	sender := &smtpSender{n.SMTPServer, n.SMTPPort, n.SMTPFromEmail, n.SMTPPassword, n.EmailFromDisplayName}
	templateCache, err := template.ParseFiles(n.VerifyEmailTemplate, n.WelcomeTemplate,
		n.NewLoginTemplate, n.LockedOutTemplate, n.EmailChangedTemplate, n.PasswordChangedTemplate)
	if err != nil {
		return nil, err
	}
	return &emailer{
		templateCache:           templateCache,
		sender:                  sender,
		VerifyEmailTemplate:     n.VerifyEmailTemplate,
		VerifyEmailSubject:      n.VerifyEmailSubject,
		WelcomeTemplate:         n.WelcomeTemplate,
		WelcomeSubject:          n.WelcomeSubject,
		NewLoginTemplate:        n.NewLoginTemplate,
		NewLoginSubject:         n.NewLoginSubject,
		LockedOutTemplate:       n.LockedOutTemplate,
		LockedOutSubject:        n.LockedOutSubject,
		EmailChangedTemplate:    n.EmailChangedTemplate,
		EmailChangedSubject:     n.EmailChangedSubject,
		PasswordChangedTemplate: n.PasswordChangedTemplate,
		PasswordChangedSubject:  n.PasswordChangedSubject,
	}, nil
}

func (s *nginxauth) serve(port int) {
	http.HandleFunc("/auth", s.method("GET", auth))
	http.HandleFunc("/authBasic", s.method("GET", authBasic))
	http.HandleFunc("/createProfile", s.method("POST", createProfile))
	http.HandleFunc("/login", s.method("POST", login))
	http.HandleFunc("/oauth", s.method("GET", oauthLogin))
	http.HandleFunc("/register", s.method("POST", register))
	http.HandleFunc("/verifyEmail", s.method("POST", verifyEmail))
	http.HandleFunc("/updateEmail", s.method("POST", updateEmail))
	http.HandleFunc("/updatePassword", s.method("POST", updatePassword))

	http.ListenAndServe(fmt.Sprintf(":%d", port), handlers.CompressHandler(http.DefaultServeMux))
}

func (s *nginxauth) method(name string, handler func(authStore authStorer, w http.ResponseWriter, r *http.Request)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if r.Method != name {
			http.Error(w, "Unsupported method", http.StatusInternalServerError)
			return
		}
		secureOnly := strings.HasPrefix(r.Referer(), "https") // proxy to back-end so if referer is secure connection, we can use secureOnly cookies
		authStore := newAuthStore(s.backend, s.mailer, &cryptoHashStore{}, w, r, s.conf.StoragePrefix, s.cookieKey, secureOnly)
		handler(authStore, w, r)
	}
}

func auth(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	session, err := authStore.GetSession()
	if err != nil {
		authErr(w, r, err)
		return
	}

	user, err := json.Marshal(&userLogin{Email: session.Email, UserID: session.UserID, FullName: session.FullName})
	if err != nil {
		authErr(w, r, err)
		return
	}

	addUserHeader(string(user), w)
}

func authErr(w http.ResponseWriter, r *http.Request, err error) {
	http.Error(w, "Authentication required: "+err.Error(), http.StatusUnauthorized)
	logError(err)
}

func logError(err error) {
	if a, ok := err.(*authError); ok {
		log.Println(a.Trace())
	} else {
		log.Println(err)
	}
}

func authBasic(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	session, err := authStore.GetBasicAuth()
	if err != nil {
		basicErr(w, r, err)
		return
	}

	user, err := json.Marshal(&userLogin{Email: session.Email, UserID: session.UserID, FullName: session.FullName})
	if err != nil {
		basicErr(w, r, err)
		return
	}

	addUserHeader(string(user), w)
}

func basicErr(w http.ResponseWriter, r *http.Request, err error) {
	w.Header().Set("WWW-Authenticate", "Basic realm='Endfirst.com'")
	http.Error(w, "Authentication required: "+err.Error(), http.StatusUnauthorized)
	logError(err)
}

func oauthLogin(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	run("oauthLogin", authStore.OAuthLogin, w)
}

func login(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	run("login", authStore.Login, w)
}

func register(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	run("register", authStore.Register, w)
}

func createProfile(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	run("createProfile", authStore.CreateProfile, w)
}

func updateEmail(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	run("updateEmail", authStore.UpdateEmail, w)
}

func updatePassword(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	run("updatePassword", authStore.UpdatePassword, w)
}

func verifyEmail(authStore authStorer, w http.ResponseWriter, r *http.Request) {
	destinationURL, err := authStore.VerifyEmail()
	writeOutput(w, fmt.Sprintf("{ \"result\": \"Success\", \"destinationURL\": \"%s\" }", destinationURL), err)
}

func run(name string, method func() error, w http.ResponseWriter) {
	writeOutput(w, "{ \"result\": \"Success\" }", method())
}

func writeOutput(w http.ResponseWriter, message string, err error) {
	w.Header().Add("Access-Control-Allow-Origin", "*")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		logError(err)
	} else {
		w.Header().Add("Content-Type", "application/json")
		fmt.Fprint(w, "{ \"result\": \"Success\" }")
	}
}

func addUserHeader(userJSON string, w http.ResponseWriter) {
	w.Header().Add("X-User", userJSON)
}

func createLogfile(logFile string) (*os.File, error) {
	dir := path.Dir(logFile)
	if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
		os.MkdirAll(dir, 0755)
	}
	eLog, err := os.OpenFile(logFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
	if err != nil {
		return nil, err
	}
	log.SetOutput(eLog)
	return eLog, nil
}
<|endoftext|>


<commit_before>package web

import (
	"log"
	"net/http"

	"github.com/generationtux/brizo/auth"
	"github.com/generationtux/brizo/database"
	githuboauth "github.com/google/go-github/github"
	"github.com/mholt/binding"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/github"
)

const htmlAddUser = `<!doctype html>
<form action="/api/v1/users" method="post">
  Add user:
  <input type="text" name="username">
</form>

`

// AuthAddNewUser @todo move to JS UI
func AuthAddNewUser(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	w.WriteHeader(http.StatusOK)
	w.Write([]byte(htmlAddUser))
}

const htmlIndex = `
Log in with GitHub

`

var (
	oauthConf = &oauth2.Config{
		ClientID:     "",
		ClientSecret: "",
		Scopes:       []string{"user", "user:email", "repo"},
		Endpoint:     github.Endpoint,
	}
	oauthStateString = auth.GetOAuthStateString()
)

// AuthMainHandler @todo move to JS UI
func AuthMainHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	w.WriteHeader(http.StatusOK)
	w.Write([]byte(htmlIndex))
}

// AuthGithubHandler for requesting oauth access from Github
func AuthGithubHandler(w http.ResponseWriter, r *http.Request) {
	auth.HydrateOAuthConfig(oauthConf)
	url := oauthConf.AuthCodeURL(oauthStateString, oauth2.AccessTypeOnline)
	http.Redirect(w, r, url, http.StatusTemporaryRedirect)
}

// AuthGithubCallbackHandler for handling oauth access response from Github
func AuthGithubCallbackHandler(w http.ResponseWriter, r *http.Request) {
	auth.HydrateOAuthConfig(oauthConf)
	oAuthCallbackForm := new(auth.OAuthCallbackForm)
	errs := binding.Bind(r, oAuthCallbackForm)
	if errs.Handle(w) {
		return
	}
	if oAuthCallbackForm.State != oauthStateString {
		log.Printf("invalid oauth state, expected '%s', got '%s'\n", oauthStateString, oAuthCallbackForm.State)
		http.Error(w, "invalid oauth state", http.StatusBadRequest)
		return
	}
	token, err := oauthConf.Exchange(oauth2.NoContext, oAuthCallbackForm.Code)
	if err != nil {
		log.Printf("oauthConf.Exchange() failed with '%s'\n", err)
		http.Error(w, "there was an error when establishing an oauth exchange", http.StatusBadRequest)
		return
	}

	oauthClient := oauthConf.Client(oauth2.NoContext, token)
	client := githuboauth.NewClient(oauthClient)
	user, _, err := client.Users.Get("")
	if err != nil {
		log.Printf("client.Users.Get() failed with '%s'\n", err)
		http.Error(w, "there was an error while attempting to get user details", http.StatusBadGateway)
		return
	}
	db, err := database.Connect()
	defer db.Close()
	if err != nil {
		log.Printf("Database error: '%s'\n", err)
		http.Error(w, "there was an error while connecting to the database", http.StatusInternalServerError)
		return
	}

	if auth.IsFirstUser(db) {
		auth.CreateNewGithubUser(db, user, token.AccessToken)
		http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
		return
	} else if auth.GithubUserAllowed(db, *user.Login) {
		// @todo check that non-required attributes exist
		brizoUser := auth.User{
			Username:       *user.Login,
			Name:           *user.Name,
			Email:          *user.Email,
			GithubUsername: *user.Login,
			GithubToken:    token.AccessToken,
		}
		success, err := auth.UpdateUser(db, &brizoUser)
		if success == false {
			log.Printf("failed to update user '%s' because '%s'\n", *user.Login, err)
			// @todo update to correct status code
			http.Error(w, "there was an error when updating the user", http.StatusInternalServerError)
			return
		}
		http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
		return
	}
	// @todo user is not allowed
	log.Printf("'%s' attempted to authenticate without an account\n", *user.Login)
	http.Error(w, "user has not been created prior to authentication", http.StatusForbidden)
}
<commit_msg>added CreateToken to authentication flow<commit_after>package web

import (
	"log"
	"net/http"

	"github.com/generationtux/brizo/auth"
	"github.com/generationtux/brizo/database"
	githuboauth "github.com/google/go-github/github"
	"github.com/mholt/binding"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/github"
)

const htmlAddUser = `<!doctype html>
<form action="/api/v1/users" method="post">
  Add user:
  <input type="text" name="username">
</form>

`

// AuthAddNewUser @todo move to JS UI
func AuthAddNewUser(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	w.WriteHeader(http.StatusOK)
	w.Write([]byte(htmlAddUser))
}

const htmlIndex = `
Log in with GitHub

`

var (
	oauthConf = &oauth2.Config{
		ClientID:     "",
		ClientSecret: "",
		Scopes:       []string{"user", "user:email", "repo"},
		Endpoint:     github.Endpoint,
	}
	oauthStateString = auth.GetOAuthStateString()
)

// AuthMainHandler @todo move to JS UI
func AuthMainHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	w.WriteHeader(http.StatusOK)
	w.Write([]byte(htmlIndex))
}

// AuthGithubHandler for requesting oauth access from Github
func AuthGithubHandler(w http.ResponseWriter, r *http.Request) {
	auth.HydrateOAuthConfig(oauthConf)
	url := oauthConf.AuthCodeURL(oauthStateString, oauth2.AccessTypeOnline)
	http.Redirect(w, r, url, http.StatusTemporaryRedirect)
}

// AuthGithubCallbackHandler for handling oauth access response from Github
func AuthGithubCallbackHandler(w http.ResponseWriter, r *http.Request) {
	auth.HydrateOAuthConfig(oauthConf)
	oAuthCallbackForm := new(auth.OAuthCallbackForm)
	errs := binding.Bind(r, oAuthCallbackForm)
	if errs.Handle(w) {
		return
	}
	if oAuthCallbackForm.State != oauthStateString {
		log.Printf("invalid oauth state, expected '%s', got '%s'\n", oauthStateString, oAuthCallbackForm.State)
		http.Error(w, "invalid oauth state", http.StatusBadRequest)
		return
	}
	token, err := oauthConf.Exchange(oauth2.NoContext, oAuthCallbackForm.Code)
	if err != nil {
		log.Printf("oauthConf.Exchange() failed with '%s'\n", err)
		http.Error(w, "there was an error when establishing an oauth exchange", http.StatusBadRequest)
		return
	}

	oauthClient := oauthConf.Client(oauth2.NoContext, token)
	client := githuboauth.NewClient(oauthClient)
	user, _, err := client.Users.Get("")
	if err != nil {
		log.Printf("client.Users.Get() failed with '%s'\n", err)
		http.Error(w, "there was an error while attempting to get user details", http.StatusBadGateway)
		return
	}
	db, err := database.Connect()
	defer db.Close()
	if err != nil {
		log.Printf("Database error: '%s'\n", err)
		http.Error(w, "there was an error while connecting to the database", http.StatusInternalServerError)
		return
	}

	if auth.IsFirstUser(db) {
		user := auth.CreateNewGithubUser(db, user, token.AccessToken)
        token := auth.CreateToken(user)
		http.Redirect(w, r, "/app/auth?token=" + token, http.StatusTemporaryRedirect)
		return
	} else if auth.GithubUserAllowed(db, *user.Login) {
		// @todo check that non-required attributes exist
		brizoUser := auth.User{
			Username:       *user.Login,
			Name:           *user.Name,
			Email:          *user.Email,
			GithubUsername: *user.Login,
			GithubToken:    token.AccessToken,
		}
		success, err := auth.UpdateUser(db, &brizoUser)
		if success == false {
			log.Printf("failed to update user '%s' because '%s'\n", *user.Login, err)
			// @todo update to correct status code
			http.Error(w, "there was an error when updating the user", http.StatusInternalServerError)
			return
		}
        token := auth.CreateToken(&brizoUser)
		http.Redirect(w, r, "/app/auth?token=" + token, http.StatusTemporaryRedirect)
		return
	}
	// @todo user is not allowed
	log.Printf("'%s' attempted to authenticate without an account\n", *user.Login)
	http.Error(w, "user has not been created prior to authentication", http.StatusForbidden)
}
<|endoftext|>


<commit_before>package main
<commit_msg>glob: add matchExp<commit_after>package main

func matchExp(pattern, name string) bool {
	px := 0
	nx := 0
	for px < len(pattern) || nx < len(name) {
		if px < len(pattern) {
			c := pattern[px]
			switch c {
			default: // ordinary character
				if nx < len(name) && name[nx] == c {
					px++
					nx++
					continue
				}
			case '?': // single-character wildcard
				if nx < len(name) {
					px++
					nx++
					continue
				}
			case '*': // zero-or-more-character wildcard
				// Try to match at nx, nx+1, and so on.
				for ; nx <= len(name); nx++ {
					if matchExp(pattern[px+1:], name[nx:]) {
						return true
					}
				}
			}
		}
		// Mismatch.
		return false
	}
	// Matched all of pattern to all of name. Success.
	return true
}
<|endoftext|>