<commit_before>package main

import (
	"bytes"
	"os"
	"regexp"
	"strconv"
	"strings"

	logrus "github.com/Sirupsen/logrus"
	docopt "github.com/docopt/docopt-go"

	"github.com/9seconds/ah/app/commands"
	"github.com/9seconds/ah/app/environments"
	"github.com/9seconds/ah/app/slices"
	"github.com/9seconds/ah/app/utils"
)

const docoptOptions = `ah - A better history.

Ah is a better way to traverse the history of your shell prompts. You can
store an outputs of your commands, you can search with regular expressions
out of box, bookmark commands etc.

You may want to check detailed readme at https://github.com/9seconds/ah

Just a short reminder on possible subcommands:
    - s  - shows extended output from your HISTFILE
    - b  - bookmarks any command you want to have a faster access.
    - e  - executes a command by its bookmark name or history number.
    - t  - traces an output of the command and stores it safely.
    - l  - lists you an output of the command.
    - lb - lists available bookmarks.
    - rb - removes bookmarks.
    - gt - garbage collecting of the traces. Cleans old outputs.
    - gb - garbage collecting of the bookmarks. Swipes out old ones.
    - ad - add command to the list of auto ah'ed
    - ar - remove commands from the list of auto ah'ed.
    - al - list of commands which should be auto ah'ed.
    - at - creates a command to execute using auto tee if possible.

Usage:
    ah [options] s [-z] [-g PATTERN] [<lastNcommands> | <startFromNCommand> <finishByMCommand>]
    ah [options] b <commandNumber> <bookmarkAs>
    ah [options] e [-x] [-y] <commandNumberOrBookMarkName>
    ah [options] t [-x] [-y] [--] <command>...
    ah [options] l <numberOfCommandYouWantToCheck>
    ah [options] lb
    ah [options] rb <bookmarkToRemove>...
    ah [options] (gt | gb) (--keepLatest <keepLatest> | --olderThan <olderThan> | --all)
    ah [options] al
    ah [options] ad [-x] [-y] <command>...
    ah [options] ar <command>...
    ah [options] at <commandToExecute>
    ah (-h | --help)
    ah --version

Options:
    -s SHELL, --shell=SHELL
       Shell flavour you are using.
       By default, ah will do some shallow investigations.
    -f HISTFILE, --histfile=HISTFILE
       The path to a history file.
       By default ah will try to use default history file of your shell.
    -t HISTTIMEFORMAT, --histtimeformat=HISTTIMEFORMAT
       A time format for history output. Will use $HISTTIMEFORMAT by default.
    -d APPDIR, --appdir=APPDIR
       A place where ah has to store its data.
    -m TMPDIR, --tmpdir=TMPDIR
       A temporary place where ah stores an output. Set it only if you need it.
    -g PATTERN, --grep PATTERN
       A pattern to filter command lines. It is regular expression if no -f option is set.
    -y, --tty
       Allocates pseudo-tty is necessary.
    -x, --run-in-real-shell
       Runs a command in real interactive shell.
    -z, --fuzzy
       Interpret -g pattern as fuzzy match string.
    -v, --debug
       Shows a debug log of command execution.`

const version = "ah 0.14"

var validateBookmarkName = utils.CreateRegexp(`^[A-Za-z_]\w*$`)

type executor func(map[string]interface{}, *environments.Environment)

func main() {
	defer func() {
		if exc := recover(); exc != nil {
			utils.Logger.Fatal(exc)
		}
	}()

	arguments, err := docopt.Parse(docoptOptions, nil, true, version, false)
	if err != nil {
		panic(err)
	}

	if arguments["--debug"].(bool) {
		utils.EnableLogging()
	} else {
		utils.DisableLogging()
	}
	utils.Logger.WithField("arguments", arguments).Info("Parsed arguments")

	defaultEnv := environments.MakeDefaultEnvironment()
	cmdLineEnv := new(environments.Environment)
	configEnv, err := defaultEnv.ReadFromConfig()
	if err != nil {
		utils.Logger.WithField("error", err).Warn("Cannot read config file")
	}

	argShell := arguments["--shell"]
	if argShell != nil {
		cmdLineEnv.Shell = argShell.(string)
	}

	argHistFile := arguments["--histfile"]
	if argHistFile != nil {
		cmdLineEnv.HistFile = argHistFile.(string)
	}

	argHistTimeFormat := arguments["--histtimeformat"]
	if argHistTimeFormat != nil {
		cmdLineEnv.HistTimeFormat = argHistTimeFormat.(string)
	}

	argAppDir := arguments["--appdir"]
	if argAppDir != nil {
		cmdLineEnv.AppDir = argAppDir.(string)
	}

	argTmpDir := arguments["--tmpdir"]
	if argTmpDir != nil {
		cmdLineEnv.TmpDir = argTmpDir.(string)
	}

	utils.Logger.WithFields(logrus.Fields{
		"default":    defaultEnv,
		"config":     configEnv,
		"cmdLineEnv": cmdLineEnv,
	}).Debug("Environments")

	env := environments.MergeEnvironments(defaultEnv, configEnv, cmdLineEnv)
	utils.Logger.WithField("result env", env).Debug("Ready to start")

	utils.Logger.WithFields(logrus.Fields{
		"error": os.MkdirAll(env.TracesDir, 0777),
	}).Info("Create traces dir")
	utils.Logger.WithFields(logrus.Fields{
		"error": os.MkdirAll(env.BookmarksDir, 0777),
	}).Info("Create bookmarks dir")
	utils.Logger.WithFields(logrus.Fields{
		"error": os.MkdirAll(env.TmpDir, 0777),
	}).Info("Create create temporary dir")

	var exec executor
	switch {
	case arguments["t"].(bool):
		utils.Logger.Info("Execute command 'tee'")
		exec = executeTee
	case arguments["s"].(bool):
		utils.Logger.Info("Execute command 'show'")
		exec = executeShow
	case arguments["l"].(bool):
		utils.Logger.Info("Execute command 'listTrace'")
		exec = executeListTrace
	case arguments["b"].(bool):
		utils.Logger.Info("Execute command 'listTrace'")
		exec = executeListTrace
	case arguments["e"].(bool):
		utils.Logger.Info("Execute command 'execute'")
		exec = executeExec
	case arguments["lb"].(bool):
		utils.Logger.Info("Execute command 'listBookmarks'")
		exec = executeListBookmarks
	case arguments["rb"].(bool):
		utils.Logger.Info("Execute command 'removeBookmarks'")
		exec = executeRemoveBookmarks
	case arguments["gt"].(bool) || arguments["gb"].(bool):
		utils.Logger.Info("Execute command 'gc'")
		exec = executeGC
	case arguments["al"].(bool):
		utils.Logger.Info("Execute command 'al'")
		exec = executeAl
	case arguments["ad"].(bool):
		utils.Logger.Info("Execute command 'ad'")
		exec = executeAd
	case arguments["ar"].(bool):
		utils.Logger.Info("Execute command 'ar'")
		exec = executeAr
	case arguments["at"].(bool):
		utils.Logger.Info("Execute command 'at'")
		exec = executeAt
	default:
		utils.Logger.Panic("Unknown command. Please be more precise")
		return
	}
	exec(arguments, env)
}

func executeTee(arguments map[string]interface{}, env *environments.Environment) {
	cmds := arguments["<command>"].([]string)
	cmd := strings.Join(cmds, " ")
	tty := arguments["--tty"].(bool)
	interactive := arguments["--run-in-real-shell"].(bool)

	utils.Logger.WithFields(logrus.Fields{
		"command":     cmd,
		"pseudo-tty":  tty,
		"interactive": interactive,
	}).Info("Arguments of 'tee'")

	commands.Tee(cmd, interactive, tty, env)
}

func executeShow(arguments map[string]interface{}, env *environments.Environment) {
	slice, err := slices.ExtractSlice(
		arguments["<lastNcommands>"],
		arguments["<startFromNCommand>"],
		arguments["<finishByMCommand>"])
	if err != nil {
		utils.Logger.Panic(err)
	}

	var filter *utils.Regexp
	if arguments["--grep"] != nil {
		query := arguments["--grep"].(string)
		if arguments["--fuzzy"].(bool) {
			regex := new(bytes.Buffer)
			for _, character := range query {
				regex.WriteString(".*?")
				regex.WriteString(regexp.QuoteMeta(string(character)))
			}
			regex.WriteString(".*?")
			query = regex.String()
		}
		filter = utils.CreateRegexp(query)
	}

	utils.Logger.WithFields(logrus.Fields{
		"slice":  slice,
		"filter": filter,
	}).Info("Arguments of 'show'")

	commands.Show(slice, filter, env)
}

func executeListTrace(arguments map[string]interface{}, env *environments.Environment) {
	cmd := arguments["<numberOfCommandYouWantToCheck>"].(string)

	utils.Logger.WithFields(logrus.Fields{
		"cmd": cmd,
	}).Info("Arguments of 'listTrace'")

	commands.ListTrace(cmd, env)
}

func executeBookmark(arguments map[string]interface{}, env *environments.Environment) {
	number, err := strconv.Atoi(arguments["<commandNumber>"].(string))
	if err != nil {
		utils.Logger.Panicf("Cannot understand command number: %d", number)
	}

	bookmarkAs := arguments["<bookmarkAs>"].(string)
	if !validateBookmarkName.Match(bookmarkAs) {
		utils.Logger.Panic("Incorrect bookmark name!")
	}

	utils.Logger.WithFields(logrus.Fields{
		"commandNumber": number,
		"bookmarkAs":    bookmarkAs,
	}).Info("Arguments of 'bookmark'")

	commands.Bookmark(number, bookmarkAs, env)
}

func executeExec(arguments map[string]interface{}, env *environments.Environment) {
	commandNumberOrBookMarkName := arguments["<commandNumberOrBookMarkName>"].(string)
	tty := arguments["--tty"].(bool)
	interactive := arguments["--run-in-real-shell"].(bool)

	utils.Logger.WithFields(logrus.Fields{
		"commandNumberOrBookMarkName": commandNumberOrBookMarkName,
		"tty":         tty,
		"interactive": interactive,
	}).Info("Arguments of 'bookmark'")

	commandNumber, err := strconv.Atoi(commandNumberOrBookMarkName)
	switch {
	case err == nil:
		utils.Logger.Info("Execute command number ", commandNumber)
		commands.ExecuteCommandNumber(commandNumber, interactive, tty, env)
	case validateBookmarkName.Match(commandNumberOrBookMarkName):
		utils.Logger.Info("Execute bookmark ", commandNumberOrBookMarkName)
		commands.ExecuteBookmark(commandNumberOrBookMarkName, interactive, tty, env)
	default:
		utils.Logger.Panic("Incorrect bookmark name! It should be started with alphabet letter, and alphabet or digits after!")
	}
}

func executeGC(arguments map[string]interface{}, env *environments.Environment) {
	gcDir := commands.GcTracesDir
	if arguments["gb"].(bool) {
		gcDir = commands.GcBookmarksDir
	}

	var gcType commands.GcType
	stringParam := "1"
	switch {
	case arguments["--keepLatest"].(bool):
		gcType = commands.GcKeepLatest
		stringParam = arguments["<keepLatest>"].(string)
	case arguments["--olderThan"].(bool):
		gcType = commands.GcOlderThan
		stringParam = arguments["<keepLatest>"].(string)
	case arguments["--all"].(bool):
		gcType = commands.GcAll
	default:
		utils.Logger.Panic("Unknown subcommand command")
	}

	param, err := strconv.Atoi(stringParam)
	if err != nil {
		utils.Logger.Panic(err)
	} else if param <= 0 {
		utils.Logger.Panic("Parameter of garbage collection has to be > 0")
	}

	utils.Logger.WithFields(logrus.Fields{
		"gcType": gcType,
		"param":  param,
	}).Info("Arguments")

	commands.GC(gcType, gcDir, param, env)
}

func executeListBookmarks(_ map[string]interface{}, env *environments.Environment) {
	commands.ListBookmarks(env)
}

func executeRemoveBookmarks(arguments map[string]interface{}, env *environments.Environment) {
	bookmarks, ok := arguments["<bookmarkToRemove>"].([]string)
	if !ok || bookmarks == nil || len(bookmarks) == 0 {
		utils.Logger.Info("Nothing to do here")
		return
	}

	for _, bookmark := range bookmarks {
		if !validateBookmarkName.Match(bookmark) {
			utils.Logger.WithFields(logrus.Fields{
				"bookmark": bookmark,
			}).Panicf("Bookmark name %s is invalid", bookmark)
		}
	}

	commands.RemoveBookmarks(bookmarks, env)
}

func executeAd(arguments map[string]interface{}, env *environments.Environment) {
	cmds := arguments["<command>"].([]string)
	tty := arguments["--tty"].(bool)
	interactive := arguments["--run-in-real-shell"].(bool)

	utils.Logger.WithFields(logrus.Fields{
		"commands":    cmds,
		"tty":         tty,
		"interactive": interactive,
	}).Info("Arguments")

	commands.AutoTeeAdd(cmds, tty, interactive, env)
}

func executeAl(_ map[string]interface{}, env *environments.Environment) {
	commands.AutoTeeList(env)
}

func executeAr(arguments map[string]interface{}, env *environments.Environment) {
	cmds := arguments["<command>"].([]string)

	utils.Logger.WithFields(logrus.Fields{
		"commands": cmds,
	}).Info("Arguments")

	commands.AutoTeeRemove(cmds, env)
}

func executeAt(arguments map[string]interface{}, env *environments.Environment) {
	cmd := arguments["<commandToExecute>"].(string)

	utils.Logger.WithFields(logrus.Fields{
		"cmd": cmd,
	}).Info("Arguments")

	commands.AutoTeeCreate(cmd, env)
}
<commit_msg>Bump version<commit_after>package main

import (
	"bytes"
	"os"
	"regexp"
	"strconv"
	"strings"

	logrus "github.com/Sirupsen/logrus"
	docopt "github.com/docopt/docopt-go"

	"github.com/9seconds/ah/app/commands"
	"github.com/9seconds/ah/app/environments"
	"github.com/9seconds/ah/app/slices"
	"github.com/9seconds/ah/app/utils"
)

const docoptOptions = `ah - A better history.

Ah is a better way to traverse the history of your shell prompts. You can
store an outputs of your commands, you can search with regular expressions
out of box, bookmark commands etc.

You may want to check detailed readme at https://github.com/9seconds/ah

Just a short reminder on possible subcommands:
    - s  - shows extended output from your HISTFILE
    - b  - bookmarks any command you want to have a faster access.
    - e  - executes a command by its bookmark name or history number.
    - t  - traces an output of the command and stores it safely.
    - l  - lists you an output of the command.
    - lb - lists available bookmarks.
    - rb - removes bookmarks.
    - gt - garbage collecting of the traces. Cleans old outputs.
    - gb - garbage collecting of the bookmarks. Swipes out old ones.
    - ad - add command to the list of auto ah'ed
    - ar - remove commands from the list of auto ah'ed.
    - al - list of commands which should be auto ah'ed.
    - at - creates a command to execute using auto tee if possible.

Usage:
    ah [options] s [-z] [-g PATTERN] [<lastNcommands> | <startFromNCommand> <finishByMCommand>]
    ah [options] b <commandNumber> <bookmarkAs>
    ah [options] e [-x] [-y] <commandNumberOrBookMarkName>
    ah [options] t [-x] [-y] [--] <command>...
    ah [options] l <numberOfCommandYouWantToCheck>
    ah [options] lb
    ah [options] rb <bookmarkToRemove>...
    ah [options] (gt | gb) (--keepLatest <keepLatest> | --olderThan <olderThan> | --all)
    ah [options] al
    ah [options] ad [-x] [-y] <command>...
    ah [options] ar <command>...
    ah [options] at <commandToExecute>
    ah (-h | --help)
    ah --version

Options:
    -s SHELL, --shell=SHELL
       Shell flavour you are using.
       By default, ah will do some shallow investigations.
    -f HISTFILE, --histfile=HISTFILE
       The path to a history file.
       By default ah will try to use default history file of your shell.
    -t HISTTIMEFORMAT, --histtimeformat=HISTTIMEFORMAT
       A time format for history output. Will use $HISTTIMEFORMAT by default.
    -d APPDIR, --appdir=APPDIR
       A place where ah has to store its data.
    -m TMPDIR, --tmpdir=TMPDIR
       A temporary place where ah stores an output. Set it only if you need it.
    -g PATTERN, --grep PATTERN
       A pattern to filter command lines. It is regular expression if no -f option is set.
    -y, --tty
       Allocates pseudo-tty is necessary.
    -x, --run-in-real-shell
       Runs a command in real interactive shell.
    -z, --fuzzy
       Interpret -g pattern as fuzzy match string.
    -v, --debug
       Shows a debug log of command execution.`

const version = "ah 0.14.1"

var validateBookmarkName = utils.CreateRegexp(`^[A-Za-z_]\w*$`)

type executor func(map[string]interface{}, *environments.Environment)

func main() {
	defer func() {
		if exc := recover(); exc != nil {
			utils.Logger.Fatal(exc)
		}
	}()

	arguments, err := docopt.Parse(docoptOptions, nil, true, version, false)
	if err != nil {
		panic(err)
	}

	if arguments["--debug"].(bool) {
		utils.EnableLogging()
	} else {
		utils.DisableLogging()
	}
	utils.Logger.WithField("arguments", arguments).Info("Parsed arguments")

	defaultEnv := environments.MakeDefaultEnvironment()
	cmdLineEnv := new(environments.Environment)
	configEnv, err := defaultEnv.ReadFromConfig()
	if err != nil {
		utils.Logger.WithField("error", err).Warn("Cannot read config file")
	}

	argShell := arguments["--shell"]
	if argShell != nil {
		cmdLineEnv.Shell = argShell.(string)
	}

	argHistFile := arguments["--histfile"]
	if argHistFile != nil {
		cmdLineEnv.HistFile = argHistFile.(string)
	}

	argHistTimeFormat := arguments["--histtimeformat"]
	if argHistTimeFormat != nil {
		cmdLineEnv.HistTimeFormat = argHistTimeFormat.(string)
	}

	argAppDir := arguments["--appdir"]
	if argAppDir != nil {
		cmdLineEnv.AppDir = argAppDir.(string)
	}

	argTmpDir := arguments["--tmpdir"]
	if argTmpDir != nil {
		cmdLineEnv.TmpDir = argTmpDir.(string)
	}

	utils.Logger.WithFields(logrus.Fields{
		"default":    defaultEnv,
		"config":     configEnv,
		"cmdLineEnv": cmdLineEnv,
	}).Debug("Environments")

	env := environments.MergeEnvironments(defaultEnv, configEnv, cmdLineEnv)
	utils.Logger.WithField("result env", env).Debug("Ready to start")

	utils.Logger.WithFields(logrus.Fields{
		"error": os.MkdirAll(env.TracesDir, 0777),
	}).Info("Create traces dir")
	utils.Logger.WithFields(logrus.Fields{
		"error": os.MkdirAll(env.BookmarksDir, 0777),
	}).Info("Create bookmarks dir")
	utils.Logger.WithFields(logrus.Fields{
		"error": os.MkdirAll(env.TmpDir, 0777),
	}).Info("Create create temporary dir")

	var exec executor
	switch {
	case arguments["t"].(bool):
		utils.Logger.Info("Execute command 'tee'")
		exec = executeTee
	case arguments["s"].(bool):
		utils.Logger.Info("Execute command 'show'")
		exec = executeShow
	case arguments["l"].(bool):
		utils.Logger.Info("Execute command 'listTrace'")
		exec = executeListTrace
	case arguments["b"].(bool):
		utils.Logger.Info("Execute command 'listTrace'")
		exec = executeListTrace
	case arguments["e"].(bool):
		utils.Logger.Info("Execute command 'execute'")
		exec = executeExec
	case arguments["lb"].(bool):
		utils.Logger.Info("Execute command 'listBookmarks'")
		exec = executeListBookmarks
	case arguments["rb"].(bool):
		utils.Logger.Info("Execute command 'removeBookmarks'")
		exec = executeRemoveBookmarks
	case arguments["gt"].(bool) || arguments["gb"].(bool):
		utils.Logger.Info("Execute command 'gc'")
		exec = executeGC
	case arguments["al"].(bool):
		utils.Logger.Info("Execute command 'al'")
		exec = executeAl
	case arguments["ad"].(bool):
		utils.Logger.Info("Execute command 'ad'")
		exec = executeAd
	case arguments["ar"].(bool):
		utils.Logger.Info("Execute command 'ar'")
		exec = executeAr
	case arguments["at"].(bool):
		utils.Logger.Info("Execute command 'at'")
		exec = executeAt
	default:
		utils.Logger.Panic("Unknown command. Please be more precise")
		return
	}
	exec(arguments, env)
}

func executeTee(arguments map[string]interface{}, env *environments.Environment) {
	cmds := arguments["<command>"].([]string)
	cmd := strings.Join(cmds, " ")
	tty := arguments["--tty"].(bool)
	interactive := arguments["--run-in-real-shell"].(bool)

	utils.Logger.WithFields(logrus.Fields{
		"command":     cmd,
		"pseudo-tty":  tty,
		"interactive": interactive,
	}).Info("Arguments of 'tee'")

	commands.Tee(cmd, interactive, tty, env)
}

func executeShow(arguments map[string]interface{}, env *environments.Environment) {
	slice, err := slices.ExtractSlice(
		arguments["<lastNcommands>"],
		arguments["<startFromNCommand>"],
		arguments["<finishByMCommand>"])
	if err != nil {
		utils.Logger.Panic(err)
	}

	var filter *utils.Regexp
	if arguments["--grep"] != nil {
		query := arguments["--grep"].(string)
		if arguments["--fuzzy"].(bool) {
			regex := new(bytes.Buffer)
			for _, character := range query {
				regex.WriteString(".*?")
				regex.WriteString(regexp.QuoteMeta(string(character)))
			}
			regex.WriteString(".*?")
			query = regex.String()
		}
		filter = utils.CreateRegexp(query)
	}

	utils.Logger.WithFields(logrus.Fields{
		"slice":  slice,
		"filter": filter,
	}).Info("Arguments of 'show'")

	commands.Show(slice, filter, env)
}

func executeListTrace(arguments map[string]interface{}, env *environments.Environment) {
	cmd := arguments["<numberOfCommandYouWantToCheck>"].(string)

	utils.Logger.WithFields(logrus.Fields{
		"cmd": cmd,
	}).Info("Arguments of 'listTrace'")

	commands.ListTrace(cmd, env)
}

func executeBookmark(arguments map[string]interface{}, env *environments.Environment) {
	number, err := strconv.Atoi(arguments["<commandNumber>"].(string))
	if err != nil {
		utils.Logger.Panicf("Cannot understand command number: %d", number)
	}

	bookmarkAs := arguments["<bookmarkAs>"].(string)
	if !validateBookmarkName.Match(bookmarkAs) {
		utils.Logger.Panic("Incorrect bookmark name!")
	}

	utils.Logger.WithFields(logrus.Fields{
		"commandNumber": number,
		"bookmarkAs":    bookmarkAs,
	}).Info("Arguments of 'bookmark'")

	commands.Bookmark(number, bookmarkAs, env)
}

func executeExec(arguments map[string]interface{}, env *environments.Environment) {
	commandNumberOrBookMarkName := arguments["<commandNumberOrBookMarkName>"].(string)
	tty := arguments["--tty"].(bool)
	interactive := arguments["--run-in-real-shell"].(bool)

	utils.Logger.WithFields(logrus.Fields{
		"commandNumberOrBookMarkName": commandNumberOrBookMarkName,
		"tty":         tty,
		"interactive": interactive,
	}).Info("Arguments of 'bookmark'")

	commandNumber, err := strconv.Atoi(commandNumberOrBookMarkName)
	switch {
	case err == nil:
		utils.Logger.Info("Execute command number ", commandNumber)
		commands.ExecuteCommandNumber(commandNumber, interactive, tty, env)
	case validateBookmarkName.Match(commandNumberOrBookMarkName):
		utils.Logger.Info("Execute bookmark ", commandNumberOrBookMarkName)
		commands.ExecuteBookmark(commandNumberOrBookMarkName, interactive, tty, env)
	default:
		utils.Logger.Panic("Incorrect bookmark name! It should be started with alphabet letter, and alphabet or digits after!")
	}
}

func executeGC(arguments map[string]interface{}, env *environments.Environment) {
	gcDir := commands.GcTracesDir
	if arguments["gb"].(bool) {
		gcDir = commands.GcBookmarksDir
	}

	var gcType commands.GcType
	stringParam := "1"
	switch {
	case arguments["--keepLatest"].(bool):
		gcType = commands.GcKeepLatest
		stringParam = arguments["<keepLatest>"].(string)
	case arguments["--olderThan"].(bool):
		gcType = commands.GcOlderThan
		stringParam = arguments["<keepLatest>"].(string)
	case arguments["--all"].(bool):
		gcType = commands.GcAll
	default:
		utils.Logger.Panic("Unknown subcommand command")
	}

	param, err := strconv.Atoi(stringParam)
	if err != nil {
		utils.Logger.Panic(err)
	} else if param <= 0 {
		utils.Logger.Panic("Parameter of garbage collection has to be > 0")
	}

	utils.Logger.WithFields(logrus.Fields{
		"gcType": gcType,
		"param":  param,
	}).Info("Arguments")

	commands.GC(gcType, gcDir, param, env)
}

func executeListBookmarks(_ map[string]interface{}, env *environments.Environment) {
	commands.ListBookmarks(env)
}

func executeRemoveBookmarks(arguments map[string]interface{}, env *environments.Environment) {
	bookmarks, ok := arguments["<bookmarkToRemove>"].([]string)
	if !ok || bookmarks == nil || len(bookmarks) == 0 {
		utils.Logger.Info("Nothing to do here")
		return
	}

	for _, bookmark := range bookmarks {
		if !validateBookmarkName.Match(bookmark) {
			utils.Logger.WithFields(logrus.Fields{
				"bookmark": bookmark,
			}).Panicf("Bookmark name %s is invalid", bookmark)
		}
	}

	commands.RemoveBookmarks(bookmarks, env)
}

func executeAd(arguments map[string]interface{}, env *environments.Environment) {
	cmds := arguments["<command>"].([]string)
	tty := arguments["--tty"].(bool)
	interactive := arguments["--run-in-real-shell"].(bool)

	utils.Logger.WithFields(logrus.Fields{
		"commands":    cmds,
		"tty":         tty,
		"interactive": interactive,
	}).Info("Arguments")

	commands.AutoTeeAdd(cmds, tty, interactive, env)
}

func executeAl(_ map[string]interface{}, env *environments.Environment) {
	commands.AutoTeeList(env)
}

func executeAr(arguments map[string]interface{}, env *environments.Environment) {
	cmds := arguments["<command>"].([]string)

	utils.Logger.WithFields(logrus.Fields{
		"commands": cmds,
	}).Info("Arguments")

	commands.AutoTeeRemove(cmds, env)
}

func executeAt(arguments map[string]interface{}, env *environments.Environment) {
	cmd := arguments["<commandToExecute>"].(string)

	utils.Logger.WithFields(logrus.Fields{
		"cmd": cmd,
	}).Info("Arguments")

	commands.AutoTeeCreate(cmd, env)
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"runtime"

	"github.com/Sirupsen/logrus"
	"github.com/kleister/kleister-api/cmd"
	"github.com/kleister/kleister-api/config"
	"github.com/urfave/cli"

	_ "github.com/joho/godotenv/autoload"
)

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	app := cli.NewApp()
	app.Name = "kleister"
	app.Version = config.Version
	app.Author = "Thomas Boerger <thomas@webhippie.de>"
	app.Usage = "Manage mod packs for Minecraft"

	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:        "debug",
			Usage:       "Activate debug information",
			EnvVar:      "KLEISTER_DEBUG",
			Destination: &config.Debug,
		},
	}

	app.Before = func(c *cli.Context) error {
		logrus.SetOutput(os.Stdout)

		if config.Debug {
			logrus.SetLevel(logrus.DebugLevel)
		} else {
			logrus.SetLevel(logrus.InfoLevel)
		}

		return nil
	}

	app.Commands = []cli.Command{
		cmd.Server(),
	}

	cli.HelpFlag = cli.BoolFlag{
		Name:  "help, h",
		Usage: "Show the help, so what you see now",
	}

	cli.VersionFlag = cli.BoolFlag{
		Name:  "version, v",
		Usage: "Print the current version of that tool",
	}

	if err := app.Run(os.Args); err != nil {
		logrus.Error(err)
		os.Exit(1)
	}
}
<commit_msg>Integrated autoloading env from KLEISTER_ENV_FILE<commit_after>package main

import (
	"os"
	"runtime"

	"github.com/Sirupsen/logrus"
	"github.com/joho/godotenv"
	"github.com/kleister/kleister-api/cmd"
	"github.com/kleister/kleister-api/config"
	"github.com/urfave/cli"
)

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	if env := os.Getenv("KLEISTER_ENV_FILE"); env != "" {
		godotenv.Load(env)
	}

	app := cli.NewApp()
	app.Name = "kleister"
	app.Version = config.Version
	app.Author = "Thomas Boerger <thomas@webhippie.de>"
	app.Usage = "Manage mod packs for Minecraft"

	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:        "debug",
			Usage:       "Activate debug information",
			EnvVar:      "KLEISTER_DEBUG",
			Destination: &config.Debug,
		},
	}

	app.Before = func(c *cli.Context) error {
		logrus.SetOutput(os.Stdout)

		if config.Debug {
			logrus.SetLevel(logrus.DebugLevel)
		} else {
			logrus.SetLevel(logrus.InfoLevel)
		}

		return nil
	}

	app.Commands = []cli.Command{
		cmd.Server(),
	}

	cli.HelpFlag = cli.BoolFlag{
		Name:  "help, h",
		Usage: "Show the help, so what you see now",
	}

	cli.VersionFlag = cli.BoolFlag{
		Name:  "version, v",
		Usage: "Print the current version of that tool",
	}

	if err := app.Run(os.Args); err != nil {
		logrus.Error(err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/emicklei/go-restful"
	"github.com/garyburd/redigo/redis"
	"github.com/gographics/imagick/imagick"
)

// https://github.com/gographics/imagick
// https://github.com/nfnt/resize
// sudo port install pkgconfig
// sudo port install imagemagick
// alt: https://github.com/maddox/magick-installer/blob/master/magick-installer.sh
// http://www.graphicsmagick.org/benchmarks.html

// convert --version

type ImageResizer struct {
	weedMasterHostPort string
	redisHostPort      string
	redisConn          redis.Conn
	hosts              map[string]string
}

// {"locations":[{"publicUrl":"node5.kluster.local.nl.bol.com:8765","url":"localhost:8765"}]}

type WeedLookUp struct {
	Locations []struct {
		PublicUrl string `json:"publicUrl"`
		Url       string `json:"url"`
	} `json:"locations"`
}

func (i ImageResizer) AddWebService() {
	ws := new(restful.WebService)
	ws.Consumes("*/*")
	ws.Produces("image/jpeg;image/png;image/webp")
	ws.Route(ws.GET("/images/{id}").To(i.resizeImagick))
	restful.Add(ws)
}

func (i *ImageResizer) reconnectRedis() {
	i.disconnectRedis()
	log.Printf("Connecting to Redis on %s\n", i.redisHostPort)
	c, err := redis.Dial("tcp", i.redisHostPort)
	if err != nil {
		log.Fatal(err)
	}
	i.redisConn = c
}

func (i *ImageResizer) disconnectRedis() {
	if i.redisConn != nil {
		i.redisConn.Close()
		i.redisConn = nil
	}
}

func (i ImageResizer) lookupUrl(id string) string {
	// 4,4ebc1e7836ea
	parts := strings.Split(id, ",")
	volume := parts[0]
	host, ok := i.hosts[volume]
	if !ok {
		resp, err := http.Get(fmt.Sprintf("http://%s/dir/lookup?volumeId=%s", i.weedMasterHostPort, volume))
		if err != nil {
			return ""
		}
		defer resp.Body.Close()
		lookup := WeedLookUp{}
		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return ""
		}
		json.Unmarshal(data, &lookup)
		host = lookup.Locations[0].PublicUrl
		i.hosts[volume] = host
	}
	return fmt.Sprintf("http://%s/%s", host, id)
}

func (i ImageResizer) resizeImagick(req *restful.Request, resp *restful.Response) {
	now := time.Now()
	var err error
	id := req.PathParameter("id")
	query_width := req.QueryParameter("w")
	if len(query_width) == 0 {
		query_width = "1000"
	}
	result_width, err := strconv.Atoi(query_width)
	if err != nil {
		resp.WriteErrorString(500, "Cannot convert w:"+err.Error())
		return
	}

	mw := imagick.NewMagickWand()
	// Schedule cleanup
	defer mw.Destroy()

	reply, err := i.redisConn.Do("GET", id)
	if err != nil {
		resp.WriteErrorString(500, "Redis GET failed:"+err.Error())
		return
	}
	if reply == nil {
		resp.WriteErrorString(404, "Redis says: no such id:"+id)
		return
	}
	fid := string(reply.([]byte))
	url := i.lookupUrl(fid)

	if len(url) == 0 {
		resp.WriteErrorString(500, "Volume lookup failed")
		return
	}
	log.Printf("id:%s -> url:%s", id, url)

	err = mw.ReadImage(url)
	if err != nil {
		resp.WriteErrorString(500, "Read image failed:"+err.Error())
		return
	}
	// Get original logo size
	width := mw.GetImageWidth()
	height := mw.GetImageHeight()
	ratio := float64(height) / float64(width)

	// Calculate half the size
	hWidth := uint(result_width)
	hHeight := uint(float64(result_width) * ratio)

	// Resize the image using the Lanczos filter
	// The blur factor is a float, where > 1 is blurry, < 1 is sharp
	err = mw.ResizeImage(hWidth, hHeight, imagick.FILTER_LANCZOS, 0.8)
	if err != nil {
		resp.WriteErrorString(500, "Resize image failed:"+err.Error())
		return
	}

	// Set the compression quality to 95 (high quality = low compression)
	err = mw.SetImageCompressionQuality(95)
	if err != nil {
		resp.WriteErrorString(500, "Set Compression failed:"+err.Error())
		return
	}

	resp.Header().Set("Content-Type", "image/webp")
	err = mw.SetImageFormat("webp")
	if err != nil {
		resp.WriteErrorString(500, "Set image format failed:"+err.Error())
		return
	}

	data := mw.GetImagesBlob()
	_, err = resp.ResponseWriter.Write(data)
	if err != nil {
		resp.WriteErrorString(500, err.Error())
		return
	}

	log.Printf("resized %s (%s) to width=%s in %v", id, fid, query_width, (time.Now().Sub(now)))
}

func main() {
	imagick.Initialize()
	// Schedule cleanup
	defer imagick.Terminate()

	resizer := ImageResizer{
		redisHostPort:      "10.10.135.91:6379",
		weedMasterHostPort: "node5.kluster.local.nl.bol.com:9333",
		hosts:              map[string]string{}}
	resizer.reconnectRedis()
	resizer.AddWebService()
	defer resizer.disconnectRedis()

	log.Printf("start listening on localhost:8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}
<commit_msg>use redis pool<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/emicklei/go-restful"
	"github.com/garyburd/redigo/redis"
	"github.com/gographics/imagick/imagick"
)

// https://github.com/gographics/imagick
// https://github.com/nfnt/resize
// sudo port install pkgconfig
// sudo port install imagemagick
// alt: https://github.com/maddox/magick-installer/blob/master/magick-installer.sh
// http://www.graphicsmagick.org/benchmarks.html

// convert --version

type ImageResizer struct {
	weedMasterHostPort string
	redisPool          *redis.Pool
	redisHostPort      string
	hosts              map[string]string
}

// {"locations":[{"publicUrl":"node5.kluster.local.nl.bol.com:8765","url":"localhost:8765"}]}

type WeedLookUp struct {
	Locations []struct {
		PublicUrl string `json:"publicUrl"`
		Url       string `json:"url"`
	} `json:"locations"`
}

func (i ImageResizer) AddWebService() {
	ws := new(restful.WebService)
	ws.Consumes("*/*")
	ws.Produces("image/jpeg;image/png;image/webp")
	ws.Route(ws.GET("/images/{id}").To(i.resizeImagick))
	restful.Add(ws)
}

func (i ImageResizer) lookupUrl(id string) string {
	// 4,4ebc1e7836ea
	parts := strings.Split(id, ",")
	volume := parts[0]
	host, ok := i.hosts[volume]
	if !ok {
		resp, err := http.Get(fmt.Sprintf("http://%s/dir/lookup?volumeId=%s", i.weedMasterHostPort, volume))
		if err != nil {
			return ""
		}
		defer resp.Body.Close()
		lookup := WeedLookUp{}
		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return ""
		}
		json.Unmarshal(data, &lookup)
		host = lookup.Locations[0].PublicUrl
		i.hosts[volume] = host
	}
	return fmt.Sprintf("http://%s/%s", host, id)
}

func (i ImageResizer) resizeImagick(req *restful.Request, resp *restful.Response) {
	now := time.Now()
	var err error
	id := req.PathParameter("id")
	query_width := req.QueryParameter("w")
	if len(query_width) == 0 {
		query_width = "1000"
	}
	result_width, err := strconv.Atoi(query_width)
	if err != nil {
		resp.WriteErrorString(500, "Cannot convert w:"+err.Error())
		return
	}

	mw := imagick.NewMagickWand()
	// Schedule cleanup
	defer mw.Destroy()

	redisConn := i.redisPool.Get()
	reply, err := redisConn.Do("GET", id)
	if err != nil {
		resp.WriteErrorString(500, "Redis GET failed:"+err.Error())
		return
	}
	defer redisConn.Close()

	if reply == nil {
		resp.WriteErrorString(404, "Redis says: no such id:"+id)
		return
	}
	fid := string(reply.([]byte))
	url := i.lookupUrl(fid)

	if len(url) == 0 {
		resp.WriteErrorString(500, "Volume lookup failed")
		return
	}
	log.Printf("id:%s -> url:%s", id, url)

	err = mw.ReadImage(url)
	if err != nil {
		resp.WriteErrorString(500, "Read image failed:"+err.Error())
		return
	}
	// Get original logo size
	width := mw.GetImageWidth()
	height := mw.GetImageHeight()
	ratio := float64(height) / float64(width)

	// Calculate half the size
	hWidth := uint(result_width)
	hHeight := uint(float64(result_width) * ratio)

	// Resize the image using the Lanczos filter
	// The blur factor is a float, where > 1 is blurry, < 1 is sharp
	err = mw.ResizeImage(hWidth, hHeight, imagick.FILTER_LANCZOS, 0.8)
	if err != nil {
		resp.WriteErrorString(500, "Resize image failed:"+err.Error())
		return
	}

	// Set the compression quality to 95 (high quality = low compression)
	err = mw.SetImageCompressionQuality(95)
	if err != nil {
		resp.WriteErrorString(500, "Set Compression failed:"+err.Error())
		return
	}

	resp.Header().Set("Content-Type", "image/webp")
	err = mw.SetImageFormat("webp")
	if err != nil {
		resp.WriteErrorString(500, "Set image format failed:"+err.Error())
		return
	}

	data := mw.GetImagesBlob()
	_, err = resp.ResponseWriter.Write(data)
	if err != nil {
		resp.WriteErrorString(500, err.Error())
		return
	}

	log.Printf("resized %s (%s) to width=%s in %v", id, fid, query_width, (time.Now().Sub(now)))
}

func main() {
	imagick.Initialize()
	// Schedule cleanup
	defer imagick.Terminate()

	pool := &redis.Pool{
		MaxIdle:     3,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", "10.10.135.91:6379")
			if err != nil {
				return nil, err
			}
			return c, err
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}
	defer pool.Close()

	resizer := ImageResizer{
		redisPool:          pool,
		weedMasterHostPort: "node5.kluster.local.nl.bol.com:9333",
		hosts:              map[string]string{}}

	resizer.AddWebService()

	log.Printf("start listening on localhost:8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}
<|endoftext|>


<commit_before>package bbConvert

import "strings"

var (
	pWrap = true
	style map[string]string
	class string
	p     string
)

//BBtohtml simply takes in a string with BBCode and exports the string converted to html
func BBtohtml(input string) string {
	updatep()
	input = strings.Trim(input, "\n")
	out := bbconv(input)
	out = "\n" + out + "\n"
	if pWrap {
		out = strings.Replace(out, "\n", "
"+p, -1)
		out = strings.TrimPrefix(out, "
")
		out = strings.TrimSuffix(out, p)
		out = strings.Replace(out, p+"
", "", -1)
	} else {
		out = strings.Replace(out, "\n", " ", -1)
	}
	return out
}

//SetWrap determines if the output should have pargraph tags at every newline
//If it's set to false(default) then newlines will be converted to spaces
func SetWrap(tf bool) {
	pWrap = tf
	updatep()
}

//SetStyle allows you to add a particular css style to the wraped paragraph tags
//If you want to undo a style just set it's value to an empty string
//Don't worry about the value having white spaces, it will automagically add
//single quotes if there's whitespace
func SetStyle(css, value string) {
	if value != "" {
		value = strings.TrimSpace(value)
		value = strings.Trim(value, "'")
		value = strings.Trim(value, "\"")
		if style == nil {
			style = make(map[string]string)
		}
		style[css] = value
	} else {
		if style != nil {
			_, ok := style[css]
			if ok {
				delete(style, css)
				if len(style) == 0 {
					style = nil
				}
			}
		}
	}
	updatep()
}

//AddClass allows you to add a particular class to the wraped paragraph tags
func AddClass(cl string) {
	if strings.HasSuffix(class, " ") {
		class += cl
	} else {
		class += " " + cl
	}
	updatep()
}

func updatep() {
	if pWrap {
		p = "
"
	} else {
		p = ""
	}
}
<commit_msg>Added package comment<commit_after>/*Package bbConvert converts BBCode to HTML. I built this for a school project
and have successfully implemented it on a website.
It has support for many BBCode tags and properly handles newlines (\n) and new
paragraphs*/
package bbConvert

import "strings"

var (
	pWrap = true
	style map[string]string
	class string
	p     string
)

//BBtohtml simply takes in a string with BBCode and exports the string converted to html
func BBtohtml(input string) string {
	updatep()
	input = strings.Trim(input, "\n")
	out := bbconv(input)
	out = "\n" + out + "\n"
	if pWrap {
		out = strings.Replace(out, "\n", "
"+p, -1)
		out = strings.TrimPrefix(out, "
")
		out = strings.TrimSuffix(out, p)
		out = strings.Replace(out, p+"
", "", -1)
	} else {
		out = strings.Replace(out, "\n", " ", -1)
	}
	return out
}

//SetWrap determines if the output should have pargraph tags at every newline
//If it's set to false(default) then newlines will be converted to spaces
func SetWrap(tf bool) {
	pWrap = tf
	updatep()
}

//SetStyle allows you to add a particular css style to the wraped paragraph tags
//If you want to undo a style just set it's value to an empty string
//Don't worry about the value having white spaces, it will automagically add
//single quotes if there's whitespace
func SetStyle(css, value string) {
	if value != "" {
		value = strings.TrimSpace(value)
		value = strings.Trim(value, "'")
		value = strings.Trim(value, "\"")
		if style == nil {
			style = make(map[string]string)
		}
		style[css] = value
	} else {
		if style != nil {
			_, ok := style[css]
			if ok {
				delete(style, css)
				if len(style) == 0 {
					style = nil
				}
			}
		}
	}
	updatep()
}

//AddClass allows you to add a particular class to the wraped paragraph tags
func AddClass(cl string) {
	if strings.HasSuffix(class, " ") {
		class += cl
	} else {
		class += " " + cl
	}
	updatep()
}

func updatep() {
	if pWrap {
		p = "
"
	} else {
		p = ""
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"net"
	"os"
	"os/signal"
	"path"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/coreos/go-systemd/daemon"
	log "github.com/coreos/flannel/Godeps/_workspace/src/github.com/golang/glog"

	"github.com/coreos/flannel/backend"
	"github.com/coreos/flannel/pkg/ip"
	"github.com/coreos/flannel/pkg/task"
	"github.com/coreos/flannel/subnet"
	"github.com/coreos/flannel/backend/alloc"
	"github.com/coreos/flannel/backend/udp"
)

type CmdLineOpts struct {
	etcdEndpoints string
	etcdPrefix    string
	help          bool
	version       bool
	ipMasq        bool
	subnetFile    string
	iface         string
}

var opts CmdLineOpts

func init() {
	flag.StringVar(&opts.etcdEndpoints, "etcd-endpoints", "http://127.0.0.1:4001", "a comma-delimited list of etcd endpoints")
	flag.StringVar(&opts.etcdPrefix, "etcd-prefix", "/coreos.com/network", "etcd prefix")
	flag.StringVar(&opts.subnetFile, "subnet-file", "/run/flannel/subnet.env", "filename where env variables (subnet and MTU values) will be written to")
	flag.StringVar(&opts.iface, "iface", "", "interface to use (IP or name) for inter-host communication")
	flag.BoolVar(&opts.ipMasq, "ip-masq", false, "setup IP masquerade rule for traffic destined outside of overlay network")
	flag.BoolVar(&opts.help, "help", false, "print this message")
	flag.BoolVar(&opts.version, "version", false, "print version and exit")
}

// TODO: This is yet another copy (others found in etcd, fleet) -- Pull it out!
// flagsFromEnv parses all registered flags in the given flagset,
// and if they are not already set it attempts to set their values from
// environment variables. Environment variables take the name of the flag but
// are UPPERCASE, have the given prefix, and any dashes are replaced by
// underscores - for example: some-flag => PREFIX_SOME_FLAG
func flagsFromEnv(prefix string, fs *flag.FlagSet) {
	alreadySet := make(map[string]bool)
	fs.Visit(func(f *flag.Flag) {
		alreadySet[f.Name] = true
	})
	fs.VisitAll(func(f *flag.Flag) {
		if !alreadySet[f.Name] {
			key := strings.ToUpper(prefix + "_" + strings.Replace(f.Name, "-", "_", -1))
			val := os.Getenv(key)
			if val != "" {
				fs.Set(f.Name, val)
			}
		}
	})
}

func writeSubnetFile(sn *backend.SubnetDef) error {
	// Write out the first usable IP by incrementing
	// sn.IP by one
	sn.Net.IP += 1

	dir, _ := path.Split(opts.subnetFile)
	os.MkdirAll(dir, 0755)

	f, err := os.Create(opts.subnetFile)
	if err != nil {
		return err
	}
	defer f.Close()

	if _, err = fmt.Fprintf(f, "FLANNEL_SUBNET=%s\n", sn.Net); err != nil {
		return err
	}
	if _, err = fmt.Fprintf(f, "FLANNEL_MTU=%d\n", sn.MTU); err != nil {
		return err
	}
	return nil
}

func lookupIface() (*net.Interface, net.IP, error) {
	var iface *net.Interface
	var ipaddr net.IP
	var err error

	if len(opts.iface) > 0 {
		if ipaddr = net.ParseIP(opts.iface); ipaddr != nil {
			iface, err = ip.GetInterfaceByIP(ipaddr)
			if err != nil {
				return nil, nil, fmt.Errorf("Error looking up interface %s: %s", opts.iface, err)
			}
		} else {
			iface, err = net.InterfaceByName(opts.iface)
			if err != nil {
				return nil, nil, fmt.Errorf("Error looking up interface %s: %s", opts.iface, err)
			}
		}
	} else {
		log.Info("Determining IP address of default interface")
		if iface, err = ip.GetDefaultGatewayIface(); err != nil {
			return nil, nil, fmt.Errorf("Failed to get default interface: %s", err)
		}
	}

	if ipaddr == nil {
		ipaddr, err = ip.GetIfaceIP4Addr(iface)
		if err != nil {
			return nil, nil, fmt.Errorf("Failed to find IPv4 address for interface %s", iface.Name)
		}
	}

	return iface, ipaddr, nil
}

func makeSubnetManager() *subnet.SubnetManager {
	peers := strings.Split(opts.etcdEndpoints, ",")

	for {
		sm, err := subnet.NewSubnetManager(peers, opts.etcdPrefix)
		if err == nil {
			return sm
		}

		log.Error("Failed to create SubnetManager: ", err)
		time.Sleep(time.Second)
	}
}

func newBackend() (backend.Backend, error) {
	sm := makeSubnetManager()
	config := sm.GetConfig()

	var bt struct {
		Type string
	}

	if len(config.Backend) == 0 {
		bt.Type = "udp"
	} else {
		if err := json.Unmarshal(config.Backend, &bt); err != nil {
			return nil, fmt.Errorf("Error decoding Backend property of config: %v", err)
		}
	}

	switch strings.ToLower(bt.Type) {
	case "udp":
		return udp.New(sm, config.Backend), nil
	case "alloc":
		return alloc.New(sm), nil
	default:
		return nil, fmt.Errorf("'%v': unknown backend type", bt.Type)
	}
}

func run(be backend.Backend, exit chan int) {
	var err error
	defer func() {
		if err == nil || err == task.ErrCanceled {
			exit <- 0
		} else {
			log.Error(err)
			exit <- 1
		}
	}()

	iface, ipaddr, err := lookupIface()
	if err != nil {
		return
	}

	if iface.MTU == 0 {
		err = fmt.Errorf("Failed to determine MTU for %s interface", ipaddr)
		return
	}

	log.Infof("Using %s as external interface", ipaddr)

	sn, err := be.Init(iface, ipaddr, opts.ipMasq)
	if err != nil {
		log.Error("Could not init %v backend: %v", be.Name(), err)
		return
	}

	writeSubnetFile(sn)
	daemon.SdNotify("READY=1")

	log.Infof("%s mode initialized", be.Name())
	be.Run()
}

func main() {
	// glog will log to tmp files by default. override so all entries
	// can flow into journald (if running under systemd)
	flag.Set("logtostderr", "true")

	// now parse command line args
	flag.Parse()

	if opts.help {
		fmt.Fprintf(os.Stderr, "Usage: %s [OPTION]...\n", os.Args[0])
		flag.PrintDefaults()
		os.Exit(0)
	}

	if opts.version {
		fmt.Fprintln(os.Stderr, Version)
		os.Exit(0)
	}

	flagsFromEnv("FLANNELD", flag.CommandLine)

	be, err := newBackend()
	if err != nil {
		log.Info(err)
		os.Exit(1)
	}

	// Register for SIGINT and SIGTERM and wait for one of them to arrive
	log.Info("Installing signal handlers")
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, os.Interrupt, syscall.SIGTERM)

	exit := make(chan int)
	go run(be, exit)

	for {
		select {
		case <-sigs:
			// unregister to get default OS nuke behaviour in case we don't exit cleanly
			signal.Stop(sigs)

			log.Info("Exiting...")
			be.Stop()

		case code := <-exit:
			log.Infof("%s mode exited", be.Name())
			os.Exit(code)
		}
	}
}
<commit_msg>log output: fix backend initialization failed error output<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"net"
	"os"
	"os/signal"
	"path"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/coreos/go-systemd/daemon"
	log "github.com/coreos/flannel/Godeps/_workspace/src/github.com/golang/glog"

	"github.com/coreos/flannel/backend"
	"github.com/coreos/flannel/pkg/ip"
	"github.com/coreos/flannel/pkg/task"
	"github.com/coreos/flannel/subnet"
	"github.com/coreos/flannel/backend/alloc"
	"github.com/coreos/flannel/backend/udp"
)

type CmdLineOpts struct {
	etcdEndpoints string
	etcdPrefix    string
	help          bool
	version       bool
	ipMasq        bool
	subnetFile    string
	iface         string
}

var opts CmdLineOpts

func init() {
	flag.StringVar(&opts.etcdEndpoints, "etcd-endpoints", "http://127.0.0.1:4001", "a comma-delimited list of etcd endpoints")
	flag.StringVar(&opts.etcdPrefix, "etcd-prefix", "/coreos.com/network", "etcd prefix")
	flag.StringVar(&opts.subnetFile, "subnet-file", "/run/flannel/subnet.env", "filename where env variables (subnet and MTU values) will be written to")
	flag.StringVar(&opts.iface, "iface", "", "interface to use (IP or name) for inter-host communication")
	flag.BoolVar(&opts.ipMasq, "ip-masq", false, "setup IP masquerade rule for traffic destined outside of overlay network")
	flag.BoolVar(&opts.help, "help", false, "print this message")
	flag.BoolVar(&opts.version, "version", false, "print version and exit")
}

// TODO: This is yet another copy (others found in etcd, fleet) -- Pull it out!
// flagsFromEnv parses all registered flags in the given flagset,
// and if they are not already set it attempts to set their values from
// environment variables. Environment variables take the name of the flag but
// are UPPERCASE, have the given prefix, and any dashes are replaced by
// underscores - for example: some-flag => PREFIX_SOME_FLAG
func flagsFromEnv(prefix string, fs *flag.FlagSet) {
	alreadySet := make(map[string]bool)
	fs.Visit(func(f *flag.Flag) {
		alreadySet[f.Name] = true
	})
	fs.VisitAll(func(f *flag.Flag) {
		if !alreadySet[f.Name] {
			key := strings.ToUpper(prefix + "_" + strings.Replace(f.Name, "-", "_", -1))
			val := os.Getenv(key)
			if val != "" {
				fs.Set(f.Name, val)
			}
		}
	})
}

func writeSubnetFile(sn *backend.SubnetDef) error {
	// Write out the first usable IP by incrementing
	// sn.IP by one
	sn.Net.IP += 1

	dir, _ := path.Split(opts.subnetFile)
	os.MkdirAll(dir, 0755)

	f, err := os.Create(opts.subnetFile)
	if err != nil {
		return err
	}
	defer f.Close()

	if _, err = fmt.Fprintf(f, "FLANNEL_SUBNET=%s\n", sn.Net); err != nil {
		return err
	}
	if _, err = fmt.Fprintf(f, "FLANNEL_MTU=%d\n", sn.MTU); err != nil {
		return err
	}
	return nil
}

func lookupIface() (*net.Interface, net.IP, error) {
	var iface *net.Interface
	var ipaddr net.IP
	var err error

	if len(opts.iface) > 0 {
		if ipaddr = net.ParseIP(opts.iface); ipaddr != nil {
			iface, err = ip.GetInterfaceByIP(ipaddr)
			if err != nil {
				return nil, nil, fmt.Errorf("Error looking up interface %s: %s", opts.iface, err)
			}
		} else {
			iface, err = net.InterfaceByName(opts.iface)
			if err != nil {
				return nil, nil, fmt.Errorf("Error looking up interface %s: %s", opts.iface, err)
			}
		}
	} else {
		log.Info("Determining IP address of default interface")
		if iface, err = ip.GetDefaultGatewayIface(); err != nil {
			return nil, nil, fmt.Errorf("Failed to get default interface: %s", err)
		}
	}

	if ipaddr == nil {
		ipaddr, err = ip.GetIfaceIP4Addr(iface)
		if err != nil {
			return nil, nil, fmt.Errorf("Failed to find IPv4 address for interface %s", iface.Name)
		}
	}

	return iface, ipaddr, nil
}

func makeSubnetManager() *subnet.SubnetManager {
	peers := strings.Split(opts.etcdEndpoints, ",")

	for {
		sm, err := subnet.NewSubnetManager(peers, opts.etcdPrefix)
		if err == nil {
			return sm
		}

		log.Error("Failed to create SubnetManager: ", err)
		time.Sleep(time.Second)
	}
}

func newBackend() (backend.Backend, error) {
	sm := makeSubnetManager()
	config := sm.GetConfig()

	var bt struct {
		Type string
	}

	if len(config.Backend) == 0 {
		bt.Type = "udp"
	} else {
		if err := json.Unmarshal(config.Backend, &bt); err != nil {
			return nil, fmt.Errorf("Error decoding Backend property of config: %v", err)
		}
	}

	switch strings.ToLower(bt.Type) {
	case "udp":
		return udp.New(sm, config.Backend), nil
	case "alloc":
		return alloc.New(sm), nil
	default:
		return nil, fmt.Errorf("'%v': unknown backend type", bt.Type)
	}
}

func run(be backend.Backend, exit chan int) {
	var err error
	defer func() {
		if err == nil || err == task.ErrCanceled {
			exit <- 0
		} else {
			log.Error(err)
			exit <- 1
		}
	}()

	iface, ipaddr, err := lookupIface()
	if err != nil {
		return
	}

	if iface.MTU == 0 {
		err = fmt.Errorf("Failed to determine MTU for %s interface", ipaddr)
		return
	}

	log.Infof("Using %s as external interface", ipaddr)

	sn, err := be.Init(iface, ipaddr, opts.ipMasq)
	if err != nil {
		log.Errorf("Could not init %v backend: %v", be.Name(), err)
		return
	}

	writeSubnetFile(sn)
	daemon.SdNotify("READY=1")

	log.Infof("%s mode initialized", be.Name())
	be.Run()
}

func main() {
	// glog will log to tmp files by default. override so all entries
	// can flow into journald (if running under systemd)
	flag.Set("logtostderr", "true")

	// now parse command line args
	flag.Parse()

	if opts.help {
		fmt.Fprintf(os.Stderr, "Usage: %s [OPTION]...\n", os.Args[0])
		flag.PrintDefaults()
		os.Exit(0)
	}

	if opts.version {
		fmt.Fprintln(os.Stderr, Version)
		os.Exit(0)
	}

	flagsFromEnv("FLANNELD", flag.CommandLine)

	be, err := newBackend()
	if err != nil {
		log.Info(err)
		os.Exit(1)
	}

	// Register for SIGINT and SIGTERM and wait for one of them to arrive
	log.Info("Installing signal handlers")
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, os.Interrupt, syscall.SIGTERM)

	exit := make(chan int)
	go run(be, exit)

	for {
		select {
		case <-sigs:
			// unregister to get default OS nuke behaviour in case we don't exit cleanly
			signal.Stop(sigs)

			log.Info("Exiting...")
			be.Stop()

		case code := <-exit:
			log.Infof("%s mode exited", be.Name())
			os.Exit(code)
		}
	}
}
<|endoftext|>


<commit_before>package main

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

	"github.com/Acconut/hcl/hcl/printer"
	"github.com/Acconut/hcl/json/parser"
)

func main() {
	if err := convert(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func convert() error {
	input, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		return fmt.Errorf("unable to read from stdin: %s", err)
	}

	ast, err := parser.Parse([]byte(input))
	if err != nil {
		return fmt.Errorf("unable to parse JSON: %s", err)
	}

	err = printer.Fprint(os.Stdout, ast)
	if err != nil {
		return fmt.Errorf("unable to print HCL: %s", err)
	}

	return nil
}
<commit_msg>Add version outputting<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"

	"github.com/Acconut/hcl/hcl/printer"
	"github.com/Acconut/hcl/json/parser"
)

// VERSION is what is returned by the `-v` flag
var VERSION = "v0.0.4"

func main() {
	version := flag.Bool("version", false, "Prints current app version")
	flag.Parse()
	if *version {
		fmt.Println(VERSION)
		os.Exit(0)
	}

	if err := convert(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func convert() error {
	input, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		return fmt.Errorf("unable to read from stdin: %s", err)
	}

	ast, err := parser.Parse([]byte(input))
	if err != nil {
		return fmt.Errorf("unable to parse JSON: %s", err)
	}

	err = printer.Fprint(os.Stdout, ast)
	if err != nil {
		return fmt.Errorf("unable to print HCL: %s", err)
	}

	return nil
}
<|endoftext|>


<commit_before>// Package c2go contains the main function for running the executable.
//
// Installation
//
//     go get -u github.com/elliotchance/c2go
//
// Usage
//
//     c2go myfile.c
//
package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"regexp"
	"strings"

	"errors"
	"reflect"

	"github.com/elliotchance/c2go/ast"
	"github.com/elliotchance/c2go/program"
	"github.com/elliotchance/c2go/transpiler"
)

// Version can be requested through the command line with:
//
//     c2go -v
//
// See https://github.com/elliotchance/c2go/wiki/Release-Process
const Version = "v0.16.3 Radium 2017-10-17"

var stderr io.Writer = os.Stderr

// ProgramArgs defines the options available when processing the program. There
// is no constructor since the zeroed out values are the appropriate defaults -
// you need only set the options you need.
//
// TODO: Better separation on CLI modes
// https://github.com/elliotchance/c2go/issues/134
type ProgramArgs struct {
	verbose     bool
	ast         bool
	inputFile   string
	outputFile  string
	packageName string

	// A private option to output the Go as a *_test.go file.
	outputAsTest bool
}

func readAST(data []byte) []string {
	uncolored := regexp.MustCompile(`\x1b\[[\d;]+m`).ReplaceAll(data, []byte{})
	return strings.Split(string(uncolored), "\n")
}

type treeNode struct {
	indent int
	node   ast.Node
}

func convertLinesToNodes(lines []string) []treeNode {
	nodes := make([]treeNode, len(lines))
	var counter int
	for _, line := range lines {
		if strings.TrimSpace(line) == "" {
			continue
		}

		// It is tempting to discard null AST nodes, but these may
		// have semantic importance: for example, they represent omitted
		// for-loop conditions, as in for(;;).
		line = strings.Replace(line, "<<<NULL>>>", "NullStmt", 1)
		trimmed := strings.TrimLeft(line, "|\\- `")
		node := ast.Parse(trimmed)
		indentLevel := (len(line) - len(trimmed)) / 2
		nodes[counter] = treeNode{indentLevel, node}
		counter++
	}
	nodes = nodes[0:counter]

	return nodes
}

// buildTree converts an array of nodes, each prefixed with a depth into a tree.
func buildTree(nodes []treeNode, depth int) []ast.Node {
	if len(nodes) == 0 {
		return []ast.Node{}
	}

	// Split the list into sections, treat each section as a tree with its own
	// root.
	sections := [][]treeNode{}
	for _, node := range nodes {
		if node.indent == depth {
			sections = append(sections, []treeNode{node})
		} else {
			sections[len(sections)-1] = append(sections[len(sections)-1], node)
		}
	}

	results := []ast.Node{}
	for _, section := range sections {
		slice := []treeNode{}
		for _, n := range section {
			if n.indent > depth {
				slice = append(slice, n)
			}
		}

		children := buildTree(slice, depth+1)
		for _, child := range children {
			section[0].node.AddChild(child)
		}
		results = append(results, section[0].node)
	}

	return results
}

func toJSON(tree []interface{}) []map[string]interface{} {
	r := make([]map[string]interface{}, len(tree))

	for j, n := range tree {
		rn := reflect.ValueOf(n).Elem()
		r[j] = make(map[string]interface{})
		r[j]["node"] = rn.Type().Name()

		for i := 0; i < rn.NumField(); i++ {
			name := strings.ToLower(rn.Type().Field(i).Name)
			value := rn.Field(i).Interface()

			if name == "children" {
				v := value.([]interface{})

				if len(v) == 0 {
					continue
				}

				value = toJSON(v)
			}

			r[j][name] = value
		}
	}

	return r
}

func check(prefix string, e error) {
	if e != nil {
		panic(prefix + e.Error())
	}
}

// Start begins transpiling an input file.
func Start(args ProgramArgs) error {
	if os.Getenv("GOPATH") == "" {
		return fmt.Errorf("The $GOPATH must be set")
	}

	// 1. Compile it first (checking for errors)
	_, err := os.Stat(args.inputFile)
	if err != nil {
		return fmt.Errorf("Input file is not found")
	}

	// 2. Preprocess
	var pp []byte
	{
		// See : https://clang.llvm.org/docs/CommandGuide/clang.html
		// clang -E <file>    Run the preprocessor stage.
		cmd := exec.Command("clang", "-E", args.inputFile)
		var out bytes.Buffer
		var stderr bytes.Buffer
		cmd.Stdout = &out
		cmd.Stderr = &stderr
		err = cmd.Run()
		if err != nil {
			return fmt.Errorf("preprocess failed: %v\nStdErr = %v", err, stderr.String())
		}
		pp = []byte(out.String())
	}

	ppFilePath := path.Join("/tmp", "pp.c")
	err = ioutil.WriteFile(ppFilePath, pp, 0644)
	if err != nil {
		return fmt.Errorf("writing to %s failed: %v", ppFilePath, err)
	}

	// 3. Generate JSON from AST
	astPP, err := exec.Command("clang", "-Xclang", "-ast-dump", "-fsyntax-only", ppFilePath).Output()
	if err != nil {
		// If clang fails it still prints out the AST, so we have to run it
		// again to get the real error.
		errBody, _ := exec.Command("clang", ppFilePath).CombinedOutput()

		panic("clang failed: " + err.Error() + ":\n\n" + string(errBody))
	}

	lines := readAST(astPP)
	if args.ast {
		for _, l := range lines {
			fmt.Println(l)
		}
		fmt.Println()

		return nil
	}

	p := program.NewProgram()
	p.Verbose = args.verbose
	p.OutputAsTest = true // args.outputAsTest

	nodes := convertLinesToNodes(lines)
	tree := buildTree(nodes, 0)
	ast.FixPositions(tree)

	// Repair the floating literals. See RepairFloatingLiteralsFromSource for
	// more information.
	floatingErrors := ast.RepairFloatingLiteralsFromSource(tree[0], ppFilePath)

	for _, fErr := range floatingErrors {
		message := fmt.Sprintf("could not read exact floating literal: %s",
			fErr.Err.Error())
		p.AddMessage(p.GenerateWarningMessage(errors.New(message), fErr.Node))
	}

	err = transpiler.TranspileAST(args.inputFile, args.packageName, p, tree[0].(ast.Node))
	if err != nil {
		panic(err)
	}

	outputFilePath := args.outputFile

	if outputFilePath == "" {
		cleanFileName := filepath.Clean(filepath.Base(args.inputFile))
		extension := filepath.Ext(args.inputFile)
		outputFilePath = cleanFileName[0:len(cleanFileName)-len(extension)] + ".go"
	}

	err = ioutil.WriteFile(outputFilePath, []byte(p.String()), 0644)
	if err != nil {
		return fmt.Errorf("writing C output file failed: %v", err)
	}

	return nil
}

// newTempFile - returns temp file
func newTempFile(dir, prefix, suffix string) (*os.File, error) {
	for index := 1; index < 10000; index++ {
		path := filepath.Join(dir, fmt.Sprintf("%s%03d%s", prefix, index, suffix))
		if _, err := os.Stat(path); err != nil {
			return os.Create(path)
		}
	}
	return nil, fmt.Errorf("could not create file: %s%03d%s", prefix, 1, suffix)
}

var (
	versionFlag       = flag.Bool("v", false, "print the version and exit")
	transpileCommand  = flag.NewFlagSet("transpile", flag.ContinueOnError)
	verboseFlag       = transpileCommand.Bool("V", false, "print progress as comments")
	outputFlag        = transpileCommand.String("o", "", "output Go generated code to the specified file")
	packageFlag       = transpileCommand.String("p", "main", "set the name of the generated package")
	transpileHelpFlag = transpileCommand.Bool("h", false, "print help information")
	astCommand        = flag.NewFlagSet("ast", flag.ContinueOnError)
	astHelpFlag       = astCommand.Bool("h", false, "print help information")
)

func main() {
	code := runCommand()
	if code != 0 {
		os.Exit(code)
	}
}

func runCommand() int {
	flag.Usage = func() {
		usage := "Usage: %s [-v] [<command>] [<flags>] file.c\n\n"
		usage += "Commands:\n"
		usage += "  transpile\ttranspile an input C source file to Go\n"
		usage += "  ast\t\tprint AST before translated Go code\n\n"

		usage += "Flags:\n"
		fmt.Fprintf(stderr, usage, os.Args[0])
		flag.PrintDefaults()
	}

	transpileCommand.SetOutput(stderr)
	astCommand.SetOutput(stderr)

	flag.Parse()

	if *versionFlag {
		// Simply print out the version and exit.
		fmt.Println(Version)
		return 0
	}

	if flag.NArg() < 1 {
		flag.Usage()
		return 1
	}

	args := ProgramArgs{verbose: *verboseFlag, ast: false}

	switch os.Args[1] {
	case "ast":
		err := astCommand.Parse(os.Args[2:])
		if err != nil {
			fmt.Printf("ast command cannot parse: %v", err)
			return 1
		}

		if *astHelpFlag || astCommand.NArg() == 0 {
			fmt.Fprintf(stderr, "Usage: %s ast file.c\n", os.Args[0])
			astCommand.PrintDefaults()
			return 1
		}

		args.ast = true
		args.inputFile = astCommand.Arg(0)
	case "transpile":
		err := transpileCommand.Parse(os.Args[2:])
		if err != nil {
			fmt.Printf("transpile command cannot parse: %v", err)
			return 1
		}

		if *transpileHelpFlag || transpileCommand.NArg() == 0 {
			fmt.Fprintf(stderr, "Usage: %s transpile [-V] [-o file.go] [-p package] file.c\n", os.Args[0])
			transpileCommand.PrintDefaults()
			return 1
		}

		args.inputFile = transpileCommand.Arg(0)
		args.outputFile = *outputFlag
		args.packageName = *packageFlag
	default:
		flag.Usage()
		return 1
	}

	if err := Start(args); err != nil {
		fmt.Printf("Error: %v", err)
		return 1
	}

	return 0
}
<commit_msg>Bump version: v0.16.4 Radium 2017-10-18<commit_after>// Package c2go contains the main function for running the executable.
//
// Installation
//
//     go get -u github.com/elliotchance/c2go
//
// Usage
//
//     c2go myfile.c
//
package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"regexp"
	"strings"

	"errors"
	"reflect"

	"github.com/elliotchance/c2go/ast"
	"github.com/elliotchance/c2go/program"
	"github.com/elliotchance/c2go/transpiler"
)

// Version can be requested through the command line with:
//
//     c2go -v
//
// See https://github.com/elliotchance/c2go/wiki/Release-Process
const Version = "v0.16.4 Radium 2017-10-18"

var stderr io.Writer = os.Stderr

// ProgramArgs defines the options available when processing the program. There
// is no constructor since the zeroed out values are the appropriate defaults -
// you need only set the options you need.
//
// TODO: Better separation on CLI modes
// https://github.com/elliotchance/c2go/issues/134
type ProgramArgs struct {
	verbose     bool
	ast         bool
	inputFile   string
	outputFile  string
	packageName string

	// A private option to output the Go as a *_test.go file.
	outputAsTest bool
}

func readAST(data []byte) []string {
	uncolored := regexp.MustCompile(`\x1b\[[\d;]+m`).ReplaceAll(data, []byte{})
	return strings.Split(string(uncolored), "\n")
}

type treeNode struct {
	indent int
	node   ast.Node
}

func convertLinesToNodes(lines []string) []treeNode {
	nodes := make([]treeNode, len(lines))
	var counter int
	for _, line := range lines {
		if strings.TrimSpace(line) == "" {
			continue
		}

		// It is tempting to discard null AST nodes, but these may
		// have semantic importance: for example, they represent omitted
		// for-loop conditions, as in for(;;).
		line = strings.Replace(line, "<<<NULL>>>", "NullStmt", 1)
		trimmed := strings.TrimLeft(line, "|\\- `")
		node := ast.Parse(trimmed)
		indentLevel := (len(line) - len(trimmed)) / 2
		nodes[counter] = treeNode{indentLevel, node}
		counter++
	}
	nodes = nodes[0:counter]

	return nodes
}

// buildTree converts an array of nodes, each prefixed with a depth into a tree.
func buildTree(nodes []treeNode, depth int) []ast.Node {
	if len(nodes) == 0 {
		return []ast.Node{}
	}

	// Split the list into sections, treat each section as a tree with its own
	// root.
	sections := [][]treeNode{}
	for _, node := range nodes {
		if node.indent == depth {
			sections = append(sections, []treeNode{node})
		} else {
			sections[len(sections)-1] = append(sections[len(sections)-1], node)
		}
	}

	results := []ast.Node{}
	for _, section := range sections {
		slice := []treeNode{}
		for _, n := range section {
			if n.indent > depth {
				slice = append(slice, n)
			}
		}

		children := buildTree(slice, depth+1)
		for _, child := range children {
			section[0].node.AddChild(child)
		}
		results = append(results, section[0].node)
	}

	return results
}

func toJSON(tree []interface{}) []map[string]interface{} {
	r := make([]map[string]interface{}, len(tree))

	for j, n := range tree {
		rn := reflect.ValueOf(n).Elem()
		r[j] = make(map[string]interface{})
		r[j]["node"] = rn.Type().Name()

		for i := 0; i < rn.NumField(); i++ {
			name := strings.ToLower(rn.Type().Field(i).Name)
			value := rn.Field(i).Interface()

			if name == "children" {
				v := value.([]interface{})

				if len(v) == 0 {
					continue
				}

				value = toJSON(v)
			}

			r[j][name] = value
		}
	}

	return r
}

func check(prefix string, e error) {
	if e != nil {
		panic(prefix + e.Error())
	}
}

// Start begins transpiling an input file.
func Start(args ProgramArgs) error {
	if os.Getenv("GOPATH") == "" {
		return fmt.Errorf("The $GOPATH must be set")
	}

	// 1. Compile it first (checking for errors)
	_, err := os.Stat(args.inputFile)
	if err != nil {
		return fmt.Errorf("Input file is not found")
	}

	// 2. Preprocess
	var pp []byte
	{
		// See : https://clang.llvm.org/docs/CommandGuide/clang.html
		// clang -E <file>    Run the preprocessor stage.
		cmd := exec.Command("clang", "-E", args.inputFile)
		var out bytes.Buffer
		var stderr bytes.Buffer
		cmd.Stdout = &out
		cmd.Stderr = &stderr
		err = cmd.Run()
		if err != nil {
			return fmt.Errorf("preprocess failed: %v\nStdErr = %v", err, stderr.String())
		}
		pp = []byte(out.String())
	}

	ppFilePath := path.Join("/tmp", "pp.c")
	err = ioutil.WriteFile(ppFilePath, pp, 0644)
	if err != nil {
		return fmt.Errorf("writing to %s failed: %v", ppFilePath, err)
	}

	// 3. Generate JSON from AST
	astPP, err := exec.Command("clang", "-Xclang", "-ast-dump", "-fsyntax-only", ppFilePath).Output()
	if err != nil {
		// If clang fails it still prints out the AST, so we have to run it
		// again to get the real error.
		errBody, _ := exec.Command("clang", ppFilePath).CombinedOutput()

		panic("clang failed: " + err.Error() + ":\n\n" + string(errBody))
	}

	lines := readAST(astPP)
	if args.ast {
		for _, l := range lines {
			fmt.Println(l)
		}
		fmt.Println()

		return nil
	}

	p := program.NewProgram()
	p.Verbose = args.verbose
	p.OutputAsTest = true // args.outputAsTest

	nodes := convertLinesToNodes(lines)
	tree := buildTree(nodes, 0)
	ast.FixPositions(tree)

	// Repair the floating literals. See RepairFloatingLiteralsFromSource for
	// more information.
	floatingErrors := ast.RepairFloatingLiteralsFromSource(tree[0], ppFilePath)

	for _, fErr := range floatingErrors {
		message := fmt.Sprintf("could not read exact floating literal: %s",
			fErr.Err.Error())
		p.AddMessage(p.GenerateWarningMessage(errors.New(message), fErr.Node))
	}

	err = transpiler.TranspileAST(args.inputFile, args.packageName, p, tree[0].(ast.Node))
	if err != nil {
		panic(err)
	}

	outputFilePath := args.outputFile

	if outputFilePath == "" {
		cleanFileName := filepath.Clean(filepath.Base(args.inputFile))
		extension := filepath.Ext(args.inputFile)
		outputFilePath = cleanFileName[0:len(cleanFileName)-len(extension)] + ".go"
	}

	err = ioutil.WriteFile(outputFilePath, []byte(p.String()), 0644)
	if err != nil {
		return fmt.Errorf("writing C output file failed: %v", err)
	}

	return nil
}

// newTempFile - returns temp file
func newTempFile(dir, prefix, suffix string) (*os.File, error) {
	for index := 1; index < 10000; index++ {
		path := filepath.Join(dir, fmt.Sprintf("%s%03d%s", prefix, index, suffix))
		if _, err := os.Stat(path); err != nil {
			return os.Create(path)
		}
	}
	return nil, fmt.Errorf("could not create file: %s%03d%s", prefix, 1, suffix)
}

var (
	versionFlag       = flag.Bool("v", false, "print the version and exit")
	transpileCommand  = flag.NewFlagSet("transpile", flag.ContinueOnError)
	verboseFlag       = transpileCommand.Bool("V", false, "print progress as comments")
	outputFlag        = transpileCommand.String("o", "", "output Go generated code to the specified file")
	packageFlag       = transpileCommand.String("p", "main", "set the name of the generated package")
	transpileHelpFlag = transpileCommand.Bool("h", false, "print help information")
	astCommand        = flag.NewFlagSet("ast", flag.ContinueOnError)
	astHelpFlag       = astCommand.Bool("h", false, "print help information")
)

func main() {
	code := runCommand()
	if code != 0 {
		os.Exit(code)
	}
}

func runCommand() int {
	flag.Usage = func() {
		usage := "Usage: %s [-v] [<command>] [<flags>] file.c\n\n"
		usage += "Commands:\n"
		usage += "  transpile\ttranspile an input C source file to Go\n"
		usage += "  ast\t\tprint AST before translated Go code\n\n"

		usage += "Flags:\n"
		fmt.Fprintf(stderr, usage, os.Args[0])
		flag.PrintDefaults()
	}

	transpileCommand.SetOutput(stderr)
	astCommand.SetOutput(stderr)

	flag.Parse()

	if *versionFlag {
		// Simply print out the version and exit.
		fmt.Println(Version)
		return 0
	}

	if flag.NArg() < 1 {
		flag.Usage()
		return 1
	}

	args := ProgramArgs{verbose: *verboseFlag, ast: false}

	switch os.Args[1] {
	case "ast":
		err := astCommand.Parse(os.Args[2:])
		if err != nil {
			fmt.Printf("ast command cannot parse: %v", err)
			return 1
		}

		if *astHelpFlag || astCommand.NArg() == 0 {
			fmt.Fprintf(stderr, "Usage: %s ast file.c\n", os.Args[0])
			astCommand.PrintDefaults()
			return 1
		}

		args.ast = true
		args.inputFile = astCommand.Arg(0)
	case "transpile":
		err := transpileCommand.Parse(os.Args[2:])
		if err != nil {
			fmt.Printf("transpile command cannot parse: %v", err)
			return 1
		}

		if *transpileHelpFlag || transpileCommand.NArg() == 0 {
			fmt.Fprintf(stderr, "Usage: %s transpile [-V] [-o file.go] [-p package] file.c\n", os.Args[0])
			transpileCommand.PrintDefaults()
			return 1
		}

		args.inputFile = transpileCommand.Arg(0)
		args.outputFile = *outputFlag
		args.packageName = *packageFlag
	default:
		flag.Usage()
		return 1
	}

	if err := Start(args); err != nil {
		fmt.Printf("Error: %v", err)
		return 1
	}

	return 0
}
<|endoftext|>


<commit_before>package main

import "log"
import "fmt"
import "os"

import slack "github.com/weirdtales/senor-rosado/slack"

func main() {
    // TODO: signals
    if len(os.Args) < 2 {
        fmt.Fprintf(os.Stderr, "usage: %s <TOKEN>\n", os.Args[0])
        os.Exit(1)
    }

    conn, err := slack.Connect(os.Args[1])
    if err != nil {
        log.Fatal(err)
    }

    os.Exit(loop(conn))
}

func loop(conn slack.Conn) int {
    reply := slack.Message{}
    replyToUser := true
    for {
        msg, err := conn.Get()
        if err != nil {
            log.Fatal(err)
        }

        if os.Getenv("DEBUG") == "1" {
            log.Printf("[d] msg=%+v", msg)
        }
        if ! msg.Respond {
            continue
        }
        log.Printf(">>> %s %s: %s", msg.Channel, msg.User, msg.Text)

        switch msg.Command {
            case "help", "?", "usage", "-h", "--help":
                reply.Text = "not yet"
            case "toggle-reply-target":
                log.Printf("-?- toggling replyToUser: %v", !replyToUser)
                replyToUser = !replyToUser
        }

        if reply.Text != "" {
            if replyToUser {
                reply.Text = "<@" + msg.User + "> " + reply.Text
            }

            log.Printf("<<< %s %s", msg.Channel, reply.Text)
            err = conn.Send(reply, msg.Channel)
            if err != nil {
                log.Fatal(err)
            }
        }

        reply = slack.Message{}
    }
    return 0
}
<commit_msg>redundant<commit_after>package main

import "log"
import "fmt"
import "os"

import "github.com/weirdtales/senor-rosado/slack"

func main() {
    // TODO: signals
    if len(os.Args) < 2 {
        fmt.Fprintf(os.Stderr, "usage: %s <TOKEN>\n", os.Args[0])
        os.Exit(1)
    }

    conn, err := slack.Connect(os.Args[1])
    if err != nil {
        log.Fatal(err)
    }

    os.Exit(loop(conn))
}

func loop(conn slack.Conn) int {
    reply := slack.Message{}
    replyToUser := true
    for {
        msg, err := conn.Get()
        if err != nil {
            log.Fatal(err)
        }

        if os.Getenv("DEBUG") == "1" {
            log.Printf("[d] msg=%+v", msg)
        }
        if ! msg.Respond {
            continue
        }
        log.Printf(">>> %s %s: %s", msg.Channel, msg.User, msg.Text)

        switch msg.Command {
            case "help", "?", "usage", "-h", "--help":
                reply.Text = "not yet"
            case "toggle-reply-target":
                log.Printf("-?- toggling replyToUser: %v", !replyToUser)
                replyToUser = !replyToUser
        }

        if reply.Text != "" {
            if replyToUser {
                reply.Text = "<@" + msg.User + "> " + reply.Text
            }

            log.Printf("<<< %s %s", msg.Channel, reply.Text)
            err = conn.Send(reply, msg.Channel)
            if err != nil {
                log.Fatal(err)
            }
        }

        reply = slack.Message{}
    }
    return 0
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	"os"
	"encoding/json"
	"gopkg.in/yaml.v2"
	"github.com/jmoiron/sqlx"
	"github.com/julienschmidt/httprouter"
	"text/template"
	_ "github.com/mattn/go-sqlite3"
)

var settings = `
driver: sqlite3
rules:
  - path: /show/:id
    query: SELECT * FROM test WHERE id = '{{.id}}';
  - path: /create/
    query: INSERT INTO test (body) VALUES ("lililil"), ("OUE");
`

// Response defines the JSON contents for response to resource request by HTTP.
type Response struct {
	Success bool `json:"success"`
	Rows []map[string]interface{} `json:"rows"`
	ErrorType string `json:"errorType"`
	ErrorDescription string `json:"errorDescription"`
}

// InputRule is part of InputConfig
type InputRule struct {
	Path string
	Query string
	Queries []string
	Method string
}

// InputConfig is for reading YAML config file
type InputConfig struct {
	Driver string `yaml:"driver"`
	Rules []InputRule `yaml:"rules"`
}

// Rule is part of `Config`, it's set of the routing path and the SQL query.
type Rule struct {
	Path string
	Queries []string
	Method Method
}

// Config contains configs of whole app
type Config struct {
	Driver string
	Rules []Rule
}

// Config returns one converted to Config struct
func (ic InputConfig) Config() (Config, error) {
	rules, err := normalizeRules(ic.Rules)
	if err != nil {
		return Config{}, err
	}

	return Config{
		Driver: ic.Driver,
		Rules: rules,
	}, nil
}

func normalizeRules(orig []InputRule) ([]Rule, error) {
	result := []Rule{}
	for _, rule := range orig {
		normalized, err := normalizeRule(rule)
		if err != nil {
			return []Rule{}, err
		}
		result = append(result, normalized)
	}
	return result, nil
}

func normalizeRule(orig InputRule) (Rule, error) {
	queries, err := normalizeQuery(orig.Query, orig.Queries)
	if err != nil {
		return Rule{}, err
	}

	method, err := newMethod(orig.Method)
	if err != nil {
		return Rule{}, err
	}

	path, err := normalizePath(orig.Path)
	if err != nil {
		return Rule{}, err
	}

	return Rule{
		Queries: queries,
		Method: method,
		Path: path,
	}, nil
}

func normalizePath(orig string) (string, error) {
	return orig, nil
}

func normalizeQuery(query string, queries []string) ([]string, error) {
	if query == "" && len(queries) == 0 {
		return []string{}, fmt.Errorf("both of `query` and `queries` can't be defined in a rule")
	} else if query != "" {
		return []string{query}, nil
	} else if len(queries) > 0 {
		return queries, nil
	}
	return []string{}, fmt.Errorf("at least one SQL query must be given per rule")
}

func newMethod(method string) (Method, error) {
	switch method {
	case "GET":
		return GET, nil
	case "POST":
		return POST, nil
	case "PUT":
		return PUT, nil
	case "PATCH":
		return PATCH, nil
	case "DELETE":
		return DELETE, nil
	}
	return "", fmt.Errorf("invalid method name")
}

// Method is enum for HTTP methods.
type Method string

const (
	// GET expresses GET method
	GET Method = "GET"

	// POST expresses POST method
	POST = "POST"

	// PUT expresses PUT method
	PUT = "PUT"

	// PATCH expresses PATCH method
	PATCH = "PATCH"

	// DELETE expresses DELETE method
	DELETE = "DELETE"
)

func main() {
	inputConfig := InputConfig{}
	yaml.Unmarshal([]byte(settings), &inputConfig)
	config, err := inputConfig.Config()
	if err != nil {
		fmt.Printf("invalid configuration: %s\n", err)
		return
	}

	db, err := sqlx.Open(config.Driver, "./test.db")
	if err != nil {
		panic(err)
	}

	router := httprouter.New()
	for _, rule := range config.Rules {
		router.Handle(string(rule.Method), rule.Path, createHandler(db, rule))
	}
	fmt.Println(http.ListenAndServe(":8000", router))
}

func createHandler(db *sqlx.DB, r Rule) httprouter.Handle {
	return func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
		t, err := template.New("sql").Parse(r.Queries)
		if err != nil {
			fmt.Println("invalid SQL template")
			return
		}
		err = t.Execute(os.Stdout, createParamMap(params))
		if err != nil {
			fmt.Println(err)
			return
		}

		rows, err := db.Queryx(r.SQL)
		if err != nil {
			bts, err2 := json.Marshal(response{
				Success: false,
				ErrorType: "sqlExecutionError",
				ErrorDescription: err.Error(),
			})
			if err2 != nil {
				panic(err2)
			}
			w.Write(bts)
			return
		}
		res, err := createMapSliceFromRows(rows)
		if err != nil {
			bts, err2 := json.Marshal(response{
				Success: false,
				ErrorType: "sqlExecutionError",
				ErrorDescription: err.Error(),
			})
			if err2 != nil {
				panic(err2)
			}
			w.Write(bts)
			return
		}
		if err != nil {
			panic(err)
		}
		bts, err := json.Marshal(response{
			Success: true,
			Rows: res,
		})
		if err != nil {
			panic(err)
		}
		w.Write(bts)
	}
}

func createParamMap(params httprouter.Params) map[string]string {
	result := make(map[string]string)
	for _, param := range params {
		result[param.Key] = param.Value
	}
	return result
}

type mapString []byte

func (bts mapString) MarshalText() ([]byte, error) {
	return bts, nil
}

func createMapSliceFromRows(rows *sqlx.Rows) ([]map[string]interface{}, error) {
	result := []map[string]interface{}{}
	for rows.Next() {
		cols := make(map[string]interface{})
		err := rows.MapScan(cols)
		if err != nil {
			return nil, err
		}

		newCols := make(map[string]interface{})
		for k, v := range cols {
			if str, ok := v.([]byte); ok {
				newCols[k] = mapString(str)
			} else {
				newCols[k] = v
			}
		}
		result = append(result, newCols)
	}
	return result, nil
}
<commit_msg>[Add] `befores` and `afters` added to config<commit_after>package main

import (
	"fmt"
	"net/http"
	"os"
	"encoding/json"
	"gopkg.in/yaml.v2"
	"github.com/jmoiron/sqlx"
	"github.com/julienschmidt/httprouter"
	"text/template"
	_ "github.com/mattn/go-sqlite3"
)

var settings = `
driver: sqlite3
rules:
  - path: /show/:id
    query: SELECT * FROM test WHERE id = '{{.id}}';
  - path: /create/
    query: INSERT INTO test (body) VALUES ("lililil"), ("OUE");
`

// Response defines the JSON contents for response to resource request by HTTP.
type Response struct {
	Success bool `json:"success"`
	Rows []map[string]interface{} `json:"rows"`
	ErrorType string `json:"errorType"`
	ErrorDescription string `json:"errorDescription"`
}

// InputRule is part of InputConfig
type InputRule struct {
	Path string
	Before string
	Befores []string
	Query string
	Queries []string
	After string
	Afters []string
	Method string
	Transaction bool
}

// InputConfig is for reading YAML config file
type InputConfig struct {
	Driver string `yaml:"driver"`
	Rules []InputRule `yaml:"rules"`
}

// Rule is part of `Config`, it's set of the routing path and the SQL query.
type Rule struct {
	Path string
	Befores []string
	Queries []string
	Afters []string
	Method Method
	Transaction bool
}

// Config contains configs of whole app
type Config struct {
	Driver string
	Rules []Rule
}

// Config returns one converted to Config struct
func (ic InputConfig) Config() (Config, error) {
	rules, err := normalizeRules(ic.Rules)
	if err != nil {
		return Config{}, err
	}

	return Config{
		Driver: ic.Driver,
		Rules: rules,
	}, nil
}

func normalizeRules(orig []InputRule) ([]Rule, error) {
	result := []Rule{}
	for _, rule := range orig {
		normalized, err := normalizeRule(rule)
		if err != nil {
			return []Rule{}, err
		}
		result = append(result, normalized)
	}
	return result, nil
}

func normalizeRule(orig InputRule) (Rule, error) {
	befores, err := normalizeBefores(orig.Before, orig.Befores)
	if err != nil {
		return Rule{}, err
	}

	queries, err := normalizeQuery(orig.Query, orig.Queries)
	if err != nil {
		return Rule{}, err
	}

	afters, err := normalizeAfters(orig.After, orig.Afters)
	if err != nil {
		return Rule{}, err
	}

	method, err := newMethod(orig.Method)
	if err != nil {
		return Rule{}, err
	}

	path, err := normalizePath(orig.Path)
	if err != nil {
		return Rule{}, err
	}

	return Rule{
		Befores: befores,
		Queries: queries,
		Afters: afters,
		Method: method,
		Path: path,
	}, nil
}

func normalizePath(orig string) (string, error) {
	return orig, nil
}

func normalizeBefores(before string, befores []string) ([]string, error) {
	if before == "" && len(befores) == 0 {
		return []string{}, fmt.Errorf("both of `before` and `befores` can't be defined in a rule")
	} else if before != "" {
		return []string{before}, nil
	} else if len(befores) > 0 {
		return befores, nil
	}
	return []string{}, nil
}

func normalizeAfters(after string, afters []string) ([]string, error) {
	if after == "" && len(afters) == 0 {
		return []string{}, fmt.Errorf("both of `after` and `afters` can't be defined in a rule")
	} else if after != "" {
		return []string{after}, nil
	} else if len(afters) > 0 {
		return afters, nil
	}
	return []string{}, nil
}

func normalizeQuery(query string, queries []string) ([]string, error) {
	if query == "" && len(queries) == 0 {
		return []string{}, fmt.Errorf("both of `query` and `queries` can't be defined in a rule")
	} else if query != "" {
		return []string{query}, nil
	} else if len(queries) > 0 {
		return queries, nil
	}
	return []string{}, fmt.Errorf("at least one SQL query must be given per rule")
}

func newMethod(method string) (Method, error) {
	switch method {
	case "GET":
		return GET, nil
	case "POST":
		return POST, nil
	case "PUT":
		return PUT, nil
	case "PATCH":
		return PATCH, nil
	case "DELETE":
		return DELETE, nil
	}
	return "", fmt.Errorf("invalid method name")
}

// Method is enum for HTTP methods.
type Method string

const (
	// GET expresses GET method
	GET Method = "GET"

	// POST expresses POST method
	POST = "POST"

	// PUT expresses PUT method
	PUT = "PUT"

	// PATCH expresses PATCH method
	PATCH = "PATCH"

	// DELETE expresses DELETE method
	DELETE = "DELETE"
)

func main() {
	inputConfig := InputConfig{}
	yaml.Unmarshal([]byte(settings), &inputConfig)
	config, err := inputConfig.Config()
	if err != nil {
		fmt.Printf("invalid configuration: %s\n", err)
		return
	}

	db, err := sqlx.Open(config.Driver, "./test.db")
	if err != nil {
		panic(err)
	}

	router := httprouter.New()
	for _, rule := range config.Rules {
		router.Handle(string(rule.Method), rule.Path, createHandler(db, rule))
	}
	fmt.Println(http.ListenAndServe(":8000", router))
}

func createHandler(db *sqlx.DB, r Rule) httprouter.Handle {
	return func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
		t, err := template.New("sql").Parse(r.Queries)
		if err != nil {
			fmt.Println("invalid SQL template")
			return
		}
		err = t.Execute(os.Stdout, createParamMap(params))
		if err != nil {
			fmt.Println(err)
			return
		}

		rows, err := db.Queryx(r.SQL)
		if err != nil {
			bts, err2 := json.Marshal(response{
				Success: false,
				ErrorType: "sqlExecutionError",
				ErrorDescription: err.Error(),
			})
			if err2 != nil {
				panic(err2)
			}
			w.Write(bts)
			return
		}
		res, err := createMapSliceFromRows(rows)
		if err != nil {
			bts, err2 := json.Marshal(response{
				Success: false,
				ErrorType: "sqlExecutionError",
				ErrorDescription: err.Error(),
			})
			if err2 != nil {
				panic(err2)
			}
			w.Write(bts)
			return
		}
		if err != nil {
			panic(err)
		}
		bts, err := json.Marshal(response{
			Success: true,
			Rows: res,
		})
		if err != nil {
			panic(err)
		}
		w.Write(bts)
	}
}

func createParamMap(params httprouter.Params) map[string]string {
	result := make(map[string]string)
	for _, param := range params {
		result[param.Key] = param.Value
	}
	return result
}

type mapString []byte

func (bts mapString) MarshalText() ([]byte, error) {
	return bts, nil
}

func createMapSliceFromRows(rows *sqlx.Rows) ([]map[string]interface{}, error) {
	result := []map[string]interface{}{}
	for rows.Next() {
		cols := make(map[string]interface{})
		err := rows.MapScan(cols)
		if err != nil {
			return nil, err
		}

		newCols := make(map[string]interface{})
		for k, v := range cols {
			if str, ok := v.([]byte); ok {
				newCols[k] = mapString(str)
			} else {
				newCols[k] = v
			}
		}
		result = append(result, newCols)
	}
	return result, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/sha1"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"html"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	"github.com/dchest/uniuri"
	"github.com/ewhal/pygments"
	_ "github.com/go-sql-driver/mysql"
	"github.com/gorilla/mux"
)

const (
	ADDRESS  = "http://localhost:9900"
	LENGTH   = 6
	PORT     = ":9900"
	USERNAME = ""
	PASS     = ""
	NAME     = ""
	DATABASE = USERNAME + ":" + PASS + "@/" + NAME + "?charset=utf8"
)

type Response struct {
	ID     string `json:"id"`
	HASH   string `json:"hash"`
	URL    string `json:"url"`
	SIZE   int    `json:"size"`
	DELKEY string `json:"delkey"`
}

type Page struct {
	Title string
	Body  []byte
	Raw   string
	Home  string
}

func check(err error) {
	if err != nil {
		fmt.Println(err)
	}
}

func generateName() string {
	s := uniuri.NewLen(LENGTH)
	db, err := sql.Open("mysql", DATABASE)
	check(err)

	query, err := db.Query("select id from pastebin")
	for query.Next() {
		var id string
		err := query.Scan(&id)
		if err != nil {

		}
		if id == s {
			generateName()
		}
	}
	db.Close()

	return s

}
func hash(paste string) string {
	hasher := sha1.New()

	hasher.Write([]byte(paste))
	sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
	return sha
}

func save(raw string, lang string) []string {
	db, err := sql.Open("mysql", DATABASE)
	check(err)

	sha := hash(raw)
	query, err := db.Query("select id, hash, data, delkey from pastebin")
	for query.Next() {
		var id, hash, paste, delkey string
		err := query.Scan(&id, &hash, &paste, &delkey)
		check(err)
		if hash == sha {
			url := ADDRESS + "/p/" + id
			return []string{id, hash, url, paste, delkey}
		}
	}
	id := generateName()
	var url string
	if lang == "" {
		url = ADDRESS + "/p/" + id
	} else {
		url = ADDRESS + "/p/" + id + "/" + lang
	}
	delKey := uniuri.NewLen(40)
	paste := html.EscapeString(raw)

	stmt, err := db.Prepare("INSERT INTO pastebin(id, hash, data, delkey) values(?,?,?,?)")
	check(err)
	_, err = stmt.Exec(id, sha, paste, delKey)
	check(err)
	db.Close()
	return []string{id, sha, url, paste, delKey}
}

func delHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	delkey := vars["delKey"]

	db, err := sql.Open("mysql", DATABASE)
	check(err)

	stmt, err := db.Prepare("delete from pastebin where delkey=?")
	check(err)

	res, err := stmt.Exec(html.EscapeString(delkey))
	check(err)

	_, err = res.RowsAffected()
	if err == sql.ErrNoRows {
		io.WriteString(w, "Error invalid paste")
	} else {
		io.WriteString(w, paste+" deleted")
	}
	db.Close()

}
func saveHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	output := vars["output"]
	switch r.Method {
	case "POST":
		paste := r.FormValue("p")
		lang := r.FormValue("lang")
		if paste == "" {
			http.Error(w, "Empty paste", 500)
			return
		}
		values := save(paste, lang)
		b := &Response{
			ID:     values[0],
			HASH:   values[1],
			URL:    values[2],
			SIZE:   len(values[3]),
			DELKEY: values[4],
		}

		switch output {
		case "json":

			w.Header().Set("Content-Type", "application/json")
			err := json.NewEncoder(w).Encode(b)

			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		case "xml":
			x, err := xml.MarshalIndent(b, "", "  ")
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

			w.Header().Set("Content-Type", "application/xml")
			w.Write(x)

		case "html":
			w.Header().Set("Content-Type", "text/html")
			io.WriteString(w, "
URL: "+b.URL+"
")
			io.WriteString(w, "
Delete Key: "+b.DELKEY+"
")

		case "redirect":
			http.Redirect(w, r, b.URL, 301)

		default:
			w.Header().Set("Content-Type", "plain/text")
			io.WriteString(w, b.URL+"\n")
			io.WriteString(w, "delete key: "+b.DELKEY+"\n")
		}
	}

}

func highlight(s string, lang string) (string, error) {

	highlight, err := pygments.Highlight(html.UnescapeString(s), html.EscapeString(lang), "html", "style=autumn,linenos=True, lineanchors=True,anchorlinenos=True,noclasses=True,", "utf-8")
	if err != nil {
		return "", err
	}
	return highlight, nil

}

func getPaste(paste string, lang string) string {
	param1 := html.EscapeString(paste)
	db, err := sql.Open("mysql", DATABASE)
	var s string
	err = db.QueryRow("select data from pastebin where id=?", param1).Scan(&s)
	db.Close()
	check(err)

	if err == sql.ErrNoRows {
		return "Error invalid paste"
	} else {
		if lang == "" {
			return html.UnescapeString(s)
		} else {
			high, err := highlight(s, lang)
			check(err)
			return high

		}
	}

}

var templates = template.Must(template.ParseFiles("assets/paste.html", "assets/index.html"))
var syntax, _ = ioutil.ReadFile("assets/syntax.html")

func pasteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	lang := vars["lang"]
	s := getPaste(paste, lang)
	link := ADDRESS + "/raw/" + paste
	if lang == "" {
		p := &Page{
			Title: paste,
			Body:  []byte(s),
			Raw:   link,
			Home:  ADDRESS,
		}
		err := templates.ExecuteTemplate(w, "paste.html", p)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}

	} else {
		fmt.Fprintf(w, string(syntax), paste, paste, s, ADDRESS, link)

	}
}

func cloneHandler(w http.ResponseWriter, r *http.Request) {
}
func downloadHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s := getPaste(paste, "")
	http.ServeContent(w, r, paste, time.Now(), bytes.NewReader([]byte(s)))

}
func rawHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s := getPaste(paste, "")
	io.WriteString(w, s)

}

func main() {
	router := mux.NewRouter()
	router.HandleFunc("/p/{pasteId}", pasteHandler)
	router.HandleFunc("/raw/{pasteId}", rawHandler)
	router.HandleFunc("/p/{pasteId}/{lang}", pasteHandler)
	router.HandleFunc("/clone/{pasteId}", cloneHandler)
	router.HandleFunc("/download/{pasteId}", downloadHandler)
	router.HandleFunc("/save", saveHandler)
	router.HandleFunc("/save/{output}", saveHandler)
	router.HandleFunc("/del/{pasteId}/{delKey}", delHandler)
	router.PathPrefix("/").Handler(http.StripPrefix("/", http.FileServer(http.Dir("assets/"))))
	err := http.ListenAndServe(PORT, router)
	if err != nil {
		log.Fatal(err)
	}

}
<commit_msg>Add content headers<commit_after>package main

import (
	"crypto/sha1"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"html"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/dchest/uniuri"
	"github.com/ewhal/pygments"
	_ "github.com/go-sql-driver/mysql"
	"github.com/gorilla/mux"
)

const (
	ADDRESS  = "http://localhost:9900"
	LENGTH   = 6
	PORT     = ":9900"
	USERNAME = ""
	PASS     = ""
	NAME     = ""
	DATABASE = USERNAME + ":" + PASS + "@/" + NAME + "?charset=utf8"
)

type Response struct {
	ID     string `json:"id"`
	HASH   string `json:"hash"`
	URL    string `json:"url"`
	SIZE   int    `json:"size"`
	DELKEY string `json:"delkey"`
}

type Page struct {
	Title string
	Body  []byte
	Raw   string
	Home  string
}

func check(err error) {
	if err != nil {
		fmt.Println(err)
	}
}

func generateName() string {
	s := uniuri.NewLen(LENGTH)
	db, err := sql.Open("mysql", DATABASE)
	check(err)

	query, err := db.Query("select id from pastebin")
	for query.Next() {
		var id string
		err := query.Scan(&id)
		if err != nil {

		}
		if id == s {
			generateName()
		}
	}
	db.Close()

	return s

}
func hash(paste string) string {
	hasher := sha1.New()

	hasher.Write([]byte(paste))
	sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
	return sha
}

func save(raw string, lang string) []string {
	db, err := sql.Open("mysql", DATABASE)
	check(err)

	sha := hash(raw)
	query, err := db.Query("select id, hash, data, delkey from pastebin")
	for query.Next() {
		var id, hash, paste, delkey string
		err := query.Scan(&id, &hash, &paste, &delkey)
		check(err)
		if hash == sha {
			url := ADDRESS + "/p/" + id
			return []string{id, hash, url, paste, delkey}
		}
	}
	id := generateName()
	var url string
	if lang == "" {
		url = ADDRESS + "/p/" + id
	} else {
		url = ADDRESS + "/p/" + id + "/" + lang
	}
	delKey := uniuri.NewLen(40)
	paste := html.EscapeString(raw)

	stmt, err := db.Prepare("INSERT INTO pastebin(id, hash, data, delkey) values(?,?,?,?)")
	check(err)
	_, err = stmt.Exec(id, sha, paste, delKey)
	check(err)
	db.Close()
	return []string{id, sha, url, paste, delKey}
}

func delHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	delkey := vars["delKey"]

	db, err := sql.Open("mysql", DATABASE)
	check(err)

	stmt, err := db.Prepare("delete from pastebin where delkey=?")
	check(err)

	res, err := stmt.Exec(html.EscapeString(delkey))
	check(err)

	_, err = res.RowsAffected()
	if err == sql.ErrNoRows {
		io.WriteString(w, "Error invalid paste")
	} else {
		io.WriteString(w, paste+" deleted")
	}
	db.Close()

}
func saveHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	output := vars["output"]
	switch r.Method {
	case "POST":
		paste := r.FormValue("p")
		lang := r.FormValue("lang")
		if paste == "" {
			http.Error(w, "Empty paste", 500)
			return
		}
		values := save(paste, lang)
		b := &Response{
			ID:     values[0],
			HASH:   values[1],
			URL:    values[2],
			SIZE:   len(values[3]),
			DELKEY: values[4],
		}

		switch output {
		case "json":

			w.Header().Set("Content-Type", "application/json")
			err := json.NewEncoder(w).Encode(b)

			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		case "xml":
			x, err := xml.MarshalIndent(b, "", "  ")
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

			w.Header().Set("Content-Type", "application/xml")
			w.Write(x)

		case "html":
			w.Header().Set("Content-Type", "text/html")
			io.WriteString(w, "
URL: "+b.URL+"
")
			io.WriteString(w, "
Delete Key: "+b.DELKEY+"
")

		case "redirect":
			http.Redirect(w, r, b.URL, 301)

		default:
			w.Header().Set("Content-Type", "plain/text")
			io.WriteString(w, b.URL+"\n")
			io.WriteString(w, "delete key: "+b.DELKEY+"\n")
		}
	}

}

func highlight(s string, lang string) (string, error) {

	highlight, err := pygments.Highlight(html.UnescapeString(s), html.EscapeString(lang), "html", "style=autumn,linenos=True, lineanchors=True,anchorlinenos=True,noclasses=True,", "utf-8")
	if err != nil {
		return "", err
	}
	return highlight, nil

}

func getPaste(paste string, lang string) string {
	param1 := html.EscapeString(paste)
	db, err := sql.Open("mysql", DATABASE)
	var s string
	err = db.QueryRow("select data from pastebin where id=?", param1).Scan(&s)
	db.Close()
	check(err)

	if err == sql.ErrNoRows {
		return "Error invalid paste"
	} else {
		if lang == "" {
			return html.UnescapeString(s)
		} else {
			high, err := highlight(s, lang)
			check(err)
			return high

		}
	}

}

var templates = template.Must(template.ParseFiles("assets/paste.html", "assets/index.html"))
var syntax, _ = ioutil.ReadFile("assets/syntax.html")

func pasteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	lang := vars["lang"]
	s := getPaste(paste, lang)
	link := ADDRESS + "/raw/" + paste
	if lang == "" {
		p := &Page{
			Title: paste,
			Body:  []byte(s),
			Raw:   link,
			Home:  ADDRESS,
		}
		err := templates.ExecuteTemplate(w, "paste.html", p)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}

	} else {
		fmt.Fprintf(w, string(syntax), paste, paste, s, ADDRESS, link)

	}
}

func cloneHandler(w http.ResponseWriter, r *http.Request) {
}
func downloadHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s := getPaste(paste, "")
	w.Header().Set("Content-Disposition", "attachment; filename="+paste)
	w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
	io.WriteString(w, s)

}
func rawHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s := getPaste(paste, "")
	io.WriteString(w, s)

}

func main() {
	router := mux.NewRouter()
	router.HandleFunc("/p/{pasteId}", pasteHandler)
	router.HandleFunc("/raw/{pasteId}", rawHandler)
	router.HandleFunc("/p/{pasteId}/{lang}", pasteHandler)
	router.HandleFunc("/clone/{pasteId}", cloneHandler)
	router.HandleFunc("/download/{pasteId}", downloadHandler)
	router.HandleFunc("/save", saveHandler)
	router.HandleFunc("/save/{output}", saveHandler)
	router.HandleFunc("/del/{pasteId}/{delKey}", delHandler)
	router.PathPrefix("/").Handler(http.StripPrefix("/", http.FileServer(http.Dir("assets/"))))
	err := http.ListenAndServe(PORT, router)
	if err != nil {
		log.Fatal(err)
	}

}
<|endoftext|>